@stackone/malachite 2.37.1 → 2.38.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.
Files changed (94) hide show
  1. package/COMPONENTS.md +7 -2
  2. package/dist/assets/icons/account.svg.js +2 -2
  3. package/dist/assets/icons/account.svg.js.map +1 -1
  4. package/dist/assets/icons/building.svg.js +6 -0
  5. package/dist/assets/icons/building.svg.js.map +1 -0
  6. package/dist/assets/icons/chevrons_up_down.svg.js +6 -0
  7. package/dist/assets/icons/chevrons_up_down.svg.js.map +1 -0
  8. package/dist/assets/icons/connector.svg.js +6 -0
  9. package/dist/assets/icons/connector.svg.js.map +1 -0
  10. package/dist/assets/icons/external_link.svg.js +6 -0
  11. package/dist/assets/icons/external_link.svg.js.map +1 -0
  12. package/dist/assets/icons/field_coverage.svg.js +6 -0
  13. package/dist/assets/icons/field_coverage.svg.js.map +1 -0
  14. package/dist/assets/icons/layout.svg.js +6 -0
  15. package/dist/assets/icons/layout.svg.js.map +1 -0
  16. package/dist/assets/icons/link.svg.js +6 -0
  17. package/dist/assets/icons/link.svg.js.map +1 -0
  18. package/dist/assets/icons/playground.svg.js +6 -0
  19. package/dist/assets/icons/playground.svg.js.map +1 -0
  20. package/dist/components/ActionMenu.js +139 -170
  21. package/dist/components/ActionMenu.js.map +1 -1
  22. package/dist/components/Chat/ChatModelPicker.js +64 -60
  23. package/dist/components/Chat/ChatModelPicker.js.map +1 -1
  24. package/dist/components/CustomIcons/BuildingIcon.js +16 -0
  25. package/dist/components/CustomIcons/BuildingIcon.js.map +1 -0
  26. package/dist/components/CustomIcons/ChevronsUpDownIcon.js +16 -0
  27. package/dist/components/CustomIcons/ChevronsUpDownIcon.js.map +1 -0
  28. package/dist/components/CustomIcons/ConnectorIcon.js +16 -0
  29. package/dist/components/CustomIcons/ConnectorIcon.js.map +1 -0
  30. package/dist/components/CustomIcons/ExternalLinkIcon.js +16 -0
  31. package/dist/components/CustomIcons/ExternalLinkIcon.js.map +1 -0
  32. package/dist/components/CustomIcons/FieldCoverageIcon.js +16 -0
  33. package/dist/components/CustomIcons/FieldCoverageIcon.js.map +1 -0
  34. package/dist/components/CustomIcons/LayoutIcon.js +16 -0
  35. package/dist/components/CustomIcons/LayoutIcon.js.map +1 -0
  36. package/dist/components/CustomIcons/LinkIcon.js +16 -0
  37. package/dist/components/CustomIcons/LinkIcon.js.map +1 -0
  38. package/dist/components/CustomIcons/PlaygroundIcon.js +16 -0
  39. package/dist/components/CustomIcons/PlaygroundIcon.js.map +1 -0
  40. package/dist/components/CustomIcons/index.js +303 -279
  41. package/dist/components/CustomIcons/index.js.map +1 -1
  42. package/dist/components/NavItem.js +158 -0
  43. package/dist/components/NavItem.js.map +1 -0
  44. package/dist/components/Popover.js +262 -0
  45. package/dist/components/Popover.js.map +1 -0
  46. package/dist/components/PopoverParts.js +46 -0
  47. package/dist/components/PopoverParts.js.map +1 -0
  48. package/dist/components/QueryInput.js +103 -97
  49. package/dist/components/QueryInput.js.map +1 -1
  50. package/dist/components/SearchTrigger.js +37 -0
  51. package/dist/components/SearchTrigger.js.map +1 -0
  52. package/dist/components/Sidebar.js +174 -0
  53. package/dist/components/Sidebar.js.map +1 -0
  54. package/dist/components/Tooltip.js +97 -92
  55. package/dist/components/Tooltip.js.map +1 -1
  56. package/dist/components/UsageCard.js +44 -0
  57. package/dist/components/UsageCard.js.map +1 -0
  58. package/dist/components/actionMenuKeyboard.js +23 -0
  59. package/dist/components/actionMenuKeyboard.js.map +1 -0
  60. package/dist/components/actionMenuStyles.js +83 -0
  61. package/dist/components/actionMenuStyles.js.map +1 -0
  62. package/dist/components/ariaState.js +5 -0
  63. package/dist/components/ariaState.js.map +1 -0
  64. package/dist/components/chromeStyles.js +6 -0
  65. package/dist/components/chromeStyles.js.map +1 -0
  66. package/dist/components/composeRefs.js +27 -0
  67. package/dist/components/composeRefs.js.map +1 -0
  68. package/dist/components/floatingMenuGeometry.js +74 -35
  69. package/dist/components/floatingMenuGeometry.js.map +1 -1
  70. package/dist/components/overlayBehaviour.js +90 -84
  71. package/dist/components/overlayBehaviour.js.map +1 -1
  72. package/dist/components/popoverTree.js +14 -0
  73. package/dist/components/popoverTree.js.map +1 -0
  74. package/dist/components/portalOverlay.js +28 -22
  75. package/dist/components/portalOverlay.js.map +1 -1
  76. package/dist/components/sidebarContext.js +9 -0
  77. package/dist/components/sidebarContext.js.map +1 -0
  78. package/dist/components/topLayer.js +18 -18
  79. package/dist/components/topLayer.js.map +1 -1
  80. package/dist/components/useActionMenuPosition.js +73 -0
  81. package/dist/components/useActionMenuPosition.js.map +1 -0
  82. package/dist/components/useHoverClose.js +18 -0
  83. package/dist/components/useHoverClose.js.map +1 -0
  84. package/dist/components/useLatestRef.js +11 -0
  85. package/dist/components/useLatestRef.js.map +1 -0
  86. package/dist/components/usePopoverPosition.js +62 -0
  87. package/dist/components/usePopoverPosition.js.map +1 -0
  88. package/dist/components/usePopoverTree.js +34 -0
  89. package/dist/components/usePopoverTree.js.map +1 -0
  90. package/dist/index.d.ts +387 -100
  91. package/dist/index.js +365 -335
  92. package/dist/index.js.map +1 -1
  93. package/dist/tailwind.css.js +1 -1
  94. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PopoverParts.js","sources":["../../src/components/PopoverParts.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport Tooltip from './Tooltip';\nimport { BORDER, NO_SCROLLBAR } from './chromeStyles';\nimport { FOCUS_RING_INSET } from './focusRing';\n\nexport interface PopoverHeaderProps {\n title: string;\n action?: React.ReactNode;\n}\n\nexport const PopoverHeader: React.FC<PopoverHeaderProps> = ({ title, action }) => (\n <div\n className={`flex items-center justify-between border-0 border-b border-solid ${BORDER} px-5 py-4 text-[12px] leading-[15px] font-normal text-[var(--malachite-text-dimmed,rgb(161,161,161))]`}\n >\n <span>{title}</span>\n {action}\n </div>\n);\n\nexport const PopoverList: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <div className={`flex max-h-80 flex-col gap-[2px] overflow-y-auto p-2 ${NO_SCROLLBAR}`}>\n {children}\n </div>\n);\n\nexport const PopoverSection = forwardRef<HTMLDivElement, { children: React.ReactNode }>(\n ({ children }, ref) => (\n <div ref={ref} className={`border-0 border-t border-solid ${BORDER} p-2`}>\n {children}\n </div>\n ),\n);\nPopoverSection.displayName = 'Popover.Section';\n\nexport const PopoverEmpty: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <div className=\"px-3 py-2 text-[length:var(--malachite-font-size-small,13px)] text-[var(--malachite-text-dimmed,rgb(161,161,161))] select-none\">\n {children}\n </div>\n);\n\nexport interface PopoverActionProps {\n icon: React.ReactNode;\n 'aria-label': string;\n onClick?: () => void;\n disabled?: boolean;\n tooltip?: string;\n}\n\nexport const PopoverAction: React.FC<PopoverActionProps> = ({\n icon,\n 'aria-label': ariaLabel,\n onClick,\n disabled = false,\n tooltip,\n}) => {\n const button = (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n onClick={disabled ? undefined : onClick}\n className={`m-0 inline-flex size-5 items-center justify-center rounded-[var(--malachite-radius-sm,4px)] border-0 bg-transparent p-0 transition-colors duration-150 [&_svg]:size-3! ${disabled ? 'cursor-not-allowed text-[var(--malachite-text-placeholder,rgb(187,187,187))] opacity-50' : `cursor-pointer text-[var(--malachite-text-placeholder,rgb(187,187,187))] hover:bg-[var(--malachite-pillbutton-background,rgb(241,241,241))] hover:text-[var(--malachite-text-secondary,rgb(123,123,123))]`} ${FOCUS_RING_INSET}`}\n >\n {icon}\n </button>\n );\n return tooltip ? <Tooltip text={tooltip}>{button}</Tooltip> : button;\n};\n"],"names":["PopoverHeader","title","action","jsxs","BORDER","jsx","PopoverList","children","NO_SCROLLBAR","PopoverSection","forwardRef","ref","PopoverEmpty","PopoverAction","icon","ariaLabel","onClick","disabled","tooltip","button","FOCUS_RING_INSET","Tooltip"],"mappings":";;;;;AAUO,MAAMA,IAA8C,CAAC,EAAE,OAAAC,GAAO,QAAAC,QACjE,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,WAAW,oEAAoEC,CAAM;AAAA,IAErF,UAAA;AAAA,MAAA,gBAAAC,EAAC,UAAM,UAAAJ,EAAA,CAAM;AAAA,MACZC;AAAA,IAAA;AAAA,EAAA;AACL,GAGSI,IAAuD,CAAC,EAAE,UAAAC,EAAA,MACnE,gBAAAF,EAAC,OAAA,EAAI,WAAW,wDAAwDG,CAAY,IAC/E,UAAAD,EAAA,CACL,GAGSE,IAAiBC;AAAA,EAC1B,CAAC,EAAE,UAAAH,EAAA,GAAYI,MACX,gBAAAN,EAAC,OAAA,EAAI,KAAAM,GAAU,WAAW,kCAAkCP,CAAM,QAC7D,UAAAG,EAAA,CACL;AAER;AACAE,EAAe,cAAc;AAEtB,MAAMG,IAAwD,CAAC,EAAE,UAAAL,QACpE,gBAAAF,EAAC,OAAA,EAAI,WAAU,kIACV,UAAAE,EAAA,CACL,GAWSM,IAA8C,CAAC;AAAA,EACxD,MAAAC;AAAA,EACA,cAAcC;AAAA,EACd,SAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,SAAAC;AACJ,MAAM;AACF,QAAMC,IACF,gBAAAd;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,MAAK;AAAA,MACL,cAAYU;AAAA,MACZ,iBAAeE,KAAY;AAAA,MAC3B,SAASA,IAAW,SAAYD;AAAA,MAChC,WAAW,0KAA0KC,IAAW,4FAA4F,2MAA2M,IAAIG,CAAgB;AAAA,MAE1f,UAAAN;AAAA,IAAA;AAAA,EAAA;AAGT,SAAOI,IAAU,gBAAAb,EAACgB,GAAA,EAAQ,MAAMH,GAAU,aAAO,IAAaC;AAClE;"}
@@ -1,17 +1,18 @@
1
- import { jsxs as S, jsx as d } from "react/jsx-runtime";
2
- import { useId as xt, useState as E, useRef as g, useLayoutEffect as T, useCallback as et, useEffect as bt, useInsertionEffect as wt } from "react";
1
+ import { jsxs as E, jsx as d } from "react/jsx-runtime";
2
+ import { useId as xt, useState as T, useRef as g, useCallback as F, useLayoutEffect as k, useEffect as bt, useInsertionEffect as wt } from "react";
3
3
  import { createPortal as vt } from "react-dom";
4
4
  import yt from "./Spinner.js";
5
5
  import { CONTROL_TEXT_SIZE as _, CONTROL_TEXT_SIZE_CLASS as rt } from "./controlTextSize.js";
6
6
  import { pushEscapeLayer as St } from "./escapeLayers.js";
7
7
  import { ensureMultiSelectPanelStyles as Et } from "./optionRowStyles.js";
8
- import { overlayIdentity as Tt } from "./portalOverlay.js";
9
- import { computeCaretMenuGeometry as kt } from "./queryInputGeometry.js";
10
- const Mt = {
8
+ import { useOwnedByPopover as Tt } from "./popoverTree.js";
9
+ import { overlayIdentity as kt } from "./portalOverlay.js";
10
+ import { computeCaretMenuGeometry as Mt } from "./queryInputGeometry.js";
11
+ const Lt = {
11
12
  small: "h-[var(--malachite-control-height-small,28px)] px-[10px] rounded-[var(--malachite-radius-10,10px)]",
12
13
  medium: "h-[var(--malachite-control-height-medium,32px)] px-[10px] rounded-xl",
13
14
  large: "h-[var(--malachite-control-height-large,42px)] px-[12px] rounded-[var(--malachite-radius-xxl,14px)]"
14
- }, Lt = {
15
+ }, It = {
15
16
  key: "var(--malachite-codeblock-keyword, rgb(12, 88, 174))",
16
17
  value: "var(--malachite-codeblock-string, rgb(2, 122, 66))",
17
18
  operator: "var(--malachite-codeblock-type, rgb(12, 88, 174))",
@@ -19,7 +20,7 @@ const Mt = {
19
20
  punctuation: "var(--malachite-codeblock-foreground, rgb(10, 10, 10))",
20
21
  error: "var(--malachite-text-error, rgb(237, 53, 54))",
21
22
  plain: "var(--malachite-text-primary, rgb(10, 10, 10))"
22
- }, It = {
23
+ }, Rt = {
23
24
  small: {
24
25
  fontFamily: "inherit",
25
26
  fontSize: _.small,
@@ -44,7 +45,7 @@ const Mt = {
44
45
  lineHeight: "normal",
45
46
  padding: 0
46
47
  }
47
- }, F = 220, nt = 360, ot = {
48
+ }, B = 220, nt = 360, ot = {
48
49
  display: "flex",
49
50
  alignItems: "center",
50
51
  justifyContent: "center",
@@ -52,73 +53,78 @@ const Mt = {
52
53
  padding: "10px 12px",
53
54
  color: "var(--malachite-text-dimmed, rgb(161, 161, 161))",
54
55
  whiteSpace: "nowrap"
55
- }, Rt = (r) => {
56
+ }, Dt = (r) => {
56
57
  r.preventDefault();
57
- }, Dt = (r, f) => {
58
- const a = [...f.filter(
58
+ }, _t = (r, f) => {
59
+ const l = [...f.filter(
59
60
  (n) => n.start >= 0 && n.end <= r.length && n.start < n.end
60
- )].sort((n, k) => n.start - k.start), s = [];
61
+ )].sort((n, M) => n.start - M.start), s = [];
61
62
  let u = 0;
62
- for (const n of a)
63
+ for (const n of l)
63
64
  n.start < u || (s.push(n), u = n.end);
64
65
  return s;
65
- }, _t = (r, f) => {
66
+ }, Ht = (r, f) => {
66
67
  const h = [];
67
- let a = 0;
68
- for (const s of Dt(r, f))
69
- s.start > a && h.push({ start: a, end: s.start, kind: "plain" }), h.push(s), a = s.end;
70
- return a < r.length && h.push({ start: a, end: r.length, kind: "plain" }), h;
71
- }, jt = ({
68
+ let l = 0;
69
+ for (const s of _t(r, f))
70
+ s.start > l && h.push({ start: l, end: s.start, kind: "plain" }), h.push(s), l = s.end;
71
+ return l < r.length && h.push({ start: l, end: r.length, kind: "plain" }), h;
72
+ }, Zt = ({
72
73
  value: r,
73
74
  onChange: f,
74
75
  tokens: h = [],
75
- suggestions: a,
76
+ suggestions: l,
76
77
  activeRange: s,
77
78
  onAccept: u,
78
79
  onQueryContextChange: n,
79
- onSubmit: k,
80
- placeholder: B,
80
+ onSubmit: M,
81
+ placeholder: K,
81
82
  size: x = "large",
82
- disabled: M = !1,
83
- loading: L = !1,
83
+ disabled: L = !1,
84
+ loading: I = !1,
84
85
  emptyMessage: H,
85
86
  className: it = "",
86
87
  style: at,
87
88
  "aria-label": lt,
88
- "aria-labelledby": K
89
+ "aria-labelledby": U
89
90
  }) => {
90
- const W = `${xt()}-listbox`, U = (t) => `${W}-option-${t}`, [N, j] = E(!1), [Y, O] = E(() => r.length), [st, $] = E(0), [ct, A] = E(!1), [i, Z] = E(null), b = g(null), C = g(null), G = g(null), I = g(null), P = g([]), z = g(null), dt = Array.isArray(a), w = a ?? [], v = w.length > 0, l = N && (L || v || dt && !v && !!H) && !ct && !M, y = l && v && !L, c = v ? Math.min(st, w.length - 1) : -1;
91
- T(() => {
92
- O((t) => Math.min(t, r.length));
91
+ const W = `${xt()}-listbox`, j = (t) => `${W}-option-${t}`, [O, Y] = T(!1), [Z, N] = T(() => r.length), [st, $] = T(0), [ct, A] = T(!1), [i, C] = T(null), b = g(null), G = g(null), P = g(null), w = g(null), V = g([]), z = g(null), dt = Array.isArray(l), v = l ?? [], y = v.length > 0, a = O && (I || y || dt && !y && !!H) && !ct && !L;
92
+ Tt(
93
+ F(() => w.current, []),
94
+ a
95
+ );
96
+ const S = a && y && !I, c = y ? Math.min(st, v.length - 1) : -1;
97
+ k(() => {
98
+ N((t) => Math.min(t, r.length));
93
99
  }, [r]);
94
- const R = et(() => {
95
- const t = b.current, e = C.current;
100
+ const R = F(() => {
101
+ const t = b.current, e = G.current;
96
102
  t && e && (e.style.transform = `translateX(${-t.scrollLeft}px)`);
97
103
  }, []);
98
- T(() => {
104
+ k(() => {
99
105
  R();
100
106
  }, [r, R]);
101
- const m = et(() => {
107
+ const m = F(() => {
102
108
  var o, p, D;
103
109
  const t = b.current;
104
110
  if (!t)
105
111
  return;
106
- const e = (((o = G.current) == null ? void 0 : o.offsetWidth) ?? 0) - t.scrollLeft;
107
- Z(
108
- kt({
112
+ const e = (((o = P.current) == null ? void 0 : o.offsetWidth) ?? 0) - t.scrollLeft;
113
+ C(
114
+ Mt({
109
115
  inputRect: t.getBoundingClientRect(),
110
116
  caretOffsetPx: e,
111
- menuWidth: ((p = I.current) == null ? void 0 : p.offsetWidth) ?? F,
112
- menuHeight: ((D = I.current) == null ? void 0 : D.offsetHeight) ?? 0,
117
+ menuWidth: ((p = w.current) == null ? void 0 : p.offsetWidth) ?? B,
118
+ menuHeight: ((D = w.current) == null ? void 0 : D.offsetHeight) ?? 0,
113
119
  viewportWidth: window.innerWidth,
114
120
  viewportHeight: window.innerHeight
115
121
  })
116
122
  );
117
123
  }, []);
118
- T(() => {
119
- l ? m() : Z(null);
120
- }, [l, r, Y, a, L, m]), bt(() => {
121
- if (!l)
124
+ k(() => {
125
+ a ? m() : C(null);
126
+ }, [a, r, Z, l, I, m]), bt(() => {
127
+ if (!a)
122
128
  return;
123
129
  const t = () => m();
124
130
  window.addEventListener("scroll", t, !0), window.addEventListener("resize", t);
@@ -126,71 +132,71 @@ const Mt = {
126
132
  return () => {
127
133
  window.removeEventListener("scroll", t, !0), window.removeEventListener("resize", t), e();
128
134
  };
129
- }, [l, m]), T(() => {
135
+ }, [a, m]), k(() => {
130
136
  const t = z.current;
131
137
  if (t === null)
132
138
  return;
133
139
  z.current = null;
134
140
  const e = b.current;
135
- !e || t.value !== r || (e.setSelectionRange(t.caret, t.caret), O(t.caret), n == null || n({ value: r, caret: t.caret }), R(), m());
136
- }, [r]), T(() => {
137
- if (!y)
141
+ !e || t.value !== r || (e.setSelectionRange(t.caret, t.caret), N(t.caret), n == null || n({ value: r, caret: t.caret }), R(), m());
142
+ }, [r]), k(() => {
143
+ if (!S)
138
144
  return;
139
- const t = P.current[c], e = I.current;
145
+ const t = V.current[c], e = w.current;
140
146
  if (!t || !e)
141
147
  return;
142
148
  const o = t.offsetTop + t.offsetHeight;
143
149
  o > e.scrollTop + e.clientHeight ? e.scrollTop = o - e.clientHeight : t.offsetTop < e.scrollTop && (e.scrollTop = t.offsetTop);
144
- }, [c, y]), wt(() => {
145
- l && Et();
146
- }, [l]);
147
- const V = (t, e) => {
148
- O(e), n == null || n({ value: t, caret: e });
150
+ }, [c, S]), wt(() => {
151
+ a && Et();
152
+ }, [a]);
153
+ const q = (t, e) => {
154
+ N(e), n == null || n({ value: t, caret: e });
149
155
  }, pt = (t) => {
150
156
  const e = t.target.value;
151
- A(!1), $(0), f(e), V(e, t.target.selectionStart ?? e.length);
157
+ A(!1), $(0), f(e), q(e, t.target.selectionStart ?? e.length);
152
158
  }, ht = (t) => {
153
159
  const e = t.currentTarget;
154
- V(e.value, e.selectionStart ?? e.value.length);
160
+ q(e.value, e.selectionStart ?? e.value.length);
155
161
  }, X = (t) => {
156
- var tt;
157
- const e = ((tt = b.current) == null ? void 0 : tt.selectionStart) ?? r.length, o = s ?? { start: e, end: e }, p = Math.max(0, Math.min(o.start, r.length)), D = Math.max(p, Math.min(o.end, r.length)), J = t.insertText ?? t.label, Q = r.slice(0, p) + J + r.slice(D);
158
- z.current = { value: Q, caret: p + J.length }, f(Q), u == null || u(t);
162
+ var et;
163
+ const e = ((et = b.current) == null ? void 0 : et.selectionStart) ?? r.length, o = s ?? { start: e, end: e }, p = Math.max(0, Math.min(o.start, r.length)), D = Math.max(p, Math.min(o.end, r.length)), Q = t.insertText ?? t.label, tt = r.slice(0, p) + Q + r.slice(D);
164
+ z.current = { value: tt, caret: p + Q.length }, f(tt), u == null || u(t);
159
165
  }, ft = (t) => {
160
- if (y && (t.key === "ArrowDown" || t.key === "ArrowUp")) {
166
+ if (S && (t.key === "ArrowDown" || t.key === "ArrowUp")) {
161
167
  t.preventDefault();
162
- const o = w.length;
168
+ const o = v.length;
163
169
  $(
164
170
  t.key === "ArrowDown" ? (c + 1) % o : (c - 1 + o) % o
165
171
  );
166
172
  return;
167
173
  }
168
- const e = y && c >= 0 ? w[c] : void 0;
174
+ const e = S && c >= 0 ? v[c] : void 0;
169
175
  if (t.key === "Enter") {
170
176
  if (e) {
171
177
  t.preventDefault(), X(e);
172
178
  return;
173
179
  }
174
- k && (t.preventDefault(), k(r));
180
+ M && (t.preventDefault(), M(r));
175
181
  return;
176
182
  }
177
183
  t.key === "Tab" && e && (t.preventDefault(), X(e));
178
- }, ut = _t(r, h), q = It[x], mt = L ? (
184
+ }, ut = Ht(r, h), J = Rt[x], mt = I ? (
179
185
  // `role="listbox"` admits only option/group children.
180
- /* @__PURE__ */ S("div", { role: "presentation", style: ot, children: [
186
+ /* @__PURE__ */ E("div", { role: "presentation", style: ot, children: [
181
187
  /* @__PURE__ */ d(yt, { size: "xxxsmall" }),
182
188
  /* @__PURE__ */ d("span", { children: "Loading…" })
183
189
  ] })
184
- ) : v ? w.map((t, e) => {
190
+ ) : y ? v.map((t, e) => {
185
191
  const o = e === c;
186
- return /* @__PURE__ */ S(
192
+ return /* @__PURE__ */ E(
187
193
  "button",
188
194
  {
189
195
  ref: (p) => {
190
- P.current[e] = p;
196
+ V.current[e] = p;
191
197
  },
192
198
  type: "button",
193
- id: U(e),
199
+ id: j(e),
194
200
  role: "option",
195
201
  "aria-selected": o,
196
202
  tabIndex: -1,
@@ -241,31 +247,31 @@ const Mt = {
241
247
  },
242
248
  t.id
243
249
  );
244
- }) : H ? /* @__PURE__ */ d("div", { role: "presentation", style: ot, children: H }) : null, gt = M ? "" : "hover:border-[var(--malachite-text-placeholder)]";
245
- return /* @__PURE__ */ S(
250
+ }) : H ? /* @__PURE__ */ d("div", { role: "presentation", style: ot, children: H }) : null, gt = L ? "" : "hover:border-[var(--malachite-text-placeholder)]";
251
+ return /* @__PURE__ */ E(
246
252
  "div",
247
253
  {
248
- className: `relative w-full ${Mt[x]} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${gt} transition-colors flex items-center ${M ? "opacity-60 cursor-not-allowed" : ""} ${it}`,
254
+ className: `relative w-full ${Lt[x]} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${gt} transition-colors flex items-center ${L ? "opacity-60 cursor-not-allowed" : ""} ${it}`,
249
255
  style: {
250
- boxShadow: N ? "var(--malachite-shadow-accent, 0px 1px 0px 0px rgba(0, 175, 102, 0.15))" : "0px 1px 1px 0px rgba(0, 0, 0, 0.15)",
251
- borderColor: N ? "var(--malachite-control-border-hover, rgba(0, 175, 102, 0.4))" : void 0,
256
+ boxShadow: O ? "var(--malachite-shadow-accent, 0px 1px 0px 0px rgba(0, 175, 102, 0.15))" : "0px 1px 1px 0px rgba(0, 0, 0, 0.15)",
257
+ borderColor: O ? "var(--malachite-control-border-hover, rgba(0, 175, 102, 0.4))" : void 0,
252
258
  ...at
253
259
  },
254
260
  children: [
255
- /* @__PURE__ */ S("div", { className: "relative flex-1 h-full min-w-0 overflow-hidden", children: [
256
- /* @__PURE__ */ S(
261
+ /* @__PURE__ */ E("div", { className: "relative flex-1 h-full min-w-0 overflow-hidden", children: [
262
+ /* @__PURE__ */ E(
257
263
  "div",
258
264
  {
259
- ref: C,
265
+ ref: G,
260
266
  "aria-hidden": "true",
261
267
  className: `absolute inset-0 flex items-center pointer-events-none ${rt[x]}`,
262
- style: { ...q, whiteSpace: "pre" },
268
+ style: { ...J, whiteSpace: "pre" },
263
269
  children: [
264
270
  ut.map((t) => /* @__PURE__ */ d(
265
271
  "span",
266
272
  {
267
273
  style: {
268
- color: Lt[t.kind],
274
+ color: It[t.kind],
269
275
  ...t.kind === "error" ? { textDecoration: "underline wavy" } : {}
270
276
  },
271
277
  children: r.slice(t.start, t.end)
@@ -275,9 +281,9 @@ const Mt = {
275
281
  /* @__PURE__ */ d(
276
282
  "span",
277
283
  {
278
- ref: G,
284
+ ref: P,
279
285
  style: { position: "absolute", top: 0, left: 0, visibility: "hidden" },
280
- children: r.slice(0, Y)
286
+ children: r.slice(0, Z)
281
287
  }
282
288
  )
283
289
  ]
@@ -289,52 +295,52 @@ const Mt = {
289
295
  ref: b,
290
296
  type: "text",
291
297
  role: "combobox",
292
- "aria-expanded": l,
293
- "aria-controls": l ? W : void 0,
294
- "aria-activedescendant": y && c >= 0 ? U(c) : void 0,
298
+ "aria-expanded": a,
299
+ "aria-controls": a ? W : void 0,
300
+ "aria-activedescendant": S && c >= 0 ? j(c) : void 0,
295
301
  "aria-autocomplete": "list",
296
302
  autoComplete: "off",
297
303
  spellCheck: !1,
298
- "aria-labelledby": K,
299
- "aria-label": K ? void 0 : lt ?? B,
304
+ "aria-labelledby": U,
305
+ "aria-label": U ? void 0 : lt ?? K,
300
306
  value: r,
301
307
  onChange: pt,
302
308
  onSelect: ht,
303
309
  onScroll: () => {
304
- R(), l && m();
310
+ R(), a && m();
305
311
  },
306
312
  onKeyDown: ft,
307
313
  onFocus: () => {
308
- j(!0), A(!1);
314
+ Y(!0), A(!1);
309
315
  },
310
- onBlur: () => j(!1),
311
- placeholder: B,
312
- disabled: M,
316
+ onBlur: () => Y(!1),
317
+ placeholder: K,
318
+ disabled: L,
313
319
  className: `absolute inset-0 w-full h-full bg-transparent border-none outline-none ${rt[x]} placeholder:text-[var(--malachite-text-placeholder)] placeholder:font-medium disabled:cursor-not-allowed`,
314
320
  style: {
315
- ...q,
321
+ ...J,
316
322
  color: "transparent",
317
323
  caretColor: "var(--malachite-text-primary, rgb(10, 10, 10))"
318
324
  }
319
325
  }
320
326
  )
321
327
  ] }),
322
- l && vt(
328
+ a && vt(
323
329
  /* @__PURE__ */ d(
324
330
  "div",
325
331
  {
326
- ref: I,
332
+ ref: w,
327
333
  id: W,
328
334
  role: "listbox",
329
- ...Tt("dropdown"),
330
- onMouseDown: Rt,
335
+ ...kt("dropdown"),
336
+ onMouseDown: Dt,
331
337
  style: {
332
338
  position: "fixed",
333
339
  top: (i == null ? void 0 : i.top) ?? 0,
334
340
  left: (i == null ? void 0 : i.left) ?? 0,
335
341
  minWidth: Math.min(
336
- F,
337
- (i == null ? void 0 : i.width) ?? F
342
+ B,
343
+ (i == null ? void 0 : i.width) ?? B
338
344
  ),
339
345
  maxWidth: Math.min(
340
346
  nt,
@@ -364,7 +370,7 @@ const Mt = {
364
370
  );
365
371
  };
366
372
  export {
367
- jt as QueryInput,
368
- jt as default
373
+ Zt as QueryInput,
374
+ Zt as default
369
375
  };
370
376
  //# sourceMappingURL=QueryInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueryInput.js","sources":["../../src/components/QueryInput.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useId,\n useInsertionEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport Spinner from './Spinner';\nimport { CONTROL_TEXT_SIZE, CONTROL_TEXT_SIZE_CLASS } from './controlTextSize';\nimport { pushEscapeLayer } from './escapeLayers';\nimport { ensureMultiSelectPanelStyles } from './optionRowStyles';\nimport { overlayIdentity } from './portalOverlay';\nimport { type CaretMenuGeometry, computeCaretMenuGeometry } from './queryInputGeometry';\n\nexport type QueryTokenKind =\n | 'key'\n | 'value'\n | 'operator'\n | 'negation'\n | 'punctuation'\n | 'error'\n | 'plain';\n\nexport interface QueryToken {\n /** Index into `value`. */\n start: number;\n /** Exclusive. */\n end: number;\n kind: QueryTokenKind;\n}\n\nexport interface QuerySuggestion {\n id: string;\n label: string;\n /** Secondary text, right-aligned in the row. */\n detail?: string;\n /** What replaces `activeRange` when accepted. Defaults to `label`. */\n insertText?: string;\n}\n\nexport type QueryInputSize = 'small' | 'medium' | 'large';\n\nexport interface QueryInputProps {\n value: string;\n onChange: (value: string) => void;\n /** Ranges to colour. Tokens that are out of range, reversed or overlapping are ignored. */\n tokens?: QueryToken[];\n /** Rows for the caret menu. Empty or undefined means the menu stays closed. */\n suggestions?: QuerySuggestion[];\n /** The span an accepted suggestion replaces. Defaults to a zero-width span at the caret. */\n activeRange?: { start: number; end: number };\n onAccept?: (suggestion: QuerySuggestion) => void;\n /** Every value change AND every caret move, so the consumer can recompute tokens/suggestions. */\n onQueryContextChange?: (context: { value: string; caret: number }) => void;\n /** Enter with nothing highlighted in the menu. */\n onSubmit?: (value: string) => void;\n placeholder?: string;\n size?: QueryInputSize;\n disabled?: boolean;\n /** Suggestions are being fetched: the menu shows a loading row instead of the empty message. */\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n style?: React.CSSProperties;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n// Same 28/32/42 ladder as Search, minus the icon gap this component has no icon to space.\nconst SIZE_CLASSES: Record<QueryInputSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)] px-[10px] rounded-[var(--malachite-radius-10,10px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)] px-[10px] rounded-xl',\n large: 'h-[var(--malachite-control-height-large,42px)] px-[12px] rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst TOKEN_COLORS: Record<QueryTokenKind, string> = {\n key: 'var(--malachite-codeblock-keyword, rgb(12, 88, 174))',\n value: 'var(--malachite-codeblock-string, rgb(2, 122, 66))',\n operator: 'var(--malachite-codeblock-type, rgb(12, 88, 174))',\n negation: 'var(--malachite-text-destructive, rgb(237, 53, 54))',\n punctuation: 'var(--malachite-codeblock-foreground, rgb(10, 10, 10))',\n error: 'var(--malachite-text-error, rgb(237, 53, 54))',\n plain: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n};\n\n// The one place the mirror and the input agree on typography: diverge here and the coloured\n// text drifts out from under the caret it's supposed to sit beneath.\nconst TEXT_STYLE: Record<QueryInputSize, React.CSSProperties> = {\n small: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.small,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n medium: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.medium,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n large: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.large,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n};\n\n/** Before layout the portal hasn't painted yet, so the first geometry pass needs a width. */\nconst MENU_FALLBACK_WIDTH_PX = 220;\n\nconst MENU_MAX_WIDTH_PX = 360;\n\nconst MENU_MESSAGE_STYLE: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '10px 12px',\n color: 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n whiteSpace: 'nowrap',\n};\n\n/** Keeps focus (and the caret) on the input so a row click never blurs it first. */\nconst handleMenuMouseDown = (event: React.MouseEvent) => {\n event.preventDefault();\n};\n\ninterface QuerySegment {\n start: number;\n end: number;\n kind: QueryTokenKind;\n}\n\n/** Drops tokens the consumer got wrong rather than letting them corrupt the render. */\nconst sanitizeTokens = (value: string, tokens: QueryToken[]): QueryToken[] => {\n const inRange = tokens.filter(\n (token) => token.start >= 0 && token.end <= value.length && token.start < token.end,\n );\n const sorted = [...inRange].sort((a, b) => a.start - b.start);\n const accepted: QueryToken[] = [];\n let cursor = 0;\n for (const token of sorted) {\n if (token.start < cursor) {\n continue;\n }\n accepted.push(token);\n cursor = token.end;\n }\n return accepted;\n};\n\n/** Fills the gaps between tokens with 'plain' segments so the mirror's text always equals `value`. */\nconst buildSegments = (value: string, tokens: QueryToken[]): QuerySegment[] => {\n const segments: QuerySegment[] = [];\n let cursor = 0;\n for (const token of sanitizeTokens(value, tokens)) {\n if (token.start > cursor) {\n segments.push({ start: cursor, end: token.start, kind: 'plain' });\n }\n segments.push(token);\n cursor = token.end;\n }\n if (cursor < value.length) {\n segments.push({ start: cursor, end: value.length, kind: 'plain' });\n }\n return segments;\n};\n\nconst QueryInput: React.FC<QueryInputProps> = ({\n value,\n onChange,\n tokens = [],\n suggestions,\n activeRange,\n onAccept,\n onQueryContextChange,\n onSubmit,\n placeholder,\n size = 'large',\n disabled = false,\n loading = false,\n emptyMessage,\n className = '',\n style,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n}) => {\n const instanceId = useId();\n const listboxId = `${instanceId}-listbox`;\n const getRowId = (index: number) => `${listboxId}-option-${index}`;\n\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState(() => value.length);\n const [rawHighlightedIndex, setHighlightedIndex] = useState(0);\n // Escape closes the menu whatever `suggestions` and `loading` say. Lifted by an edit or a\n // refocus, so navigating a dismissed query does not pop it back open.\n const [dismissed, setDismissed] = useState(false);\n const [menuPosition, setMenuPosition] = useState<CaretMenuGeometry | null>(null);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const mirrorRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const rowRefs = useRef<(HTMLButtonElement | null)[]>([]);\n // Caret restore after an accepted suggestion. Carries the string it was computed against:\n // nothing obliges a controlled consumer to apply the value handed to `onChange`, and a\n // caret from a rejected or rewritten suggestion must not land on a later unrelated edit.\n const pendingSelectionRef = useRef<{ value: string; caret: number } | null>(null);\n\n const suggestionsProvided = Array.isArray(suggestions);\n const suggestionList = suggestions ?? [];\n const hasSuggestions = suggestionList.length > 0;\n const isEmptyList = suggestionsProvided && !hasSuggestions;\n const wantsMenu = loading || hasSuggestions || (isEmptyList && !!emptyMessage);\n const isMenuOpen = focused && wantsMenu && !dismissed && !disabled;\n // `loading` paints the spinner over any rows the consumer is still holding, so nothing is\n // on screen to arrow through, accept, or point `aria-activedescendant` at.\n const rowsVisible = isMenuOpen && hasSuggestions && !loading;\n\n // A consumer's `suggestions` array is commonly rebuilt inline, so its identity changes on\n // any parent re-render and cannot stand in for \"the candidates changed\". Clamping during\n // render keeps the row the user arrowed to, and keeps the highlight inside a shrunken list.\n const highlightedIndex = hasSuggestions\n ? Math.min(rawHighlightedIndex, suggestionList.length - 1)\n : -1;\n\n useLayoutEffect(() => {\n setCaret((current) => Math.min(current, value.length));\n }, [value]);\n\n const syncMirrorScroll = useCallback(() => {\n const input = inputRef.current;\n const mirror = mirrorRef.current;\n if (input && mirror) {\n mirror.style.transform = `translateX(${-input.scrollLeft}px)`;\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-syncs on every value change, not on value itself\n useLayoutEffect(() => {\n syncMirrorScroll();\n }, [value, syncMirrorScroll]);\n\n const updateMenuPosition = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n const caretOffsetPx = (measureRef.current?.offsetWidth ?? 0) - input.scrollLeft;\n setMenuPosition(\n computeCaretMenuGeometry({\n inputRect: input.getBoundingClientRect(),\n caretOffsetPx,\n menuWidth: menuRef.current?.offsetWidth ?? MENU_FALLBACK_WIDTH_PX,\n menuHeight: menuRef.current?.offsetHeight ?? 0,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n }),\n );\n }, []);\n\n // Depends on `caret` as well as `value`: the measuring span is sliced at the caret, so an\n // arrow-key move with no edit still changes where the menu belongs.\n // biome-ignore lint/correctness/useExhaustiveDependencies: repositions on every keystroke, not on value itself\n useLayoutEffect(() => {\n if (isMenuOpen) {\n updateMenuPosition();\n } else {\n setMenuPosition(null);\n }\n // `suggestions` and `loading` are here because they change the menu's own size: rows\n // arriving after a fetch resize it while the query and caret sit still, and a stale\n // measurement would leave `openUp` and the caret-aligned `left` computed for the old box.\n }, [isMenuOpen, value, caret, suggestions, loading, updateMenuPosition]);\n\n useEffect(() => {\n if (!isMenuOpen) {\n return undefined;\n }\n const handleScrollOrResize = () => updateMenuPosition();\n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n const popEscapeLayer = pushEscapeLayer(() => setDismissed(true));\n return () => {\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n popEscapeLayer();\n };\n }, [isMenuOpen, updateMenuPosition]);\n\n // Restore the caret placed by the last accepted suggestion once the new `value` has\n // actually rendered. Guarded on the ref so an externally-driven value change never gets\n // its selection clobbered.\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentionally re-reads latest closures via pendingSelectionRef's gate\n useLayoutEffect(() => {\n const pending = pendingSelectionRef.current;\n if (pending === null) {\n return;\n }\n pendingSelectionRef.current = null;\n const input = inputRef.current;\n // Dropped unless the consumer applied exactly the string this caret was measured\n // against. A rejected or rewritten suggestion leaves the caret where the user put it.\n if (!input || pending.value !== value) {\n return;\n }\n input.setSelectionRange(pending.caret, pending.caret);\n setCaret(pending.caret);\n onQueryContextChange?.({ value, caret: pending.caret });\n syncMirrorScroll();\n updateMenuPosition();\n }, [value]);\n\n // Scrolled by hand rather than with `scrollIntoView`, which would also scroll the page and\n // carry the field itself out of view. Same reason MultiSelect does it this way.\n useLayoutEffect(() => {\n if (!rowsVisible) {\n return;\n }\n const row = rowRefs.current[highlightedIndex];\n const container = menuRef.current;\n if (!row || !container) {\n return;\n }\n const rowBottom = row.offsetTop + row.offsetHeight;\n if (rowBottom > container.scrollTop + container.clientHeight) {\n container.scrollTop = rowBottom - container.clientHeight;\n } else if (row.offsetTop < container.scrollTop) {\n container.scrollTop = row.offsetTop;\n }\n }, [highlightedIndex, rowsVisible]);\n\n // useInsertionEffect, not layout: the rules have to land before the rows paint.\n useInsertionEffect(() => {\n if (isMenuOpen) {\n ensureMultiSelectPanelStyles();\n }\n }, [isMenuOpen]);\n\n const reportCaret = (nextValue: string, nextCaret: number) => {\n setCaret(nextCaret);\n onQueryContextChange?.({ value: nextValue, caret: nextCaret });\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n // Editing is the user asking again, so it lifts an earlier Escape. Moving the caret is\n // not, and neither is a new `suggestions` array: that identity changes on any parent\n // re-render, which would undo the dismissal with nothing having been asked.\n setDismissed(false);\n setHighlightedIndex(0);\n onChange(next);\n reportCaret(next, event.target.selectionStart ?? next.length);\n };\n\n const handleSelect = (event: React.SyntheticEvent<HTMLInputElement>) => {\n const target = event.currentTarget;\n reportCaret(target.value, target.selectionStart ?? target.value.length);\n };\n\n const acceptSuggestion = (suggestion: QuerySuggestion) => {\n const fallbackCaret = inputRef.current?.selectionStart ?? value.length;\n const range = activeRange ?? { start: fallbackCaret, end: fallbackCaret };\n // Clamped for the same reason `sanitizeTokens` drops a bad range, except this one\n // writes: `slice` reads a negative index from the end of the string, so an unchecked\n // `start` of -1 silently rewrites the tail instead of doing nothing.\n const start = Math.max(0, Math.min(range.start, value.length));\n const end = Math.max(start, Math.min(range.end, value.length));\n const insertText = suggestion.insertText ?? suggestion.label;\n const next = value.slice(0, start) + insertText + value.slice(end);\n pendingSelectionRef.current = { value: next, caret: start + insertText.length };\n onChange(next);\n onAccept?.(suggestion);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (rowsVisible && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {\n event.preventDefault();\n const count = suggestionList.length;\n // Steps from the clamped index, so a list that shrank moves from the row on screen\n // rather than from a raw index the user can no longer see.\n setHighlightedIndex(\n event.key === 'ArrowDown'\n ? (highlightedIndex + 1) % count\n : (highlightedIndex - 1 + count) % count,\n );\n return;\n }\n\n const highlighted =\n rowsVisible && highlightedIndex >= 0 ? suggestionList[highlightedIndex] : undefined;\n\n if (event.key === 'Enter') {\n if (highlighted) {\n event.preventDefault();\n acceptSuggestion(highlighted);\n return;\n }\n if (onSubmit) {\n // Otherwise a surrounding <form> submits too and the query is sent twice.\n // Without the prop the native submit is left alone, which is the useful default.\n event.preventDefault();\n onSubmit(value);\n }\n return;\n }\n\n if (event.key === 'Tab' && highlighted) {\n // Tab completes the term and stays put, the way an editor or a search bar does.\n // Letting focus move on would hand the next keystroke to another field.\n event.preventDefault();\n acceptSuggestion(highlighted);\n }\n };\n\n const segments = buildSegments(value, tokens);\n const textStyle = TEXT_STYLE[size];\n\n const menuContent = (() => {\n if (loading) {\n return (\n // `role=\"listbox\"` admits only option/group children.\n <div role=\"presentation\" style={MENU_MESSAGE_STYLE}>\n <Spinner size=\"xxxsmall\" />\n <span>Loading…</span>\n </div>\n );\n }\n if (hasSuggestions) {\n return suggestionList.map((suggestion, index) => {\n const highlighted = index === highlightedIndex;\n return (\n <button\n key={suggestion.id}\n ref={(element) => {\n rowRefs.current[index] = element;\n }}\n type=\"button\"\n id={getRowId(index)}\n role=\"option\"\n aria-selected={highlighted}\n // Focus stays on the input under the activedescendant model, so a row\n // must not become its own tab stop.\n tabIndex={-1}\n onClick={() => acceptSuggestion(suggestion)}\n onMouseEnter={() => setHighlightedIndex(index)}\n className=\"malachite-multiselect-option\"\n data-highlighted={highlighted}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n width: '100%',\n flexShrink: 0,\n border: 'none',\n textAlign: 'left',\n borderRadius: 8,\n padding: '8px 10px',\n font: 'inherit',\n cursor: 'pointer',\n color: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n }}\n >\n <span\n style={{\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {suggestion.label}\n </span>\n {suggestion.detail && (\n <span\n style={{\n flexShrink: 0,\n fontSize: 'var(--malachite-font-size-xsmall, 11px)',\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n }}\n >\n {suggestion.detail}\n </span>\n )}\n </button>\n );\n });\n }\n if (emptyMessage) {\n // `role=\"listbox\"` admits only option/group children.\n return (\n <div role=\"presentation\" style={MENU_MESSAGE_STYLE}>\n {emptyMessage}\n </div>\n );\n }\n return null;\n })();\n\n const hoverBorderClass = disabled ? '' : 'hover:border-[var(--malachite-text-placeholder)]';\n\n return (\n <div\n className={`relative w-full ${SIZE_CLASSES[size]} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${hoverBorderClass} transition-colors flex items-center ${disabled ? 'opacity-60 cursor-not-allowed' : ''} ${className}`}\n style={{\n boxShadow: focused\n ? 'var(--malachite-shadow-accent, 0px 1px 0px 0px rgba(0, 175, 102, 0.15))'\n : '0px 1px 1px 0px rgba(0, 0, 0, 0.15)',\n borderColor: focused\n ? 'var(--malachite-control-border-hover, rgba(0, 175, 102, 0.4))'\n : undefined,\n ...style,\n }}\n >\n {/* Clips here, not on the mirror: the mirror is what translates, and a transform\n carries the element's own clip rect with it, so the window onto the text would\n slide out of the field by exactly `scrollLeft`. */}\n <div className=\"relative flex-1 h-full min-w-0 overflow-hidden\">\n {/* aria-hidden: purely decorative, the input carries the accessible value. */}\n <div\n ref={mirrorRef}\n aria-hidden=\"true\"\n className={`absolute inset-0 flex items-center pointer-events-none ${CONTROL_TEXT_SIZE_CLASS[size]}`}\n style={{ ...textStyle, whiteSpace: 'pre' }}\n >\n {segments.map((segment) => (\n <span\n key={segment.start}\n style={{\n color: TOKEN_COLORS[segment.kind],\n ...(segment.kind === 'error'\n ? { textDecoration: 'underline wavy' }\n : {}),\n }}\n >\n {value.slice(segment.start, segment.end)}\n </span>\n ))}\n <span\n ref={measureRef}\n style={{ position: 'absolute', top: 0, left: 0, visibility: 'hidden' }}\n >\n {value.slice(0, caret)}\n </span>\n </div>\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isMenuOpen}\n aria-controls={isMenuOpen ? listboxId : undefined}\n aria-activedescendant={\n rowsVisible && highlightedIndex >= 0\n ? getRowId(highlightedIndex)\n : undefined\n }\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n spellCheck={false}\n aria-labelledby={ariaLabelledBy}\n // A visible label outranks it, so the fallback only applies without one.\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? placeholder)}\n value={value}\n onChange={handleChange}\n onSelect={handleSelect}\n onScroll={() => {\n syncMirrorScroll();\n if (isMenuOpen) {\n updateMenuPosition();\n }\n }}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setFocused(true);\n setDismissed(false);\n }}\n onBlur={() => setFocused(false)}\n placeholder={placeholder}\n disabled={disabled}\n className={`absolute inset-0 w-full h-full bg-transparent border-none outline-none ${CONTROL_TEXT_SIZE_CLASS[size]} placeholder:text-[var(--malachite-text-placeholder)] placeholder:font-medium disabled:cursor-not-allowed`}\n style={{\n ...textStyle,\n color: 'transparent',\n caretColor: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n }}\n />\n </div>\n {isMenuOpen &&\n createPortal(\n <div\n ref={menuRef}\n id={listboxId}\n role=\"listbox\"\n // Rides the dropdown overlay band, but borrows the multiselect option\n // rows below: their highlight follows `data-highlighted`, which is the\n // keyboard cursor this menu has, rather than a bare `:hover`.\n {...overlayIdentity('dropdown')}\n onMouseDown={handleMenuMouseDown}\n style={{\n position: 'fixed',\n top: menuPosition?.top ?? 0,\n left: menuPosition?.left ?? 0,\n minWidth: Math.min(\n MENU_FALLBACK_WIDTH_PX,\n menuPosition?.width ?? MENU_FALLBACK_WIDTH_PX,\n ),\n maxWidth: Math.min(\n MENU_MAX_WIDTH_PX,\n menuPosition?.width ?? MENU_MAX_WIDTH_PX,\n ),\n background: 'var(--malachite-card-background, rgb(255, 255, 255))',\n border: '1px solid var(--malachite-card-border, rgb(232, 232, 232))',\n borderRadius: 12,\n boxShadow: '0px 2px 5px 0px rgba(0, 0, 0, 0.1)',\n padding: 4,\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n maxHeight: 320,\n overflowY: 'auto',\n fontSize: CONTROL_TEXT_SIZE[size],\n visibility: menuPosition ? 'visible' : 'hidden',\n opacity: menuPosition ? 1 : 0,\n }}\n >\n {menuContent}\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nexport default QueryInput;\nexport { QueryInput };\n"],"names":["SIZE_CLASSES","TOKEN_COLORS","TEXT_STYLE","CONTROL_TEXT_SIZE","MENU_FALLBACK_WIDTH_PX","MENU_MAX_WIDTH_PX","MENU_MESSAGE_STYLE","handleMenuMouseDown","event","sanitizeTokens","value","tokens","sorted","token","a","b","accepted","cursor","buildSegments","segments","QueryInput","onChange","suggestions","activeRange","onAccept","onQueryContextChange","onSubmit","placeholder","size","disabled","loading","emptyMessage","className","style","ariaLabel","ariaLabelledBy","listboxId","useId","getRowId","index","focused","setFocused","useState","caret","setCaret","rawHighlightedIndex","setHighlightedIndex","dismissed","setDismissed","menuPosition","setMenuPosition","inputRef","useRef","mirrorRef","measureRef","menuRef","rowRefs","pendingSelectionRef","suggestionsProvided","suggestionList","hasSuggestions","isMenuOpen","rowsVisible","highlightedIndex","useLayoutEffect","current","syncMirrorScroll","useCallback","input","mirror","updateMenuPosition","caretOffsetPx","_a","computeCaretMenuGeometry","_b","_c","useEffect","handleScrollOrResize","popEscapeLayer","pushEscapeLayer","pending","row","container","rowBottom","useInsertionEffect","ensureMultiSelectPanelStyles","reportCaret","nextValue","nextCaret","handleChange","next","handleSelect","target","acceptSuggestion","suggestion","fallbackCaret","range","start","end","insertText","handleKeyDown","count","highlighted","textStyle","menuContent","jsxs","jsx","Spinner","element","hoverBorderClass","CONTROL_TEXT_SIZE_CLASS","segment","createPortal","overlayIdentity"],"mappings":"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"}
1
+ {"version":3,"file":"QueryInput.js","sources":["../../src/components/QueryInput.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useId,\n useInsertionEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport Spinner from './Spinner';\nimport { CONTROL_TEXT_SIZE, CONTROL_TEXT_SIZE_CLASS } from './controlTextSize';\nimport { pushEscapeLayer } from './escapeLayers';\nimport { ensureMultiSelectPanelStyles } from './optionRowStyles';\nimport { useOwnedByPopover } from './popoverTree';\nimport { overlayIdentity } from './portalOverlay';\nimport { type CaretMenuGeometry, computeCaretMenuGeometry } from './queryInputGeometry';\n\nexport type QueryTokenKind =\n | 'key'\n | 'value'\n | 'operator'\n | 'negation'\n | 'punctuation'\n | 'error'\n | 'plain';\n\nexport interface QueryToken {\n /** Index into `value`. */\n start: number;\n /** Exclusive. */\n end: number;\n kind: QueryTokenKind;\n}\n\nexport interface QuerySuggestion {\n id: string;\n label: string;\n /** Secondary text, right-aligned in the row. */\n detail?: string;\n /** What replaces `activeRange` when accepted. Defaults to `label`. */\n insertText?: string;\n}\n\nexport type QueryInputSize = 'small' | 'medium' | 'large';\n\nexport interface QueryInputProps {\n value: string;\n onChange: (value: string) => void;\n /** Ranges to colour. Tokens that are out of range, reversed or overlapping are ignored. */\n tokens?: QueryToken[];\n /** Rows for the caret menu. Empty or undefined means the menu stays closed. */\n suggestions?: QuerySuggestion[];\n /** The span an accepted suggestion replaces. Defaults to a zero-width span at the caret. */\n activeRange?: { start: number; end: number };\n onAccept?: (suggestion: QuerySuggestion) => void;\n /** Every value change AND every caret move, so the consumer can recompute tokens/suggestions. */\n onQueryContextChange?: (context: { value: string; caret: number }) => void;\n /** Enter with nothing highlighted in the menu. */\n onSubmit?: (value: string) => void;\n placeholder?: string;\n size?: QueryInputSize;\n disabled?: boolean;\n /** Suggestions are being fetched: the menu shows a loading row instead of the empty message. */\n loading?: boolean;\n emptyMessage?: string;\n className?: string;\n style?: React.CSSProperties;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n// Same 28/32/42 ladder as Search, minus the icon gap this component has no icon to space.\nconst SIZE_CLASSES: Record<QueryInputSize, string> = {\n small: 'h-[var(--malachite-control-height-small,28px)] px-[10px] rounded-[var(--malachite-radius-10,10px)]',\n medium: 'h-[var(--malachite-control-height-medium,32px)] px-[10px] rounded-xl',\n large: 'h-[var(--malachite-control-height-large,42px)] px-[12px] rounded-[var(--malachite-radius-xxl,14px)]',\n};\n\nconst TOKEN_COLORS: Record<QueryTokenKind, string> = {\n key: 'var(--malachite-codeblock-keyword, rgb(12, 88, 174))',\n value: 'var(--malachite-codeblock-string, rgb(2, 122, 66))',\n operator: 'var(--malachite-codeblock-type, rgb(12, 88, 174))',\n negation: 'var(--malachite-text-destructive, rgb(237, 53, 54))',\n punctuation: 'var(--malachite-codeblock-foreground, rgb(10, 10, 10))',\n error: 'var(--malachite-text-error, rgb(237, 53, 54))',\n plain: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n};\n\n// The one place the mirror and the input agree on typography: diverge here and the coloured\n// text drifts out from under the caret it's supposed to sit beneath.\nconst TEXT_STYLE: Record<QueryInputSize, React.CSSProperties> = {\n small: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.small,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n medium: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.medium,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n large: {\n fontFamily: 'inherit',\n fontSize: CONTROL_TEXT_SIZE.large,\n fontWeight: 500,\n letterSpacing: 'normal',\n lineHeight: 'normal',\n padding: 0,\n },\n};\n\n/** Before layout the portal hasn't painted yet, so the first geometry pass needs a width. */\nconst MENU_FALLBACK_WIDTH_PX = 220;\n\nconst MENU_MAX_WIDTH_PX = 360;\n\nconst MENU_MESSAGE_STYLE: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '10px 12px',\n color: 'var(--malachite-text-dimmed, rgb(161, 161, 161))',\n whiteSpace: 'nowrap',\n};\n\n/** Keeps focus (and the caret) on the input so a row click never blurs it first. */\nconst handleMenuMouseDown = (event: React.MouseEvent) => {\n event.preventDefault();\n};\n\ninterface QuerySegment {\n start: number;\n end: number;\n kind: QueryTokenKind;\n}\n\n/** Drops tokens the consumer got wrong rather than letting them corrupt the render. */\nconst sanitizeTokens = (value: string, tokens: QueryToken[]): QueryToken[] => {\n const inRange = tokens.filter(\n (token) => token.start >= 0 && token.end <= value.length && token.start < token.end,\n );\n const sorted = [...inRange].sort((a, b) => a.start - b.start);\n const accepted: QueryToken[] = [];\n let cursor = 0;\n for (const token of sorted) {\n if (token.start < cursor) {\n continue;\n }\n accepted.push(token);\n cursor = token.end;\n }\n return accepted;\n};\n\n/** Fills the gaps between tokens with 'plain' segments so the mirror's text always equals `value`. */\nconst buildSegments = (value: string, tokens: QueryToken[]): QuerySegment[] => {\n const segments: QuerySegment[] = [];\n let cursor = 0;\n for (const token of sanitizeTokens(value, tokens)) {\n if (token.start > cursor) {\n segments.push({ start: cursor, end: token.start, kind: 'plain' });\n }\n segments.push(token);\n cursor = token.end;\n }\n if (cursor < value.length) {\n segments.push({ start: cursor, end: value.length, kind: 'plain' });\n }\n return segments;\n};\n\nconst QueryInput: React.FC<QueryInputProps> = ({\n value,\n onChange,\n tokens = [],\n suggestions,\n activeRange,\n onAccept,\n onQueryContextChange,\n onSubmit,\n placeholder,\n size = 'large',\n disabled = false,\n loading = false,\n emptyMessage,\n className = '',\n style,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n}) => {\n const instanceId = useId();\n const listboxId = `${instanceId}-listbox`;\n const getRowId = (index: number) => `${listboxId}-option-${index}`;\n\n const [focused, setFocused] = useState(false);\n const [caret, setCaret] = useState(() => value.length);\n const [rawHighlightedIndex, setHighlightedIndex] = useState(0);\n // Escape closes the menu whatever `suggestions` and `loading` say. Lifted by an edit or a\n // refocus, so navigating a dismissed query does not pop it back open.\n const [dismissed, setDismissed] = useState(false);\n const [menuPosition, setMenuPosition] = useState<CaretMenuGeometry | null>(null);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const mirrorRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const rowRefs = useRef<(HTMLButtonElement | null)[]>([]);\n // Caret restore after an accepted suggestion. Carries the string it was computed against:\n // nothing obliges a controlled consumer to apply the value handed to `onChange`, and a\n // caret from a rejected or rewritten suggestion must not land on a later unrelated edit.\n const pendingSelectionRef = useRef<{ value: string; caret: number } | null>(null);\n\n const suggestionsProvided = Array.isArray(suggestions);\n const suggestionList = suggestions ?? [];\n const hasSuggestions = suggestionList.length > 0;\n const isEmptyList = suggestionsProvided && !hasSuggestions;\n const wantsMenu = loading || hasSuggestions || (isEmptyList && !!emptyMessage);\n const isMenuOpen = focused && wantsMenu && !dismissed && !disabled;\n useOwnedByPopover(\n useCallback(() => menuRef.current, []),\n isMenuOpen,\n );\n // `loading` paints the spinner over any rows the consumer is still holding, so nothing is\n // on screen to arrow through, accept, or point `aria-activedescendant` at.\n const rowsVisible = isMenuOpen && hasSuggestions && !loading;\n\n // A consumer's `suggestions` array is commonly rebuilt inline, so its identity changes on\n // any parent re-render and cannot stand in for \"the candidates changed\". Clamping during\n // render keeps the row the user arrowed to, and keeps the highlight inside a shrunken list.\n const highlightedIndex = hasSuggestions\n ? Math.min(rawHighlightedIndex, suggestionList.length - 1)\n : -1;\n\n useLayoutEffect(() => {\n setCaret((current) => Math.min(current, value.length));\n }, [value]);\n\n const syncMirrorScroll = useCallback(() => {\n const input = inputRef.current;\n const mirror = mirrorRef.current;\n if (input && mirror) {\n mirror.style.transform = `translateX(${-input.scrollLeft}px)`;\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-syncs on every value change, not on value itself\n useLayoutEffect(() => {\n syncMirrorScroll();\n }, [value, syncMirrorScroll]);\n\n const updateMenuPosition = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n const caretOffsetPx = (measureRef.current?.offsetWidth ?? 0) - input.scrollLeft;\n setMenuPosition(\n computeCaretMenuGeometry({\n inputRect: input.getBoundingClientRect(),\n caretOffsetPx,\n menuWidth: menuRef.current?.offsetWidth ?? MENU_FALLBACK_WIDTH_PX,\n menuHeight: menuRef.current?.offsetHeight ?? 0,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n }),\n );\n }, []);\n\n // Depends on `caret` as well as `value`: the measuring span is sliced at the caret, so an\n // arrow-key move with no edit still changes where the menu belongs.\n // biome-ignore lint/correctness/useExhaustiveDependencies: repositions on every keystroke, not on value itself\n useLayoutEffect(() => {\n if (isMenuOpen) {\n updateMenuPosition();\n } else {\n setMenuPosition(null);\n }\n // `suggestions` and `loading` are here because they change the menu's own size: rows\n // arriving after a fetch resize it while the query and caret sit still, and a stale\n // measurement would leave `openUp` and the caret-aligned `left` computed for the old box.\n }, [isMenuOpen, value, caret, suggestions, loading, updateMenuPosition]);\n\n useEffect(() => {\n if (!isMenuOpen) {\n return undefined;\n }\n const handleScrollOrResize = () => updateMenuPosition();\n window.addEventListener('scroll', handleScrollOrResize, true);\n window.addEventListener('resize', handleScrollOrResize);\n const popEscapeLayer = pushEscapeLayer(() => setDismissed(true));\n return () => {\n window.removeEventListener('scroll', handleScrollOrResize, true);\n window.removeEventListener('resize', handleScrollOrResize);\n popEscapeLayer();\n };\n }, [isMenuOpen, updateMenuPosition]);\n\n // Restore the caret placed by the last accepted suggestion once the new `value` has\n // actually rendered. Guarded on the ref so an externally-driven value change never gets\n // its selection clobbered.\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentionally re-reads latest closures via pendingSelectionRef's gate\n useLayoutEffect(() => {\n const pending = pendingSelectionRef.current;\n if (pending === null) {\n return;\n }\n pendingSelectionRef.current = null;\n const input = inputRef.current;\n // Dropped unless the consumer applied exactly the string this caret was measured\n // against. A rejected or rewritten suggestion leaves the caret where the user put it.\n if (!input || pending.value !== value) {\n return;\n }\n input.setSelectionRange(pending.caret, pending.caret);\n setCaret(pending.caret);\n onQueryContextChange?.({ value, caret: pending.caret });\n syncMirrorScroll();\n updateMenuPosition();\n }, [value]);\n\n // Scrolled by hand rather than with `scrollIntoView`, which would also scroll the page and\n // carry the field itself out of view. Same reason MultiSelect does it this way.\n useLayoutEffect(() => {\n if (!rowsVisible) {\n return;\n }\n const row = rowRefs.current[highlightedIndex];\n const container = menuRef.current;\n if (!row || !container) {\n return;\n }\n const rowBottom = row.offsetTop + row.offsetHeight;\n if (rowBottom > container.scrollTop + container.clientHeight) {\n container.scrollTop = rowBottom - container.clientHeight;\n } else if (row.offsetTop < container.scrollTop) {\n container.scrollTop = row.offsetTop;\n }\n }, [highlightedIndex, rowsVisible]);\n\n // useInsertionEffect, not layout: the rules have to land before the rows paint.\n useInsertionEffect(() => {\n if (isMenuOpen) {\n ensureMultiSelectPanelStyles();\n }\n }, [isMenuOpen]);\n\n const reportCaret = (nextValue: string, nextCaret: number) => {\n setCaret(nextCaret);\n onQueryContextChange?.({ value: nextValue, caret: nextCaret });\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n // Editing is the user asking again, so it lifts an earlier Escape. Moving the caret is\n // not, and neither is a new `suggestions` array: that identity changes on any parent\n // re-render, which would undo the dismissal with nothing having been asked.\n setDismissed(false);\n setHighlightedIndex(0);\n onChange(next);\n reportCaret(next, event.target.selectionStart ?? next.length);\n };\n\n const handleSelect = (event: React.SyntheticEvent<HTMLInputElement>) => {\n const target = event.currentTarget;\n reportCaret(target.value, target.selectionStart ?? target.value.length);\n };\n\n const acceptSuggestion = (suggestion: QuerySuggestion) => {\n const fallbackCaret = inputRef.current?.selectionStart ?? value.length;\n const range = activeRange ?? { start: fallbackCaret, end: fallbackCaret };\n // Clamped for the same reason `sanitizeTokens` drops a bad range, except this one\n // writes: `slice` reads a negative index from the end of the string, so an unchecked\n // `start` of -1 silently rewrites the tail instead of doing nothing.\n const start = Math.max(0, Math.min(range.start, value.length));\n const end = Math.max(start, Math.min(range.end, value.length));\n const insertText = suggestion.insertText ?? suggestion.label;\n const next = value.slice(0, start) + insertText + value.slice(end);\n pendingSelectionRef.current = { value: next, caret: start + insertText.length };\n onChange(next);\n onAccept?.(suggestion);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (rowsVisible && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {\n event.preventDefault();\n const count = suggestionList.length;\n // Steps from the clamped index, so a list that shrank moves from the row on screen\n // rather than from a raw index the user can no longer see.\n setHighlightedIndex(\n event.key === 'ArrowDown'\n ? (highlightedIndex + 1) % count\n : (highlightedIndex - 1 + count) % count,\n );\n return;\n }\n\n const highlighted =\n rowsVisible && highlightedIndex >= 0 ? suggestionList[highlightedIndex] : undefined;\n\n if (event.key === 'Enter') {\n if (highlighted) {\n event.preventDefault();\n acceptSuggestion(highlighted);\n return;\n }\n if (onSubmit) {\n // Otherwise a surrounding <form> submits too and the query is sent twice.\n // Without the prop the native submit is left alone, which is the useful default.\n event.preventDefault();\n onSubmit(value);\n }\n return;\n }\n\n if (event.key === 'Tab' && highlighted) {\n // Tab completes the term and stays put, the way an editor or a search bar does.\n // Letting focus move on would hand the next keystroke to another field.\n event.preventDefault();\n acceptSuggestion(highlighted);\n }\n };\n\n const segments = buildSegments(value, tokens);\n const textStyle = TEXT_STYLE[size];\n\n const menuContent = (() => {\n if (loading) {\n return (\n // `role=\"listbox\"` admits only option/group children.\n <div role=\"presentation\" style={MENU_MESSAGE_STYLE}>\n <Spinner size=\"xxxsmall\" />\n <span>Loading…</span>\n </div>\n );\n }\n if (hasSuggestions) {\n return suggestionList.map((suggestion, index) => {\n const highlighted = index === highlightedIndex;\n return (\n <button\n key={suggestion.id}\n ref={(element) => {\n rowRefs.current[index] = element;\n }}\n type=\"button\"\n id={getRowId(index)}\n role=\"option\"\n aria-selected={highlighted}\n // Focus stays on the input under the activedescendant model, so a row\n // must not become its own tab stop.\n tabIndex={-1}\n onClick={() => acceptSuggestion(suggestion)}\n onMouseEnter={() => setHighlightedIndex(index)}\n className=\"malachite-multiselect-option\"\n data-highlighted={highlighted}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n width: '100%',\n flexShrink: 0,\n border: 'none',\n textAlign: 'left',\n borderRadius: 8,\n padding: '8px 10px',\n font: 'inherit',\n cursor: 'pointer',\n color: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n }}\n >\n <span\n style={{\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {suggestion.label}\n </span>\n {suggestion.detail && (\n <span\n style={{\n flexShrink: 0,\n fontSize: 'var(--malachite-font-size-xsmall, 11px)',\n color: 'var(--malachite-text-secondary, rgb(123, 123, 123))',\n }}\n >\n {suggestion.detail}\n </span>\n )}\n </button>\n );\n });\n }\n if (emptyMessage) {\n // `role=\"listbox\"` admits only option/group children.\n return (\n <div role=\"presentation\" style={MENU_MESSAGE_STYLE}>\n {emptyMessage}\n </div>\n );\n }\n return null;\n })();\n\n const hoverBorderClass = disabled ? '' : 'hover:border-[var(--malachite-text-placeholder)]';\n\n return (\n <div\n className={`relative w-full ${SIZE_CLASSES[size]} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${hoverBorderClass} transition-colors flex items-center ${disabled ? 'opacity-60 cursor-not-allowed' : ''} ${className}`}\n style={{\n boxShadow: focused\n ? 'var(--malachite-shadow-accent, 0px 1px 0px 0px rgba(0, 175, 102, 0.15))'\n : '0px 1px 1px 0px rgba(0, 0, 0, 0.15)',\n borderColor: focused\n ? 'var(--malachite-control-border-hover, rgba(0, 175, 102, 0.4))'\n : undefined,\n ...style,\n }}\n >\n {/* Clips here, not on the mirror: the mirror is what translates, and a transform\n carries the element's own clip rect with it, so the window onto the text would\n slide out of the field by exactly `scrollLeft`. */}\n <div className=\"relative flex-1 h-full min-w-0 overflow-hidden\">\n {/* aria-hidden: purely decorative, the input carries the accessible value. */}\n <div\n ref={mirrorRef}\n aria-hidden=\"true\"\n className={`absolute inset-0 flex items-center pointer-events-none ${CONTROL_TEXT_SIZE_CLASS[size]}`}\n style={{ ...textStyle, whiteSpace: 'pre' }}\n >\n {segments.map((segment) => (\n <span\n key={segment.start}\n style={{\n color: TOKEN_COLORS[segment.kind],\n ...(segment.kind === 'error'\n ? { textDecoration: 'underline wavy' }\n : {}),\n }}\n >\n {value.slice(segment.start, segment.end)}\n </span>\n ))}\n <span\n ref={measureRef}\n style={{ position: 'absolute', top: 0, left: 0, visibility: 'hidden' }}\n >\n {value.slice(0, caret)}\n </span>\n </div>\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isMenuOpen}\n aria-controls={isMenuOpen ? listboxId : undefined}\n aria-activedescendant={\n rowsVisible && highlightedIndex >= 0\n ? getRowId(highlightedIndex)\n : undefined\n }\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n spellCheck={false}\n aria-labelledby={ariaLabelledBy}\n // A visible label outranks it, so the fallback only applies without one.\n aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? placeholder)}\n value={value}\n onChange={handleChange}\n onSelect={handleSelect}\n onScroll={() => {\n syncMirrorScroll();\n if (isMenuOpen) {\n updateMenuPosition();\n }\n }}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n setFocused(true);\n setDismissed(false);\n }}\n onBlur={() => setFocused(false)}\n placeholder={placeholder}\n disabled={disabled}\n className={`absolute inset-0 w-full h-full bg-transparent border-none outline-none ${CONTROL_TEXT_SIZE_CLASS[size]} placeholder:text-[var(--malachite-text-placeholder)] placeholder:font-medium disabled:cursor-not-allowed`}\n style={{\n ...textStyle,\n color: 'transparent',\n caretColor: 'var(--malachite-text-primary, rgb(10, 10, 10))',\n }}\n />\n </div>\n {isMenuOpen &&\n createPortal(\n <div\n ref={menuRef}\n id={listboxId}\n role=\"listbox\"\n // Rides the dropdown overlay band, but borrows the multiselect option\n // rows below: their highlight follows `data-highlighted`, which is the\n // keyboard cursor this menu has, rather than a bare `:hover`.\n {...overlayIdentity('dropdown')}\n onMouseDown={handleMenuMouseDown}\n style={{\n position: 'fixed',\n top: menuPosition?.top ?? 0,\n left: menuPosition?.left ?? 0,\n minWidth: Math.min(\n MENU_FALLBACK_WIDTH_PX,\n menuPosition?.width ?? MENU_FALLBACK_WIDTH_PX,\n ),\n maxWidth: Math.min(\n MENU_MAX_WIDTH_PX,\n menuPosition?.width ?? MENU_MAX_WIDTH_PX,\n ),\n background: 'var(--malachite-card-background, rgb(255, 255, 255))',\n border: '1px solid var(--malachite-card-border, rgb(232, 232, 232))',\n borderRadius: 12,\n boxShadow: '0px 2px 5px 0px rgba(0, 0, 0, 0.1)',\n padding: 4,\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n maxHeight: 320,\n overflowY: 'auto',\n fontSize: CONTROL_TEXT_SIZE[size],\n visibility: menuPosition ? 'visible' : 'hidden',\n opacity: menuPosition ? 1 : 0,\n }}\n >\n {menuContent}\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nexport default QueryInput;\nexport { QueryInput };\n"],"names":["SIZE_CLASSES","TOKEN_COLORS","TEXT_STYLE","CONTROL_TEXT_SIZE","MENU_FALLBACK_WIDTH_PX","MENU_MAX_WIDTH_PX","MENU_MESSAGE_STYLE","handleMenuMouseDown","event","sanitizeTokens","value","tokens","sorted","token","a","b","accepted","cursor","buildSegments","segments","QueryInput","onChange","suggestions","activeRange","onAccept","onQueryContextChange","onSubmit","placeholder","size","disabled","loading","emptyMessage","className","style","ariaLabel","ariaLabelledBy","listboxId","useId","getRowId","index","focused","setFocused","useState","caret","setCaret","rawHighlightedIndex","setHighlightedIndex","dismissed","setDismissed","menuPosition","setMenuPosition","inputRef","useRef","mirrorRef","measureRef","menuRef","rowRefs","pendingSelectionRef","suggestionsProvided","suggestionList","hasSuggestions","isMenuOpen","useOwnedByPopover","useCallback","rowsVisible","highlightedIndex","useLayoutEffect","current","syncMirrorScroll","input","mirror","updateMenuPosition","caretOffsetPx","_a","computeCaretMenuGeometry","_b","_c","useEffect","handleScrollOrResize","popEscapeLayer","pushEscapeLayer","pending","row","container","rowBottom","useInsertionEffect","ensureMultiSelectPanelStyles","reportCaret","nextValue","nextCaret","handleChange","next","handleSelect","target","acceptSuggestion","suggestion","fallbackCaret","range","start","end","insertText","handleKeyDown","count","highlighted","textStyle","menuContent","jsxs","jsx","Spinner","element","hoverBorderClass","CONTROL_TEXT_SIZE_CLASS","segment","createPortal","overlayIdentity"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { jsxs as m, jsx as r } from "react/jsx-runtime";
2
+ import { forwardRef as b } from "react";
3
+ import p from "./CustomIcons/SearchIcon.js";
4
+ import { FOCUS_RING as h } from "./focusRing.js";
5
+ const g = `group flex items-center shrink-0 border border-solid border-transparent m-0 cursor-pointer font-sans font-normal text-left rounded-[var(--malachite-radius-xl,12px)] bg-[var(--malachite-pillbutton-background,rgb(241,241,241))] text-[var(--malachite-pillbutton-foreground,rgb(123,123,123))] enabled:hover:bg-[var(--malachite-pillbutton-hover-background,rgb(232,232,232))] disabled:cursor-not-allowed disabled:opacity-50 transition-[background-color] duration-200 ${h}`, f = "inline-flex items-center justify-center h-[25px] px-2 rounded-lg border border-solid border-[var(--malachite-card-border,rgb(232,232,232))] bg-[var(--malachite-card-sunken-background,rgb(250,250,250))] font-mono text-[length:var(--malachite-font-size-small,13px)] font-normal leading-none text-[var(--malachite-text-placeholder,rgb(187,187,187))]", n = {
6
+ field: "w-full h-10 gap-2 px-3 text-[length:var(--malachite-font-size-medium,14px)]",
7
+ icon: "w-9 h-[37px] justify-center p-0"
8
+ }, u = b(
9
+ ({
10
+ label: t = "Search",
11
+ shortcut: a,
12
+ iconOnly: e = !1,
13
+ "aria-label": o,
14
+ className: l = "",
15
+ ...i
16
+ }, s) => /* @__PURE__ */ m(
17
+ "button",
18
+ {
19
+ ref: s,
20
+ type: "button",
21
+ ...i,
22
+ "aria-label": e ? o ?? t : o,
23
+ className: `${g} ${e ? n.icon : n.field} ${l}`.trim(),
24
+ children: [
25
+ /* @__PURE__ */ r(p, { size: 16, className: "shrink-0" }),
26
+ !e && /* @__PURE__ */ r("span", { className: "min-w-0 flex-1 truncate", children: t }),
27
+ !e && a && a.length > 0 && /* @__PURE__ */ r("span", { "aria-hidden": "true", className: "flex shrink-0 items-center gap-[5px]", children: a.map((d, c) => /* @__PURE__ */ r("kbd", { className: f, children: d }, c)) })
28
+ ]
29
+ }
30
+ )
31
+ );
32
+ u.displayName = "SearchTrigger";
33
+ export {
34
+ u as SearchTrigger,
35
+ u as default
36
+ };
37
+ //# sourceMappingURL=SearchTrigger.js.map