pixelize-design-library 2.4.2-beta.34 → 2.4.2-beta.35

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 (84) hide show
  1. package/dist/Components/AppSwitcher/AppSwitcher.js +10 -4
  2. package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -3
  3. package/dist/Components/Common/fieldStyles.js +1 -1
  4. package/dist/Components/CopyButton/CopyButton.js +7 -6
  5. package/dist/Components/DatePicker/CalendarPanel.js +8 -5
  6. package/dist/Components/DatePicker/RangeDatePicker.js +27 -3
  7. package/dist/Components/DatePicker/SingleDatePicker.js +48 -14
  8. package/dist/Components/DatePicker/TimeOnlyPicker.js +7 -1
  9. package/dist/Components/DatePicker/TimePicker.js +3 -3
  10. package/dist/Components/DatePicker/TimePickerInput.js +1 -1
  11. package/dist/Components/Dropdown/DropDown.js +19 -6
  12. package/dist/Components/EmptyState/EmptyState.js +1 -1
  13. package/dist/Components/FileUpload/FileUpload.js +2 -2
  14. package/dist/Components/FilterSidebar/FilterSidebar.js +5 -5
  15. package/dist/Components/FilterSidebar/filterHoverStyle.d.ts +2 -1
  16. package/dist/Components/FilterSidebar/filterHoverStyle.js +3 -4
  17. package/dist/Components/Input/TextInput.styles.js +2 -2
  18. package/dist/Components/InputTextArea/InputTextArea.style.js +2 -2
  19. package/dist/Components/MoreItems/MoreItems.js +3 -1
  20. package/dist/Components/MultiSelect/MultiSelect.js +2 -2
  21. package/dist/Components/NavigationBar/NavigationBar.js +6 -7
  22. package/dist/Components/NumberInput/NumberInput.styles.js +2 -2
  23. package/dist/Components/OrgSwitcher/OrgSwitcher.js +14 -10
  24. package/dist/Components/PdfViewer/PdfViewer.js +4 -4
  25. package/dist/Components/RolesPermission/RolesPermission.js +4 -3
  26. package/dist/Components/SearchSelect/SearchSelect.js +46 -41
  27. package/dist/Components/Select/Select.styles.js +1 -1
  28. package/dist/Components/SelectSearch/SelectSearch.js +35 -17
  29. package/dist/Components/SelectV2/SelectV2.js +3 -0
  30. package/dist/Components/Table/TableProps.d.ts +2 -0
  31. package/dist/Components/Table/components/TableBody.js +7 -10
  32. package/dist/Components/Table/filters/CompactSelect.js +29 -8
  33. package/dist/Components/Table/settings/ManageColumns.js +5 -3
  34. package/dist/Components/Table/settings/TableSettings.js +4 -2
  35. package/dist/Components/Trail/EditableCell.js +1 -1
  36. package/dist/Components/UserDetails/DeactivateConfirmModal.js +1 -1
  37. package/dist/Components/UserDetails/UserDetails.js +5 -3
  38. package/dist/Hooks/exclusiveOverlay.d.ts +4 -0
  39. package/dist/Hooks/exclusiveOverlay.js +22 -0
  40. package/dist/Hooks/useExclusiveOverlay.d.ts +5 -0
  41. package/dist/Hooks/useExclusiveOverlay.js +24 -0
  42. package/dist/Theme/chakra/Menu.styles.js +4 -2
  43. package/dist/Utils/table.d.ts +3 -0
  44. package/dist/Utils/table.js +44 -1
  45. package/dist/esm/Components/AppSwitcher/AppSwitcher.js +11 -5
  46. package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -3
  47. package/dist/esm/Components/Common/fieldStyles.js +1 -1
  48. package/dist/esm/Components/CopyButton/CopyButton.js +7 -6
  49. package/dist/esm/Components/DatePicker/CalendarPanel.js +9 -6
  50. package/dist/esm/Components/DatePicker/RangeDatePicker.js +28 -4
  51. package/dist/esm/Components/DatePicker/SingleDatePicker.js +49 -15
  52. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +7 -1
  53. package/dist/esm/Components/DatePicker/TimePicker.js +3 -3
  54. package/dist/esm/Components/DatePicker/TimePickerInput.js +1 -1
  55. package/dist/esm/Components/Dropdown/DropDown.js +20 -7
  56. package/dist/esm/Components/EmptyState/EmptyState.js +1 -1
  57. package/dist/esm/Components/FileUpload/FileUpload.js +2 -2
  58. package/dist/esm/Components/FilterSidebar/FilterSidebar.js +5 -5
  59. package/dist/esm/Components/FilterSidebar/filterHoverStyle.js +3 -4
  60. package/dist/esm/Components/Input/TextInput.styles.js +2 -2
  61. package/dist/esm/Components/InputTextArea/InputTextArea.style.js +2 -2
  62. package/dist/esm/Components/MoreItems/MoreItems.js +3 -1
  63. package/dist/esm/Components/MultiSelect/MultiSelect.js +2 -2
  64. package/dist/esm/Components/NavigationBar/NavigationBar.js +6 -7
  65. package/dist/esm/Components/NumberInput/NumberInput.styles.js +2 -2
  66. package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +14 -10
  67. package/dist/esm/Components/PdfViewer/PdfViewer.js +4 -4
  68. package/dist/esm/Components/RolesPermission/RolesPermission.js +4 -3
  69. package/dist/esm/Components/SearchSelect/SearchSelect.js +46 -41
  70. package/dist/esm/Components/Select/Select.styles.js +1 -1
  71. package/dist/esm/Components/SelectSearch/SelectSearch.js +35 -17
  72. package/dist/esm/Components/SelectV2/SelectV2.js +3 -0
  73. package/dist/esm/Components/Table/components/TableBody.js +7 -10
  74. package/dist/esm/Components/Table/filters/CompactSelect.js +29 -8
  75. package/dist/esm/Components/Table/settings/ManageColumns.js +5 -3
  76. package/dist/esm/Components/Table/settings/TableSettings.js +5 -3
  77. package/dist/esm/Components/Trail/EditableCell.js +1 -1
  78. package/dist/esm/Components/UserDetails/DeactivateConfirmModal.js +1 -1
  79. package/dist/esm/Components/UserDetails/UserDetails.js +5 -3
  80. package/dist/esm/Hooks/exclusiveOverlay.js +16 -0
  81. package/dist/esm/Hooks/useExclusiveOverlay.js +20 -0
  82. package/dist/esm/Theme/chakra/Menu.styles.js +4 -2
  83. package/dist/esm/Utils/table.js +45 -3
  84. package/package.json +1 -1
@@ -1,10 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { forwardRef, useCallback, useEffect, useId, useRef, useState } from "react";
2
+ import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
3
  import { Box, Flex, Button, useDisclosure, List, ListItem, Portal, } from "@chakra-ui/react";
4
4
  import { motion } from "framer-motion";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { scrollbarStyles } from "../../Theme/tokens/builders/scrollbar.js";
7
- import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
7
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
8
+ import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
8
9
  import { ChevronDown } from "lucide-react";
9
10
  import { rafThrottle } from "../../Utils/rafThrottle.js";
10
11
  const MotionBox = motion(forwardRef((props, ref) => (_jsx(Box, { ref: ref, ...props }))));
@@ -19,7 +20,9 @@ const SIZE_MAP = {
19
20
  const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleOptionSelect, dropdownType = "button", text, DropdownIcon, isVisibleIconShow = true, buttonProps, headStyle, ListStyle, ItemStyle, LabelStyle, ImageStyle, size, optionsSize, divider = false, ariaLabel, }, ref) => {
20
21
  var _a, _b;
21
22
  const theme = useCustomTheme();
22
- const { isOpen, onOpen, onToggle, onClose } = useDisclosure();
23
+ const rowBackgrounds = useMemo(() => listRowBackgrounds(theme.colors), [theme.colors]);
24
+ const { isOpen, onOpen, onClose } = useDisclosure();
25
+ const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
23
26
  const dropdownRef = useRef(null);
24
27
  const menuRef = useRef(null);
25
28
  const [menuPos, setMenuPos] = useState({ top: 0, left: 0, width: 0 });
@@ -49,6 +52,16 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
49
52
  }
50
53
  else {
51
54
  pendingFocusIndex.current = index;
55
+ requestExclusiveOpen();
56
+ onOpen();
57
+ }
58
+ };
59
+ const handleToggle = () => {
60
+ if (isOpen) {
61
+ onClose();
62
+ }
63
+ else {
64
+ requestExclusiveOpen();
52
65
  onOpen();
53
66
  }
54
67
  };
@@ -91,7 +104,7 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
91
104
  // `fireEvent` does not simulate a real browser's Enter/Space-activates-
92
105
  // button default action either.
93
106
  e.preventDefault();
94
- onToggle();
107
+ handleToggle();
95
108
  }
96
109
  };
97
110
  const handleMenuKeyDown = (e) => {
@@ -207,13 +220,13 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
207
220
  };
208
221
  const Chevron = isVisibleIconShow ? (_jsx(Box, { as: "span", display: "inline-flex", transition: "transform 0.2s ease", transform: isOpen ? "rotate(180deg)" : "rotate(0deg)", children: _jsx(ChevronDown, { size: s.chevron }) })) : undefined;
209
222
  const dropDownToggleOption = () => {
210
- const ButtonToggle = (_jsx(Button, { ref: buttonTriggerRef, onClick: onToggle, onKeyDown: handleTriggerKeyDown, size: s.btn, colorScheme: "primary", borderRadius: "lg", fontWeight: 600, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (ButtonText ? undefined : "Open menu"), rightIcon: Chevron, sx: { transition: "all 0.15s ease", ...(dropDownButtonStyle) }, ...buttonProps, children: _jsxs(Box, { as: "span", display: "inline-flex", alignItems: "center", gap: DropdownIcon && ButtonText ? s.gap : 0, children: [DropdownIcon, ButtonText] }) }));
211
- const TextToggle = (_jsxs(Flex, { ref: textTriggerRef, onClick: onToggle, onKeyDown: handleTriggerKeyDown, align: "center", gap: 1.5, cursor: "pointer", fontSize: s.fontSize, fontWeight: 500, color: theme.colors.text[700], transition: "color 0.15s ease", _hover: { color: theme.colors.accentText }, style: dropDownButtonStyle, role: "button", tabIndex: 0, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (text ? undefined : "Open menu"), children: [DropdownIcon, text, Chevron] }));
223
+ const ButtonToggle = (_jsx(Button, { ref: buttonTriggerRef, onClick: handleToggle, onKeyDown: handleTriggerKeyDown, size: s.btn, colorScheme: "primary", borderRadius: "lg", fontWeight: 600, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (ButtonText ? undefined : "Open menu"), rightIcon: Chevron, sx: { transition: "all 0.15s ease", ...(dropDownButtonStyle) }, ...buttonProps, children: _jsxs(Box, { as: "span", display: "inline-flex", alignItems: "center", gap: DropdownIcon && ButtonText ? s.gap : 0, children: [DropdownIcon, ButtonText] }) }));
224
+ const TextToggle = (_jsxs(Flex, { ref: textTriggerRef, onClick: handleToggle, onKeyDown: handleTriggerKeyDown, align: "center", gap: 1.5, cursor: "pointer", fontSize: s.fontSize, fontWeight: 500, color: theme.colors.text[700], transition: "color 0.15s ease", _hover: { color: theme.colors.accentText }, style: dropDownButtonStyle, role: "button", tabIndex: 0, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (text ? undefined : "Open menu"), children: [DropdownIcon, text, Chevron] }));
212
225
  return dropdownType === "button" ? ButtonToggle : TextToggle;
213
226
  };
214
227
  const DropdownContentRender = () => {
215
228
  var _a;
216
- const hoverTint = resolveHoverTint(theme.colors.primary[500], theme.colors.background[50]);
229
+ const hoverTint = rowBackgrounds.active;
217
230
  return (_jsx(List, { id: menuId, role: "menu", onKeyDown: handleMenuKeyDown, bg: theme.colors.background[50], border: `0.063rem solid ${theme.colors.boxborder[200]}`, borderRadius: "xl", boxShadow: (_a = theme.shadows) === null || _a === void 0 ? void 0 : _a.lg, py: 1.5, mt: "0.375rem", minWidth: s.minW, maxH: "18rem", overflowY: "auto", overflowX: "hidden", sx: scrollbarStyles(theme.colors, "overlay"), style: ListStyle, children: options.map((option, index) => (_jsxs(ListItem, { ref: (node) => {
218
231
  itemRefs.current[index] = node;
219
232
  }, role: "menuitem", tabIndex: index === activeIndex ? 0 : -1, onClick: () => {
@@ -25,7 +25,7 @@ const EmptyState = ({ title = "No data found", description, icon: IconComp = Inb
25
25
  const accentSoft = palette[50];
26
26
  const accent = accentTextOnCanvas(palette, accentSoft);
27
27
  const containerStyles = variant === "subtle"
28
- ? { bg: theme.colors.gray[50], borderRadius: "2xl" }
28
+ ? { bg: theme.colors.background[50], borderRadius: "2xl" }
29
29
  : variant === "dashed"
30
30
  ? {
31
31
  border: "2px dashed",
@@ -14,7 +14,7 @@ const FileUpload = ({ onFilesUploaded, uploadedFiles, onRemoveFile, acceptTypes
14
14
  const [previewUrl, setPreviewUrl] = React.useState(null);
15
15
  const [previewTitle, setPreviewTitle] = React.useState(null);
16
16
  const [errors, setErrors] = React.useState([]);
17
- const bg = colors.gray[50];
17
+ const bg = colors.background[50];
18
18
  const border = colors.boxborder[500];
19
19
  const mappedAccept = acceptTypes.reduce((acc, ext) => {
20
20
  const mime = mimeMap[ext];
@@ -54,7 +54,7 @@ const FileUpload = ({ onFilesUploaded, uploadedFiles, onRemoveFile, acceptTypes
54
54
  setErrors(messages);
55
55
  },
56
56
  });
57
- return (_jsxs(_Fragment, { children: [_jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsxs(Box, { ...getRootProps(), border: "2px dashed", borderColor: border, borderRadius: "md", p: compact ? 3 : 10, textAlign: "center", bg: bg, cursor: "pointer", transition: "all 0.2s", _hover: { bg: colors.gray[100] }, position: "relative", children: [_jsx("input", { ...getInputProps({ "aria-label": inputAriaLabel }) }), _jsxs(Stack, { direction: compact ? "row" : "column", spacing: compact ? 3 : 2, align: "center", justify: "center", children: [_jsx(Icon, { as: Upload, boxSize: compact ? 4 : 6 }), _jsxs(Stack, { spacing: 0, align: compact ? "start" : "center", children: [_jsx(Text, { fontWeight: "medium", fontSize: compact ? "sm" : "md", color: colors.textMuted, children: "Drag and drop files here" }), _jsxs(Text, { fontSize: compact ? "xs" : "sm", color: colors.textMuted, children: [acceptTypes.join(", "), " up to ", toMB(maxSizeKB), " ", maxFiles ? `- ${maxFiles} file(s) max` : ""] })] })] })] }), errors.length > 0 && (_jsx(Box, { children: errors.map((err, idx) => (_jsx(Text, { fontSize: "sm", color: colors.semanticText.error, children: err }, idx))) })), uploadedFiles.length > 0 && (_jsxs(Box, { children: [_jsx(Box, { display: "flex", alignItems: "center", gap: 2, children: _jsx(Text, { fontFamily: "open-sans, sans-serif", fontWeight: 600, fontSize: 14, lineHeight: "100%", letterSpacing: "4%", textTransform: "uppercase", py: 4, children: "Uploaded Files" }) }), _jsx(List, { spacing: 2, children: uploadedFiles.map((file, index) => (_jsxs(Box, { borderWidth: "0.063rem", borderRadius: "md", px: 3, py: 2, bg: colors.background[50], children: [_jsxs(ListItem, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [_jsxs(HStack, { spacing: 3, flex: "1", children: [file.type.startsWith("image/") ? (_jsxs(Box, { boxSize: "2.5rem", cursor: "pointer", position: "relative", _hover: {
57
+ return (_jsxs(_Fragment, { children: [_jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsxs(Box, { ...getRootProps(), border: "2px dashed", borderColor: border, borderRadius: "md", p: compact ? 3 : 10, textAlign: "center", bg: bg, cursor: "pointer", transition: "all 0.2s", _hover: { bg: colors.background[100] }, position: "relative", children: [_jsx("input", { ...getInputProps({ "aria-label": inputAriaLabel }) }), _jsxs(Stack, { direction: compact ? "row" : "column", spacing: compact ? 3 : 2, align: "center", justify: "center", children: [_jsx(Icon, { as: Upload, boxSize: compact ? 4 : 6 }), _jsxs(Stack, { spacing: 0, align: compact ? "start" : "center", children: [_jsx(Text, { fontWeight: "medium", fontSize: compact ? "sm" : "md", color: colors.textMuted, children: "Drag and drop files here" }), _jsxs(Text, { fontSize: compact ? "xs" : "sm", color: colors.textMuted, children: [acceptTypes.join(", "), " up to ", toMB(maxSizeKB), " ", maxFiles ? `- ${maxFiles} file(s) max` : ""] })] })] })] }), errors.length > 0 && (_jsx(Box, { children: errors.map((err, idx) => (_jsx(Text, { fontSize: "sm", color: colors.semanticText.error, children: err }, idx))) })), uploadedFiles.length > 0 && (_jsxs(Box, { children: [_jsx(Box, { display: "flex", alignItems: "center", gap: 2, children: _jsx(Text, { fontFamily: "open-sans, sans-serif", fontWeight: 600, fontSize: 14, lineHeight: "100%", letterSpacing: "4%", textTransform: "uppercase", py: 4, children: "Uploaded Files" }) }), _jsx(List, { spacing: 2, children: uploadedFiles.map((file, index) => (_jsxs(Box, { borderWidth: "0.063rem", borderRadius: "md", px: 3, py: 2, bg: colors.background[50], children: [_jsxs(ListItem, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [_jsxs(HStack, { spacing: 3, flex: "1", children: [file.type.startsWith("image/") ? (_jsxs(Box, { boxSize: "2.5rem", cursor: "pointer", position: "relative", _hover: {
58
58
  ".hover-icon": {
59
59
  opacity: 1,
60
60
  bg: "blackAlpha.500",
@@ -144,13 +144,13 @@ panelPadding = 3, clearAllButton = true, onClearAllHandler,
144
144
  pointerEvents: 'none', // Allow clicks to pass through track
145
145
  zIndex: 3,
146
146
  margin: 0,
147
- } })] }), _jsxs(SimpleGrid, { columns: 2, spacing: 2, pt: 2, w: "full", children: [_jsxs(Popover, { isOpen: openPrice.id === section.id && openPrice.target === "min", onClose: () => setOpenPrice({}), placement: "bottom-start", closeOnBlur: true, children: [_jsx(PopoverTrigger, { children: _jsx(Flex, { borderWidth: "0", borderRadius: "md", alignItems: "center", px: 3, py: 2, bg: theme.colors.gray[50], borderColor: theme.colors.boxborder[500], cursor: "pointer", onClick: () => setOpenPrice({ id: section.id, target: "min" }), gap: 2, overflow: "hidden", children: _jsx(Box, { ml: "auto", children: _jsxs(Text, { fontSize: "12px", color: theme.colors.text[500], whiteSpace: "nowrap", children: [currentMin, range.unit ? ` ${range.unit}` : ""] }) }) }) }), _jsx(Portal, { children: _jsx(PopoverContent, { width: "6rem", p: 0, zIndex: 1600, bg: theme.colors.background[50], children: _jsx(PopoverBody, { p: 0, children: _jsx(VStack, { align: "stretch", spacing: 0, maxH: "12rem", overflowY: "auto", children: values.map((v) => (_jsxs(Flex, { px: 2, py: 1, align: "center", justify: "space-between", cursor: "pointer", bg: currentMin === v ? theme.colors.red[50] : theme.colors.background[50], borderLeftWidth: currentMin === v ? 3 : 0, borderLeftStyle: "solid", borderLeftColor: currentMin === v ? theme.colors.red[400] : "transparent", _hover: { bg: hoverBg }, onClick: () => {
147
+ } })] }), _jsxs(SimpleGrid, { columns: 2, spacing: 2, pt: 2, w: "full", children: [_jsxs(Popover, { isOpen: openPrice.id === section.id && openPrice.target === "min", onClose: () => setOpenPrice({}), placement: "bottom-start", closeOnBlur: true, children: [_jsx(PopoverTrigger, { children: _jsx(Flex, { borderWidth: "0", borderRadius: "md", alignItems: "center", px: 3, py: 2, bg: theme.colors.background[50], borderColor: theme.colors.boxborder[500], cursor: "pointer", onClick: () => setOpenPrice({ id: section.id, target: "min" }), gap: 2, overflow: "hidden", children: _jsx(Box, { ml: "auto", children: _jsxs(Text, { fontSize: "12px", color: theme.colors.text[500], whiteSpace: "nowrap", children: [currentMin, range.unit ? ` ${range.unit}` : ""] }) }) }) }), _jsx(Portal, { children: _jsx(PopoverContent, { width: "6rem", p: 0, zIndex: 1600, bg: theme.colors.background[50], children: _jsx(PopoverBody, { p: 0, children: _jsx(VStack, { align: "stretch", spacing: 0, maxH: "12rem", overflowY: "auto", children: values.map((v) => (_jsxs(Flex, { px: 2, py: 1, align: "center", justify: "space-between", cursor: "pointer", bg: currentMin === v ? theme.colors.red[50] : theme.colors.background[50], borderLeftWidth: currentMin === v ? 3 : 0, borderLeftStyle: "solid", borderLeftColor: currentMin === v ? theme.colors.red[400] : "transparent", _hover: { bg: hoverBg }, onClick: () => {
148
148
  const min = v;
149
149
  const max = currentMax;
150
150
  const nextVal = [Math.min(min, max), Math.max(min, max)];
151
151
  setInternalSelected((prev) => { const next = { ...prev, [section.id]: nextVal }; onChange === null || onChange === void 0 ? void 0 : onChange(next); return next; });
152
152
  setOpenPrice({});
153
- }, children: [_jsxs(Text, { fontSize: "sm", color: theme.colors.gray[800], children: [v, range.unit ? ` ${range.unit}` : ""] }), currentMin === v ? (_jsx(Box, { bg: theme.colors.red[100], borderRadius: "full", p: 1, display: "flex", alignItems: "center", children: _jsx(Check, { size: 9, color: onFilled(theme.colors.red[100], theme.colors.white, theme.colors.black) }) })) : null] }, `min-${v}`))) }) }) }) })] }), _jsxs(Popover, { isOpen: openPrice.id === section.id && openPrice.target === "max", onClose: () => setOpenPrice({}), placement: "bottom-start", closeOnBlur: true, children: [_jsx(PopoverTrigger, { children: _jsx(Flex, { borderWidth: "0", borderRadius: "md", alignItems: "center", px: 3, py: 2, bg: theme.colors.gray[50], borderColor: theme.colors.boxborder[500], cursor: "pointer", onClick: () => setOpenPrice({ id: section.id, target: "max" }), gap: 2, overflow: "hidden", children: _jsx(Box, { ml: "auto", children: _jsxs(Text, { fontSize: "12px", color: theme.colors.text[500], whiteSpace: "nowrap", children: [currentMax, range.unit ? ` ${range.unit}` : ""] }) }) }) }), _jsx(PopoverContent, { width: "6rem", p: 0, bg: theme.colors.background[50], children: _jsx(PopoverBody, { p: 0, children: _jsx(VStack, { align: "stretch", spacing: 0, maxH: "12rem", overflowY: "auto", children: values.map((v) => (_jsxs(Flex, { px: 2, py: 1, align: "center", justify: "space-between", cursor: "pointer", bg: currentMax === v ? theme.colors.red[50] : theme.colors.background[50], borderLeftWidth: currentMax === v ? 3 : 0, borderLeftStyle: "solid", borderLeftColor: currentMax === v ? theme.colors.red[400] : "transparent", _hover: { bg: hoverBg }, onClick: () => {
153
+ }, children: [_jsxs(Text, { fontSize: "sm", color: theme.colors.gray[800], children: [v, range.unit ? ` ${range.unit}` : ""] }), currentMin === v ? (_jsx(Box, { bg: theme.colors.red[100], borderRadius: "full", p: 1, display: "flex", alignItems: "center", children: _jsx(Check, { size: 9, color: onFilled(theme.colors.red[100], theme.colors.white, theme.colors.black) }) })) : null] }, `min-${v}`))) }) }) }) })] }), _jsxs(Popover, { isOpen: openPrice.id === section.id && openPrice.target === "max", onClose: () => setOpenPrice({}), placement: "bottom-start", closeOnBlur: true, children: [_jsx(PopoverTrigger, { children: _jsx(Flex, { borderWidth: "0", borderRadius: "md", alignItems: "center", px: 3, py: 2, bg: theme.colors.background[50], borderColor: theme.colors.boxborder[500], cursor: "pointer", onClick: () => setOpenPrice({ id: section.id, target: "max" }), gap: 2, overflow: "hidden", children: _jsx(Box, { ml: "auto", children: _jsxs(Text, { fontSize: "12px", color: theme.colors.text[500], whiteSpace: "nowrap", children: [currentMax, range.unit ? ` ${range.unit}` : ""] }) }) }) }), _jsx(PopoverContent, { width: "6rem", p: 0, bg: theme.colors.background[50], children: _jsx(PopoverBody, { p: 0, children: _jsx(VStack, { align: "stretch", spacing: 0, maxH: "12rem", overflowY: "auto", children: values.map((v) => (_jsxs(Flex, { px: 2, py: 1, align: "center", justify: "space-between", cursor: "pointer", bg: currentMax === v ? theme.colors.red[50] : theme.colors.background[50], borderLeftWidth: currentMax === v ? 3 : 0, borderLeftStyle: "solid", borderLeftColor: currentMax === v ? theme.colors.red[400] : "transparent", _hover: { bg: hoverBg }, onClick: () => {
154
154
  const max = v;
155
155
  const min = currentMin;
156
156
  const nextVal = [Math.min(min, max), Math.max(min, max)];
@@ -169,7 +169,7 @@ panelPadding = 3, clearAllButton = true, onClearAllHandler,
169
169
  const isRowSelected = String(internalSelected[section.id] || "") === String(r);
170
170
  const starColor = accentTextOnCanvas(theme.colors.orange, isRowSelected ? theme.colors.red[50] : theme.colors.background[50]);
171
171
  return Array.from({ length: 5 }, (_, i) => (_jsx(Box, { children: _jsx(Star, { size: 16, color: starColor, fill: i < r ? starColor : "none" }) }, `star-${r}-${i}`)));
172
- })() }), _jsx(Text, { fontSize: "sm", color: theme.colors.text[500], children: "& Up" })] }) }, `rating-${r}`))) })) : null, section.searchable && (_jsx(Input, { size: "xs", h: "26px", fontSize: "xs", placeholder: `Search ${section.label}...`, borderRadius: "md", bg: theme.colors.gray[50], border: "1px solid",
172
+ })() }), _jsx(Text, { fontSize: "sm", color: theme.colors.text[500], children: "& Up" })] }) }, `rating-${r}`))) })) : null, section.searchable && (_jsx(Input, { size: "xs", h: "26px", fontSize: "xs", placeholder: `Search ${section.label}...`, borderRadius: "md", bg: theme.colors.background[50], border: "1px solid",
173
173
  // boxborder[500], not raw gray[200]: WCAG 1.4.11 needs >=3.0 for a control
174
174
  // boundary against any named surface up to `muted` (lightest); gray[200] fails
175
175
  // there in dark mode.
@@ -228,7 +228,7 @@ panelPadding = 3, clearAllButton = true, onClearAllHandler,
228
228
  : {
229
229
  justifyContent: "space-between",
230
230
  padding: 0,
231
- background: theme.colors.gray[50],
231
+ background: theme.colors.background[50],
232
232
  borderRadius: theme.radii.lg,
233
233
  border: `1px solid ${theme.colors.gray[200]}`,
234
234
  marginBottom: 6,
@@ -249,6 +249,6 @@ panelPadding = 3, clearAllButton = true, onClearAllHandler,
249
249
  },
250
250
  },
251
251
  }));
252
- return (_jsxs(Box, { w: width, bg: variant === "minimal" ? theme.colors.background[50] : theme.colors.gray[50], p: containerPadding !== undefined ? containerPadding : (variant === "minimal" ? 3 : 2), borderRadius: variant === "minimal" ? "lg" : "none", boxShadow: variant === "minimal" ? "sm" : "none", border: variant === "minimal" ? `1px solid ${theme.colors.gray[200]}` : "none", h: "fit-content", maxH: containerHeight !== undefined ? containerHeight : undefined, overflowY: containerHeight !== undefined ? "auto" : "visible", children: [_jsxs(Flex, { className: "filters-header", align: "center", justify: "space-between", mb: 2, borderBottom: "2px solid", borderColor: theme.colors.gray[100], children: [_jsx(Text, { fontSize: "lg", fontWeight: "bold", color: theme.colors.text[500], children: "Filters" }), activeCount > 0 && clearAllButton && (_jsx(_Fragment, { children: _jsx(Button, { size: "xs", variant: "outline", leftIcon: _jsx(X, { size: 12 }), onClick: clearAll, "aria-label": "Clear All", className: "clear-all-btn", colorScheme: "red", children: "Clear All" }) }))] }), _jsx(Accordion, { allowMultiple: true, defaultIndex: sidebarOptions.map((_, i) => i), items: items })] }));
252
+ return (_jsxs(Box, { w: width, bg: theme.colors.background[50], p: containerPadding !== undefined ? containerPadding : (variant === "minimal" ? 3 : 2), borderRadius: variant === "minimal" ? "lg" : "none", boxShadow: variant === "minimal" ? "sm" : "none", border: variant === "minimal" ? `1px solid ${theme.colors.gray[200]}` : "none", h: "fit-content", maxH: containerHeight !== undefined ? containerHeight : undefined, overflowY: containerHeight !== undefined ? "auto" : "visible", children: [_jsxs(Flex, { className: "filters-header", align: "center", justify: "space-between", mb: 2, borderBottom: "2px solid", borderColor: theme.colors.gray[100], children: [_jsx(Text, { fontSize: "lg", fontWeight: "bold", color: theme.colors.text[500], children: "Filters" }), activeCount > 0 && clearAllButton && (_jsx(_Fragment, { children: _jsx(Button, { size: "xs", variant: "outline", leftIcon: _jsx(X, { size: 12 }), onClick: clearAll, "aria-label": "Clear All", className: "clear-all-btn", colorScheme: "red", children: "Clear All" }) }))] }), _jsx(Accordion, { allowMultiple: true, defaultIndex: sidebarOptions.map((_, i) => i), items: items })] }));
253
253
  };
254
254
  export default FilterSidebar;
@@ -1,4 +1,3 @@
1
- import { liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
2
- import { AA_NORMAL_TEXT } from "../../Theme/tokens/builders/accentText.js";
3
- // The fill itself must clear AA against `text[500]`, the only ink these rows ever use.
4
- export const getFilterHoverBg = (colors, isDark) => isDark ? liftToContrast(colors.gray[300], colors.text[500], AA_NORMAL_TEXT) : colors.gray[50];
1
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
2
+ /** Shared with every selectable list row — never seed from `primary[500]` or `primary.opacity[8]`. */
3
+ export const getFilterHoverBg = (colors, _isDark) => listRowBackgrounds(colors).active;
@@ -47,7 +47,7 @@ export const Input = {
47
47
  const primary = theme.colors.primary[500];
48
48
  return {
49
49
  field: {
50
- bg: theme.colors.gray[50],
50
+ bg: theme.colors.background[50],
51
51
  border: "0.063rem solid",
52
52
  borderColor,
53
53
  _placeholder: {
@@ -81,7 +81,7 @@ export const Input = {
81
81
  boxShadow: 'inherit',
82
82
  },
83
83
  _disabled: {
84
- bg: theme.colors.gray[100],
84
+ bg: theme.colors.background[100],
85
85
  opacity: 1,
86
86
  cursor: "not-allowed",
87
87
  _hover: {
@@ -29,7 +29,7 @@ export const Textarea = {
29
29
  return {
30
30
  border: "0.063rem solid",
31
31
  borderColor,
32
- bg: theme.colors.gray[50],
32
+ bg: theme.colors.background[50],
33
33
  _placeholder: {
34
34
  color: placeholderInk(theme.colors),
35
35
  },
@@ -59,7 +59,7 @@ export const Textarea = {
59
59
  boxShadow: 'inherit',
60
60
  },
61
61
  _disabled: {
62
- bg: theme.colors.gray[100],
62
+ bg: theme.colors.background[100],
63
63
  opacity: 1,
64
64
  cursor: "not-allowed",
65
65
  _hover: {
@@ -1,12 +1,14 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Popover, PopoverArrow, PopoverBody, PopoverContent, PopoverTrigger, SimpleGrid, Text, } from "@chakra-ui/react";
3
3
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
4
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
4
5
  const MoreItems = ({ items, moreCount, triggerText, colorResolver, hideDots = false, columns = 2, minWidth = "260px", triggerMaxWidth = "250px", trigger = "hover", placement = "bottom-start", }) => {
5
6
  const theme = useCustomTheme();
7
+ const countBadgeBg = listRowBackgrounds(theme.colors).selected;
6
8
  const count = moreCount !== null && moreCount !== void 0 ? moreCount : items.length;
7
9
  if (count <= 0)
8
10
  return triggerText ? _jsx(_Fragment, { children: triggerText }) : null;
9
- return (_jsxs(Popover, { trigger: trigger, placement: placement, isLazy: true, children: [_jsx(PopoverTrigger, { children: _jsxs(Box, { display: "inline-flex", alignItems: "center", maxW: triggerMaxWidth, cursor: "pointer", children: [triggerText !== undefined && (_jsx(Box, { as: "span", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: triggerText })), _jsxs(Box, { as: "span", ml: "6px", px: "8px", py: "1px", fontSize: "12px", fontWeight: 600, lineHeight: "1.4", borderRadius: "full", color: theme.colors.accentText, bg: theme.colors.primary[50], transition: "all 0.15s ease", _hover: { bg: theme.colors.primary[100] }, children: ["+", count, " more"] })] }) }), _jsxs(PopoverContent, { width: "auto", minWidth: minWidth, maxH: "280px", overflowY: "auto", borderRadius: "xl",
11
+ return (_jsxs(Popover, { trigger: trigger, placement: placement, isLazy: true, children: [_jsx(PopoverTrigger, { children: _jsxs(Box, { display: "inline-flex", alignItems: "center", maxW: triggerMaxWidth, cursor: "pointer", children: [triggerText !== undefined && (_jsx(Box, { as: "span", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: triggerText })), _jsxs(Box, { as: "span", ml: "6px", px: "8px", py: "1px", fontSize: "12px", fontWeight: 600, lineHeight: "1.4", borderRadius: "full", color: theme.colors.accentText, bg: countBadgeBg, transition: "all 0.15s ease", _hover: { bg: listRowBackgrounds(theme.colors).selectedActive }, children: ["+", count, " more"] })] }) }), _jsxs(PopoverContent, { width: "auto", minWidth: minWidth, maxH: "280px", overflowY: "auto", borderRadius: "xl",
10
12
  // Chakra defaults this surface to `colors.gray.700` in dark, which against the
11
13
  // swapped (dark-inverted) palette is a *light* grey — wrong for a popover bg. Pin it.
12
14
  bg: theme.colors.background[50], boxShadow: "lg", _focus: { outline: "none", boxShadow: "lg" }, children: [_jsx(PopoverArrow, { bg: theme.colors.background[50] }), _jsx(PopoverBody, { p: 3, children: _jsx(SimpleGrid, { columns: columns, spacingX: 4, spacingY: 2, children: items === null || items === void 0 ? void 0 : items.map((item, index) => {
@@ -55,14 +55,14 @@ export default function MultiSelect({ value, onValueChange, width = "100%", labe
55
55
  // surface up to `muted` (lightest); [500] fails there, [800] clears all with margin.
56
56
  borderColor: error || localError
57
57
  ? theme.colors.semanticText.error
58
- : theme.colors.boxborder[500], borderRadius: "lg", bg: theme.colors.gray[50], minH: s.minH, transition: "border-color 0.2s, box-shadow 0.2s", _focusWithin: {
58
+ : theme.colors.boxborder[500], borderRadius: "lg", bg: theme.colors.background[50], minH: s.minH, transition: "border-color 0.2s, box-shadow 0.2s", _focusWithin: {
59
59
  borderColor: error || localError
60
60
  ? theme.colors.semanticText.error
61
61
  : theme.colors.primary[500],
62
62
  boxShadow: `0 0 0 0.125rem ${error || localError
63
63
  ? theme.colors.boxShadow.error
64
64
  : theme.colors.boxShadow.primary}`,
65
- }, children: [options.map((option) => (_jsx(Tag, { size: s.tagSize, colorScheme: "primary", label: option.label, onIconClick: () => handleRemove(option), icon: X }, option.id))), _jsx(Input, { ref: inputRef, type: "text", value: inputValue, isDisabled: isDisabled, isReadOnly: isReadOnly, id: id, name: name, size: size, variant: "unstyled", h: s.fieldHeight, minH: s.fieldHeight, fontSize: s.fieldFontSize, fontWeight: "500", color: theme.colors.gray[700], letterSpacing: "0.02em", flex: "1", minW: 0, style: {
65
+ }, children: [options.map((option) => (_jsx(Tag, { size: s.tagSize, colorScheme: "primary", label: option.label, onIconClick: () => handleRemove(option), icon: X }, option.id))), _jsx(Input, { ref: inputRef, type: "text", value: inputValue, isDisabled: isDisabled, isReadOnly: isReadOnly, id: id, name: name, size: size, variant: "unstyled", h: s.fieldHeight, minH: s.fieldHeight, fontSize: s.fieldFontSize, fontWeight: "500", color: theme.colors.text[700], letterSpacing: "0.02em", flex: "1", minW: 0, style: {
66
66
  backgroundColor: "transparent",
67
67
  ...inputStyle,
68
68
  }, onChange: handleInputChange, onKeyDown: handleKeyDown, placeholder: options.length === 0 ? placeholderText : "" })] }), (error || localError) && (_jsx(ErrorMessage, { errorMessage: localError || errorMessage })), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
@@ -3,17 +3,16 @@ import { Avatar, Box, Button, Center, Flex, Menu, MenuButton, MenuDivider, MenuI
3
3
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
4
4
  import { accentTextOnCanvas, isDarkCanvas } from "../../Theme/tokens/builders/accentText.js";
5
5
  import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
6
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
6
7
  import { resolveStatusTone } from "../../Theme/tokens/builders/statusTone.js";
7
8
  import { CircleArrowLeft, LogOut, PanelLeftClose, PanelRightClose, } from "lucide-react";
8
9
  // Roomy enough to hover without aiming: the glyph is only 1.25rem.
9
10
  const SIDEBAR_TOGGLE_HIT = "2.5rem";
10
11
  export default function NavBar({ userAvathar, userName, userRole, navMenu, moreIcon, handleNavOnClick, handleLogout, logoutText, navigationBarText, sideBarToggole, onSideBarToggole, forceSideBarToggle = false, onSideBarPeek, }) {
11
12
  const theme = useCustomTheme();
12
- // For a near-neutral brand (e.g. zinc), `primary[50]` is itself a pale near-white tint — on
13
- // the menu's own near-white surface that measured as low as ~1.02:1, an invisible hover.
14
- const menuHoverBg = resolveHoverTint(theme.colors.primary[50], theme.colors.backgroundColor.light);
13
+ const rowBackgrounds = listRowBackgrounds(theme.colors);
14
+ const menuHoverBg = rowBackgrounds.active;
15
15
  const barHoverBg = resolveHoverTint(theme.colors.gray[100], theme.colors.backgroundColor.light);
16
- const menuHoverInk = accentTextOnCanvas(theme.colors.primary, menuHoverBg);
17
16
  const dangerTone = resolveStatusTone(theme.colors.semantic.error, isDarkCanvas(theme.colors.backgroundColor.main) ? "dark" : "light");
18
17
  // Shared rounded pill affordance for the bar's icon controls.
19
18
  const iconButtonStyle = {
@@ -41,9 +40,9 @@ export default function NavBar({ userAvathar, userName, userRole, navMenu, moreI
41
40
  color: theme.colors.text[900],
42
41
  gap: theme.space["2"],
43
42
  transition: "background 0.12s",
44
- _hover: { bg: menuHoverBg, color: menuHoverInk },
45
- _focus: { bg: menuHoverBg, color: menuHoverInk },
46
- _active: { bg: menuHoverBg, color: menuHoverInk },
43
+ _hover: { bg: menuHoverBg },
44
+ _focus: { bg: menuHoverBg },
45
+ _active: { bg: rowBackgrounds.selectedActive },
47
46
  };
48
47
  return (_jsx(Box, { bg: theme.colors.backgroundColor.light, px: 4, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: _jsxs(Flex, { h: 16, alignItems: "center", justifyContent: "space-between", children: [_jsxs(Box, { display: "flex", gap: 1.5, alignItems: "center", children: [_jsx(Box, { as: "button", type: "button", onClick: () => onSideBarToggole === null || onSideBarToggole === void 0 ? void 0 : onSideBarToggole(), onMouseEnter: onSideBarPeek, onFocus: onSideBarPeek, "aria-label": sideBarToggole ? "Close navigation menu" : "Open navigation menu", "aria-expanded": !!sideBarToggole, ...iconButtonStyle, display: forceSideBarToggle ? "flex" : { base: "flex", lg: "none" }, w: SIDEBAR_TOGGLE_HIT, h: SIDEBAR_TOGGLE_HIT, children: sideBarToggole ? (_jsx(PanelLeftClose, { size: "1.25rem" })) : (_jsx(PanelRightClose, { size: "1.25rem" })) }), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) && (_jsx(Box, { ...iconButtonStyle, as: "button", type: "button", "aria-label": "Go back", display: "flex", onClick: () => { var _a; return (_a = navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.onIconClick) === null || _a === void 0 ? void 0 : _a.call(navigationBarText); }, children: _jsx(CircleArrowLeft, { size: "1.25rem", color: theme.colors.text[500] }) })), (navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text) && (_jsx(Text, { color: accentTextOnCanvas(theme.colors.secondary, theme.colors.backgroundColor.light), fontSize: "1.25rem", fontWeight: 600, fontFamily: "open-sans, sans-serif", letterSpacing: "-0.013rem", children: navigationBarText === null || navigationBarText === void 0 ? void 0 : navigationBarText.text }))] }), _jsx(Flex, { minW: 0, flexShrink: 1, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 4, minW: 0, children: [moreIcon && (_jsx(Box, { display: "flex", alignItems: "center", minW: 0, children: moreIcon })), _jsxs(Menu, { children: [_jsx(MenuButton, { as: Button, rounded: "full", variant: "link", cursor: "pointer", minW: 0, flexShrink: 0, children: _jsx(Avatar, { size: "sm", name: userName, src: userAvathar }) }), _jsx(MenuList, { alignItems: "center", zIndex: 5, p: 0, py: "0.375rem",
49
48
  // Without a cap one long title stretches the whole dropdown; titles truncate instead.
@@ -32,7 +32,7 @@ export const NumberInput = {
32
32
  const primary = theme.colors.primary[500];
33
33
  return {
34
34
  field: {
35
- bg: theme.colors.gray[50],
35
+ bg: theme.colors.background[50],
36
36
  border: "0.063rem solid",
37
37
  borderColor,
38
38
  _placeholder: {
@@ -66,7 +66,7 @@ export const NumberInput = {
66
66
  boxShadow: 'inherit',
67
67
  },
68
68
  _disabled: {
69
- bg: theme.colors.gray[100],
69
+ bg: theme.colors.background[100],
70
70
  opacity: 1,
71
71
  cursor: "not-allowed",
72
72
  _hover: {
@@ -6,6 +6,8 @@ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { accentTextOnCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
7
7
  import { chartMode } from "../../Theme/tokens/builders/chartColorsFromTheme.js";
8
8
  import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
9
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
10
+ import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
9
11
  import { avatarColor, orgInitial, } from "./OrgSwitcherProps.js";
10
12
  const sizeMap = {
11
13
  sm: { h: "32px", avatar: "22px", font: "0.8rem", sub: "0.65rem", px: 2 },
@@ -23,8 +25,14 @@ const Avatar = ({ org, boxSize, fontSize, }) => {
23
25
  const OrgSwitcher = ({ organizations, value, onChange, isLoading = false, isSearchable, searchThreshold = 6, triggerVariant = "ghost", size = "md", maxWidth = "200px", menuMinWidth = "280px", placeholder = "Select organization", ariaLabel = "Switch organization", showRole = true, }) => {
24
26
  var _a;
25
27
  const theme = useCustomTheme();
28
+ const rowBackgrounds = useMemo(() => listRowBackgrounds(theme.colors), [theme.colors]);
26
29
  const s = sizeMap[size];
27
30
  const { isOpen, onOpen, onClose } = useDisclosure();
31
+ const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
32
+ const handlePopoverOpen = () => {
33
+ requestExclusiveOpen();
34
+ onOpen();
35
+ };
28
36
  const [query, setQuery] = useState("");
29
37
  const searchRef = useRef(null);
30
38
  const [activeIndex, setActiveIndex] = useState(0);
@@ -69,7 +77,7 @@ const OrgSwitcher = ({ organizations, value, onChange, isLoading = false, isSear
69
77
  const triggerStyles = triggerVariant === "outline"
70
78
  ? { border: "1px solid", borderColor: theme.colors.boxborder[500], bg: theme.colors.background[50] }
71
79
  : triggerVariant === "subtle"
72
- ? { bg: theme.colors.gray[50] }
80
+ ? { bg: theme.colors.background[50] }
73
81
  : { bg: "transparent" };
74
82
  // `gray[100]` hover on a "transparent" trigger reads against whatever's actually behind it —
75
83
  // this control lives in a navbar-like shell, so `backgroundColor.light` is that surface. For a
@@ -82,7 +90,7 @@ const OrgSwitcher = ({ organizations, value, onChange, isLoading = false, isSear
82
90
  if (org.id !== value)
83
91
  onChange(org.id, org);
84
92
  };
85
- return (_jsxs(Popover, { isOpen: isOpen, onOpen: onOpen, onClose: () => {
93
+ return (_jsxs(Popover, { isOpen: isOpen, onOpen: handlePopoverOpen, onClose: () => {
86
94
  onClose();
87
95
  setQuery("");
88
96
  }, placement: "bottom-start", initialFocusRef: showSearch ? searchRef : firstOptionRef, isLazy: true, children: [_jsx(PopoverTrigger, { children: _jsxs(Flex, { as: "button", type: "button", "aria-label": ariaLabel, align: "center", gap: s.px === 2 ? "8px" : "10px", h: s.h, px: s.px, borderRadius: "lg", cursor: isLoading ? "default" : "pointer", opacity: isLoading ? 0.6 : 1, pointerEvents: isLoading ? "none" : "auto", transition: "background 0.15s ease", _hover: { bg: triggerVariant === "ghost" ? triggerHoverBg : undefined }, ...triggerStyles, children: [selected ? (_jsx(Avatar, { org: selected, boxSize: s.avatar, fontSize: s.sub })) : (_jsx(Flex, { align: "center", justify: "center", boxSize: s.avatar, borderRadius: "lg", bg: theme.colors.gray[100], color: accentTextOnCanvas(theme.colors.gray, theme.colors.gray[100]), flexShrink: 0, children: _jsx(Building2, { size: 14 }) })), _jsx(Text, { fontSize: s.font, fontWeight: 600, color: theme.colors.gray[700], maxW: maxWidth, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", textAlign: "left", children: (_a = selected === null || selected === void 0 ? void 0 : selected.name) !== null && _a !== void 0 ? _a : placeholder }), isLoading ? (_jsx(Spinner, { size: "xs", thickness: "1.5px", color: theme.colors.accentText, flexShrink: 0 })) : (_jsx(Box, { as: ChevronsUpDown, size: 16, color: theme.colors.textMuted, flexShrink: 0 }))] }) }), _jsx(PopoverContent, { minW: menuMinWidth, w: "auto",
@@ -97,18 +105,14 @@ const OrgSwitcher = ({ organizations, value, onChange, isLoading = false, isSear
97
105
  }
98
106
  }, borderRadius: "lg" })] }) })), _jsxs(Box, { role: "listbox", "aria-label": "Organizations", maxH: "320px", overflowY: "auto", py: 1, onKeyDown: handleListKeyDown, children: [filtered.map((org, idx) => {
99
107
  const isActive = org.id === value;
100
- // Active row's hover repeated its own resting `primary[50]` fill — a zero-delta
101
- // hover, invisible by construction. `resolveHoverTint` walks a fill away from a
102
- // backdrop until distinguishable, so handing it its own resting bg as the backdrop
103
- // is enough to make hover read as a real state change on both active and inactive rows.
104
108
  const rowHoverBg = isActive
105
- ? resolveHoverTint(theme.colors.primary[50], theme.colors.primary[50])
106
- : resolveHoverTint(theme.colors.gray[50], theme.colors.backgroundColor.light);
109
+ ? rowBackgrounds.selectedActive
110
+ : rowBackgrounds.active;
107
111
  return (_jsxs(Flex, { as: "button", type: "button", role: "option", "aria-selected": isActive, ref: (el) => {
108
112
  optionRefs.current[idx] = el;
109
113
  if (idx === 0)
110
114
  firstOptionRef.current = el;
111
- }, tabIndex: idx === activeIndex ? 0 : -1, align: "center", gap: "10px", w: "100%", textAlign: "left", border: "none", fontFamily: "inherit", px: 3, py: 2, cursor: "pointer", bg: isActive ? theme.colors.primary[50] : "transparent", transition: "background 0.12s ease", _hover: { bg: rowHoverBg }, onClick: () => handleSelect(org), children: [_jsx(Avatar, { org: org, boxSize: s.avatar, fontSize: s.sub }), _jsxs(Box, { flex: "1", minW: 0, children: [_jsx(Text, { fontSize: s.font, fontWeight: isActive ? 600 : 500, color: theme.colors.text[900], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: org.name }), showRole && org.role && (_jsx(Text, { fontSize: s.sub, color: theme.colors.text[500], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: org.role }))] }), isActive && (_jsx(Box, { as: Check, size: 16, color: accentTextOnCanvas(theme.colors.primary, theme.colors.primary[50]), flexShrink: 0 }))] }, org.id));
112
- }), filtered.length === 0 && (_jsx(Text, { fontSize: "sm", color: theme.colors.gray[500], textAlign: "center", py: 6, children: "No organizations found" }))] })] }) })] }));
115
+ }, tabIndex: idx === activeIndex ? 0 : -1, align: "center", gap: "10px", w: "100%", textAlign: "left", border: "none", fontFamily: "inherit", px: 3, py: 2, cursor: "pointer", bg: isActive ? rowBackgrounds.selected : "transparent", transition: "background 0.12s ease", _hover: { bg: rowHoverBg }, onClick: () => handleSelect(org), children: [_jsx(Avatar, { org: org, boxSize: s.avatar, fontSize: s.sub }), _jsxs(Box, { flex: "1", minW: 0, children: [_jsx(Text, { fontSize: s.font, fontWeight: isActive ? 600 : 500, color: theme.colors.text[900], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: org.name }), showRole && org.role && (_jsx(Text, { fontSize: s.sub, color: theme.colors.text[500], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: org.role }))] }), isActive && (_jsx(Box, { as: Check, size: 16, color: theme.colors.accentText, flexShrink: 0 }))] }, org.id));
116
+ }), filtered.length === 0 && (_jsx(Text, { fontSize: "sm", color: theme.colors.textMuted, textAlign: "center", py: 6, children: "No organizations found" }))] })] }) })] }));
113
117
  };
114
118
  export default OrgSwitcher;
@@ -3,13 +3,13 @@ import { Box, Flex, Text } from "@chakra-ui/react";
3
3
  import { Download, ExternalLink, FileText } from "lucide-react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
5
  import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
6
- import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
6
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
7
7
  import ToolTip from "../ToolTip/ToolTip.js";
8
8
  const PdfViewer = ({ pdfUrl, fileName = "Document.pdf", height = "480px", showToolbar = true, borderRadius = "xl", }) => {
9
9
  const theme = useCustomTheme();
10
- const toolbarSurface = theme.colors.gray[50];
10
+ const toolbarSurface = theme.colors.background[50];
11
11
  const iconHoverInk = accentTextOnCanvas(theme.colors.primary, toolbarSurface);
12
- const iconHoverBg = resolveHoverTint(theme.colors.primary[50], toolbarSurface);
13
- return (_jsxs(Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], children: [showToolbar && (_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.gray[50], children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(FileText, { size: 18, color: theme.colors.accentText }), _jsx(Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), _jsxs(Flex, { align: "center", gap: 1, children: [_jsx(ToolTip, { label: "Open in new tab", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(ExternalLink, { size: 16 }) }) }), _jsx(ToolTip, { label: "Download", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, download: fileName, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(Download, { size: 16 }) }) })] })] })), _jsx(Box, { as: "embed", src: pdfUrl, type: "application/pdf", width: "100%", height: height, display: "block" })] }));
12
+ const iconHoverBg = listRowBackgrounds(theme.colors).active;
13
+ return (_jsxs(Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], children: [showToolbar && (_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.background[50], children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(FileText, { size: 18, color: theme.colors.accentText }), _jsx(Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), _jsxs(Flex, { align: "center", gap: 1, children: [_jsx(ToolTip, { label: "Open in new tab", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(ExternalLink, { size: 16 }) }) }), _jsx(ToolTip, { label: "Download", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, download: fileName, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(Download, { size: 16 }) }) })] })] })), _jsx(Box, { as: "embed", src: pdfUrl, type: "application/pdf", width: "100%", height: height, display: "block" })] }));
14
14
  };
15
15
  export default PdfViewer;
@@ -3,7 +3,7 @@ import { useMemo, useState } from "react";
3
3
  import { Badge, Box, Checkbox, Divider, Flex, Heading, HStack, IconButton, Skeleton, Table, Tbody, Td, Text, Th, Thead, Tooltip, Tr, VStack, } from "@chakra-ui/react";
4
4
  import { ArrowLeft, Check, Pencil, Plus, ShieldCheck, SquareArrowOutUpRight, Trash2, } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
- import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
6
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
7
7
  import Button from "../Button/Button.js";
8
8
  import TextInput from "../Input/TextInput.js";
9
9
  import EmptyState from "../EmptyState/EmptyState.js";
@@ -59,8 +59,9 @@ const RolesPermission = ({ view, mode = "create", roles, isRolesLoading = false,
59
59
  const surface = colors.background[50];
60
60
  const muted = colors.textMuted;
61
61
  const heading = colors.text[900];
62
- const headBg = colors.gray[50];
63
- const rowHover = resolveHoverTint(colors.gray[50], surface);
62
+ const rowBackgrounds = listRowBackgrounds(colors);
63
+ const headBg = colors.background[100];
64
+ const rowHover = rowBackgrounds.active;
64
65
  const isViewMode = mode === "view";
65
66
  const columnLabels = {
66
67
  read: labels.read,