@burdenoff/fe-libs 2026.1006.2 → 2026.1007.1

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 (52) hide show
  1. package/dist/chrome/ContextSwitcher.d.ts.map +1 -1
  2. package/dist/chrome/ContextSwitcher.js +93 -89
  3. package/dist/chrome/GlobalSearch.d.ts.map +1 -1
  4. package/dist/chrome/GlobalSearch.js +94 -96
  5. package/dist/chrome/NotificationCenter.d.ts.map +1 -1
  6. package/dist/chrome/NotificationCenter.js +62 -62
  7. package/dist/chrome/ShortcutHelpDialog.d.ts.map +1 -1
  8. package/dist/chrome/ShortcutHelpDialog.js +103 -97
  9. package/dist/chrome/notificationCenter/NotificationPanel.d.ts.map +1 -1
  10. package/dist/chrome/notificationCenter/NotificationPanel.js +28 -17
  11. package/dist/chrome/notificationCenter/usePanelChrome.d.ts +0 -1
  12. package/dist/chrome/notificationCenter/usePanelChrome.d.ts.map +1 -1
  13. package/dist/chrome/notificationCenter/usePanelChrome.js +1 -10
  14. package/dist/chrome/shellOverlayLayer.d.ts +42 -0
  15. package/dist/chrome/shellOverlayLayer.d.ts.map +1 -0
  16. package/dist/chrome/shellOverlayLayer.js +4 -0
  17. package/dist/shared/assistant/appControls/languageReply.d.ts +28 -0
  18. package/dist/shared/assistant/appControls/languageReply.d.ts.map +1 -0
  19. package/dist/shared/assistant/appControls/languageReply.js +17 -0
  20. package/dist/shared/assistant/appControls/text.d.ts +7 -1
  21. package/dist/shared/assistant/appControls/text.d.ts.map +1 -1
  22. package/dist/shared/assistant/appControls/text.js +4 -3
  23. package/dist/shared/assistant/conversation.d.ts +2 -0
  24. package/dist/shared/assistant/conversation.d.ts.map +1 -1
  25. package/dist/shared/assistant/displayContent.d.ts.map +1 -1
  26. package/dist/shared/assistant/displayContent.js +14 -11
  27. package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -1
  28. package/dist/shared/assistant/history/historyMapping.js +10 -5
  29. package/dist/shared/assistant/index.d.ts +1 -0
  30. package/dist/shared/assistant/index.d.ts.map +1 -1
  31. package/dist/shared/assistant/ui/AIAssistantPanel.js +8 -8
  32. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  33. package/dist/shared/assistant/ui/AssistantChatArea.js +1012 -939
  34. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
  35. package/dist/shared/assistant/ui/AssistantMessageItem.js +105 -97
  36. package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
  37. package/dist/shared/assistant/ui/AssistantMoreMenu.js +112 -108
  38. package/dist/shared/assistant/ui/composer/AssistantAttachmentButton.d.ts.map +1 -1
  39. package/dist/shared/assistant/ui/composer/AssistantAttachmentButton.js +66 -62
  40. package/dist/shared/assistant/ui/controlConfirmDialog.js +4 -4
  41. package/dist/shared/assistant/ui/useDropdownEscape.d.ts +8 -30
  42. package/dist/shared/assistant/ui/useDropdownEscape.d.ts.map +1 -1
  43. package/dist/shared/assistant/ui/useDropdownEscape.js +6 -20
  44. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +7 -7
  45. package/dist/shared/assistant/uiActions/recordNames.d.ts +18 -6
  46. package/dist/shared/assistant/uiActions/recordNames.d.ts.map +1 -1
  47. package/dist/shared/assistant/uiActions/recordNames.js +42 -37
  48. package/dist/shared/components/EscapeLayer.d.ts +15 -0
  49. package/dist/shared/components/EscapeLayer.d.ts.map +1 -0
  50. package/dist/shared/components/EscapeLayer.js +31 -0
  51. package/dist/shared-assistant.js +151 -150
  52. package/package.json +3 -1
@@ -1,92 +1,96 @@
1
- import { useAssistantTr as e } from "../../i18n.js";
1
+ import { EscapeLayer as e } from "../../../components/EscapeLayer.js";
2
+ import { useAssistantTr as t } from "../../i18n.js";
2
3
  import "../../attachments.js";
3
- import { availableAttachmentSources as t, deviceHasCamera as n } from "../../attachmentSources.js";
4
- import { hasConnectSource as r, useAssistantConnectSource as i } from "./connectSource.js";
5
- import { AssistantConnectSourceItem as a } from "./AssistantConnectSourceItem.js";
6
- import { useDropdownEscape as o } from "../useDropdownEscape.js";
7
- import { useCallback as s, useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
8
- import { Camera as f, FileText as p, FolderOpen as m, ImageIcon as h, Plus as g } from "lucide-react";
9
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
4
+ import { availableAttachmentSources as n, deviceHasCamera as r } from "../../attachmentSources.js";
5
+ import { hasConnectSource as i, useAssistantConnectSource as a } from "./connectSource.js";
6
+ import { AssistantConnectSourceItem as o } from "./AssistantConnectSourceItem.js";
7
+ import { useDropdownEscape as s } from "../useDropdownEscape.js";
8
+ import { useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
9
+ import { Camera as p, FileText as m, FolderOpen as h, ImageIcon as g, Plus as _ } from "lucide-react";
10
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
10
11
  //#region src/shared/assistant/ui/composer/AssistantAttachmentButton.tsx
11
- var y = "flex size-9 items-center justify-center rounded-full border border-border-subtle bg-bg-elevated text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong disabled:cursor-not-allowed disabled:text-text-muted disabled:hover:bg-bg-elevated", b = `${y} sm:w-auto sm:gap-1.5 sm:px-3`, x = {
12
- camera: f,
13
- gallery: h,
14
- documents: p,
15
- files: m
16
- }, S = ({ onFiles: f, onPickerOpen: p, direction: m = "up", canAddMore: h, disabled: S = !1, showLabel: C = !1 }) => {
17
- let w = e(), T = u(null), E = u(null), D = u(null), [O, k] = d(!1), A = u(p);
18
- A.current = p;
19
- let j = l(() => t(n()), []), M = r(i()), N = h || M, P = h ? M ? `${w("composer.attach", "Attach files or photos")} · ${w("composer.connectSource", "Connect a source")}` : w("composer.attach", "Attach files or photos") : w("composer.attachFull", "Attachment limit reached ({{max}})", { max: 5 }), F = C && h && M ? w("composer.connectSource", "Connect a source") : null;
20
- o(O, E, D, () => k(!1)), c(() => {
21
- if (!O) return;
12
+ var b = "flex size-9 items-center justify-center rounded-full border border-border-subtle bg-bg-elevated text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong disabled:cursor-not-allowed disabled:text-text-muted disabled:hover:bg-bg-elevated", x = `${b} sm:w-auto sm:gap-1.5 sm:px-3`, S = {
13
+ camera: p,
14
+ gallery: g,
15
+ documents: m,
16
+ files: h
17
+ }, C = ({ onFiles: p, onPickerOpen: m, direction: h = "up", canAddMore: g, disabled: C = !1, showLabel: w = !1 }) => {
18
+ let T = t(), E = d(null), D = d(null), O = d(null), [k, A] = f(!1), j = d(m);
19
+ j.current = m;
20
+ let M = u(() => n(r()), []), N = i(a()), P = g || N, F = g ? N ? `${T("composer.attach", "Attach files or photos")} · ${T("composer.connectSource", "Connect a source")}` : T("composer.attach", "Attach files or photos") : T("composer.attachFull", "Attachment limit reached ({{max}})", { max: 5 }), I = w && g && N ? T("composer.connectSource", "Connect a source") : null, L = s(O, () => A(!1));
21
+ l(() => {
22
+ if (!k) return;
22
23
  let e = (e) => {
23
24
  let t = e.target;
24
- E.current?.contains(t) || D.current?.contains(t) || k(!1);
25
+ D.current?.contains(t) || O.current?.contains(t) || A(!1);
25
26
  };
26
27
  return window.addEventListener("mousedown", e), () => {
27
28
  window.removeEventListener("mousedown", e);
28
29
  };
29
- }, [O]);
30
- let I = s((e) => {
31
- f(e.target.files), e.target.value = "";
32
- }, [f]), L = s((e) => {
33
- let t = T.current;
34
- t && (t.accept = e.accept, t.multiple = e.multiple, e.capture ? t.setAttribute("capture", e.capture) : t.removeAttribute("capture"), k(!1), A.current?.(), t.click());
30
+ }, [k]);
31
+ let R = c((e) => {
32
+ p(e.target.files), e.target.value = "";
33
+ }, [p]), z = c((e) => {
34
+ let t = E.current;
35
+ t && (t.accept = e.accept, t.multiple = e.multiple, e.capture ? t.setAttribute("capture", e.capture) : t.removeAttribute("capture"), A(!1), j.current?.(), t.click());
35
36
  }, []);
36
- return /* @__PURE__ */ v("div", {
37
+ return /* @__PURE__ */ y("div", {
37
38
  className: "relative flex-shrink-0",
38
39
  children: [
39
- /* @__PURE__ */ _("input", {
40
- ref: T,
40
+ /* @__PURE__ */ v("input", {
41
+ ref: E,
41
42
  type: "file",
42
43
  multiple: !0,
43
44
  className: "hidden",
44
- onChange: I,
45
+ onChange: R,
45
46
  tabIndex: -1,
46
47
  "aria-hidden": "true",
47
48
  "data-testid": "assistant-attach-input"
48
49
  }),
49
- /* @__PURE__ */ v("button", {
50
- ref: D,
50
+ /* @__PURE__ */ y("button", {
51
+ ref: O,
51
52
  type: "button",
52
- onClick: () => k((e) => !e),
53
- disabled: S || !N,
54
- title: P,
55
- "aria-label": P,
53
+ onClick: () => A((e) => !e),
54
+ disabled: C || !P,
55
+ title: F,
56
+ "aria-label": F,
56
57
  "aria-haspopup": "menu",
57
- "aria-expanded": O,
58
- className: F ? b : y,
58
+ "aria-expanded": k,
59
+ className: I ? x : b,
59
60
  "data-testid": "assistant-attach",
60
- children: [/* @__PURE__ */ _(g, { className: "size-4" }), F ? /* @__PURE__ */ _("span", {
61
+ children: [/* @__PURE__ */ v(_, { className: "size-4" }), I ? /* @__PURE__ */ v("span", {
61
62
  className: "hidden max-w-[10rem] truncate text-[13px] font-medium leading-tight sm:block",
62
63
  "data-testid": "assistant-attach-label",
63
- children: F
64
+ children: I
64
65
  }) : null]
65
66
  }),
66
- O ? /* @__PURE__ */ v("div", {
67
- ref: E,
68
- role: "menu",
69
- "aria-label": w("composer.attachSource", "Attach from"),
70
- className: `absolute ${m === "up" ? "bottom-full mb-2" : "top-full mt-2"} left-0 z-30 min-w-44 overflow-hidden rounded-xl border border-border-default bg-bg-elevated py-1 shadow-lg`,
71
- "data-testid": "assistant-attach-menu",
72
- children: [j.map((e) => {
73
- let t = x[e.id];
74
- return /* @__PURE__ */ v("button", {
75
- type: "button",
76
- role: "menuitem",
77
- disabled: !h,
78
- onClick: () => L(e),
79
- className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm text-text-primary transition-colors hover:bg-bg-sunken focus:outline-none focus-visible:bg-bg-sunken disabled:cursor-not-allowed disabled:text-text-muted disabled:hover:bg-transparent",
80
- "data-testid": `assistant-attach-source-${e.id}`,
81
- children: [/* @__PURE__ */ _(t, {
82
- className: "size-4 flex-shrink-0 text-text-secondary",
83
- "aria-hidden": "true"
84
- }), w(e.labelKey, e.labelFallback)]
85
- }, e.id);
86
- }), /* @__PURE__ */ _(a, { onActivate: () => k(!1) })]
67
+ k ? /* @__PURE__ */ v(e, {
68
+ ...L,
69
+ children: /* @__PURE__ */ y("div", {
70
+ ref: D,
71
+ role: "menu",
72
+ "aria-label": T("composer.attachSource", "Attach from"),
73
+ className: `absolute ${h === "up" ? "bottom-full mb-2" : "top-full mt-2"} left-0 z-30 min-w-44 overflow-hidden rounded-xl border border-border-default bg-bg-elevated py-1 shadow-lg`,
74
+ "data-testid": "assistant-attach-menu",
75
+ children: [M.map((e) => {
76
+ let t = S[e.id];
77
+ return /* @__PURE__ */ y("button", {
78
+ type: "button",
79
+ role: "menuitem",
80
+ disabled: !g,
81
+ onClick: () => z(e),
82
+ className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm text-text-primary transition-colors hover:bg-bg-sunken focus:outline-none focus-visible:bg-bg-sunken disabled:cursor-not-allowed disabled:text-text-muted disabled:hover:bg-transparent",
83
+ "data-testid": `assistant-attach-source-${e.id}`,
84
+ children: [/* @__PURE__ */ v(t, {
85
+ className: "size-4 flex-shrink-0 text-text-secondary",
86
+ "aria-hidden": "true"
87
+ }), T(e.labelKey, e.labelFallback)]
88
+ }, e.id);
89
+ }), /* @__PURE__ */ v(o, { onActivate: () => A(!1) })]
90
+ })
87
91
  }) : null
88
92
  ]
89
93
  });
90
94
  };
91
95
  //#endregion
92
- export { S as AssistantAttachmentButton };
96
+ export { C as AssistantAttachmentButton };
@@ -1,6 +1,6 @@
1
1
  import { useAssistantTr as e } from "../i18n.js";
2
- import { AssistantControlConfirmDialog as t } from "./AssistantControlConfirmDialog.js";
3
- import { confirmDialogCopy as n } from "../appControls/copy.js";
2
+ import { confirmDialogCopy as t } from "../appControls/copy.js";
3
+ import { AssistantControlConfirmDialog as n } from "./AssistantControlConfirmDialog.js";
4
4
  import { createContext as r, useCallback as i, useContext as a, useMemo as o, useState as s } from "react";
5
5
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
6
  //#region src/shared/assistant/ui/controlConfirmDialog.tsx
@@ -33,9 +33,9 @@ var f = ({ children: r }) => {
33
33
  }), [p, d.open]);
34
34
  return /* @__PURE__ */ l(u.Provider, {
35
35
  value: g,
36
- children: [r, d.request ? /* @__PURE__ */ c(t, {
36
+ children: [r, d.request ? /* @__PURE__ */ c(n, {
37
37
  open: d.open,
38
- copy: n(a, d.request.prompt),
38
+ copy: t(a, d.request.prompt),
39
39
  tr: a,
40
40
  onConfirm: h,
41
41
  onDismiss: m
@@ -1,34 +1,12 @@
1
1
  import { RefObject } from 'react';
2
+ interface DropdownEscapeHandlers {
3
+ onDismiss: () => void;
4
+ }
2
5
  /**
3
- * Escape closes a dropdown inside the assistant panel — and closes ONLY it.
4
- *
5
- * ★★★ WHY CAPTURE. Both dropdowns used to listen on `window` in the bubble
6
- * phase. `window` is the LAST node an event reaches, so the panel's own
7
- * shortcut hook — on `document`, also bubbling — always ran first, saw focus
8
- * inside the panel, found no full-surface overlay open, and closed the WHOLE
9
- * assistant. One press dismissed a dropdown and destroyed the streaming turn,
10
- * the draft and the attachments; this handler then ran on an unmounted
11
- * component. Capture on `document` reaches this node ahead of every bubble
12
- * listener on it, whatever order they registered in — the only placement that
13
- * reliably wins.
14
- *
15
- * ★★★ WHY IT IS STILL SCOPED TO FOCUS. Consuming Escape unconditionally while
16
- * open is the same mistake pointing the other way: the dropdown stays mounted
17
- * when focus leaves it without a click (open it from the keyboard, Tab to the
18
- * transcript toggle, press Enter), and it would then swallow an Escape meant
19
- * for the layer the user actually opened last, closing a menu they cannot even
20
- * see. So the key is taken only while focus is still inside the menu or on its
21
- * trigger — the same containment question `focusIsInsidePanel` answers for the
22
- * panel, and the same one this component's outside-click handler already asks.
23
- *
24
- * ★ `stopPropagation`, NOT `stopImmediatePropagation`: stopping in the capture
25
- * phase already prevents every bubble listener from seeing the key. The
26
- * immediate variant would additionally kill unrelated capture listeners on
27
- * `document`, which are none of a dropdown's business.
28
- *
29
- * Shared by `AssistantMoreMenu` and `AssistantAttachmentButton` so the rule
30
- * lives in one place — the two copies had drifted into being identical
31
- * comment-for-comment, which is a third copy waiting to happen.
6
+ * Dismissal for an open dropdown's shared Radix EscapeLayer.
7
+ * The mounted top layer owns Escape even after keyboard focus leaves it;
8
+ * the existing outside-mousedown behaviour stays with the callers.
32
9
  */
33
- export declare function useDropdownEscape(open: boolean, menuRef: RefObject<HTMLElement | null>, buttonRef: RefObject<HTMLElement | null>, close: () => void): void;
10
+ export declare function useDropdownEscape(buttonRef: RefObject<HTMLElement | null>, close: () => void): DropdownEscapeHandlers;
11
+ export {};
34
12
  //# sourceMappingURL=useDropdownEscape.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDropdownEscape.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/useDropdownEscape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACtC,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACxC,KAAK,EAAE,MAAM,IAAI,GAChB,IAAI,CAiCN"}
1
+ {"version":3,"file":"useDropdownEscape.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/useDropdownEscape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpD,UAAU,sBAAsB;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACxC,KAAK,EAAE,MAAM,IAAI,GAChB,sBAAsB,CAMxB"}
@@ -1,23 +1,9 @@
1
- import { focusIsInsidePanel as e } from "./panelOverlays.js";
2
- import { useEffect as t, useRef as n } from "react";
1
+ import { useCallback as e } from "react";
3
2
  //#region src/shared/assistant/ui/useDropdownEscape.ts
4
- function r(r, i, a, o) {
5
- let s = n(o);
6
- t(() => {
7
- s.current = o;
8
- }, [o]), t(() => {
9
- if (!r) return;
10
- let t = (t) => {
11
- if (t.key !== "Escape") return;
12
- let n = document.activeElement;
13
- (e(i.current, n) || e(a.current, n)) && (t.preventDefault(), t.stopPropagation(), s.current(), a.current?.focus());
14
- };
15
- return document.addEventListener("keydown", t, !0), () => document.removeEventListener("keydown", t, !0);
16
- }, [
17
- r,
18
- i,
19
- a
20
- ]);
3
+ function t(t, n) {
4
+ return { onDismiss: e(() => {
5
+ n(), t.current?.focus();
6
+ }, [n, t]) };
21
7
  }
22
8
  //#endregion
23
- export { r as useDropdownEscape };
9
+ export { t as useDropdownEscape };
@@ -4,9 +4,9 @@ import { useAssistantTr as n } from "../../i18n.js";
4
4
  import { micIsInterrupt as r, showsAssistantCaption as ee, voiceStageState as i } from "../../voice/voiceStageState.js";
5
5
  import { VOICE_THINKING_LABEL as a, composeVoiceStatus as te, voiceStatusSuffix as ne } from "../../voice/voiceStatus.js";
6
6
  import { spokenSoFar as o } from "../../voice/voiceSession.js";
7
- import { ASSISTANT_PANEL_ATTR as re, ASSISTANT_VOICE_SESSION_ATTR as ie } from "../panelOverlays.js";
8
- import { AssistantAttachmentButton as ae } from "../composer/AssistantAttachmentButton.js";
9
- import { AssistantAttachmentChips as oe } from "../composer/AssistantAttachmentChips.js";
7
+ import { AssistantAttachmentButton as re } from "../composer/AssistantAttachmentButton.js";
8
+ import { AssistantAttachmentChips as ie } from "../composer/AssistantAttachmentChips.js";
9
+ import { ASSISTANT_PANEL_ATTR as ae, ASSISTANT_VOICE_SESSION_ATTR as oe } from "../panelOverlays.js";
10
10
  import { AssistantVoiceOrb as se } from "./AssistantVoiceOrb.js";
11
11
  import { VoiceMiniController as ce } from "./VoiceMiniController.js";
12
12
  import { VoiceStage as le } from "./VoiceStage.js";
@@ -38,7 +38,7 @@ var m = ({ session: m, turns: ye = [], onSaveTranscript: be, onContinueInChat: x
38
38
  };
39
39
  }, []), c(() => {
40
40
  j.current?.focus();
41
- }, []), e(M, { fallbackSelector: `[${re}]` }), c(() => {
41
+ }, []), e(M, { fallbackSelector: `[${ae}]` }), c(() => {
42
42
  let e = (e) => {
43
43
  if (e.key === "Escape") {
44
44
  let t = fe({
@@ -107,7 +107,7 @@ var m = ({ session: m, turns: ye = [], onSaveTranscript: be, onContinueInChat: x
107
107
  "aria-modal": F || void 0,
108
108
  "aria-label": O("voiceSession.title", "Voice conversation"),
109
109
  "data-testid": "assistant-voice-session",
110
- [ie]: "",
110
+ [oe]: "",
111
111
  children: [
112
112
  /* @__PURE__ */ p("button", {
113
113
  ref: j,
@@ -211,7 +211,7 @@ var m = ({ session: m, turns: ye = [], onSaveTranscript: be, onContinueInChat: x
211
211
  }) : null,
212
212
  y ? /* @__PURE__ */ f("div", {
213
213
  className: `absolute ${F ? "left-6 top-6" : I ? "left-11 top-2" : "left-3 top-3"}`,
214
- children: /* @__PURE__ */ f(ae, {
214
+ children: /* @__PURE__ */ f(re, {
215
215
  onFiles: (e) => {
216
216
  y(e), P((e) => e === "mini" ? "panel" : e);
217
217
  },
@@ -223,7 +223,7 @@ var m = ({ session: m, turns: ye = [], onSaveTranscript: be, onContinueInChat: x
223
223
  (v.length > 0 || b > 0) && !I ? /* @__PURE__ */ f("div", {
224
224
  className: `absolute ${F ? "bottom-24 left-24 right-24" : "bottom-16 left-16 right-16"}`,
225
225
  "data-testid": "assistant-voice-attachments",
226
- children: /* @__PURE__ */ f(oe, {
226
+ children: /* @__PURE__ */ f(ie, {
227
227
  attachments: v,
228
228
  onRemove: Ce ?? (() => void 0),
229
229
  onRetry: we ?? (() => void 0),
@@ -47,28 +47,40 @@ export interface RecordRequest {
47
47
  /** Adapters named by the sentence's noun; empty: every adapter. */
48
48
  adapterIds: string[];
49
49
  }
50
- export declare function parseRecordRequest(utterance: string, adapters: readonly Pick<AssistantRecordAdapter, "id" | "nouns">[]): RecordRequest | null;
50
+ export declare function parseRecordRequest(utterance: string, adapters: readonly Pick<AssistantRecordAdapter, 'id' | 'nouns'>[]): RecordRequest | null;
51
51
  export interface RecordAnswer {
52
- adapter: Pick<AssistantRecordAdapter, "id">;
52
+ adapter: Pick<AssistantRecordAdapter, 'id'>;
53
53
  route: AssistantEntityRoute;
54
54
  /** The kind's translated name. */
55
55
  noun: string;
56
56
  matches: readonly AssistantRecordMatch[];
57
57
  }
58
58
  export type RecordPlan = {
59
- kind: "none";
59
+ kind: 'none';
60
60
  } | {
61
- kind: "open";
61
+ kind: 'open';
62
62
  destination: LocalDestination;
63
63
  } | {
64
- kind: "choose";
64
+ kind: 'choose';
65
65
  /** `kinds`: the same name in different kinds of record; `records`: several of one kind. */
66
- why: "kinds" | "records";
66
+ why: 'kinds' | 'records';
67
67
  candidates: LocalDestination[];
68
68
  /** The distinct kind names among the candidates, in order. */
69
69
  nouns: string[];
70
70
  };
71
71
  export declare const RECORD_CHOICE_MAX = 4;
72
+ /**
73
+ * ★ BOFF-8680: THE form a record's name and the name a person typed are
74
+ * compared in. It is `canonical` (`appControls/text.ts`), the very function
75
+ * that turned the spoken or typed sentence into the request, so the two sides
76
+ * cannot disagree: "Sales & Marketing" is "sales and marketing" on both,
77
+ * "P&L" is "p and l", and a Hindi or Tamil word keeps its vowel signs.
78
+ *
79
+ * A PRODUCT ADAPTER that wants to recognise an EXACT name (to rank it first, or
80
+ * to skip a fuzzy search) MUST use this function and not its own copy: a copy
81
+ * drifts, and nothing fails when it does.
82
+ */
83
+ export declare function normaliseRecordName(value: string): string;
72
84
  export declare function planRecordResolution(name: string, answers: readonly RecordAnswer[]): RecordPlan;
73
85
  /** How long the panel waits for the product's APIs before the sentence goes to the model. */
74
86
  export declare const RECORD_LOOKUP_TIMEOUT_MS = 2500;
@@ -1 +1 @@
1
- {"version":3,"file":"recordNames.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/recordNames.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recordNames.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/recordNames.ts"],"names":[],"mappings":"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"}
@@ -1,59 +1,64 @@
1
- import { fillEntityRoute as e } from "./entityRoutes.js";
2
- import { ENTITY_TARGET_PREFIX as t } from "./resolveTarget.js";
1
+ import { canonical as e } from "../appControls/text.js";
2
+ import { fillEntityRoute as t } from "./entityRoutes.js";
3
+ import { ENTITY_TARGET_PREFIX as n } from "./resolveTarget.js";
3
4
  //#region src/shared/assistant/uiActions/recordNames.ts
4
- var n = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), r = new Set(/* @__PURE__ */ "it.that.this.there.here.back.them.those.one.link.page.screen.list.tab.section.view.all.my.the.new.first.second.third.fourth.last.next.previous.settings".split(".")), i = /(?:^| )(?:page|screen|list|tab|section|view|settings|menu)$/, a = 60, o = "(?:open|go to|take me to|pull up|bring up|navigate to|switch to|show me)", s = "(?:open|go to|take me to|pull up|bring up|navigate to)";
5
- function c(e, t) {
5
+ var r = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = new Set(/* @__PURE__ */ "it.that.this.there.here.back.them.those.one.link.page.screen.list.tab.section.view.all.my.the.new.first.second.third.fourth.last.next.previous.settings".split(".")), a = /(?:^| )(?:page|screen|list|tab|section|view|settings|menu)$/, o = 60, s = "(?:open|go to|take me to|pull up|bring up|navigate to|switch to|show me)", c = "(?:open|go to|take me to|pull up|bring up|navigate to)";
6
+ function l(e, t) {
6
7
  if (t.length === 0) return null;
7
- let c = (e) => t.filter((t) => t.nouns.includes(e)).map((e) => e.id), l = [...new Set(t.flatMap((e) => e.nouns))].sort((e, t) => t.length - e.length), u = (e) => {
8
+ let n = (e) => t.filter((t) => t.nouns.includes(e)).map((e) => e.id), l = [...new Set(t.flatMap((e) => e.nouns))].sort((e, t) => t.length - e.length), u = (e) => {
8
9
  let t = e.trim();
9
- return t.length >= 2 && t.length <= a && !r.has(t) && !i.test(t);
10
+ return t.length >= 2 && t.length <= o && !i.has(t) && !a.test(t);
10
11
  };
11
12
  if (l.length > 0) {
12
- let t = l.map((e) => n(e)).join("|"), r = RegExp(`^${o} (?:the |my )?(${t}) (?:(?:called|named) )?(.+)$`).exec(e);
13
- if (r && u(r[2] ?? "")) {
14
- let e = c(r[1] ?? "");
13
+ let t = l.map((e) => r(e)).join("|"), i = RegExp(`^${s} (?:the |my )?(${t}) (?:(?:called|named) )?(.+)$`).exec(e);
14
+ if (i && u(i[2] ?? "")) {
15
+ let e = n(i[1] ?? "");
15
16
  if (e.length > 0) return {
16
- name: (r[2] ?? "").trim(),
17
+ name: (i[2] ?? "").trim(),
17
18
  adapterIds: e
18
19
  };
19
20
  }
20
- let i = RegExp(`^${o} (?:the |my )?(.+?) (${t})$`).exec(e);
21
- if (i && u(i[1] ?? "")) {
22
- let e = c(i[2] ?? "");
21
+ let a = RegExp(`^${s} (?:the |my )?(.+?) (${t})$`).exec(e);
22
+ if (a && u(a[1] ?? "")) {
23
+ let e = n(a[2] ?? "");
23
24
  if (e.length > 0) return {
24
- name: (i[1] ?? "").trim(),
25
+ name: (a[1] ?? "").trim(),
25
26
  adapterIds: e
26
27
  };
27
28
  }
28
29
  }
29
- let d = RegExp(`^${s} (?:the |my )?(.+)$`).exec(e);
30
+ let d = RegExp(`^${c} (?:the |my )?(.+)$`).exec(e);
30
31
  return d && u(d[1] ?? "") && (d[1] ?? "").length >= 3 ? {
31
32
  name: (d[1] ?? "").trim(),
32
33
  adapterIds: []
33
34
  } : null;
34
35
  }
35
- var l = 4, u = (e) => e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
36
- function d(e, t) {
36
+ var u = 4;
37
+ function d(t) {
38
+ return e(t);
39
+ }
40
+ var f = d;
41
+ function p(e, t) {
37
42
  let n = t.split(" ");
38
43
  return e.split(" ").every((e) => n.some((t) => t.startsWith(e)));
39
44
  }
40
- function f(n, r) {
41
- let i = u(n);
45
+ function m(e, r) {
46
+ let i = f(e);
42
47
  if (!i) return { kind: "none" };
43
48
  let a = [];
44
- for (let n of r) for (let r of n.matches) {
45
- let o = e(n.route, r.params);
49
+ for (let e of r) for (let r of e.matches) {
50
+ let o = t(e.route, r.params);
46
51
  if (o === null) continue;
47
- let s = u(r.name), c = s === i;
48
- !c && !d(i, s) || a.some((e) => e.destination.path === o) || a.push({
49
- adapterId: n.adapter.id,
50
- noun: n.noun,
52
+ let s = f(r.name), c = s === i;
53
+ !c && !p(i, s) || a.some((e) => e.destination.path === o) || a.push({
54
+ adapterId: e.adapter.id,
55
+ noun: e.noun,
51
56
  exact: c,
52
57
  destination: {
53
- id: `${t}${n.route.id}`,
54
- label: r.name.trim().slice(0, 80) || n.noun,
58
+ id: `${n}${e.route.id}`,
59
+ label: r.name.trim().slice(0, 80) || e.noun,
55
60
  path: o,
56
- context: n.noun
61
+ context: e.noun
57
62
  }
58
63
  });
59
64
  }
@@ -71,23 +76,23 @@ function f(n, r) {
71
76
  nouns: [...new Set(l.map((e) => e.noun))]
72
77
  };
73
78
  }
74
- var p = 2500, m = 50, h = 200;
75
- function g(e) {
79
+ var h = 2500, g = 50, _ = 200;
80
+ function v(e) {
76
81
  if (typeof e != "object" || !e) return !1;
77
82
  let { name: t, params: n } = e;
78
83
  if (typeof t != "string") return !1;
79
84
  let r = t.trim();
80
- if (r.length === 0 || r.length > h || typeof n != "object" || !n || Array.isArray(n)) return !1;
85
+ if (r.length === 0 || r.length > _ || typeof n != "object" || !n || Array.isArray(n)) return !1;
81
86
  let i = Object.values(n);
82
87
  return i.length > 0 && i.every((e) => typeof e == "string");
83
88
  }
84
- function _(e) {
89
+ function y(e) {
85
90
  if (!Array.isArray(e)) return [];
86
91
  let t = [];
87
- for (let n of e) if (g(n) && t.push(n), t.length >= 50) break;
92
+ for (let n of e) if (v(n) && t.push(n), t.length >= 50) break;
88
93
  return t;
89
94
  }
90
- async function v(e) {
95
+ async function b(e) {
91
96
  let t = new AbortController(), n, r = new Promise((r) => {
92
97
  n = setTimeout(() => {
93
98
  t.abort(), r(null);
@@ -111,10 +116,10 @@ async function v(e) {
111
116
  adapter: n,
112
117
  route: i,
113
118
  noun: s,
114
- matches: _(o)
119
+ matches: y(o)
115
120
  };
116
121
  }));
117
- return f(e.name, n);
122
+ return m(e.name, n);
118
123
  } catch {
119
124
  return { kind: "none" };
120
125
  } finally {
@@ -122,4 +127,4 @@ async function v(e) {
122
127
  }
123
128
  }
124
129
  //#endregion
125
- export { l as RECORD_CHOICE_MAX, p as RECORD_LOOKUP_TIMEOUT_MS, m as RECORD_MATCHES_MAX, g as isRecordMatch, v as lookupNamedRecords, c as parseRecordRequest, f as planRecordResolution, _ as sanitizeRecordMatches };
130
+ export { u as RECORD_CHOICE_MAX, h as RECORD_LOOKUP_TIMEOUT_MS, g as RECORD_MATCHES_MAX, v as isRecordMatch, b as lookupNamedRecords, d as normaliseRecordName, l as parseRecordRequest, m as planRecordResolution, y as sanitizeRecordMatches };
@@ -0,0 +1,15 @@
1
+ import { ReactElement } from 'react';
2
+ interface EscapeLayerProps {
3
+ children: ReactElement;
4
+ onDismiss: () => void;
5
+ /** Modal chrome joins the focus/pointer stack and paints in the same root as Dialog. */
6
+ modal?: boolean;
7
+ }
8
+ /**
9
+ * Custom chrome overlays share Radix's stack with dialogs and menus (BOFF-8677).
10
+ * Only the top layer takes Escape, before the assistant's bubble listener sees it.
11
+ * Nonmodal owners keep their existing outside-click and focus behaviour.
12
+ */
13
+ export declare function EscapeLayer({ children, onDismiss, modal, }: EscapeLayerProps): ReactElement;
14
+ export {};
15
+ //# sourceMappingURL=EscapeLayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EscapeLayer.d.ts","sourceRoot":"","sources":["../../../src/shared/components/EscapeLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,UAAU,gBAAgB;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,wFAAwF;IACxF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,SAAS,EACT,KAAa,GACd,EAAE,gBAAgB,GAAG,YAAY,CA+BjC"}
@@ -0,0 +1,31 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { DismissableLayer as t, DismissableLayerBranch as n } from "@radix-ui/react-dismissable-layer";
3
+ import { FocusScope as r } from "@radix-ui/react-focus-scope";
4
+ import { createPortal as i } from "react-dom";
5
+ //#region src/shared/components/EscapeLayer.tsx
6
+ var a = (e) => e.preventDefault();
7
+ function o({ children: o, onDismiss: s, modal: c = !1 }) {
8
+ let l = /* @__PURE__ */ e(t, {
9
+ asChild: !0,
10
+ disableOutsidePointerEvents: c,
11
+ onEscapeKeyDown: (e) => {
12
+ e.defaultPrevented || (e.preventDefault(), s());
13
+ },
14
+ onPointerDownOutside: a,
15
+ onFocusOutside: a,
16
+ children: o
17
+ });
18
+ if (!c) return l;
19
+ let u = /* @__PURE__ */ e(r, {
20
+ asChild: !0,
21
+ loop: !0,
22
+ trapped: !0,
23
+ children: /* @__PURE__ */ e(n, {
24
+ asChild: !0,
25
+ children: l
26
+ })
27
+ });
28
+ return typeof document > "u" ? u : i(u, document.body);
29
+ }
30
+ //#endregion
31
+ export { o as EscapeLayer };