pixelize-design-library 2.4.2-beta.63 → 2.4.2-beta.65

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 (135) hide show
  1. package/CHANGELOG.md +130 -8
  2. package/COMPONENT-GOTCHAS.md +63 -7
  3. package/DESIGN-GUIDE.md +8 -3
  4. package/dist/Components/Button/Button.styles.js +7 -2
  5. package/dist/Components/CopyButton/CopyButton.d.ts +3 -1
  6. package/dist/Components/CopyButton/CopyButton.js +2 -2
  7. package/dist/Components/Drawer/Drawer.d.ts +1 -1
  8. package/dist/Components/Drawer/Drawer.js +6 -2
  9. package/dist/Components/Drawer/DrawerProps.d.ts +4 -0
  10. package/dist/Components/Dropdown/DropDown.js +2 -9
  11. package/dist/Components/FilePreview/FilePreview.js +2 -1
  12. package/dist/Components/FileUploader/FileUploader.js +4 -0
  13. package/dist/Components/FileUploader/FileUploaderProps.d.ts +1 -1
  14. package/dist/Components/FormDrawer/FormDrawer.d.ts +1 -1
  15. package/dist/Components/FormDrawer/FormDrawer.js +3 -3
  16. package/dist/Components/FormDrawer/FormDrawerProps.d.ts +2 -0
  17. package/dist/Components/Input/TextInput.styles.js +10 -6
  18. package/dist/Components/KanbanBoard/KanbanBoard.js +6 -5
  19. package/dist/Components/Modal/dialogNaming.d.ts +8 -0
  20. package/dist/Components/Modal/dialogNaming.js +21 -0
  21. package/dist/Components/NavLauncher/LauncherTabs.js +2 -2
  22. package/dist/Components/NavLauncher/NavLauncher.d.ts +1 -1
  23. package/dist/Components/NavLauncher/NavLauncher.js +257 -47
  24. package/dist/Components/NavLauncher/NavLauncherProps.d.ts +79 -3
  25. package/dist/Components/NavLauncher/ScopeBar.d.ts +14 -0
  26. package/dist/Components/NavLauncher/ScopeBar.js +137 -0
  27. package/dist/Components/NavLauncher/engine/distance.d.ts +4 -0
  28. package/dist/Components/NavLauncher/engine/distance.js +41 -0
  29. package/dist/Components/NavLauncher/engine/engine.d.ts +84 -0
  30. package/dist/Components/NavLauncher/engine/engine.js +471 -0
  31. package/dist/Components/NavLauncher/engine/fold.d.ts +15 -0
  32. package/dist/Components/NavLauncher/engine/fold.js +83 -0
  33. package/dist/Components/NavLauncher/engine/index.d.ts +21 -0
  34. package/dist/Components/NavLauncher/engine/index.js +17 -0
  35. package/dist/Components/NavLauncher/launcherParts.d.ts +2 -0
  36. package/dist/Components/NavLauncher/launcherParts.js +11 -7
  37. package/dist/Components/NavLauncher/match.d.ts +13 -2
  38. package/dist/Components/NavLauncher/match.js +26 -12
  39. package/dist/Components/NavLauncher/searchLayout.d.ts +60 -0
  40. package/dist/Components/NavLauncher/searchLayout.js +108 -0
  41. package/dist/Components/NavLauncher/spotlight.d.ts +39 -0
  42. package/dist/Components/NavLauncher/spotlight.js +202 -0
  43. package/dist/Components/NavLauncher/spotlightParts.d.ts +49 -0
  44. package/dist/Components/NavLauncher/spotlightParts.js +108 -0
  45. package/dist/Components/NavigationBar/NavigationBar.js +2 -1
  46. package/dist/Components/OrgSwitcher/OrgSwitcher.js +2 -4
  47. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +6 -5
  48. package/dist/Components/ScrollToTop/ScrollToTop.js +4 -3
  49. package/dist/Components/SearchSelect/SearchSelect.js +4 -16
  50. package/dist/Components/Select/SelectPopup.js +1 -3
  51. package/dist/Components/Select/optionRowInk.d.ts +12 -0
  52. package/dist/Components/Select/optionRowInk.js +10 -1
  53. package/dist/Components/SelectSearch/SelectSearch.js +1 -10
  54. package/dist/Components/Table/Table.js +3 -2
  55. package/dist/Components/Table/TableProps.d.ts +1 -1
  56. package/dist/Components/Table/components/TableBody.js +9 -1
  57. package/dist/Components/Table/components/TableHeader.js +9 -2
  58. package/dist/Components/Table/components/TableLoading.d.ts +4 -1
  59. package/dist/Components/Table/components/TableLoading.js +13 -6
  60. package/dist/Components/Table/filters/CompactSelect.js +1 -10
  61. package/dist/Components/Table/variants/TableVariantContext.d.ts +1 -1
  62. package/dist/Components/Table/variants/TableVariantContext.js +3 -3
  63. package/dist/Components/WizardDialog/WizardDialog.d.ts +1 -1
  64. package/dist/Components/WizardDialog/WizardDialog.js +15 -3
  65. package/dist/Components/WizardDialog/WizardDialogProps.d.ts +5 -3
  66. package/dist/Components/WorkspaceWindow/WorkspaceTrayPreview.js +4 -0
  67. package/dist/Components/WorkspaceWindow/WorkspaceWindow.d.ts +2 -2
  68. package/dist/Components/WorkspaceWindow/WorkspaceWindow.js +26 -18
  69. package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts +38 -8
  70. package/dist/Theme/chakra/Menu.styles.d.ts +8 -0
  71. package/dist/Theme/chakra/Menu.styles.js +7 -0
  72. package/dist/Theme/chakra/componentStyles.d.ts +8 -0
  73. package/dist/Theme/chakra/componentStyles.js +2 -2
  74. package/dist/Theme/chakra/ringShadow.d.ts +3 -0
  75. package/dist/Theme/chakra/ringShadow.js +7 -0
  76. package/dist/Theme/tokens/builders/accentText.d.ts +2 -0
  77. package/dist/Theme/tokens/builders/accentText.js +7 -1
  78. package/dist/Theme/tokens/builders/buildDarkPalette.d.ts +1 -1
  79. package/dist/Theme/tokens/builders/buildDarkPalette.js +5 -5
  80. package/dist/Theme/tokens/builders/filledSurface.d.ts +5 -1
  81. package/dist/Theme/tokens/builders/filledSurface.js +17 -4
  82. package/dist/Theme/tokens/builders/planeStep.d.ts +1 -0
  83. package/dist/Theme/tokens/builders/planeStep.js +5 -4
  84. package/dist/Utils/table.js +2 -2
  85. package/dist/esm/Components/Button/Button.styles.js +8 -3
  86. package/dist/esm/Components/CopyButton/CopyButton.js +2 -2
  87. package/dist/esm/Components/Drawer/Drawer.js +6 -2
  88. package/dist/esm/Components/Dropdown/DropDown.js +2 -9
  89. package/dist/esm/Components/FilePreview/FilePreview.js +3 -2
  90. package/dist/esm/Components/FileUploader/FileUploader.js +4 -0
  91. package/dist/esm/Components/FormDrawer/FormDrawer.js +3 -3
  92. package/dist/esm/Components/Input/TextInput.styles.js +10 -6
  93. package/dist/esm/Components/KanbanBoard/KanbanBoard.js +6 -5
  94. package/dist/esm/Components/Modal/dialogNaming.js +18 -0
  95. package/dist/esm/Components/NavLauncher/LauncherTabs.js +2 -2
  96. package/dist/esm/Components/NavLauncher/NavLauncher.js +259 -49
  97. package/dist/esm/Components/NavLauncher/ScopeBar.js +134 -0
  98. package/dist/esm/Components/NavLauncher/engine/distance.js +37 -0
  99. package/dist/esm/Components/NavLauncher/engine/engine.js +458 -0
  100. package/dist/esm/Components/NavLauncher/engine/fold.js +74 -0
  101. package/dist/esm/Components/NavLauncher/engine/index.js +14 -0
  102. package/dist/esm/Components/NavLauncher/launcherParts.js +10 -6
  103. package/dist/esm/Components/NavLauncher/match.js +25 -12
  104. package/dist/esm/Components/NavLauncher/searchLayout.js +100 -0
  105. package/dist/esm/Components/NavLauncher/spotlight.js +194 -0
  106. package/dist/esm/Components/NavLauncher/spotlightParts.js +95 -0
  107. package/dist/esm/Components/NavigationBar/NavigationBar.js +2 -1
  108. package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +2 -4
  109. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -6
  110. package/dist/esm/Components/ScrollToTop/ScrollToTop.js +5 -4
  111. package/dist/esm/Components/SearchSelect/SearchSelect.js +6 -18
  112. package/dist/esm/Components/Select/SelectPopup.js +2 -4
  113. package/dist/esm/Components/Select/optionRowInk.js +7 -0
  114. package/dist/esm/Components/SelectSearch/SelectSearch.js +2 -11
  115. package/dist/esm/Components/Table/Table.js +4 -3
  116. package/dist/esm/Components/Table/components/TableBody.js +10 -2
  117. package/dist/esm/Components/Table/components/TableHeader.js +10 -3
  118. package/dist/esm/Components/Table/components/TableLoading.js +10 -6
  119. package/dist/esm/Components/Table/filters/CompactSelect.js +2 -11
  120. package/dist/esm/Components/Table/variants/TableVariantContext.js +3 -3
  121. package/dist/esm/Components/WizardDialog/WizardDialog.js +15 -3
  122. package/dist/esm/Components/WorkspaceWindow/WorkspaceTrayPreview.js +4 -0
  123. package/dist/esm/Components/WorkspaceWindow/WorkspaceWindow.js +28 -20
  124. package/dist/esm/Theme/chakra/Menu.styles.js +7 -0
  125. package/dist/esm/Theme/chakra/componentStyles.js +2 -2
  126. package/dist/esm/Theme/chakra/ringShadow.js +3 -0
  127. package/dist/esm/Theme/tokens/builders/accentText.js +5 -0
  128. package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +5 -5
  129. package/dist/esm/Theme/tokens/builders/filledSurface.js +18 -5
  130. package/dist/esm/Theme/tokens/builders/planeStep.js +3 -3
  131. package/dist/esm/Utils/table.js +2 -2
  132. package/dist/esm/index.js +6 -5
  133. package/dist/index.d.ts +10 -8
  134. package/dist/index.js +14 -6
  135. package/package.json +1 -1
@@ -0,0 +1,74 @@
1
+ // Accents, nukta and joiners fold away; vowel signs and viramas belong to the letter.
2
+ const OPTIONAL_MARKS =
3
+ // eslint-disable-next-line no-misleading-character-class -- each mark is removed on its own
4
+ /[\u0300-\u036f\u0591-\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06ed\u093c\u1ab0-\u1aff\u1dc0-\u1dff\u200c\u200d\u20d0-\u20ff\ufe20-\ufe2f]/g;
5
+ const CHANDRABINDU = /\u0901/g;
6
+ const ANUSVARA = "\u0902";
7
+ const MARK = /\p{M}/u;
8
+ const SEPARATOR = /[^\p{L}\p{N}\p{M}]+/u;
9
+ const SPECIAL = {
10
+ ß: "ss",
11
+ æ: "ae",
12
+ œ: "oe",
13
+ ø: "o",
14
+ ł: "l",
15
+ đ: "d",
16
+ ı: "i",
17
+ };
18
+ const SPECIAL_RE = /[ßæœøłđı]/g;
19
+ const DEVANAGARI_VIRAMA = 0x094d;
20
+ /** Case- and accent-insensitive form used for every comparison: "Crème Brûlée" -> "creme brulee". */
21
+ export const foldText = (text) => text
22
+ .normalize("NFKD")
23
+ .replace(OPTIONAL_MARKS, "")
24
+ .replace(CHANDRABINDU, ANUSVARA)
25
+ .toLowerCase()
26
+ .replace(SPECIAL_RE, (ch) => SPECIAL[ch]);
27
+ export const splitWords = (folded) => folded.split(SEPARATOR).filter(Boolean);
28
+ /** Folded, de-duplicated query tokens in typing order. */
29
+ export const tokenize = (query) => Array.from(new Set(splitWords(foldText(query))));
30
+ /** True when folded text carries combining marks, so its written letters span several characters. */
31
+ export const hasMarks = (folded) => MARK.test(folded);
32
+ const isDevanagariConsonant = (code) => (code >= 0x0915 && code <= 0x0939) || (code >= 0x0978 && code <= 0x097f);
33
+ const markCodes = new Map();
34
+ const isMarkCode = (code, char) => {
35
+ if (code < 0x0300)
36
+ return false;
37
+ let known = markCodes.get(code);
38
+ if (known === undefined) {
39
+ known = MARK.test(char);
40
+ markCodes.set(code, known);
41
+ }
42
+ return known;
43
+ };
44
+ /** Written letters: a base with its marks; a Devanagari conjunct counts as one. */
45
+ export const letters = (word) => {
46
+ var _a;
47
+ const out = [];
48
+ let previous = 0;
49
+ for (const char of word) {
50
+ const code = (_a = char.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
51
+ const joins = isMarkCode(code, char) ||
52
+ (previous === DEVANAGARI_VIRAMA && isDevanagariConsonant(code));
53
+ if (joins && out.length > 0)
54
+ out[out.length - 1] += char;
55
+ else
56
+ out.push(char);
57
+ previous = code;
58
+ }
59
+ return out;
60
+ };
61
+ export const foldWithMap = (text) => {
62
+ let folded = "";
63
+ const map = [];
64
+ let at = 0;
65
+ for (const char of text) {
66
+ const piece = foldText(char);
67
+ for (let i = 0; i < piece.length; i += 1)
68
+ map.push(at);
69
+ folded += piece;
70
+ at += char.length;
71
+ }
72
+ map.push(text.length);
73
+ return { folded, map };
74
+ };
@@ -0,0 +1,14 @@
1
+ import { createMatcher, createSearchIndex, editDistance, foldText, highlightRanges, matchesQuery, searchDocuments, searchIndex, tokenize, usageBoosts, } from "./engine.js";
2
+ /** Framework-free ranked search used by NavLauncher; reusable by any list, picker or palette. */
3
+ export const LauncherSearchEngine = Object.freeze({
4
+ createIndex: createSearchIndex,
5
+ search: searchIndex,
6
+ searchDocuments,
7
+ createMatcher,
8
+ matches: matchesQuery,
9
+ highlightRanges,
10
+ usageBoosts,
11
+ foldText,
12
+ tokenize,
13
+ editDistance,
14
+ });
@@ -3,6 +3,7 @@ import { Box, Flex, Heading, Text } from "@chakra-ui/react";
3
3
  import { Lock, Star } from "lucide-react";
4
4
  import { createContext, Fragment, useContext, } from "react";
5
5
  import { FOCUS_VISIBLE_OVER_STATE, focusVisibleStyles, } from "../../Theme/chakra/focusRing.styles.js";
6
+ import { insetRingShadow } from "../../Theme/chakra/ringShadow.js";
6
7
  import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
7
8
  import { AA_NON_TEXT, liftToContrast, } from "../../Theme/tokens/builders/outlineRung.js";
8
9
  import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
@@ -41,7 +42,7 @@ export const activeRowSurface = (colors) => {
41
42
  const { edge, fill } = activeRowStyle(colors);
42
43
  return {
43
44
  backgroundColor: fill,
44
- boxShadow: `inset 0 0 0 1px ${edge}`,
45
+ boxShadow: insetRingShadow(edge),
45
46
  outline: "2px solid transparent",
46
47
  outlineOffset: "-2px",
47
48
  };
@@ -110,9 +111,12 @@ export function RowIcon({ icon: Icon, size, stroke = 1.75, mt }) {
110
111
  return null;
111
112
  return (_jsx(Box, { as: "span", color: colors.textMuted, display: "inline-flex", flexShrink: 0, mt: mt, transition: transitionFor(["color"]), _groupHover: { color: colors.accentText }, _groupFocusWithin: { color: colors.accentText }, sx: { "[data-reveal=true] &": { color: colors.accentText } }, children: _jsx(Icon, { size: size, strokeWidth: stroke, "aria-hidden": true }) }));
112
113
  }
114
+ const HighlightOptionsContext = createContext(undefined);
115
+ export const HighlightOptionsProvider = HighlightOptionsContext.Provider;
113
116
  export function Highlight({ text, query }) {
114
117
  const { colors } = useCustomTheme();
115
- return (_jsx(_Fragment, { children: highlightSegments(text, query).map((segment, i) => segment.isMatch ? (_jsx(Box, { as: "mark", bg: "transparent", color: "inherit", fontWeight: 650, textDecoration: "underline", textDecorationColor: colors.primary.opacity[48], textDecorationThickness: "1.5px", textUnderlineOffset: "2px", children: segment.text }, i)) : (_jsx(Fragment, { children: segment.text }, i))) }));
118
+ const options = useContext(HighlightOptionsContext);
119
+ return (_jsx(_Fragment, { children: highlightSegments(text, query, options).map((segment, i) => segment.isMatch ? (_jsx(Box, { as: "mark", bg: "transparent", color: "inherit", fontWeight: 650, textDecoration: "underline", textDecorationColor: colors.primary.opacity[48], textDecorationThickness: "1.5px", textUnderlineOffset: "2px", children: segment.text }, i)) : (_jsx(Fragment, { children: segment.text }, i))) }));
116
120
  }
117
121
  export function RowActions({ children }) {
118
122
  const { colors } = useCustomTheme();
@@ -129,7 +133,7 @@ export function RowActions({ children }) {
129
133
  }
130
134
  export function RowTip({ text }) {
131
135
  const { colors } = useCustomTheme();
132
- return (_jsx(Box, { role: "tooltip", position: "absolute", right: "20px", top: "-26px", zIndex: 2, px: "8px", py: "3px", borderRadius: "6px", fontSize: "11px", fontWeight: 600, whiteSpace: "nowrap", bg: colors.text[900], color: colors.surfaceRaised, visibility: "hidden", pointerEvents: "none", _groupHover: { visibility: "visible" }, children: text }));
136
+ return (_jsx(Box, { role: "tooltip", position: "absolute", right: "20px", top: "-26px", zIndex: 2, px: "8px", py: "3px", borderRadius: "6px", fontSize: "xs-minus", fontWeight: 600, whiteSpace: "nowrap", bg: colors.text[900], color: colors.surfaceRaised, visibility: "hidden", pointerEvents: "none", _groupHover: { visibility: "visible" }, children: text }));
133
137
  }
134
138
  export function ModuleRow({ module, keyScreens, isPinned, onTogglePin, pinId, labels, link, }) {
135
139
  const { colors } = useCustomTheme();
@@ -150,11 +154,11 @@ export function RailRow({ screen, module, link, isStrong = false, trailing, pinI
150
154
  const hover = useRowHover();
151
155
  const focus = useRowFocus();
152
156
  const isTouch = useTouchDensity();
153
- return (_jsxs(Flex, { "data-group": true, position: "relative", align: "center", gap: "10px", h: isTouch ? "44px" : "32px", pl: "8px", pr: "4px", borderRadius: "8px", transition: transitionFor(["background-color"]), _hover: hover._hover, _focusWithin: hover._focusWithin, sx: focus.sx, children: [_jsx(RowIcon, { icon: (_a = screen.icon) !== null && _a !== void 0 ? _a : module.icon, size: 15 }), _jsx(OverflowToolTip, { label: screen.label, placement: "top-start", children: _jsx(Box, { as: link.linkAs, href: screen.href, "data-launcher-item": true, ...focus.primary, "data-pin-id": pinId, onClick: link.onPlainClick, flex: 1, minW: 0, fontSize: "13px", fontWeight: isStrong ? 500 : 400, color: colors.text[900], noOfLines: 1, borderRadius: "sm", sx: stretchedLink("8px"), children: screen.label }) }), _jsx(Flex, { position: "relative", zIndex: 1, align: "center", gap: "2px", children: trailing })] }));
157
+ return (_jsxs(Flex, { "data-group": true, position: "relative", align: "center", gap: "10px", h: isTouch ? "44px" : "32px", pl: "8px", pr: "4px", borderRadius: "8px", transition: transitionFor(["background-color"]), _hover: hover._hover, _focusWithin: hover._focusWithin, sx: focus.sx, children: [_jsx(RowIcon, { icon: (_a = screen.icon) !== null && _a !== void 0 ? _a : module.icon, size: 15 }), _jsx(OverflowToolTip, { label: screen.label, placement: "top-start", children: _jsx(Box, { as: link.linkAs, href: screen.href, "data-launcher-item": true, ...focus.primary, "data-pin-id": pinId, onClick: link.onPlainClick, flex: 1, minW: 0, fontSize: "xs-plus", fontWeight: isStrong ? 500 : 400, color: colors.text[900], noOfLines: 1, borderRadius: "sm", sx: stretchedLink("8px"), children: screen.label }) }), _jsx(Flex, { position: "relative", zIndex: 1, align: "center", gap: "2px", children: trailing })] }));
154
158
  }
155
159
  export function PinTextButton({ label, text, onToggle }) {
156
160
  const { colors } = useCustomTheme();
157
- return (_jsxs(Box, { as: "button", type: "button", "aria-label": label, flexShrink: 0, h: "22px", px: "7px", display: "inline-flex", alignItems: "center", gap: "4px", borderRadius: "6px", borderWidth: "1px", borderColor: colors.boxborder[200], bg: colors.surfaceRaised, color: colors.text[700], fontSize: "11px", fontWeight: 600, cursor: "pointer", opacity: 0, transition: transitionFor(["opacity", "background-color"]), sx: { ...revealStyles(colors), "@media (hover: none)": { opacity: 1 } }, onClick: (event) => {
161
+ return (_jsxs(Box, { as: "button", type: "button", "aria-label": label, flexShrink: 0, h: "22px", px: "7px", display: "inline-flex", alignItems: "center", gap: "4px", borderRadius: "6px", borderWidth: "1px", borderColor: colors.boxborder[200], bg: colors.surfaceRaised, color: colors.text[700], fontSize: "xs-minus", fontWeight: 600, cursor: "pointer", opacity: 0, transition: transitionFor(["opacity", "background-color"]), sx: { ...revealStyles(colors), "@media (hover: none)": { opacity: 1 } }, onClick: (event) => {
158
162
  event.preventDefault();
159
163
  event.stopPropagation();
160
164
  onToggle();
@@ -166,7 +170,7 @@ export function PinnedTile({ screen, module, link, labels, onTogglePin, }) {
166
170
  const Icon = (_a = screen.icon) !== null && _a !== void 0 ? _a : module.icon;
167
171
  const focus = useRowFocus(true);
168
172
  const isTouch = useTouchDensity();
169
- return (_jsxs(Flex, { "data-group": true, "data-nav-cell": true, position: "relative", align: "center", gap: "8px", h: isTouch ? "44px" : "36px", pl: "9px", pr: "4px", borderRadius: "9px", borderWidth: "1px", borderColor: colors.boxborder[200], bg: colors.surfaceRaised, transition: transitionFor(["border-color", "background-color"]), _hover: { borderColor: colors.gray[300] }, sx: focus.sx, children: [Icon ? (_jsx(Box, { as: "span", display: "inline-flex", flexShrink: 0, color: colors.accentText, children: _jsx(Icon, { size: 15, strokeWidth: 1.8, "aria-hidden": true }) })) : null, _jsx(OverflowToolTip, { label: screen.label, placement: "top-start", children: _jsx(Box, { as: link.linkAs, href: screen.href, "data-launcher-item": true, ...focus.primary, "data-pin-id": onTogglePin ? screen.id : undefined, onClick: link.onPlainClick, flex: 1, minW: 0, fontSize: "13px", fontWeight: 500, color: colors.text[900], noOfLines: 1, borderRadius: "sm", sx: stretchedLink("9px"), children: screen.label }) }), _jsx(CountBadge, { value: screen.badge, size: "tile" }), onTogglePin ? (_jsx(Box, { position: "relative", zIndex: 1, flexShrink: 0, w: "0", overflow: "hidden", transition: transitionFor(["width"]), _groupHover: { w: "22px" }, _groupFocusWithin: { w: "22px" }, children: _jsx(PinToggle, { isPinned: true, size: 12, label: labels.unpin(screen.label), title: labels.unpinTip, onToggle: onTogglePin }) })) : null] }));
173
+ return (_jsxs(Flex, { "data-group": true, "data-nav-cell": true, position: "relative", align: "center", gap: "8px", h: isTouch ? "44px" : "36px", pl: "9px", pr: "4px", borderRadius: "9px", borderWidth: "1px", borderColor: colors.boxborder[200], bg: colors.surfaceRaised, transition: transitionFor(["border-color", "background-color"]), _hover: { borderColor: colors.gray[300] }, sx: focus.sx, children: [Icon ? (_jsx(Box, { as: "span", display: "inline-flex", flexShrink: 0, color: colors.accentText, children: _jsx(Icon, { size: 15, strokeWidth: 1.8, "aria-hidden": true }) })) : null, _jsx(OverflowToolTip, { label: screen.label, placement: "top-start", children: _jsx(Box, { as: link.linkAs, href: screen.href, "data-launcher-item": true, ...focus.primary, "data-pin-id": onTogglePin ? screen.id : undefined, onClick: link.onPlainClick, flex: 1, minW: 0, fontSize: "xs-plus", fontWeight: 500, color: colors.text[900], noOfLines: 1, borderRadius: "sm", sx: stretchedLink("9px"), children: screen.label }) }), _jsx(CountBadge, { value: screen.badge, size: "tile" }), onTogglePin ? (_jsx(Box, { position: "relative", zIndex: 1, flexShrink: 0, w: "0", overflow: "hidden", transition: transitionFor(["width"]), _groupHover: { w: "22px" }, _groupFocusWithin: { w: "22px" }, children: _jsx(PinToggle, { isPinned: true, size: 12, label: labels.unpin(screen.label), title: labels.unpinTip, onToggle: onTogglePin }) })) : null] }));
170
174
  }
171
175
  export function AppsSection({ apps, hues, currentAppId, heading, hideHeading = false, onSelect, }) {
172
176
  const { colors } = useCustomTheme();
@@ -1,3 +1,4 @@
1
+ import { highlightRanges } from "./engine/engine.js";
1
2
  const normalize = (text) => text.toLocaleLowerCase().normalize("NFKD");
2
3
  function score(label, haystack, tokens) {
3
4
  if (!tokens.every((t) => haystack.includes(t)))
@@ -23,6 +24,12 @@ function rank(rows, text, tokens) {
23
24
  .sort((a, b) => a.s - b.s || a.index - b.index)
24
25
  .map((r) => r.row);
25
26
  }
27
+ export function filterItems(items, query) {
28
+ const tokens = normalize(query).split(/\s+/).filter(Boolean);
29
+ if (tokens.length === 0)
30
+ return [];
31
+ return rank([...items], (a) => { var _a, _b; return `${a.label} ${(_a = a.context) !== null && _a !== void 0 ? _a : ""} ${(_b = a.keywords) !== null && _b !== void 0 ? _b : ""}`; }, tokens);
32
+ }
26
33
  export function flattenScreens(sections) {
27
34
  var _a, _b, _c;
28
35
  const seen = new Set();
@@ -48,6 +55,7 @@ export function flattenScreens(sections) {
48
55
  }
49
56
  return out;
50
57
  }
58
+ /** @deprecated Legacy flat search; NavLauncher uses searchLauncherSections (classic) or the spotlight engine. */
51
59
  export function searchLauncher(input) {
52
60
  var _a, _b;
53
61
  const tokens = normalize(input.query).split(/\s+/).filter(Boolean);
@@ -137,8 +145,23 @@ export function searchLauncherSections(input) {
137
145
  ].filter((g) => g.items.length > 0);
138
146
  return { sections, groups };
139
147
  }
148
+ const toSegments = (text, ranges) => {
149
+ const out = [];
150
+ let cursor = 0;
151
+ for (const [start, end] of ranges) {
152
+ if (start > cursor)
153
+ out.push({ text: text.slice(cursor, start), isMatch: false });
154
+ out.push({ text: text.slice(start, end), isMatch: true });
155
+ cursor = end;
156
+ }
157
+ if (cursor < text.length)
158
+ out.push({ text: text.slice(cursor), isMatch: false });
159
+ return out.length ? out : [{ text, isMatch: false }];
160
+ };
140
161
  /** Splits `text` so every case-insensitive occurrence of a query token is its own matched segment. */
141
- export function highlightSegments(text, query) {
162
+ export function highlightSegments(text, query, options) {
163
+ if (options === null || options === void 0 ? void 0 : options.fuzzy)
164
+ return toSegments(text, highlightRanges(text, query, { synonyms: options.synonyms }));
142
165
  const lower = text.toLocaleLowerCase();
143
166
  const tokens = query.toLocaleLowerCase().split(/\s+/).filter(Boolean);
144
167
  if (tokens.length === 0 || lower.length !== text.length)
@@ -158,15 +181,5 @@ export function highlightSegments(text, query) {
158
181
  else
159
182
  merged.push([...range]);
160
183
  }
161
- const out = [];
162
- let cursor = 0;
163
- for (const [start, end] of merged) {
164
- if (start > cursor)
165
- out.push({ text: text.slice(cursor, start), isMatch: false });
166
- out.push({ text: text.slice(start, end), isMatch: true });
167
- cursor = end;
168
- }
169
- if (cursor < text.length)
170
- out.push({ text: text.slice(cursor), isMatch: false });
171
- return out.length ? out : [{ text, isMatch: false }];
184
+ return toSegments(text, merged);
172
185
  }
@@ -0,0 +1,100 @@
1
+ import { SCOPE_ACTIONS, SCOPE_ALL } from "./spotlight.js";
2
+ export const inScope = (groups, scope) => scope === SCOPE_ALL ? groups : groups.filter((g) => g.scope === scope);
3
+ /** A scope's items as passed, unranked, for browsing before typing. */
4
+ export const scopeGroups = (input) => {
5
+ var _a, _b, _c;
6
+ const groups = [];
7
+ if (input.scope === SCOPE_ACTIONS && ((_a = input.actions) === null || _a === void 0 ? void 0 : _a.length)) {
8
+ groups.push({
9
+ id: SCOPE_ACTIONS,
10
+ label: input.actionsLabel,
11
+ scope: SCOPE_ACTIONS,
12
+ isSection: false,
13
+ items: input.actions.map((action) => ({ ...action, id: `action:${action.id}` })),
14
+ });
15
+ }
16
+ for (const group of (_b = input.extraResults) !== null && _b !== void 0 ? _b : []) {
17
+ const scope = (_c = group.scope) !== null && _c !== void 0 ? _c : group.id;
18
+ if (scope !== input.scope || group.items.length === 0)
19
+ continue;
20
+ groups.push({
21
+ id: group.id,
22
+ label: group.label,
23
+ scope,
24
+ isSection: false,
25
+ items: group.items.map((item) => ({ ...item, id: `${group.id}:${item.id}` })),
26
+ });
27
+ }
28
+ return groups;
29
+ };
30
+ export const countByScope = (groups, answers) => {
31
+ var _a;
32
+ const counts = new Map();
33
+ let all = answers;
34
+ for (const group of groups) {
35
+ counts.set(group.scope, ((_a = counts.get(group.scope)) !== null && _a !== void 0 ? _a : 0) + group.items.length);
36
+ all += group.items.length;
37
+ }
38
+ counts.set(SCOPE_ALL, all);
39
+ return counts;
40
+ };
41
+ export const takeTopHit = (groups) => {
42
+ let at = -1;
43
+ let index = -1;
44
+ let bestScore = 0;
45
+ for (let g = 0; g < groups.length; g += 1) {
46
+ groups[g].items.forEach((item, i) => {
47
+ var _a, _b;
48
+ if (((_a = item.score) !== null && _a !== void 0 ? _a : 0) <= bestScore)
49
+ return;
50
+ bestScore = (_b = item.score) !== null && _b !== void 0 ? _b : 0;
51
+ at = g;
52
+ index = i;
53
+ });
54
+ }
55
+ if (at < 0)
56
+ return { groups };
57
+ return {
58
+ topHit: groups[at].items[index],
59
+ groups: groups
60
+ .map((group, g) => (g === at ? { ...group, items: group.items.filter((_, i) => i !== index) } : group))
61
+ .filter((group) => group.items.length > 0),
62
+ };
63
+ };
64
+ /** Flat option order for keyboard and ARIA plus per-row group sizes for `moveResult`. */
65
+ export const layoutSearch = (input) => {
66
+ const blocks = [];
67
+ const entries = [];
68
+ const sizes = [];
69
+ if (input.answers.length) {
70
+ blocks.push({ type: "answers", start: 0, items: input.answers });
71
+ for (const item of input.answers) {
72
+ entries.push({ type: "answer", item });
73
+ sizes.push(1);
74
+ }
75
+ }
76
+ if (input.topHit) {
77
+ blocks.push({ type: "top", start: entries.length, item: input.topHit });
78
+ entries.push({ type: "top", item: input.topHit });
79
+ sizes.push(1);
80
+ }
81
+ let total = entries.length;
82
+ for (const group of input.groups) {
83
+ const cap = input.limit !== undefined && !input.expanded.has(group.id) ? Math.max(1, input.limit) : Infinity;
84
+ const visible = group.items.slice(0, cap);
85
+ const hidden = group.items.length - visible.length;
86
+ const start = entries.length;
87
+ for (const item of visible)
88
+ entries.push({ type: "row", item, groupId: group.id });
89
+ sizes.push(visible.length);
90
+ total += group.items.length;
91
+ let more;
92
+ if (hidden > 0) {
93
+ more = { index: entries.length, count: hidden };
94
+ entries.push({ type: "more", groupId: group.id, count: hidden });
95
+ sizes.push(1);
96
+ }
97
+ blocks.push({ type: "group", group, start, visible, more });
98
+ }
99
+ return { blocks, entries, sizes, total };
100
+ };
@@ -0,0 +1,194 @@
1
+ import { createSearchIndex, searchDocuments, searchIndex, usageBoosts, } from "./engine/engine.js";
2
+ export const SCOPE_ALL = "all";
3
+ export const SCOPE_SCREENS = "screens";
4
+ export const SCOPE_ACTIONS = "actions";
5
+ const SHOWN_FIELDS = new Set(["keyword", "fact", "answer"]);
6
+ const RELATIVE_CUTOFF = 0.25;
7
+ const keywordFields = (keywords) => (typeof keywords === "string" ? keywords.split(/[,;|]/) : (keywords !== null && keywords !== void 0 ? keywords : []))
8
+ .map((k) => k.trim())
9
+ .filter(Boolean)
10
+ .map((text) => ({ name: "keyword", text, weight: 0.75 }));
11
+ const label = (text) => ({
12
+ name: "label",
13
+ text,
14
+ weight: 1,
15
+ });
16
+ export const itemFields = (item) => {
17
+ var _a;
18
+ return [
19
+ label(item.label),
20
+ ...keywordFields(item.keywords),
21
+ ...(item.context
22
+ ? [{ name: "context", text: item.context, weight: 0.45 }]
23
+ : []),
24
+ ...((_a = item.facts) !== null && _a !== void 0 ? _a : []).map((f) => ({
25
+ name: "fact",
26
+ text: `${f.label}: ${f.value}`,
27
+ weight: 0.6,
28
+ })),
29
+ ...(item.answer
30
+ ? [
31
+ { name: "answer", text: item.answer.label, weight: 0.9 },
32
+ { name: "answer", text: item.answer.value, weight: 0.5 },
33
+ ]
34
+ : []),
35
+ ];
36
+ };
37
+ const decorate = (result, hit) => {
38
+ var _a;
39
+ return ({
40
+ ...result,
41
+ score: hit.score,
42
+ keywordHint: (_a = hit.matches.find((m) => SHOWN_FIELDS.has(m.field))) === null || _a === void 0 ? void 0 : _a.text,
43
+ });
44
+ };
45
+ export function createSpotlightIndex(sections, actions, actionsLabel) {
46
+ var _a;
47
+ const documents = [];
48
+ const entries = [];
49
+ const groups = [];
50
+ const seen = new Set();
51
+ const add = (fields, entry) => {
52
+ documents.push({ id: entry.result.id, fields });
53
+ entries.push(entry);
54
+ };
55
+ for (const section of sections) {
56
+ const groupId = `section:${section.id}`;
57
+ groups.push({
58
+ id: groupId,
59
+ label: section.label,
60
+ scope: SCOPE_SCREENS,
61
+ isSection: true,
62
+ });
63
+ for (const module of section.modules) {
64
+ if (module.screens.length === 0)
65
+ continue;
66
+ add([
67
+ label(module.label),
68
+ ...keywordFields(module.keywords),
69
+ { name: "context", text: section.label, weight: 0.35 },
70
+ ], {
71
+ groupId,
72
+ usageId: module.screens[0].id,
73
+ result: {
74
+ id: `module:${module.id}`,
75
+ kind: "module",
76
+ label: module.label,
77
+ icon: module.icon,
78
+ badge: module.badge,
79
+ isNew: module.isNew,
80
+ href: module.href,
81
+ screenId: module.screens[0].id,
82
+ },
83
+ });
84
+ for (const screen of module.screens) {
85
+ if (screen.label === module.label || seen.has(screen.id))
86
+ continue;
87
+ seen.add(screen.id);
88
+ add([
89
+ label(screen.label),
90
+ ...keywordFields(screen.keywords),
91
+ { name: "context", text: module.label, weight: 0.5 },
92
+ { name: "section", text: section.label, weight: 0.3 },
93
+ ], {
94
+ groupId,
95
+ usageId: screen.id,
96
+ result: {
97
+ id: `screen:${screen.id}`,
98
+ kind: "screen",
99
+ label: screen.label,
100
+ context: module.label,
101
+ icon: (_a = screen.icon) !== null && _a !== void 0 ? _a : module.icon,
102
+ badge: screen.badge,
103
+ href: screen.href,
104
+ },
105
+ });
106
+ }
107
+ }
108
+ }
109
+ if (actions === null || actions === void 0 ? void 0 : actions.length) {
110
+ groups.push({
111
+ id: SCOPE_ACTIONS,
112
+ label: actionsLabel,
113
+ scope: SCOPE_ACTIONS,
114
+ isSection: false,
115
+ });
116
+ for (const action of actions) {
117
+ add(itemFields(action), {
118
+ groupId: SCOPE_ACTIONS,
119
+ result: { ...action, id: `action:${action.id}` },
120
+ });
121
+ }
122
+ }
123
+ return { index: createSearchIndex(documents), entries, groups };
124
+ }
125
+ export function spotlightBoosts(spot, usage) {
126
+ const byScreen = usageBoosts(usage);
127
+ const out = {};
128
+ spot.entries.forEach((entry) => {
129
+ const boost = entry.usageId ? byScreen[entry.usageId] : undefined;
130
+ if (boost)
131
+ out[entry.result.id] = boost;
132
+ });
133
+ return out;
134
+ }
135
+ const searchGroup = (group, query, synonyms) => {
136
+ const hits = searchDocuments(group.items.map((item) => ({ id: item.id, fields: itemFields(item) })), query, { synonyms });
137
+ const result = (index) => ({
138
+ ...group.items[index],
139
+ id: `${group.id}:${group.items[index].id}`,
140
+ });
141
+ if (group.matchLocally)
142
+ return hits.map((hit) => decorate(result(hit.index), hit));
143
+ const byIndex = new Map(hits.map((hit) => [hit.index, hit]));
144
+ return group.items.map((_, index) => {
145
+ const hit = byIndex.get(index);
146
+ return hit ? decorate(result(index), hit) : { ...result(index), score: 0 };
147
+ });
148
+ };
149
+ /** Ranked groups; local rows under 25% of the best score are dropped. */
150
+ export function searchSpotlight(spot, input) {
151
+ var _a, _b, _c, _d;
152
+ if (!input.query.trim())
153
+ return [];
154
+ const hits = searchIndex(spot.index, input.query, {
155
+ synonyms: input.synonyms,
156
+ boosts: input.boosts,
157
+ });
158
+ const byGroup = new Map();
159
+ for (const hit of hits) {
160
+ const entry = spot.entries[hit.index];
161
+ const rows = (_a = byGroup.get(entry.groupId)) !== null && _a !== void 0 ? _a : [];
162
+ rows.push(decorate(entry.result, hit));
163
+ byGroup.set(entry.groupId, rows);
164
+ }
165
+ const groups = spot.groups.map((g) => {
166
+ var _a;
167
+ return ({
168
+ ...g,
169
+ items: (_a = byGroup.get(g.id)) !== null && _a !== void 0 ? _a : [],
170
+ });
171
+ });
172
+ for (const group of (_b = input.extraResults) !== null && _b !== void 0 ? _b : []) {
173
+ groups.push({
174
+ id: group.id,
175
+ label: group.label,
176
+ scope: (_c = group.scope) !== null && _c !== void 0 ? _c : group.id,
177
+ isSection: false,
178
+ items: searchGroup(group, input.query, input.synonyms),
179
+ });
180
+ }
181
+ const remote = new Set((_d = input.extraResults) === null || _d === void 0 ? void 0 : _d.filter((g) => !g.matchLocally).map((g) => g.id));
182
+ const floor = RELATIVE_CUTOFF *
183
+ Math.max(0, ...groups.flatMap((g) => g.items.map((i) => { var _a; return (_a = i.score) !== null && _a !== void 0 ? _a : 0; })));
184
+ return groups
185
+ .map((g) => remote.has(g.id)
186
+ ? g
187
+ : { ...g, items: g.items.filter((i) => { var _a; return ((_a = i.score) !== null && _a !== void 0 ? _a : 0) >= floor; }) })
188
+ .filter((g) => g.items.length > 0);
189
+ }
190
+ export function matchAnswers(answers, query, synonyms) {
191
+ if (!(answers === null || answers === void 0 ? void 0 : answers.length))
192
+ return [];
193
+ return searchGroup({ id: "answer", label: "", items: answers, matchLocally: true }, query, synonyms);
194
+ }
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Box, Flex, Text } from "@chakra-ui/react";
3
+ import { ChevronDown, Search as SearchIcon } from "lucide-react";
4
+ import { useRef } from "react";
5
+ import { reducedMotionSx } from "../../Theme/chakra/motion.js";
6
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
7
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
8
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
9
+ import Button from "../Button/Button.js";
10
+ import CopyButton from "../CopyButton/CopyButton.js";
11
+ import { KbdShortcut } from "../Kbd/Kbd.js";
12
+ import { activeRowStyle, activeRowSurface, CountBadge, Highlight, useTouchDensity, } from "./launcherParts.js";
13
+ export const QUICK_ACTION_LIMIT = 5;
14
+ const HIDE_ON_TOUCH = { "@media (hover: none)": { display: "none" } };
15
+ export function QuickActionsRow({ items, label, link, onRun, }) {
16
+ return (_jsx(Flex, { role: "group", "aria-label": label, "data-testid": "launcher-quick-actions", gap: "6px", minW: 0, flexWrap: "wrap", px: "4px", children: items.slice(0, QUICK_ACTION_LIMIT).map((item) => {
17
+ const Icon = item.icon;
18
+ const common = {
19
+ variant: "outline",
20
+ colorScheme: "gray",
21
+ size: "sm",
22
+ borderRadius: "full",
23
+ flexShrink: 0,
24
+ label: item.label,
25
+ leftIcon: Icon ? (_jsx(Icon, { size: 14, strokeWidth: 2, "aria-hidden": true })) : undefined,
26
+ };
27
+ return item.href && !item.run ? (_jsx(Button, { ...common, as: link.linkAs, href: item.href, onClick: link.onPlainClick }, item.id)) : (_jsx(Button, { ...common, onClick: () => onRun(item) }, item.id));
28
+ }) }));
29
+ }
30
+ const useCardSurface = (isActive) => {
31
+ const { colors } = useCustomTheme();
32
+ const { edge, fill } = activeRowStyle(colors);
33
+ return {
34
+ position: "relative",
35
+ borderRadius: "xl",
36
+ borderWidth: "1px",
37
+ borderColor: isActive ? edge : colors.boxborder[200],
38
+ bg: isActive ? fill : colors.surfaceRaised,
39
+ transition: transitionFor(["background-color", "border-color"]),
40
+ sx: reducedMotionSx(),
41
+ };
42
+ };
43
+ function IconChip({ icon, size }) {
44
+ const { colors } = useCustomTheme();
45
+ const Icon = icon !== null && icon !== void 0 ? icon : SearchIcon;
46
+ return (_jsx(Flex, { boxSize: `${size}px`, borderRadius: "10px", bg: colors.primary.opacity[8], color: colors.accentText, align: "center", justify: "center", flexShrink: 0, children: _jsx(Icon, { size: Math.round(size / 2), strokeWidth: 1.8, "aria-hidden": true }) }));
47
+ }
48
+ function CardAnchor({ item, link }) {
49
+ if (!item.href)
50
+ return null;
51
+ return (_jsx(Box, { as: link.linkAs, href: item.href, tabIndex: -1, "aria-hidden": true, onClick: link.onPlainClick, position: "absolute", inset: 0, borderRadius: "xl" }));
52
+ }
53
+ export function TopHitCard({ item, query, isActive, optionId, link, labels, onOpen, onHover, describedBy, }) {
54
+ const { colors } = useCustomTheme();
55
+ const surface = useCardSurface(isActive);
56
+ const meta = [item.context, item.hint].filter(Boolean).join(" · ");
57
+ return (_jsxs(Flex, { role: "presentation", "data-group": true, "data-reveal": isActive, direction: "column", gap: "10px", p: "12px", onMouseMove: onHover, ...surface, children: [_jsxs(Flex, { id: optionId, role: "option", "aria-selected": isActive, "aria-describedby": describedBy, "data-active": isActive, align: "center", gap: "12px", minW: 0, cursor: "pointer", onClick: () => {
58
+ if (!item.href)
59
+ onOpen();
60
+ }, children: [_jsx(IconChip, { icon: item.icon, size: 40 }), _jsxs(Flex, { direction: "column", flex: 1, minW: 0, gap: "2px", children: [_jsx(Text, { fontSize: "md", lineHeight: "22px", fontWeight: 600, color: colors.text[900], noOfLines: 1, children: _jsx(Highlight, { text: item.label, query: query }) }), meta ? (_jsx(Text, { fontSize: "12.5px", color: colors.textMuted, noOfLines: 1, children: meta })) : null, item.keywordHint ? (_jsxs(Text, { fontSize: "xs", color: colors.textMuted, noOfLines: 1, children: [`${labels.matchedOn} “`, _jsx(Highlight, { text: item.keywordHint, query: query }), "\u201D"] })) : null] }), _jsx(CountBadge, { value: item.badge }), _jsx(Box, { "aria-hidden": true, flexShrink: 0, sx: HIDE_ON_TOUCH, children: _jsx(KbdShortcut, { shortcut: "enter", size: "sm" }) })] }), _jsx(CardAnchor, { item: item, link: link })] }));
61
+ }
62
+ export function AnswerCard({ item, isActive, optionId, link, labels, onOpen, onHover, describedBy, }) {
63
+ var _a, _b;
64
+ const { colors } = useCustomTheme();
65
+ const surface = useCardSurface(isActive);
66
+ const answer = (_a = item.answer) !== null && _a !== void 0 ? _a : {
67
+ label: (_b = item.context) !== null && _b !== void 0 ? _b : "",
68
+ value: item.label,
69
+ };
70
+ const acts = Boolean(item.href || item.run);
71
+ return (_jsxs(Flex, { role: "presentation", "data-group": true, p: "12px 14px", onMouseMove: onHover, ...surface, children: [_jsxs(Flex, { id: optionId, role: "option", "aria-selected": isActive, "aria-describedby": describedBy, "data-active": isActive, align: "center", gap: "12px", flex: 1, minW: 0, cursor: "pointer", onClick: () => {
72
+ if (!item.href)
73
+ onOpen();
74
+ }, children: [_jsx(IconChip, { icon: item.icon, size: 36 }), _jsxs(Flex, { direction: "column", flex: 1, minW: 0, gap: "1px", children: [answer.label ? (_jsx(Text, { fontSize: "xs-minus", fontWeight: 600, letterSpacing: "0.06em", textTransform: "uppercase", color: colors.textMuted, noOfLines: 1, children: answer.label })) : null, _jsx(Text, { id: `${optionId}-value`, fontSize: "lg", lineHeight: "24px", fontWeight: 600, color: colors.text[900], noOfLines: 2, children: answer.value }), answer.hint ? (_jsx(Text, { fontSize: "xs", color: colors.textMuted, noOfLines: 1, children: answer.hint })) : null] }), _jsxs(Flex, { "aria-hidden": true, align: "center", gap: "6px", flexShrink: 0, fontSize: "11.5px", color: colors.textMuted, sx: HIDE_ON_TOUCH, children: [_jsx(KbdShortcut, { shortcut: "enter", size: "xs" }), acts ? labels.hintOpen : labels.hintCopy] })] }), _jsx(CardAnchor, { item: item, link: link })] }));
75
+ }
76
+ export function ShowMoreOption({ count, isActive, optionId, label, onExpand, onHover, }) {
77
+ const { colors } = useCustomTheme();
78
+ const isTouch = useTouchDensity();
79
+ return (_jsxs(Flex, { id: optionId, role: "option", "aria-selected": isActive, "data-active": isActive, align: "center", gap: "6px", minH: isTouch ? "44px" : "30px", px: "8px", mt: "2px", borderRadius: "lg", cursor: "pointer", fontSize: "12.5px", fontWeight: 500, color: colors.accentText, onClick: onExpand, onMouseMove: onHover, _hover: { bg: listRowBackgrounds(colors).active }, sx: isActive ? activeRowSurface(colors) : undefined, children: [_jsx(ChevronDown, { size: 14, strokeWidth: 2, "aria-hidden": true }), label(count)] }));
80
+ }
81
+ export const describeFacts = (facts) => facts.map((f) => `${f.label}: ${f.value}`).join("; ");
82
+ export function FactList({ facts, labels, layout, onCopied, onCopyBlocked, }) {
83
+ const { colors } = useCustomTheme();
84
+ const values = useRef([]);
85
+ const isPane = layout === "pane";
86
+ return (_jsx(Box, { as: "dl", m: 0, display: "grid", gridTemplateColumns: isPane ? "minmax(0, 1fr)" : "repeat(auto-fill, minmax(11rem, 1fr))", gap: isPane ? "12px" : "6px 16px", children: facts.map((fact, i) => (_jsxs(Box, { minW: 0, children: [_jsx(Text, { as: "dt", fontSize: "11.5px", lineHeight: "16px", color: colors.textMuted, children: fact.label }), _jsxs(Flex, { as: "dd", m: 0, align: "center", gap: "2px", minW: 0, children: [_jsx(Text, { ref: (node) => {
87
+ values.current[i] = node;
88
+ }, fontSize: isPane ? "13.5px" : "12.5px", lineHeight: "20px", color: colors.text[900], wordBreak: "break-word", minW: 0, children: fact.value }), fact.copyable ? (_jsx(CopyButton, { value: fact.value, tooltip: labels.copy(fact.label), copiedLabel: labels.copied, size: isPane ? "xs" : "sm", iconSize: 14, onCopy: onCopied, onCopyError: () => onCopyBlocked(values.current[i]) })) : null] })] }, `${fact.label}-${i}`))) }));
89
+ }
90
+ export function PreviewPane({ item, placement, width, labels, onCopied, onCopyBlocked, }) {
91
+ var _a, _b, _c, _d, _e;
92
+ const { colors } = useCustomTheme();
93
+ const isDock = placement === "dock";
94
+ return (_jsx(Flex, { as: "aside", "aria-label": labels.preview, "data-testid": "launcher-preview", "data-scroll-region": true, direction: "column", gap: isDock ? "10px" : "16px", w: isDock ? "100%" : width, maxH: isDock ? "min(45vh, 20rem)" : undefined, flexShrink: 0, px: "18px", pt: isDock ? "12px" : "16px", pb: isDock ? "12px" : "16px", bg: colors.backgroundColor.subtle, ...(isDock ? { borderTopWidth: "1px" } : { borderLeftWidth: "1px" }), borderColor: colors.boxborder[200], overflowY: "auto", children: item ? (_jsxs(_Fragment, { children: [_jsxs(Flex, { align: "center", gap: "10px", minW: 0, children: [_jsx(IconChip, { icon: item.icon, size: isDock ? 28 : 36 }), _jsxs(Box, { minW: 0, children: [_jsx(Text, { fontSize: isDock ? "14px" : "15px", fontWeight: 600, color: colors.text[900], noOfLines: isDock ? 1 : 2, children: (_b = (_a = item.answer) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : item.label }), item.context || item.answer ? (_jsx(Text, { fontSize: "xs", color: colors.textMuted, noOfLines: 1, children: (_d = (_c = item.answer) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : item.context })) : null] })] }), ((_e = item.facts) === null || _e === void 0 ? void 0 : _e.length) ? (_jsx(FactList, { facts: item.facts, labels: labels, layout: isDock ? "inline" : "pane", onCopied: onCopied, onCopyBlocked: onCopyBlocked }, item.id)) : (_jsxs(Flex, { "aria-hidden": true, align: "center", gap: "6px", fontSize: "xs", color: colors.textMuted, children: [_jsx(KbdShortcut, { shortcut: "enter", size: "xs" }), labels.hintOpen] }))] })) : null }));
95
+ }