pixelize-design-library 2.4.2-beta.3 → 2.4.2-beta.5

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 (111) hide show
  1. package/dist/Components/Accordion/Accordion.js +2 -2
  2. package/dist/Components/Button/Button.styles.js +4 -3
  3. package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.js +5 -5
  4. package/dist/Components/Common/fieldStyles.js +1 -1
  5. package/dist/Components/CopyButton/CopyButton.js +1 -1
  6. package/dist/Components/CustomModulesTable/EditModuleModal.js +1 -1
  7. package/dist/Components/DatePicker/CalendarPanel.js +1 -1
  8. package/dist/Components/DatePicker/RangeDatePicker.js +1 -1
  9. package/dist/Components/DatePicker/SingleDatePicker.js +1 -1
  10. package/dist/Components/DatePicker/TimeOnlyPicker.js +1 -1
  11. package/dist/Components/Dropdown/DropDown.js +3 -13
  12. package/dist/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtp.js +1 -1
  13. package/dist/Components/FilePreview/FilePreview.js +1 -1
  14. package/dist/Components/FilterSidebar/FilterSidebar.js +2 -2
  15. package/dist/Components/Input/TextInput.styles.js +5 -1
  16. package/dist/Components/KanbanBoard/KanbanBoard.js +5 -45
  17. package/dist/Components/LimitReachedModal/LimitReachedModal.js +4 -5
  18. package/dist/Components/MultiSelect/MultiSelect.js +1 -1
  19. package/dist/Components/OrgSwitcher/OrgSwitcher.js +2 -2
  20. package/dist/Components/PinInput/PinInput.js +1 -1
  21. package/dist/Components/PlanPill/PlanPill.js +5 -5
  22. package/dist/Components/PlanPill/planPillGradient.d.ts +2 -14
  23. package/dist/Components/PlanPill/planPillGradient.js +3 -15
  24. package/dist/Components/ProductCard/ProductPrice.js +1 -1
  25. package/dist/Components/ProfileCard/ProfileCard.js +1 -1
  26. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +1 -1
  27. package/dist/Components/Reorder/Reorder.js +1 -1
  28. package/dist/Components/ScrollbarBox/ScrollbarBox.d.ts +13 -0
  29. package/dist/Components/ScrollbarBox/ScrollbarBox.js +11 -0
  30. package/dist/Components/SearchSelect/SearchSelect.js +3 -3
  31. package/dist/Components/Select/Select.styles.js +1 -1
  32. package/dist/Components/SelectSearch/SelectSearch.js +3 -3
  33. package/dist/Components/SelectV2/SelectV2.js +3 -10
  34. package/dist/Components/StageProgress/StageProgress.js +2 -9
  35. package/dist/Components/Table/Table.js +7 -20
  36. package/dist/Components/Table/components/TableBody.js +1 -1
  37. package/dist/Components/Table/components/TableHeader.js +1 -1
  38. package/dist/Components/Table/filters/ActiveFilters.js +2 -18
  39. package/dist/Components/Table/settings/ManageColumns.js +2 -16
  40. package/dist/Components/Table/settings/TableSettings.js +4 -10
  41. package/dist/Components/Timeline/Timeline.js +2 -2
  42. package/dist/Components/Toaster/Toaster.js +1 -1
  43. package/dist/Components/UpgradeButton/UpgradeButton.js +3 -3
  44. package/dist/Constants/Sidebar.js +3 -2
  45. package/dist/Theme/chakra/Menu.styles.d.ts +1 -0
  46. package/dist/Theme/chakra/Menu.styles.js +3 -0
  47. package/dist/Theme/chakra/componentStyles.d.ts +1 -0
  48. package/dist/Theme/chakra/createBrandTheme.js +3 -16
  49. package/dist/Theme/tokens/builders/gradientInk.d.ts +22 -0
  50. package/dist/Theme/tokens/builders/gradientInk.js +28 -0
  51. package/dist/Theme/tokens/builders/index.d.ts +2 -0
  52. package/dist/Theme/tokens/builders/index.js +2 -0
  53. package/dist/Theme/tokens/builders/outlineRung.d.ts +5 -0
  54. package/dist/Theme/tokens/builders/outlineRung.js +19 -0
  55. package/dist/Theme/tokens/builders/scrollbar.d.ts +12 -0
  56. package/dist/Theme/tokens/builders/scrollbar.js +57 -0
  57. package/dist/Theme/tokens/builders/surfaceRungs.d.ts +2 -0
  58. package/dist/Theme/tokens/builders/surfaceRungs.js +7 -2
  59. package/dist/esm/Components/Accordion/Accordion.js +2 -2
  60. package/dist/esm/Components/Button/Button.styles.js +5 -4
  61. package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +5 -5
  62. package/dist/esm/Components/Common/fieldStyles.js +1 -1
  63. package/dist/esm/Components/CopyButton/CopyButton.js +1 -1
  64. package/dist/esm/Components/CustomModulesTable/EditModuleModal.js +1 -1
  65. package/dist/esm/Components/DatePicker/CalendarPanel.js +1 -1
  66. package/dist/esm/Components/DatePicker/RangeDatePicker.js +1 -1
  67. package/dist/esm/Components/DatePicker/SingleDatePicker.js +1 -1
  68. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +1 -1
  69. package/dist/esm/Components/Dropdown/DropDown.js +3 -13
  70. package/dist/esm/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtp.js +1 -1
  71. package/dist/esm/Components/FilePreview/FilePreview.js +1 -1
  72. package/dist/esm/Components/FilterSidebar/FilterSidebar.js +2 -2
  73. package/dist/esm/Components/Input/TextInput.styles.js +5 -1
  74. package/dist/esm/Components/KanbanBoard/KanbanBoard.js +5 -45
  75. package/dist/esm/Components/LimitReachedModal/LimitReachedModal.js +4 -5
  76. package/dist/esm/Components/MultiSelect/MultiSelect.js +1 -1
  77. package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +2 -2
  78. package/dist/esm/Components/PinInput/PinInput.js +1 -1
  79. package/dist/esm/Components/PlanPill/PlanPill.js +6 -6
  80. package/dist/esm/Components/PlanPill/planPillGradient.js +3 -15
  81. package/dist/esm/Components/ProductCard/ProductPrice.js +1 -1
  82. package/dist/esm/Components/ProfileCard/ProfileCard.js +1 -1
  83. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +1 -1
  84. package/dist/esm/Components/Reorder/Reorder.js +1 -1
  85. package/dist/esm/Components/ScrollbarBox/ScrollbarBox.js +9 -0
  86. package/dist/esm/Components/SearchSelect/SearchSelect.js +3 -3
  87. package/dist/esm/Components/Select/Select.styles.js +1 -1
  88. package/dist/esm/Components/SelectSearch/SelectSearch.js +3 -3
  89. package/dist/esm/Components/SelectV2/SelectV2.js +3 -10
  90. package/dist/esm/Components/StageProgress/StageProgress.js +2 -9
  91. package/dist/esm/Components/Table/Table.js +7 -20
  92. package/dist/esm/Components/Table/components/TableBody.js +1 -1
  93. package/dist/esm/Components/Table/components/TableHeader.js +1 -1
  94. package/dist/esm/Components/Table/filters/ActiveFilters.js +2 -18
  95. package/dist/esm/Components/Table/settings/ManageColumns.js +2 -16
  96. package/dist/esm/Components/Table/settings/TableSettings.js +4 -10
  97. package/dist/esm/Components/Timeline/Timeline.js +2 -2
  98. package/dist/esm/Components/Toaster/Toaster.js +1 -1
  99. package/dist/esm/Components/UpgradeButton/UpgradeButton.js +3 -3
  100. package/dist/esm/Constants/Sidebar.js +3 -2
  101. package/dist/esm/Theme/chakra/Menu.styles.js +3 -0
  102. package/dist/esm/Theme/chakra/createBrandTheme.js +3 -16
  103. package/dist/esm/Theme/tokens/builders/gradientInk.js +22 -0
  104. package/dist/esm/Theme/tokens/builders/index.js +2 -0
  105. package/dist/esm/Theme/tokens/builders/outlineRung.js +18 -0
  106. package/dist/esm/Theme/tokens/builders/scrollbar.js +52 -0
  107. package/dist/esm/Theme/tokens/builders/surfaceRungs.js +7 -2
  108. package/dist/esm/index.js +4 -1
  109. package/dist/index.d.ts +7 -1
  110. package/dist/index.js +13 -3
  111. package/package.json +1 -1
@@ -19,3 +19,5 @@ __exportStar(require("./buildBrandTokens"), exports);
19
19
  __exportStar(require("./buildDarkPalette"), exports);
20
20
  __exportStar(require("./chartColorsFromTheme"), exports);
21
21
  __exportStar(require("./color"), exports);
22
+ __exportStar(require("./scrollbar"), exports);
23
+ __exportStar(require("./gradientInk"), exports);
@@ -14,6 +14,11 @@ export declare const AA_NON_TEXT = 3;
14
14
  * Tries the far side first, falls back to the near side, and stops at the first passing step.
15
15
  */
16
16
  export declare function liftToContrast(hex: string, backdrop: string, target?: number): string;
17
+ /**
18
+ * Mirror of `liftToContrast`: walks ink TOWARD the backdrop, stopping at the last step that
19
+ * still clears `target`. For ink that must stay legible without reading as body copy.
20
+ */
21
+ export declare function softenToContrast(hex: string, backdrop: string, target: number): string;
17
22
  /**
18
23
  * `boxborder[500]` is the rung every control outline reads (Checkbox, SearchSelect, the date
19
24
  * pickers, the editor's inputs). It was authored as a decorative value — measured 1.30-2.56:1
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AA_NON_TEXT = exports.MIN_PERCEPTIBLE_STEP = void 0;
4
4
  exports.liftToContrast = liftToContrast;
5
+ exports.softenToContrast = softenToContrast;
5
6
  exports.withOutlineRung = withOutlineRung;
6
7
  exports.resolveHoverTint = resolveHoverTint;
7
8
  const color_1 = require("./color");
@@ -36,6 +37,24 @@ function liftToContrast(hex, backdrop, target = exports.AA_NON_TEXT) {
36
37
  const ends = [(0, color_1.withLightness)(hex, 100, s), (0, color_1.withLightness)(hex, 0, s)];
37
38
  return (0, color_1.contrastRatio)(ends[0], backdrop) >= (0, color_1.contrastRatio)(ends[1], backdrop) ? ends[0] : ends[1];
38
39
  }
40
+ /**
41
+ * Mirror of `liftToContrast`: walks ink TOWARD the backdrop, stopping at the last step that
42
+ * still clears `target`. For ink that must stay legible without reading as body copy.
43
+ */
44
+ function softenToContrast(hex, backdrop, target) {
45
+ if ((0, color_1.contrastRatio)(hex, backdrop) <= target)
46
+ return hex;
47
+ const { s, l: start } = (0, color_1.hexToHsl)(hex);
48
+ const toward = (0, color_1.relativeLuminance)(backdrop) < 0.5 ? -1 : 1;
49
+ let softest = hex;
50
+ for (let l = start; l > 0 && l < 100; l += toward) {
51
+ const next = (0, color_1.withLightness)(hex, l, s);
52
+ if ((0, color_1.contrastRatio)(next, backdrop) < target)
53
+ break;
54
+ softest = next;
55
+ }
56
+ return softest;
57
+ }
39
58
  /**
40
59
  * `boxborder[500]` is the rung every control outline reads (Checkbox, SearchSelect, the date
41
60
  * pickers, the editor's inputs). It was authored as a decorative value — measured 1.30-2.56:1
@@ -0,0 +1,12 @@
1
+ import type { PaletteProps } from "../types";
2
+ export type ScrollbarStyle = Record<string, unknown>;
3
+ /** One width everywhere. The 3px, 4px, 5px and 10px bars in use were all accidents. */
4
+ export declare const SCROLLBAR_WIDTH = "6px";
5
+ export type ScrollbarVariant = "default" | "overlay" | "hover";
6
+ /**
7
+ * The single source of scrollbar chrome. `overlay` drops the track for bars that float over a
8
+ * card; `hover` keeps the thumb invisible until the region is hovered.
9
+ */
10
+ export declare function scrollbarStyles(palette: PaletteProps, variant?: ScrollbarVariant): ScrollbarStyle;
11
+ /** The same chrome for the document itself, where `&` selectors do not apply. */
12
+ export declare function globalScrollbarStyles(palette: PaletteProps): ScrollbarStyle;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SCROLLBAR_WIDTH = void 0;
4
+ exports.scrollbarStyles = scrollbarStyles;
5
+ exports.globalScrollbarStyles = globalScrollbarStyles;
6
+ /** One width everywhere. The 3px, 4px, 5px and 10px bars in use were all accidents. */
7
+ exports.SCROLLBAR_WIDTH = "6px";
8
+ const RADIUS = "6px";
9
+ /**
10
+ * The single source of scrollbar chrome. `overlay` drops the track for bars that float over a
11
+ * card; `hover` keeps the thumb invisible until the region is hovered.
12
+ */
13
+ function scrollbarStyles(palette, variant = "default") {
14
+ const { gray } = palette;
15
+ const track = variant === "default" ? gray[100] : "transparent";
16
+ const thumb = variant === "hover" ? "transparent" : gray[400];
17
+ return {
18
+ scrollbarWidth: "thin",
19
+ scrollbarColor: `${thumb} ${track}`,
20
+ "&::-webkit-scrollbar": {
21
+ width: exports.SCROLLBAR_WIDTH,
22
+ height: exports.SCROLLBAR_WIDTH,
23
+ },
24
+ "&::-webkit-scrollbar-track": {
25
+ background: track,
26
+ borderRadius: RADIUS,
27
+ },
28
+ "&::-webkit-scrollbar-thumb": {
29
+ background: thumb,
30
+ borderRadius: RADIUS,
31
+ transition: "background 0.2s ease",
32
+ },
33
+ "&::-webkit-scrollbar-thumb:hover": {
34
+ background: gray[500],
35
+ },
36
+ "&::-webkit-scrollbar-corner": {
37
+ background: track,
38
+ },
39
+ ...(variant === "hover"
40
+ ? {
41
+ "&:hover": { scrollbarColor: `${gray[400]} ${track}` },
42
+ "&:hover::-webkit-scrollbar-thumb": { background: gray[400] },
43
+ }
44
+ : {}),
45
+ };
46
+ }
47
+ /** The same chrome for the document itself, where `&` selectors do not apply. */
48
+ function globalScrollbarStyles(palette) {
49
+ const { gray } = palette;
50
+ return {
51
+ "::-webkit-scrollbar": { width: exports.SCROLLBAR_WIDTH, height: exports.SCROLLBAR_WIDTH },
52
+ "::-webkit-scrollbar-track": { background: gray[100] },
53
+ "::-webkit-scrollbar-thumb": { background: gray[400], borderRadius: RADIUS },
54
+ "::-webkit-scrollbar-thumb:hover": { background: gray[500] },
55
+ "::-webkit-scrollbar-corner": { background: gray[100] },
56
+ };
57
+ }
@@ -1,4 +1,6 @@
1
1
  import type { PaletteProps } from "../types";
2
+ /** Clear of the 4.5 gate, but well under body text so a hint never reads as a value. */
3
+ export declare const PLACEHOLDER_TEXT = 5;
2
4
  export declare const namedSurfaces: (palette: PaletteProps) => string[];
3
5
  /** The surface an ink is closest to — clearing it clears every other one. */
4
6
  export declare const hardestSurface: (ink: string, surfaces: string[]) => string;
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hardestSurface = exports.namedSurfaces = void 0;
3
+ exports.hardestSurface = exports.namedSurfaces = exports.PLACEHOLDER_TEXT = void 0;
4
4
  exports.withSurfaceRungs = withSurfaceRungs;
5
5
  const color_1 = require("./color");
6
6
  const outlineRung_1 = require("./outlineRung");
7
7
  const accentText_1 = require("./accentText");
8
8
  const semanticText_1 = require("./semanticText");
9
+ /** Clear of the 4.5 gate, but well under body text so a hint never reads as a value. */
10
+ exports.PLACEHOLDER_TEXT = 5;
9
11
  const namedSurfaces = (palette) => [
10
12
  ...Object.values(palette.backgroundColor),
11
13
  palette.background[50],
@@ -19,6 +21,7 @@ exports.hardestSurface = hardestSurface;
19
21
  function withSurfaceRungs(palette) {
20
22
  const surfaces = (0, exports.namedSurfaces)(palette);
21
23
  const lift = (ink, target) => (0, outlineRung_1.liftToContrast)(ink, (0, exports.hardestSurface)(ink, surfaces), target);
24
+ const soften = (ink, target) => (0, outlineRung_1.softenToContrast)(ink, (0, exports.hardestSurface)(ink, surfaces), target);
22
25
  const semanticText = semanticText_1.SEMANTIC_TONES.reduce((acc, tone) => {
23
26
  acc[tone] = lift(palette.semanticText[tone], accentText_1.AA_NORMAL_TEXT);
24
27
  return acc;
@@ -30,9 +33,11 @@ function withSurfaceRungs(palette) {
30
33
  semanticText,
31
34
  text: { ...palette.text, 500: lift(palette.text[500], accentText_1.AA_NORMAL_TEXT) },
32
35
  header: { ...palette.header, 500: lift(palette.header[500], accentText_1.AA_NORMAL_TEXT) },
36
+ // Placeholder must stay legible without reading as a filled value: the ramp delivered
37
+ // 6.85:1, level with `textMuted`, so it is settled back down to just clear of AA.
33
38
  placeholder: {
34
39
  ...palette.placeholder,
35
- 500: lift(palette.placeholder[500], accentText_1.AA_NORMAL_TEXT),
40
+ 500: soften(lift(palette.placeholder[500], accentText_1.AA_NORMAL_TEXT), exports.PLACEHOLDER_TEXT),
36
41
  },
37
42
  boxborder: { ...palette.boxborder, 500: lift(palette.boxborder[500], outlineRung_1.AA_NON_TEXT) },
38
43
  };
@@ -8,13 +8,13 @@ import { getAccordionHoverColors } from "./accordionColors.js";
8
8
  const Accordion = ({ allowMultiple, allowToggle, index, onChange, reduceMotion, items, ...rest }) => {
9
9
  const { colors } = useCustomTheme();
10
10
  const isDark = isDarkCanvas(colors.backgroundColor.main);
11
- const border = colors.boxborder[300];
11
+ const border = colors.boxborder[200];
12
12
  const headingColor = colors.text[800];
13
13
  const bodyColor = colors.text[600];
14
14
  const { expandedBg, softHover } = useMemo(() => getAccordionHoverColors(colors, isDark), [colors, isDark]);
15
15
  return (_jsx(ChakraAccordian, { allowMultiple: allowMultiple, allowToggle: allowToggle, index: index, onChange: onChange, reduceMotion: reduceMotion, ...rest, children: items.map((item, idx) => {
16
16
  var _a;
17
- return (_jsx(AccordionItem, { border: `0.063rem solid ${border}`, borderRadius: "xl", bg: colors.background[50], mb: 3, overflow: "hidden", transition: "border-color 0.15s ease, box-shadow 0.15s ease", _last: { mb: 0 }, _hover: { borderColor: colors.boxborder[400] }, ...item.itemProps, sx: (_a = item.customStyles) === null || _a === void 0 ? void 0 : _a.itemStyle, children: ({ isExpanded }) => {
17
+ return (_jsx(AccordionItem, { border: `0.063rem solid ${border}`, borderRadius: "xl", bg: colors.background[50], mb: 3, overflow: "hidden", transition: "border-color 0.15s ease, box-shadow 0.15s ease", _last: { mb: 0 }, _hover: { borderColor: colors.boxborder[200] }, ...item.itemProps, sx: (_a = item.customStyles) === null || _a === void 0 ? void 0 : _a.itemStyle, children: ({ isExpanded }) => {
18
18
  var _a, _b, _c;
19
19
  return (_jsxs(_Fragment, { children: [_jsx("h2", { children: _jsxs(AccordionButton, { px: 4, py: 3, gap: 3, fontSize: "0.875rem", fontWeight: 600, color: headingColor, bg: isExpanded ? expandedBg : "transparent", transition: "background 0.15s ease", _hover: { bg: isExpanded ? expandedBg : softHover }, _focusVisible: {
20
20
  boxShadow: "none",
@@ -1,4 +1,5 @@
1
- import { accentTextOnCanvas, isDarkCanvas, onFilled, onGradient } from "../../Theme/tokens/builders/accentText.js";
1
+ import { accentTextOnCanvas, isDarkCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
2
+ import { resolveGradient, gradientCss } from "../../Theme/tokens/builders/gradientInk.js";
2
3
  /**
3
4
  * Outline/ghost/link text sits ON the canvas, so it needs a rung that stays readable there —
4
5
  * `[500]` is pinned dark enough to carry a white label on the solid variant and measures only
@@ -138,11 +139,11 @@ export const Button = {
138
139
  // Theme-based two-tone gradient: each theme defines its own `gradient` {from,to} pair.
139
140
  // Ignores colorScheme; hover/active shift brightness so it works for any pair.
140
141
  gradient: ({ theme }) => {
141
- const g = theme.colors.gradient;
142
- const bg = `linear-gradient(135deg, ${g.from} 0%, ${g.to} 100%)`;
142
+ const g = resolveGradient(theme.colors.gradient, theme.colors.white, theme.colors.black);
143
+ const bg = gradientCss(g);
143
144
  return {
144
145
  bgImage: bg,
145
- color: onGradient(g.from, g.to, theme.colors.white, theme.colors.black),
146
+ color: g.ink,
146
147
  border: "none",
147
148
  _hover: {
148
149
  bgImage: bg,
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect } from "react";
3
3
  import { Box, Button, ButtonGroup, IconButton, Menu, MenuButton, MenuItem, MenuList, Tooltip, } from "@chakra-ui/react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
- import { onGradient } from "../../Theme/tokens/builders/accentText.js";
5
+ import { resolveGradient, gradientCss } from "../../Theme/tokens/builders/gradientInk.js";
6
6
  import { hexToRgb } from "../../Theme/tokens/builders/color.js";
7
7
  import { rafThrottle } from "../../Utils/rafThrottle.js";
8
8
  export default function ButtonGroupIcon({ leftIcon, rightIcon, onLeftIconClick, onRightIconClick, buttonText, onButtonClick, onButtongroupClick, size, variant, color, buttonGroupStyle, buttonGroupLeftIconStyle, buttonGroupRightIconStyle, buttonStyle, onBlurLeftIcon, onBlurRightIcon, dropdownOptions, // New prop for dropdown options
@@ -46,9 +46,9 @@ rightIconDropdown, menulistStyle, menuItemStyle, isLoading, divider = true, left
46
46
  // keep the segments transparent (so it doesn't restart per button/icon), with a
47
47
  // translucent-white hover overlay for per-segment feedback.
48
48
  const isGradient = variant === "gradient";
49
- const gradientStops = theme.colors.gradient;
50
- const gradientBg = `linear-gradient(135deg, ${gradientStops.from} 0%, ${gradientStops.to} 100%)`;
51
- const gradientInk = onGradient(gradientStops.from, gradientStops.to, theme.colors.white, theme.colors.black);
49
+ const gradientStops = resolveGradient(theme.colors.gradient, theme.colors.white, theme.colors.black);
50
+ const gradientBg = gradientCss(gradientStops);
51
+ const gradientInk = gradientStops.ink;
52
52
  const whiteRgb = hexToRgb(theme.colors.white);
53
53
  const whiteOverlay = (alpha) => `rgba(${whiteRgb.r}, ${whiteRgb.g}, ${whiteRgb.b}, ${alpha})`;
54
54
  const gradientItemSx = isGradient
@@ -87,7 +87,7 @@ rightIconDropdown, menulistStyle, menuItemStyle, isLoading, divider = true, left
87
87
  mx: 0,
88
88
  borderRadius: "none",
89
89
  borderBottom: "1px solid",
90
- borderColor: theme.colors.boxborder[300],
90
+ borderColor: theme.colors.boxborder[200],
91
91
  }
92
92
  : {}),
93
93
  _hover: { bg: theme.colors.primary[50], color: theme.colors.primary[700] },
@@ -11,7 +11,7 @@ export const FIELD_TRANSITION = "border-color 0.2s, box-shadow 0.2s";
11
11
  export const getFieldStateStyles = (theme, { error = false, focused = false } = {}) => {
12
12
  // [800], not [500]: WCAG 1.4.11 needs >=3.0 for a control boundary against any named surface
13
13
  // up to `muted` (lightest); [500] fails there, [800] clears all with margin.
14
- const idleBorder = theme.colors.boxborder[800];
14
+ const idleBorder = theme.colors.boxborder[500];
15
15
  const primary = theme.colors.primary[500];
16
16
  const errorColor = theme.colors.semanticText.error;
17
17
  const ringPrimary = theme.colors.boxShadow.primary;
@@ -34,7 +34,7 @@ const CopyButton = ({ value, variant = "icon", label = "Copy", copiedLabel = "Co
34
34
  if (variant === "button") {
35
35
  return (_jsxs(Flex, { as: "button", align: "center", gap: "6px", px: "12px", py: "6px", borderRadius: "lg", border: "1px solid",
36
36
  // [800], not [500]: a real control boundary needs >=3:1 on every surface up to `muted`.
37
- borderColor: copied ? success : theme.colors.boxborder[800], bg: "transparent", color: copied ? success : theme.colors.gray[700], fontSize: "14px", fontWeight: 500, transition: "all 0.15s ease", _hover: { borderColor: accent, color: accent }, onClick: handleCopy, children: [copied ? _jsx(Check, { size: iconSize }) : _jsx(Copy, { size: iconSize }), _jsx(Text, { children: copied ? copiedLabel : label })] }));
37
+ borderColor: copied ? success : theme.colors.boxborder[500], bg: "transparent", color: copied ? success : theme.colors.gray[700], fontSize: "14px", fontWeight: 500, transition: "all 0.15s ease", _hover: { borderColor: accent, color: accent }, onClick: handleCopy, children: [copied ? _jsx(Check, { size: iconSize }) : _jsx(Copy, { size: iconSize }), _jsx(Text, { children: copied ? copiedLabel : label })] }));
38
38
  }
39
39
  return (_jsx(ToolTip, { label: copied ? copiedLabel : tooltip, placement: "top", children: _jsx(IconButton, { "aria-label": tooltip, size: size, variant: "ghost", onClick: handleCopy, color: copied ? success : theme.colors.gray[500], _hover: { color: accent, bg: theme.colors.primary[50] }, icon: copied ? _jsx(Check, { size: iconSize }) : _jsx(Copy, { size: iconSize }) }) }));
40
40
  };
@@ -14,6 +14,6 @@ const EditModuleModal = ({ isOpen, onClose, initialName, isLoading, onSubmit, la
14
14
  // [200] is the decorative divider rung (~1.2:1, correct for the ModalHeader border
15
15
  // above) — a real control's resting outline needs 1.4.11's 3:1, which is what every
16
16
  // other input in this library (TextInput, NumberInput, DatePicker) reads from [800].
17
- borderColor: colors.boxborder[800], mb: 5 }), _jsxs(HStack, { justifyContent: "flex-end", spacing: 3, children: [_jsx(Button, { label: labels.cancel, onClick: onClose, variant: "outline", colorScheme: "gray", size: "sm" }), _jsx(Button, { label: labels.update, onClick: () => onSubmit(name.trim()), colorScheme: "primary", size: "sm", isLoading: isLoading, isDisabled: !name.trim() })] })] })] })] }));
17
+ borderColor: colors.boxborder[500], mb: 5 }), _jsxs(HStack, { justifyContent: "flex-end", spacing: 3, children: [_jsx(Button, { label: labels.cancel, onClick: onClose, variant: "outline", colorScheme: "gray", size: "sm" }), _jsx(Button, { label: labels.update, onClick: () => onSubmit(name.trim()), colorScheme: "primary", size: "sm", isLoading: isLoading, isDisabled: !name.trim() })] })] })] })] }));
18
18
  };
19
19
  export default EditModuleModal;
@@ -20,7 +20,7 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
20
20
  const hasRange = !!(rangeStart && rangeEnd && !isSameDay(rangeStart, rangeEnd));
21
21
  const selectStyles = {
22
22
  border: "1px solid",
23
- // boxborder[500] is the control-outline rung the sibling pickers already use; boxborder[300]
23
+ // boxborder[500] is the control-outline rung the sibling pickers already use; boxborder[200]
24
24
  // is decorative and measured 1.85:1 on the dark canvas — the select read as borderless.
25
25
  borderColor: theme.colors.boxborder[500],
26
26
  borderRadius: "md",
@@ -201,6 +201,6 @@ export const RangeDatePicker = (props) => {
201
201
  return;
202
202
  }
203
203
  setTempRangeEnd(setTimeFrom(endTimeBaseDate, t));
204
- }, dateFormat: timePickerFormat, disabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[300], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
204
+ }, dateFormat: timePickerFormat, disabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
205
205
  };
206
206
  export default RangeDatePicker;
@@ -964,7 +964,7 @@ export const SingleDatePicker = (props) => {
964
964
  setTempDate(updatedDate);
965
965
  setInputValue(format(updatedDate, resolvedDateFormat));
966
966
  setIsTyping(false);
967
- }, disabled: disabled })) })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[300], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: () => {
967
+ }, disabled: disabled })) })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: () => {
968
968
  setTempDate(null);
969
969
  requestClose(null);
970
970
  }, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: () => requestClose(), children: "Apply" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
@@ -73,6 +73,6 @@ export const TimeOnlyPicker = (props) => {
73
73
  onOpen();
74
74
  }, error: error, size: sizeKey }) }) }) }), _jsx(PopoverContent, { width: "auto", p: 4, ref: popoverRef, boxShadow: "lg", bg: theme.colors.background[50], children: _jsxs(PopoverBody, { children: [_jsx(TimePicker, { date: resolvedTempDate, dateFormat: dateFormat, onChange: (updatedDate) => {
75
75
  handleTimePickerChange(updatedDate);
76
- } }), _jsxs(Box, { display: "flex", justifyContent: "space-between", mt: 4, pt: 4, borderTop: "1px solid", borderColor: theme.colors.boxborder[300], children: [_jsx(ChakraButton, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }), _jsx(ChakraButton, { size: "sm", colorScheme: "primary", onClick: handleOk, children: "OK" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
76
+ } }), _jsxs(Box, { display: "flex", justifyContent: "space-between", mt: 4, pt: 4, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(ChakraButton, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }), _jsx(ChakraButton, { size: "sm", colorScheme: "primary", onClick: handleOk, children: "OK" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
77
77
  };
78
78
  export default TimeOnlyPicker;
@@ -3,6 +3,7 @@ import { forwardRef, useCallback, useEffect, useId, useRef, useState } from "rea
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
+ import { scrollbarStyles } from "../../Theme/tokens/builders/scrollbar.js";
6
7
  import { ChevronDown } from "lucide-react";
7
8
  import { rafThrottle } from "../../Utils/rafThrottle.js";
8
9
  const MotionBox = motion(forwardRef((props, ref) => (_jsx(Box, { ref: ref, ...props }))));
@@ -211,18 +212,7 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
211
212
  };
212
213
  const DropdownContentRender = () => {
213
214
  var _a;
214
- 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: {
215
- scrollbarWidth: "thin",
216
- scrollbarColor: `${theme.colors.gray[300]} transparent`,
217
- "&::-webkit-scrollbar": { width: "6px" },
218
- "&::-webkit-scrollbar-thumb": {
219
- background: theme.colors.gray[300],
220
- borderRadius: "base",
221
- },
222
- "&::-webkit-scrollbar-thumb:hover": {
223
- background: theme.colors.gray[400],
224
- },
225
- }, style: ListStyle, children: options.map((option, index) => (_jsxs(ListItem, { ref: (node) => {
215
+ 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) => {
226
216
  itemRefs.current[index] = node;
227
217
  }, role: "menuitem", tabIndex: index === activeIndex ? 0 : -1, onClick: () => {
228
218
  handleListItemClick(option.id, option.label);
@@ -234,7 +224,7 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
234
224
  bg: theme.colors.primary.opacity[8],
235
225
  color: theme.colors.accentText,
236
226
  }, borderBottom: divider
237
- ? `0.063rem solid ${theme.colors.boxborder[100]}`
227
+ ? `0.063rem solid ${theme.colors.boxborder[200]}`
238
228
  : undefined, sx: { "&:last-child": { borderBottom: "none" } }, style: ItemStyle, fontWeight: 500, children: [(option === null || option === void 0 ? void 0 : option.image) && (_jsx(Box, { as: option.image, boxSize: s.img, flexShrink: 0, color: theme.colors.textMuted, style: ImageStyle })), _jsx(Box, { as: "span", fontSize: s.fontSize, isTruncated: true,
239
229
  // fontWeight={400}
240
230
  style: LabelStyle, children: option.label })] }, option.id))) }));
@@ -8,7 +8,7 @@ export default function VerifyEmailOtp({ resendMail, onChange, onComplete, place
8
8
  // [800], not [300]: WCAG 1.4.11 needs >=3.0 for a control boundary against any
9
9
  // named surface up to `muted` (lightest); [300] fails there, [800] clears all
10
10
  // with margin.
11
- borderColor: theme.colors.boxborder[800], backgroundColor: theme.colors.background[200], _focus: {
11
+ borderColor: theme.colors.boxborder[500], backgroundColor: theme.colors.background[200], _focus: {
12
12
  borderColor: theme.colors.primary[500],
13
13
  boxShadow: `0 0 0 0.063rem ${theme.colors.primary[500]}`,
14
14
  } }, index))) }) }), _jsx(Flex, { justify: "center", children: _jsxs(Text, { fontSize: "sm", color: theme.colors.gray[600], children: ["Didn\u2019t receive the code?", " ", _jsx(Button, { variant: "link", color: theme.colors.accentText, fontWeight: "semibold", onClick: resendMail, children: "Resend Code" })] }) })] }));
@@ -64,7 +64,7 @@ export const FilePreview = ({ isOpen, onClose, fileUrl, fileName, fileType, hide
64
64
  , {
65
65
  // Chakra's default Modal drives its bg off `--modal-bg`, which flips to
66
66
  // `colors.gray.700` under `_dark` — a light grey in our derived dark palettes.
67
- bg: theme.colors.background[50], borderRadius: "2xl", overflow: "hidden", initial: { opacity: 0, scale: 0.96, y: 8 }, animate: { opacity: 1, scale: 1, y: 0 }, transition: { duration: 0.2, ease: "easeOut" }, children: [_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[100], children: [_jsx(ToolTip, { label: fileName || "File", placement: "bottom", children: _jsx(Text, { fontSize: "sm", fontWeight: 600, maxW: "60%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName || "Preview" }) }), _jsxs(Flex, { align: "center", gap: 1, children: [kind === "image" && (_jsxs(_Fragment, { children: [_jsx(ToolTip, { label: "Zoom out", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Zoom out", size: "sm", variant: "ghost", icon: _jsx(Minus, { size: 16 }), onClick: () => setZoom((z) => Math.max(0.25, z - 0.25)) }) }), _jsx(ToolTip, { label: "Zoom in", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Zoom in", size: "sm", variant: "ghost", icon: _jsx(Plus, { size: 16 }), onClick: () => setZoom((z) => Math.min(4, z + 0.25)) }) }), _jsx(ToolTip, { label: "Rotate", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Rotate", size: "sm", variant: "ghost", icon: _jsx(RotateCw, { size: 16 }), onClick: () => setRotation((r) => (r + 90) % 360) }) })] })), !hideDownload && (_jsx(ToolTip, { label: "Download", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Download", size: "sm", variant: "ghost", color: theme.colors.semanticText.success, icon: _jsx(Download, { size: 18 }), onClick: () => downloadFile(fileUrl, fileName) }) })), _jsx(ModalCloseButton, { position: "static" })] })] }), _jsx(ModalBody, { p: 5, children: renderBody() })] })] }));
67
+ bg: theme.colors.background[50], borderRadius: "2xl", overflow: "hidden", initial: { opacity: 0, scale: 0.96, y: 8 }, animate: { opacity: 1, scale: 1, y: 0 }, transition: { duration: 0.2, ease: "easeOut" }, children: [_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(ToolTip, { label: fileName || "File", placement: "bottom", children: _jsx(Text, { fontSize: "sm", fontWeight: 600, maxW: "60%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName || "Preview" }) }), _jsxs(Flex, { align: "center", gap: 1, children: [kind === "image" && (_jsxs(_Fragment, { children: [_jsx(ToolTip, { label: "Zoom out", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Zoom out", size: "sm", variant: "ghost", icon: _jsx(Minus, { size: 16 }), onClick: () => setZoom((z) => Math.max(0.25, z - 0.25)) }) }), _jsx(ToolTip, { label: "Zoom in", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Zoom in", size: "sm", variant: "ghost", icon: _jsx(Plus, { size: 16 }), onClick: () => setZoom((z) => Math.min(4, z + 0.25)) }) }), _jsx(ToolTip, { label: "Rotate", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Rotate", size: "sm", variant: "ghost", icon: _jsx(RotateCw, { size: 16 }), onClick: () => setRotation((r) => (r + 90) % 360) }) })] })), !hideDownload && (_jsx(ToolTip, { label: "Download", placement: "bottom", children: _jsx(IconButton, { "aria-label": "Download", size: "sm", variant: "ghost", color: theme.colors.semanticText.success, icon: _jsx(Download, { size: 18 }), onClick: () => downloadFile(fileUrl, fileName) }) })), _jsx(ModalCloseButton, { position: "static" })] })] }), _jsx(ModalBody, { p: 5, children: renderBody() })] })] }));
68
68
  };
69
69
  /** Thumbnail with a hover "preview" affordance that opens {@link FilePreview}. */
70
70
  export const FilePreviewTrigger = ({ fileUrl, fileName, fileType, thumbWidth = "100px", thumbHeight = "60px", hideDownload = false, }) => {
@@ -170,10 +170,10 @@ panelPadding = 3, clearAllButton = true, onClearAllHandler,
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
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",
173
- // boxborder[800], not raw gray[200]: WCAG 1.4.11 needs >=3.0 for a control
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.
176
- borderColor: theme.colors.boxborder[800], _focus: { borderColor: theme.colors.red[400], boxShadow: "none" }, value: searchTerms[section.id] || "", onChange: (e) => {
176
+ borderColor: theme.colors.boxborder[500], _focus: { borderColor: theme.colors.red[400], boxShadow: "none" }, value: searchTerms[section.id] || "", onChange: (e) => {
177
177
  const v = e.target.value;
178
178
  setSearchTerms((prev) => ({ ...prev, [section.id]: v }));
179
179
  if (v)
@@ -1,3 +1,5 @@
1
+ import { softenToContrast } from "../../Theme/tokens/builders/outlineRung.js";
2
+ import { PLACEHOLDER_TEXT } from "../../Theme/tokens/builders/surfaceRungs.js";
1
3
  export const Input = {
2
4
  baseStyle: {
3
5
  field: {
@@ -48,8 +50,10 @@ export const Input = {
48
50
  bg: theme.colors.gray[50],
49
51
  border: "0.063rem solid",
50
52
  borderColor,
53
+ // `textMuted` is body copy, so a hint read as a filled value (6.59:1).
54
+ // Settled against the field's own bg to just clear of AA.
51
55
  _placeholder: {
52
- color: theme.colors.textMuted,
56
+ color: softenToContrast(theme.colors.placeholder[500], theme.colors.gray[50], PLACEHOLDER_TEXT),
53
57
  },
54
58
  _hover: {
55
59
  borderColor: primary,
@@ -5,6 +5,7 @@ import { DragDropContext, Droppable, Draggable, } from "@hello-pangea/dnd";
5
5
  import { Plus, Trash2, GripVertical, ChevronLeft, ChevronRight } from "lucide-react";
6
6
  import { VariableSizeList as List, } from "react-window";
7
7
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
8
+ import { scrollbarStyles } from "../../Theme/tokens/builders/scrollbar.js";
8
9
  import { useGetPreferences, useSavePreferences, } from "../../Hooks/usePreferences.js";
9
10
  import AccountCard from "./AccountCard.js";
10
11
  import HeaderActions from "../Header/HeaderActions.js";
@@ -364,37 +365,15 @@ const KanbanBoard = ({ data, customColumns, customizeColumn, onDrag, onDelete, o
364
365
  : colors.boxborder[200]}`, transition: "background 0.15s ease, border-color 0.15s ease, width 0.2s ease", display: "flex", flexDirection: "column", flexShrink: 0, overflow: isColCollapsed ? "visible" : "hidden", height: `${containerHeight - 60}px`, onMouseEnter: () => setHoveredColumn(colId), onMouseLeave: () => setHoveredColumn(null), children: [isColCollapsed ? (_jsxs(Flex, { direction: "column", align: "stretch", flex: "1", width: "100%", minH: 0, overflow: "visible", position: "relative", children: [_jsxs(Flex, { as: "header", direction: "column", align: "center", flexShrink: 0, width: "100%", py: 3, px: 1, gap: 3, borderTop: "0.25rem solid", borderTopColor: (_a = column.color) !== null && _a !== void 0 ? _a : colors.primary[500], bg: colors.background[100], position: "relative", zIndex: 1, children: [enableColumnReorder && columnDragHandleProps ? (_jsx(Flex, { align: "center", justify: "center", flexShrink: 0, cursor: "grab", ...columnDragHandleProps, children: _jsx(Box, { as: GripVertical, size: 14, color: colors.textMuted }) })) : null, enableColumnCollapse && (_jsx(Flex, { flexShrink: 0, w: "100%", justify: "center", bg: colors.background[100], position: "relative", zIndex: 3, children: _jsx(IconButton, { "aria-label": "Expand column", icon: _jsx(ChevronRight, { size: 14 }), variant: "ghost", size: "xs", minW: "1.5rem", h: "1.75rem", onClick: () => toggleColumnCollapsed(colId) }) })), _jsx(Text, { as: "span", fontWeight: "700", fontSize: "0.75rem", color: colors.text[700], sx: {
365
366
  writingMode: "vertical-rl",
366
367
  textOrientation: "mixed",
367
- }, maxH: `${Math.max(120, containerHeight - 200)}px`, overflow: "hidden", lineHeight: "1.2", title: column.title, children: column.title }), _jsx(Badge, { minW: "1.25rem", h: "1.25rem", borderRadius: "full", border: "1px solid", borderColor: colors.boxborder[200], display: "flex", backgroundColor: colors.background[100], alignItems: "center", justifyContent: "center", color: colors.text[900], fontWeight: 600, fontSize: "10px", children: (_b = column === null || column === void 0 ? void 0 : column.items) === null || _b === void 0 ? void 0 : _b.length })] }), column.customNode ? (_jsx(Box, { flexShrink: 0, minH: COLLAPSED_CUSTOM_NODE_TOP_RESERVE, w: "100%", bg: colors.background[100], "aria-hidden": true })) : null, column.customNode ? (_jsx(Box, { as: "section", "aria-label": "Column summary", flex: "1", minH: 0, w: "100%", overflow: "visible", py: 2, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", bg: colors.background[100], position: "relative", zIndex: 2, children: _jsx(Box, { position: "relative", transform: "rotate(90deg)", transformOrigin: "center center", marginTop: '1rem', children: _jsx(VStack, { align: "stretch", spacing: 1, minW: "max-content", fontSize: "xs", color: colors.text[600], children: column.customNode() }) }) })) : (_jsx(Box, { flex: "1", minH: 0 }))] })) : (_jsxs(Flex, { width: "100%", h: !isColCollapsed && !!((_c = column.customNode) === null || _c === void 0 ? void 0 : _c.call(column)) ? "auto" : "2.75rem", align: !isColCollapsed && !!((_d = column.customNode) === null || _d === void 0 ? void 0 : _d.call(column)) ? "flex-start" : "center", px: 3, py: 2, flexShrink: 0, justifyContent: "space-between", position: "relative", gap: 2, borderBottom: `0.063rem solid ${colors.boxborder[100]}`, children: [_jsxs(Flex, { direction: "column", gap: 1, minW: 0, flex: "1", children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(Box, { boxSize: "0.625rem", borderRadius: "full", bg: (_e = column.color) !== null && _e !== void 0 ? _e : colors.primary[500], flexShrink: 0 }), enableColumnReorder && columnDragHandleProps ? (_jsx(Flex, { align: "center", justify: "center", flexShrink: 0, cursor: "grab", ...columnDragHandleProps, children: _jsx(Box, { as: GripVertical, size: 14, color: colors.textMuted }) })) : null, _jsx(Text, { as: "span", fontWeight: "600", fontSize: "0.875rem", color: colors.text[700], noOfLines: 1, minW: 0, children: _jsx(OverflowTooltipText, { placement: "top", children: column.title }) })] }), column.customNode ? (_jsx(Box, { as: "section", "aria-label": "Column summary", width: "100%", flexShrink: 0, fontSize: "xs", color: colors.text[600], children: (_f = column.customNode) === null || _f === void 0 ? void 0 : _f.call(column) })) : null] }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Badge, { minW: "1.5rem", h: "1.5rem", px: 2, borderRadius: "full", backgroundColor: colors.gray[100], display: "flex", alignItems: "center", justifyContent: "center", color: colors.text[700], fontWeight: 600, fontSize: "0.625rem", children: (_g = column === null || column === void 0 ? void 0 : column.items) === null || _g === void 0 ? void 0 : _g.length }), enableColumnCollapse && (_jsx(IconButton, { "aria-label": "Collapse column", icon: _jsx(ChevronLeft, { size: 14 }), variant: "ghost", size: "xs", minW: "1.5rem", h: "1.75rem", flexShrink: 0, onClick: () => toggleColumnCollapsed(colId) })), canDelete &&
368
+ }, maxH: `${Math.max(120, containerHeight - 200)}px`, overflow: "hidden", lineHeight: "1.2", title: column.title, children: column.title }), _jsx(Badge, { minW: "1.25rem", h: "1.25rem", borderRadius: "full", border: "1px solid", borderColor: colors.boxborder[200], display: "flex", backgroundColor: colors.background[100], alignItems: "center", justifyContent: "center", color: colors.text[900], fontWeight: 600, fontSize: "10px", children: (_b = column === null || column === void 0 ? void 0 : column.items) === null || _b === void 0 ? void 0 : _b.length })] }), column.customNode ? (_jsx(Box, { flexShrink: 0, minH: COLLAPSED_CUSTOM_NODE_TOP_RESERVE, w: "100%", bg: colors.background[100], "aria-hidden": true })) : null, column.customNode ? (_jsx(Box, { as: "section", "aria-label": "Column summary", flex: "1", minH: 0, w: "100%", overflow: "visible", py: 2, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", bg: colors.background[100], position: "relative", zIndex: 2, children: _jsx(Box, { position: "relative", transform: "rotate(90deg)", transformOrigin: "center center", marginTop: '1rem', children: _jsx(VStack, { align: "stretch", spacing: 1, minW: "max-content", fontSize: "xs", color: colors.text[600], children: column.customNode() }) }) })) : (_jsx(Box, { flex: "1", minH: 0 }))] })) : (_jsxs(Flex, { width: "100%", h: !isColCollapsed && !!((_c = column.customNode) === null || _c === void 0 ? void 0 : _c.call(column)) ? "auto" : "2.75rem", align: !isColCollapsed && !!((_d = column.customNode) === null || _d === void 0 ? void 0 : _d.call(column)) ? "flex-start" : "center", px: 3, py: 2, flexShrink: 0, justifyContent: "space-between", position: "relative", gap: 2, borderBottom: `0.063rem solid ${colors.boxborder[200]}`, children: [_jsxs(Flex, { direction: "column", gap: 1, minW: 0, flex: "1", children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(Box, { boxSize: "0.625rem", borderRadius: "full", bg: (_e = column.color) !== null && _e !== void 0 ? _e : colors.primary[500], flexShrink: 0 }), enableColumnReorder && columnDragHandleProps ? (_jsx(Flex, { align: "center", justify: "center", flexShrink: 0, cursor: "grab", ...columnDragHandleProps, children: _jsx(Box, { as: GripVertical, size: 14, color: colors.textMuted }) })) : null, _jsx(Text, { as: "span", fontWeight: "600", fontSize: "0.875rem", color: colors.text[700], noOfLines: 1, minW: 0, children: _jsx(OverflowTooltipText, { placement: "top", children: column.title }) })] }), column.customNode ? (_jsx(Box, { as: "section", "aria-label": "Column summary", width: "100%", flexShrink: 0, fontSize: "xs", color: colors.text[600], children: (_f = column.customNode) === null || _f === void 0 ? void 0 : _f.call(column) })) : null] }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Badge, { minW: "1.5rem", h: "1.5rem", px: 2, borderRadius: "full", backgroundColor: colors.gray[100], display: "flex", alignItems: "center", justifyContent: "center", color: colors.text[700], fontWeight: 600, fontSize: "0.625rem", children: (_g = column === null || column === void 0 ? void 0 : column.items) === null || _g === void 0 ? void 0 : _g.length }), enableColumnCollapse && (_jsx(IconButton, { "aria-label": "Collapse column", icon: _jsx(ChevronLeft, { size: 14 }), variant: "ghost", size: "xs", minW: "1.5rem", h: "1.75rem", flexShrink: 0, onClick: () => toggleColumnCollapsed(colId) })), canDelete &&
368
369
  hoveredColumn === colId &&
369
370
  column.items.length > 0 && (_jsx(Box, { as: Trash2, size: 16, cursor: "pointer", color: colors.text[600], _hover: { color: colors.semanticText.error }, onClick: () => handleColumnDelete(colId), transition: "color 0.2s ease", flexShrink: 0 })), !(canDelete &&
370
371
  hoveredColumn === colId &&
371
372
  column.items.length > 0) && _jsx(Box, { width: "16px", height: "16px", flexShrink: 0 })] })] })), !isColCollapsed && (_jsxs(Box, { px: 2, flex: "1", overflowY: "auto", width: "100%", sx: {
373
+ ...scrollbarStyles(colors),
372
374
  overflowY: "auto",
373
375
  overflowX: "hidden",
374
- scrollbarWidth: "thin",
375
- scrollbarColor: `${colors.gray[300]} transparent`,
376
- "&::-webkit-scrollbar": {
377
- width: "6px !important",
378
- height: "6px !important",
379
- },
380
- "&::-webkit-scrollbar-track": {
381
- background: colors.gray[100],
382
- borderRadius: "base",
383
- marginTop: "4px",
384
- marginBottom: "4px",
385
- },
386
- "&::-webkit-scrollbar-thumb": {
387
- background: colors.gray[300],
388
- borderRadius: "base",
389
- border: "1px solid",
390
- borderColor: colors.gray[100],
391
- },
392
- "&::-webkit-scrollbar-thumb:hover": {
393
- background: colors.gray[400],
394
- },
395
- "&": {
396
- scrollbarGutter: "stable both-edges",
397
- },
376
+ "&": { scrollbarGutter: "stable both-edges" },
398
377
  cursor: canDrag ? "grab" : "not-allowed",
399
378
  }, children: [(noItems === null || noItems === void 0 ? void 0 : noItems.isVisible) && column.items.length === 0 && (_jsx(NoItemsTemplate, { column: column, noItems: noItems, colors: colors })), virtualization ? (_jsx(List, { ref: (el) => {
400
379
  if (el)
@@ -409,26 +388,7 @@ const KanbanBoard = ({ data, customColumns, customizeColumn, onDrag, onDelete, o
409
388
  return null;
410
389
  const showAddColumn = Boolean(customizeColumn === null || customizeColumn === void 0 ? void 0 : customizeColumn.isVisible);
411
390
  const hasAnyColumns = Object.keys(columns).length > 0;
412
- const flexScrollSx = {
413
- "&::-webkit-scrollbar": {
414
- height: "6px",
415
- },
416
- "&::-webkit-scrollbar-track": {
417
- background: colors.gray[100],
418
- borderRadius: "base",
419
- margin: "0 4px",
420
- },
421
- "&::-webkit-scrollbar-thumb": {
422
- background: colors.gray[400],
423
- borderRadius: "base",
424
- border: `1px solid ${colors.gray[100]}`,
425
- },
426
- "&::-webkit-scrollbar-thumb:hover": {
427
- background: colors.gray[500],
428
- },
429
- scrollbarWidth: "thin",
430
- scrollbarColor: `${colors.gray[400]} ${colors.gray[100]}`,
431
- };
391
+ const flexScrollSx = scrollbarStyles(colors);
432
392
  const addColumnBox = !isBoardLoading && showAddColumn && hasAnyColumns && (_jsx(Box, { width: columnWidth, borderRadius: "lg", border: `0.125rem dashed ${colors.boxborder[500]}`, bg: colors.background[100], flexShrink: 0, height: `${containerHeight - 60}px`, display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer", _hover: { borderColor: colors.primary[500] }, onClick: () => { var _a; return (_a = customizeColumn === null || customizeColumn === void 0 ? void 0 : customizeColumn.onAddColumn) === null || _a === void 0 ? void 0 : _a.call(customizeColumn); }, children: _jsxs(Flex, { direction: "column", align: "center", gap: 2, children: [_jsx(Box, { as: Plus, size: 20, color: colors.text[700] }), _jsx(Text, { fontSize: "sm", color: colors.text[600], children: (customizeColumn === null || customizeColumn === void 0 ? void 0 : customizeColumn.buttonText) || "Add column" })] }) }));
433
393
  const columnsList = Object.entries(columns).map(([colId, column], colIndex) => {
434
394
  const isColCollapsed = enableColumnCollapse && Boolean(collapsedColumns[colId]);
@@ -4,7 +4,7 @@ import { CheckCircle, Crown, Users } from "lucide-react";
4
4
  import Button from "../Button/Button.js";
5
5
  import UpgradeButton from "../UpgradeButton/UpgradeButton.js";
6
6
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
7
- import { onGradient } from "../../Theme/tokens/builders/accentText.js";
7
+ import { resolveGradient } from "../../Theme/tokens/builders/gradientInk.js";
8
8
  import { formatLimitUsage, resolveLimitCopy } from "./limitReachedCopy.js";
9
9
  const KIND_ICON = {
10
10
  record: Crown,
@@ -19,10 +19,9 @@ const LimitReachedModal = ({ isOpen, onClose, kind, limit = null, used = null, c
19
19
  const copy = resolveLimitCopy(kind, canManageBilling);
20
20
  const usage = formatLimitUsage(kind, used, limit);
21
21
  const KindIcon = KIND_ICON[kind];
22
- const gradient = colors.gradient;
23
- // Header banner uses the brand gradient (not a fixed blue/purple) so it reads correctly
24
- // across all 9 brand themes, with ink picked for AA against whichever stop is lighter.
25
- const ink = onGradient(gradient.from, gradient.to, colors.white, colors.black);
22
+ // Header banner uses the brand gradient so it reads correctly across all 9 brands.
23
+ const gradient = resolveGradient(colors.gradient, colors.white, colors.black);
24
+ const ink = gradient.ink;
26
25
  return (_jsxs(Modal, { isOpen: isOpen, onClose: onClose, isCentered: true, size: "lg", motionPreset: "slideInBottom", children: [_jsx(ModalOverlay, { backdropFilter: "blur(5px)" }), _jsxs(ModalContent, { borderRadius: "xl", overflow: "hidden", boxShadow: "2xl", mx: 4, children: [_jsxs(Box, { bgGradient: `linear(to-r, ${gradient.from}, ${gradient.to})`, color: ink, children: [_jsx(ModalHeader, { pb: 4, children: _jsxs(Flex, { align: "center", children: [_jsx(Icon, { as: KindIcon, boxSize: "24px", mr: "12px" }), _jsx(Text, { fontSize: "xl", fontWeight: "bold", children: title !== null && title !== void 0 ? title : copy.title })] }) }), _jsx(ModalCloseButton, { "aria-label": "Dismiss", color: ink, _hover: { opacity: 0.7 } })] }), _jsxs(ModalBody, { py: 6, children: [_jsx(Text, { textAlign: "center", fontSize: "md", fontWeight: 600, color: colors.text[700], children: message !== null && message !== void 0 ? message : copy.message }), usage && (_jsx(Text, { textAlign: "center", fontSize: "sm", color: colors.textMuted, mt: 2, children: usage })), features && features.length > 0 && (_jsx(List, { spacing: 2, mt: 5, children: features.map((feature) => (_jsxs(ListItem, { display: "flex", alignItems: "center", fontSize: "sm", color: colors.text[600], children: [_jsx(ListIcon, { as: CheckCircle, color: colors.semanticText.success }), feature] }, feature))) }))] }), _jsx(Divider, {}), _jsx(ModalFooter, { children: _jsxs(HStack, { spacing: 3, children: [_jsx(Button, { label: canManageBilling ? "Maybe later" : "Close", variant: "outline", colorScheme: "gray", size: "md", onClick: onClose }), canManageBilling && (_jsx(UpgradeButton, { label: "Upgrade plan", size: "md", onClick: () => onUpgrade === null || onUpgrade === void 0 ? void 0 : onUpgrade() }))] }) })] })] }));
27
26
  };
28
27
  export default LimitReachedModal;
@@ -55,7 +55,7 @@ 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[800], 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.gray[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],
@@ -63,11 +63,11 @@ const OrgSwitcher = ({ organizations, value, onChange, isLoading = false, isSear
63
63
  focusOption(filtered.length - 1);
64
64
  }
65
65
  }, [activeIndex, filtered.length, focusOption]);
66
- // boxborder[800], not raw gray[200]: this styles a real `<button>` (Flex as="button" below),
66
+ // boxborder[500], not raw gray[200]: this styles a real `<button>` (Flex as="button" below),
67
67
  // so its border is a control boundary — WCAG 1.4.11 needs >=3.0 against any named surface up
68
68
  // to `muted` (lightest); gray[200] fails there in dark mode.
69
69
  const triggerStyles = triggerVariant === "outline"
70
- ? { border: "1px solid", borderColor: theme.colors.boxborder[800], bg: theme.colors.background[50] }
70
+ ? { border: "1px solid", borderColor: theme.colors.boxborder[500], bg: theme.colors.background[50] }
71
71
  : triggerVariant === "subtle"
72
72
  ? { bg: theme.colors.gray[50] }
73
73
  : { bg: "transparent" };
@@ -8,7 +8,7 @@ export default function PinInputs({ otp, mask, defaultValue, placeholder, manage
8
8
  // [800], not [300]/[700]: WCAG 1.4.11 needs >=3.0 for a control boundary, measured
9
9
  // against the parent surface — up to `muted` (lightest). [700] fails there (2.41-2.72);
10
10
  // [800] clears all named surfaces with margin (3.44-3.90).
11
- borderColor: theme.colors.boxborder[800], _focus: {
11
+ borderColor: theme.colors.boxborder[500], _focus: {
12
12
  borderColor: theme.colors.primary[500],
13
13
  boxShadow: `0 0 0 0.063rem ${theme.colors.primary[500]}`,
14
14
  } }, index))) }) })] }));