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

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 (123) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/COMPONENT-GOTCHAS.md +88 -2
  3. package/DESIGN-GUIDE.md +26 -3
  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/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  8. package/dist/Components/Breadcrumbs/Breadcrumbs.js +33 -10
  9. package/dist/Components/Breadcrumbs/BreadcrumbsProps.d.ts +16 -2
  10. package/dist/Components/Card/Card.d.ts +3 -1
  11. package/dist/Components/Card/Card.js +12 -2
  12. package/dist/Components/Card/CardProps.d.ts +5 -1
  13. package/dist/Components/Editor/Editor.js +50 -2
  14. package/dist/Components/Editor/EditorFieldBar.d.ts +15 -0
  15. package/dist/Components/Editor/EditorFieldBar.js +19 -0
  16. package/dist/Components/Editor/EditorProps.d.ts +74 -1
  17. package/dist/Components/Editor/MakeDynamicDialog.d.ts +12 -0
  18. package/dist/Components/Editor/MakeDynamicDialog.js +59 -0
  19. package/dist/Components/Editor/editorLabels.d.ts +4 -0
  20. package/dist/Components/Editor/editorLabels.js +24 -0
  21. package/dist/Components/Editor/editorTokenStyles.d.ts +28 -0
  22. package/dist/Components/Editor/editorTokenStyles.js +30 -0
  23. package/dist/Components/Editor/editorTokens.d.ts +26 -0
  24. package/dist/Components/Editor/editorTokens.js +134 -0
  25. package/dist/Components/Editor/useEditorBridge.d.ts +40 -0
  26. package/dist/Components/Editor/useEditorBridge.js +141 -0
  27. package/dist/Components/Kbd/Kbd.d.ts +6 -0
  28. package/dist/Components/Kbd/Kbd.js +33 -0
  29. package/dist/Components/Kbd/KbdProps.d.ts +17 -0
  30. package/dist/Components/Kbd/KbdProps.js +2 -0
  31. package/dist/Components/LauncherTrigger/LauncherTrigger.d.ts +4 -0
  32. package/dist/Components/LauncherTrigger/LauncherTrigger.js +41 -0
  33. package/dist/Components/LauncherTrigger/LauncherTriggerProps.d.ts +16 -0
  34. package/dist/Components/LauncherTrigger/LauncherTriggerProps.js +2 -0
  35. package/dist/Components/NavLauncher/NavLauncher.d.ts +3 -0
  36. package/dist/Components/NavLauncher/NavLauncher.js +395 -0
  37. package/dist/Components/NavLauncher/NavLauncherProps.d.ts +187 -0
  38. package/dist/Components/NavLauncher/NavLauncherProps.js +2 -0
  39. package/dist/Components/NavLauncher/NewTabLink.d.ts +3 -0
  40. package/dist/Components/NavLauncher/NewTabLink.js +14 -0
  41. package/dist/Components/NavLauncher/PinToggle.d.ts +3 -0
  42. package/dist/Components/NavLauncher/PinToggle.js +21 -0
  43. package/dist/Components/NavLauncher/launcherParts.d.ts +93 -0
  44. package/dist/Components/NavLauncher/launcherParts.js +130 -0
  45. package/dist/Components/NavLauncher/match.d.ts +53 -0
  46. package/dist/Components/NavLauncher/match.js +178 -0
  47. package/dist/Components/NavLauncher/revealStyles.d.ts +4 -0
  48. package/dist/Components/NavLauncher/revealStyles.js +19 -0
  49. package/dist/Components/NavigationBar/NavigationBar.d.ts +1 -1
  50. package/dist/Components/NavigationBar/NavigationBar.js +2 -2
  51. package/dist/Components/NavigationBar/NavigationBarProps.d.ts +2 -0
  52. package/dist/Components/PageHeader/PageHeader.d.ts +1 -1
  53. package/dist/Components/PageHeader/PageHeader.js +9 -2
  54. package/dist/Components/PageHeader/PageHeaderProps.d.ts +8 -0
  55. package/dist/Components/PdfViewer/PdfViewer.d.ts +21 -4
  56. package/dist/Components/PdfViewer/PdfViewer.js +124 -3
  57. package/dist/Components/Search/Search.js +2 -1
  58. package/dist/Components/SideBar/SecondaryBar.js +4 -3
  59. package/dist/Components/SideBar/SideBar.d.ts +1 -1
  60. package/dist/Components/SideBar/SideBar.js +30 -9
  61. package/dist/Components/SideBar/SideBarProps.d.ts +32 -0
  62. package/dist/Components/SideBar/components/MenuItemBox.d.ts +6 -0
  63. package/dist/Components/SideBar/components/MenuItemBox.js +8 -4
  64. package/dist/Components/SideBar/components/MenuPopoverContent.js +3 -2
  65. package/dist/Components/SideBar/components/OtherApps.js +2 -1
  66. package/dist/Components/SideBar/components/PinnedSection.d.ts +17 -0
  67. package/dist/Components/SideBar/components/PinnedSection.js +98 -0
  68. package/dist/Components/SideBar/sidebarFocus.d.ts +23 -0
  69. package/dist/Components/SideBar/sidebarFocus.js +20 -0
  70. package/dist/Components/StageProgress/StageProgress.js +2 -2
  71. package/dist/Components/StageProgress/StageProgressProps.d.ts +2 -0
  72. package/dist/Components/StageProgress/StepperStage.js +5 -2
  73. package/dist/Components/WizardDialog/WizardDialog.d.ts +9 -0
  74. package/dist/Components/WizardDialog/WizardDialog.js +102 -0
  75. package/dist/Components/WizardDialog/WizardDialogProps.d.ts +48 -0
  76. package/dist/Components/WizardDialog/WizardDialogProps.js +2 -0
  77. package/dist/Components/WizardDialog/useWizardFlow.d.ts +22 -0
  78. package/dist/Components/WizardDialog/useWizardFlow.js +47 -0
  79. package/dist/Components/WizardDialog/wizardSteps.d.ts +31 -0
  80. package/dist/Components/WizardDialog/wizardSteps.js +40 -0
  81. package/dist/esm/Components/AppSwitcher/AppSwitcher.js +2 -1
  82. package/dist/esm/Components/AppSwitcher/AppSwitcherProps.js +5 -3
  83. package/dist/esm/Components/Breadcrumbs/Breadcrumbs.js +35 -12
  84. package/dist/esm/Components/Card/Card.js +12 -2
  85. package/dist/esm/Components/Editor/Editor.js +48 -3
  86. package/dist/esm/Components/Editor/EditorFieldBar.js +13 -0
  87. package/dist/esm/Components/Editor/MakeDynamicDialog.js +20 -0
  88. package/dist/esm/Components/Editor/editorLabels.js +20 -0
  89. package/dist/esm/Components/Editor/editorTokenStyles.js +25 -0
  90. package/dist/esm/Components/Editor/editorTokens.js +121 -0
  91. package/dist/esm/Components/Editor/useEditorBridge.js +138 -0
  92. package/dist/esm/Components/Kbd/Kbd.js +28 -0
  93. package/dist/esm/Components/Kbd/KbdProps.js +1 -0
  94. package/dist/esm/Components/LauncherTrigger/LauncherTrigger.js +37 -0
  95. package/dist/esm/Components/LauncherTrigger/LauncherTriggerProps.js +1 -0
  96. package/dist/esm/Components/NavLauncher/NavLauncher.js +356 -0
  97. package/dist/esm/Components/NavLauncher/NavLauncherProps.js +1 -0
  98. package/dist/esm/Components/NavLauncher/NewTabLink.js +11 -0
  99. package/dist/esm/Components/NavLauncher/PinToggle.js +18 -0
  100. package/dist/esm/Components/NavLauncher/launcherParts.js +110 -0
  101. package/dist/esm/Components/NavLauncher/match.js +172 -0
  102. package/dist/esm/Components/NavLauncher/revealStyles.js +15 -0
  103. package/dist/esm/Components/NavigationBar/NavigationBar.js +3 -3
  104. package/dist/esm/Components/PageHeader/PageHeader.js +9 -2
  105. package/dist/esm/Components/PdfViewer/PdfViewer.js +123 -2
  106. package/dist/esm/Components/Search/Search.js +3 -2
  107. package/dist/esm/Components/SideBar/SecondaryBar.js +4 -3
  108. package/dist/esm/Components/SideBar/SideBar.js +31 -10
  109. package/dist/esm/Components/SideBar/components/MenuItemBox.js +4 -2
  110. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +3 -2
  111. package/dist/esm/Components/SideBar/components/OtherApps.js +2 -1
  112. package/dist/esm/Components/SideBar/components/PinnedSection.js +92 -0
  113. package/dist/esm/Components/SideBar/sidebarFocus.js +15 -0
  114. package/dist/esm/Components/StageProgress/StageProgress.js +2 -2
  115. package/dist/esm/Components/StageProgress/StepperStage.js +5 -2
  116. package/dist/esm/Components/WizardDialog/WizardDialog.js +58 -0
  117. package/dist/esm/Components/WizardDialog/WizardDialogProps.js +1 -0
  118. package/dist/esm/Components/WizardDialog/useWizardFlow.js +44 -0
  119. package/dist/esm/Components/WizardDialog/wizardSteps.js +35 -0
  120. package/dist/esm/index.js +7 -0
  121. package/dist/index.d.ts +19 -4
  122. package/dist/index.js +21 -1
  123. package/package.json +1 -1
@@ -12,13 +12,14 @@ import { scaleFor } from "../../../Theme/chakra/paletteFromTheme.js";
12
12
  import TruncatedTextWithTooltip from "./TextTruncation.js";
13
13
  import { sanitizeId } from "../sidebarId.js";
14
14
  import ToolTip from "../../ToolTip/ToolTip.js";
15
+ import { sidebarFocusStyles } from "../sidebarFocus.js";
15
16
  import { SIDEBAR_ROW } from "../sidebarScale.js";
16
17
  /**
17
18
  * These rows are real `<a href>`s now, so the browser's own gestures have to keep working —
18
19
  * cmd/ctrl-click for a new tab, shift for a window, middle-click. Only a plain left click is
19
20
  * routed through the in-app handler.
20
21
  */
21
- const isBrowserNavigationGesture = (e) => e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0;
22
+ export const isBrowserNavigationGesture = (e) => e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0;
22
23
  const MenuItemBox = ({ menu, activeMenu, toggle, handleClick, isOpen, onToggle, overlay = false, }) => {
23
24
  var _a, _b, _c, _d, _e;
24
25
  const theme = useCustomTheme();
@@ -86,6 +87,7 @@ const MenuItemBox = ({ menu, activeMenu, toggle, handleClick, isOpen, onToggle,
86
87
  cursor: isBlocked ? "not-allowed" : "pointer",
87
88
  opacity: isBlocked ? 0.6 : 1,
88
89
  transition: "background 0.12s",
90
+ sx: sidebarFocusStyles(theme.colors),
89
91
  };
90
92
  const buttonContent = (_jsxs(Flex, { align: "center", gap: "9px", justify: toggle ? "center" : "space-between", w: "100%", children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", children: [_jsxs(Box, { position: "relative", display: "flex", alignItems: "center", children: [_jsx(Icon, { as: icon, fontSize: "md", verticalAlign: "middle", color: isAnyActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isAnyActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" }), toggle && (badgeValue != null || hasSubmenuBadge) && (_jsx(Box, { position: "absolute", top: "0", right: "0", w: "0.375rem", h: "0.375rem", borderRadius: "full", bg: theme.colors.sidebar.semanticText.error }))] }), !toggle && (_jsx(TruncatedTextWithTooltip
91
93
  // open={isOpen}
@@ -138,7 +140,7 @@ const MenuItemBox = ({ menu, activeMenu, toggle, handleClick, isOpen, onToggle,
138
140
  e.preventDefault();
139
141
  if (!isSubBlocked)
140
142
  handleClick === null || handleClick === void 0 ? void 0 : handleClick(sub);
141
- }, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, transition: "background 0.12s", children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", flex: "1", children: [sub.icon ? (_jsx(Icon, { as: sub.icon, fontSize: SIDEBAR_ROW.iconSize, flexShrink: 0, color: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" })) : (_jsx(Box, { w: "5px", h: "5px", borderRadius: "full", flexShrink: 0, bg: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { bg: theme.colors.white }, transition: "background 0.12s" })), _jsx(TruncatedTextWithTooltip, { fontSize: SIDEBAR_ROW.fontSize, fontWeight: isSubActive ? 600 : 500, lineHeight: "1", color: isSubActive ? activeAccent.label : theme.colors.sidebar.mutedLabel, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, children: sub.title })] }), sub.locked ? (_jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon })) : (() => {
143
+ }, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, transition: "background 0.12s", sx: sidebarFocusStyles(theme.colors), children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", flex: "1", children: [sub.icon ? (_jsx(Icon, { as: sub.icon, fontSize: SIDEBAR_ROW.iconSize, flexShrink: 0, color: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" })) : (_jsx(Box, { w: "5px", h: "5px", borderRadius: "full", flexShrink: 0, bg: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { bg: theme.colors.white }, transition: "background 0.12s" })), _jsx(TruncatedTextWithTooltip, { fontSize: SIDEBAR_ROW.fontSize, fontWeight: isSubActive ? 600 : 500, lineHeight: "1", color: isSubActive ? activeAccent.label : theme.colors.sidebar.mutedLabel, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, children: sub.title })] }), sub.locked ? (_jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon })) : (() => {
142
144
  var _a, _b, _c, _d;
143
145
  const subCfg = typeof sub.badge === "object" && sub.badge !== null
144
146
  ? sub.badge
@@ -9,6 +9,7 @@ import { sidebarRowPeak } from "../../../Theme/tokens/builders/sidebarAccent.js"
9
9
  import { scaleFor } from "../../../Theme/chakra/paletteFromTheme.js";
10
10
  import TruncatedTextWithTooltip from "./TextTruncation.js";
11
11
  import ToolTip from "../../ToolTip/ToolTip.js";
12
+ import { sidebarFocusStyles } from "../sidebarFocus.js";
12
13
  import { SIDEBAR_ROW } from "../sidebarScale.js";
13
14
  const MenuPopoverContent = ({ menu, handleMenuClick, activeMenu, }) => {
14
15
  var _a;
@@ -26,7 +27,7 @@ const MenuPopoverContent = ({ menu, handleMenuClick, activeMenu, }) => {
26
27
  if (!isBlocked)
27
28
  handleMenuClick === null || handleMenuClick === void 0 ? void 0 : handleMenuClick(menu);
28
29
  }
29
- }, cursor: !hasSubMenu ? (isBlocked ? "not-allowed" : "pointer") : "default", "aria-disabled": !hasSubMenu && isBlocked ? true : undefined, children: [_jsx(Icon, { as: icon, fontSize: "md", flexShrink: 0, color: !hasSubMenu && isParentActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon }), _jsx(TruncatedTextWithTooltip, { fontWeight: 600, fontSize: SIDEBAR_ROW.fontSize, flex: "1", color: theme.colors.white, children: title }), (() => {
30
+ }, cursor: !hasSubMenu ? (isBlocked ? "not-allowed" : "pointer") : "default", "aria-disabled": !hasSubMenu && isBlocked ? true : undefined, sx: hasSubMenu ? undefined : sidebarFocusStyles(theme.colors, theme.colors.sidebar.elevated), children: [_jsx(Icon, { as: icon, fontSize: "md", flexShrink: 0, color: !hasSubMenu && isParentActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon }), _jsx(TruncatedTextWithTooltip, { fontWeight: 600, fontSize: SIDEBAR_ROW.fontSize, flex: "1", color: theme.colors.white, children: title }), (() => {
30
31
  var _a, _b, _c, _d;
31
32
  const cfg = typeof badge === "object" && badge !== null
32
33
  ? badge
@@ -50,7 +51,7 @@ const MenuPopoverContent = ({ menu, handleMenuClick, activeMenu, }) => {
50
51
  }, px: 2, h: SIDEBAR_ROW.subHeight, mb: "2px", borderRadius: "lg", align: "center", justify: "space-between", gap: 2, borderLeft: "2px solid", borderLeftColor: isSubActive ? theme.colors.sidebar.activeIcon : "transparent", bg: isSubActive ? "whiteAlpha.300" : "transparent", _hover: {
51
52
  bg: isSubBlocked ? "transparent" : isSubActive ? "whiteAlpha.400" : "whiteAlpha.200",
52
53
  cursor: !isSubBlocked ? "pointer" : "not-allowed",
53
- }, opacity: isSubBlocked ? 0.5 : 1, pointerEvents: isSubBlocked ? "none" : "auto", transition: "background 0.12s", children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", flex: "1", children: [sub.icon ? (_jsx(Icon, { as: sub.icon, fontSize: SIDEBAR_ROW.iconSize, flexShrink: 0, color: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" })) : (_jsx(Box, { w: "5px", h: "5px", borderRadius: "full", flexShrink: 0, bg: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { bg: theme.colors.white }, transition: "background 0.12s" })), _jsx(TruncatedTextWithTooltip, { fontSize: SIDEBAR_ROW.fontSize, fontWeight: isSubActive ? 600 : 500, flex: 1, color: isSubActive ? activeAccent.label : theme.colors.white, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, children: sub.title })] }), sub.locked ? (sub.lockedReason ? (_jsx(ToolTip, { label: sub.lockedReason, placement: "top", children: _jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon }) })) : (_jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon }))) : (() => {
54
+ }, opacity: isSubBlocked ? 0.5 : 1, pointerEvents: isSubBlocked ? "none" : "auto", transition: "background 0.12s", sx: sidebarFocusStyles(theme.colors, theme.colors.sidebar.elevated), children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", flex: "1", children: [sub.icon ? (_jsx(Icon, { as: sub.icon, fontSize: SIDEBAR_ROW.iconSize, flexShrink: 0, color: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" })) : (_jsx(Box, { w: "5px", h: "5px", borderRadius: "full", flexShrink: 0, bg: isSubActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isSubActive ? undefined : { bg: theme.colors.white }, transition: "background 0.12s" })), _jsx(TruncatedTextWithTooltip, { fontSize: SIDEBAR_ROW.fontSize, fontWeight: isSubActive ? 600 : 500, flex: 1, color: isSubActive ? activeAccent.label : theme.colors.white, _groupHover: isSubActive ? undefined : { color: theme.colors.white }, children: sub.title })] }), sub.locked ? (sub.lockedReason ? (_jsx(ToolTip, { label: sub.lockedReason, placement: "top", children: _jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon }) })) : (_jsx(Icon, { as: LockKeyhole, fontSize: "md", color: theme.colors.sidebar.mutedIcon }))) : (() => {
54
55
  var _a, _b, _c, _d;
55
56
  const cfg = typeof sub.badge === "object" && sub.badge !== null
56
57
  ? sub.badge
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Box, Flex, Text, Popover, PopoverTrigger, PopoverContent, PopoverBody, Portal, } from "@chakra-ui/react";
3
3
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
4
+ import { sidebarFocusStyles } from "../sidebarFocus.js";
4
5
  const OtherApps = ({ toggle, otherApps }) => {
5
6
  const theme = useCustomTheme();
6
7
  if (!otherApps || otherApps.length === 0)
@@ -10,7 +11,7 @@ const OtherApps = ({ toggle, otherApps }) => {
10
11
  return (_jsx(Box, { display: "flex", alignItems: "center", justifyContent: "center", color: theme.colors.sidebar.mutedIcon, fontSize: "15px", flexShrink: 0, children: (_a = app.icon) !== null && _a !== void 0 ? _a : (_jsx(Box, { w: "0.5rem", h: "0.5rem", borderRadius: "full", bg: app.color, boxShadow: `0 0 5px ${app.color}`, flexShrink: 0 })) }));
11
12
  };
12
13
  // Grid cell: icon on top, truncated label below (label hidden when collapsed).
13
- const appCell = (app) => (_jsxs(Flex, { as: "button", type: "button", direction: "column", align: "center", justify: "center", gap: "3px", px: "2px", py: "6px", borderRadius: "lg", cursor: "pointer", border: "none", bg: "transparent", w: "100%", _hover: { backgroundColor: "whiteAlpha.200" }, transition: "background 0.12s", onClick: app.onClick, children: [appIcon(app), !toggle && (_jsx(Text, { fontSize: "9.5px", color: theme.colors.sidebar.mutedLabel, textAlign: "center", maxW: "44px", isTruncated: true, children: app.name }))] }));
14
+ const appCell = (app) => (_jsxs(Flex, { as: "button", type: "button", direction: "column", align: "center", justify: "center", gap: "3px", px: "2px", py: "6px", borderRadius: "lg", cursor: "pointer", border: "none", bg: "transparent", w: "100%", _hover: { backgroundColor: "whiteAlpha.200" }, transition: "background 0.12s", sx: sidebarFocusStyles(theme.colors), onClick: app.onClick, children: [appIcon(app), !toggle && (_jsx(Text, { fontSize: "9.5px", color: theme.colors.sidebar.mutedLabel, textAlign: "center", maxW: "44px", isTruncated: true, children: app.name }))] }));
14
15
  const flyoutBody = (app) => {
15
16
  var _a;
16
17
  return (_jsxs(_Fragment, { children: [_jsxs(Flex, { alignItems: "center", gap: 2, mb: 1, onClick: app.onClick, children: [(_a = app.icon) !== null && _a !== void 0 ? _a : (_jsx(Box, { w: "0.5rem", h: "0.5rem", borderRadius: "full", bg: app.color, boxShadow: `0 0 5px ${app.color}`, flexShrink: 0 })), _jsx(Text, { fontSize: "sm", fontWeight: 700, color: theme.colors.white, children: app.name })] }), app.description && (_jsx(Text, { fontSize: "xs", color: theme.colors.sidebar.mutedLabel, children: app.description }))] }));
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useState } from "react";
3
+ import { Badge, Box, Flex, Icon } from "@chakra-ui/react";
4
+ import { ChevronDown, ChevronUp, PinOff } from "lucide-react";
5
+ import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
6
+ import { sidebarFocusStyles } from "../sidebarFocus.js";
7
+ import { resolveSoftTone } from "../../../Theme/tokens/builders/tone.js";
8
+ import { sidebarRowPeak } from "../../../Theme/tokens/builders/sidebarAccent.js";
9
+ import { scaleFor } from "../../../Theme/chakra/paletteFromTheme.js";
10
+ import { getSidebarActiveAccent } from "../sidebarAccentColors.js";
11
+ import { sanitizeId } from "../sidebarId.js";
12
+ import { SIDEBAR_ROW } from "../sidebarScale.js";
13
+ import ToolTip from "../../ToolTip/ToolTip.js";
14
+ import TruncatedTextWithTooltip from "./TextTruncation.js";
15
+ import { isBrowserNavigationGesture } from "./MenuItemBox.js";
16
+ export const DEFAULT_PINNED_LABEL = "Pinned";
17
+ export const DEFAULT_PINNED_LIMIT = 5;
18
+ const DEFAULT_LABELS = {
19
+ showMore: "Show {count} more",
20
+ showLess: "Show less",
21
+ unpin: "Unpin {title}",
22
+ };
23
+ const UNPIN_SIZE = "24px";
24
+ const LADDER = { hover: "whiteAlpha.200", active: "whiteAlpha.300", activeHover: "whiteAlpha.400" };
25
+ const VISUALLY_HIDDEN = {
26
+ position: "absolute",
27
+ width: "1px",
28
+ height: "1px",
29
+ padding: 0,
30
+ margin: "-1px",
31
+ clip: "rect(0, 0, 0, 0)",
32
+ whiteSpace: "nowrap",
33
+ border: 0,
34
+ };
35
+ const readBadge = (badge) => {
36
+ var _a;
37
+ const cfg = typeof badge === "object" && badge !== null ? badge : null;
38
+ const value = (_a = cfg === null || cfg === void 0 ? void 0 : cfg.count) !== null && _a !== void 0 ? _a : (typeof badge !== "object" ? badge : undefined);
39
+ return { cfg, value };
40
+ };
41
+ const PinnedSection = ({ items, label = DEFAULT_PINNED_LABEL, limit = DEFAULT_PINNED_LIMIT, toggle, overlay, activeId, labels, onItemClick, onUnpin, }) => {
42
+ const theme = useCustomTheme();
43
+ const activeAccent = getSidebarActiveAccent(theme.colors);
44
+ const text = { ...DEFAULT_LABELS, ...labels };
45
+ const headingId = `pinned-${sanitizeId(useId())}`;
46
+ const cap = Math.max(1, limit);
47
+ const rowHeight = overlay ? SIDEBAR_ROW.overlayHeight : SIDEBAR_ROW.height;
48
+ const activeIndex = activeId == null ? -1 : items.findIndex((i) => String(i.id) === String(activeId));
49
+ const [showAll, setShowAll] = useState(activeIndex >= cap);
50
+ useEffect(() => {
51
+ if (activeIndex >= cap)
52
+ setShowAll(true);
53
+ }, [activeIndex, cap]);
54
+ if (items.length === 0)
55
+ return null;
56
+ const hiddenCount = Math.max(0, items.length - cap);
57
+ const visible = showAll ? items : items.slice(0, cap);
58
+ const badgeSurface = sidebarRowPeak(theme.colors.sidebar.background[500]);
59
+ const unpinReplacesBadge = !!onUnpin && !overlay;
60
+ const renderBadge = (badge) => {
61
+ var _a, _b, _c;
62
+ const { cfg, value } = readBadge(badge);
63
+ if (value == null)
64
+ return null;
65
+ const tone = resolveSoftTone(theme.colors, scaleFor(theme.colors, (_a = cfg === null || cfg === void 0 ? void 0 : cfg.color) !== null && _a !== void 0 ? _a : "teal"), badgeSurface);
66
+ return (_jsx(Badge, { bg: tone.bg, color: tone.fg, fontSize: "xs", variant: (_b = cfg === null || cfg === void 0 ? void 0 : cfg.variant) !== null && _b !== void 0 ? _b : "subtle", borderRadius: (_c = cfg === null || cfg === void 0 ? void 0 : cfg.radius) !== null && _c !== void 0 ? _c : "full", ...(unpinReplacesBadge
67
+ ? { _groupHover: { opacity: 0 }, _groupFocusWithin: { opacity: 0 } }
68
+ : {}), children: value }));
69
+ };
70
+ const renderRow = (item) => {
71
+ const isActive = activeIndex >= 0 && String(item.id) === String(activeId);
72
+ const anchor = (_jsx(Box, { as: "a", href: item.url, "data-group": "", "data-pinned-id": String(item.id), "aria-label": toggle ? item.title : undefined, "aria-current": isActive ? "page" : undefined, display: "flex", alignItems: "center", textAlign: "left", textDecoration: "none", w: "100%", h: rowHeight, borderRadius: "lg", pl: "10px", pr: !toggle && onUnpin ? `calc(10px + ${UNPIN_SIZE})` : "10px", fontWeight: "medium", borderLeft: "2px solid", borderLeftColor: isActive ? theme.colors.sidebar.activeIcon : "transparent", backgroundColor: isActive ? LADDER.active : "transparent", color: theme.colors.sidebar.mutedIcon, _hover: { backgroundColor: isActive ? LADDER.activeHover : LADDER.hover }, cursor: "pointer", transition: "background 0.12s", sx: sidebarFocusStyles(theme.colors), onClick: (e) => {
73
+ if (item.url && isBrowserNavigationGesture(e))
74
+ return;
75
+ e.preventDefault();
76
+ onItemClick(item);
77
+ }, children: _jsxs(Flex, { align: "center", gap: "9px", justify: toggle ? "center" : "space-between", w: "100%", children: [_jsxs(Flex, { align: "center", gap: "9px", overflow: "hidden", flex: toggle ? undefined : 1, minW: 0, children: [_jsxs(Box, { position: "relative", display: "flex", alignItems: "center", children: [_jsx(Icon, { as: item.icon, fontSize: "md", color: isActive ? activeAccent.icon : theme.colors.sidebar.mutedIcon, _groupHover: isActive ? undefined : { color: theme.colors.white }, transition: "color 0.12s" }), toggle && readBadge(item.badge).value != null && (_jsx(Box, { position: "absolute", top: "0", right: "0", w: "0.375rem", h: "0.375rem", borderRadius: "full", bg: theme.colors.sidebar.semanticText.error }))] }), !toggle && (_jsx(TruncatedTextWithTooltip, { fontSize: SIDEBAR_ROW.fontSize, lineHeight: "1", flex: "1", color: isActive ? activeAccent.label : theme.colors.white, fontWeight: isActive ? 600 : 500, _groupHover: isActive ? undefined : { color: theme.colors.white }, children: item.title }))] }), !toggle && renderBadge(item.badge)] }) }));
78
+ return (_jsxs(Box, { as: "li", listStyleType: "none", position: "relative", "data-group": "", children: [toggle ? (_jsx(ToolTip, { label: item.title, placement: "right", children: anchor })) : (anchor), onUnpin && !toggle && (_jsx(Box, { as: "button", type: "button", "aria-label": text.unpin.replace("{title}", item.title), onClick: () => onUnpin(item), position: "absolute", top: "50%", right: "6px", transform: "translateY(-50%)", w: UNPIN_SIZE, h: UNPIN_SIZE, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "lg", border: "none", bg: "transparent", cursor: "pointer", color: theme.colors.sidebar.mutedIcon, opacity: overlay ? 1 : 0, _groupHover: { opacity: 1 }, _groupFocusWithin: { opacity: 1 }, _hover: {
79
+ bg: LADDER.active,
80
+ color: theme.colors.white,
81
+ }, transition: "opacity 0.12s, background 0.12s", sx: sidebarFocusStyles(theme.colors), children: _jsx(Icon, { as: PinOff, fontSize: "sm" }) }))] }, String(item.id)));
82
+ };
83
+ const disclosureLabel = showAll
84
+ ? text.showLess
85
+ : text.showMore.replace("{count}", String(hiddenCount));
86
+ const disclosureButton = (_jsxs(Box, { as: "button", type: "button", "aria-expanded": showAll, "aria-label": toggle ? disclosureLabel : undefined, onClick: () => setShowAll((v) => !v), display: "flex", alignItems: "center", justifyContent: toggle ? "center" : "flex-start", gap: "9px", w: "100%", h: rowHeight, px: "10px", borderRadius: "lg", border: "none", borderLeft: "2px solid transparent", bg: "transparent", cursor: "pointer", color: theme.colors.sidebar.mutedLabel, fontSize: SIDEBAR_ROW.fontSize, fontWeight: "medium", _hover: {
87
+ backgroundColor: LADDER.hover,
88
+ color: theme.colors.white,
89
+ }, transition: "background 0.12s", sx: sidebarFocusStyles(theme.colors), children: [_jsx(Icon, { as: showAll ? ChevronUp : ChevronDown, fontSize: "md", flexShrink: 0 }), !toggle && _jsx("span", { children: disclosureLabel })] }));
90
+ return (_jsxs(Box, { mb: toggle ? "5px" : "3px", "data-testid": "sidebar-pinned", children: [_jsx(Box, { id: headingId, as: "h2", px: "10px", pt: overlay ? "6px" : "10px", pb: "3px", fontSize: "9.5px", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.1em", color: theme.colors.sidebar.mutedLabel, whiteSpace: "nowrap", overflow: "hidden", sx: toggle ? VISUALLY_HIDDEN : undefined, children: label }), _jsxs(Box, { as: "ul", "aria-labelledby": headingId, display: "flex", flexDirection: "column", gap: "2px", m: 0, p: 0, children: [visible.map(renderRow), hiddenCount > 0 && (_jsx(Box, { as: "li", listStyleType: "none", children: toggle ? (_jsx(ToolTip, { label: disclosureLabel, placement: "right", children: disclosureButton })) : (disclosureButton) }))] }), _jsx(Box, { h: "1px", bg: theme.colors.sidebar.divider, mx: 2, mt: overlay ? "6px" : "8px", mb: overlay ? "3px" : "5px" })] }));
91
+ };
92
+ export default PinnedSection;
@@ -0,0 +1,15 @@
1
+ import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
2
+ import { AA_NON_TEXT, liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
3
+ const cache = new Map();
4
+ /** The ring is derived for the canvas; the rail is near-black in both modes, so it is re-settled against the rail. */
5
+ export const sidebarFocusRing = (colors, surface = colors.sidebar.background[500]) => {
6
+ const key = `${colors.focusRing.ring}|${surface}`;
7
+ let tokens = cache.get(key);
8
+ if (!tokens) {
9
+ tokens = { ring: liftToContrast(colors.focusRing.ring, surface, AA_NON_TEXT), halo: surface };
10
+ cache.set(key, tokens);
11
+ }
12
+ return { focusRing: tokens };
13
+ };
14
+ /** `focusVisibleStyles` for a control sitting on the rail (or on `surface`, e.g. the flyout). */
15
+ export const sidebarFocusStyles = (colors, surface) => focusVisibleStyles(sidebarFocusRing(colors, surface));
@@ -27,12 +27,12 @@ const StageProgress = ({ stages, variant = "chevron", value, onChange, size = "m
27
27
  return "upcoming";
28
28
  };
29
29
  const total = stages.length;
30
- return (_jsx(Box, { display: "flex", alignItems: variant === "stepper" ? "flex-start" : "stretch", gap: gapFor[variant], overflowX: "auto", p: "0.1rem", sx: scrollbarStyles(theme.colors, "overlay"), children: stages.map((stage, index) => {
30
+ return (_jsx(Box, { as: variant === "stepper" ? "ol" : undefined, m: variant === "stepper" ? 0 : undefined, listStyleType: variant === "stepper" ? "none" : undefined, display: "flex", alignItems: variant === "stepper" ? "flex-start" : "stretch", gap: gapFor[variant], overflowX: "auto", p: "0.1rem", sx: scrollbarStyles(theme.colors, "overlay"), children: stages.map((stage, index) => {
31
31
  var _a;
32
32
  const state = stateFor(index);
33
33
  const stageDisabled = (_a = stage.isDisabled) !== null && _a !== void 0 ? _a : stage.disabled;
34
34
  if (variant === "stepper") {
35
- return (_jsx(StepperStage, { label: stage.label, number: index + 1, state: state, size: size, colorScheme: colorScheme, isReadOnly: isReadOnly, isDisabled: stageDisabled, showCheck: showCheck, isFirst: index === 0, isLast: index === total - 1, leftDone: activeIndex > -1 && index <= activeIndex, rightDone: activeIndex > -1 && index < activeIndex, scrollIntoViewWhenActive: scrollActiveIntoView, onClick: () => onChange === null || onChange === void 0 ? void 0 : onChange(stage.id, stage, index) }, stage.id));
35
+ return (_jsx(StepperStage, { label: stage.label, number: index + 1, state: state, size: size, colorScheme: colorScheme, isReadOnly: isReadOnly, isDisabled: stageDisabled, showCheck: showCheck, isFirst: index === 0, isLast: index === total - 1, leftDone: activeIndex > -1 && index <= activeIndex, rightDone: activeIndex > -1 && index < activeIndex, scrollIntoViewWhenActive: scrollActiveIntoView, asListItem: true, onClick: () => onChange === null || onChange === void 0 ? void 0 : onChange(stage.id, stage, index) }, stage.id));
36
36
  }
37
37
  return (_jsx(StageItem, { label: stage.label, index: index, total: total, state: state, variant: variant, size: size, colorScheme: colorScheme, isReadOnly: isReadOnly, isDisabled: stageDisabled, showCheck: showCheck, minWidth: minStageWidth, scrollIntoViewWhenActive: scrollActiveIntoView, tooltipThreshold: tooltipThreshold, onClick: () => onChange === null || onChange === void 0 ? void 0 : onChange(stage.id, stage, index) }, stage.id));
38
38
  }) }));
@@ -11,7 +11,7 @@ const sizeMap = {
11
11
  md: { circle: "30px", font: "0.8rem", label: "0.8rem", icon: 14, minW: "104px" },
12
12
  lg: { circle: "38px", font: "0.95rem", label: "0.9rem", icon: 16, minW: "124px" },
13
13
  };
14
- const StepperStage = ({ label, number, state, size = "md", colorScheme = "primary", onClick, isReadOnly = false, isDisabled, disabled: legacyDisabled = false, showCheck = true, isFirst, isLast, leftDone, rightDone, scrollIntoViewWhenActive = true, }) => {
14
+ const StepperStage = ({ label, number, state, size = "md", colorScheme = "primary", onClick, isReadOnly = false, isDisabled, disabled: legacyDisabled = false, showCheck = true, isFirst, isLast, leftDone, rightDone, scrollIntoViewWhenActive = true, asListItem = false, }) => {
15
15
  const disabled = isDisabled !== null && isDisabled !== void 0 ? isDisabled : legacyDisabled;
16
16
  const theme = useCustomTheme();
17
17
  const palette = resolveStagePalette(theme, colorScheme);
@@ -33,10 +33,13 @@ const StepperStage = ({ label, number, state, size = "md", colorScheme = "primar
33
33
  const circleColor = filled ? palette.onStrong : palette.mutedText;
34
34
  const circleBorder = filled ? palette.strong : palette.muted;
35
35
  const line = (done, hidden) => (_jsx(Box, { flex: "1", height: "2px", bg: done ? palette.strong : palette.muted, visibility: hidden ? "hidden" : "visible", transition: "background 0.18s ease" }));
36
- return (_jsxs(Flex, { ref: ref, direction: "column", align: "center", flex: "1", minWidth: s.minW, flexShrink: 0, as: (interactive ? "button" : "div"), type: interactive ? "button" : undefined, "data-group": "", "aria-disabled": disabled ? true : undefined, border: "none", bg: "transparent", cursor: interactive ? "pointer" : "default", opacity: disabled ? 0.55 : 1, onClick: interactive ? onClick : undefined, borderRadius: "lg", sx: interactive ? focusVisibleStyles(theme.colors) : undefined, children: [_jsxs(Flex, { align: "center", width: "100%", children: [line(leftDone, isFirst), _jsx(Flex, { align: "center", justify: "center", boxSize: s.circle, borderRadius: "full", flexShrink: 0, bg: circleBg, color: circleColor, border: "2px solid", borderColor: circleBorder, fontSize: s.font, fontWeight: 600, transition: transitionFor(["background-color", "border-color", "color", "box-shadow"]), "aria-current": state === "active" ? "step" : undefined, sx: state === "active"
36
+ const node = (_jsxs(Flex, { ref: ref, direction: "column", align: "center", flex: "1", minWidth: s.minW, flexShrink: 0, as: (interactive ? "button" : "div"), type: interactive ? "button" : undefined, "data-group": "", "aria-disabled": disabled ? true : undefined, border: "none", bg: "transparent", cursor: interactive ? "pointer" : "default", opacity: disabled ? 0.55 : 1, onClick: interactive ? onClick : undefined, borderRadius: "lg", sx: interactive ? focusVisibleStyles(theme.colors) : undefined, children: [_jsxs(Flex, { align: "center", width: "100%", children: [line(leftDone, isFirst), _jsx(Flex, { align: "center", justify: "center", boxSize: s.circle, borderRadius: "full", flexShrink: 0, bg: circleBg, color: circleColor, border: "2px solid", borderColor: circleBorder, fontSize: s.font, fontWeight: 600, transition: transitionFor(["background-color", "border-color", "color", "box-shadow"]), "aria-current": state === "active" ? "step" : undefined, sx: state === "active"
37
37
  ? { boxShadow: `0 0 0 4px ${palette.soft}` }
38
38
  : undefined, _groupHover: interactive
39
39
  ? { borderColor: palette.strong, bg: palette.strong, color: palette.onStrong }
40
40
  : undefined, children: showCheck && state === "completed" ? _jsx(Check, { size: s.icon }) : number }), line(rightDone, isLast)] }), _jsx(Text, { mt: 2, px: 1, borderRadius: "sm", fontSize: s.label, fontWeight: state === "active" ? 600 : 500, color: state === "upcoming" ? palette.mutedText : palette.softText, textAlign: "center", noOfLines: 2, transition: "background 0.18s ease, color 0.18s ease", _groupHover: interactive ? { bg: palette.strong, color: palette.onStrong } : undefined, children: label })] }));
41
+ if (!asListItem)
42
+ return node;
43
+ return (_jsx(Box, { as: "li", display: "flex", flex: "1", minWidth: s.minW, flexShrink: 0, listStyleType: "none", children: node }));
41
44
  };
42
45
  export default StepperStage;
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ import { Alert, AlertDescription, AlertIcon, AlertTitle, Box, Flex, Heading, ListItem, Text, UnorderedList, } from "@chakra-ui/react";
4
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ import Modal, { ModalBody, ModalFooter } from "../Modal/Modal.js";
6
+ import Button from "../Button/Button.js";
7
+ import StageProgress from "../StageProgress/StageProgress.js";
8
+ import DescriptionList from "../DescriptionList/DescriptionList.js";
9
+ import { useWizardFlow } from "./useWizardFlow.js";
10
+ export { wizardTransition, firstInvalidStep, INITIAL_WIZARD_STATE } from "./wizardSteps.js";
11
+ const DEFAULT_LABELS = {
12
+ back: "Back",
13
+ next: "Continue",
14
+ finish: "Finish",
15
+ cancel: "Cancel",
16
+ stepOf: (current, total) => `Step ${current} of ${total}`,
17
+ fixErrors: "Fix the following to continue",
18
+ review: "Review",
19
+ };
20
+ const WizardBody = ({ flow, steps, labels, testId }) => {
21
+ const { colors } = useCustomTheme();
22
+ const headingRef = useRef(null);
23
+ const previousStep = useRef(flow.step.id);
24
+ const reviewed = steps.filter((candidate) => candidate.summary !== undefined);
25
+ useEffect(() => {
26
+ var _a;
27
+ if (previousStep.current === flow.step.id)
28
+ return;
29
+ previousStep.current = flow.step.id;
30
+ (_a = headingRef.current) === null || _a === void 0 ? void 0 : _a.focus();
31
+ }, [flow.step.id]);
32
+ return (_jsxs(Flex, { direction: "column", gap: 5, "data-testid": testId, "data-step": flow.step.id, children: [_jsx(StageProgress, { variant: "stepper", size: "sm", showCheck: true, stages: steps.map((candidate, index) => ({
33
+ id: candidate.id,
34
+ label: candidate.label,
35
+ isDisabled: index > flow.furthest,
36
+ })), value: flow.step.id, onChange: (_id, _stage, index) => flow.goto(index) }), _jsxs(Box, { children: [_jsx(Text, { fontSize: "xs", color: colors.textMuted, children: labels.stepOf(flow.index + 1, steps.length) }), _jsx(Heading, { ref: headingRef, tabIndex: -1, as: "h3", fontSize: "md", fontWeight: 600, color: colors.header[900], _focus: { outline: "none" }, children: flow.step.label })] }), flow.errors.length ? (_jsxs(Alert, { status: "error", variant: "subtle", borderRadius: "md", alignItems: "flex-start", role: "alert", "data-testid": "wizard-errors", children: [_jsx(AlertIcon, {}), _jsxs(Box, { children: [_jsx(AlertTitle, { fontSize: "sm", children: labels.fixErrors }), _jsx(AlertDescription, { fontSize: "sm", children: _jsx(UnorderedList, { mt: 1, children: flow.errors.map((message) => (_jsx(ListItem, { children: message }, message))) }) })] })] })) : null, _jsx(Box, { children: flow.step.content }), flow.isLast && reviewed.length ? (_jsxs(Box, { "data-testid": "wizard-review", children: [_jsx(Heading, { as: "h4", fontSize: "sm", fontWeight: 600, mb: 2, color: colors.header[900], children: labels.review }), _jsx(DescriptionList, { layout: "inline", columns: { base: 1 }, items: reviewed.map((candidate) => ({
37
+ label: candidate.label,
38
+ value: candidate.summary,
39
+ })) })] })) : null] }));
40
+ };
41
+ const WizardFooter = ({ flow, labels, isFinishing, onCancel }) => (_jsxs(Flex, { w: "100%", justify: "space-between", gap: 2, wrap: "wrap", children: [onCancel ? (_jsx(Button, { variant: "ghost", colorScheme: "gray", label: labels.cancel, onClick: onCancel, isDisabled: isFinishing, "data-testid": "wizard-cancel" })) : (_jsx("span", {})), _jsxs(Flex, { gap: 2, children: [!flow.isFirst ? (_jsx(Button, { variant: "outline", colorScheme: "gray", label: labels.back, onClick: flow.back, isDisabled: isFinishing, "data-testid": "wizard-back" })) : null, flow.isLast ? (_jsx(Button, { variant: "solid", colorScheme: "primary", label: labels.finish, onClick: flow.finish, isLoading: isFinishing, loadingText: labels.finish, "data-testid": "wizard-finish" })) : (_jsx(Button, { variant: "solid", colorScheme: "primary", label: labels.next, onClick: flow.next, "data-testid": "wizard-next" }))] })] }));
42
+ /** Modal wizard that owns step state: validated Continue, locked future steps, error summary, review on the last step. */
43
+ export const WizardDialog = ({ isOpen, onClose, title, subtitle, steps, onFinish, isFinishing = false, stepId, onStepChange, size = "3xl", labels, "data-testid": testId, }) => {
44
+ const flow = useWizardFlow({ steps, stepId, onStepChange, onFinish, resetWhen: !isOpen });
45
+ const resolved = { ...DEFAULT_LABELS, ...labels };
46
+ const guardedClose = () => {
47
+ if (!isFinishing)
48
+ onClose();
49
+ };
50
+ return (_jsxs(Modal, { isOpen: isOpen, onClose: guardedClose, size: size, isCentered: true, scrollBehavior: "inside", title: title, subtitle: subtitle, closeOnOverlayClick: false, closeOnEsc: !isFinishing, hideCloseButton: isFinishing, children: [_jsx(ModalBody, { children: _jsx(WizardBody, { flow: flow, steps: steps, labels: resolved, testId: testId !== null && testId !== void 0 ? testId : "wizard-dialog" }) }), _jsx(ModalFooter, { children: _jsx(WizardFooter, { flow: flow, labels: resolved, isFinishing: isFinishing, onCancel: guardedClose }) })] }));
51
+ };
52
+ /** The same wizard inline, for a full-page flow rather than a modal. */
53
+ export const Wizard = ({ steps, onFinish, isFinishing = false, stepId, onStepChange, labels, onCancel, "data-testid": testId, }) => {
54
+ const flow = useWizardFlow({ steps, stepId, onStepChange, onFinish });
55
+ const resolved = { ...DEFAULT_LABELS, ...labels };
56
+ return (_jsxs(Flex, { direction: "column", gap: 6, children: [_jsx(WizardBody, { flow: flow, steps: steps, labels: resolved, testId: testId !== null && testId !== void 0 ? testId : "wizard" }), _jsx(WizardFooter, { flow: flow, labels: resolved, isFinishing: isFinishing, onCancel: onCancel })] }));
57
+ };
58
+ export default WizardDialog;
@@ -0,0 +1,44 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { INITIAL_WIZARD_STATE, firstInvalidStep, wizardTransition, } from "./wizardSteps.js";
3
+ export function useWizardFlow({ steps, stepId, onStepChange, onFinish, resetWhen }) {
4
+ const [state, setState] = useState(INITIAL_WIZARD_STATE);
5
+ const validators = steps.map((step) => step.validate);
6
+ const controlledIndex = stepId === undefined ? -1 : steps.findIndex((s) => s.id === stepId);
7
+ const isControlled = stepId !== undefined;
8
+ const index = Math.min(isControlled ? Math.max(controlledIndex, 0) : state.index, Math.max(steps.length - 1, 0));
9
+ const furthest = Math.max(state.furthest, index);
10
+ useEffect(() => {
11
+ if (resetWhen)
12
+ setState(INITIAL_WIZARD_STATE);
13
+ }, [resetWhen]);
14
+ const dispatch = useCallback((action) => {
15
+ const base = { ...state, index, furthest };
16
+ const next = wizardTransition(base, action, validators);
17
+ setState(next);
18
+ if (next.index !== index)
19
+ onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(steps[next.index].id);
20
+ },
21
+ // eslint-disable-next-line react-hooks/exhaustive-deps
22
+ [state, index, furthest, steps, onStepChange]);
23
+ const finish = useCallback(() => {
24
+ const invalid = firstInvalidStep(validators);
25
+ if (invalid) {
26
+ dispatch({ type: "fail", ...invalid });
27
+ return;
28
+ }
29
+ onFinish();
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, [dispatch, steps, onFinish]);
32
+ return {
33
+ index,
34
+ furthest,
35
+ errors: state.errors,
36
+ step: steps[index],
37
+ isFirst: index === 0,
38
+ isLast: index === steps.length - 1,
39
+ next: () => dispatch({ type: "next" }),
40
+ back: () => dispatch({ type: "back" }),
41
+ goto: (target) => dispatch({ type: "goto", index: target }),
42
+ finish,
43
+ };
44
+ }
@@ -0,0 +1,35 @@
1
+ export const INITIAL_WIZARD_STATE = { index: 0, furthest: 0, errors: [] };
2
+ /** Pure step reducer: `next` validates the current step, `goto` only reaches steps up to `furthest`. */
3
+ export function wizardTransition(state, action, validators) {
4
+ var _a, _b;
5
+ const last = validators.length - 1;
6
+ switch (action.type) {
7
+ case "next": {
8
+ const errors = (_b = (_a = validators[state.index]) === null || _a === void 0 ? void 0 : _a.call(validators)) !== null && _b !== void 0 ? _b : [];
9
+ if (errors.length)
10
+ return { ...state, errors };
11
+ const index = Math.min(state.index + 1, last);
12
+ return { index, furthest: Math.max(state.furthest, index), errors: [] };
13
+ }
14
+ case "back":
15
+ return { ...state, index: Math.max(state.index - 1, 0), errors: [] };
16
+ case "goto":
17
+ if (action.index < 0 || action.index > state.furthest)
18
+ return state;
19
+ return { ...state, index: action.index, errors: [] };
20
+ case "fail":
21
+ return { ...state, index: action.index, errors: action.errors };
22
+ case "reset":
23
+ return INITIAL_WIZARD_STATE;
24
+ }
25
+ }
26
+ /** First step whose validator reports errors, or null when every step is valid. */
27
+ export function firstInvalidStep(validators) {
28
+ var _a, _b;
29
+ for (let index = 0; index < validators.length; index += 1) {
30
+ const errors = (_b = (_a = validators[index]) === null || _a === void 0 ? void 0 : _a.call(validators)) !== null && _b !== void 0 ? _b : [];
31
+ if (errors.length)
32
+ return { index, errors };
33
+ }
34
+ return null;
35
+ }
package/dist/esm/index.js CHANGED
@@ -262,3 +262,10 @@ export { default as ProductCardGrid } from "./Components/ProductCard/ProductCard
262
262
  export { default as ProductCardSkeleton } from "./Components/ProductCard/ProductCardSkeleton.js";
263
263
  export { default as QuickAddSheet } from "./Components/ProductCard/QuickAddSheet.js";
264
264
  export * from "./Components/Primitives/Primitives.js";
265
+ export { default as Kbd, KbdShortcut } from "./Components/Kbd/Kbd.js";
266
+ export { default as LauncherTrigger } from "./Components/LauncherTrigger/LauncherTrigger.js";
267
+ export { default as NavLauncher } from "./Components/NavLauncher/NavLauncher.js";
268
+ export { default as PinToggle } from "./Components/NavLauncher/PinToggle.js";
269
+ export { default as NewTabLink } from "./Components/NavLauncher/NewTabLink.js";
270
+ export { searchLauncher, searchLauncherSections, flattenScreens } from "./Components/NavLauncher/match.js";
271
+ export { default as WizardDialog, Wizard, wizardTransition, firstInvalidStep, } from "./Components/WizardDialog/WizardDialog.js";
package/dist/index.d.ts CHANGED
@@ -147,7 +147,7 @@ export type { LimitReachedModalProps, LimitKind, } from "./Components/LimitReach
147
147
  export type { AccountHandoffConfig, AccountHandoff, AccountHandoffLinkOptions, AccountHandoffUsersOptions, ResolveReturnUrlOptions, } from "./Utils/accountHandoff";
148
148
  export type { TableProps, TableHeaderProps, TableColumnType, TableDensity, TableVariant, TableEmptyState, TableRenderGroup, HeaderActionsProps, ColumnSortingProps, ExportOption, DataObject, FilterValues, } from "./Components/Table/TableProps";
149
149
  export type { ButtonProps } from "./Components/Button/ButtonProps";
150
- export type { CardProps } from "./Components/Card/CardProps";
150
+ export type { CardProps, CardPadding } from "./Components/Card/CardProps";
151
151
  export type { ProfileCardProps, ProfileCardVariant, ProfileCardVariantLegacy, } from "./Components/ProfileCard/ProfileCardProps";
152
152
  export type { ChakraModelProps as ModalProps } from "./Components/Modal/ModalProps";
153
153
  export type { DrawerProps } from "./Components/Drawer/DrawerProps";
@@ -175,11 +175,11 @@ export type { LoadingProps } from "./Components/Loading/LoadingProps";
175
175
  export type { SkeletonProps } from "./Components/Skeletons/SkeletonProps";
176
176
  export type { ProgressBarProps } from "./Components/ProgressBar/ProgressBarProps";
177
177
  export type { ToasterToastProps } from "./Components/Toaster/ToasterProps";
178
- export type { BreadcrumbsProps, BreadcrumbItem } from "./Components/Breadcrumbs/BreadcrumbsProps";
178
+ export type { BreadcrumbsProps, BreadcrumbItem, BreadcrumbsLabels } from "./Components/Breadcrumbs/BreadcrumbsProps";
179
179
  export type { TimelineProps, TimelineEvent, TimelineEvents, TimelineNote, TimelineNoteAttachment, } from "./Components/Timeline/TimelineProps";
180
180
  export type { Stage, StageProgressProps, StageItemProps, StageSize, StageState, StageVariant, StageColorScheme, } from "./Components/StageProgress/StageProgressProps";
181
181
  export type { FileUploaderProps, MimeExtension } from "./Components/FileUpload/FileUploadProps";
182
- export type { SidebarProps, SidebarUser, SecondaryBarProps, OtherAppsProps, MenuProps as SidebarMenuProps, } from "./Components/SideBar/SideBarProps";
182
+ export type { SidebarProps, SidebarUser, SecondaryBarProps, OtherAppsProps, MenuProps as SidebarMenuProps, SidebarPinnedItem, SidebarPinnedLabels, SidebarCollapseTransition, } from "./Components/SideBar/SideBarProps";
183
183
  export type { NavbarProps, MenuProps as NavbarMenuProps } from "./Components/NavigationBar/NavigationBarProps";
184
184
  export type { HeaderProps } from "./Components/Header/HeaderProps";
185
185
  export { appInitials, filterApps, matchesShortcut, formatShortcut, buildSuiteApps, } from "./Components/AppSwitcher/AppSwitcherProps";
@@ -211,7 +211,7 @@ export { fieldControlStyles, controlSizeStyles } from "./Components/Common/field
211
211
  export { fieldLabelStyles } from "./Components/Common/FormLabel";
212
212
  export { fieldMessageStyles } from "./Components/Common/fieldMessageStyles";
213
213
  export { default as PageHeader } from "./Components/PageHeader/PageHeader";
214
- export type { PageHeaderProps } from "./Components/PageHeader/PageHeaderProps";
214
+ export type { PageHeaderProps, PageHeaderTitleSize, PageHeaderActionsLayout } from "./Components/PageHeader/PageHeaderProps";
215
215
  export { default as StatCard } from "./Components/StatCard/StatCard";
216
216
  export type { StatCardProps } from "./Components/StatCard/StatCardProps";
217
217
  export { default as ErrorState } from "./Components/QueryState/ErrorState";
@@ -354,3 +354,18 @@ export { default as QuickAddSheet } from "./Components/ProductCard/QuickAddSheet
354
354
  export type { ProductCardProps, ProductCardLayout, ProductCardDensity, ProductCardAspectRatio, ProductCardAction, ProductCardLabels, ProductCardPressHandler, ProductCardSkeletonProps, ProductCardGridProps, ProductCardGridColumns } from "./Components/ProductCard/ProductCardProps";
355
355
  export type { QuickAddSheetProps, QuickAddSheetLabels, QuickAddPresentation } from "./Components/ProductCard/QuickAddSheetProps";
356
356
  export * from "./Components/Primitives/Primitives";
357
+ export { default as Kbd, KbdShortcut } from "./Components/Kbd/Kbd";
358
+ export type { KbdProps, KbdShortcutProps } from "./Components/Kbd/KbdProps";
359
+ export { default as LauncherTrigger } from "./Components/LauncherTrigger/LauncherTrigger";
360
+ export type { LauncherTriggerProps } from "./Components/LauncherTrigger/LauncherTriggerProps";
361
+ export { default as NavLauncher } from "./Components/NavLauncher/NavLauncher";
362
+ export { default as PinToggle } from "./Components/NavLauncher/PinToggle";
363
+ export { default as NewTabLink } from "./Components/NavLauncher/NewTabLink";
364
+ export { searchLauncher, searchLauncherSections, flattenScreens } from "./Components/NavLauncher/match";
365
+ export type { LauncherResult, LauncherResultView, LauncherSectionResult } from "./Components/NavLauncher/match";
366
+ export type { LauncherIcon, LauncherScreen, LauncherModule, LauncherSection, LauncherSearchItem, LauncherResultGroup, LauncherLabels, LauncherNavigateOptions, NavLauncherProps, PinToggleProps, NewTabLinkProps, } from "./Components/NavLauncher/NavLauncherProps";
367
+ export { default as WizardDialog, Wizard, wizardTransition, firstInvalidStep, } from "./Components/WizardDialog/WizardDialog";
368
+ export type { WizardStep, WizardLabels, WizardDialogProps, WizardProps } from "./Components/WizardDialog/WizardDialogProps";
369
+ export type { WizardState, WizardAction, StepValidator } from "./Components/WizardDialog/wizardSteps";
370
+ export type { PdfViewerProps, PdfViewerLabels } from "./Components/PdfViewer/PdfViewer";
371
+ export type { EditorProps, EditorApi, EditorMergeField, EditorTokenSyntax, EditorToolbarButton, EditorLabels, } from "./Components/Editor/EditorProps";
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ exports.appInitials = exports.describeDayStates = exports.resolveDayStateVisual
47
47
  exports.Backdrop = exports.QueryStateBoundary = exports.ErrorState = exports.StatCard = exports.PageHeader = exports.fieldMessageStyles = exports.fieldLabelStyles = exports.controlSizeStyles = exports.fieldControlStyles = exports.FieldMessage = exports.useFieldIds = exports.REDUCED_MOTION_QUERY = exports.reducedMotionSx = exports.usePrefersReducedMotion = exports.OVERLAY_BLUR = exports.overlayScrimStyles = exports.RAISED_OVERLAY = exports.raisedRule = exports.buildSurfaceRaised = exports.tooltipSurface = exports.SCRIM_OPACITY = exports.overlayScrim = exports.resolveSoftTone = exports.toneInk = exports.toneScale = exports.toneToSemantic = exports.toneToColorScheme = exports.isTone = exports.TONES = exports.transitionFor = exports.MOTION_EASE = exports.MOTION_MS = exports.isControlSize = exports.DEFAULT_CONTROL_SIZE = exports.CONTROL_SIZE_NAMES = exports.CONTROL_SIZES = exports.inkSafeGradientToken = exports.gradientCss = exports.resolveGradient = exports.fieldSurfaces = exports.placeholderInkOn = exports.placeholderInk = exports.SCROLLBAR_WIDTH = exports.globalScrollbarStyles = exports.scrollbarStyles = exports.useAppSwitcherShortcut = exports.buildSuiteApps = exports.formatShortcut = exports.matchesShortcut = exports.filterApps = void 0;
48
48
  exports.RangeSlider = exports.getApiErrorStatus = exports.getApiErrorMessage = exports.defaultValidationMessages = exports.validateYoutubeUrl = exports.validateVideoFile = exports.validateVideoFileType = exports.validateFile = exports.validateFileSize = exports.validateFileType = exports.validatePositiveNumber = exports.validateRequired = exports.validatePassword = exports.validateEmail = exports.EMAIL_REGEX = exports.createEnumLabelResolver = exports.humanize = exports.clearChunkReloadGuard = exports.isChunkLoadError = exports.installPreloadErrorReload = exports.lazyWithRetry = exports.useAnchoredPanelHeight = exports.formatRelativeTime = exports.formatCount = exports.groupConsecutive = exports.sectionizeByDay = exports.NotificationItem = exports.NotificationList = exports.NotificationPanel = exports.NotificationBell = exports.ConfirmDialog = exports.TabPanel = exports.TabPanels = exports.Tab = exports.TabList = exports.Tabs = exports.Accordian = exports.SaveBar = exports.FeedbackForm = exports.PersonChip = exports.initialsFor = exports.avatarScaleKeyFor = exports.resolveAvatarColorway = exports.AvatarGroup = exports.Avatar = exports.SettingsSection = exports.SettingRow = exports.FilterBar = exports.DescriptionList = exports.Spinner = void 0;
49
49
  exports.MediaGallery = exports.PaymentOptionGroup = exports.PaymentOption = exports.AddressCardGroup = exports.AddressCard = exports.DetailSections = exports.ReviewList = exports.ReviewSummary = exports.SpecTable = exports.OffersList = exports.TrustBadges = exports.PincodeChecker = exports.StickyBuyBar = exports.BagBar = exports.OrderStatusTimeline = exports.CouponField = exports.OrderSummary = exports.CartItem = exports.QuantityStepper = exports.VariantSelector = exports.OptionChip = exports.WishlistToggle = exports.ProductBadges = exports.StockStatus = exports.PriceBlock = exports.Rating = exports.SEEK_STEP_SECONDS = exports.PLAYBACK_SPEEDS = exports.ZOOM_STEP = exports.MAX_ZOOM = exports.MIN_ZOOM = exports.resolveMediaUrl = exports.fileKind = exports.countMedia = exports.planPreview = exports.buildFileItems = exports.buildMediaItems = exports.MediaStatusPanel = exports.MediaScrubber = exports.defaultMediaAudioPlayerLabels = exports.MediaAudioPlayer = exports.defaultMediaViewerLabels = exports.defaultMediaDocumentStageLabels = exports.MediaDocumentStage = exports.defaultMediaVideoPlayerLabels = exports.MediaVideoPlayer = exports.defaultMediaImageViewerLabels = exports.MediaImageViewer = exports.useFileViewer = exports.MediaViewer = void 0;
50
- exports.QuickAddSheet = exports.ProductCardSkeleton = exports.ProductCardGrid = exports.unitPrice = exports.discountAmount = exports.discountPercent = exports.formatPrice = exports.firstAvailableSelection = exports.priceRange = exports.remainingStock = exports.isOptionAvailable = exports.findVariant = exports.selectionComplete = exports.stockState = exports.LOW_STOCK_THRESHOLD = exports.defaultMediaLightboxLabels = exports.defaultMediaGalleryLabels = exports.MediaLightbox = void 0;
50
+ exports.firstInvalidStep = exports.wizardTransition = exports.Wizard = exports.WizardDialog = exports.flattenScreens = exports.searchLauncherSections = exports.searchLauncher = exports.NewTabLink = exports.PinToggle = exports.NavLauncher = exports.LauncherTrigger = exports.KbdShortcut = exports.Kbd = exports.QuickAddSheet = exports.ProductCardSkeleton = exports.ProductCardGrid = exports.unitPrice = exports.discountAmount = exports.discountPercent = exports.formatPrice = exports.firstAvailableSelection = exports.priceRange = exports.remainingStock = exports.isOptionAvailable = exports.findVariant = exports.selectionComplete = exports.stockState = exports.LOW_STOCK_THRESHOLD = exports.defaultMediaLightboxLabels = exports.defaultMediaGalleryLabels = exports.MediaLightbox = void 0;
51
51
  const Accordion_1 = __importDefault(require("./Components/Accordion/Accordion"));
52
52
  exports.Accordion = Accordion_1.default;
53
53
  const AlertDialog_1 = __importDefault(require("./Components/AlertDialog/AlertDialog"));
@@ -668,3 +668,23 @@ Object.defineProperty(exports, "ProductCardSkeleton", { enumerable: true, get: f
668
668
  var QuickAddSheet_1 = require("./Components/ProductCard/QuickAddSheet");
669
669
  Object.defineProperty(exports, "QuickAddSheet", { enumerable: true, get: function () { return __importDefault(QuickAddSheet_1).default; } });
670
670
  __exportStar(require("./Components/Primitives/Primitives"), exports);
671
+ var Kbd_1 = require("./Components/Kbd/Kbd");
672
+ Object.defineProperty(exports, "Kbd", { enumerable: true, get: function () { return __importDefault(Kbd_1).default; } });
673
+ Object.defineProperty(exports, "KbdShortcut", { enumerable: true, get: function () { return Kbd_1.KbdShortcut; } });
674
+ var LauncherTrigger_1 = require("./Components/LauncherTrigger/LauncherTrigger");
675
+ Object.defineProperty(exports, "LauncherTrigger", { enumerable: true, get: function () { return __importDefault(LauncherTrigger_1).default; } });
676
+ var NavLauncher_1 = require("./Components/NavLauncher/NavLauncher");
677
+ Object.defineProperty(exports, "NavLauncher", { enumerable: true, get: function () { return __importDefault(NavLauncher_1).default; } });
678
+ var PinToggle_1 = require("./Components/NavLauncher/PinToggle");
679
+ Object.defineProperty(exports, "PinToggle", { enumerable: true, get: function () { return __importDefault(PinToggle_1).default; } });
680
+ var NewTabLink_1 = require("./Components/NavLauncher/NewTabLink");
681
+ Object.defineProperty(exports, "NewTabLink", { enumerable: true, get: function () { return __importDefault(NewTabLink_1).default; } });
682
+ var match_1 = require("./Components/NavLauncher/match");
683
+ Object.defineProperty(exports, "searchLauncher", { enumerable: true, get: function () { return match_1.searchLauncher; } });
684
+ Object.defineProperty(exports, "searchLauncherSections", { enumerable: true, get: function () { return match_1.searchLauncherSections; } });
685
+ Object.defineProperty(exports, "flattenScreens", { enumerable: true, get: function () { return match_1.flattenScreens; } });
686
+ var WizardDialog_1 = require("./Components/WizardDialog/WizardDialog");
687
+ Object.defineProperty(exports, "WizardDialog", { enumerable: true, get: function () { return __importDefault(WizardDialog_1).default; } });
688
+ Object.defineProperty(exports, "Wizard", { enumerable: true, get: function () { return WizardDialog_1.Wizard; } });
689
+ Object.defineProperty(exports, "wizardTransition", { enumerable: true, get: function () { return WizardDialog_1.wizardTransition; } });
690
+ Object.defineProperty(exports, "firstInvalidStep", { enumerable: true, get: function () { return WizardDialog_1.firstInvalidStep; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelize-design-library",
3
- "version": "2.4.2-beta.58",
3
+ "version": "2.4.2-beta.59",
4
4
  "description": "React component library for Pixelize apps: themeable Chakra-based components, design tokens and light/dark brand theming.",
5
5
  "keywords": [
6
6
  "react",