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

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 (93) hide show
  1. package/dist/Components/AppSwitcher/AppSwitcher.js +12 -49
  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/SegmentedControl/SegmentedControl.d.ts +1 -1
  28. package/dist/Components/SegmentedControl/SegmentedControl.js +40 -10
  29. package/dist/Components/SegmentedControl/SegmentedControlProps.d.ts +3 -0
  30. package/dist/Components/Select/Select.styles.js +1 -1
  31. package/dist/Components/SelectSearch/SelectSearch.js +35 -17
  32. package/dist/Components/SelectV2/SelectV2.js +3 -0
  33. package/dist/Components/Table/TableProps.d.ts +2 -0
  34. package/dist/Components/Table/components/TableBody.js +7 -10
  35. package/dist/Components/Table/filters/CompactSelect.js +29 -8
  36. package/dist/Components/Table/settings/ManageColumns.js +5 -3
  37. package/dist/Components/Table/settings/TableSettings.js +4 -2
  38. package/dist/Components/Toggle/TableToggle.js +68 -18
  39. package/dist/Components/Toggle/TableToggleProps.d.ts +3 -0
  40. package/dist/Components/ToggleSwitch/ToggleSwitch.js +1 -1
  41. package/dist/Components/Trail/EditableCell.js +1 -1
  42. package/dist/Components/UserDetails/DeactivateConfirmModal.js +1 -1
  43. package/dist/Components/UserDetails/UserDetails.js +5 -3
  44. package/dist/Hooks/exclusiveOverlay.d.ts +4 -0
  45. package/dist/Hooks/exclusiveOverlay.js +22 -0
  46. package/dist/Hooks/useExclusiveOverlay.d.ts +5 -0
  47. package/dist/Hooks/useExclusiveOverlay.js +24 -0
  48. package/dist/Theme/chakra/Menu.styles.js +4 -2
  49. package/dist/Utils/table.d.ts +3 -0
  50. package/dist/Utils/table.js +44 -1
  51. package/dist/esm/Components/AppSwitcher/AppSwitcher.js +13 -50
  52. package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -3
  53. package/dist/esm/Components/Common/fieldStyles.js +1 -1
  54. package/dist/esm/Components/CopyButton/CopyButton.js +7 -6
  55. package/dist/esm/Components/DatePicker/CalendarPanel.js +9 -6
  56. package/dist/esm/Components/DatePicker/RangeDatePicker.js +28 -4
  57. package/dist/esm/Components/DatePicker/SingleDatePicker.js +49 -15
  58. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +7 -1
  59. package/dist/esm/Components/DatePicker/TimePicker.js +3 -3
  60. package/dist/esm/Components/DatePicker/TimePickerInput.js +1 -1
  61. package/dist/esm/Components/Dropdown/DropDown.js +20 -7
  62. package/dist/esm/Components/EmptyState/EmptyState.js +1 -1
  63. package/dist/esm/Components/FileUpload/FileUpload.js +2 -2
  64. package/dist/esm/Components/FilterSidebar/FilterSidebar.js +5 -5
  65. package/dist/esm/Components/FilterSidebar/filterHoverStyle.js +3 -4
  66. package/dist/esm/Components/Input/TextInput.styles.js +2 -2
  67. package/dist/esm/Components/InputTextArea/InputTextArea.style.js +2 -2
  68. package/dist/esm/Components/MoreItems/MoreItems.js +3 -1
  69. package/dist/esm/Components/MultiSelect/MultiSelect.js +2 -2
  70. package/dist/esm/Components/NavigationBar/NavigationBar.js +6 -7
  71. package/dist/esm/Components/NumberInput/NumberInput.styles.js +2 -2
  72. package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +14 -10
  73. package/dist/esm/Components/PdfViewer/PdfViewer.js +4 -4
  74. package/dist/esm/Components/RolesPermission/RolesPermission.js +4 -3
  75. package/dist/esm/Components/SearchSelect/SearchSelect.js +46 -41
  76. package/dist/esm/Components/SegmentedControl/SegmentedControl.js +42 -12
  77. package/dist/esm/Components/Select/Select.styles.js +1 -1
  78. package/dist/esm/Components/SelectSearch/SelectSearch.js +35 -17
  79. package/dist/esm/Components/SelectV2/SelectV2.js +3 -0
  80. package/dist/esm/Components/Table/components/TableBody.js +7 -10
  81. package/dist/esm/Components/Table/filters/CompactSelect.js +29 -8
  82. package/dist/esm/Components/Table/settings/ManageColumns.js +5 -3
  83. package/dist/esm/Components/Table/settings/TableSettings.js +5 -3
  84. package/dist/esm/Components/Toggle/TableToggle.js +67 -17
  85. package/dist/esm/Components/ToggleSwitch/ToggleSwitch.js +1 -1
  86. package/dist/esm/Components/Trail/EditableCell.js +1 -1
  87. package/dist/esm/Components/UserDetails/DeactivateConfirmModal.js +1 -1
  88. package/dist/esm/Components/UserDetails/UserDetails.js +5 -3
  89. package/dist/esm/Hooks/exclusiveOverlay.js +16 -0
  90. package/dist/esm/Hooks/useExclusiveOverlay.js +20 -0
  91. package/dist/esm/Theme/chakra/Menu.styles.js +4 -2
  92. package/dist/esm/Utils/table.js +45 -3
  93. package/package.json +1 -1
@@ -5,9 +5,11 @@ import Checkbox from "../../Checkbox/Checkbox.js";
5
5
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
6
6
  import { scrollbarStyles } from "../../../Theme/tokens/builders/scrollbar.js";
7
7
  import { accentTextOnCanvas } from "../../../Theme/tokens/builders/accentText.js";
8
+ import { listRowBackgrounds } from "../../../Theme/tokens/builders/rowStates.js";
8
9
  import { ChevronDown, ChevronUp, GripVertical } from "lucide-react";
9
10
  const ManageColumns = ({ columns, items, setItems, childInputMethodsRef, }) => {
10
11
  const theme = useCustomTheme();
12
+ const rowBackgrounds = useMemo(() => listRowBackgrounds(theme.colors), [theme.colors]);
11
13
  const [searchTerm, setSearchTerm] = useState("");
12
14
  const [draggedItemIndex, setDraggedItemIndex] = useState(null);
13
15
  const [error, setError] = useState(null);
@@ -78,14 +80,14 @@ const ManageColumns = ({ columns, items, setItems, childInputMethodsRef, }) => {
78
80
  return (_jsxs(ListItem, { draggable: true, onDragStart: () => handleDragStart(index), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, bg: isDraggingThisItem
79
81
  ? theme.colors.primary[100]
80
82
  : isDropZone
81
- ? theme.colors.primary[50]
83
+ ? rowBackgrounds.selected
82
84
  : "transparent", display: "flex", alignItems: "center", borderRadius: "sm", border: "1px solid", borderColor: isDraggingThisItem
83
85
  ? theme.colors.primary[400]
84
86
  : "transparent", cursor: "grab", fontSize: "13px", px: 2, py: "3px", mb: "3px", transition: "all 0.15s ease", _hover: {
85
- bg: theme.colors.gray[50],
87
+ bg: rowBackgrounds.active,
86
88
  borderColor: theme.colors.boxborder[200],
87
89
  }, _active: { cursor: "grabbing" }, children: [_jsx(Box, { as: "span", "aria-hidden": "true", display: "inline-flex", cursor: "grab", mr: 1, _hover: { color: theme.colors.gray[500] }, children: _jsx(GripVertical, { size: 14 }) }), _jsx(Checkbox, { isChecked: !item.isHidden, label: String(item.label), onChange: () => toggleCheckbox(item.id), size: "sm", labelSx: {
88
- color: item.isHidden ? theme.colors.gray[500] : theme.colors.gray[700],
90
+ color: item.isHidden ? theme.colors.textMuted : theme.colors.text[700],
89
91
  } }), _jsx(Text, { fontSize: "12px", color: theme.colors.gray[500], ml: 'auto', children: index + 1 }), _jsx(IconButton, { "aria-label": `Move ${item.label} up`, icon: _jsx(ChevronUp, { size: 14 }), variant: "ghost", size: "xs", ml: 1, minW: "auto", h: "auto", p: 0, color: theme.colors.gray[500], isDisabled: realIndex <= 0, onClick: () => moveItem(item.id, -1) }), _jsx(IconButton, { "aria-label": `Move ${item.label} down`, icon: _jsx(ChevronDown, { size: 14 }), variant: "ghost", size: "xs", ml: 1, minW: "auto", h: "auto", p: 0, color: theme.colors.gray[500], isDisabled: realIndex === -1 || realIndex >= items.length - 1, onClick: () => moveItem(item.id, 1) })] }, item.id));
90
92
  })) : (_jsx(Text, { color: theme.colors.textMuted, textAlign: "center", fontSize: "sm", py: 6, children: "No columns found" })) }), _jsxs(Text, { fontSize: "xs", color: theme.colors.gray[500], mt: 2, textAlign: "right", children: [visibleCount, " / ", items.length, " visible"] })] }));
91
93
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Flex, IconButton, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalOverlay, Tabs, TabList, TabPanels, Tab, TabPanel, Text, } from "@chakra-ui/react";
3
- import { useCallback, useRef, useState } from "react";
3
+ import { useCallback, useMemo, useRef, useState } from "react";
4
4
  import { motion } from "framer-motion";
5
5
  import ManageColumns from "./ManageColumns.js";
6
6
  import Button from "../../Button/Button.js";
@@ -8,6 +8,7 @@ import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
8
8
  import { scrollbarStyles } from "../../../Theme/tokens/builders/scrollbar.js";
9
9
  import { Settings, Check } from "lucide-react";
10
10
  import ToolTip from "../../ToolTip/ToolTip.js";
11
+ import { listRowBackgrounds } from "../../../Theme/tokens/builders/rowStates.js";
11
12
  const MotionModalContent = motion(ModalContent);
12
13
  const DENSITY_OPTIONS = [
13
14
  { value: "compact", label: "Compact", desc: "Tight rows — fit more data on screen" },
@@ -16,6 +17,7 @@ const DENSITY_OPTIONS = [
16
17
  ];
17
18
  const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, groupBy, }) => {
18
19
  const theme = useCustomTheme();
20
+ const rowBackgrounds = useMemo(() => listRowBackgrounds(theme.colors), [theme.colors]);
19
21
  const childInputMethodsRef = useRef({});
20
22
  const [settingsOpen, setSettingsOpen] = useState(false);
21
23
  const [selectedIndex, setSelectedIndex] = useState(0);
@@ -50,7 +52,7 @@ const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, g
50
52
  color: theme.colors.accentText
51
53
  } }) }), _jsxs(Modal, { isOpen: settingsOpen, onClose: () => setSettingsOpen(false), size: "md", children: [_jsx(ModalOverlay, {}), _jsxs(MotionModalContent, { mt: "0", top: "0", 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: "620px", minH: "520px", maxH: "90vh", display: "flex", flexDirection: "column", bg: theme.colors.background[50], 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) => {
52
54
  const selected = density === opt.value;
53
- 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 ? theme.colors.primary.opacity[8] : theme.colors.transparent, transition: "all 0.15s", _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));
55
+ 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: "all 0.15s", _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));
54
56
  }) }) }), _jsx(TabPanel, { px: 0, py: 0, children: _jsx(Box, { sx: {
55
57
  "& [role='listitem'], & > div > div": {
56
58
  py: "4px !important",
@@ -68,7 +70,7 @@ const TableSettings = ({ columns, onSave, density = "normal", onDensityChange, g
68
70
  .map((opt) => {
69
71
  var _a;
70
72
  const selected = selectedGroup === opt.id;
71
- 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 ? theme.colors.primary.opacity[8] : theme.colors.transparent, transition: "all 0.15s", _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__")));
73
+ 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: "all 0.15s", _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__")));
72
74
  }) })] })] }) })] }), _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 })] })] })] })] }));
73
75
  };
74
76
  export default TableSettings;
@@ -1,43 +1,93 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useLayoutEffect, useRef, useState } from "react";
2
3
  import { Box, IconButton } from "@chakra-ui/react";
3
4
  import { Columns3, Table2 } from "lucide-react";
4
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
6
  import { AA_NON_TEXT, liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
7
+ import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
6
8
  import ToolTip from "../ToolTip/ToolTip.js";
7
- const TableToggle = ({ value, onChange }) => {
9
+ const MODES = ["grid", "list"];
10
+ const TableToggle = ({ value, onChange, variant = "default" }) => {
8
11
  const theme = useCustomTheme();
9
12
  const { colors } = theme;
13
+ const isBrandSlide = variant === "brandSlide";
14
+ const isUnderlineSlide = variant === "underlineSlide";
15
+ const hasIndicator = isBrandSlide || isUnderlineSlide;
16
+ const brandFill = resolveFilledSurface(colors.primary, colors);
10
17
  const restInk = liftToContrast(colors.background[800], colors.background[600], AA_NON_TEXT);
11
18
  const hoverInk = liftToContrast(colors.background[900], colors.background[400], AA_NON_TEXT);
19
+ const trackRef = useRef(null);
20
+ const refs = useRef([]);
21
+ const [pill, setPill] = useState(null);
22
+ const selectedIndex = MODES.indexOf(value);
23
+ useLayoutEffect(() => {
24
+ if (!hasIndicator)
25
+ return;
26
+ const track = trackRef.current;
27
+ const node = refs.current[selectedIndex];
28
+ if (!track || !node) {
29
+ setPill(null);
30
+ return;
31
+ }
32
+ const trackRect = track.getBoundingClientRect();
33
+ const nodeRect = node.getBoundingClientRect();
34
+ setPill({ left: nodeRect.left - trackRect.left, width: nodeRect.width });
35
+ }, [hasIndicator, selectedIndex]);
12
36
  const styles = {
13
37
  container: {
14
38
  display: "flex",
15
39
  alignItems: "center",
16
- bg: colors.background[600],
17
- p: "0.125rem",
18
- borderRadius: "md",
40
+ bg: isBrandSlide ? colors.primary.opacity[8] : isUnderlineSlide ? "transparent" : colors.background[600],
41
+ p: isUnderlineSlide ? "0" : "0.125rem",
42
+ borderRadius: isUnderlineSlide ? "none" : "md",
43
+ borderBottom: isUnderlineSlide ? `0.0625rem solid ${colors.boxborder[200]}` : undefined,
19
44
  height: "2rem",
20
- gap: "0.125rem",
45
+ gap: isUnderlineSlide ? "0" : "0.125rem",
21
46
  width: "6.3rem",
47
+ position: "relative",
22
48
  },
23
49
  button: (mode) => ({
24
- bg: value === mode ? colors.background[50] : "transparent",
25
- boxShadow: value === mode ? "md" : "none",
26
- color: value === mode ? colors.text[900] : restInk,
27
- borderRadius: "base",
50
+ position: "relative",
51
+ zIndex: 1,
52
+ bg: hasIndicator ? "transparent" : value === mode ? colors.backgroundColor.light : "transparent",
53
+ boxShadow: hasIndicator ? "none" : value === mode ? "md" : "none",
54
+ color: isBrandSlide
55
+ ? value === mode
56
+ ? brandFill.color
57
+ : restInk
58
+ : value === mode
59
+ ? colors.accentText
60
+ : restInk,
61
+ borderRadius: isUnderlineSlide ? "none" : "base",
28
62
  height: "1.75rem",
29
- border: "0.031rem solid",
30
- borderColor: value === mode ? colors.background[400] : "transparent",
63
+ border: hasIndicator ? "none" : "0.031rem solid",
64
+ borderColor: hasIndicator
65
+ ? "transparent"
66
+ : value === mode
67
+ ? colors.primary.opacity[32]
68
+ : "transparent",
31
69
  padding: "0.313rem 0.813rem",
32
70
  _hover: {
33
- bg: value === mode
34
- ? colors.background[50]
35
- : colors.background[400],
36
- color: value === mode ? colors.text[900] : hoverInk,
71
+ bg: hasIndicator
72
+ ? "transparent"
73
+ : value === mode
74
+ ? colors.backgroundColor.light
75
+ : colors.background[400],
76
+ color: isBrandSlide
77
+ ? value === mode
78
+ ? brandFill.color
79
+ : hoverInk
80
+ : value === mode
81
+ ? colors.accentText
82
+ : hoverInk,
37
83
  },
38
- transition: "all 0.3s ease-in-out",
84
+ transition: "color 0.2s ease-in-out",
39
85
  }),
40
86
  };
41
- return (_jsxs(Box, { ...styles.container, children: [_jsx(ToolTip, { label: "Table View", placement: "top", fontSize: 12, hasArrow: true, children: _jsx(IconButton, { "aria-label": "Grid View", icon: _jsx(Table2, { size: "1.25rem" }), variant: "ghost", onClick: () => onChange("grid"), ...styles.button("grid") }) }), _jsx(ToolTip, { label: "Kanban View", placement: "top", fontSize: 12, hasArrow: true, children: _jsx(IconButton, { "aria-label": "List View", icon: _jsx(Columns3, { size: "1.25rem" }), variant: "ghost", onClick: () => onChange("list"), ...styles.button("list") }) })] }));
87
+ return (_jsxs(Box, { ref: trackRef, ...styles.container, children: [isBrandSlide && pill && (_jsx(Box, { "aria-hidden": "true", position: "absolute", top: "0.125rem", left: 0, h: "1.75rem", w: `${pill.width}px`, borderRadius: "base", 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: "-0.0625rem", 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: "Table View", placement: "top", fontSize: 12, hasArrow: true, children: _jsx(IconButton, { ref: (node) => {
88
+ refs.current[0] = node;
89
+ }, "aria-label": "Grid View", icon: _jsx(Table2, { size: "1.25rem" }), variant: "ghost", onClick: () => onChange("grid"), ...styles.button("grid") }) }), _jsx(ToolTip, { label: "Kanban View", placement: "top", fontSize: 12, hasArrow: true, children: _jsx(IconButton, { ref: (node) => {
90
+ refs.current[1] = node;
91
+ }, "aria-label": "List View", icon: _jsx(Columns3, { size: "1.25rem" }), variant: "ghost", onClick: () => onChange("list"), ...styles.button("list") }) })] }));
42
92
  };
43
93
  export default TableToggle;
@@ -11,5 +11,5 @@ export default function ToggleSwitch({ isChecked, onChange, isDisabled = false,
11
11
  return (_jsx(Box, { as: "button", type: "button", id: id, role: "switch", "aria-checked": isChecked, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, disabled: isDisabled, onClick: () => onChange(!isChecked), position: "relative", display: "inline-flex", alignItems: "center", flexShrink: 0, w: dims.w, h: dims.h, p: 0, borderRadius: "full", borderWidth: "1px", borderStyle: "solid", borderColor: isChecked ? colors.primary[500] : colors.boxborder[500], bg: isChecked ? colors.primary[500] : colors.background[600], opacity: isDisabled ? 0.5 : 1, cursor: isDisabled ? "not-allowed" : "pointer", transition: "background-color 0.2s ease, border-color 0.2s ease", _focusVisible: {
12
12
  outline: "none",
13
13
  boxShadow: `0 0 0 2px ${colors.primary[300]}`,
14
- }, children: _jsx(Box, { "aria-hidden": "true", position: "absolute", left: "0.125rem", w: dims.knob, h: dims.knob, borderRadius: "full", bg: colors.background[50], boxShadow: "sm", transition: "transform 0.2s ease", transform: isChecked ? `translateX(${dims.travel})` : "translateX(0)" }) }));
14
+ }, children: _jsx(Box, { "aria-hidden": "true", position: "absolute", left: "0.125rem", w: dims.knob, h: dims.knob, borderRadius: "full", bg: colors.white, boxShadow: "sm", transition: "transform 0.2s ease", transform: isChecked ? `translateX(${dims.travel})` : "translateX(0)" }) }));
15
15
  }
@@ -20,7 +20,7 @@ export const EditableCell = ({ row, column, isEditable, handleCellClick, handleC
20
20
  return (_jsx(Box, { width: "50%", ref: cellRef, children: _jsx(Input, { type: "date", value: value, onChange: (e) => handleCellChange(row.id, column.label, e.target.value) }) }));
21
21
  }
22
22
  else if (column.label === "priority") {
23
- return (_jsx(Box, { width: "100%", ref: cellRef, children: _jsxs(Menu, { isOpen: true, children: [_jsx(MenuButton, { as: Button, rightIcon: _jsx(ChevronDown, {}), bg: colors.teal[50], color: accentTextOnCanvas(colors.teal, colors.teal[50]), _hover: { bg: colors.teal[100] }, _active: { bg: colors.teal[200] }, children: value }), _jsxs(MenuList, { children: [_jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "Low"), _hover: { bg: colors.teal[100] }, children: "Low" }), _jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "Medium"), _hover: { bg: colors.teal[100] }, children: "Medium" }), _jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "High"), _hover: { bg: colors.teal[100] }, children: "High" })] })] }) }));
23
+ return (_jsx(Box, { width: "100%", ref: cellRef, children: _jsxs(Menu, { isOpen: true, children: [_jsx(MenuButton, { as: Button, rightIcon: _jsx(ChevronDown, {}), bg: colors.teal[50], color: accentTextOnCanvas(colors.teal, colors.teal[50]), _hover: { bg: colors.teal[100] }, _active: { bg: colors.teal[200] }, children: value }), _jsxs(MenuList, { children: [_jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "Low"), children: "Low" }), _jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "Medium"), children: "Medium" }), _jsx(MenuItem, { onClick: () => handleCellChange(row.id, column.label, "High"), children: "High" })] })] }) }));
24
24
  }
25
25
  else {
26
26
  return (_jsx(Box, { width: "100%", ref: cellRef, children: _jsx(Input, { value: value, onChange: (e) => handleCellChange(row.id, column.label, e.target.value) }) }));
@@ -9,6 +9,6 @@ const DeactivateConfirmModal = ({ isOpen, onClose, userName, isLoading, onConfir
9
9
  const { colors } = useCustomTheme();
10
10
  const mode = isDarkCanvas(colors.backgroundColor.main) ? "dark" : "light";
11
11
  const errorTone = resolveStatusTone(colors.semantic.error, mode);
12
- return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.background[50], borderRadius: "2xl", overflow: "hidden", children: [_jsxs(ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], display: "flex", alignItems: "center", gap: 3, children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: errorTone.bg, color: errorTone.fg, children: _jsx(AlertTriangle, { size: 18 }) }), _jsx(Text, { fontSize: "1.05rem", fontWeight: 600, children: labels.confirmDeactivation })] }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 6, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsx(Text, { fontSize: "md", fontWeight: 500, color: colors.text[900], children: labels.deactivateConfirmQuestion }), _jsx(Box, { bg: colors.gray[50], borderRadius: "lg", p: 4, border: "1px solid", borderColor: colors.boxborder[200], children: _jsxs(Text, { color: colors.textMuted, fontSize: "sm", children: [userName ? `${userName} ` : "", labels.deactivateConfirmDescription] }) }), _jsxs(HStack, { justifyContent: "flex-end", spacing: 3, pt: 2, children: [_jsx(Button, { label: labels.cancel, onClick: onClose, variant: "outline", size: "sm", colorScheme: "gray" }), _jsx(Button, { label: labels.deactivateUser, onClick: onConfirm, colorScheme: "red", size: "sm", isLoading: isLoading, leftIcon: _jsx(Trash2, { size: 16 }) })] })] }) })] })] }));
12
+ return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, isCentered: true, children: [_jsx(ModalOverlay, { backdropFilter: "blur(4px)" }), _jsxs(ModalContent, { bg: colors.background[50], borderRadius: "2xl", overflow: "hidden", children: [_jsxs(ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], display: "flex", alignItems: "center", gap: 3, children: [_jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: errorTone.bg, color: errorTone.fg, children: _jsx(AlertTriangle, { size: 18 }) }), _jsx(Text, { fontSize: "1.05rem", fontWeight: 600, children: labels.confirmDeactivation })] }), _jsx(ModalCloseButton, {}), _jsx(ModalBody, { py: 6, children: _jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsx(Text, { fontSize: "md", fontWeight: 500, color: colors.text[900], children: labels.deactivateConfirmQuestion }), _jsx(Box, { bg: colors.background[50], borderRadius: "lg", p: 4, border: "1px solid", borderColor: colors.boxborder[200], children: _jsxs(Text, { color: colors.textMuted, fontSize: "sm", children: [userName ? `${userName} ` : "", labels.deactivateConfirmDescription] }) }), _jsxs(HStack, { justifyContent: "flex-end", spacing: 3, pt: 2, children: [_jsx(Button, { label: labels.cancel, onClick: onClose, variant: "outline", size: "sm", colorScheme: "gray" }), _jsx(Button, { label: labels.deactivateUser, onClick: onConfirm, colorScheme: "red", size: "sm", isLoading: isLoading, leftIcon: _jsx(Trash2, { size: 16 }) })] })] }) })] })] }));
13
13
  };
14
14
  export default DeactivateConfirmModal;
@@ -5,6 +5,7 @@ import { ChevronLeft, RefreshCw, Send, Shield, Trash2, UserPlus, Users, UserRoun
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
7
7
  import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
8
+ import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
8
9
  import EmptyState from "../EmptyState/EmptyState.js";
9
10
  import AddUserModal from "./AddUserModal.js";
10
11
  import ChangeRoleModal from "./ChangeRoleModal.js";
@@ -55,6 +56,7 @@ const UserDetails = ({ users, selectedUser, selectedUserId, roleOptions = [], ca
55
56
  const [actionUserId, setActionUserId] = useState(null);
56
57
  const border = colors.boxborder[200];
57
58
  const surface = colors.background[50];
59
+ const rowBackgrounds = useMemo(() => listRowBackgrounds(colors), [colors]);
58
60
  const muted = colors.textMuted;
59
61
  const heading = colors.text[900];
60
62
  const avatarBg = colors.primary[100];
@@ -71,10 +73,10 @@ const UserDetails = ({ users, selectedUser, selectedUserId, roleOptions = [], ca
71
73
  const renderStatusBadge = (isActive) => (_jsx(Badge, { variant: "subtle", colorScheme: isActive ? successScheme : dangerScheme, borderRadius: "full", px: 2, py: 0.5, fontSize: "0.65rem", fontWeight: 600, textTransform: "none", children: isActive ? labels.active : labels.inactive }));
72
74
  return (_jsxs(Flex, { backgroundColor: colors.backgroundColor.main, minHeight: minHeight, p: { base: 3, md: 4 }, gap: 3, flexDirection: { base: "column", lg: "row" }, children: [_jsxs(Box, { width: { base: "100%", lg: "300px" }, backgroundColor: surface, borderRadius: "xl", boxShadow: "sm", border: "1px solid", borderColor: border, position: "relative", order: { base: 2, lg: 1 }, overflow: "hidden", display: "flex", flexDirection: "column", children: [_jsxs(Flex, { px: 4, py: 3, borderBottom: "1px solid", borderColor: border, alignItems: "center", justifyContent: "space-between", children: [_jsxs(HStack, { spacing: 2, children: [onBack && (_jsx(IconButton, { "aria-label": "Go back", icon: _jsx(ChevronLeft, { size: 18 }), variant: "ghost", size: "xs", color: muted, onClick: onBack })), _jsx(Heading, { size: "sm", fontWeight: 600, color: heading, children: labels.teamMembers }), _jsx(Badge, { colorScheme: "gray", borderRadius: "full", fontSize: "0.65rem", px: 2, children: users.length })] }), onRefresh && (_jsx(IconButton, { "aria-label": labels.refreshList, icon: _jsx(RefreshCw, { size: 15 }), variant: "ghost", size: "xs", color: muted, onClick: onRefresh, isLoading: isUsersLoading }))] }), _jsx(Box, { flex: 1, overflowY: "auto", maxHeight: { base: "380px", lg: `calc(${minHeight} - 80px)` }, children: isUsersLoading ? (_jsx(VStack, { spacing: 2, p: 3, children: Array.from({ length: 6 }).map((_, idx) => (_jsxs(Flex, { alignItems: "center", gap: 3, p: 2, w: "100%", children: [_jsx(SkeletonCircle, { size: "9" }), _jsxs(Box, { flex: 1, children: [_jsx(Skeleton, { height: "12px", mb: 2, width: "80%" }), _jsx(Skeleton, { height: "9px", width: "60%" })] })] }, idx))) })) : users.length === 0 ? (_jsx(EmptyState, { icon: Users, title: labels.noUsers, size: "sm", minH: "220px" })) : (_jsx(VStack, { spacing: 1, p: 2, align: "stretch", children: users.map((user) => {
73
75
  const isSelected = selectedUserId != null && selectedUserId === user.id;
74
- return (_jsxs(Flex, { p: 2.5, w: "100%", cursor: "pointer", alignItems: "center", gap: 2.5, backgroundColor: isSelected ? colors.primary[50] : "transparent", _hover: {
76
+ return (_jsxs(Flex, { p: 2.5, w: "100%", cursor: "pointer", alignItems: "center", gap: 2.5, backgroundColor: isSelected ? rowBackgrounds.selected : "transparent", _hover: {
75
77
  background: isSelected
76
- ? colors.primary[50]
77
- : resolveHoverTint(colors.gray[50], surface),
78
+ ? rowBackgrounds.selectedActive
79
+ : rowBackgrounds.active,
78
80
  }, transition: "background 0.15s ease", borderRadius: "lg", position: "relative", onClick: () => onSelectUser === null || onSelectUser === void 0 ? void 0 : onSelectUser(user), children: [isSelected && (_jsx(Box, { position: "absolute", left: 0, top: "20%", bottom: "20%", width: "3px", borderRadius: "full", bg: colors.primary[500] })), _jsx(Avatar, { size: "sm", name: `${user.firstName} ${user.lastName}`, src: user.profile, bg: avatarBg, color: avatarColor }), _jsxs(Box, { flex: 1, overflow: "hidden", children: [_jsxs(Text, { fontSize: "sm", fontWeight: 600, noOfLines: 1, color: heading, children: [user.firstName, " ", user.lastName] }), _jsx(Text, { fontSize: "xs", color: muted, noOfLines: 1, children: user.email })] }), renderStatusBadge(user.isActive)] }, user.id));
79
81
  }) })) })] }), _jsxs(Box, { flex: 1, backgroundColor: surface, borderRadius: "xl", boxShadow: "sm", border: "1px solid", borderColor: border, display: "flex", flexDirection: "column", order: { base: 1, lg: 2 }, overflow: "hidden", children: [_jsxs(Flex, { justifyContent: "space-between", alignItems: "center", px: 4, py: 3, borderBottom: "1px solid", borderColor: border, children: [_jsx(Heading, { size: "sm", fontWeight: 600, color: heading, children: selectedUser ? labels.userDetails : labels.selectTeamMember }), canManageUsers && (_jsx(Button, { size: "sm", colorScheme: "primary", fontSize: "xs", leftIcon: _jsx(UserPlus, { size: 15 }), onClick: onAddUserOpen, children: labels.addUser }))] }), _jsx(Box, { flex: 1, overflowY: "auto", children: isUsersLoading ? (_jsxs(VStack, { spacing: 4, p: 4, align: "stretch", children: [_jsxs(Flex, { align: "center", gap: 4, children: [_jsx(SkeletonCircle, { size: "16" }), _jsxs(Box, { flex: 1, children: [_jsx(Skeleton, { height: "18px", width: "50%", mb: 2 }), _jsx(Skeleton, { height: "12px", width: "35%" })] })] }), Array.from({ length: 4 }).map((_, idx) => (_jsxs(Box, { w: "100%", children: [_jsx(Skeleton, { height: "12px", width: "30%", mb: 2 }), _jsx(Skeleton, { height: "10px", width: "80%" })] }, idx)))] })) : selectedUser ? (_jsxs(_Fragment, { children: [_jsxs(Flex, { direction: { base: "column", md: "row" }, alignItems: { base: "flex-start", md: "center" }, justifyContent: "space-between", gap: 4, p: 4, borderBottom: "1px solid", borderColor: border, children: [_jsxs(Flex, { alignItems: "center", gap: 4, children: [_jsxs(Box, { position: "relative", children: [_jsx(Avatar, { size: "lg", name: selectedUser.name, src: selectedUser.profilePhoto, bg: avatarBg, color: avatarColor }), selectedUser.isCurrent && (_jsx(Badge, { position: "absolute", bottom: -1, right: -1, colorScheme: "blue", variant: "solid", fontSize: "0.6rem", borderRadius: "full", px: 2, py: 0.5, boxShadow: "sm", textTransform: "none", children: labels.you }))] }), _jsxs(Box, { children: [_jsx(Heading, { size: "md", mb: 1, color: heading, children: selectedUser.name }), _jsx(Text, { fontSize: "sm", color: muted, mb: 2, children: selectedUser.role }), _jsxs(HStack, { spacing: 2, children: [renderStatusBadge(selectedUser.isActive), selectedUser.isPending && (_jsx(Badge, { variant: "subtle", borderRadius: "full", px: 2, py: 0.5, fontSize: "0.65rem", fontWeight: 600, colorScheme: "orange", textTransform: "none", children: labels.pendingInvitation }))] })] })] }), canManageUsers &&
80
82
  !selectedUser.isSuperAdmin && (_jsxs(HStack, { spacing: 2, flexWrap: "wrap", children: [!selectedUser.isCurrent && !selectedUser.isActive && (_jsx(Button, { size: "xs", variant: "outline", colorScheme: "blue", fontSize: "xs", leftIcon: _jsx(Send, { size: 13 }), isLoading: isInviteLoading, onClick: () => selectedUser.userId != null &&
@@ -0,0 +1,16 @@
1
+ let active = null;
2
+ export const exclusiveOpen = (id, close) => {
3
+ if (active && active.id !== id) {
4
+ active.close();
5
+ }
6
+ active = { id, close };
7
+ };
8
+ export const exclusiveClose = (id) => {
9
+ if ((active === null || active === void 0 ? void 0 : active.id) === id) {
10
+ active = null;
11
+ }
12
+ };
13
+ /** Test-only reset — not exported from the package root. */
14
+ export const resetExclusiveOverlay = () => {
15
+ active = null;
16
+ };
@@ -0,0 +1,20 @@
1
+ import { useCallback, useEffect, useId, useRef } from "react";
2
+ import { exclusiveClose, exclusiveOpen } from "./exclusiveOverlay.js";
3
+ /**
4
+ * Register this overlay with the global dismiss coordinator. Call `requestOpen()`
5
+ * immediately before opening; `onClose` is invoked when another overlay opens.
6
+ */
7
+ export const useExclusiveOverlay = (isOpen, onClose) => {
8
+ const id = useId();
9
+ const onCloseRef = useRef(onClose);
10
+ onCloseRef.current = onClose;
11
+ const requestOpen = useCallback(() => {
12
+ exclusiveOpen(id, () => onCloseRef.current());
13
+ }, [id]);
14
+ useEffect(() => {
15
+ if (!isOpen) {
16
+ exclusiveClose(id);
17
+ }
18
+ }, [isOpen, id]);
19
+ return requestOpen;
20
+ };
@@ -1,5 +1,6 @@
1
1
  import { createMultiStyleConfigHelpers, cssVar } from "@chakra-ui/react";
2
2
  import { menuAnatomy } from "@chakra-ui/anatomy";
3
+ import { listRowBackgrounds } from "../tokens/builders/rowStates.js";
3
4
  import { paletteOf } from "./paletteFromTheme.js";
4
5
  const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(menuAnatomy.keys);
5
6
  const $bg = cssVar("menu-bg");
@@ -21,8 +22,9 @@ const $bg = cssVar("menu-bg");
21
22
  const $itemBg = cssVar("menu-item-bg");
22
23
  const baseStyle = definePartsStyle(({ theme }) => {
23
24
  const colors = paletteOf(theme);
24
- const hoverBg = colors.primary.opacity[8];
25
- const activeBg = colors.primary.opacity[16];
25
+ const rowBgs = listRowBackgrounds(colors);
26
+ const hoverBg = rowBgs.active;
27
+ const activeBg = rowBgs.selectedActive;
26
28
  return {
27
29
  list: {
28
30
  [$bg.variable]: colors.backgroundColor.light,
@@ -1,7 +1,9 @@
1
1
  import React, { useCallback, useEffect, useRef } from "react";
2
- import { DEFAULT_BLACK, DEFAULT_WHITE, isDarkCanvas, onFilled, } from "../Theme/tokens/builders/accentText.js";
2
+ import { AA_NORMAL_TEXT, DEFAULT_BLACK, DEFAULT_WHITE, isDarkCanvas, onFilled, } from "../Theme/tokens/builders/accentText.js";
3
+ import { compositeOver } from "../Theme/tokens/builders/color.js";
4
+ import { liftToContrast } from "../Theme/tokens/builders/outlineRung.js";
3
5
  import { labelOnFill, solidFillRung } from "../Theme/tokens/builders/filledSurface.js";
4
- import { resolveStatusTone } from "../Theme/tokens/builders/statusTone.js";
6
+ import { resolveAvatarFill, resolveStatusTone } from "../Theme/tokens/builders/statusTone.js";
5
7
  // Built once, not per comparison: sorting 10k rows runs this ~130k times, and constructing a
6
8
  // collator is orders of magnitude dearer than using one.
7
9
  const COLLATOR = new Intl.Collator(undefined, {
@@ -54,7 +56,45 @@ export function SortMultiColumnData(data, sortConfig) {
54
56
  return 0;
55
57
  });
56
58
  }
59
+ /** Theme-aware status palette per value — soft fill + semantic ink from `resolveStatusTone`. */
60
+ export function buildSemanticStatusPalette(toneByValue, theme) {
61
+ const c = theme.colors;
62
+ const mode = isDarkCanvas(c.backgroundColor.main) ? "dark" : "light";
63
+ const scales = {
64
+ info: c.semantic.info,
65
+ warning: c.semantic.warning,
66
+ success: c.semantic.success,
67
+ error: c.semantic.error,
68
+ neutral: c.gray,
69
+ };
70
+ return Object.fromEntries(Object.entries(toneByValue).map(([value, key]) => {
71
+ const scale = scales[key];
72
+ const tone = resolveStatusTone(scale, mode);
73
+ const solidRung = solidFillRung(scale, c.white);
74
+ const solid = scale[solidRung];
75
+ return [
76
+ value,
77
+ {
78
+ solid,
79
+ soft: tone.bg,
80
+ text: tone.fg,
81
+ onSolid: labelOnFill(solid, c.white, c.black),
82
+ },
83
+ ];
84
+ }));
85
+ }
57
86
  const withAlpha = (hex, aa) => /^#([0-9a-fA-F]{6})$/.test(hex) ? `${hex}${aa}` : hex;
87
+ /** Consumer `statusColors` values are fill seeds — derive bleed + pill ink from them. */
88
+ const resolveStatusOverride = (fill, white, black, surface) => {
89
+ const soft = withAlpha(fill, "22");
90
+ const solid = resolveAvatarFill(fill);
91
+ return {
92
+ solid,
93
+ soft,
94
+ text: liftToContrast(fill, compositeOver(soft, surface), AA_NORMAL_TEXT),
95
+ onSolid: onFilled(solid, white, black),
96
+ };
97
+ };
58
98
  /** Deterministic, theme-aware color palette for groups + status pills. */
59
99
  export function buildTablePalette(theme) {
60
100
  const c = theme.colors;
@@ -92,10 +132,12 @@ const hashKey = (value) => {
92
132
  };
93
133
  /** Pick a deterministic palette color for a value, with optional consumer override hex. */
94
134
  export function pickTableColor(value, palette, override, theme) {
135
+ var _a;
95
136
  const white = theme ? theme.colors.white : DEFAULT_WHITE;
96
137
  const black = theme ? theme.colors.black : DEFAULT_BLACK;
97
138
  if (override) {
98
- return { solid: override, soft: withAlpha(override, "22"), text: override, onSolid: onFilled(override, white, black) };
139
+ const surface = (_a = theme === null || theme === void 0 ? void 0 : theme.colors.background[50]) !== null && _a !== void 0 ? _a : DEFAULT_WHITE;
140
+ return resolveStatusOverride(override, white, black, surface);
99
141
  }
100
142
  if (!palette.length) {
101
143
  throw new Error("pickTableColor: empty palette — build it with buildTablePalette(theme).");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelize-design-library",
3
- "version": "2.4.2-beta.34",
3
+ "version": "2.4.2-beta.36",
4
4
  "description": "React component library for Pixelize apps: themeable Chakra-based components, design tokens and light/dark brand theming.",
5
5
  "keywords": [
6
6
  "react",