diff --git a/apps/desktop/src/components/grid/DataGridConditionEditor.vue b/apps/desktop/src/components/grid/DataGridConditionEditor.vue index 0b3526ef08..f0b4c6d520 100644 --- a/apps/desktop/src/components/grid/DataGridConditionEditor.vue +++ b/apps/desktop/src/components/grid/DataGridConditionEditor.vue @@ -2,6 +2,7 @@ import { computed, nextTick, onMounted, onUnmounted, ref, useId, watch, type CSSProperties } from "vue"; import { ChevronDown, X } from "@lucide/vue"; import { completeDataGridConditionQuote, useDataGridConditionEditor, type DataGridConditionColumnOption, type DataGridConditionSuggestion, type DataGridConditionSuggestionProvider } from "@/composables/useDataGridConditionEditor"; +import { tokenizeDataGridCondition, type DataGridConditionTokenType } from "@/lib/dataGrid/dataGridConditionHighlight"; import { getDataGridConditionSuggestionPosition, getDataGridConditionSuggestionPreferredWidth } from "@/lib/dataGrid/dataGridConditionSuggestionPosition"; import type { DataGridConditionHistoryKind, DataGridConditionHistoryScope } from "@/lib/dataGrid/dataGridConditionHistory"; @@ -73,6 +74,25 @@ const editor = useDataGridConditionEditor({ const activeEditor = computed(() => overlayRef.value ?? inputRef.value); const hasValue = computed(() => modelValue.value.trim().length > 0); +// Syntax highlight tokens rendered in a layer below the (transparent-text) +// 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(() => ({ transform: `translateX(${-highlightScrollLeft.value}px)` })); +const expandedHighlightStyle = computed(() => ({ transform: `translate(${-highlightScrollLeft.value}px, ${-highlightScrollTop.value}px)` })); + +function highlightTokenClass(type: DataGridConditionTokenType): string | undefined { + if (type === "plain") return undefined; + return `data-grid-condition-token--${type}`; +} + +function onEditorScroll(event: Event) { + const target = event.currentTarget as HTMLTextAreaElement; + highlightScrollLeft.value = target.scrollLeft; + highlightScrollTop.value = target.scrollTop; +} const emptyHistoryText = computed(() => (modelValue.value.trim() ? props.historyNoMatchesText : props.historyEmptyText)); const activeSuggestionId = computed(() => (editor.highlightedIndex.value >= 0 ? `${suggestionListId}-${editor.highlightedIndex.value}` : undefined)); const suggestionPreferredWidth = computed(() => getDataGridConditionSuggestionPreferredWidth(editor.suggestions.value)); @@ -501,6 +521,9 @@ defineExpose({ focus, dismiss: editor.dismiss, rememberHistory: editor.rememberH {{ props.kind === "where" ? "WHERE" : "ORDER BY" }}
+