@12-apps/ui 6.39.17 → 6.39.19

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.
Files changed (34) hide show
  1. package/dist/_internal/components/form/Autocomplete/Autocomplete.js +2 -2
  2. package/dist/_internal/components/form/Autocomplete/useAutocomplete.js +1 -1
  3. package/dist/_internal/components/form/CodeEditor/CodeEditor.hooks.js +2 -2
  4. package/dist/_internal/components/form/CodeEditor/CodeEditor.js +3 -3
  5. package/dist/_internal/components/form/CodeEditor/CodeEditor.monaco.js +3 -1
  6. package/dist/_internal/components/form/index.js +9 -6
  7. package/dist/_internal/components/index.js +9 -6
  8. package/dist/{chunk-HD6ZNARS.js → chunk-5F5Q6VJ2.js} +7 -1
  9. package/dist/chunk-5F5Q6VJ2.js.map +1 -0
  10. package/dist/chunk-IDMG332I.js +1 -0
  11. package/dist/{chunk-QG73YT6D.js → chunk-L36S7YJB.js} +2 -2
  12. package/dist/{chunk-HBRKA67N.js → chunk-M4P7NS2L.js} +20 -12
  13. package/dist/chunk-M4P7NS2L.js.map +1 -0
  14. package/dist/{chunk-DQZCQV2C.js → chunk-Y6G4I42P.js} +2 -2
  15. package/dist/{chunk-4Y6W7BT4.js → chunk-YQCRQHVU.js} +2 -2
  16. package/dist/form/Autocomplete.js +2 -2
  17. package/dist/form/CodeEditor.js +8 -5
  18. package/dist/types/components/form/Autocomplete/useAutocomplete.d.ts.map +1 -1
  19. package/dist/types/components/form/CodeEditor/CodeEditor.monaco.d.ts +32 -2
  20. package/dist/types/components/form/CodeEditor/CodeEditor.monaco.d.ts.map +1 -1
  21. package/dist/types/components/form/CodeEditor/index.d.ts +2 -0
  22. package/dist/types/components/form/CodeEditor/index.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/components/form/Autocomplete/useAutocomplete.ts +35 -10
  25. package/src/components/form/CodeEditor/CodeEditor.md +70 -0
  26. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +37 -2
  27. package/src/components/form/CodeEditor/index.ts +2 -0
  28. package/dist/chunk-HBRKA67N.js.map +0 -1
  29. package/dist/chunk-HD6ZNARS.js.map +0 -1
  30. package/dist/chunk-JEBPCAWD.js +0 -1
  31. /package/dist/{chunk-JEBPCAWD.js.map → chunk-IDMG332I.js.map} +0 -0
  32. /package/dist/{chunk-QG73YT6D.js.map → chunk-L36S7YJB.js.map} +0 -0
  33. /package/dist/{chunk-DQZCQV2C.js.map → chunk-Y6G4I42P.js.map} +0 -0
  34. /package/dist/{chunk-4Y6W7BT4.js.map → chunk-YQCRQHVU.js.map} +0 -0
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  Autocomplete,
3
3
  Autocomplete_default
4
- } from "../../../../chunk-DQZCQV2C.js";
5
- import "../../../../chunk-HBRKA67N.js";
4
+ } from "../../../../chunk-Y6G4I42P.js";
5
+ import "../../../../chunk-M4P7NS2L.js";
6
6
  import "../../../../chunk-H6AWKLOV.js";
7
7
  import "../../../../chunk-PELRSZFU.js";
8
8
  import "../../../../chunk-JXS56EW5.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useAutocomplete
3
- } from "../../../../chunk-HBRKA67N.js";
3
+ } from "../../../../chunk-M4P7NS2L.js";
4
4
  import "../../../../chunk-PELRSZFU.js";
5
5
  import "../../../../chunk-JXS56EW5.js";
6
6
  import "../../../../chunk-PZ5AY32C.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  useCodeEditor
3
- } from "../../../../chunk-QG73YT6D.js";
4
- import "../../../../chunk-HD6ZNARS.js";
3
+ } from "../../../../chunk-L36S7YJB.js";
4
+ import "../../../../chunk-5F5Q6VJ2.js";
5
5
  import "../../../../chunk-FQ6UW7IY.js";
6
6
  import "../../../../chunk-6JAIFIPW.js";
7
7
  import "../../../../chunk-N3GAFIXG.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  CodeEditor
3
- } from "../../../../chunk-4Y6W7BT4.js";
4
- import "../../../../chunk-QG73YT6D.js";
3
+ } from "../../../../chunk-YQCRQHVU.js";
4
+ import "../../../../chunk-L36S7YJB.js";
5
5
  import "../../../../chunk-X3OWMTLO.js";
6
6
  import "../../../../chunk-3TVUW7QE.js";
7
- import "../../../../chunk-HD6ZNARS.js";
7
+ import "../../../../chunk-5F5Q6VJ2.js";
8
8
  import "../../../../chunk-GDN2LUTZ.js";
9
9
  import "../../../../chunk-7FDU3FIN.js";
10
10
  import "../../../../chunk-EPEJMTCQ.js";
@@ -1,15 +1,17 @@
1
1
  import {
2
+ configureCodeEditor,
2
3
  configureTypeScriptDefaults,
3
4
  registerEditorThemes,
4
5
  registerSaveShortcut,
5
6
  resolveEditorTheme,
6
7
  scheduleAutoFormat
7
- } from "../../../../chunk-HD6ZNARS.js";
8
+ } from "../../../../chunk-5F5Q6VJ2.js";
8
9
  import "../../../../chunk-FQ6UW7IY.js";
9
10
  import "../../../../chunk-6JAIFIPW.js";
10
11
  import "../../../../chunk-N3GAFIXG.js";
11
12
  import "../../../../chunk-PZ5AY32C.js";
12
13
  export {
14
+ configureCodeEditor,
13
15
  configureTypeScriptDefaults,
14
16
  registerEditorThemes,
15
17
  registerSaveShortcut,
@@ -79,14 +79,16 @@ import {
79
79
  import "../../../chunk-7EH4D6FU.js";
80
80
  import "../../../chunk-G3XLFQ2Z.js";
81
81
  import "../../../chunk-Z6WSW6B4.js";
82
- import "../../../chunk-JEBPCAWD.js";
82
+ import "../../../chunk-IDMG332I.js";
83
83
  import {
84
84
  CodeEditor
85
- } from "../../../chunk-4Y6W7BT4.js";
86
- import "../../../chunk-QG73YT6D.js";
85
+ } from "../../../chunk-YQCRQHVU.js";
86
+ import "../../../chunk-L36S7YJB.js";
87
87
  import "../../../chunk-X3OWMTLO.js";
88
88
  import "../../../chunk-3TVUW7QE.js";
89
- import "../../../chunk-HD6ZNARS.js";
89
+ import {
90
+ configureCodeEditor
91
+ } from "../../../chunk-5F5Q6VJ2.js";
90
92
  import "../../../chunk-ZU4NDURP.js";
91
93
  import {
92
94
  Command,
@@ -139,8 +141,8 @@ import "../../../chunk-P5JCOFK3.js";
139
141
  import "../../../chunk-2LXHUGYB.js";
140
142
  import {
141
143
  Autocomplete
142
- } from "../../../chunk-DQZCQV2C.js";
143
- import "../../../chunk-HBRKA67N.js";
144
+ } from "../../../chunk-Y6G4I42P.js";
145
+ import "../../../chunk-M4P7NS2L.js";
144
146
  import "../../../chunk-H6AWKLOV.js";
145
147
  import "../../../chunk-PELRSZFU.js";
146
148
  import "../../../chunk-JXS56EW5.js";
@@ -268,6 +270,7 @@ export {
268
270
  Toggle,
269
271
  ToggleGroup,
270
272
  UploadButton,
273
+ configureCodeEditor,
271
274
  createQuickRanges,
272
275
  resolveDayRange
273
276
  };
@@ -267,14 +267,16 @@ import {
267
267
  import "../../chunk-7EH4D6FU.js";
268
268
  import "../../chunk-G3XLFQ2Z.js";
269
269
  import "../../chunk-Z6WSW6B4.js";
270
- import "../../chunk-JEBPCAWD.js";
270
+ import "../../chunk-IDMG332I.js";
271
271
  import {
272
272
  CodeEditor
273
- } from "../../chunk-4Y6W7BT4.js";
274
- import "../../chunk-QG73YT6D.js";
273
+ } from "../../chunk-YQCRQHVU.js";
274
+ import "../../chunk-L36S7YJB.js";
275
275
  import "../../chunk-X3OWMTLO.js";
276
276
  import "../../chunk-3TVUW7QE.js";
277
- import "../../chunk-HD6ZNARS.js";
277
+ import {
278
+ configureCodeEditor
279
+ } from "../../chunk-5F5Q6VJ2.js";
278
280
  import "../../chunk-ZU4NDURP.js";
279
281
  import {
280
282
  Command,
@@ -345,8 +347,8 @@ import "../../chunk-P5JCOFK3.js";
345
347
  import "../../chunk-2LXHUGYB.js";
346
348
  import {
347
349
  Autocomplete
348
- } from "../../chunk-DQZCQV2C.js";
349
- import "../../chunk-HBRKA67N.js";
350
+ } from "../../chunk-Y6G4I42P.js";
351
+ import "../../chunk-M4P7NS2L.js";
350
352
  import "../../chunk-H6AWKLOV.js";
351
353
  import "../../chunk-PELRSZFU.js";
352
354
  import "../../chunk-JXS56EW5.js";
@@ -1000,6 +1002,7 @@ export {
1000
1002
  brandGradient,
1001
1003
  capturePwaInstallEvent,
1002
1004
  chartValueFormatter,
1005
+ configureCodeEditor,
1003
1006
  createConfirmButton,
1004
1007
  createQuickRanges,
1005
1008
  detectNotificationBrowser,
@@ -3,6 +3,11 @@ import {
3
3
  } from "./chunk-FQ6UW7IY.js";
4
4
 
5
5
  // src/components/form/CodeEditor/CodeEditor.monaco.ts
6
+ import { loader } from "@monaco-editor/react";
7
+ var configureCodeEditor = ({ monaco, getWorker }) => {
8
+ loader.config({ monaco });
9
+ self.MonacoEnvironment = { getWorker };
10
+ };
6
11
  var chromeColors = (chrome) => ({
7
12
  "editor.background": chrome.background,
8
13
  "editor.foreground": chrome.foreground,
@@ -80,10 +85,11 @@ var resolveEditorTheme = (themeProp, paletteMode) => {
80
85
  };
81
86
 
82
87
  export {
88
+ configureCodeEditor,
83
89
  registerEditorThemes,
84
90
  configureTypeScriptDefaults,
85
91
  scheduleAutoFormat,
86
92
  registerSaveShortcut,
87
93
  resolveEditorTheme
88
94
  };
89
- //# sourceMappingURL=chunk-HD6ZNARS.js.map
95
+ //# sourceMappingURL=chunk-5F5Q6VJ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/form/CodeEditor/CodeEditor.monaco.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles/index.js';\nimport { loader, type Monaco } from '@monaco-editor/react';\nimport type { editor, Environment } from 'monaco-editor';\n\nimport { uiInk, type UiInk } from '../../../tokens/ink';\n\ntype EditorChrome = UiInk['codeEditor']['light'];\n\nexport interface ConfigureCodeEditorOptions {\n /**\n * The `monaco-editor` module the host's own bundler resolved, e.g.\n * `import * as monaco from 'monaco-editor'`. Handing it to the loader is\n * what stops `@monaco-editor/react` fetching its own copy from\n * `cdn.jsdelivr.net` at runtime — see `loader.config` below.\n */\n monaco: Monaco;\n /**\n * Monaco's web-worker factory. The package cannot supply this itself: wiring\n * a worker needs a bundler-specific import (Vite's `?worker` suffix, or the\n * equivalent in another bundler), and this package is built by tsup/esbuild,\n * which does not understand that suffix. The host's own Vite (or other)\n * entry point builds this from its own worker imports and passes it here.\n */\n getWorker: NonNullable<Environment['getWorker']>;\n}\n\n/**\n * Points `@monaco-editor/react` at the host's own installed Monaco instead of\n * its default CDN loader, and wires up Monaco's web workers.\n *\n * Bundler-agnostic on purpose: it takes the resolved `monaco` module and a\n * `getWorker` factory rather than importing either itself, so it can be\n * called from any Vite (or other bundler) entry point — see `CodeEditor.md`\n * for the Storybook preview and host snippets that call it.\n *\n * Call this once, before the first `CodeEditor` mounts (a Vite entry point's\n * module scope runs once, which is early enough).\n */\nexport const configureCodeEditor = ({ monaco, getWorker }: ConfigureCodeEditorOptions): void => {\n loader.config({ monaco });\n (self as unknown as { MonacoEnvironment: Environment }).MonacoEnvironment = { getWorker };\n};\n\n/** Monaco's colour keys, filled from one mode's chrome. */\nconst chromeColors = (chrome: EditorChrome) => ({\n 'editor.background': chrome.background,\n 'editor.foreground': chrome.foreground,\n 'editor.lineHighlightBackground': chrome.lineHighlight,\n 'editorLineNumber.foreground': chrome.lineNumber,\n 'editorIndentGuide.background': chrome.gutterBorder,\n 'editor.selectionBackground': chrome.selection,\n});\n\nconst customLightTheme = (chrome: EditorChrome) => ({\n base: 'vs' as const,\n inherit: true,\n rules: [\n { token: 'comment', foreground: '6A737D', fontStyle: 'italic' },\n { token: 'keyword', foreground: 'D73A49' },\n { token: 'string', foreground: '032F62' },\n { token: 'number', foreground: '005CC5' },\n ],\n colors: chromeColors(chrome),\n});\n\nconst customDarkTheme = (chrome: EditorChrome) => ({\n base: 'vs-dark' as const,\n inherit: true,\n rules: [\n { token: 'comment', foreground: '6A737D', fontStyle: 'italic' },\n { token: 'keyword', foreground: 'F97583' },\n { token: 'string', foreground: '9ECBFF' },\n { token: 'number', foreground: '79B8FF' },\n ],\n colors: chromeColors(chrome),\n});\n\n// Main component\nconst AUTO_FORMAT_DELAY_MS = 100;\n\nexport const registerEditorThemes = (monaco: Monaco, theme: Theme) => {\n const chrome = uiInk(theme).codeEditor;\n monaco.editor.defineTheme('custom-light', customLightTheme(chrome.light));\n monaco.editor.defineTheme('custom-dark', customDarkTheme(chrome.dark));\n};\n\n// Best-effort: a Monaco build without the TypeScript worker (as in jsdom) throws\n// here, and the editor is still usable without it.\nexport const configureTypeScriptDefaults = (monaco: Monaco) => {\n try {\n const tsLanguage = monaco.languages\n .getLanguages()\n .find((language) => language.id === 'typescript');\n\n if (!tsLanguage) return;\n\n monaco.languages.typescript.typescriptDefaults.setCompilerOptions({\n target: monaco.languages.typescript.ScriptTarget.ES2020,\n allowNonTsExtensions: true,\n moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,\n module: monaco.languages.typescript.ModuleKind.CommonJS,\n noEmit: true,\n esModuleInterop: true,\n jsx: monaco.languages.typescript.JsxEmit.React,\n reactNamespace: 'React',\n allowJs: true,\n typeRoots: ['node_modules/@types'],\n });\n\n monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: false,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n } catch {\n // Silently handle any TypeScript configuration errors in test environments\n }\n};\n\nexport const scheduleAutoFormat = (mountedEditor: editor.IStandaloneCodeEditor, enabled: boolean) => {\n if (!enabled) return;\n\n window.setTimeout(() => {\n mountedEditor.getAction('editor.action.formatDocument')?.run();\n }, AUTO_FORMAT_DELAY_MS);\n};\n\nexport const registerSaveShortcut = (\n mountedEditor: editor.IStandaloneCodeEditor,\n monaco: Monaco,\n onSave?: (value: string) => void,\n) => {\n mountedEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {\n onSave?.(mountedEditor.getValue());\n });\n};\n\n// 'auto' follows the MUI palette; otherwise the caller's choice wins.\nexport const resolveEditorTheme = (themeProp: string, paletteMode: string) => {\n const wantsDark = themeProp === 'auto' ? paletteMode === 'dark' : themeProp === 'dark';\n\n return wantsDark ? 'custom-dark' : 'custom-light';\n};\n\n// Monaco's options object. Only the first five entries vary with our props; the\n// rest are fixed editor preferences.\n"],"mappings":";;;;;AACA,SAAS,cAA2B;AAqC7B,IAAM,sBAAsB,CAAC,EAAE,QAAQ,UAAU,MAAwC;AAC9F,SAAO,OAAO,EAAE,OAAO,CAAC;AACxB,EAAC,KAAuD,oBAAoB,EAAE,UAAU;AAC1F;AAGA,IAAM,eAAe,CAAC,YAA0B;AAAA,EAC9C,qBAAqB,OAAO;AAAA,EAC5B,qBAAqB,OAAO;AAAA,EAC5B,kCAAkC,OAAO;AAAA,EACzC,+BAA+B,OAAO;AAAA,EACtC,gCAAgC,OAAO;AAAA,EACvC,8BAA8B,OAAO;AACvC;AAEA,IAAM,mBAAmB,CAAC,YAA0B;AAAA,EAClD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,EAAE,OAAO,WAAW,YAAY,UAAU,WAAW,SAAS;AAAA,IAC9D,EAAE,OAAO,WAAW,YAAY,SAAS;AAAA,IACzC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,IACxC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,EAC1C;AAAA,EACA,QAAQ,aAAa,MAAM;AAC7B;AAEA,IAAM,kBAAkB,CAAC,YAA0B;AAAA,EACjD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,EAAE,OAAO,WAAW,YAAY,UAAU,WAAW,SAAS;AAAA,IAC9D,EAAE,OAAO,WAAW,YAAY,SAAS;AAAA,IACzC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,IACxC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,EAC1C;AAAA,EACA,QAAQ,aAAa,MAAM;AAC7B;AAGA,IAAM,uBAAuB;AAEtB,IAAM,uBAAuB,CAAC,QAAgB,UAAiB;AACpE,QAAM,SAAS,MAAM,KAAK,EAAE;AAC5B,SAAO,OAAO,YAAY,gBAAgB,iBAAiB,OAAO,KAAK,CAAC;AACxE,SAAO,OAAO,YAAY,eAAe,gBAAgB,OAAO,IAAI,CAAC;AACvE;AAIO,IAAM,8BAA8B,CAAC,WAAmB;AAC7D,MAAI;AACF,UAAM,aAAa,OAAO,UACvB,aAAa,EACb,KAAK,CAAC,aAAa,SAAS,OAAO,YAAY;AAElD,QAAI,CAAC,WAAY;AAEjB,WAAO,UAAU,WAAW,mBAAmB,mBAAmB;AAAA,MAChE,QAAQ,OAAO,UAAU,WAAW,aAAa;AAAA,MACjD,sBAAsB;AAAA,MACtB,kBAAkB,OAAO,UAAU,WAAW,qBAAqB;AAAA,MACnE,QAAQ,OAAO,UAAU,WAAW,WAAW;AAAA,MAC/C,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,KAAK,OAAO,UAAU,WAAW,QAAQ;AAAA,MACzC,gBAAgB;AAAA,MAChB,SAAS;AAAA,MACT,WAAW,CAAC,qBAAqB;AAAA,IACnC,CAAC;AAED,WAAO,UAAU,WAAW,mBAAmB,sBAAsB;AAAA,MACnE,sBAAsB;AAAA,MACtB,oBAAoB;AAAA,MACpB,yBAAyB;AAAA,IAC3B,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;AAEO,IAAM,qBAAqB,CAAC,eAA6C,YAAqB;AACnG,MAAI,CAAC,QAAS;AAEd,SAAO,WAAW,MAAM;AACtB,kBAAc,UAAU,8BAA8B,GAAG,IAAI;AAAA,EAC/D,GAAG,oBAAoB;AACzB;AAEO,IAAM,uBAAuB,CAClC,eACA,QACA,WACG;AACH,gBAAc,WAAW,OAAO,OAAO,UAAU,OAAO,QAAQ,MAAM,MAAM;AAC1E,aAAS,cAAc,SAAS,CAAC;AAAA,EACnC,CAAC;AACH;AAGO,IAAM,qBAAqB,CAAC,WAAmB,gBAAwB;AAC5E,QAAM,YAAY,cAAc,SAAS,gBAAgB,SAAS,cAAc;AAEhF,SAAO,YAAY,gBAAgB;AACrC;","names":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-IDMG332I.js.map
@@ -4,7 +4,7 @@ import {
4
4
  registerSaveShortcut,
5
5
  resolveEditorTheme,
6
6
  scheduleAutoFormat
7
- } from "./chunk-HD6ZNARS.js";
7
+ } from "./chunk-5F5Q6VJ2.js";
8
8
 
9
9
  // src/components/form/CodeEditor/CodeEditor.hooks.ts
10
10
  import { useTheme } from "@mui/material/styles/index.js";
@@ -79,4 +79,4 @@ var useCodeEditor = ({
79
79
  export {
80
80
  useCodeEditor
81
81
  };
82
- //# sourceMappingURL=chunk-QG73YT6D.js.map
82
+ //# sourceMappingURL=chunk-L36S7YJB.js.map
@@ -74,14 +74,14 @@ function useGhostFlagReset(justCompletedGhost, setJustCompletedGhost) {
74
74
  return () => clearTimeout(timer);
75
75
  }, [justCompletedGhost, setJustCompletedGhost]);
76
76
  }
77
- function useLoadingOpen(isLoading, inputValue, disabled, setOpen, setActiveIndex) {
77
+ function useLoadingOpen(isLoading, inputValue, disabled, userClosedDropdown, setOpen, setActiveIndex) {
78
78
  useEffect(() => {
79
- if (isLoading && inputValue.trim().length > 0 && !disabled) setOpen(true);
79
+ if (isLoading && inputValue.trim().length > 0 && !disabled && !userClosedDropdown) setOpen(true);
80
80
  if (disabled) {
81
81
  setOpen(false);
82
82
  setActiveIndex(-1);
83
83
  }
84
- }, [isLoading, inputValue, disabled, setOpen, setActiveIndex]);
84
+ }, [isLoading, inputValue, disabled, userClosedDropdown, setOpen, setActiveIndex]);
85
85
  }
86
86
  function maybeAutoOpen(a, hasResults) {
87
87
  const canAutoOpen = a.inputValue.trim() && a.isInputFocused && !a.composition && !a.justCompletedGhost && !a.userClosedDropdown;
@@ -160,20 +160,21 @@ function commitSingleSelect(item, p, s, onChange) {
160
160
  s.setInputValue(label);
161
161
  onChange(label);
162
162
  }
163
+ function commitPick(item, linkUrl, p, s, onChange) {
164
+ if (linkUrl !== null) (p.openLink ?? defaultOpenLink)(linkUrl, item);
165
+ else if (p.multiple) commitMultiSelect(item, p, s, onChange);
166
+ else commitSingleSelect(item, p, s, onChange);
167
+ }
163
168
  function runSelectItem(item, p, s, onChange) {
164
169
  const url = (p.getUrl ?? defaultGetUrl)(item);
165
170
  const isLink = (p.getSuggestionType ?? defaultGetSuggestionType)(item) === "link" && Boolean(url);
166
- if (isLink) {
167
- (p.openLink ?? defaultOpenLink)(url, item);
168
- } else if (p.multiple) {
169
- commitMultiSelect(item, p, s, onChange);
170
- } else {
171
- commitSingleSelect(item, p, s, onChange);
172
- }
171
+ const isSingleSelectPick = isLink || !p.multiple;
172
+ commitPick(item, isLink ? url : null, p, s, onChange);
173
173
  s.setOpen(false);
174
174
  s.setActiveIndex(-1);
175
175
  p.onSelect?.(item);
176
176
  s.inputRef.current?.focus();
177
+ if (isSingleSelectPick) s.setUserClosedDropdown(true);
177
178
  }
178
179
  function buildKeyContext(p, s, selectItem, onChange) {
179
180
  return {
@@ -213,7 +214,14 @@ function useAutocomplete(p) {
213
214
  useDebounceCleanup(s.debounceRef);
214
215
  useScrollActiveIntoView(s.activeIndex, optionIdPrefix, s.listRef);
215
216
  useGhostFlagReset(s.justCompletedGhost, s.setJustCompletedGhost);
216
- useLoadingOpen(Boolean(p.isLoading), s.inputValue, Boolean(p.disabled), s.setOpen, s.setActiveIndex);
217
+ useLoadingOpen(
218
+ Boolean(p.isLoading),
219
+ s.inputValue,
220
+ Boolean(p.disabled),
221
+ s.userClosedDropdown,
222
+ s.setOpen,
223
+ s.setActiveIndex
224
+ );
217
225
  useLocalFilter(p, s);
218
226
  useGhostText(p, s);
219
227
  const selectItem = (item) => runSelectItem(item, p, s, debouncedOnChange);
@@ -258,4 +266,4 @@ function useAutocomplete(p) {
258
266
  export {
259
267
  useAutocomplete
260
268
  };
261
- //# sourceMappingURL=chunk-HBRKA67N.js.map
269
+ //# sourceMappingURL=chunk-M4P7NS2L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/form/Autocomplete/useAutocomplete.ts"],"sourcesContent":["import { useEffect, useId, useRef, useState } from 'react';\n\nimport {\n defaultGetKey,\n defaultGetLabel,\n defaultGetSuggestionType,\n defaultGetUrl,\n defaultOpenLink,\n filterSuggestions,\n firstGhostSuggestion,\n type MatchMode,\n} from './Autocomplete.helpers';\nimport { handleAutocompleteKey, type KeyContext } from './Autocomplete.keys';\nimport type { AutocompleteProps } from './Autocomplete.types';\n\ntype Setter<V> = React.Dispatch<React.SetStateAction<V>>;\n\n/** All mutable state + refs for one Autocomplete instance. */\ninterface AutocompleteState<T> {\n open: boolean;\n setOpen: Setter<boolean>;\n activeIndex: number;\n setActiveIndex: Setter<number>;\n ghost: string;\n setGhost: Setter<string>;\n inputValue: string;\n setInputValue: Setter<string>;\n composition: boolean;\n setComposition: Setter<boolean>;\n filteredSuggestions: T[];\n setFilteredSuggestions: Setter<T[]>;\n isInputFocused: boolean;\n setIsInputFocused: Setter<boolean>;\n justCompletedGhost: boolean;\n setJustCompletedGhost: Setter<boolean>;\n userClosedDropdown: boolean;\n setUserClosedDropdown: Setter<boolean>;\n inputRef: React.RefObject<HTMLInputElement | null>;\n listRef: React.RefObject<HTMLUListElement | null>;\n debounceRef: React.RefObject<number | undefined>;\n}\n\nfunction useAutocompleteState<T>(value: string, suggestions: T[]): AutocompleteState<T> {\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [ghost, setGhost] = useState('');\n const [inputValue, setInputValue] = useState(value);\n const [composition, setComposition] = useState(false);\n const [filteredSuggestions, setFilteredSuggestions] = useState<T[]>(suggestions);\n const [isInputFocused, setIsInputFocused] = useState(false);\n const [justCompletedGhost, setJustCompletedGhost] = useState(false);\n const [userClosedDropdown, setUserClosedDropdown] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLUListElement | null>(null);\n const debounceRef = useRef<number | undefined>(undefined);\n return {\n open, setOpen, activeIndex, setActiveIndex, ghost, setGhost, inputValue, setInputValue,\n composition, setComposition, filteredSuggestions, setFilteredSuggestions, isInputFocused,\n setIsInputFocused, justCompletedGhost, setJustCompletedGhost, userClosedDropdown,\n setUserClosedDropdown, inputRef, listRef, debounceRef,\n };\n}\n\n// ---- effects (one tiny hook each; explicit params keep deps complete) --------\n\nfunction useValueSync(value: string, setInputValue: Setter<string>): void {\n useEffect(() => setInputValue(value), [value, setInputValue]);\n}\n\nfunction useDebounceCleanup(debounceRef: React.RefObject<number | undefined>): void {\n useEffect(\n () => () => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current);\n },\n [debounceRef],\n );\n}\n\nfunction useScrollActiveIntoView(\n activeIndex: number,\n optionIdPrefix: string,\n listRef: React.RefObject<HTMLUListElement | null>,\n): void {\n useEffect(() => {\n if (activeIndex < 0 || !listRef.current) return;\n document\n .getElementById(`${optionIdPrefix}-${activeIndex}`)\n ?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, optionIdPrefix, listRef]);\n}\n\nfunction useGhostFlagReset(justCompletedGhost: boolean, setJustCompletedGhost: Setter<boolean>): void {\n useEffect(() => {\n if (!justCompletedGhost) return;\n const timer = setTimeout(() => setJustCompletedGhost(false), 50);\n return () => clearTimeout(timer);\n }, [justCompletedGhost, setJustCompletedGhost]);\n}\n\nfunction useLoadingOpen(\n isLoading: boolean,\n inputValue: string,\n disabled: boolean,\n userClosedDropdown: boolean,\n setOpen: Setter<boolean>,\n setActiveIndex: Setter<number>,\n): void {\n useEffect(() => {\n if (isLoading && inputValue.trim().length > 0 && !disabled && !userClosedDropdown) setOpen(true);\n if (disabled) {\n setOpen(false);\n setActiveIndex(-1);\n }\n }, [isLoading, inputValue, disabled, userClosedDropdown, setOpen, setActiveIndex]);\n}\n\n/** Inputs to the auto-open check, all primitive/stable so effect deps stay complete. */\ninterface AutoOpenArgs {\n inputValue: string;\n isInputFocused: boolean;\n composition: boolean;\n justCompletedGhost: boolean;\n userClosedDropdown: boolean;\n activeIndex: number;\n setOpen: Setter<boolean>;\n setActiveIndex: Setter<number>;\n}\n\n/** Auto-open the dropdown once local filtering has a fresh result set. */\nfunction maybeAutoOpen(a: AutoOpenArgs, hasResults: boolean): void {\n const canAutoOpen =\n a.inputValue.trim() &&\n a.isInputFocused &&\n !a.composition &&\n !a.justCompletedGhost &&\n !a.userClosedDropdown;\n if (!canAutoOpen) return;\n a.setOpen(true);\n if (hasResults && a.activeIndex === -1) a.setActiveIndex(0);\n}\n\nfunction useLocalFilter<T>(p: AutocompleteProps<T>, s: AutocompleteState<T>): void {\n const propSuggestions = p.suggestions;\n const getLabel = p.getLabel ?? defaultGetLabel;\n const matchMode: MatchMode = p.matchMode ?? 'contains';\n const async = Boolean(p.async);\n const {\n inputValue, isInputFocused, composition, justCompletedGhost, userClosedDropdown, activeIndex,\n setFilteredSuggestions, setOpen, setActiveIndex,\n } = s;\n useEffect(() => {\n const suggestions = propSuggestions ?? [];\n if (async || !inputValue) {\n setFilteredSuggestions(suggestions);\n return;\n }\n const filtered = filterSuggestions(suggestions, inputValue, matchMode, getLabel);\n setFilteredSuggestions(filtered);\n maybeAutoOpen(\n { inputValue, isInputFocused, composition, justCompletedGhost, userClosedDropdown, activeIndex, setOpen, setActiveIndex },\n filtered.length > 0,\n );\n }, [\n propSuggestions, inputValue, async, getLabel, matchMode, isInputFocused, composition,\n justCompletedGhost, userClosedDropdown, activeIndex, setFilteredSuggestions, setOpen, setActiveIndex,\n ]);\n}\n\nfunction useGhostText<T>(p: AutocompleteProps<T>, s: AutocompleteState<T>): void {\n const getLabel = p.getLabel ?? defaultGetLabel;\n const getType = p.getSuggestionType ?? defaultGetSuggestionType;\n const showGhost = p.showGhostText ?? true;\n const { inputValue, filteredSuggestions, isInputFocused, composition, setGhost } = s;\n useEffect(() => {\n if (!inputValue || !isInputFocused || composition || !showGhost) {\n setGhost('');\n return;\n }\n const first = firstGhostSuggestion(filteredSuggestions, inputValue, getLabel, getType);\n setGhost(first ? getLabel(first).slice(inputValue.length) : '');\n }, [inputValue, filteredSuggestions, isInputFocused, composition, showGhost, getLabel, getType, setGhost]);\n}\n\n// ---- selection (split by mode to keep each function under the complexity bar) -\n\nfunction commitMultiSelect<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const getKey = p.getKey ?? defaultGetKey;\n const current = p.selectedItems ?? [];\n if (!current.some((sel) => getKey(sel) === getKey(item))) p.onSelectedItemsChange?.([...current, item]);\n s.setInputValue('');\n onChange('');\n s.setUserClosedDropdown(false);\n}\n\nfunction commitSingleSelect<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const label = (p.getLabel ?? defaultGetLabel)(item);\n s.setInputValue(label);\n onChange(label);\n}\n\n/** Apply a pick: open a link suggestion, or commit a search one to the input. */\nfunction commitPick<T>(\n item: T,\n linkUrl: string | null,\n p: AutocompleteProps<T>,\n s: AutocompleteState<T>,\n onChange: (v: string) => void,\n): void {\n if (linkUrl !== null) (p.openLink ?? defaultOpenLink)(linkUrl, item);\n else if (p.multiple) commitMultiSelect(item, p, s, onChange);\n else commitSingleSelect(item, p, s, onChange);\n}\n\nfunction runSelectItem<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const url = (p.getUrl ?? defaultGetUrl)(item);\n const isLink = (p.getSuggestionType ?? defaultGetSuggestionType)(item) === 'link' && Boolean(url);\n // A single-select pick (search or link) ends the current search: the list\n // stays closed until the user types again. `multiple` mode is unchanged —\n // commitMultiSelect already clears inputValue and resets the flag itself,\n // so the empty-input branch of the filter effect keeps the list closed.\n const isSingleSelectPick = isLink || !p.multiple;\n commitPick(item, isLink ? (url as string) : null, p, s, onChange);\n s.setOpen(false);\n s.setActiveIndex(-1);\n p.onSelect?.(item);\n s.inputRef.current?.focus();\n // Set LAST so a re-fired `onFocus` cannot clear the flag. The close itself\n // relies on the input never blurring during a pick (the option's\n // `onMouseDown` preventDefault, and Enter keeps focus): `onFocus` reopens a\n // non-empty input directly, without reading this flag.\n if (isSingleSelectPick) s.setUserClosedDropdown(true);\n}\n\nfunction buildKeyContext<T>(\n p: AutocompleteProps<T>,\n s: AutocompleteState<T>,\n selectItem: (item: T) => void,\n onChange: (v: string) => void,\n): KeyContext<T> {\n return {\n open: s.open, activeIndex: s.activeIndex, filteredSuggestions: s.filteredSuggestions,\n maxVisibleItems: p.maxVisibleItems ?? 10, allowFreeText: p.allowFreeText ?? true,\n inputValue: s.inputValue, ghost: s.ghost, isInputFocused: s.isInputFocused,\n multiple: Boolean(p.multiple), selectedItems: p.selectedItems ?? [],\n getLabel: p.getLabel ?? defaultGetLabel,\n getSuggestionType: p.getSuggestionType ?? defaultGetSuggestionType,\n setOpen: s.setOpen, setActiveIndex: s.setActiveIndex, setUserClosedDropdown: s.setUserClosedDropdown,\n setInputValue: s.setInputValue, setGhost: s.setGhost, setJustCompletedGhost: s.setJustCompletedGhost,\n debouncedOnChange: onChange, selectItem, onSelectedItemsChange: p.onSelectedItemsChange,\n };\n}\n\n/** The full view-model the presentational component renders. */\nexport interface AutocompleteView<T> {\n id: string;\n listId: string;\n optionIdPrefix: string;\n state: AutocompleteState<T>;\n visibleSuggestions: T[];\n activeDescendant: string | undefined;\n selectItem: (item: T) => void;\n removeSelectedItem: (item: T) => void;\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onFocus: () => void;\n onBlur: () => void;\n onClickAway: () => void;\n}\n\n/** Wire state, effects, and (plain, per-render) handlers for the Autocomplete component. */\nexport function useAutocomplete<T>(p: AutocompleteProps<T>): AutocompleteView<T> {\n const componentId = useId();\n const id = p.id || componentId;\n const optionIdPrefix = `${id}-option`;\n const s = useAutocompleteState<T>(p.value, p.suggestions ?? []);\n\n const debouncedOnChange = (val: string): void => {\n if (s.debounceRef.current) window.clearTimeout(s.debounceRef.current);\n s.debounceRef.current = window.setTimeout(() => p.onChange(val), p.debounceMs ?? 150);\n };\n\n useValueSync(p.value, s.setInputValue);\n useDebounceCleanup(s.debounceRef);\n useScrollActiveIntoView(s.activeIndex, optionIdPrefix, s.listRef);\n useGhostFlagReset(s.justCompletedGhost, s.setJustCompletedGhost);\n useLoadingOpen(\n Boolean(p.isLoading),\n s.inputValue,\n Boolean(p.disabled),\n s.userClosedDropdown,\n s.setOpen,\n s.setActiveIndex,\n );\n useLocalFilter(p, s);\n useGhostText(p, s);\n\n const selectItem = (item: T): void => runSelectItem(item, p, s, debouncedOnChange);\n\n return {\n id,\n listId: `${id}-listbox`,\n optionIdPrefix,\n state: s,\n visibleSuggestions: s.filteredSuggestions.slice(0, p.maxVisibleItems ?? 10),\n activeDescendant: s.activeIndex >= 0 ? `${optionIdPrefix}-${s.activeIndex}` : undefined,\n selectItem,\n removeSelectedItem: (item: T): void => {\n const getKey = p.getKey ?? defaultGetKey;\n p.onSelectedItemsChange?.((p.selectedItems ?? []).filter((sel) => getKey(sel) !== getKey(item)));\n s.inputRef.current?.focus();\n },\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>): void =>\n handleAutocompleteKey(e, s.composition, buildKeyContext(p, s, selectItem, debouncedOnChange)),\n onInputChange: (e: React.ChangeEvent<HTMLInputElement>): void => {\n s.setInputValue(e.target.value);\n debouncedOnChange(e.target.value);\n if (!s.open || s.filteredSuggestions.length === 0) s.setActiveIndex(-1);\n s.setUserClosedDropdown(false);\n },\n onFocus: (): void => {\n s.setIsInputFocused(true);\n s.setUserClosedDropdown(false);\n if (!s.inputValue.trim()) return;\n s.setOpen(true);\n if (s.filteredSuggestions.length > 0 && s.activeIndex === -1) s.setActiveIndex(0);\n },\n onBlur: (): void => {\n window.setTimeout(() => s.setIsInputFocused(false), 150);\n },\n onClickAway: (): void => {\n s.setOpen(false);\n s.setActiveIndex(-1);\n s.setUserClosedDropdown(true);\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useAutocomplete
3
- } from "./chunk-HBRKA67N.js";
3
+ } from "./chunk-M4P7NS2L.js";
4
4
  import {
5
5
  AutocompleteInput,
6
6
  ChipList,
@@ -131,4 +131,4 @@ export {
131
131
  Autocomplete,
132
132
  Autocomplete_default
133
133
  };
134
- //# sourceMappingURL=chunk-DQZCQV2C.js.map
134
+ //# sourceMappingURL=chunk-Y6G4I42P.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useCodeEditor
3
- } from "./chunk-QG73YT6D.js";
3
+ } from "./chunk-L36S7YJB.js";
4
4
  import {
5
5
  makeTestId,
6
6
  resolveCodeEditorProps
@@ -178,4 +178,4 @@ var CodeEditor = (componentProps) => {
178
178
  export {
179
179
  CodeEditor
180
180
  };
181
- //# sourceMappingURL=chunk-4Y6W7BT4.js.map
181
+ //# sourceMappingURL=chunk-YQCRQHVU.js.map
@@ -2,8 +2,8 @@ import "../chunk-2LXHUGYB.js";
2
2
  import {
3
3
  Autocomplete,
4
4
  Autocomplete_default
5
- } from "../chunk-DQZCQV2C.js";
6
- import "../chunk-HBRKA67N.js";
5
+ } from "../chunk-Y6G4I42P.js";
6
+ import "../chunk-M4P7NS2L.js";
7
7
  import "../chunk-H6AWKLOV.js";
8
8
  import "../chunk-PELRSZFU.js";
9
9
  import "../chunk-JXS56EW5.js";
@@ -1,11 +1,13 @@
1
- import "../chunk-JEBPCAWD.js";
1
+ import "../chunk-IDMG332I.js";
2
2
  import {
3
3
  CodeEditor
4
- } from "../chunk-4Y6W7BT4.js";
5
- import "../chunk-QG73YT6D.js";
4
+ } from "../chunk-YQCRQHVU.js";
5
+ import "../chunk-L36S7YJB.js";
6
6
  import "../chunk-X3OWMTLO.js";
7
7
  import "../chunk-3TVUW7QE.js";
8
- import "../chunk-HD6ZNARS.js";
8
+ import {
9
+ configureCodeEditor
10
+ } from "../chunk-5F5Q6VJ2.js";
9
11
  import "../chunk-GDN2LUTZ.js";
10
12
  import "../chunk-7FDU3FIN.js";
11
13
  import "../chunk-EPEJMTCQ.js";
@@ -16,6 +18,7 @@ import "../chunk-N3GAFIXG.js";
16
18
  import "../chunk-YKCAJ2TN.js";
17
19
  import "../chunk-PZ5AY32C.js";
18
20
  export {
19
- CodeEditor
21
+ CodeEditor,
22
+ configureCodeEditor
20
23
  };
21
24
  //# sourceMappingURL=CodeEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAutocomplete.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Autocomplete/useAutocomplete.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,KAAK,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD,8DAA8D;AAC9D,UAAU,iBAAiB,CAAC,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,mBAAmB,EAAE,CAAC,EAAE,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAClD,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAClD;AAkMD,gEAAgE;AAChE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC5B,kBAAkB,EAAE,CAAC,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,kBAAkB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC9D,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAChE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CA0D/E"}
1
+ {"version":3,"file":"useAutocomplete.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Autocomplete/useAutocomplete.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,KAAK,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD,8DAA8D;AAC9D,UAAU,iBAAiB,CAAC,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,mBAAmB,EAAE,CAAC,EAAE,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAClD,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAClD;AAoND,gEAAgE;AAChE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC5B,kBAAkB,EAAE,CAAC,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,kBAAkB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC9D,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAChE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAiE/E"}
@@ -1,6 +1,36 @@
1
1
  import type { Theme } from '@mui/material/styles/index.js';
2
- import type { Monaco } from '@monaco-editor/react';
3
- import type { editor } from 'monaco-editor';
2
+ import { type Monaco } from '@monaco-editor/react';
3
+ import type { editor, Environment } from 'monaco-editor';
4
+ export interface ConfigureCodeEditorOptions {
5
+ /**
6
+ * The `monaco-editor` module the host's own bundler resolved, e.g.
7
+ * `import * as monaco from 'monaco-editor'`. Handing it to the loader is
8
+ * what stops `@monaco-editor/react` fetching its own copy from
9
+ * `cdn.jsdelivr.net` at runtime — see `loader.config` below.
10
+ */
11
+ monaco: Monaco;
12
+ /**
13
+ * Monaco's web-worker factory. The package cannot supply this itself: wiring
14
+ * a worker needs a bundler-specific import (Vite's `?worker` suffix, or the
15
+ * equivalent in another bundler), and this package is built by tsup/esbuild,
16
+ * which does not understand that suffix. The host's own Vite (or other)
17
+ * entry point builds this from its own worker imports and passes it here.
18
+ */
19
+ getWorker: NonNullable<Environment['getWorker']>;
20
+ }
21
+ /**
22
+ * Points `@monaco-editor/react` at the host's own installed Monaco instead of
23
+ * its default CDN loader, and wires up Monaco's web workers.
24
+ *
25
+ * Bundler-agnostic on purpose: it takes the resolved `monaco` module and a
26
+ * `getWorker` factory rather than importing either itself, so it can be
27
+ * called from any Vite (or other bundler) entry point — see `CodeEditor.md`
28
+ * for the Storybook preview and host snippets that call it.
29
+ *
30
+ * Call this once, before the first `CodeEditor` mounts (a Vite entry point's
31
+ * module scope runs once, which is early enough).
32
+ */
33
+ export declare const configureCodeEditor: ({ monaco, getWorker }: ConfigureCodeEditorOptions) => void;
4
34
  export declare const registerEditorThemes: (monaco: Monaco, theme: Theme) => void;
5
35
  export declare const configureTypeScriptDefaults: (monaco: Monaco) => void;
6
36
  export declare const scheduleAutoFormat: (mountedEditor: editor.IStandaloneCodeEditor, enabled: boolean) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"CodeEditor.monaco.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/CodeEditor/CodeEditor.monaco.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AA2C5C,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,EAAE,OAAO,KAAK,SAIhE,CAAC;AAIF,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,SA6BzD,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,eAAe,MAAM,CAAC,qBAAqB,EAAE,SAAS,OAAO,SAM/F,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,eAAe,MAAM,CAAC,qBAAqB,EAC3C,QAAQ,MAAM,EACd,SAAS,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,SAKjC,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,EAAE,aAAa,MAAM,mCAIxE,CAAC"}
1
+ {"version":3,"file":"CodeEditor.monaco.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/CodeEditor/CodeEditor.monaco.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAMzD,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAAI,uBAAuB,0BAA0B,KAAG,IAGvF,CAAC;AAuCF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,EAAE,OAAO,KAAK,SAIhE,CAAC;AAIF,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,SA6BzD,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,eAAe,MAAM,CAAC,qBAAqB,EAAE,SAAS,OAAO,SAM/F,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,eAAe,MAAM,CAAC,qBAAqB,EAC3C,QAAQ,MAAM,EACd,SAAS,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,SAKjC,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,EAAE,aAAa,MAAM,mCAIxE,CAAC"}
@@ -1,3 +1,5 @@
1
1
  export { CodeEditor } from './CodeEditor';
2
+ export { configureCodeEditor } from './CodeEditor.monaco';
3
+ export type { ConfigureCodeEditorOptions } from './CodeEditor.monaco';
2
4
  export type { CodeEditorProps, EditorLanguage, EditorTheme } from './CodeEditor.types';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/CodeEditor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/CodeEditor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACtE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.39.17",
3
+ "version": "6.39.19",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -101,16 +101,17 @@ function useLoadingOpen(
101
101
  isLoading: boolean,
102
102
  inputValue: string,
103
103
  disabled: boolean,
104
+ userClosedDropdown: boolean,
104
105
  setOpen: Setter<boolean>,
105
106
  setActiveIndex: Setter<number>,
106
107
  ): void {
107
108
  useEffect(() => {
108
- if (isLoading && inputValue.trim().length > 0 && !disabled) setOpen(true);
109
+ if (isLoading && inputValue.trim().length > 0 && !disabled && !userClosedDropdown) setOpen(true);
109
110
  if (disabled) {
110
111
  setOpen(false);
111
112
  setActiveIndex(-1);
112
113
  }
113
- }, [isLoading, inputValue, disabled, setOpen, setActiveIndex]);
114
+ }, [isLoading, inputValue, disabled, userClosedDropdown, setOpen, setActiveIndex]);
114
115
  }
115
116
 
116
117
  /** Inputs to the auto-open check, all primitive/stable so effect deps stay complete. */
@@ -197,20 +198,37 @@ function commitSingleSelect<T>(item: T, p: AutocompleteProps<T>, s: Autocomplete
197
198
  onChange(label);
198
199
  }
199
200
 
201
+ /** Apply a pick: open a link suggestion, or commit a search one to the input. */
202
+ function commitPick<T>(
203
+ item: T,
204
+ linkUrl: string | null,
205
+ p: AutocompleteProps<T>,
206
+ s: AutocompleteState<T>,
207
+ onChange: (v: string) => void,
208
+ ): void {
209
+ if (linkUrl !== null) (p.openLink ?? defaultOpenLink)(linkUrl, item);
210
+ else if (p.multiple) commitMultiSelect(item, p, s, onChange);
211
+ else commitSingleSelect(item, p, s, onChange);
212
+ }
213
+
200
214
  function runSelectItem<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {
201
215
  const url = (p.getUrl ?? defaultGetUrl)(item);
202
216
  const isLink = (p.getSuggestionType ?? defaultGetSuggestionType)(item) === 'link' && Boolean(url);
203
- if (isLink) {
204
- (p.openLink ?? defaultOpenLink)(url as string, item);
205
- } else if (p.multiple) {
206
- commitMultiSelect(item, p, s, onChange);
207
- } else {
208
- commitSingleSelect(item, p, s, onChange);
209
- }
217
+ // A single-select pick (search or link) ends the current search: the list
218
+ // stays closed until the user types again. `multiple` mode is unchanged —
219
+ // commitMultiSelect already clears inputValue and resets the flag itself,
220
+ // so the empty-input branch of the filter effect keeps the list closed.
221
+ const isSingleSelectPick = isLink || !p.multiple;
222
+ commitPick(item, isLink ? (url as string) : null, p, s, onChange);
210
223
  s.setOpen(false);
211
224
  s.setActiveIndex(-1);
212
225
  p.onSelect?.(item);
213
226
  s.inputRef.current?.focus();
227
+ // Set LAST so a re-fired `onFocus` cannot clear the flag. The close itself
228
+ // relies on the input never blurring during a pick (the option's
229
+ // `onMouseDown` preventDefault, and Enter keeps focus): `onFocus` reopens a
230
+ // non-empty input directly, without reading this flag.
231
+ if (isSingleSelectPick) s.setUserClosedDropdown(true);
214
232
  }
215
233
 
216
234
  function buildKeyContext<T>(
@@ -265,7 +283,14 @@ export function useAutocomplete<T>(p: AutocompleteProps<T>): AutocompleteView<T>
265
283
  useDebounceCleanup(s.debounceRef);
266
284
  useScrollActiveIntoView(s.activeIndex, optionIdPrefix, s.listRef);
267
285
  useGhostFlagReset(s.justCompletedGhost, s.setJustCompletedGhost);
268
- useLoadingOpen(Boolean(p.isLoading), s.inputValue, Boolean(p.disabled), s.setOpen, s.setActiveIndex);
286
+ useLoadingOpen(
287
+ Boolean(p.isLoading),
288
+ s.inputValue,
289
+ Boolean(p.disabled),
290
+ s.userClosedDropdown,
291
+ s.setOpen,
292
+ s.setActiveIndex,
293
+ );
269
294
  useLocalFilter(p, s);
270
295
  useGhostText(p, s);
271
296
 
@@ -348,3 +348,73 @@ test('CodeEditor has no accessibility violations', async () => {
348
348
  - `@monaco-editor/react`: Monaco Editor React wrapper
349
349
  - `@mui/material`: Material-UI components and theming
350
350
  - `@mui/icons-material`: Material-UI icons
351
+
352
+ ## Monaco setup (required in the host)
353
+
354
+ `@monaco-editor/react`'s default loader fetches Monaco from
355
+ `cdn.jsdelivr.net` at runtime — a network dependency the CDN version does not
356
+ even match (`monaco-editor` here is a `dependencies` entry, so the runtime
357
+ version is whatever the host resolves). **A host must configure it before the
358
+ first `CodeEditor` mounts**, or the editor silently depends on that CDN.
359
+
360
+ This package cannot do that wiring itself: Monaco's web workers need a
361
+ bundler-specific import (Vite's `?worker` suffix, or another bundler's
362
+ equivalent), and the package is built by tsup/esbuild, which does not
363
+ understand that suffix. Instead, `configureCodeEditor` (exported from
364
+ `@12-apps/ui/form/CodeEditor`) takes the host's own resolved `monaco` module
365
+ and a `getWorker` factory, and does the rest:
366
+
367
+ ```ts
368
+ // A Vite entry point — main.tsx, or (as here) .storybook/preview.tsx.
369
+ import * as monaco from 'monaco-editor';
370
+ import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
371
+ import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
372
+ import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
373
+ import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
374
+ import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
375
+ import { configureCodeEditor } from '@12-apps/ui/form/CodeEditor';
376
+
377
+ configureCodeEditor({
378
+ monaco,
379
+ getWorker: (_workerId, label) => {
380
+ switch (label) {
381
+ case 'json':
382
+ return new JsonWorker();
383
+ case 'css':
384
+ case 'scss':
385
+ case 'less':
386
+ return new CssWorker();
387
+ case 'html':
388
+ case 'handlebars':
389
+ case 'razor':
390
+ return new HtmlWorker();
391
+ case 'typescript':
392
+ case 'javascript':
393
+ return new TsWorker();
394
+ default:
395
+ return new EditorWorker();
396
+ }
397
+ },
398
+ });
399
+ ```
400
+
401
+ Call it once, at module scope, before any `CodeEditor` renders. This
402
+ package's own Storybook (`.storybook/preview.tsx`) calls it exactly this way,
403
+ so its stories load Monaco from `node_modules` rather than the CDN — see
404
+ `CodeEditor.monaco.ts` for `configureCodeEditor`'s implementation.
405
+
406
+ **One Monaco version.** The `monaco` module a host passes in is resolved from
407
+ its own `node_modules`, at whatever version its lockfile picked for
408
+ `monaco-editor` — keep that version aligned with this package's own
409
+ `monaco-editor` dependency (currently `^0.53.0`) so the types this package
410
+ ships describe the Monaco that actually runs.
411
+
412
+ **The CDN is still available, as an explicit opt-in** — never a silent
413
+ default. A host that would rather not bundle Monaco can call the loader
414
+ itself instead of `configureCodeEditor`:
415
+
416
+ ```ts
417
+ import { loader } from '@monaco-editor/react';
418
+
419
+ loader.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.53.0/min/vs' } });
420
+ ```
@@ -1,11 +1,46 @@
1
1
  import type { Theme } from '@mui/material/styles/index.js';
2
- import type { Monaco } from '@monaco-editor/react';
3
- import type { editor } from 'monaco-editor';
2
+ import { loader, type Monaco } from '@monaco-editor/react';
3
+ import type { editor, Environment } from 'monaco-editor';
4
4
 
5
5
  import { uiInk, type UiInk } from '../../../tokens/ink';
6
6
 
7
7
  type EditorChrome = UiInk['codeEditor']['light'];
8
8
 
9
+ export interface ConfigureCodeEditorOptions {
10
+ /**
11
+ * The `monaco-editor` module the host's own bundler resolved, e.g.
12
+ * `import * as monaco from 'monaco-editor'`. Handing it to the loader is
13
+ * what stops `@monaco-editor/react` fetching its own copy from
14
+ * `cdn.jsdelivr.net` at runtime — see `loader.config` below.
15
+ */
16
+ monaco: Monaco;
17
+ /**
18
+ * Monaco's web-worker factory. The package cannot supply this itself: wiring
19
+ * a worker needs a bundler-specific import (Vite's `?worker` suffix, or the
20
+ * equivalent in another bundler), and this package is built by tsup/esbuild,
21
+ * which does not understand that suffix. The host's own Vite (or other)
22
+ * entry point builds this from its own worker imports and passes it here.
23
+ */
24
+ getWorker: NonNullable<Environment['getWorker']>;
25
+ }
26
+
27
+ /**
28
+ * Points `@monaco-editor/react` at the host's own installed Monaco instead of
29
+ * its default CDN loader, and wires up Monaco's web workers.
30
+ *
31
+ * Bundler-agnostic on purpose: it takes the resolved `monaco` module and a
32
+ * `getWorker` factory rather than importing either itself, so it can be
33
+ * called from any Vite (or other bundler) entry point — see `CodeEditor.md`
34
+ * for the Storybook preview and host snippets that call it.
35
+ *
36
+ * Call this once, before the first `CodeEditor` mounts (a Vite entry point's
37
+ * module scope runs once, which is early enough).
38
+ */
39
+ export const configureCodeEditor = ({ monaco, getWorker }: ConfigureCodeEditorOptions): void => {
40
+ loader.config({ monaco });
41
+ (self as unknown as { MonacoEnvironment: Environment }).MonacoEnvironment = { getWorker };
42
+ };
43
+
9
44
  /** Monaco's colour keys, filled from one mode's chrome. */
10
45
  const chromeColors = (chrome: EditorChrome) => ({
11
46
  'editor.background': chrome.background,
@@ -1,2 +1,4 @@
1
1
  export { CodeEditor } from './CodeEditor';
2
+ export { configureCodeEditor } from './CodeEditor.monaco';
3
+ export type { ConfigureCodeEditorOptions } from './CodeEditor.monaco';
2
4
  export type { CodeEditorProps, EditorLanguage, EditorTheme } from './CodeEditor.types';
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/Autocomplete/useAutocomplete.ts"],"sourcesContent":["import { useEffect, useId, useRef, useState } from 'react';\n\nimport {\n defaultGetKey,\n defaultGetLabel,\n defaultGetSuggestionType,\n defaultGetUrl,\n defaultOpenLink,\n filterSuggestions,\n firstGhostSuggestion,\n type MatchMode,\n} from './Autocomplete.helpers';\nimport { handleAutocompleteKey, type KeyContext } from './Autocomplete.keys';\nimport type { AutocompleteProps } from './Autocomplete.types';\n\ntype Setter<V> = React.Dispatch<React.SetStateAction<V>>;\n\n/** All mutable state + refs for one Autocomplete instance. */\ninterface AutocompleteState<T> {\n open: boolean;\n setOpen: Setter<boolean>;\n activeIndex: number;\n setActiveIndex: Setter<number>;\n ghost: string;\n setGhost: Setter<string>;\n inputValue: string;\n setInputValue: Setter<string>;\n composition: boolean;\n setComposition: Setter<boolean>;\n filteredSuggestions: T[];\n setFilteredSuggestions: Setter<T[]>;\n isInputFocused: boolean;\n setIsInputFocused: Setter<boolean>;\n justCompletedGhost: boolean;\n setJustCompletedGhost: Setter<boolean>;\n userClosedDropdown: boolean;\n setUserClosedDropdown: Setter<boolean>;\n inputRef: React.RefObject<HTMLInputElement | null>;\n listRef: React.RefObject<HTMLUListElement | null>;\n debounceRef: React.RefObject<number | undefined>;\n}\n\nfunction useAutocompleteState<T>(value: string, suggestions: T[]): AutocompleteState<T> {\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [ghost, setGhost] = useState('');\n const [inputValue, setInputValue] = useState(value);\n const [composition, setComposition] = useState(false);\n const [filteredSuggestions, setFilteredSuggestions] = useState<T[]>(suggestions);\n const [isInputFocused, setIsInputFocused] = useState(false);\n const [justCompletedGhost, setJustCompletedGhost] = useState(false);\n const [userClosedDropdown, setUserClosedDropdown] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLUListElement | null>(null);\n const debounceRef = useRef<number | undefined>(undefined);\n return {\n open, setOpen, activeIndex, setActiveIndex, ghost, setGhost, inputValue, setInputValue,\n composition, setComposition, filteredSuggestions, setFilteredSuggestions, isInputFocused,\n setIsInputFocused, justCompletedGhost, setJustCompletedGhost, userClosedDropdown,\n setUserClosedDropdown, inputRef, listRef, debounceRef,\n };\n}\n\n// ---- effects (one tiny hook each; explicit params keep deps complete) --------\n\nfunction useValueSync(value: string, setInputValue: Setter<string>): void {\n useEffect(() => setInputValue(value), [value, setInputValue]);\n}\n\nfunction useDebounceCleanup(debounceRef: React.RefObject<number | undefined>): void {\n useEffect(\n () => () => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current);\n },\n [debounceRef],\n );\n}\n\nfunction useScrollActiveIntoView(\n activeIndex: number,\n optionIdPrefix: string,\n listRef: React.RefObject<HTMLUListElement | null>,\n): void {\n useEffect(() => {\n if (activeIndex < 0 || !listRef.current) return;\n document\n .getElementById(`${optionIdPrefix}-${activeIndex}`)\n ?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, optionIdPrefix, listRef]);\n}\n\nfunction useGhostFlagReset(justCompletedGhost: boolean, setJustCompletedGhost: Setter<boolean>): void {\n useEffect(() => {\n if (!justCompletedGhost) return;\n const timer = setTimeout(() => setJustCompletedGhost(false), 50);\n return () => clearTimeout(timer);\n }, [justCompletedGhost, setJustCompletedGhost]);\n}\n\nfunction useLoadingOpen(\n isLoading: boolean,\n inputValue: string,\n disabled: boolean,\n setOpen: Setter<boolean>,\n setActiveIndex: Setter<number>,\n): void {\n useEffect(() => {\n if (isLoading && inputValue.trim().length > 0 && !disabled) setOpen(true);\n if (disabled) {\n setOpen(false);\n setActiveIndex(-1);\n }\n }, [isLoading, inputValue, disabled, setOpen, setActiveIndex]);\n}\n\n/** Inputs to the auto-open check, all primitive/stable so effect deps stay complete. */\ninterface AutoOpenArgs {\n inputValue: string;\n isInputFocused: boolean;\n composition: boolean;\n justCompletedGhost: boolean;\n userClosedDropdown: boolean;\n activeIndex: number;\n setOpen: Setter<boolean>;\n setActiveIndex: Setter<number>;\n}\n\n/** Auto-open the dropdown once local filtering has a fresh result set. */\nfunction maybeAutoOpen(a: AutoOpenArgs, hasResults: boolean): void {\n const canAutoOpen =\n a.inputValue.trim() &&\n a.isInputFocused &&\n !a.composition &&\n !a.justCompletedGhost &&\n !a.userClosedDropdown;\n if (!canAutoOpen) return;\n a.setOpen(true);\n if (hasResults && a.activeIndex === -1) a.setActiveIndex(0);\n}\n\nfunction useLocalFilter<T>(p: AutocompleteProps<T>, s: AutocompleteState<T>): void {\n const propSuggestions = p.suggestions;\n const getLabel = p.getLabel ?? defaultGetLabel;\n const matchMode: MatchMode = p.matchMode ?? 'contains';\n const async = Boolean(p.async);\n const {\n inputValue, isInputFocused, composition, justCompletedGhost, userClosedDropdown, activeIndex,\n setFilteredSuggestions, setOpen, setActiveIndex,\n } = s;\n useEffect(() => {\n const suggestions = propSuggestions ?? [];\n if (async || !inputValue) {\n setFilteredSuggestions(suggestions);\n return;\n }\n const filtered = filterSuggestions(suggestions, inputValue, matchMode, getLabel);\n setFilteredSuggestions(filtered);\n maybeAutoOpen(\n { inputValue, isInputFocused, composition, justCompletedGhost, userClosedDropdown, activeIndex, setOpen, setActiveIndex },\n filtered.length > 0,\n );\n }, [\n propSuggestions, inputValue, async, getLabel, matchMode, isInputFocused, composition,\n justCompletedGhost, userClosedDropdown, activeIndex, setFilteredSuggestions, setOpen, setActiveIndex,\n ]);\n}\n\nfunction useGhostText<T>(p: AutocompleteProps<T>, s: AutocompleteState<T>): void {\n const getLabel = p.getLabel ?? defaultGetLabel;\n const getType = p.getSuggestionType ?? defaultGetSuggestionType;\n const showGhost = p.showGhostText ?? true;\n const { inputValue, filteredSuggestions, isInputFocused, composition, setGhost } = s;\n useEffect(() => {\n if (!inputValue || !isInputFocused || composition || !showGhost) {\n setGhost('');\n return;\n }\n const first = firstGhostSuggestion(filteredSuggestions, inputValue, getLabel, getType);\n setGhost(first ? getLabel(first).slice(inputValue.length) : '');\n }, [inputValue, filteredSuggestions, isInputFocused, composition, showGhost, getLabel, getType, setGhost]);\n}\n\n// ---- selection (split by mode to keep each function under the complexity bar) -\n\nfunction commitMultiSelect<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const getKey = p.getKey ?? defaultGetKey;\n const current = p.selectedItems ?? [];\n if (!current.some((sel) => getKey(sel) === getKey(item))) p.onSelectedItemsChange?.([...current, item]);\n s.setInputValue('');\n onChange('');\n s.setUserClosedDropdown(false);\n}\n\nfunction commitSingleSelect<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const label = (p.getLabel ?? defaultGetLabel)(item);\n s.setInputValue(label);\n onChange(label);\n}\n\nfunction runSelectItem<T>(item: T, p: AutocompleteProps<T>, s: AutocompleteState<T>, onChange: (v: string) => void): void {\n const url = (p.getUrl ?? defaultGetUrl)(item);\n const isLink = (p.getSuggestionType ?? defaultGetSuggestionType)(item) === 'link' && Boolean(url);\n if (isLink) {\n (p.openLink ?? defaultOpenLink)(url as string, item);\n } else if (p.multiple) {\n commitMultiSelect(item, p, s, onChange);\n } else {\n commitSingleSelect(item, p, s, onChange);\n }\n s.setOpen(false);\n s.setActiveIndex(-1);\n p.onSelect?.(item);\n s.inputRef.current?.focus();\n}\n\nfunction buildKeyContext<T>(\n p: AutocompleteProps<T>,\n s: AutocompleteState<T>,\n selectItem: (item: T) => void,\n onChange: (v: string) => void,\n): KeyContext<T> {\n return {\n open: s.open, activeIndex: s.activeIndex, filteredSuggestions: s.filteredSuggestions,\n maxVisibleItems: p.maxVisibleItems ?? 10, allowFreeText: p.allowFreeText ?? true,\n inputValue: s.inputValue, ghost: s.ghost, isInputFocused: s.isInputFocused,\n multiple: Boolean(p.multiple), selectedItems: p.selectedItems ?? [],\n getLabel: p.getLabel ?? defaultGetLabel,\n getSuggestionType: p.getSuggestionType ?? defaultGetSuggestionType,\n setOpen: s.setOpen, setActiveIndex: s.setActiveIndex, setUserClosedDropdown: s.setUserClosedDropdown,\n setInputValue: s.setInputValue, setGhost: s.setGhost, setJustCompletedGhost: s.setJustCompletedGhost,\n debouncedOnChange: onChange, selectItem, onSelectedItemsChange: p.onSelectedItemsChange,\n };\n}\n\n/** The full view-model the presentational component renders. */\nexport interface AutocompleteView<T> {\n id: string;\n listId: string;\n optionIdPrefix: string;\n state: AutocompleteState<T>;\n visibleSuggestions: T[];\n activeDescendant: string | undefined;\n selectItem: (item: T) => void;\n removeSelectedItem: (item: T) => void;\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onFocus: () => void;\n onBlur: () => void;\n onClickAway: () => void;\n}\n\n/** Wire state, effects, and (plain, per-render) handlers for the Autocomplete component. */\nexport function useAutocomplete<T>(p: AutocompleteProps<T>): AutocompleteView<T> {\n const componentId = useId();\n const id = p.id || componentId;\n const optionIdPrefix = `${id}-option`;\n const s = useAutocompleteState<T>(p.value, p.suggestions ?? []);\n\n const debouncedOnChange = (val: string): void => {\n if (s.debounceRef.current) window.clearTimeout(s.debounceRef.current);\n s.debounceRef.current = window.setTimeout(() => p.onChange(val), p.debounceMs ?? 150);\n };\n\n useValueSync(p.value, s.setInputValue);\n useDebounceCleanup(s.debounceRef);\n useScrollActiveIntoView(s.activeIndex, optionIdPrefix, s.listRef);\n useGhostFlagReset(s.justCompletedGhost, s.setJustCompletedGhost);\n useLoadingOpen(Boolean(p.isLoading), s.inputValue, Boolean(p.disabled), s.setOpen, s.setActiveIndex);\n useLocalFilter(p, s);\n useGhostText(p, s);\n\n const selectItem = (item: T): void => runSelectItem(item, p, s, debouncedOnChange);\n\n return {\n id,\n listId: `${id}-listbox`,\n optionIdPrefix,\n state: s,\n visibleSuggestions: s.filteredSuggestions.slice(0, p.maxVisibleItems ?? 10),\n activeDescendant: s.activeIndex >= 0 ? `${optionIdPrefix}-${s.activeIndex}` : undefined,\n selectItem,\n removeSelectedItem: (item: T): void => {\n const getKey = p.getKey ?? defaultGetKey;\n p.onSelectedItemsChange?.((p.selectedItems ?? []).filter((sel) => getKey(sel) !== getKey(item)));\n s.inputRef.current?.focus();\n },\n onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>): void =>\n handleAutocompleteKey(e, s.composition, buildKeyContext(p, s, selectItem, debouncedOnChange)),\n onInputChange: (e: React.ChangeEvent<HTMLInputElement>): void => {\n s.setInputValue(e.target.value);\n debouncedOnChange(e.target.value);\n if (!s.open || s.filteredSuggestions.length === 0) s.setActiveIndex(-1);\n s.setUserClosedDropdown(false);\n },\n onFocus: (): void => {\n s.setIsInputFocused(true);\n s.setUserClosedDropdown(false);\n if (!s.inputValue.trim()) return;\n s.setOpen(true);\n if (s.filteredSuggestions.length > 0 && s.activeIndex === -1) s.setActiveIndex(0);\n },\n onBlur: (): void => {\n window.setTimeout(() => s.setIsInputFocused(false), 150);\n },\n onClickAway: (): void => {\n s.setOpen(false);\n s.setActiveIndex(-1);\n s.setUserClosedDropdown(true);\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/CodeEditor/CodeEditor.monaco.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles/index.js';\nimport type { Monaco } from '@monaco-editor/react';\nimport type { editor } from 'monaco-editor';\n\nimport { uiInk, type UiInk } from '../../../tokens/ink';\n\ntype EditorChrome = UiInk['codeEditor']['light'];\n\n/** Monaco's colour keys, filled from one mode's chrome. */\nconst chromeColors = (chrome: EditorChrome) => ({\n 'editor.background': chrome.background,\n 'editor.foreground': chrome.foreground,\n 'editor.lineHighlightBackground': chrome.lineHighlight,\n 'editorLineNumber.foreground': chrome.lineNumber,\n 'editorIndentGuide.background': chrome.gutterBorder,\n 'editor.selectionBackground': chrome.selection,\n});\n\nconst customLightTheme = (chrome: EditorChrome) => ({\n base: 'vs' as const,\n inherit: true,\n rules: [\n { token: 'comment', foreground: '6A737D', fontStyle: 'italic' },\n { token: 'keyword', foreground: 'D73A49' },\n { token: 'string', foreground: '032F62' },\n { token: 'number', foreground: '005CC5' },\n ],\n colors: chromeColors(chrome),\n});\n\nconst customDarkTheme = (chrome: EditorChrome) => ({\n base: 'vs-dark' as const,\n inherit: true,\n rules: [\n { token: 'comment', foreground: '6A737D', fontStyle: 'italic' },\n { token: 'keyword', foreground: 'F97583' },\n { token: 'string', foreground: '9ECBFF' },\n { token: 'number', foreground: '79B8FF' },\n ],\n colors: chromeColors(chrome),\n});\n\n// Main component\nconst AUTO_FORMAT_DELAY_MS = 100;\n\nexport const registerEditorThemes = (monaco: Monaco, theme: Theme) => {\n const chrome = uiInk(theme).codeEditor;\n monaco.editor.defineTheme('custom-light', customLightTheme(chrome.light));\n monaco.editor.defineTheme('custom-dark', customDarkTheme(chrome.dark));\n};\n\n// Best-effort: a Monaco build without the TypeScript worker (as in jsdom) throws\n// here, and the editor is still usable without it.\nexport const configureTypeScriptDefaults = (monaco: Monaco) => {\n try {\n const tsLanguage = monaco.languages\n .getLanguages()\n .find((language) => language.id === 'typescript');\n\n if (!tsLanguage) return;\n\n monaco.languages.typescript.typescriptDefaults.setCompilerOptions({\n target: monaco.languages.typescript.ScriptTarget.ES2020,\n allowNonTsExtensions: true,\n moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,\n module: monaco.languages.typescript.ModuleKind.CommonJS,\n noEmit: true,\n esModuleInterop: true,\n jsx: monaco.languages.typescript.JsxEmit.React,\n reactNamespace: 'React',\n allowJs: true,\n typeRoots: ['node_modules/@types'],\n });\n\n monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: false,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n } catch {\n // Silently handle any TypeScript configuration errors in test environments\n }\n};\n\nexport const scheduleAutoFormat = (mountedEditor: editor.IStandaloneCodeEditor, enabled: boolean) => {\n if (!enabled) return;\n\n window.setTimeout(() => {\n mountedEditor.getAction('editor.action.formatDocument')?.run();\n }, AUTO_FORMAT_DELAY_MS);\n};\n\nexport const registerSaveShortcut = (\n mountedEditor: editor.IStandaloneCodeEditor,\n monaco: Monaco,\n onSave?: (value: string) => void,\n) => {\n mountedEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {\n onSave?.(mountedEditor.getValue());\n });\n};\n\n// 'auto' follows the MUI palette; otherwise the caller's choice wins.\nexport const resolveEditorTheme = (themeProp: string, paletteMode: string) => {\n const wantsDark = themeProp === 'auto' ? paletteMode === 'dark' : themeProp === 'dark';\n\n return wantsDark ? 'custom-dark' : 'custom-light';\n};\n\n// Monaco's options object. Only the first five entries vary with our props; the\n// rest are fixed editor preferences.\n"],"mappings":";;;;;AASA,IAAM,eAAe,CAAC,YAA0B;AAAA,EAC9C,qBAAqB,OAAO;AAAA,EAC5B,qBAAqB,OAAO;AAAA,EAC5B,kCAAkC,OAAO;AAAA,EACzC,+BAA+B,OAAO;AAAA,EACtC,gCAAgC,OAAO;AAAA,EACvC,8BAA8B,OAAO;AACvC;AAEA,IAAM,mBAAmB,CAAC,YAA0B;AAAA,EAClD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,EAAE,OAAO,WAAW,YAAY,UAAU,WAAW,SAAS;AAAA,IAC9D,EAAE,OAAO,WAAW,YAAY,SAAS;AAAA,IACzC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,IACxC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,EAC1C;AAAA,EACA,QAAQ,aAAa,MAAM;AAC7B;AAEA,IAAM,kBAAkB,CAAC,YAA0B;AAAA,EACjD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,EAAE,OAAO,WAAW,YAAY,UAAU,WAAW,SAAS;AAAA,IAC9D,EAAE,OAAO,WAAW,YAAY,SAAS;AAAA,IACzC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,IACxC,EAAE,OAAO,UAAU,YAAY,SAAS;AAAA,EAC1C;AAAA,EACA,QAAQ,aAAa,MAAM;AAC7B;AAGA,IAAM,uBAAuB;AAEtB,IAAM,uBAAuB,CAAC,QAAgB,UAAiB;AACpE,QAAM,SAAS,MAAM,KAAK,EAAE;AAC5B,SAAO,OAAO,YAAY,gBAAgB,iBAAiB,OAAO,KAAK,CAAC;AACxE,SAAO,OAAO,YAAY,eAAe,gBAAgB,OAAO,IAAI,CAAC;AACvE;AAIO,IAAM,8BAA8B,CAAC,WAAmB;AAC7D,MAAI;AACF,UAAM,aAAa,OAAO,UACvB,aAAa,EACb,KAAK,CAAC,aAAa,SAAS,OAAO,YAAY;AAElD,QAAI,CAAC,WAAY;AAEjB,WAAO,UAAU,WAAW,mBAAmB,mBAAmB;AAAA,MAChE,QAAQ,OAAO,UAAU,WAAW,aAAa;AAAA,MACjD,sBAAsB;AAAA,MACtB,kBAAkB,OAAO,UAAU,WAAW,qBAAqB;AAAA,MACnE,QAAQ,OAAO,UAAU,WAAW,WAAW;AAAA,MAC/C,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,KAAK,OAAO,UAAU,WAAW,QAAQ;AAAA,MACzC,gBAAgB;AAAA,MAChB,SAAS;AAAA,MACT,WAAW,CAAC,qBAAqB;AAAA,IACnC,CAAC;AAED,WAAO,UAAU,WAAW,mBAAmB,sBAAsB;AAAA,MACnE,sBAAsB;AAAA,MACtB,oBAAoB;AAAA,MACpB,yBAAyB;AAAA,IAC3B,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AACF;AAEO,IAAM,qBAAqB,CAAC,eAA6C,YAAqB;AACnG,MAAI,CAAC,QAAS;AAEd,SAAO,WAAW,MAAM;AACtB,kBAAc,UAAU,8BAA8B,GAAG,IAAI;AAAA,EAC/D,GAAG,oBAAoB;AACzB;AAEO,IAAM,uBAAuB,CAClC,eACA,QACA,WACG;AACH,gBAAc,WAAW,OAAO,OAAO,UAAU,OAAO,QAAQ,MAAM,MAAM;AAC1E,aAAS,cAAc,SAAS,CAAC;AAAA,EACnC,CAAC;AACH;AAGO,IAAM,qBAAqB,CAAC,WAAmB,gBAAwB;AAC5E,QAAM,YAAY,cAAc,SAAS,gBAAgB,SAAS,cAAc;AAEhF,SAAO,YAAY,gBAAgB;AACrC;","names":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-JEBPCAWD.js.map