pixelize-design-library 2.4.2-beta.58 → 2.4.2-beta.60

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 (244) hide show
  1. package/CHANGELOG.md +149 -5
  2. package/COMPONENT-GOTCHAS.md +205 -18
  3. package/DESIGN-GUIDE.md +43 -9
  4. package/dist/Components/AppSwitcher/AppSwitcher.js +5 -1
  5. package/dist/Components/AppSwitcher/AppSwitcherProps.d.ts +2 -0
  6. package/dist/Components/AppSwitcher/AppSwitcherProps.js +7 -4
  7. package/dist/Components/AudioRecorder/AudioRecorder.d.ts +8 -0
  8. package/dist/Components/AudioRecorder/AudioRecorder.js +169 -0
  9. package/dist/Components/AudioRecorder/AudioRecorderProps.d.ts +20 -0
  10. package/dist/Components/AudioRecorder/AudioRecorderProps.js +2 -0
  11. package/dist/Components/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  12. package/dist/Components/Breadcrumbs/Breadcrumbs.js +33 -10
  13. package/dist/Components/Breadcrumbs/BreadcrumbsProps.d.ts +16 -2
  14. package/dist/Components/BulkSelectionBar/BulkSelectionBar.d.ts +3 -0
  15. package/dist/Components/BulkSelectionBar/BulkSelectionBar.js +43 -0
  16. package/dist/Components/BulkSelectionBar/BulkSelectionBarProps.d.ts +35 -0
  17. package/dist/Components/BulkSelectionBar/BulkSelectionBarProps.js +2 -0
  18. package/dist/Components/BulkSelectionBar/index.d.ts +2 -0
  19. package/dist/Components/BulkSelectionBar/index.js +8 -0
  20. package/dist/Components/CalendarGrid/CalendarGrid.d.ts +3 -0
  21. package/dist/Components/CalendarGrid/CalendarGrid.js +173 -0
  22. package/dist/Components/CalendarGrid/CalendarGridProps.d.ts +54 -0
  23. package/dist/Components/CalendarGrid/CalendarGridProps.js +2 -0
  24. package/dist/Components/CalendarGrid/calendarMath.d.ts +49 -0
  25. package/dist/Components/CalendarGrid/calendarMath.js +178 -0
  26. package/dist/Components/Card/Card.d.ts +3 -1
  27. package/dist/Components/Card/Card.js +12 -2
  28. package/dist/Components/Card/CardProps.d.ts +5 -1
  29. package/dist/Components/CircularProgress/CircularProgress.d.ts +4 -0
  30. package/dist/Components/CircularProgress/CircularProgress.js +39 -0
  31. package/dist/Components/CircularProgress/CircularProgressProps.d.ts +22 -0
  32. package/dist/Components/CircularProgress/CircularProgressProps.js +2 -0
  33. package/dist/Components/CircularProgress/arc.d.ts +12 -0
  34. package/dist/Components/CircularProgress/arc.js +16 -0
  35. package/dist/Components/Common/fieldStyles.d.ts +1 -0
  36. package/dist/Components/Common/fieldStyles.js +2 -1
  37. package/dist/Components/Drawer/Drawer.d.ts +1 -1
  38. package/dist/Components/Drawer/Drawer.js +4 -2
  39. package/dist/Components/Drawer/DrawerProps.d.ts +3 -1
  40. package/dist/Components/Editor/Editor.js +50 -2
  41. package/dist/Components/Editor/EditorFieldBar.d.ts +15 -0
  42. package/dist/Components/Editor/EditorFieldBar.js +19 -0
  43. package/dist/Components/Editor/EditorProps.d.ts +74 -1
  44. package/dist/Components/Editor/MakeDynamicDialog.d.ts +12 -0
  45. package/dist/Components/Editor/MakeDynamicDialog.js +59 -0
  46. package/dist/Components/Editor/editorLabels.d.ts +4 -0
  47. package/dist/Components/Editor/editorLabels.js +24 -0
  48. package/dist/Components/Editor/editorTokenStyles.d.ts +28 -0
  49. package/dist/Components/Editor/editorTokenStyles.js +30 -0
  50. package/dist/Components/Editor/editorTokens.d.ts +26 -0
  51. package/dist/Components/Editor/editorTokens.js +134 -0
  52. package/dist/Components/Editor/useEditorBridge.d.ts +40 -0
  53. package/dist/Components/Editor/useEditorBridge.js +141 -0
  54. package/dist/Components/EmptyState/EmptyState.js +2 -1
  55. package/dist/Components/EmptyState/EmptyStateProps.d.ts +2 -2
  56. package/dist/Components/FormDrawer/FormDrawer.d.ts +2 -0
  57. package/dist/Components/FormDrawer/FormDrawer.js +97 -0
  58. package/dist/Components/FormDrawer/FormDrawerProps.d.ts +55 -0
  59. package/dist/Components/FormDrawer/FormDrawerProps.js +2 -0
  60. package/dist/Components/Kbd/Kbd.d.ts +6 -0
  61. package/dist/Components/Kbd/Kbd.js +33 -0
  62. package/dist/Components/Kbd/KbdProps.d.ts +17 -0
  63. package/dist/Components/Kbd/KbdProps.js +2 -0
  64. package/dist/Components/LauncherTrigger/LauncherTrigger.d.ts +4 -0
  65. package/dist/Components/LauncherTrigger/LauncherTrigger.js +48 -0
  66. package/dist/Components/LauncherTrigger/LauncherTriggerProps.d.ts +18 -0
  67. package/dist/Components/LauncherTrigger/LauncherTriggerProps.js +2 -0
  68. package/dist/Components/Modal/Modal.d.ts +1 -1
  69. package/dist/Components/Modal/Modal.js +4 -2
  70. package/dist/Components/Modal/ModalProps.d.ts +3 -1
  71. package/dist/Components/Modal/warnDroppedSlotChildren.d.ts +2 -0
  72. package/dist/Components/Modal/warnDroppedSlotChildren.js +45 -0
  73. package/dist/Components/NavLauncher/NavLauncher.d.ts +3 -0
  74. package/dist/Components/NavLauncher/NavLauncher.js +452 -0
  75. package/dist/Components/NavLauncher/NavLauncherProps.d.ts +187 -0
  76. package/dist/Components/NavLauncher/NavLauncherProps.js +2 -0
  77. package/dist/Components/NavLauncher/NewTabLink.d.ts +3 -0
  78. package/dist/Components/NavLauncher/NewTabLink.js +14 -0
  79. package/dist/Components/NavLauncher/PinToggle.d.ts +3 -0
  80. package/dist/Components/NavLauncher/PinToggle.js +21 -0
  81. package/dist/Components/NavLauncher/launcherParts.d.ts +152 -0
  82. package/dist/Components/NavLauncher/launcherParts.js +212 -0
  83. package/dist/Components/NavLauncher/match.d.ts +53 -0
  84. package/dist/Components/NavLauncher/match.js +178 -0
  85. package/dist/Components/NavLauncher/revealStyles.d.ts +4 -0
  86. package/dist/Components/NavLauncher/revealStyles.js +19 -0
  87. package/dist/Components/NavigationBar/NavigationBar.d.ts +1 -1
  88. package/dist/Components/NavigationBar/NavigationBar.js +2 -2
  89. package/dist/Components/NavigationBar/NavigationBarProps.d.ts +2 -0
  90. package/dist/Components/PageHeader/PageHeader.d.ts +1 -1
  91. package/dist/Components/PageHeader/PageHeader.js +9 -2
  92. package/dist/Components/PageHeader/PageHeaderProps.d.ts +8 -0
  93. package/dist/Components/PdfViewer/PdfViewer.d.ts +21 -4
  94. package/dist/Components/PdfViewer/PdfViewer.js +124 -3
  95. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -0
  96. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewerProps.d.ts +1 -1
  97. package/dist/Components/QueryState/QueryStateBoundary.d.ts +2 -2
  98. package/dist/Components/QueryState/QueryStateBoundary.js +9 -3
  99. package/dist/Components/QueryState/QueryStateProps.d.ts +19 -2
  100. package/dist/Components/Search/Search.js +2 -1
  101. package/dist/Components/SectionRail/SectionRail.d.ts +3 -0
  102. package/dist/Components/SectionRail/SectionRail.js +49 -0
  103. package/dist/Components/SectionRail/SectionRailProps.d.ts +23 -0
  104. package/dist/Components/SectionRail/SectionRailProps.js +2 -0
  105. package/dist/Components/SectionRail/index.d.ts +2 -0
  106. package/dist/Components/SectionRail/index.js +8 -0
  107. package/dist/Components/SegmentedControl/SegmentedControl.js +9 -14
  108. package/dist/Components/SegmentedControl/segmentedInk.d.ts +0 -2
  109. package/dist/Components/SegmentedControl/segmentedInk.js +1 -5
  110. package/dist/Components/SideBar/SecondaryBar.js +4 -3
  111. package/dist/Components/SideBar/SideBar.d.ts +1 -1
  112. package/dist/Components/SideBar/SideBar.js +30 -9
  113. package/dist/Components/SideBar/SideBarProps.d.ts +32 -0
  114. package/dist/Components/SideBar/components/MenuItemBox.d.ts +6 -0
  115. package/dist/Components/SideBar/components/MenuItemBox.js +8 -4
  116. package/dist/Components/SideBar/components/MenuPopoverContent.js +3 -2
  117. package/dist/Components/SideBar/components/OtherApps.js +2 -1
  118. package/dist/Components/SideBar/components/PinnedSection.d.ts +17 -0
  119. package/dist/Components/SideBar/components/PinnedSection.js +98 -0
  120. package/dist/Components/SideBar/sidebarFocus.d.ts +23 -0
  121. package/dist/Components/SideBar/sidebarFocus.js +20 -0
  122. package/dist/Components/StageProgress/StageProgress.js +2 -2
  123. package/dist/Components/StageProgress/StageProgressProps.d.ts +2 -0
  124. package/dist/Components/StageProgress/StepperStage.js +5 -2
  125. package/dist/Components/StatCard/StatCard.d.ts +1 -1
  126. package/dist/Components/StatCard/StatCard.js +6 -2
  127. package/dist/Components/StatCard/StatCardProps.d.ts +3 -0
  128. package/dist/Components/StatusTag/StatusTag.d.ts +4 -0
  129. package/dist/Components/StatusTag/StatusTag.js +24 -0
  130. package/dist/Components/StatusTag/StatusTagProps.d.ts +20 -0
  131. package/dist/Components/StatusTag/StatusTagProps.js +2 -0
  132. package/dist/Components/Table/Table.d.ts +1 -1
  133. package/dist/Components/Table/Table.js +6 -2
  134. package/dist/Components/Table/TableProps.d.ts +20 -0
  135. package/dist/Components/Table/components/TableBody.d.ts +1 -1
  136. package/dist/Components/Table/components/TableBody.js +43 -18
  137. package/dist/Components/Table/components/TableHeader.d.ts +1 -1
  138. package/dist/Components/Table/components/TableHeader.js +7 -5
  139. package/dist/Components/Table/components/rowDetail.d.ts +32 -0
  140. package/dist/Components/Table/components/rowDetail.js +20 -0
  141. package/dist/Components/Table/hooks/useRowExpansion.d.ts +7 -0
  142. package/dist/Components/Table/hooks/useRowExpansion.js +27 -0
  143. package/dist/Components/Tabs/Tabs.d.ts +1 -1
  144. package/dist/Components/Tabs/Tabs.js +15 -2
  145. package/dist/Components/Tabs/TabsProps.d.ts +6 -2
  146. package/dist/Components/Tabs/components/Tab.js +4 -33
  147. package/dist/Components/Tabs/components/TabLinkList.d.ts +7 -0
  148. package/dist/Components/Tabs/components/TabLinkList.js +34 -0
  149. package/dist/Components/Tabs/useTabAppearance.d.ts +17 -0
  150. package/dist/Components/Tabs/useTabAppearance.js +67 -0
  151. package/dist/Components/Tag/Tag.js +11 -1
  152. package/dist/Components/Tag/TagProps.d.ts +4 -0
  153. package/dist/Components/Tag/tagDot.d.ts +3 -0
  154. package/dist/Components/Tag/tagDot.js +21 -0
  155. package/dist/Components/WizardDialog/WizardDialog.d.ts +9 -0
  156. package/dist/Components/WizardDialog/WizardDialog.js +102 -0
  157. package/dist/Components/WizardDialog/WizardDialogProps.d.ts +48 -0
  158. package/dist/Components/WizardDialog/WizardDialogProps.js +2 -0
  159. package/dist/Components/WizardDialog/useWizardFlow.d.ts +22 -0
  160. package/dist/Components/WizardDialog/useWizardFlow.js +47 -0
  161. package/dist/Components/WizardDialog/wizardSteps.d.ts +31 -0
  162. package/dist/Components/WizardDialog/wizardSteps.js +40 -0
  163. package/dist/esm/Components/AppSwitcher/AppSwitcher.js +2 -1
  164. package/dist/esm/Components/AppSwitcher/AppSwitcherProps.js +5 -3
  165. package/dist/esm/Components/AudioRecorder/AudioRecorder.js +161 -0
  166. package/dist/esm/Components/AudioRecorder/AudioRecorderProps.js +1 -0
  167. package/dist/esm/Components/Breadcrumbs/Breadcrumbs.js +35 -12
  168. package/dist/esm/Components/BulkSelectionBar/BulkSelectionBar.js +38 -0
  169. package/dist/esm/Components/BulkSelectionBar/BulkSelectionBarProps.js +1 -0
  170. package/dist/esm/Components/BulkSelectionBar/index.js +1 -0
  171. package/dist/esm/Components/CalendarGrid/CalendarGrid.js +168 -0
  172. package/dist/esm/Components/CalendarGrid/CalendarGridProps.js +1 -0
  173. package/dist/esm/Components/CalendarGrid/calendarMath.js +155 -0
  174. package/dist/esm/Components/Card/Card.js +12 -2
  175. package/dist/esm/Components/CircularProgress/CircularProgress.js +37 -0
  176. package/dist/esm/Components/CircularProgress/CircularProgressProps.js +1 -0
  177. package/dist/esm/Components/CircularProgress/arc.js +11 -0
  178. package/dist/esm/Components/Common/fieldStyles.js +2 -1
  179. package/dist/esm/Components/Drawer/Drawer.js +4 -2
  180. package/dist/esm/Components/Editor/Editor.js +48 -3
  181. package/dist/esm/Components/Editor/EditorFieldBar.js +13 -0
  182. package/dist/esm/Components/Editor/MakeDynamicDialog.js +20 -0
  183. package/dist/esm/Components/Editor/editorLabels.js +20 -0
  184. package/dist/esm/Components/Editor/editorTokenStyles.js +25 -0
  185. package/dist/esm/Components/Editor/editorTokens.js +121 -0
  186. package/dist/esm/Components/Editor/useEditorBridge.js +138 -0
  187. package/dist/esm/Components/EmptyState/EmptyState.js +2 -1
  188. package/dist/esm/Components/FormDrawer/FormDrawer.js +58 -0
  189. package/dist/esm/Components/FormDrawer/FormDrawerProps.js +1 -0
  190. package/dist/esm/Components/Kbd/Kbd.js +28 -0
  191. package/dist/esm/Components/Kbd/KbdProps.js +1 -0
  192. package/dist/esm/Components/LauncherTrigger/LauncherTrigger.js +41 -0
  193. package/dist/esm/Components/LauncherTrigger/LauncherTriggerProps.js +1 -0
  194. package/dist/esm/Components/Modal/Modal.js +4 -2
  195. package/dist/esm/Components/Modal/warnDroppedSlotChildren.js +38 -0
  196. package/dist/esm/Components/NavLauncher/NavLauncher.js +413 -0
  197. package/dist/esm/Components/NavLauncher/NavLauncherProps.js +1 -0
  198. package/dist/esm/Components/NavLauncher/NewTabLink.js +11 -0
  199. package/dist/esm/Components/NavLauncher/PinToggle.js +18 -0
  200. package/dist/esm/Components/NavLauncher/launcherParts.js +187 -0
  201. package/dist/esm/Components/NavLauncher/match.js +172 -0
  202. package/dist/esm/Components/NavLauncher/revealStyles.js +15 -0
  203. package/dist/esm/Components/NavigationBar/NavigationBar.js +3 -3
  204. package/dist/esm/Components/PageHeader/PageHeader.js +9 -2
  205. package/dist/esm/Components/PdfViewer/PdfViewer.js +123 -2
  206. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -0
  207. package/dist/esm/Components/QueryState/QueryStateBoundary.js +10 -4
  208. package/dist/esm/Components/Search/Search.js +3 -2
  209. package/dist/esm/Components/SectionRail/SectionRail.js +44 -0
  210. package/dist/esm/Components/SectionRail/SectionRailProps.js +1 -0
  211. package/dist/esm/Components/SectionRail/index.js +1 -0
  212. package/dist/esm/Components/SegmentedControl/SegmentedControl.js +11 -16
  213. package/dist/esm/Components/SegmentedControl/segmentedInk.js +0 -3
  214. package/dist/esm/Components/SideBar/SecondaryBar.js +4 -3
  215. package/dist/esm/Components/SideBar/SideBar.js +31 -10
  216. package/dist/esm/Components/SideBar/components/MenuItemBox.js +4 -2
  217. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +3 -2
  218. package/dist/esm/Components/SideBar/components/OtherApps.js +2 -1
  219. package/dist/esm/Components/SideBar/components/PinnedSection.js +92 -0
  220. package/dist/esm/Components/SideBar/sidebarFocus.js +15 -0
  221. package/dist/esm/Components/StageProgress/StageProgress.js +2 -2
  222. package/dist/esm/Components/StageProgress/StepperStage.js +5 -2
  223. package/dist/esm/Components/StatCard/StatCard.js +6 -2
  224. package/dist/esm/Components/StatusTag/StatusTag.js +19 -0
  225. package/dist/esm/Components/StatusTag/StatusTagProps.js +1 -0
  226. package/dist/esm/Components/Table/Table.js +7 -3
  227. package/dist/esm/Components/Table/components/TableBody.js +43 -18
  228. package/dist/esm/Components/Table/components/TableHeader.js +7 -5
  229. package/dist/esm/Components/Table/components/rowDetail.js +14 -0
  230. package/dist/esm/Components/Table/hooks/useRowExpansion.js +23 -0
  231. package/dist/esm/Components/Tabs/Tabs.js +15 -2
  232. package/dist/esm/Components/Tabs/components/Tab.js +4 -33
  233. package/dist/esm/Components/Tabs/components/TabLinkList.js +29 -0
  234. package/dist/esm/Components/Tabs/useTabAppearance.js +63 -0
  235. package/dist/esm/Components/Tag/Tag.js +12 -2
  236. package/dist/esm/Components/Tag/tagDot.js +17 -0
  237. package/dist/esm/Components/WizardDialog/WizardDialog.js +58 -0
  238. package/dist/esm/Components/WizardDialog/WizardDialogProps.js +1 -0
  239. package/dist/esm/Components/WizardDialog/useWizardFlow.js +44 -0
  240. package/dist/esm/Components/WizardDialog/wizardSteps.js +35 -0
  241. package/dist/esm/index.js +14 -0
  242. package/dist/index.d.ts +35 -6
  243. package/dist/index.js +38 -4
  244. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ import type { LauncherIcon, LauncherResultGroup, LauncherSearchItem, LauncherSection } from "./NavLauncherProps";
2
+ export type LauncherResult = {
3
+ id: string;
4
+ label: string;
5
+ context?: string;
6
+ icon?: LauncherIcon;
7
+ hint?: string;
8
+ badge?: number | string;
9
+ href?: string;
10
+ run?: () => void;
11
+ screenId?: string;
12
+ /** Set on `searchLauncherSections` rows: a module row or one of its screens. */
13
+ kind?: "module" | "screen";
14
+ /** Keyword that matched a module or screen whose own name did not. */
15
+ keywordHint?: string;
16
+ isNew?: boolean;
17
+ };
18
+ export type LauncherResultView = {
19
+ id: string;
20
+ label: string;
21
+ items: LauncherResult[];
22
+ };
23
+ export declare function flattenScreens(sections: readonly LauncherSection[]): LauncherResult[];
24
+ export declare function searchLauncher(input: {
25
+ query: string;
26
+ sections: readonly LauncherSection[];
27
+ actions?: readonly LauncherSearchItem[];
28
+ extraResults?: readonly LauncherResultGroup[];
29
+ screensLabel: string;
30
+ actionsLabel: string;
31
+ }): LauncherResultView[];
32
+ export type LauncherSectionResult = {
33
+ id: string;
34
+ label: string;
35
+ items: LauncherResult[];
36
+ };
37
+ /** Search that keeps the sections: per section, matching modules, each followed by its matching screens. */
38
+ export declare function searchLauncherSections(input: {
39
+ query: string;
40
+ sections: readonly LauncherSection[];
41
+ actions?: readonly LauncherSearchItem[];
42
+ extraResults?: readonly LauncherResultGroup[];
43
+ actionsLabel: string;
44
+ }): {
45
+ sections: LauncherSectionResult[];
46
+ groups: LauncherResultView[];
47
+ };
48
+ export type HighlightSegment = {
49
+ text: string;
50
+ isMatch: boolean;
51
+ };
52
+ /** Splits `text` so every case-insensitive occurrence of a query token is its own matched segment. */
53
+ export declare function highlightSegments(text: string, query: string): HighlightSegment[];
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flattenScreens = flattenScreens;
4
+ exports.searchLauncher = searchLauncher;
5
+ exports.searchLauncherSections = searchLauncherSections;
6
+ exports.highlightSegments = highlightSegments;
7
+ const normalize = (text) => text.toLocaleLowerCase().normalize("NFKD");
8
+ function score(label, haystack, tokens) {
9
+ if (!tokens.every((t) => haystack.includes(t)))
10
+ return null;
11
+ const l = normalize(label);
12
+ const q = tokens.join(" ");
13
+ if (l === q)
14
+ return 0;
15
+ if (l.startsWith(q))
16
+ return 1;
17
+ if (l.split(/\s+/).some((w) => w.startsWith(tokens[0])))
18
+ return 2;
19
+ return l.includes(tokens[0]) ? 3 : 4;
20
+ }
21
+ function rank(rows, text, tokens) {
22
+ return rows
23
+ .map((row, index) => ({
24
+ row,
25
+ index,
26
+ s: score(row.label, normalize(text(row)), tokens),
27
+ }))
28
+ .filter((r) => r.s !== null)
29
+ .sort((a, b) => a.s - b.s || a.index - b.index)
30
+ .map((r) => r.row);
31
+ }
32
+ function flattenScreens(sections) {
33
+ var _a, _b, _c;
34
+ const seen = new Set();
35
+ const out = [];
36
+ for (const section of sections) {
37
+ for (const module of section.modules) {
38
+ for (const screen of module.screens) {
39
+ if (seen.has(screen.id))
40
+ continue;
41
+ seen.add(screen.id);
42
+ out.push({
43
+ id: `screen:${screen.id}`,
44
+ screenId: screen.id,
45
+ label: screen.label,
46
+ context: screen.label === module.label ? section.label : module.label,
47
+ icon: (_a = screen.icon) !== null && _a !== void 0 ? _a : module.icon,
48
+ badge: screen.badge,
49
+ href: screen.href,
50
+ keywords: [module.label, ...((_b = module.keywords) !== null && _b !== void 0 ? _b : []), ...((_c = screen.keywords) !== null && _c !== void 0 ? _c : [])].join(" "),
51
+ });
52
+ }
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+ function searchLauncher(input) {
58
+ var _a, _b;
59
+ const tokens = normalize(input.query).split(/\s+/).filter(Boolean);
60
+ if (tokens.length === 0)
61
+ return [];
62
+ const screens = flattenScreens(input.sections);
63
+ const actions = rank(((_a = input.actions) !== null && _a !== void 0 ? _a : []).map((a) => ({ ...a, id: `action:${a.id}` })), (a) => { var _a, _b; return `${a.label} ${(_a = a.context) !== null && _a !== void 0 ? _a : ""} ${(_b = a.keywords) !== null && _b !== void 0 ? _b : ""}`; }, tokens);
64
+ const groups = [
65
+ { id: "actions", label: input.actionsLabel, items: actions },
66
+ {
67
+ id: "screens",
68
+ label: input.screensLabel,
69
+ items: rank(screens, (s) => { var _a; return `${s.label} ${(_a = s.context) !== null && _a !== void 0 ? _a : ""} ${s.keywords}`; }, tokens),
70
+ },
71
+ ...((_b = input.extraResults) !== null && _b !== void 0 ? _b : []).map((g) => ({
72
+ id: g.id,
73
+ label: g.label,
74
+ items: g.items.map((i) => ({ ...i, id: `${g.id}:${i.id}` })),
75
+ })),
76
+ ];
77
+ return groups.filter((g) => g.items.length > 0);
78
+ }
79
+ function matchNameOrKeyword(label, keywords, tokens) {
80
+ const name = normalize(label);
81
+ if (tokens.every((t) => name.includes(t)))
82
+ return {};
83
+ const terms = keywords.map(normalize);
84
+ const all = `${name} ${terms.join(" ")}`;
85
+ if (!tokens.every((t) => all.includes(t)))
86
+ return null;
87
+ const hit = keywords.find((_, i) => tokens.some((t) => terms[i].includes(t)));
88
+ return { keyword: hit !== null && hit !== void 0 ? hit : keywords[0] };
89
+ }
90
+ /** Search that keeps the sections: per section, matching modules, each followed by its matching screens. */
91
+ function searchLauncherSections(input) {
92
+ var _a, _b, _c, _d, _e, _f;
93
+ const tokens = normalize(input.query).split(/\s+/).filter(Boolean);
94
+ if (tokens.length === 0)
95
+ return { sections: [], groups: [] };
96
+ const seen = new Set();
97
+ const sections = [];
98
+ for (const section of input.sections) {
99
+ const items = [];
100
+ for (const module of section.modules) {
101
+ const moduleHit = matchNameOrKeyword(module.label, (_a = module.keywords) !== null && _a !== void 0 ? _a : [], tokens);
102
+ if (moduleHit) {
103
+ items.push({
104
+ id: `module:${module.id}`,
105
+ kind: "module",
106
+ label: module.label,
107
+ keywordHint: moduleHit.keyword,
108
+ icon: module.icon,
109
+ badge: module.badge,
110
+ isNew: module.isNew,
111
+ href: module.href,
112
+ screenId: (_b = module.screens[0]) === null || _b === void 0 ? void 0 : _b.id,
113
+ });
114
+ }
115
+ for (const screen of module.screens) {
116
+ if (screen.label === module.label || seen.has(screen.id))
117
+ continue;
118
+ if (!matchNameOrKeyword(screen.label, (_c = screen.keywords) !== null && _c !== void 0 ? _c : [], tokens))
119
+ continue;
120
+ seen.add(screen.id);
121
+ items.push({
122
+ id: `screen:${screen.id}`,
123
+ kind: "screen",
124
+ label: screen.label,
125
+ context: module.label,
126
+ icon: (_d = screen.icon) !== null && _d !== void 0 ? _d : module.icon,
127
+ badge: screen.badge,
128
+ href: screen.href,
129
+ });
130
+ }
131
+ }
132
+ if (items.length > 0)
133
+ sections.push({ id: section.id, label: section.label, items });
134
+ }
135
+ const actions = rank(((_e = input.actions) !== null && _e !== void 0 ? _e : []).map((a) => ({ ...a, id: `action:${a.id}` })), (a) => { var _a, _b; return `${a.label} ${(_a = a.context) !== null && _a !== void 0 ? _a : ""} ${(_b = a.keywords) !== null && _b !== void 0 ? _b : ""}`; }, tokens);
136
+ const groups = [
137
+ { id: "actions", label: input.actionsLabel, items: actions },
138
+ ...((_f = input.extraResults) !== null && _f !== void 0 ? _f : []).map((g) => ({
139
+ id: g.id,
140
+ label: g.label,
141
+ items: g.items.map((i) => ({ ...i, id: `${g.id}:${i.id}` })),
142
+ })),
143
+ ].filter((g) => g.items.length > 0);
144
+ return { sections, groups };
145
+ }
146
+ /** Splits `text` so every case-insensitive occurrence of a query token is its own matched segment. */
147
+ function highlightSegments(text, query) {
148
+ const lower = text.toLocaleLowerCase();
149
+ const tokens = query.toLocaleLowerCase().split(/\s+/).filter(Boolean);
150
+ if (tokens.length === 0 || lower.length !== text.length)
151
+ return [{ text, isMatch: false }];
152
+ const ranges = [];
153
+ for (const token of tokens) {
154
+ for (let at = lower.indexOf(token); at !== -1; at = lower.indexOf(token, at + token.length)) {
155
+ ranges.push([at, at + token.length]);
156
+ }
157
+ }
158
+ ranges.sort((a, b) => a[0] - b[0]);
159
+ const merged = [];
160
+ for (const range of ranges) {
161
+ const last = merged[merged.length - 1];
162
+ if (last && range[0] <= last[1])
163
+ last[1] = Math.max(last[1], range[1]);
164
+ else
165
+ merged.push([...range]);
166
+ }
167
+ const out = [];
168
+ let cursor = 0;
169
+ for (const [start, end] of merged) {
170
+ if (start > cursor)
171
+ out.push({ text: text.slice(cursor, start), isMatch: false });
172
+ out.push({ text: text.slice(start, end), isMatch: true });
173
+ cursor = end;
174
+ }
175
+ if (cursor < text.length)
176
+ out.push({ text: text.slice(cursor), isMatch: false });
177
+ return out.length ? out : [{ text, isMatch: false }];
178
+ }
@@ -0,0 +1,4 @@
1
+ import type { SystemStyleObject } from "@chakra-ui/react";
2
+ import type { PaletteProps } from "../../Theme/tokens/types";
3
+ /** Shows a row affordance on row hover, row focus-within or its own keyboard focus, and always on touch. */
4
+ export declare const revealStyles: (colors: PaletteProps) => SystemStyleObject;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.revealStyles = void 0;
4
+ const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
5
+ const motion_1 = require("../../Theme/chakra/motion");
6
+ /** Shows a row affordance on row hover, row focus-within or its own keyboard focus, and always on touch. */
7
+ const revealStyles = (colors) => {
8
+ const ring = (0, focusRing_styles_1.focusVisibleStyles)(colors);
9
+ return {
10
+ ...ring,
11
+ _focusVisible: { ...ring._focusVisible, opacity: 1 },
12
+ _groupHover: { opacity: 1 },
13
+ _groupFocusWithin: { opacity: 1 },
14
+ "[data-reveal=true] &": { opacity: 1 },
15
+ "@media (hover: none)": { opacity: 1 },
16
+ ...(0, motion_1.reducedMotionSx)(),
17
+ };
18
+ };
19
+ exports.revealStyles = revealStyles;
@@ -1,2 +1,2 @@
1
1
  import { NavbarProps } from "./NavigationBarProps";
2
- export default function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavOnClick, handleLogout, logoutText, navigationBarText, sideBarToggole, onSideBarToggole, forceSideBarToggle, onSideBarPeek, }: NavbarProps): import("react/jsx-runtime").JSX.Element;
2
+ export default function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavOnClick, handleLogout, logoutText, navigationBarText, sideBarToggole, onSideBarToggole, forceSideBarToggle, onSideBarPeek, leading, }: NavbarProps): import("react/jsx-runtime").JSX.Element;
@@ -16,7 +16,7 @@ const PersonChip_1 = __importDefault(require("../PersonChip/PersonChip"));
16
16
  const lucide_react_1 = require("lucide-react");
17
17
  // Roomy enough to hover without aiming: the glyph is only 1.25rem.
18
18
  const SIDEBAR_TOGGLE_HIT = "2.5rem";
19
- function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavOnClick, handleLogout, logoutText, navigationBarText, sideBarToggole, onSideBarToggole, forceSideBarToggle = false, onSideBarPeek, }) {
19
+ function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavOnClick, handleLogout, logoutText, navigationBarText, sideBarToggole, onSideBarToggole, forceSideBarToggle = false, onSideBarPeek, leading, }) {
20
20
  const theme = (0, useCustomTheme_1.useCustomTheme)();
21
21
  const rowBackgrounds = (0, rowStates_1.listRowBackgrounds)(theme.colors);
22
22
  const menuHoverBg = rowBackgrounds.active;
@@ -52,7 +52,7 @@ function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavO
52
52
  _focus: { bg: menuHoverBg },
53
53
  _active: { bg: rowBackgrounds.selectedActive },
54
54
  };
55
- return ((0, jsx_runtime_1.jsx)(react_1.Box, { bg: theme.colors.backgroundColor.light, px: 4, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: (0, jsx_runtime_1.jsxs)(react_1.Flex, { h: 16, alignItems: "center", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsxs)(react_1.Box, { display: "flex", gap: 1.5, alignItems: "center", children: [(0, jsx_runtime_1.jsx)(react_1.Box, { as: "button", type: "button", onClick: () => onSideBarToggole === null || onSideBarToggole === void 0 ? void 0 : onSideBarToggole(), onMouseEnter: onSideBarPeek, onFocus: onSideBarPeek, "aria-label": sideBarToggole ? "Close navigation menu" : "Open navigation menu", "aria-expanded": !!sideBarToggole, ...iconButtonStyle, display: forceSideBarToggle ? "flex" : { base: "flex", lg: "none" }, w: SIDEBAR_TOGGLE_HIT, h: SIDEBAR_TOGGLE_HIT, children: sideBarToggole ? ((0, jsx_runtime_1.jsx)(lucide_react_1.PanelLeftClose, { size: "1.25rem" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.PanelRightClose, { size: "1.25rem" })) }), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) && ((0, jsx_runtime_1.jsx)(react_1.Box, { ...iconButtonStyle, as: "button", type: "button", "aria-label": "Go back", display: "flex", onClick: () => { var _a; return (_a = navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) === null || _a === void 0 ? void 0 : _a.call(navigationBarText); }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.CircleArrowLeft, { size: "1.25rem", color: theme.colors.text[500] }) })), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text) && ((0, jsx_runtime_1.jsx)(react_1.Text, { color: (0, accentText_1.accentTextOnCanvas)(theme.colors.secondary, theme.colors.backgroundColor.light), fontSize: "1.25rem", fontWeight: 600, fontFamily: "open-sans, sans-serif", letterSpacing: "-0.013rem", children: navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text }))] }), (0, jsx_runtime_1.jsx)(react_1.Flex, { minW: 0, flexShrink: 1, children: (0, jsx_runtime_1.jsxs)(react_1.Stack, { direction: "row", alignItems: "center", spacing: 4, minW: 0, children: [moreIcon && ((0, jsx_runtime_1.jsx)(react_1.Box, { display: "flex", alignItems: "center", minW: 0, children: moreIcon })), (0, jsx_runtime_1.jsxs)(react_1.Menu, { children: [(0, jsx_runtime_1.jsx)(react_1.MenuButton, { as: react_1.Button, rounded: "full", variant: "link", cursor: "pointer", minW: 0, flexShrink: 0, children: (0, jsx_runtime_1.jsx)(Avatar_1.default, { size: "sm", name: userName, src: userAvathar }) }), (0, jsx_runtime_1.jsx)(react_1.MenuList, { alignItems: "center", zIndex: 5, p: 0, py: "0.375rem",
55
+ return ((0, jsx_runtime_1.jsx)(react_1.Box, { bg: theme.colors.backgroundColor.light, px: 4, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: (0, jsx_runtime_1.jsxs)(react_1.Flex, { h: 16, alignItems: "center", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsxs)(react_1.Box, { display: "flex", gap: 1.5, alignItems: "center", children: [(0, jsx_runtime_1.jsx)(react_1.Box, { as: "button", type: "button", onClick: () => onSideBarToggole === null || onSideBarToggole === void 0 ? void 0 : onSideBarToggole(), onMouseEnter: onSideBarPeek, onFocus: onSideBarPeek, "aria-label": sideBarToggole ? "Close navigation menu" : "Open navigation menu", "aria-expanded": !!sideBarToggole, ...iconButtonStyle, display: forceSideBarToggle ? "flex" : { base: "flex", lg: "none" }, w: SIDEBAR_TOGGLE_HIT, h: SIDEBAR_TOGGLE_HIT, children: sideBarToggole ? ((0, jsx_runtime_1.jsx)(lucide_react_1.PanelLeftClose, { size: "1.25rem" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.PanelRightClose, { size: "1.25rem" })) }), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) && ((0, jsx_runtime_1.jsx)(react_1.Box, { ...iconButtonStyle, as: "button", type: "button", "aria-label": "Go back", display: "flex", onClick: () => { var _a; return (_a = navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) === null || _a === void 0 ? void 0 : _a.call(navigationBarText); }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.CircleArrowLeft, { size: "1.25rem", color: theme.colors.text[500] }) })), leading && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [leading, (0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", "aria-hidden": "true", mx: 2, w: "1px", h: "1.625rem", bg: theme.colors.boxborder[200] })] })), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text) && ((0, jsx_runtime_1.jsx)(react_1.Text, { color: (0, accentText_1.accentTextOnCanvas)(theme.colors.secondary, theme.colors.backgroundColor.light), fontSize: "1.25rem", fontWeight: 600, fontFamily: "open-sans, sans-serif", letterSpacing: "-0.013rem", children: navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text }))] }), (0, jsx_runtime_1.jsx)(react_1.Flex, { minW: 0, flexShrink: 1, children: (0, jsx_runtime_1.jsxs)(react_1.Stack, { direction: "row", alignItems: "center", spacing: 4, minW: 0, children: [moreIcon && ((0, jsx_runtime_1.jsx)(react_1.Box, { display: "flex", alignItems: "center", minW: 0, children: moreIcon })), (0, jsx_runtime_1.jsxs)(react_1.Menu, { children: [(0, jsx_runtime_1.jsx)(react_1.MenuButton, { as: react_1.Button, rounded: "full", variant: "link", cursor: "pointer", minW: 0, flexShrink: 0, children: (0, jsx_runtime_1.jsx)(Avatar_1.default, { size: "sm", name: userName, src: userAvathar }) }), (0, jsx_runtime_1.jsx)(react_1.MenuList, { alignItems: "center", zIndex: 5, p: 0, py: "0.375rem",
56
56
  // Without a cap one long title stretches the whole dropdown; titles truncate instead.
57
57
  maxW: "18rem", bg: theme.colors.surfaceRaised,
58
58
  // NOTE: Chakra's MenuItem inherits --menu-bg hardcoded to #fff via dead _dark — set it or items stay white.
@@ -28,6 +28,8 @@ export type NavbarProps = {
28
28
  * same state the SideBar's `peekOpen` reads; it closes itself when the pointer leaves.
29
29
  */
30
30
  onSideBarPeek?: () => void;
31
+ /** Rendered between the sidebar toggle/back button and the title, outside the title element, followed by a 1px divider. */
32
+ leading?: ReactNode;
31
33
  };
32
34
  /** One navMenu entry (id/title/url/icon) — unrelated to Chakra's own MenuProps despite the shared name. */
33
35
  export type MenuProps = {
@@ -1,4 +1,4 @@
1
1
  import type { PageHeaderProps } from "./PageHeaderProps";
2
2
  /** Page header: h1 title, muted subtitle, right-aligned actions that wrap under on narrow screens. */
3
- declare const PageHeader: ({ title, subtitle, actions, breadcrumbs, leading, titleAddon, meta, tabs, "data-testid": testId, }: PageHeaderProps) => import("react/jsx-runtime").JSX.Element;
3
+ declare const PageHeader: ({ title, subtitle, actions, breadcrumbs, leading, titleAddon, meta, tabs, titleSize, actionsLayout, "data-testid": testId, }: PageHeaderProps) => import("react/jsx-runtime").JSX.Element;
4
4
  export default PageHeader;
@@ -3,9 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const jsx_runtime_1 = require("react/jsx-runtime");
4
4
  const react_1 = require("@chakra-ui/react");
5
5
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
6
+ const TITLE_STYLES = {
7
+ md: { fontSize: "lg", fontWeight: 600, letterSpacing: "-0.01em" },
8
+ lg: { fontSize: "2xl", fontWeight: 700, letterSpacing: "-0.02em", lineHeight: 1.2 },
9
+ xl: { fontSize: { base: "2xl", md: "3xl" }, fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2 },
10
+ };
6
11
  /** Page header: h1 title, muted subtitle, right-aligned actions that wrap under on narrow screens. */
7
- const PageHeader = ({ title, subtitle, actions, breadcrumbs, leading, titleAddon, meta, tabs, "data-testid": testId, }) => {
12
+ const PageHeader = ({ title, subtitle, actions, breadcrumbs, leading, titleAddon, meta, tabs, titleSize = "md", actionsLayout = "auto", "data-testid": testId, }) => {
8
13
  const { colors } = (0, useCustomTheme_1.useCustomTheme)();
9
- return ((0, jsx_runtime_1.jsxs)(react_1.Flex, { direction: "column", gap: 3, "data-testid": testId, children: [breadcrumbs && ((0, jsx_runtime_1.jsx)(react_1.Box, { fontSize: "sm", color: colors.textMuted, sx: { "[aria-current=page]": { color: colors.text[800] } }, children: breadcrumbs })), (0, jsx_runtime_1.jsxs)(react_1.Flex, { justify: "space-between", align: { base: "flex-start", md: "center" }, direction: { base: "column", md: "row" }, gap: 3, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { gap: 3, align: "center", minW: 0, children: [leading && (0, jsx_runtime_1.jsx)(react_1.Box, { flexShrink: 0, children: leading }), (0, jsx_runtime_1.jsxs)(react_1.Box, { minW: 0, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", gap: 2, wrap: "wrap", children: [(0, jsx_runtime_1.jsx)(react_1.Heading, { as: "h1", fontSize: "lg", fontWeight: 600, letterSpacing: "-0.01em", color: colors.header[900], children: title }), titleAddon] }), subtitle && ((0, jsx_runtime_1.jsx)(react_1.Text, { mt: 0.5, fontSize: "sm", color: colors.textMuted, children: subtitle })), meta && ((0, jsx_runtime_1.jsx)(react_1.Flex, { mt: 1, columnGap: 4, rowGap: 1, wrap: "wrap", align: "center", fontSize: "xs", color: colors.textMuted, children: meta }))] })] }), actions && ((0, jsx_runtime_1.jsx)(react_1.Flex, { gap: 2, wrap: "wrap", align: "center", flexShrink: 0, children: actions }))] }), tabs && (0, jsx_runtime_1.jsx)(react_1.Box, { children: tabs })] }));
14
+ const wraps = actionsLayout === "auto";
15
+ const stacked = actionsLayout === "stacked";
16
+ return ((0, jsx_runtime_1.jsxs)(react_1.Flex, { direction: "column", gap: 3, "data-testid": testId, children: [breadcrumbs && ((0, jsx_runtime_1.jsx)(react_1.Box, { fontSize: "sm", color: colors.textMuted, sx: { "[aria-current=page]": { color: colors.text[800] } }, children: breadcrumbs })), (0, jsx_runtime_1.jsxs)(react_1.Flex, { justify: "space-between", align: stacked ? "flex-start" : { base: "flex-start", md: "center" }, direction: stacked ? "column" : { base: "column", md: "row" }, wrap: wraps ? "wrap" : "nowrap", gap: 3, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { gap: 3, align: "center", minW: 0, flex: wraps ? { base: "0 1 auto", md: "1 1 16rem" } : undefined, children: [leading && (0, jsx_runtime_1.jsx)(react_1.Box, { flexShrink: 0, children: leading }), (0, jsx_runtime_1.jsxs)(react_1.Box, { minW: 0, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", gap: 2, wrap: "wrap", children: [(0, jsx_runtime_1.jsx)(react_1.Heading, { as: "h1", ...TITLE_STYLES[titleSize], color: colors.header[900], children: title }), titleAddon] }), subtitle && ((0, jsx_runtime_1.jsx)(react_1.Text, { mt: 0.5, fontSize: "sm", color: colors.textMuted, children: subtitle })), meta && ((0, jsx_runtime_1.jsx)(react_1.Flex, { mt: 1, columnGap: 4, rowGap: 1, wrap: "wrap", align: "center", fontSize: "xs", color: colors.textMuted, children: meta }))] })] }), actions && ((0, jsx_runtime_1.jsx)(react_1.Flex, { gap: 2, wrap: "wrap", align: "center", flexShrink: wraps ? undefined : 0, children: actions }))] }), tabs && (0, jsx_runtime_1.jsx)(react_1.Box, { children: tabs })] }));
10
17
  };
11
18
  exports.default = PageHeader;
@@ -16,5 +16,13 @@ export interface PageHeaderProps {
16
16
  meta?: ReactNode;
17
17
  /** Rendered full-width below the whole header, e.g. a Tabs list. */
18
18
  tabs?: ReactNode;
19
+ /** "md" = 18px/600 (default); "lg" = 24px/700; "xl" = 24px, 30px from `md`, 700, tighter tracking. */
20
+ titleSize?: PageHeaderTitleSize;
21
+ /** "auto" (default) wraps actions below the title whenever they don't fit beside it; "stacked" always stacks; "inline" never wraps from `md` up. */
22
+ actionsLayout?: PageHeaderActionsLayout;
19
23
  "data-testid"?: string;
20
24
  }
25
+ /** Title ramp step. */
26
+ export type PageHeaderTitleSize = "md" | "lg" | "xl";
27
+ /** How the actions row sits against the title block. */
28
+ export type PageHeaderActionsLayout = "auto" | "stacked" | "inline";
@@ -1,15 +1,32 @@
1
1
  import React from "react";
2
+ /** Visible strings; every key falls back to its English default. */
3
+ export type PdfViewerLabels = Partial<{
4
+ open: string;
5
+ download: string;
6
+ unsupported: string;
7
+ failed: string;
8
+ }>;
2
9
  export interface PdfViewerProps {
3
- /** Rendered via a native browser <embed> — no fallback UI if the browser can't show PDFs inline. */
4
- pdfUrl: string;
5
- /** File name shown in the toolbar. */
10
+ /** URL of the PDF, rendered via a native browser <embed>; pass exactly one of `pdfUrl` / `getBlob`. */
11
+ pdfUrl?: string;
12
+ /** Source as a blob getter instead of a URL — for authed files; the viewer makes and revokes the object URL. */
13
+ getBlob?: () => Promise<Blob>;
14
+ /** File name shown in the toolbar and used as the download name. */
6
15
  fileName?: string;
7
16
  /** Height of the embed. */
8
17
  height?: string;
9
- /** Show the toolbar (name + open + download). */
18
+ /** Show the toolbar (name + open + download); set false when the caller renders its own file actions. */
10
19
  showToolbar?: boolean;
11
20
  /** Border radius of the frame. */
12
21
  borderRadius?: string;
22
+ /** What shows when inline PDF is unsupported or loading failed. Default: message + Open + Download. */
23
+ fallback?: React.ReactNode;
24
+ /** Fires when the embed loads; in blob mode, when the file bytes are ready (<embed> has no reliable load event). */
25
+ onLoad?: () => void;
26
+ /** Fires when `getBlob` rejects or an on-demand Open/Download fetch fails. */
27
+ onError?: (error: unknown) => void;
28
+ labels?: PdfViewerLabels;
29
+ "data-testid"?: string;
13
30
  }
14
31
  /** Always-inline PDF embed panel (never a modal) — for a modal previewer of images/video/other too, use FilePreview. */
15
32
  declare const PdfViewer: React.FC<PdfViewerProps>;
@@ -4,18 +4,139 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
- const react_1 = require("@chakra-ui/react");
7
+ const react_1 = require("react");
8
+ const react_2 = require("@chakra-ui/react");
8
9
  const lucide_react_1 = require("lucide-react");
9
10
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
10
11
  const accentText_1 = require("../../Theme/tokens/builders/accentText");
11
12
  const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
13
+ const Button_1 = __importDefault(require("../Button/Button"));
14
+ const Skeletons_1 = __importDefault(require("../Skeletons/Skeletons"));
12
15
  const ToolTip_1 = __importDefault(require("../ToolTip/ToolTip"));
16
+ const DEFAULT_LABELS = {
17
+ open: "Open in new tab",
18
+ download: "Download",
19
+ unsupported: "This browser can't display PDFs inline. Open or download the file instead.",
20
+ failed: "The document could not be loaded.",
21
+ };
22
+ const canEmbedPdf = () => typeof navigator === "undefined" || navigator.pdfViewerEnabled !== false;
23
+ const asPdf = (blob) => (blob.type ? blob : new Blob([blob], { type: "application/pdf" }));
13
24
  /** Always-inline PDF embed panel (never a modal) — for a modal previewer of images/video/other too, use FilePreview. */
14
- const PdfViewer = ({ pdfUrl, fileName = "Document.pdf", height = "480px", showToolbar = true, borderRadius = "xl", }) => {
25
+ const PdfViewer = ({ pdfUrl, getBlob, fileName = "Document.pdf", height = "480px", showToolbar = true, borderRadius = "xl", fallback, onLoad, onError, labels, "data-testid": testId, }) => {
15
26
  const theme = (0, useCustomTheme_1.useCustomTheme)();
27
+ const text = { ...DEFAULT_LABELS, ...labels };
16
28
  const toolbarSurface = theme.colors.background[50];
17
29
  const iconHoverInk = (0, accentText_1.accentTextOnCanvas)(theme.colors.primary, toolbarSurface);
18
30
  const iconHoverBg = (0, rowStates_1.listRowBackgrounds)(theme.colors).active;
19
- return ((0, jsx_runtime_1.jsxs)(react_1.Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], children: [showToolbar && ((0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.background[50], children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", gap: 2, minW: 0, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 18, color: theme.colors.accentText }), (0, jsx_runtime_1.jsx)(react_1.Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), (0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", gap: 1, children: [(0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: "Open in new tab", placement: "top", children: (0, jsx_runtime_1.jsx)(react_1.Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", "aria-label": `Open ${fileName} in a new tab`, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: 16 }) }) }), (0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: "Download", placement: "top", children: (0, jsx_runtime_1.jsx)(react_1.Box, { as: "a", href: pdfUrl, download: fileName, "aria-label": `Download ${fileName}`, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 16 }) }) })] })] })), (0, jsx_runtime_1.jsx)(react_1.Box, { as: "embed", src: pdfUrl, type: "application/pdf", width: "100%", height: height, display: "block" })] }));
31
+ const supported = canEmbedPdf();
32
+ const isBlobMode = Boolean(getBlob);
33
+ const getBlobRef = (0, react_1.useRef)(getBlob);
34
+ const onLoadRef = (0, react_1.useRef)(onLoad);
35
+ const onErrorRef = (0, react_1.useRef)(onError);
36
+ getBlobRef.current = getBlob;
37
+ onLoadRef.current = onLoad;
38
+ onErrorRef.current = onError;
39
+ const [status, setStatus] = (0, react_1.useState)(isBlobMode && supported ? "loading" : "idle");
40
+ const [objectUrl, setObjectUrl] = (0, react_1.useState)(null);
41
+ const tempUrls = (0, react_1.useRef)([]);
42
+ (0, react_1.useEffect)(() => {
43
+ var _a;
44
+ if (!isBlobMode || !supported)
45
+ return undefined;
46
+ let cancelled = false;
47
+ let created = null;
48
+ setStatus("loading");
49
+ setObjectUrl(null);
50
+ (_a = getBlobRef.current) === null || _a === void 0 ? void 0 : _a.call(getBlobRef).then((blob) => {
51
+ var _a;
52
+ if (cancelled)
53
+ return;
54
+ created = URL.createObjectURL(asPdf(blob));
55
+ setObjectUrl(created);
56
+ setStatus("ready");
57
+ (_a = onLoadRef.current) === null || _a === void 0 ? void 0 : _a.call(onLoadRef);
58
+ }, (error) => {
59
+ var _a;
60
+ if (cancelled)
61
+ return;
62
+ setStatus("error");
63
+ (_a = onErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onErrorRef, error);
64
+ });
65
+ return () => {
66
+ cancelled = true;
67
+ if (created)
68
+ URL.revokeObjectURL(created);
69
+ };
70
+ }, [isBlobMode, supported]);
71
+ (0, react_1.useEffect)(() => () => {
72
+ tempUrls.current.forEach((url) => URL.revokeObjectURL(url));
73
+ tempUrls.current = [];
74
+ }, []);
75
+ const makeTempUrl = (0, react_1.useCallback)((blob) => {
76
+ const url = URL.createObjectURL(asPdf(blob));
77
+ tempUrls.current.push(url);
78
+ return url;
79
+ }, []);
80
+ const openBlob = () => {
81
+ var _a;
82
+ if (objectUrl) {
83
+ window.open(objectUrl, "_blank", "noopener");
84
+ return;
85
+ }
86
+ const tab = window.open("", "_blank");
87
+ (_a = getBlobRef.current) === null || _a === void 0 ? void 0 : _a.call(getBlobRef).then((blob) => {
88
+ const url = makeTempUrl(blob);
89
+ if (tab)
90
+ tab.location.href = url;
91
+ else
92
+ window.location.assign(url);
93
+ }, (error) => {
94
+ var _a;
95
+ tab === null || tab === void 0 ? void 0 : tab.close();
96
+ (_a = onErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onErrorRef, error);
97
+ });
98
+ };
99
+ const downloadBlob = () => {
100
+ var _a;
101
+ (_a = getBlobRef.current) === null || _a === void 0 ? void 0 : _a.call(getBlobRef).then((blob) => {
102
+ const link = document.createElement("a");
103
+ link.href = makeTempUrl(blob);
104
+ link.download = fileName;
105
+ document.body.appendChild(link);
106
+ link.click();
107
+ link.remove();
108
+ }, (error) => { var _a; return (_a = onErrorRef.current) === null || _a === void 0 ? void 0 : _a.call(onErrorRef, error); });
109
+ };
110
+ const toolbarLabel = (kind) => {
111
+ if (labels === null || labels === void 0 ? void 0 : labels[kind])
112
+ return `${labels[kind]} ${fileName}`;
113
+ return kind === "open" ? `Open ${fileName} in a new tab` : `Download ${fileName}`;
114
+ };
115
+ const actionStyle = {
116
+ p: 2,
117
+ borderRadius: "lg",
118
+ color: theme.colors.gray[600],
119
+ _hover: { bg: iconHoverBg, color: iconHoverInk },
120
+ };
121
+ const openAction = isBlobMode ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "button", type: "button", onClick: openBlob, "aria-label": toolbarLabel("open"), ...actionStyle, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: 16, "aria-hidden": "true" }) })) : ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", "aria-label": toolbarLabel("open"), ...actionStyle, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: 16, "aria-hidden": "true" }) }));
122
+ const downloadAction = isBlobMode && !objectUrl ? ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "button", type: "button", onClick: downloadBlob, "aria-label": toolbarLabel("download"), ...actionStyle, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 16, "aria-hidden": "true" }) })) : ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "a", href: objectUrl !== null && objectUrl !== void 0 ? objectUrl : pdfUrl, download: fileName, "aria-label": toolbarLabel("download"), ...actionStyle, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 16, "aria-hidden": "true" }) }));
123
+ const showFallback = !supported || status === "error";
124
+ const isLoading = isBlobMode && supported && status === "loading";
125
+ const renderFallback = () => {
126
+ if (fallback !== undefined)
127
+ return fallback;
128
+ return ((0, jsx_runtime_1.jsxs)(react_2.Flex, { direction: "column", align: "flex-start", gap: 3, p: 4, "data-testid": "pdf-fallback", children: [(0, jsx_runtime_1.jsx)(react_2.Text, { role: "status", fontSize: "sm", color: theme.colors.textMuted, children: supported ? text.failed : text.unsupported }), !showToolbar && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { gap: 2, wrap: "wrap", children: [(0, jsx_runtime_1.jsx)(Button_1.default, { variant: "outline", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: 16, "aria-hidden": "true" }), label: text.open, onClick: isBlobMode ? openBlob : () => window.open(pdfUrl, "_blank", "noopener"), "data-testid": "pdf-open" }), (0, jsx_runtime_1.jsx)(Button_1.default, { variant: "outline", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Download, { size: 16, "aria-hidden": "true" }), label: text.download, onClick: isBlobMode ? downloadBlob : directDownload(pdfUrl, fileName), "data-testid": "pdf-download" })] }))] }));
129
+ };
130
+ return ((0, jsx_runtime_1.jsxs)(react_2.Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], "data-testid": testId, children: [showToolbar && ((0, jsx_runtime_1.jsxs)(react_2.Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.background[50], children: [(0, jsx_runtime_1.jsxs)(react_2.Flex, { align: "center", gap: 2, minW: 0, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 18, color: theme.colors.accentText, "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), (0, jsx_runtime_1.jsxs)(react_2.Flex, { align: "center", gap: 1, children: [(0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: text.open, placement: "top", children: openAction }), (0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: text.download, placement: "top", children: downloadAction })] })] })), showFallback ? (renderFallback()) : isLoading ? ((0, jsx_runtime_1.jsx)(react_2.Box, { "aria-busy": "true", "data-testid": "pdf-loading", children: (0, jsx_runtime_1.jsx)(Skeletons_1.default, { type: "skeleton", height: height, width: "100%", borderRadius: "0" }) })) : ((0, jsx_runtime_1.jsx)(react_2.Box, { as: "embed", src: objectUrl !== null && objectUrl !== void 0 ? objectUrl : pdfUrl, type: "application/pdf", title: fileName, onLoad: isBlobMode ? undefined : () => { var _a; return (_a = onLoadRef.current) === null || _a === void 0 ? void 0 : _a.call(onLoadRef); }, width: "100%", height: height, display: "block" }))] }));
131
+ };
132
+ const directDownload = (url, fileName) => () => {
133
+ if (!url)
134
+ return;
135
+ const link = document.createElement("a");
136
+ link.href = url;
137
+ link.download = fileName;
138
+ document.body.appendChild(link);
139
+ link.click();
140
+ link.remove();
20
141
  };
21
142
  exports.default = PdfViewer;
@@ -13,6 +13,11 @@ const color_1 = require("../../Theme/tokens/builders/color");
13
13
  function ProfilePhotoViewer({ photoUrl, onPhotoChange, imageWidth = "100px", imageAlt = "Profile Photo", imageObjectFit = "cover", imageBorderRadius = "full", editIconSize = "sm", editIconPositionRight = "0px", editIconPositionBottom = "0px", isRound = true, boxStyle, isEditable = false, isView = false, style, handleIsView, fallbackText, revealOnHover = true, }) {
14
14
  var _a, _b, _c, _d, _e;
15
15
  const [photo, setPhoto] = (0, react_1.useState)(photoUrl);
16
+ const [syncedUrl, setSyncedUrl] = (0, react_1.useState)(photoUrl);
17
+ if (photoUrl !== syncedUrl) {
18
+ setSyncedUrl(photoUrl);
19
+ setPhoto(photoUrl);
20
+ }
16
21
  const fileInputRef = (0, react_1.useRef)(null);
17
22
  const theme = (0, useCustomTheme_1.useCustomTheme)();
18
23
  const c = theme.colors;
@@ -1,6 +1,6 @@
1
1
  /** isEditable and isView are independent — both true shows edit and view actions side by side. */
2
2
  export type ProfilePhotoViewerProps = {
3
- /** Seeds state on mount only — a later change to this prop is not re-synced; remount (key={photoUrl}) to update. */
3
+ /** Source of the displayed image; a changed value replaces it, discarding a locally picked preview. */
4
4
  photoUrl: string;
5
5
  /** Receives the raw File (not a URL, despite the param name) — fires only when isEditable and a file is picked. */
6
6
  onPhotoChange: (photoUrl: File) => void;
@@ -1,4 +1,4 @@
1
1
  import type { QueryStateBoundaryProps } from "./QueryStateProps";
2
- /** Renders one of loading / error / empty / children for a content region; agnostic of the fetching library. */
3
- declare const QueryStateBoundary: ({ isLoading, error, isEmpty, loadingFallback, emptyFallback, empty, errorTitle, errorDescription, onRetry, isRetrying, minH, children, }: QueryStateBoundaryProps) => import("react/jsx-runtime").JSX.Element;
2
+ /** Renders one of loading / forbidden / error / empty / children for a content region; agnostic of the fetching library. */
3
+ declare const QueryStateBoundary: ({ isLoading, isForbidden, forbidden, hasData, error, isEmpty, loadingFallback, emptyFallback, empty, errorTitle, errorDescription, onRetry, isRetrying, minH, children, }: QueryStateBoundaryProps) => import("react/jsx-runtime").JSX.Element;
4
4
  export default QueryStateBoundary;
@@ -5,15 +5,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("@chakra-ui/react");
8
+ const lucide_react_1 = require("lucide-react");
8
9
  const EmptyState_1 = __importDefault(require("../EmptyState/EmptyState"));
9
10
  const Skeletons_1 = __importDefault(require("../Skeletons/Skeletons"));
10
11
  const ErrorState_1 = __importDefault(require("./ErrorState"));
11
12
  const DefaultLoading = () => ((0, jsx_runtime_1.jsxs)(react_1.Flex, { role: "status", direction: "column", gap: 4, w: "100%", py: 2, children: [(0, jsx_runtime_1.jsx)(react_1.VisuallyHidden, { children: "Loading" }), (0, jsx_runtime_1.jsx)(Skeletons_1.default, { type: "skeleton", height: 4, width: "40%" }), Array.from({ length: 4 }, (_, i) => ((0, jsx_runtime_1.jsxs)(react_1.Flex, { direction: "column", gap: 2, children: [(0, jsx_runtime_1.jsx)(Skeletons_1.default, { type: "skeleton", height: 2.5, width: "100%" }), (0, jsx_runtime_1.jsx)(Skeletons_1.default, { type: "skeleton", height: 2.5, width: "70%" })] }, i)))] }));
12
13
  const hasError = (error) => error !== undefined && error !== null && error !== false;
13
- /** Renders one of loading / error / empty / children for a content region; agnostic of the fetching library. */
14
- const QueryStateBoundary = ({ isLoading = false, error, isEmpty = false, loadingFallback, emptyFallback, empty, errorTitle, errorDescription, onRetry, isRetrying, minH = "24rem", children, }) => {
15
- if (isLoading)
14
+ /** Renders one of loading / forbidden / error / empty / children for a content region; agnostic of the fetching library. */
15
+ const QueryStateBoundary = ({ isLoading = false, isForbidden = false, forbidden, hasData = false, error, isEmpty = false, loadingFallback, emptyFallback, empty, errorTitle, errorDescription, onRetry, isRetrying, minH = "24rem", children, }) => {
16
+ var _a, _b, _c;
17
+ if (isLoading && !hasData)
16
18
  return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: loadingFallback !== null && loadingFallback !== void 0 ? loadingFallback : (0, jsx_runtime_1.jsx)(DefaultLoading, {}) });
19
+ const forbiddenNow = typeof isForbidden === "function" ? hasError(error) && isForbidden(error) : isForbidden;
20
+ if (forbiddenNow) {
21
+ return ((0, jsx_runtime_1.jsx)(react_1.Box, { role: "status", w: "100%", children: (0, jsx_runtime_1.jsx)(EmptyState_1.default, { colorScheme: "gray", icon: (_a = forbidden === null || forbidden === void 0 ? void 0 : forbidden.icon) !== null && _a !== void 0 ? _a : lucide_react_1.Lock, title: (_b = forbidden === null || forbidden === void 0 ? void 0 : forbidden.title) !== null && _b !== void 0 ? _b : "You don't have access", description: (_c = forbidden === null || forbidden === void 0 ? void 0 : forbidden.description) !== null && _c !== void 0 ? _c : "Ask an administrator to give you access to view this.", action: forbidden === null || forbidden === void 0 ? void 0 : forbidden.action, minH: minH }) }));
22
+ }
17
23
  if (hasError(error)) {
18
24
  const description = typeof errorDescription === "function" ? errorDescription(error) : errorDescription;
19
25
  return ((0, jsx_runtime_1.jsx)(ErrorState_1.default, { title: errorTitle, description: description, onRetry: onRetry, isRetrying: isRetrying, minH: minH }));
@@ -20,10 +20,27 @@ export interface ErrorStateProps {
20
20
  size?: EmptyStateProps["size"];
21
21
  minH?: EmptyStateProps["minH"];
22
22
  }
23
- /** Picks loading → error → empty → children; `children` may be a function so data is read only when ready. */
23
+ /** Copy for the no-access panel; each field falls back to a generic default. */
24
+ export interface QueryStateForbiddenProps {
25
+ /** Defaults to "You don't have access". */
26
+ title?: string;
27
+ /** Defaults to a line asking the reader to request access. */
28
+ description?: string;
29
+ /** Defaults to a lock icon. */
30
+ icon?: ElementType;
31
+ /** Node(s) under the description, e.g. a "Request access" button. */
32
+ action?: ReactNode;
33
+ }
34
+ /** Picks loading → forbidden → error → empty → children; `children` may be a function so data is read only when ready. */
24
35
  export interface QueryStateBoundaryProps {
25
- /** Checked first — wins over error and empty. */
36
+ /** Checked first — wins over forbidden, error and empty — unless `hasData` is true. */
26
37
  isLoading?: boolean;
38
+ /** Shown after loading, before error (e.g. HTTP 403); a function is only called when `error` is set. */
39
+ isForbidden?: boolean | ((error: unknown) => boolean);
40
+ /** Copy and action for the no-access panel (`role="status"`, never error-tinted). */
41
+ forbidden?: QueryStateForbiddenProps;
42
+ /** True keeps children on screen during a refetch instead of the loading state. Default false. */
43
+ hasData?: boolean;
27
44
  /** Anything except undefined, null or false shows the error state — so 0 and "" count. */
28
45
  error?: unknown;
29
46
  /** Checked only after loading and error are ruled out. */