@keboola/design 9.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { CompletionSource } from '@codemirror/autocomplete';
4
4
  import { SQLNamespace } from '@codemirror/lang-sql';
5
- import { EditorView, EditorState, KeyBinding } from '@uiw/react-codemirror';
5
+ import { EditorView, EditorState } from '@uiw/react-codemirror';
6
6
  import { SqlDialectName } from '@keboola/codemirror-lang-sql';
7
7
  export { SqlDialectName } from '@keboola/codemirror-lang-sql';
8
8
  import { M as MergeConflict, C as ChangeClassification } from './constants-D3gaMY-W.cjs';
@@ -31,12 +31,32 @@ type Props$2 = {
31
31
  searchQuery?: string;
32
32
  searchMatchIndex?: number;
33
33
  readOnly?: boolean;
34
+ /**
35
+ * Refuses edits while leaving the editor looking and behaving as it did — for a
36
+ * transient lock such as an in-flight save, where a keystroke landing mid-request
37
+ * would be overwritten by the response. `readOnly` is the wrong prop for that:
38
+ * it turns the editor into a viewer, greying the surface and taking the lint
39
+ * marks and completions with it.
40
+ */
41
+ inputLocked?: boolean;
42
+ /**
43
+ * A flat list of completions, offered everywhere in the document. One word per
44
+ * label: CodeMirror derives the pattern for the word being completed from the
45
+ * labels' characters, so a space in one widens it across whitespace and the
46
+ * editor offers nothing past the first word of a line. A phrase belongs in
47
+ * `completionSource`.
48
+ *
49
+ * Compared by identity, like `completionSource` — hand the editor a stable array.
50
+ */
34
51
  autocompletions?: string[];
35
52
  /**
36
53
  * Completions that depend on where the cursor is — a column list offered only
37
54
  * after its table, say. Wins over both `autocompletions` and `completeAny`,
38
55
  * which stay the right props for a list that is the same everywhere in the
39
56
  * document and for having no list at all. Like them, it opens on typing.
57
+ *
58
+ * Compared by identity: build it in a `useMemo` or the editor rebuilds its whole
59
+ * extension tree on every render.
40
60
  */
41
61
  completionSource?: CompletionSource;
42
62
  /**
@@ -64,7 +84,7 @@ type Props$2 = {
64
84
  readOnly?: boolean;
65
85
  onChange: (value: string) => void;
66
86
  });
67
- declare const CodeEditor: ({ value, previousValue, onChange, mode, placeholder, ariaLabel, searchQuery, searchMatchIndex, readOnly, autocompletions, completionSource, variables, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className, }: Props$2) => react_jsx_runtime.JSX.Element;
87
+ declare const CodeEditor: ({ value, previousValue, onChange, mode, placeholder, ariaLabel, searchQuery, searchMatchIndex, readOnly, inputLocked, autocompletions, completionSource, variables, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className, }: Props$2) => react_jsx_runtime.JSX.Element;
68
88
 
69
89
  type HighlightedLines = {
70
90
  from: number;
@@ -91,11 +111,15 @@ type Props$1 = {
91
111
  placeholder?: string;
92
112
  searchQuery?: string;
93
113
  searchMatchIndex?: number;
94
- extraKeys?: KeyBinding[];
95
114
  queryParser?: (sql: string) => Promise<string[]>;
96
115
  autoFocus?: boolean;
97
116
  lineNumbers?: boolean;
98
117
  className?: string;
118
+ /**
119
+ * A schema is too large to compare by value, so this one prop keeps the
120
+ * identity requirement every other prop here is now free of: hand the editor
121
+ * a stable object, or it rebuilds its whole extension tree on every render.
122
+ */
99
123
  schema?: SQLNamespace;
100
124
  variables?: EditorVariable[];
101
125
  defaultSchema?: string;
@@ -103,7 +127,7 @@ type Props$1 = {
103
127
  highlightLines?: HighlightedLines;
104
128
  dialect?: SqlDialectName;
105
129
  };
106
- declare const SqlEditor: ({ value, onChange, onSelectionChange, onCreateEditor, onDestroyEditor, onBlurEditor, onFocusEditor, placeholder, searchQuery, searchMatchIndex, readOnly, extraKeys, queryParser, autoFocus, lineNumbers, className, schema, variables, defaultDatabase, defaultSchema, highlightLines, dialect, }: Props$1) => react_jsx_runtime.JSX.Element;
130
+ declare const SqlEditor: ({ value, onChange, onSelectionChange, onCreateEditor, onDestroyEditor, onBlurEditor, onFocusEditor, placeholder, searchQuery, searchMatchIndex, readOnly, queryParser, autoFocus, lineNumbers, className, schema, variables, defaultDatabase, defaultSchema, highlightLines, dialect, }: Props$1) => react_jsx_runtime.JSX.Element;
107
131
 
108
132
  type Props = {
109
133
  mergeValue: string;
package/dist/editors.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { CompletionSource } from '@codemirror/autocomplete';
4
4
  import { SQLNamespace } from '@codemirror/lang-sql';
5
- import { EditorView, EditorState, KeyBinding } from '@uiw/react-codemirror';
5
+ import { EditorView, EditorState } from '@uiw/react-codemirror';
6
6
  import { SqlDialectName } from '@keboola/codemirror-lang-sql';
7
7
  export { SqlDialectName } from '@keboola/codemirror-lang-sql';
8
8
  import { M as MergeConflict, C as ChangeClassification } from './constants-D3gaMY-W.js';
@@ -31,12 +31,32 @@ type Props$2 = {
31
31
  searchQuery?: string;
32
32
  searchMatchIndex?: number;
33
33
  readOnly?: boolean;
34
+ /**
35
+ * Refuses edits while leaving the editor looking and behaving as it did — for a
36
+ * transient lock such as an in-flight save, where a keystroke landing mid-request
37
+ * would be overwritten by the response. `readOnly` is the wrong prop for that:
38
+ * it turns the editor into a viewer, greying the surface and taking the lint
39
+ * marks and completions with it.
40
+ */
41
+ inputLocked?: boolean;
42
+ /**
43
+ * A flat list of completions, offered everywhere in the document. One word per
44
+ * label: CodeMirror derives the pattern for the word being completed from the
45
+ * labels' characters, so a space in one widens it across whitespace and the
46
+ * editor offers nothing past the first word of a line. A phrase belongs in
47
+ * `completionSource`.
48
+ *
49
+ * Compared by identity, like `completionSource` — hand the editor a stable array.
50
+ */
34
51
  autocompletions?: string[];
35
52
  /**
36
53
  * Completions that depend on where the cursor is — a column list offered only
37
54
  * after its table, say. Wins over both `autocompletions` and `completeAny`,
38
55
  * which stay the right props for a list that is the same everywhere in the
39
56
  * document and for having no list at all. Like them, it opens on typing.
57
+ *
58
+ * Compared by identity: build it in a `useMemo` or the editor rebuilds its whole
59
+ * extension tree on every render.
40
60
  */
41
61
  completionSource?: CompletionSource;
42
62
  /**
@@ -64,7 +84,7 @@ type Props$2 = {
64
84
  readOnly?: boolean;
65
85
  onChange: (value: string) => void;
66
86
  });
67
- declare const CodeEditor: ({ value, previousValue, onChange, mode, placeholder, ariaLabel, searchQuery, searchMatchIndex, readOnly, autocompletions, completionSource, variables, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className, }: Props$2) => react_jsx_runtime.JSX.Element;
87
+ declare const CodeEditor: ({ value, previousValue, onChange, mode, placeholder, ariaLabel, searchQuery, searchMatchIndex, readOnly, inputLocked, autocompletions, completionSource, variables, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className, }: Props$2) => react_jsx_runtime.JSX.Element;
68
88
 
69
89
  type HighlightedLines = {
70
90
  from: number;
@@ -91,11 +111,15 @@ type Props$1 = {
91
111
  placeholder?: string;
92
112
  searchQuery?: string;
93
113
  searchMatchIndex?: number;
94
- extraKeys?: KeyBinding[];
95
114
  queryParser?: (sql: string) => Promise<string[]>;
96
115
  autoFocus?: boolean;
97
116
  lineNumbers?: boolean;
98
117
  className?: string;
118
+ /**
119
+ * A schema is too large to compare by value, so this one prop keeps the
120
+ * identity requirement every other prop here is now free of: hand the editor
121
+ * a stable object, or it rebuilds its whole extension tree on every render.
122
+ */
99
123
  schema?: SQLNamespace;
100
124
  variables?: EditorVariable[];
101
125
  defaultSchema?: string;
@@ -103,7 +127,7 @@ type Props$1 = {
103
127
  highlightLines?: HighlightedLines;
104
128
  dialect?: SqlDialectName;
105
129
  };
106
- declare const SqlEditor: ({ value, onChange, onSelectionChange, onCreateEditor, onDestroyEditor, onBlurEditor, onFocusEditor, placeholder, searchQuery, searchMatchIndex, readOnly, extraKeys, queryParser, autoFocus, lineNumbers, className, schema, variables, defaultDatabase, defaultSchema, highlightLines, dialect, }: Props$1) => react_jsx_runtime.JSX.Element;
130
+ declare const SqlEditor: ({ value, onChange, onSelectionChange, onCreateEditor, onDestroyEditor, onBlurEditor, onFocusEditor, placeholder, searchQuery, searchMatchIndex, readOnly, queryParser, autoFocus, lineNumbers, className, schema, variables, defaultDatabase, defaultSchema, highlightLines, dialect, }: Props$1) => react_jsx_runtime.JSX.Element;
107
131
 
108
132
  type Props = {
109
133
  mergeValue: string;
package/dist/editors.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { createContext, useRef, useEffect, useLayoutEffect, useMemo, useCallback, useSyncExternalStore, useState, use, Children, Fragment as Fragment$1 } from 'react';
2
- import { completeFromList, completeAnyWord, autocompletion } from '@codemirror/autocomplete';
2
+ import { completeAnyWord, autocompletion } from '@codemirror/autocomplete';
3
3
  import { jsonParseLinter, json } from '@codemirror/lang-json';
4
4
  import { linter } from '@codemirror/lint';
5
5
  import { unifiedMergeView } from '@codemirror/merge';
6
- import { EditorView, Decoration, ViewPlugin, gutter, GutterMarker, keymap, placeholder, tooltips, gutterLineClass } from '@codemirror/view';
7
- import CodeMirror, { EditorState, EditorView as EditorView$1, keymap as keymap$1 } from '@uiw/react-codemirror';
6
+ import { EditorView, Decoration, ViewPlugin, gutter, GutterMarker, keymap as keymap$1, placeholder, tooltips, gutterLineClass } from '@codemirror/view';
7
+ import CodeMirror, { keymap, EditorState, EditorView as EditorView$1 } from '@uiw/react-codemirror';
8
8
  import { clsx } from 'clsx';
9
9
  import { extendTailwindMerge } from 'tailwind-merge';
10
10
  import { Root as Root$1, Trigger, Portal, Content } from '@radix-ui/react-tooltip';
@@ -21,12 +21,11 @@ import { r } from '@codemirror/legacy-modes/mode/r';
21
21
  import { shell } from '@codemirror/legacy-modes/mode/shell';
22
22
  import { toml } from '@codemirror/legacy-modes/mode/toml';
23
23
  import { githubLightInit } from '@uiw/codemirror-theme-github';
24
- import { modeSpec, sfsql } from '@keboola/codemirror-lang-sfsql';
24
+ import { installExtensions, getSqlDialect } from '@keboola/codemirror-lang-sql';
25
25
  import colors from '@keboola/tailwind-config/colors';
26
26
  import { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';
27
27
  import { StateEffect, StateField, RangeSet, Compartment, RangeSetBuilder } from '@codemirror/state';
28
28
  import { defaultKeymap } from '@codemirror/commands';
29
- import { installExtensions } from '@keboola/codemirror-lang-sql';
30
29
 
31
30
  // src/components/CodeEditor/CodeEditor.tsx
32
31
 
@@ -1030,6 +1029,7 @@ var LANGUAGE_MODES = [
1030
1029
  "text/x-mysql",
1031
1030
  "text/x-pgsql",
1032
1031
  "text/x-mssql",
1032
+ // Snowflake, under a historical name — these strings are a published prop contract.
1033
1033
  "text/x-sfsql",
1034
1034
  "text/x-plsql",
1035
1035
  "text/x-rsrc",
@@ -1091,8 +1091,6 @@ var ALWAYS_OFF = {
1091
1091
  var buildBasicSetup = (readOnly) => ({
1092
1092
  ...ALWAYS_OFF,
1093
1093
  ...readOnly ? {
1094
- history: false,
1095
- historyKeymap: false,
1096
1094
  closeBrackets: false,
1097
1095
  closeBracketsKeymap: false,
1098
1096
  lintKeymap: false,
@@ -1114,20 +1112,6 @@ var buildCustomTheme = () => githubLightInit({
1114
1112
  selection: resolveToken("primary", "31 143 255")
1115
1113
  }
1116
1114
  });
1117
- var sfsqlWithLanguageData = {
1118
- ...sfsql,
1119
- languageData: {
1120
- ...sfsql.languageData,
1121
- // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.
1122
- commentTokens: { line: "--", block: { open: "/*", close: "*/" } },
1123
- autocomplete: completeFromList(
1124
- Object.keys(modeSpec.keywords).map((label) => ({
1125
- label: label.toUpperCase(),
1126
- type: "keyword"
1127
- }))
1128
- )
1129
- }
1130
- };
1131
1115
  var getLanguageMode = (mode) => {
1132
1116
  switch (mode) {
1133
1117
  case void 0:
@@ -1144,7 +1128,7 @@ var getLanguageMode = (mode) => {
1144
1128
  case "text/x-mssql":
1145
1129
  return sql({ upperCaseKeywords: true, dialect: MSSQL });
1146
1130
  case "text/x-sfsql":
1147
- return StreamLanguage.define(sfsqlWithLanguageData);
1131
+ return sql({ upperCaseKeywords: true, dialect: getSqlDialect("snowflake") });
1148
1132
  case "text/x-plsql":
1149
1133
  return sql({ upperCaseKeywords: true, dialect: PLSQL });
1150
1134
  case "text/x-rsrc":
@@ -1406,7 +1390,7 @@ var completeVariables = (variables = []) => {
1406
1390
  return { from: match.to - name.length, options };
1407
1391
  };
1408
1392
  };
1409
- var emptyArray = [];
1393
+ var useVariableCompletion = (variables = []) => useStableCallback(completeVariables(variables));
1410
1394
  var emptyObject = {};
1411
1395
  var CodeEditor = ({
1412
1396
  value,
@@ -1418,7 +1402,8 @@ var CodeEditor = ({
1418
1402
  searchQuery,
1419
1403
  searchMatchIndex,
1420
1404
  readOnly = false,
1421
- autocompletions = emptyArray,
1405
+ inputLocked = false,
1406
+ autocompletions,
1422
1407
  completionSource,
1423
1408
  variables,
1424
1409
  extraKeys = emptyObject,
@@ -1454,22 +1439,24 @@ var CodeEditor = ({
1454
1439
  [boundKeysSignature]
1455
1440
  );
1456
1441
  const tooltipLayer = useTooltipsExtension();
1457
- const variableCompletion = useMemo(() => completeVariables(variables), [variables]);
1442
+ const variableCompletion = useVariableCompletion(variables);
1458
1443
  const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
1459
1444
  const baseTheme = useThemedExtension(
1460
1445
  "code-editor:chrome",
1461
1446
  () => EditorView.theme(buildBaseThemeStyles())
1462
1447
  );
1463
1448
  const commonExtensions = useMemo(() => {
1449
+ const callerCompletions = completionSource ?? (completeAny ? completeAnyWord : autocompletions?.length ? autocompletions : null);
1450
+ const completionEntries = [
1451
+ ...callerCompletions ? [{ autocomplete: callerCompletions }] : [],
1452
+ { autocomplete: variableCompletion }
1453
+ ];
1464
1454
  return [
1465
1455
  getLanguageMode(mode),
1466
1456
  shouldLintJson(mode, readOnly) ? linter(jsonParseLinter()) : [],
1467
1457
  withLineWrapping ? EditorView.lineWrapping : [],
1468
- EditorState.languageData.of(() => [
1469
- { autocomplete: completionSource ?? (completeAny ? completeAnyWord : autocompletions) }
1470
- ]),
1471
- EditorState.languageData.of(() => [{ autocomplete: variableCompletion }]),
1472
- keymap.of(
1458
+ EditorState.languageData.of(() => completionEntries),
1459
+ keymap$1.of(
1473
1460
  boundKeys.map((key) => ({
1474
1461
  key,
1475
1462
  run: () => {
@@ -1509,7 +1496,10 @@ var CodeEditor = ({
1509
1496
  ...commonExtensions,
1510
1497
  placeholder(placeholder$1),
1511
1498
  EditorView.editable.of(!readOnly),
1512
- EditorState.readOnly.of(readOnly),
1499
+ // The lock is this facet and nothing else. `contenteditable` is what the
1500
+ // read-only wash keys off, and `basicSetup` is what holds the undo history,
1501
+ // so leaving both alone is what makes the lock invisible.
1502
+ EditorState.readOnly.of(readOnly || inputLocked),
1513
1503
  previousValue ? unifiedMergeView({
1514
1504
  original: previousValue,
1515
1505
  mergeControls: false,
@@ -1517,7 +1507,7 @@ var CodeEditor = ({
1517
1507
  collapseUnchanged: withCollapseUnchanged ? {} : void 0
1518
1508
  }) : []
1519
1509
  ];
1520
- }, [commonExtensions, placeholder$1, readOnly, previousValue, withCollapseUnchanged]);
1510
+ }, [commonExtensions, placeholder$1, readOnly, inputLocked, previousValue, withCollapseUnchanged]);
1521
1511
  const config = useMemo(() => {
1522
1512
  return {
1523
1513
  ...buildBasicSetup(readOnly),
@@ -1743,8 +1733,6 @@ var activeQueryHighlight = (splitQueries) => {
1743
1733
  })
1744
1734
  ];
1745
1735
  };
1746
-
1747
- // src/components/CodeEditor/highlighting.ts
1748
1736
  var HighlightMarker = class extends GutterMarker {
1749
1737
  toDOM() {
1750
1738
  const marker = document.createElement("div");
@@ -1860,14 +1848,13 @@ var highlightedLinesTheme = EditorView.baseTheme({
1860
1848
  backgroundColor: `${colors.blue[100]} !important`
1861
1849
  }
1862
1850
  });
1863
- function highlightingExtension(queryParser) {
1851
+ function highlightingExtension() {
1864
1852
  return [
1865
1853
  highlightedLinesField,
1866
1854
  highlightGutter,
1867
1855
  errorLineDecorations,
1868
1856
  processingLineDecorations,
1869
- highlightedLinesTheme,
1870
- ...queryParser ? activeQueryHighlight(queryParser) : []
1857
+ highlightedLinesTheme
1871
1858
  ];
1872
1859
  }
1873
1860
  function updateHighlighting(view, lines) {
@@ -1888,6 +1875,7 @@ var CUSTOM_KEYMAP = [
1888
1875
  }
1889
1876
  }
1890
1877
  ];
1878
+ var OWN_KEYMAP_EXTENSION = keymap.of([...defaultKeymap, ...CUSTOM_KEYMAP]);
1891
1879
  var buildTheme = () => ({
1892
1880
  ...buildBaseThemeStyles(),
1893
1881
  "&.cm-editor": {
@@ -1925,7 +1913,6 @@ var SqlEditor = ({
1925
1913
  searchQuery = "",
1926
1914
  searchMatchIndex,
1927
1915
  readOnly = false,
1928
- extraKeys,
1929
1916
  queryParser,
1930
1917
  autoFocus = false,
1931
1918
  lineNumbers = true,
@@ -1938,6 +1925,18 @@ var SqlEditor = ({
1938
1925
  dialect
1939
1926
  }) => {
1940
1927
  const editorRef = useRef(null);
1928
+ const handleChange = useStableCallback((next) => onChange?.(next));
1929
+ const parseQueries = useStableCallback(async (sql2) => await queryParser?.(sql2) ?? []);
1930
+ const handleBlur = useStableCallback((view) => onBlurEditor?.(view));
1931
+ const handleFocus = useStableCallback((view) => onFocusEditor?.(view));
1932
+ const handleUpdate = useStableCallback((update) => {
1933
+ if (update.selectionSet) {
1934
+ const { main } = update.state.selection;
1935
+ onSelectionChange?.(update.state.sliceDoc(main.from, main.to));
1936
+ }
1937
+ });
1938
+ const variableCompletion = useVariableCompletion(variables);
1939
+ const withQueryParser = queryParser !== void 0;
1941
1940
  const tooltipLayer = useTooltipsExtension();
1942
1941
  const customTheme = useThemedExtension("editor:syntax", buildCustomTheme);
1943
1942
  const themeExtension = useThemedExtension(
@@ -1945,34 +1944,36 @@ var SqlEditor = ({
1945
1944
  () => EditorView$1.theme(buildTheme())
1946
1945
  );
1947
1946
  const extensions = useMemo(() => {
1948
- const baseKeymap = [...defaultKeymap, ...CUSTOM_KEYMAP];
1949
1947
  return [
1950
1948
  EditorView$1.lineWrapping,
1951
- keymap$1.of(extraKeys ? [...extraKeys, ...baseKeymap] : baseKeymap),
1949
+ OWN_KEYMAP_EXTENSION,
1952
1950
  ...installExtensions({
1953
1951
  schema,
1954
1952
  defaultDatabase,
1955
1953
  defaultSchema,
1956
- variableCompletion: completeVariables(variables),
1954
+ variableCompletion,
1957
1955
  dialect
1958
1956
  }),
1959
1957
  searchExtension(),
1960
- highlightingExtension(queryParser),
1958
+ highlightingExtension(),
1959
+ withQueryParser ? activeQueryHighlight(parseQueries) : [],
1961
1960
  tooltipLayer,
1962
1961
  themeExtension,
1963
- onBlurEditor ? EditorView$1.domEventHandlers({ blur: (_, view) => onBlurEditor(view) }) : [],
1964
- onFocusEditor ? EditorView$1.domEventHandlers({ focus: (_, view) => onFocusEditor(view) }) : []
1962
+ EditorView$1.domEventHandlers({
1963
+ blur: (_, view) => handleBlur(view),
1964
+ focus: (_, view) => handleFocus(view)
1965
+ })
1965
1966
  ];
1966
1967
  }, [
1967
- extraKeys,
1968
- queryParser,
1968
+ withQueryParser,
1969
+ parseQueries,
1969
1970
  schema,
1970
1971
  defaultDatabase,
1971
1972
  defaultSchema,
1972
- variables,
1973
+ variableCompletion,
1973
1974
  dialect,
1974
- onBlurEditor,
1975
- onFocusEditor,
1975
+ handleBlur,
1976
+ handleFocus,
1976
1977
  themeExtension,
1977
1978
  tooltipLayer
1978
1979
  ]);
@@ -1989,34 +1990,17 @@ var SqlEditor = ({
1989
1990
  updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);
1990
1991
  }
1991
1992
  }, [searchQuery, searchMatchIndex]);
1992
- useEffect(() => {
1993
- if (!onDestroyEditor) return;
1994
- return () => {
1995
- onDestroyEditor();
1996
- };
1997
- }, [onDestroyEditor]);
1998
- const handleOnCreate = useCallback(
1999
- (view, state) => {
2000
- onCreateEditor?.(view, state);
2001
- if (highlightLines) {
2002
- updateHighlighting(view, highlightLines);
2003
- }
2004
- if (searchQuery) {
2005
- updateSearch(view, searchQuery, searchMatchIndex);
2006
- }
2007
- },
2008
- [onCreateEditor, highlightLines, searchQuery, searchMatchIndex]
2009
- );
2010
- const handleOnUpdate = useCallback(
2011
- (update) => {
2012
- if (update.selectionSet) {
2013
- const { main } = update.state.selection;
2014
- const text = update.state.sliceDoc(main.from, main.to);
2015
- onSelectionChange?.(text);
2016
- }
2017
- },
2018
- [onSelectionChange]
2019
- );
1993
+ const handleDestroy = useStableCallback(() => onDestroyEditor?.());
1994
+ useEffect(() => handleDestroy, [handleDestroy]);
1995
+ const handleCreate = useStableCallback((view, state) => {
1996
+ onCreateEditor?.(view, state);
1997
+ if (highlightLines) {
1998
+ updateHighlighting(view, highlightLines);
1999
+ }
2000
+ if (searchQuery) {
2001
+ updateSearch(view, searchQuery, searchMatchIndex);
2002
+ }
2003
+ });
2020
2004
  return /* @__PURE__ */ jsx(
2021
2005
  CodeMirror,
2022
2006
  {
@@ -2024,9 +2008,9 @@ var SqlEditor = ({
2024
2008
  theme: customTheme,
2025
2009
  extensions,
2026
2010
  value,
2027
- onChange,
2028
- onUpdate: handleOnUpdate,
2029
- onCreateEditor: handleOnCreate,
2011
+ onChange: handleChange,
2012
+ onUpdate: handleUpdate,
2013
+ onCreateEditor: handleCreate,
2030
2014
  autoFocus,
2031
2015
  placeholder,
2032
2016
  className,