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

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 (166) hide show
  1. package/CHANGELOG.md +75 -2
  2. package/COMPONENT-GOTCHAS.md +25 -6
  3. package/DESIGN-GUIDE.md +12 -5
  4. package/dist/Components/Button/Button.styles.js +51 -21
  5. package/dist/Components/Card/CardProps.d.ts +2 -2
  6. package/dist/Components/ConfirmDialog/ConfirmDialog.js +2 -1
  7. package/dist/Components/CustomModulesTable/CustomModulesTable.js +6 -4
  8. package/dist/Components/CustomModulesTable/EditModuleModal.js +2 -1
  9. package/dist/Components/DatePicker/RangeDatePicker.js +2 -1
  10. package/dist/Components/DatePicker/SingleDatePicker.js +2 -1
  11. package/dist/Components/DatePicker/TimeOnlyPicker.js +2 -1
  12. package/dist/Components/DatePicker/dayStates.js +2 -1
  13. package/dist/Components/Drawer/Drawer.js +2 -1
  14. package/dist/Components/Dropdown/DropDown.js +2 -1
  15. package/dist/Components/FileUpload/FileUpload.js +9 -2
  16. package/dist/Components/FilterSidebar/FilterSidebar.js +7 -4
  17. package/dist/Components/KanbanBoard/AccountCard.js +4 -2
  18. package/dist/Components/NavigationBar/NavigationBar.js +3 -2
  19. package/dist/Components/Notification/Notification.js +4 -3
  20. package/dist/Components/NotificationBell/NotificationPanel.js +4 -3
  21. package/dist/Components/OrganizationDetails/CreateOrgModal.js +2 -1
  22. package/dist/Components/OrganizationDetails/OrganizationDetails.js +5 -3
  23. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -3
  24. package/dist/Components/SearchSelect/SearchSelect.js +42 -21
  25. package/dist/Components/SearchSelect/searchSelectNav.d.ts +13 -0
  26. package/dist/Components/SearchSelect/searchSelectNav.js +40 -0
  27. package/dist/Components/Select/SelectPopup.js +2 -1
  28. package/dist/Components/SelectSearch/SelectSearch.js +2 -1
  29. package/dist/Components/SettingRow/SettingRow.js +2 -1
  30. package/dist/Components/SettingRow/SettingsSection.js +2 -1
  31. package/dist/Components/SideBar/SecondaryBar.js +4 -3
  32. package/dist/Components/SideBar/SideBar.js +16 -13
  33. package/dist/Components/SideBar/SideBarProps.d.ts +1 -1
  34. package/dist/Components/SideBar/components/MenuItemBox.js +7 -4
  35. package/dist/Components/SideBar/components/MenuPopoverContent.js +2 -1
  36. package/dist/Components/SideBar/components/OtherApps.js +2 -1
  37. package/dist/Components/SideBar/components/PinnedSection.js +7 -4
  38. package/dist/Components/SideBar/sidebarMotion.d.ts +2 -0
  39. package/dist/Components/SideBar/sidebarMotion.js +6 -0
  40. package/dist/Components/SignInActivityTable/SignInActivityTable.js +6 -4
  41. package/dist/Components/StageProgress/StageItem.js +5 -2
  42. package/dist/Components/StageProgress/StepperStage.js +2 -2
  43. package/dist/Components/StatCard/StatCard.js +2 -1
  44. package/dist/Components/Table/Table.js +6 -2
  45. package/dist/Components/Table/components/TableActions.js +3 -2
  46. package/dist/Components/Table/filters/CompactSelect.js +2 -1
  47. package/dist/Components/Table/settings/TableSettings.js +7 -2
  48. package/dist/Components/Table/variants/classic.js +3 -2
  49. package/dist/Components/Timeline/Timeline.js +11 -4
  50. package/dist/Components/Toaster/Toaster.js +19 -8
  51. package/dist/Components/Toggle/TableToggle.js +5 -2
  52. package/dist/Components/UserDetails/AddUserModal.js +2 -1
  53. package/dist/Components/UserDetails/ChangeRoleModal.js +2 -1
  54. package/dist/Components/UserDetails/UserDetails.js +3 -1
  55. package/dist/Theme/chakra/Card.styles.d.ts +7 -1
  56. package/dist/Theme/chakra/Card.styles.js +4 -1
  57. package/dist/Theme/chakra/Menu.styles.d.ts +3 -5
  58. package/dist/Theme/chakra/Menu.styles.js +3 -0
  59. package/dist/Theme/chakra/Popover.styles.d.ts +2 -11
  60. package/dist/Theme/chakra/Popover.styles.js +2 -0
  61. package/dist/Theme/chakra/common.web.d.ts +4 -0
  62. package/dist/Theme/chakra/componentStyles.d.ts +11 -3
  63. package/dist/Theme/chakra/componentStyles.js +10 -6
  64. package/dist/Theme/chakra/motion.d.ts +1 -0
  65. package/dist/Theme/chakra/motion.js +2 -1
  66. package/dist/Theme/chakra/overlay.styles.d.ts +5 -0
  67. package/dist/Theme/chakra/overlay.styles.js +4 -1
  68. package/dist/Theme/themeProps.d.ts +4 -0
  69. package/dist/Theme/tokens/brands/index.d.ts +1 -0
  70. package/dist/Theme/tokens/brands/index.js +17 -1
  71. package/dist/Theme/tokens/brands/radiant/palette.light.js +15 -0
  72. package/dist/Theme/tokens/brands/rosewood/palette.light.js +10 -10
  73. package/dist/Theme/tokens/brands/zinc/palette.dark.d.ts +7 -29
  74. package/dist/Theme/tokens/brands/zinc/palette.dark.js +3 -35
  75. package/dist/Theme/tokens/builders/buildDarkPalette.d.ts +6 -1
  76. package/dist/Theme/tokens/builders/buildDarkPalette.js +37 -8
  77. package/dist/Theme/tokens/builders/mutedText.d.ts +1 -1
  78. package/dist/Theme/tokens/builders/mutedText.js +13 -3
  79. package/dist/Theme/tokens/builders/planeStep.d.ts +4 -0
  80. package/dist/Theme/tokens/builders/planeStep.js +20 -0
  81. package/dist/Theme/tokens/builders/planes.d.ts +4 -0
  82. package/dist/Theme/tokens/builders/planes.js +33 -0
  83. package/dist/Theme/tokens/builders/skeletonShimmer.d.ts +9 -0
  84. package/dist/Theme/tokens/builders/skeletonShimmer.js +25 -0
  85. package/dist/Theme/tokens/builders/surfaceRaised.d.ts +3 -1
  86. package/dist/Theme/tokens/builders/surfaceRaised.js +18 -8
  87. package/dist/Theme/tokens/builders/surfaceRungs.js +3 -1
  88. package/dist/Theme/tokens/primitives/index.d.ts +2 -2
  89. package/dist/Theme/tokens/primitives/index.js +4 -1
  90. package/dist/Theme/tokens/primitives/motion.d.ts +1 -0
  91. package/dist/Theme/tokens/primitives/motion.js +2 -1
  92. package/dist/Theme/tokens/primitives/shadows.d.ts +16 -0
  93. package/dist/Theme/tokens/primitives/shadows.js +56 -6
  94. package/dist/Theme/tokens/primitives/typography.js +1 -1
  95. package/dist/esm/Components/Button/Button.styles.js +54 -24
  96. package/dist/esm/Components/ConfirmDialog/ConfirmDialog.js +2 -1
  97. package/dist/esm/Components/CustomModulesTable/CustomModulesTable.js +6 -4
  98. package/dist/esm/Components/CustomModulesTable/EditModuleModal.js +2 -1
  99. package/dist/esm/Components/DatePicker/RangeDatePicker.js +2 -1
  100. package/dist/esm/Components/DatePicker/SingleDatePicker.js +2 -1
  101. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +2 -1
  102. package/dist/esm/Components/DatePicker/dayStates.js +2 -1
  103. package/dist/esm/Components/Drawer/Drawer.js +2 -1
  104. package/dist/esm/Components/Dropdown/DropDown.js +2 -1
  105. package/dist/esm/Components/FileUpload/FileUpload.js +10 -3
  106. package/dist/esm/Components/FilterSidebar/FilterSidebar.js +7 -4
  107. package/dist/esm/Components/KanbanBoard/AccountCard.js +4 -2
  108. package/dist/esm/Components/NavigationBar/NavigationBar.js +3 -2
  109. package/dist/esm/Components/Notification/Notification.js +4 -3
  110. package/dist/esm/Components/NotificationBell/NotificationPanel.js +4 -3
  111. package/dist/esm/Components/OrganizationDetails/CreateOrgModal.js +2 -1
  112. package/dist/esm/Components/OrganizationDetails/OrganizationDetails.js +5 -3
  113. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -3
  114. package/dist/esm/Components/SearchSelect/SearchSelect.js +42 -21
  115. package/dist/esm/Components/SearchSelect/searchSelectNav.js +32 -0
  116. package/dist/esm/Components/Select/SelectPopup.js +2 -1
  117. package/dist/esm/Components/SelectSearch/SelectSearch.js +2 -1
  118. package/dist/esm/Components/SettingRow/SettingRow.js +2 -1
  119. package/dist/esm/Components/SettingRow/SettingsSection.js +2 -1
  120. package/dist/esm/Components/SideBar/SecondaryBar.js +4 -3
  121. package/dist/esm/Components/SideBar/SideBar.js +17 -14
  122. package/dist/esm/Components/SideBar/components/MenuItemBox.js +7 -4
  123. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +2 -1
  124. package/dist/esm/Components/SideBar/components/OtherApps.js +2 -1
  125. package/dist/esm/Components/SideBar/components/PinnedSection.js +7 -4
  126. package/dist/esm/Components/SideBar/sidebarMotion.js +3 -0
  127. package/dist/esm/Components/SignInActivityTable/SignInActivityTable.js +6 -4
  128. package/dist/esm/Components/StageProgress/StageItem.js +5 -2
  129. package/dist/esm/Components/StageProgress/StepperStage.js +2 -2
  130. package/dist/esm/Components/StatCard/StatCard.js +2 -1
  131. package/dist/esm/Components/Table/Table.js +8 -4
  132. package/dist/esm/Components/Table/components/TableActions.js +3 -2
  133. package/dist/esm/Components/Table/filters/CompactSelect.js +2 -1
  134. package/dist/esm/Components/Table/settings/TableSettings.js +8 -3
  135. package/dist/esm/Components/Table/variants/classic.js +3 -2
  136. package/dist/esm/Components/Timeline/Timeline.js +11 -4
  137. package/dist/esm/Components/Toaster/Toaster.js +20 -9
  138. package/dist/esm/Components/Toggle/TableToggle.js +5 -2
  139. package/dist/esm/Components/UserDetails/AddUserModal.js +2 -1
  140. package/dist/esm/Components/UserDetails/ChangeRoleModal.js +2 -1
  141. package/dist/esm/Components/UserDetails/UserDetails.js +3 -1
  142. package/dist/esm/Theme/chakra/Card.styles.js +4 -1
  143. package/dist/esm/Theme/chakra/Menu.styles.js +3 -0
  144. package/dist/esm/Theme/chakra/Popover.styles.js +2 -0
  145. package/dist/esm/Theme/chakra/componentStyles.js +10 -6
  146. package/dist/esm/Theme/chakra/motion.js +1 -0
  147. package/dist/esm/Theme/chakra/overlay.styles.js +3 -0
  148. package/dist/esm/Theme/tokens/brands/index.js +16 -0
  149. package/dist/esm/Theme/tokens/brands/radiant/palette.light.js +15 -0
  150. package/dist/esm/Theme/tokens/brands/rosewood/palette.light.js +10 -10
  151. package/dist/esm/Theme/tokens/brands/zinc/palette.dark.js +3 -35
  152. package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +38 -9
  153. package/dist/esm/Theme/tokens/builders/mutedText.js +12 -2
  154. package/dist/esm/Theme/tokens/builders/planeStep.js +14 -0
  155. package/dist/esm/Theme/tokens/builders/planes.js +28 -0
  156. package/dist/esm/Theme/tokens/builders/skeletonShimmer.js +21 -0
  157. package/dist/esm/Theme/tokens/builders/surfaceRaised.js +16 -7
  158. package/dist/esm/Theme/tokens/builders/surfaceRungs.js +3 -1
  159. package/dist/esm/Theme/tokens/primitives/index.js +1 -1
  160. package/dist/esm/Theme/tokens/primitives/motion.js +1 -0
  161. package/dist/esm/Theme/tokens/primitives/shadows.js +54 -5
  162. package/dist/esm/Theme/tokens/primitives/typography.js +1 -1
  163. package/dist/esm/index.js +1 -0
  164. package/dist/index.d.ts +1 -0
  165. package/dist/index.js +9 -5
  166. package/package.json +1 -1
@@ -3,6 +3,7 @@ import React, { forwardRef, useEffect, useId, useLayoutEffect, useRef, useState
3
3
  import { Button, IconButton, Popover, PopoverAnchor, PopoverBody, PopoverContent, Portal, VStack, } from "@chakra-ui/react";
4
4
  import { EllipsisVertical, ExternalLink, Pencil, Trash2 } from "lucide-react";
5
5
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
6
+ import { raisedRule } from "../../../Theme/tokens/builders/surfaceRaised.js";
6
7
  const assignRef = (ref, value) => {
7
8
  if (typeof ref === "function")
8
9
  ref(value);
@@ -53,11 +54,11 @@ const TableActions = React.memo(({ row }) => {
53
54
  // ✅ if row itself is missing, render nothing
54
55
  if (!row)
55
56
  return null;
56
- return (_jsxs("div", { ref: ref, children: [_jsx(IconButton, { ref: triggerRef, id: `popover-trigger-${popoverId}`, "aria-label": "Actions", "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-controls": `popover-content-${popoverId}`, color: theme.colors.text[900], icon: _jsx(EllipsisVertical, { size: 17 }), size: "sm", p: 0, variant: "ghost", _hover: { transform: "scale(1.2)" }, onClick: () => (isOpen ? handleClose() : handleOpen()) }), isOpen && (_jsxs(Popover, { id: popoverId, placement: "bottom-start", isOpen: true, onClose: handleClose, closeOnBlur: false, returnFocusOnClose: false, children: [_jsx(PopoverAnchor, { children: _jsx(TriggerAnchor, { target: triggerRef }) }), _jsx(Portal, { children: _jsx(PopoverContent, { w: "auto", minW: "100px", boxShadow: "lg", p: 0, zIndex: 999, bg: theme.colors.surfaceRaised, children: _jsx(PopoverBody, { p: 0, m: 0, children: _jsxs(VStack, { align: "stretch", spacing: 1, p: 0, m: 0, children: [row.onLink && (_jsxs(Button, { size: "sm", variant: "ghost", justifyContent: "flex-start", borderBottom: `1px solid ${theme.colors.boxborder[200]}`, borderRadius: 0, gap: 2, onClick: () => {
57
+ return (_jsxs("div", { ref: ref, children: [_jsx(IconButton, { ref: triggerRef, id: `popover-trigger-${popoverId}`, "aria-label": "Actions", "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-controls": `popover-content-${popoverId}`, color: theme.colors.text[900], icon: _jsx(EllipsisVertical, { size: 17 }), size: "sm", p: 0, variant: "ghost", _hover: { transform: "scale(1.2)" }, onClick: () => (isOpen ? handleClose() : handleOpen()) }), isOpen && (_jsxs(Popover, { id: popoverId, placement: "bottom-start", isOpen: true, onClose: handleClose, closeOnBlur: false, returnFocusOnClose: false, children: [_jsx(PopoverAnchor, { children: _jsx(TriggerAnchor, { target: triggerRef }) }), _jsx(Portal, { children: _jsx(PopoverContent, { w: "auto", minW: "100px", boxShadow: "lg", p: 0, zIndex: 999, bg: theme.colors.surfaceRaised, children: _jsx(PopoverBody, { p: 0, m: 0, children: _jsxs(VStack, { align: "stretch", spacing: 1, p: 0, m: 0, children: [row.onLink && (_jsxs(Button, { size: "sm", variant: "ghost", justifyContent: "flex-start", borderBottom: `1px solid ${raisedRule(theme.colors)}`, borderRadius: 0, gap: 2, onClick: () => {
57
58
  var _a;
58
59
  (_a = row.onLink) === null || _a === void 0 ? void 0 : _a.call(row, row);
59
60
  handleClose();
60
- }, children: [_jsx(ExternalLink, { size: 17 }), " View"] })), row.onEdit && (_jsxs(Button, { size: "sm", variant: "ghost", justifyContent: "flex-start", gap: 2, borderBottom: `1px solid ${theme.colors.boxborder[200]}`, borderRadius: 0, onClick: () => {
61
+ }, children: [_jsx(ExternalLink, { size: 17 }), " View"] })), row.onEdit && (_jsxs(Button, { size: "sm", variant: "ghost", justifyContent: "flex-start", gap: 2, borderBottom: `1px solid ${raisedRule(theme.colors)}`, borderRadius: 0, onClick: () => {
61
62
  var _a;
62
63
  (_a = row.onEdit) === null || _a === void 0 ? void 0 : _a.call(row, row);
63
64
  handleClose();
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  import { Box, Text, Input, Popover, PopoverTrigger, PopoverContent, PopoverBody, VStack, Portal } from "@chakra-ui/react";
4
4
  import { ChevronDown, ChevronUp, Check } from "lucide-react";
5
5
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
6
+ import { raisedRule } from "../../../Theme/tokens/builders/surfaceRaised.js";
6
7
  import { listRowBackgrounds } from "../../../Theme/tokens/builders/rowStates.js";
7
8
  import { optionRowSpec, OPTION_ROW_RADIUS } from "../../../Theme/tokens/primitives/optionRowSizes.js";
8
9
  import { optionRowInk, optionRowWeight } from "../../Select/optionRowInk.js";
@@ -54,7 +55,7 @@ const CompactSelect = ({ options, value, placeholder = "Select", height = "22px"
54
55
  e.preventDefault();
55
56
  focusOption(0);
56
57
  }
57
- }, sx: { fontSize: "0.75rem", height: "22px" } }), _jsxs(Box, { role: "listbox", "aria-label": placeholder, maxH: "12rem", overflowY: "auto", borderTop: "1px solid", borderColor: theme.colors.boxborder[200], onKeyDown: handleListKeyDown, children: [filtered.map((opt, i) => {
58
+ }, sx: { fontSize: "0.75rem", height: "22px" } }), _jsxs(Box, { role: "listbox", "aria-label": placeholder, maxH: "12rem", overflowY: "auto", borderTop: "1px solid", borderColor: raisedRule(theme.colors), onKeyDown: handleListKeyDown, children: [filtered.map((opt, i) => {
58
59
  const selected = (value === null || value === void 0 ? void 0 : value.id) === opt.id;
59
60
  const isActive = i === activeIndex;
60
61
  const rowBg = selected
@@ -5,13 +5,17 @@ import { motion } from "framer-motion";
5
5
  import ManageColumns from "./ManageColumns.js";
6
6
  import Button from "../../Button/Button.js";
7
7
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
8
+ import { raisedRule } from "../../../Theme/tokens/builders/surfaceRaised.js";
8
9
  import { scrollbarStyles } from "../../../Theme/tokens/builders/scrollbar.js";
9
10
  import { columnLabelText } from "../columnLabel.js";
10
11
  import { Settings, Check } from "lucide-react";
11
12
  import ToolTip from "../../ToolTip/ToolTip.js";
12
13
  import { listRowBackgrounds } from "../../../Theme/tokens/builders/rowStates.js";
13
- import { transitionFor } from "../../../Theme/tokens/primitives/motion.js";
14
+ import { motionTransition, transitionFor } from "../../../Theme/tokens/primitives/motion.js";
15
+ import { usePrefersReducedMotion } from "../../../Theme/chakra/motion.js";
14
16
  const MotionModalContent = motion(ModalContent);
17
+ const SHEET_ENTER = motionTransition("enter", "out");
18
+ const SHEET_EXIT = motionTransition("exit", "in");
15
19
  const DENSITY_OPTIONS = [
16
20
  { value: "compact", label: "Compact", desc: "Tight rows — fit more data on screen" },
17
21
  { value: "normal", label: "Normal", desc: "Balanced default spacing" },
@@ -19,6 +23,7 @@ const DENSITY_OPTIONS = [
19
23
  ];
20
24
  const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, groupBy, }) => {
21
25
  const theme = useCustomTheme();
26
+ const sheetOffset = usePrefersReducedMotion() ? 0 : "-100%";
22
27
  const rowBackgrounds = useMemo(() => listRowBackgrounds(theme.colors), [theme.colors]);
23
28
  const childInputMethodsRef = useRef({});
24
29
  const [settingsOpen, setSettingsOpen] = useState(false);
@@ -52,7 +57,7 @@ const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, g
52
57
  return (_jsxs(Box, { children: [_jsx(ToolTip, { label: "Table Settings", placement: "top", children: _jsx(IconButton, { "aria-label": "Table settings", icon: _jsx(Settings, { size: "1.25rem" }), onClick: handleOpen, variant: "unstyled", minW: "auto", h: "auto", display: "flex", justifyContent: "flex-end", cursor: "pointer", transition: transitionFor(["color", "transform"], "base"), color: theme.colors.text[500], _hover: {
53
58
  transform: "scale(1.1)",
54
59
  color: theme.colors.accentText
55
- } }) }), _jsxs(Modal, { isOpen: settingsOpen, onClose: () => setSettingsOpen(false), size: { base: "full", md: "md" }, children: [_jsx(ModalOverlay, {}), _jsxs(MotionModalContent, { mt: "0", top: "0", left: { base: 0, md: "auto" }, right: { base: 0, md: "auto" }, position: "absolute", borderTopRadius: "none", initial: { y: "-100%", opacity: 0 }, animate: { y: 0, opacity: 1 }, exit: { y: "-100%", opacity: 0 }, transition: { duration: 0.4, ease: "easeOut" }, padding: "0", minW: { base: "auto", md: "620px" }, minH: { base: "auto", md: "520px" }, maxH: "90vh", display: "flex", flexDirection: "column", bg: theme.colors.surfaceRaised, overflow: "hidden", children: [_jsx(ModalCloseButton, { top: 3, right: 3, zIndex: 2 }), _jsxs(Tabs, { index: selectedIndex, onChange: setSelectedIndex, variant: "unstyled", display: "flex", flexDirection: "column", flex: "1", minH: 0, children: [_jsxs(Box, { pt: 4, px: 4, children: [_jsx(Text, { fontWeight: 600, fontSize: "md", mb: 3, children: "Table Settings" }), _jsxs(TabList, { gap: 0, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Tab, { ...tabStyle, children: "Density" }), _jsx(Tab, { ...tabStyle, children: "Manage Columns" }), _jsx(Tab, { ...tabStyle, children: "Group" })] })] }), _jsx(ModalBody, { px: 4, py: 3, flex: "1", overflowY: "auto", sx: scrollbarStyles(theme.colors), children: _jsxs(TabPanels, { children: [_jsx(TabPanel, { px: 0, py: 1, children: _jsx(Flex, { direction: "column", gap: 2, children: DENSITY_OPTIONS.map((opt) => {
60
+ } }) }), _jsxs(Modal, { isOpen: settingsOpen, onClose: () => setSettingsOpen(false), size: { base: "full", md: "md" }, children: [_jsx(ModalOverlay, {}), _jsxs(MotionModalContent, { mt: "0", top: "0", left: { base: 0, md: "auto" }, right: { base: 0, md: "auto" }, position: "absolute", borderTopRadius: "none", initial: { y: sheetOffset, opacity: 0 }, animate: { y: 0, opacity: 1 }, exit: { y: sheetOffset, opacity: 0, transition: SHEET_EXIT }, transition: SHEET_ENTER, padding: "0", minW: { base: "auto", md: "620px" }, minH: { base: "auto", md: "520px" }, maxH: "90vh", display: "flex", flexDirection: "column", bg: theme.colors.surfaceRaised, overflow: "hidden", children: [_jsx(ModalCloseButton, { top: 3, right: 3, zIndex: 2 }), _jsxs(Tabs, { index: selectedIndex, onChange: setSelectedIndex, variant: "unstyled", display: "flex", flexDirection: "column", flex: "1", minH: 0, children: [_jsxs(Box, { pt: 4, px: 4, children: [_jsx(Text, { fontWeight: 600, fontSize: "md", mb: 3, children: "Table Settings" }), _jsxs(TabList, { gap: 0, borderBottom: "1px solid", borderColor: raisedRule(theme.colors), children: [_jsx(Tab, { ...tabStyle, children: "Density" }), _jsx(Tab, { ...tabStyle, children: "Manage Columns" }), _jsx(Tab, { ...tabStyle, children: "Group" })] })] }), _jsx(ModalBody, { px: 4, py: 3, flex: "1", overflowY: "auto", sx: scrollbarStyles(theme.colors), children: _jsxs(TabPanels, { children: [_jsx(TabPanel, { px: 0, py: 1, children: _jsx(Flex, { direction: "column", gap: 2, children: DENSITY_OPTIONS.map((opt) => {
56
61
  const selected = density === opt.value;
57
62
  return (_jsxs(Flex, { as: "button", type: "button", align: "center", gap: 3, px: 3, py: 2.5, borderRadius: "lg", border: "1px solid", borderColor: selected ? theme.colors.accentText : theme.colors.boxborder[200], bg: selected ? rowBackgrounds.selected : theme.colors.transparent, transition: transitionFor(["background-color", "border-color"]), _hover: { borderColor: theme.colors.accentText }, onClick: () => onDensityChange === null || onDensityChange === void 0 ? void 0 : onDensityChange(opt.value), children: [_jsx(Box, { boxSize: "1.1rem", borderRadius: "full", border: "2px solid", borderColor: selected ? theme.colors.accentText : theme.colors.boxborder[500], display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: selected && _jsx(Check, { size: 11, color: theme.colors.accentText, strokeWidth: 3 }) }), _jsxs(Box, { textAlign: "left", children: [_jsx(Text, { fontSize: "13px", fontWeight: 600, color: theme.colors.text[700], children: opt.label }), _jsx(Text, { fontSize: "11px", color: theme.colors.textMuted, children: opt.desc })] })] }, opt.value));
58
63
  }) }) }), _jsx(TabPanel, { px: 0, py: 0, children: _jsx(Box, { sx: {
@@ -73,6 +78,6 @@ const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, g
73
78
  var _a;
74
79
  const selected = selectedGroup === opt.id;
75
80
  return (_jsxs(Flex, { as: "button", type: "button", align: "center", gap: 3, px: 3, py: 2.5, borderRadius: "lg", border: "1px solid", borderColor: selected ? theme.colors.accentText : theme.colors.boxborder[200], bg: selected ? rowBackgrounds.selected : theme.colors.transparent, transition: transitionFor(["background-color", "border-color"]), _hover: { borderColor: theme.colors.accentText }, onClick: () => setSelectedGroup(opt.id), children: [_jsx(Box, { boxSize: "1.1rem", borderRadius: "full", border: "2px solid", borderColor: selected ? theme.colors.accentText : theme.colors.boxborder[500], display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: selected && _jsx(Check, { size: 11, color: theme.colors.accentText, strokeWidth: 3 }) }), _jsx(Text, { fontSize: "13px", fontWeight: 600, color: theme.colors.text[700], textAlign: "left", children: opt.label })] }, String((_a = opt.id) !== null && _a !== void 0 ? _a : "__none__")));
76
- }) })] })] }) })] }), _jsxs(ModalFooter, { gap: "0.5rem", borderTop: "1px solid", borderColor: theme.colors.boxborder[200], pt: 3, pb: 3, px: 4, children: [_jsx(Button, { label: "Close", size: "sm", onClick: () => setSettingsOpen(false), variant: "outline", colorScheme: "red" }), _jsx(Button, { label: "Save", size: "sm", onClick: handleSave })] })] })] })] }));
81
+ }) })] })] }) })] }), _jsxs(ModalFooter, { gap: "0.5rem", borderTop: "1px solid", borderColor: raisedRule(theme.colors), pt: 3, pb: 3, px: 4, children: [_jsx(Button, { label: "Close", size: "sm", onClick: () => setSettingsOpen(false), variant: "outline", colorScheme: "red" }), _jsx(Button, { label: "Save", size: "sm", onClick: handleSave })] })] })] })] }));
77
82
  };
78
83
  export default TableSettings;
@@ -1,4 +1,5 @@
1
1
  import { accentTextOnCanvas } from "../../../Theme/tokens/builders/accentText.js";
2
+ import { cardRule } from "../../../Theme/tokens/builders/planeStep.js";
2
3
  import { getTableRowHoverStyle } from "../components/tableRowHoverStyle.js";
3
4
  import { stripeFill } from "./stripe.js";
4
5
  /**
@@ -16,14 +17,14 @@ export const classicPreset = (colors, isDark) => {
16
17
  textTransform: "capitalize",
17
18
  letterSpacing: "normal",
18
19
  height: "45px",
19
- ruleColor: colors.boxborder[200],
20
+ ruleColor: cardRule(colors),
20
21
  showColumnRule: true,
21
22
  actions: "always",
22
23
  },
23
24
  row: {
24
25
  hoverBg: getTableRowHoverStyle(colors, isDark).backgroundColor,
25
26
  hoverScope: "cell",
26
- ruleColor: colors.boxborder[200],
27
+ ruleColor: cardRule(colors),
27
28
  frozenRuleColor: colors.boxborder[300],
28
29
  selectedBg: colors.primary.opacity[16],
29
30
  selectedBarColor: colors.primary[500],
@@ -4,6 +4,7 @@ import { ArrowRight, FileText, IndianRupee, Paperclip, Pencil, PencilLine, Plus,
4
4
  import React from "react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
7
+ import { bandOn } from "../../Theme/tokens/builders/planeStep.js";
7
8
  import { AA_NON_TEXT, liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
8
9
  import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
9
10
  import { BORDER_WIDTHS } from "../../Theme/tokens/primitives/borderWidths.js";
@@ -152,12 +153,14 @@ const NoteItem = React.memo(function NoteItem({ note, event, index, colors, acti
152
153
  var _a, _b;
153
154
  const isEditing = activeEditNoteId === note.log_note_id;
154
155
  const isDeleting = deletingNoteId != null && deletingNoteId === note.log_note_id;
156
+ const noteChip = bandOn(colors.primary[50], colors.gray[50]);
157
+ const noteChipInk = accentTextOnCanvas(colors.primary, noteChip);
155
158
  if (isEditing) {
156
159
  return (_jsx(Box, { children: _jsx(NoteTextArea, { isEditable: true, value: (_a = note.note) !== null && _a !== void 0 ? _a : "", title: (_b = note.title) !== null && _b !== void 0 ? _b : "", saveButtonLoading: editNoteLoading, handleSubmit: (n, t, f) => onEditNote === null || onEditNote === void 0 ? void 0 : onEditNote(note.log_note_id, n, t, f, event, index), handleCancel: () => setActiveEditNoteId(null) }) }));
157
160
  }
158
161
  return (_jsxs(Box, { position: "relative", zIndex: 1, bg: colors.gray[50], border: `${BORDER_WIDTHS.hairline} solid ${colors.boxborder[200]}`, borderRadius: "lg", px: 2.5, py: 2, opacity: isDeleting ? 0.6 : 1, _hover: { ".timeline-note-actions": { opacity: 1 } }, _focusWithin: { ".timeline-note-actions": { opacity: 1 } }, children: [_jsxs(Flex, { align: "center", gap: 1.5, mb: note.note ? 1 : 0, children: [_jsx(Box, { as: "span", color: accentTextOnCanvas(colors.primary, colors.gray[50]), display: "inline-flex", children: _jsx(StickyNote, { size: 12 }) }), note.title && (_jsx(Text, { fontSize: fontSizes["xs-minus"], fontWeight: 700, color: colors.text[800], noOfLines: 1, children: note.title })), (onEditNote || onDeleteNote) && (_jsx(Flex, { className: "timeline-note-actions", align: "center", gap: 0.5, ml: "auto", flexShrink: 0, opacity: isDeleting ? 1 : 0, transition: REVEAL_TRANSITION, sx: reducedMotionSx(), children: isDeleting ? (_jsx(Spinner, { size: "xs", color: colors.textMuted })) : (_jsxs(_Fragment, { children: [onEditNote && (_jsx(Tooltip, { label: "Edit", placement: "top", hasArrow: true, children: _jsx(Box, { as: "button", type: "button", "aria-label": "Edit note", sx: focusVisibleStyles(colors), display: "inline-flex", alignItems: "center", justifyContent: "center", p: 1, borderRadius: "md", color: colors.textMuted, bg: "transparent", cursor: "pointer", _hover: {
159
- bg: colors.primary[50],
160
- color: accentTextOnCanvas(colors.primary, colors.primary[50]),
162
+ bg: noteChip,
163
+ color: noteChipInk,
161
164
  }, onClick: (e) => {
162
165
  e.stopPropagation();
163
166
  setActiveEditNoteId(note.log_note_id);
@@ -167,7 +170,7 @@ const NoteItem = React.memo(function NoteItem({ note, event, index, colors, acti
167
170
  }, onClick: (e) => {
168
171
  e.stopPropagation();
169
172
  onDeleteNote === null || onDeleteNote === void 0 ? void 0 : onDeleteNote(note.log_note_id, event, index);
170
- }, children: _jsx(Trash2, { size: 12 }) }) }))] })) }))] }), note.note && (_jsx(Text, { fontSize: fontSizes["xs-minus"], color: colors.text[700], whiteSpace: "pre-wrap", children: note.note })), note.attachments && note.attachments.length > 0 && (_jsx(Flex, { wrap: "wrap", gap: 1.5, mt: 1.5, children: note.attachments.map((att, attIndex) => (_jsxs(Flex, { as: "a", href: att.url, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), align: "center", gap: 1, px: 1.5, py: 0.5, borderRadius: "full", bg: colors.primary[50], color: accentTextOnCanvas(colors.primary, colors.primary[50]), fontSize: MIN_TEXT, maxW: "100%", _hover: { bg: colors.primary[100] }, children: [_jsx(Paperclip, { size: 10 }), _jsx(Box, { as: "span", noOfLines: 1, maxW: "9rem", children: att.name || "attachment" })] }, attIndex))) })), (note.created_by || note.created_at) && (_jsxs(Text, { fontSize: MIN_TEXT, color: colors.textMuted, mt: 1, children: [note.created_by ? formatName(note.created_by) : "", note.created_by && note.created_at ? " · " : "", note.created_at ? formatTimestamp(note.created_at, "time") : ""] }))] }));
173
+ }, children: _jsx(Trash2, { size: 12 }) }) }))] })) }))] }), note.note && (_jsx(Text, { fontSize: fontSizes["xs-minus"], color: colors.text[700], whiteSpace: "pre-wrap", children: note.note })), note.attachments && note.attachments.length > 0 && (_jsx(Flex, { wrap: "wrap", gap: 1.5, mt: 1.5, children: note.attachments.map((att, attIndex) => (_jsxs(Flex, { as: "a", href: att.url, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), align: "center", gap: 1, px: 1.5, py: 0.5, borderRadius: "full", bg: noteChip, color: noteChipInk, fontSize: MIN_TEXT, maxW: "100%", _hover: { bg: colors.primary[100] }, children: [_jsx(Paperclip, { size: 10 }), _jsx(Box, { as: "span", noOfLines: 1, maxW: "9rem", children: att.name || "attachment" })] }, attIndex))) })), (note.created_by || note.created_at) && (_jsxs(Text, { fontSize: MIN_TEXT, color: colors.textMuted, mt: 1, children: [note.created_by ? formatName(note.created_by) : "", note.created_by && note.created_at ? " · " : "", note.created_at ? formatTimestamp(note.created_at, "time") : ""] }))] }));
171
174
  });
172
175
  // The colored event card (shared by both the desktop "tree" and mobile rail).
173
176
  // `accent` decides which edge carries the colored bar (pointing toward the spine).
@@ -177,6 +180,7 @@ const EventCard = React.memo(function EventCard({ event, index, accent, colors,
177
180
  const changes = useMemo(() => parseChanges(event.changes), [event.changes]);
178
181
  const clickable = typeof onEventClick === "function";
179
182
  const actor = formatName(event.action_by);
183
+ const addNoteHover = bandOn(colors.primary[50], colors.background[50]);
180
184
  return (_jsxs(Box, { _hover: { ".timeline-add-note": { opacity: 1 } }, _focusWithin: { ".timeline-add-note": { opacity: 1 } }, children: [_jsxs(Box, { position: "relative", zIndex: 1, bg: colors.background[50], border: `${BORDER_WIDTHS.hairline} solid ${colors.boxborder[200]}`, borderInlineStartWidth: accent === "left" ? "0.1875rem" : undefined, borderInlineEndWidth: accent === "right" ? "0.1875rem" : undefined, borderInlineStartColor: accent === "left" ? scale[400] : undefined, borderInlineEndColor: accent === "right" ? scale[400] : undefined, borderRadius: "xl", px: 3.5, py: 2.5, ...(clickable && {
181
185
  transition: CARD_TRANSITION,
182
186
  _hover: {
@@ -189,7 +193,10 @@ const EventCard = React.memo(function EventCard({ event, index, accent, colors,
189
193
  e.stopPropagation();
190
194
  setActiveNoteEventIndex(isActiveNote ? null : index);
191
195
  }, position: "relative", zIndex: 1, opacity: isActiveNote ? 1 : 0, transition: REVEAL_TRANSITION, sx: { ...focusVisibleStyles(colors), ...reducedMotionSx() }, px: 2, py: 1, borderRadius: "md", fontSize: fontSizes.xs, fontWeight: 600, color: accentTextOnCanvas(colors.primary, colors.background[50]), bg: "transparent", cursor: "pointer", _hover: {
192
- bg: colors.primary[50],
196
+ bg: addNoteHover,
197
+ color: addNoteHover === colors.primary[50]
198
+ ? undefined
199
+ : accentTextOnCanvas(colors.primary, addNoteHover),
193
200
  }, children: isActiveNote ? "Hide note" : "Add note" }))] }), event.notes && event.notes.length > 0 && (_jsx(Flex, { direction: "column", gap: 2, mt: 2, pt: 2, borderTop: `${BORDER_WIDTHS.hairline} solid ${colors.boxborder[200]}`, children: event.notes.map((note, noteIndex) => {
194
201
  var _a;
195
202
  return (_jsx(NoteItem, { note: note, event: event, index: index, colors: colors, activeEditNoteId: activeEditNoteId, setActiveEditNoteId: setActiveEditNoteId, editNoteLoading: editNoteLoading, deletingNoteId: deletingNoteId, onEditNote: onEditNote, onDeleteNote: onDeleteNote }, (_a = note.log_note_id) !== null && _a !== void 0 ? _a : noteIndex));
@@ -7,9 +7,10 @@ import { CheckCircle2, AlertTriangle, Info, XCircle, } from "lucide-react";
7
7
  import Spinner from "../Spinner/Spinner.js";
8
8
  import { toastDuration } from "./toastDuration.js";
9
9
  import { REDUCED_MOTION_QUERY, reducedMotionSx } from "../../Theme/chakra/motion.js";
10
- import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
10
+ import { motionTransition, transitionFor } from "../../Theme/tokens/primitives/motion.js";
11
11
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
12
12
  import { resolveSoftTone } from "../../Theme/tokens/builders/tone.js";
13
+ import { compositeOver } from "../../Theme/tokens/builders/color.js";
13
14
  const ToasterContext = createContext(undefined);
14
15
  const shrink = keyframes `
15
16
  from { transform: scaleX(1); }
@@ -17,11 +18,13 @@ const shrink = keyframes `
17
18
  `;
18
19
  // One-shot ring pulse on the status icon — a subtle "just happened" beat.
19
20
  const iconPulse = keyframes `
20
- 0% { box-shadow: 0 0 0 0 var(--toast-pulse-color); }
21
- 70% { box-shadow: 0 0 0 0.5rem transparent; }
22
- 100% { box-shadow: 0 0 0 0 transparent; }
21
+ 0% { transform: scale(1); opacity: 1; }
22
+ 70% { transform: scale(1.5); opacity: 0; }
23
+ 100% { transform: scale(1.5); opacity: 0; }
23
24
  `;
24
25
  const MotionBox = motion(Box);
26
+ const TOAST_ENTER = motionTransition("enter", "out");
27
+ const TOAST_EXIT = motionTransition("exit", "in");
25
28
  // Presentational toast card — owns hover state so auto-dismiss pauses while the pointer is over it.
26
29
  function ToastCard({ onClose, title, description, actions, isClosable, duration, meta, colors: c, isUrgent, }) {
27
30
  const [paused, setPaused] = useState(false);
@@ -33,15 +36,23 @@ function ToastCard({ onClose, title, description, actions, isClosable, duration,
33
36
  , {
34
37
  // The single live-region root: an explicit aria-live here, on the card's own
35
38
  // root, keeps errors from being announced a second time by a duplicate wrapper.
36
- role: isUrgent ? "alert" : undefined, "aria-live": isUrgent ? "assertive" : undefined, initial: { opacity: 0, x: 24 }, animate: { opacity: 1, x: 0 }, exit: { opacity: 0, x: 24 }, transition: { duration: 0.24, ease: [0.22, 1, 0.36, 1] }, onHoverStart: () => setPaused(true), onHoverEnd: () => setPaused(false), position: "relative", bg: c.surfaceRaised, border: `0.0625rem solid ${c.boxborder[200]}`, boxShadow: "md", borderRadius: "xl", overflow: "hidden", minW: "22.5rem", maxW: "26rem", sx: {
39
+ role: isUrgent ? "alert" : undefined, "aria-live": isUrgent ? "assertive" : undefined, initial: { opacity: 0, x: 24 }, animate: { opacity: 1, x: 0 }, exit: { opacity: 0, x: 24, transition: TOAST_EXIT }, transition: TOAST_ENTER, onHoverStart: () => setPaused(true), onHoverEnd: () => setPaused(false), position: "relative", bg: c.surfaceRaised, border: `0.0625rem solid ${c.boxborder[200]}`, boxShadow: "md", borderRadius: "xl", overflow: "hidden", minW: "22.5rem", maxW: "26rem", sx: {
37
40
  isolation: "isolate",
38
41
  transition: transitionFor(["box-shadow"]),
39
42
  _hover: { boxShadow: "lg" },
40
43
  ...reducedMotionSx(),
41
- }, children: [_jsxs(Flex, { p: 3.5, gap: 3, align: actions ? "flex-start" : "center", children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "2rem", minW: "2rem", borderRadius: "full", bg: tone.bg, color: tone.fg, sx: {
42
- ["--toast-pulse-color"]: tone.border,
43
- animation: `${iconPulse} 900ms ease-out 1`,
44
- ...reducedMotionSx(),
44
+ }, children: [_jsxs(Flex, { p: 3.5, gap: 3, align: actions ? "flex-start" : "center", children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "2rem", minW: "2rem", borderRadius: "full", position: "relative", bg: compositeOver(tone.bg, c.surfaceRaised), color: tone.fg, sx: {
45
+ "&::after": {
46
+ content: '""',
47
+ position: "absolute",
48
+ inset: 0,
49
+ borderRadius: "full",
50
+ bg: tone.border,
51
+ zIndex: -1,
52
+ opacity: 0,
53
+ animation: `${iconPulse} 900ms ease-out 1`,
54
+ ...reducedMotionSx(),
55
+ },
45
56
  }, children: meta.icon }), _jsxs(VisuallyHidden, { children: [meta.label, ":"] }), _jsxs(Box, { flex: "1", minW: 0, children: [title && (_jsx(Text, { fontWeight: 600, fontSize: "0.875rem", lineHeight: "1.3", color: c.text[800], children: title })), description && (_jsx(Text, { fontSize: "0.8125rem", lineHeight: "1.45", color: c.textMuted, mt: title ? "0.125rem" : 0, children: description })), actions && (_jsx(Flex, { gap: 2, mt: 2.5, align: "center", wrap: "wrap", children: actions(onClose) }))] }), isClosable && (_jsx(CloseButton, { onClick: onClose, size: "sm", color: c.textMuted, borderRadius: "md", alignSelf: "flex-start", _hover: {
46
57
  bg: c.gray[100],
47
58
  color: c.text[700],
@@ -8,9 +8,12 @@ import ToolTip from "../ToolTip/ToolTip.js";
8
8
  import { useSlidingPill } from "../SegmentedControl/useSlidingPill.js";
9
9
  import { BUTTON_SIZES } from "../../Theme/tokens/primitives/controlSizes.js";
10
10
  import { BORDER_WIDTHS } from "../../Theme/tokens/primitives/borderWidths.js";
11
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
11
12
  const MODES = ["grid", "list"];
12
13
  const TRACK_HEIGHT = BUTTON_SIZES.sm.height;
13
14
  const SEGMENT_HEIGHT = `calc(${TRACK_HEIGHT} - 0.25rem)`;
15
+ const INK_TRANSITION = transitionFor(["color"], "base");
16
+ const PILL_TRANSITION = transitionFor(["transform", "width"], "base", "out");
14
17
  /** Two icon-only IconButtons (Grid/List), aria-pressed marks the active one; shares variant with SegmentedControl (see MODULE.md). */
15
18
  const TableToggle = ({ value, onChange, variant = "default" }) => {
16
19
  const theme = useCustomTheme();
@@ -71,10 +74,10 @@ const TableToggle = ({ value, onChange, variant = "default" }) => {
71
74
  ? colors.accentText
72
75
  : hoverInk,
73
76
  },
74
- transition: "color 0.2s ease-in-out",
77
+ transition: INK_TRANSITION,
75
78
  }),
76
79
  };
77
- return (_jsxs(Box, { ref: trackRef, ...styles.container, children: [isBrandSlide && pill && (_jsx(Box, { "aria-hidden": "true", position: "absolute", top: "0.125rem", left: 0, h: SEGMENT_HEIGHT, w: `${pill.width}px`, borderRadius: "lg", bg: brandFill.fill, boxShadow: `0 0.125rem 0.5rem ${colors.boxShadow.primary}`, transform: `translateX(${pill.left}px)`, transition: "transform 0.24s cubic-bezier(0.2, 0.8, 0.2, 1), width 0.24s cubic-bezier(0.2, 0.8, 0.2, 1)" })), isUnderlineSlide && pill && (_jsx(Box, { "aria-hidden": "true", position: "absolute", bottom: `-${BORDER_WIDTHS.hairline}`, left: 0, h: "0.125rem", w: `${pill.width}px`, borderRadius: "full", bg: colors.primary[500], transform: `translateX(${pill.left}px)`, transition: "transform 0.24s cubic-bezier(0.2, 0.8, 0.2, 1), width 0.24s cubic-bezier(0.2, 0.8, 0.2, 1)" })), _jsx(ToolTip, { label: "Grid View", placement: "top", fontSize: "xs", hasArrow: true, children: _jsx(IconButton, { ref: (node) => {
80
+ return (_jsxs(Box, { ref: trackRef, ...styles.container, children: [isBrandSlide && pill && (_jsx(Box, { "aria-hidden": "true", position: "absolute", top: "0.125rem", left: 0, h: SEGMENT_HEIGHT, w: `${pill.width}px`, borderRadius: "lg", bg: brandFill.fill, boxShadow: `0 0.125rem 0.5rem ${colors.boxShadow.primary}`, transform: `translateX(${pill.left}px)`, transition: PILL_TRANSITION })), isUnderlineSlide && pill && (_jsx(Box, { "aria-hidden": "true", position: "absolute", bottom: `-${BORDER_WIDTHS.hairline}`, left: 0, h: "0.125rem", w: `${pill.width}px`, borderRadius: "full", bg: colors.primary[500], transform: `translateX(${pill.left}px)`, transition: PILL_TRANSITION })), _jsx(ToolTip, { label: "Grid View", placement: "top", fontSize: "xs", hasArrow: true, children: _jsx(IconButton, { ref: (node) => {
78
81
  refs.current[0] = node;
79
82
  }, "aria-label": "Grid View", "aria-pressed": value === "grid", icon: _jsx(Table2, { size: "1.25rem" }), variant: "ghost", onClick: () => onChange("grid"), ...styles.button("grid") }) }), _jsx(ToolTip, { label: "List View", placement: "top", fontSize: "xs", hasArrow: true, children: _jsx(IconButton, { ref: (node) => {
80
83
  refs.current[1] = node;
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
3
  import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, ModalFooter, FormControl, VStack, } from "@chakra-ui/react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ import { raisedRule } from "../../Theme/tokens/builders/surfaceRaised.js";
5
6
  import Button from "../Button/Button.js";
6
7
  import TextInput from "../Input/TextInput.js";
7
8
  import SearchSelect from "../SearchSelect/SearchSelect.js";
@@ -75,7 +76,7 @@ const AddUserModal = ({ isOpen, onClose, roleOptions, isLoading, onSubmit, onAdd
75
76
  type: "email",
76
77
  },
77
78
  ];
78
- return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, trapFocus: false, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [_jsxs(ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], children: [labels.addNewUser, upgradeNotice] }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 5, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [textFields.map((field) => (_jsx(FormControl, { isInvalid: !!errors[field.id], children: _jsx(TextInput, { id: field.id, name: field.id, type: field.type, label: field.label, placeholder: field.placeholder, value: values[field.id], onChange: handleChange(field.id), isRequired: true, error: !!errors[field.id], errorMessage: errors[field.id], width: "100%" }) }, field.id))), _jsx(FormControl, { isInvalid: !!errors.role, isRequired: true, children: _jsx(SearchSelect, { label: labels.role, options: roleOptions.map((item) => ({
79
+ return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, trapFocus: false, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [_jsxs(ModalHeader, { borderBottom: "1px solid", borderColor: raisedRule(colors), children: [labels.addNewUser, upgradeNotice] }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 5, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [textFields.map((field) => (_jsx(FormControl, { isInvalid: !!errors[field.id], children: _jsx(TextInput, { id: field.id, name: field.id, type: field.type, label: field.label, placeholder: field.placeholder, value: values[field.id], onChange: handleChange(field.id), isRequired: true, error: !!errors[field.id], errorMessage: errors[field.id], width: "100%" }) }, field.id))), _jsx(FormControl, { isInvalid: !!errors.role, isRequired: true, children: _jsx(SearchSelect, { label: labels.role, options: roleOptions.map((item) => ({
79
80
  id: item.id,
80
81
  label: item.label,
81
82
  })), value: (_a = values.role) !== null && _a !== void 0 ? _a : undefined, onSelect: (option) => {
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
3
  import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, ModalFooter, FormControl, VStack, } from "@chakra-ui/react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ import { raisedRule } from "../../Theme/tokens/builders/surfaceRaised.js";
5
6
  import Button from "../Button/Button.js";
6
7
  import TextInput from "../Input/TextInput.js";
7
8
  import SearchSelect from "../SearchSelect/SearchSelect.js";
@@ -31,7 +32,7 @@ const ChangeRoleModal = ({ isOpen, onClose, userId, email, currentRole, roleOpti
31
32
  return;
32
33
  await (onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit({ userId, roleId: selectedRole.id }));
33
34
  };
34
- return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, trapFocus: false, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [_jsx(ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], children: labels.changeRoleTitle }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 5, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsx(TextInput, { label: labels.email, value: email !== null && email !== void 0 ? email : "", isDisabled: true, width: "100%" }), _jsx(FormControl, { isInvalid: !!error, isRequired: true, children: _jsx(SearchSelect, { label: labels.role, options: roleOptions.map((item) => ({
35
+ return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, trapFocus: false, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [_jsx(ModalHeader, { borderBottom: "1px solid", borderColor: raisedRule(colors), children: labels.changeRoleTitle }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 5, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsx(TextInput, { label: labels.email, value: email !== null && email !== void 0 ? email : "", isDisabled: true, width: "100%" }), _jsx(FormControl, { isInvalid: !!error, isRequired: true, children: _jsx(SearchSelect, { label: labels.role, options: roleOptions.map((item) => ({
35
36
  id: item.id,
36
37
  label: item.label,
37
38
  })), value: selectedRole !== null && selectedRole !== void 0 ? selectedRole : undefined, onSelect: (option) => {
@@ -6,6 +6,7 @@ import { ChevronLeft, RefreshCw, Send, Shield, Trash2, UserPlus, Users, UserRoun
6
6
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
7
7
  import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
8
8
  import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
9
+ import { bandOn } from "../../Theme/tokens/builders/planeStep.js";
9
10
  import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
10
11
  import { focusVisibleRing } from "../../Theme/chakra/focusRing.styles.js";
11
12
  import EmptyState from "../EmptyState/EmptyState.js";
@@ -60,6 +61,7 @@ const UserDetails = ({ users, selectedUser, selectedUserId, roleOptions = [], ca
60
61
  const [actionUserId, setActionUserId] = useState(null);
61
62
  const border = colors.boxborder[200];
62
63
  const surface = colors.background[50];
64
+ const detailTile = bandOn(colors.primary[50], surface);
63
65
  const rowBackgrounds = useMemo(() => listRowBackgrounds(colors), [colors]);
64
66
  const muted = colors.textMuted;
65
67
  const heading = colors.text[900];
@@ -100,7 +102,7 @@ const UserDetails = ({ users, selectedUser, selectedUserId, roleOptions = [], ca
100
102
  const Icon = (_a = detail.icon) !== null && _a !== void 0 ? _a : UserRound;
101
103
  return (_jsxs(React.Fragment, { children: [_jsxs(Flex, { gap: 3, px: 3, py: 2.5, _hover: {
102
104
  bg: resolveHoverTint(colors.gray[50], surface),
103
- }, alignItems: "center", transition: "background 0.15s ease", children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "30px", bg: colors.primary[50], borderRadius: "lg", color: accentTextOnCanvas(colors.primary, colors.primary[50]), flexShrink: 0, children: _jsx(Icon, { size: 15 }) }), _jsx(Box, { minWidth: "110px", children: _jsx(Text, { fontSize: "xs", fontWeight: 600, color: muted, children: detail.label }) }), _jsx(Box, { flex: 1, children: _jsx(Text, { fontSize: "sm", color: heading, fontWeight: 500, children: detail.value }) })] }), index < selectedUser.details.length - 1 && (_jsx(Divider, { borderColor: border }))] }, index));
105
+ }, alignItems: "center", transition: "background 0.15s ease", children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "30px", bg: detailTile, borderRadius: "lg", color: accentTextOnCanvas(colors.primary, detailTile), flexShrink: 0, children: _jsx(Icon, { size: 15 }) }), _jsx(Box, { minWidth: "110px", children: _jsx(Text, { fontSize: "xs", fontWeight: 600, color: muted, children: detail.label }) }), _jsx(Box, { flex: 1, children: _jsx(Text, { fontSize: "sm", color: heading, fontWeight: 500, children: detail.value }) })] }), index < selectedUser.details.length - 1 && (_jsx(Divider, { borderColor: border }))] }, index));
104
106
  }) })] })] })) : (_jsx(EmptyState, { icon: UserRound, title: labels.selectTeamMember, description: labels.noUserSelected, minH: "300px" })) })] }), _jsx(AddUserModal, { isOpen: isAddUserOpen, onClose: onAddUserClose, roleOptions: roleOptions, isLoading: isAddUserLoading, onSubmit: async (values) => {
105
107
  await (onAddUserSubmit === null || onAddUserSubmit === void 0 ? void 0 : onAddUserSubmit(values));
106
108
  onAddUserClose();
@@ -36,10 +36,13 @@ const variants = {
36
36
  outline: definePartsStyle({
37
37
  container: { [$border.variable]: "1px", [$shadow.variable]: "none" },
38
38
  }),
39
+ elevated: definePartsStyle({
40
+ container: { [$border.variable]: "0", [$shadow.variable]: "shadows.card" },
41
+ }),
39
42
  };
40
43
  export const Card = defineMultiStyleConfig({
41
44
  baseStyle,
42
45
  sizes,
43
46
  variants,
44
- defaultProps: { variant: "outline", size: "md" },
47
+ defaultProps: { variant: "elevated", size: "md" },
45
48
  });
@@ -3,6 +3,7 @@ import { menuAnatomy } from "@chakra-ui/anatomy";
3
3
  import { listRowBackgrounds } from "../tokens/builders/rowStates.js";
4
4
  import { OPTION_ROW_SIZES, OPTION_ROW_RADIUS } from "../tokens/primitives/optionRowSizes.js";
5
5
  import { paletteOf } from "./paletteFromTheme.js";
6
+ import { POPUP_SURFACE } from "./overlay.styles.js";
6
7
  const itemRowSpec = OPTION_ROW_SIZES.sm;
7
8
  const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(menuAnatomy.keys);
8
9
  const $bg = cssVar("menu-bg");
@@ -21,12 +22,14 @@ const baseStyle = definePartsStyle(({ theme }) => {
21
22
  borderWidth: "1px",
22
23
  borderStyle: "solid",
23
24
  borderColor: colors.boxborder[200],
25
+ ...POPUP_SURFACE,
24
26
  },
25
27
  item: {
26
28
  minH: itemRowSpec.minH,
27
29
  px: itemRowSpec.px,
28
30
  py: itemRowSpec.py,
29
31
  mx: itemRowSpec.mx,
32
+ width: `calc(100% - 2 * ${itemRowSpec.mx})`,
30
33
  fontSize: itemRowSpec.fontSize,
31
34
  borderRadius: OPTION_ROW_RADIUS,
32
35
  bg: "transparent",
@@ -1,6 +1,7 @@
1
1
  import { createMultiStyleConfigHelpers, cssVar } from "@chakra-ui/react";
2
2
  import { popoverAnatomy } from "@chakra-ui/anatomy";
3
3
  import { paletteOf } from "./paletteFromTheme.js";
4
+ import { POPUP_SURFACE } from "./overlay.styles.js";
4
5
  const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(popoverAnatomy.keys);
5
6
  const $popperBg = cssVar("popper-bg");
6
7
  const $arrowShadowColor = cssVar("popper-arrow-shadow-color");
@@ -16,6 +17,7 @@ const baseStyle = definePartsStyle(({ theme }) => {
16
17
  borderWidth: "1px",
17
18
  borderStyle: "solid",
18
19
  borderColor: colors.boxborder[200],
20
+ ...POPUP_SURFACE,
19
21
  },
20
22
  };
21
23
  });
@@ -12,6 +12,7 @@ import { AA_NORMAL_TEXT, accentTextOnCanvas, isDarkCanvas } from "../tokens/buil
12
12
  import { labelOnFill, solidFillRung } from "../tokens/builders/filledSurface.js";
13
13
  import { liftToContrast, resolveHoverTint } from "../tokens/builders/outlineRung.js";
14
14
  import { resolveSoftTone } from "../tokens/builders/tone.js";
15
+ import { skeletonShimmer } from "../tokens/builders/skeletonShimmer.js";
15
16
  import { tooltipSurface } from "../tokens/builders/tooltipSurface.js";
16
17
  import { Drawer } from "./Drawer.styles.js";
17
18
  import { Menu } from "./Menu.styles.js";
@@ -142,12 +143,15 @@ const $skeletonStart = cssVar("skeleton-start-color");
142
143
  const $skeletonEnd = cssVar("skeleton-end-color");
143
144
  // NOTE: fixes Chakra's Skeleton hardcoding gray.100/.400 via `_dark` (dead here) — an explicit startColor/endColor prop still wins.
144
145
  const Skeleton = {
145
- baseStyle: ({ theme }) => ({
146
- [$skeletonStart.variable]: paletteOf(theme).gray[100],
147
- [$skeletonEnd.variable]: paletteOf(theme).gray[300],
148
- background: $skeletonStart.reference,
149
- borderColor: $skeletonEnd.reference,
150
- }),
146
+ baseStyle: ({ theme }) => {
147
+ const shimmer = skeletonShimmer(paletteOf(theme));
148
+ return {
149
+ [$skeletonStart.variable]: shimmer.start,
150
+ [$skeletonEnd.variable]: shimmer.end,
151
+ background: $skeletonStart.reference,
152
+ borderColor: $skeletonEnd.reference,
153
+ };
154
+ },
151
155
  };
152
156
  // NOTE: uses Chakra's own shorthand style keys (bg/w/h/pos) + !important — extendTheme deep-merges by key, so mismatched keys let Chakra's stock value win.
153
157
  const Radio = {
@@ -1,5 +1,6 @@
1
1
  import { useMatchMedia } from "../../Hooks/useMatchMedia.js";
2
2
  export const REDUCED_MOTION_QUERY = "@media (prefers-reduced-motion: reduce)";
3
+ export const MOTION_OK_QUERY = "@media (prefers-reduced-motion: no-preference)";
3
4
  const MEDIA = "(prefers-reduced-motion: reduce)";
4
5
  export const usePrefersReducedMotion = () => useMatchMedia(MEDIA, false);
5
6
  /** Spread into `sx`: drops transitions and animations when the user asks for less motion. */
@@ -1,6 +1,9 @@
1
1
  import { overlayScrim } from "../tokens/builders/scrim.js";
2
2
  import { raisedRule } from "../tokens/builders/surfaceRaised.js";
3
+ import { RADIUS_ROLE } from "../tokens/primitives/radii.js";
3
4
  export const OVERLAY_BLUR = "blur(4px)";
5
+ /** Radius and elevation every anchored popup shares: menus, popovers, selects, dropdowns. */
6
+ export const POPUP_SURFACE = { borderRadius: RADIUS_ROLE.float, boxShadow: "md" };
4
7
  /** The one Modal/Drawer backdrop; reuse it for any custom full-screen scrim. */
5
8
  export const overlayScrimStyles = (colors) => ({
6
9
  bg: overlayScrim(colors),
@@ -27,9 +27,25 @@ import { withSurfaceRungs } from "../builders/surfaceRungs.js";
27
27
  import { buildSurfaceRaised, withSurfaceRaised } from "../builders/surfaceRaised.js";
28
28
  import { buildStar } from "../builders/star.js";
29
29
  import { lazyPalette } from "../builders/lazy.js";
30
+ import { contrastRatio, mix } from "../builders/color.js";
31
+ export const LIGHT_CANVAS_STEP = 1.09;
32
+ const CANVAS_MIX_STEP = 0.0025;
33
+ const CANVAS_MIX_MAX = 0.5;
34
+ const lightCanvas = (canvas, card, ink) => {
35
+ for (let weight = 0; weight < CANVAS_MIX_MAX; weight += CANVAS_MIX_STEP) {
36
+ const next = mix(canvas, ink, weight);
37
+ if (contrastRatio(next, card) >= LIGHT_CANVAS_STEP)
38
+ return next;
39
+ }
40
+ return mix(canvas, ink, CANVAS_MIX_MAX);
41
+ };
30
42
  /** Derived, never hand-written: a copied hex goes stale the moment a canvas moves. */
31
43
  export const finalizeLightPalette = (source) => ({
32
44
  ...source,
45
+ backgroundColor: {
46
+ ...source.backgroundColor,
47
+ base: lightCanvas(source.backgroundColor.base, source.background[50], source.text[900]),
48
+ },
33
49
  sidebar: withSidebarTokens(source),
34
50
  accentText: pickAccentText(source.primary, source.backgroundColor.main),
35
51
  textMuted: buildMutedText(source.text, source.backgroundColor.main),
@@ -15,8 +15,22 @@ const primary = {
15
15
  900: "#531a14",
16
16
  opacity: buildPrimaryOpacity(PRIMARY_500),
17
17
  };
18
+ const danger = {
19
+ 50: "#fcedf3",
20
+ 100: "#f5c5db",
21
+ 200: "#f1a9ca",
22
+ 300: "#ec82b4",
23
+ 400: "#ea69a7",
24
+ 500: "#e74494",
25
+ 600: "#d23e87",
26
+ 700: "#a43069",
27
+ 800: "#7f2651",
28
+ 900: "#611c3e",
29
+ };
18
30
  const palette = {
19
31
  ...neutralTokens,
32
+ red: danger,
33
+ semantic: { ...neutralTokens.semantic, error: danger },
20
34
  ...buildBrandInk(PRIMARY_500),
21
35
  // NOTE: stops retuned so white gradient-button text clears AA at both ends — original let it drop to 4.37/2.15.
22
36
  gradient: { from: "#cd4733", to: "#a36807" }, // terracotta red → amber
@@ -118,6 +132,7 @@ const palette = {
118
132
  boxShadow: {
119
133
  primary: buildPrimaryShadowTint(PRIMARY_500),
120
134
  ...sharedBoxShadow,
135
+ error: `${danger[500]}47`,
121
136
  },
122
137
  };
123
138
  export default palette;
@@ -1,18 +1,18 @@
1
1
  import { neutralTokens, sharedBoxShadow } from "../neutrals.js";
2
2
  import { buildPrimaryOpacity, buildPrimaryShadowTint } from "../../builders/buildBrandTokens.js";
3
3
  import { buildBrandInk } from "../../builders/brandInk.js";
4
- const PRIMARY_500 = "#d16a7e"; // muted warm rose (not neon pink)
4
+ const PRIMARY_500 = "#cb6b94";
5
5
  const primary = {
6
- 50: "#fdf2f5",
7
- 100: "#f9d6de",
8
- 200: "#f2aaba",
9
- 300: "#ea7f96",
10
- 400: "#de627d",
6
+ 50: "#fcf2f7",
7
+ 100: "#f6d6e5",
8
+ 200: "#edabc9",
9
+ 300: "#e480ad",
10
+ 400: "#d76398",
11
11
  500: PRIMARY_500,
12
- 600: "#b9556b",
13
- 700: "#984558",
14
- 800: "#763646",
15
- 900: "#552634",
12
+ 600: "#b35681",
13
+ 700: "#93466a",
14
+ 800: "#723754",
15
+ 900: "#52273e",
16
16
  opacity: buildPrimaryOpacity(PRIMARY_500),
17
17
  };
18
18
  const palette = {