fix(grid): reset filter editor caret offset on expand
This commit is contained in:
2 files changed
+44
-6
No files matched your search
@@ -81,10 +81,11 @@ const hasValue = computed(() => modelValue.value.trim().length > 0);
|
||||
// textarea, so keywords / fields / values are colored without losing caret
|
||||
// and selection behavior.
|
||||
const highlightTokens = computed(() => tokenizeDataGridCondition(modelValue.value));
|
||||
const highlightScrollLeft = ref(0);
|
||||
const highlightScrollTop = ref(0);
|
||||
const collapsedHighlightStyle = computed<CSSProperties>(() => ({ transform: `translateX(${-highlightScrollLeft.value}px)` }));
|
||||
const expandedHighlightStyle = computed<CSSProperties>(() => ({ transform: `translate(${-highlightScrollLeft.value}px, ${-highlightScrollTop.value}px)` }));
|
||||
const collapsedHighlightScrollLeft = ref(0);
|
||||
const expandedHighlightScrollLeft = ref(0);
|
||||
const expandedHighlightScrollTop = ref(0);
|
||||
const collapsedHighlightStyle = computed<CSSProperties>(() => ({ transform: `translateX(${-collapsedHighlightScrollLeft.value}px)` }));
|
||||
const expandedHighlightStyle = computed<CSSProperties>(() => ({ transform: `translate(${-expandedHighlightScrollLeft.value}px, ${-expandedHighlightScrollTop.value}px)` }));
|
||||
|
||||
function highlightTokenClass(type: DataGridConditionTokenType): string | undefined {
|
||||
if (type === "plain") return undefined;
|
||||
@@ -93,8 +94,12 @@ function highlightTokenClass(type: DataGridConditionTokenType): string | undefin
|
||||
|
||||
function onEditorScroll(event: Event) {
|
||||
const target = event.currentTarget as HTMLTextAreaElement;
|
||||
highlightScrollLeft.value = target.scrollLeft;
|
||||
highlightScrollTop.value = target.scrollTop;
|
||||
if (target === overlayRef.value) {
|
||||
expandedHighlightScrollLeft.value = target.scrollLeft;
|
||||
expandedHighlightScrollTop.value = target.scrollTop;
|
||||
} else {
|
||||
collapsedHighlightScrollLeft.value = target.scrollLeft;
|
||||
}
|
||||
}
|
||||
const emptyHistoryText = computed(() => (modelValue.value.trim() ? props.historyNoMatchesText : props.historyEmptyText));
|
||||
const activeSuggestionId = computed(() => (editor.highlightedIndex.value >= 0 ? `${suggestionListId}-${editor.highlightedIndex.value}` : undefined));
|
||||
@@ -221,10 +226,15 @@ function resizeEditor(forceExpand = false) {
|
||||
expandAfterComposition = true;
|
||||
return;
|
||||
}
|
||||
const wasExpanded = expanded.value;
|
||||
const overlayFocused = document.activeElement === overlayRef.value;
|
||||
const focused = document.activeElement === input || overlayFocused;
|
||||
const nextExpanded = focused && shouldExpand(input) && (forceExpand || expanded.value);
|
||||
if (nextExpanded) {
|
||||
if (!wasExpanded) {
|
||||
expandedHighlightScrollLeft.value = 0;
|
||||
expandedHighlightScrollTop.value = 0;
|
||||
}
|
||||
const nextRect = measureExpandedRect(input);
|
||||
expandedRect.value = nextRect;
|
||||
expandedHeight.value = measureExpandedHeight(input, nextRect);
|
||||
|
||||
@@ -445,6 +445,34 @@ describe("DataGridConditionEditor quote completion", () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("does not carry the collapsed horizontal scroll into the expanded highlight layer", async () => {
|
||||
vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(function (this: HTMLElement) {
|
||||
const textWidth = (this.textContent?.length ?? 0) * 8;
|
||||
const width = this.classList.contains("data-grid-topbar-condition-pane--expanded") ? 160 : textWidth;
|
||||
return { x: 0, y: 0, left: 0, top: 0, right: width, bottom: 24, width, height: 24, toJSON: () => ({}) } as DOMRect;
|
||||
});
|
||||
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue(null);
|
||||
vi.stubGlobal("requestAnimationFrame", (callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 1;
|
||||
});
|
||||
const { input } = mountEditor("where", "test_item_id=12 and test_item_name=''");
|
||||
mockTextareaMetrics(input, { clientWidth: 80, scrollWidth: 320 });
|
||||
input.scrollLeft = 128;
|
||||
input.dispatchEvent(new Event("scroll", { bubbles: true }));
|
||||
input.focus();
|
||||
input.setSelectionRange(input.value.length, input.value.length);
|
||||
input.dispatchEvent(new Event("focus", { bubbles: true }));
|
||||
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
|
||||
const expandedHighlight = document.body.querySelector(".data-grid-condition-highlight--expanded") as HTMLElement | null;
|
||||
expect(expandedHighlight).toBeTruthy();
|
||||
expect(expandedHighlight?.style.transform).toBe("translate(0px, 0px)");
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("positions suggestions below the measured expanded editor height", () => {
|
||||
const source = readFileSync(resolve(process.cwd(), "apps/desktop/src/components/grid/DataGridConditionEditor.vue"), "utf8");
|
||||
const expandedPaneCss = source.match(/\.data-grid-topbar-condition-pane--expanded\s*\{(?<body>[\s\S]*?)\n\}/)?.groups?.body;
|
||||
|
||||
Reference in new issue
Block a user