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

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 (47) hide show
  1. package/README.md +21 -0
  2. package/dist/Components/Button/Button.styles.js +7 -6
  3. package/dist/Components/Card/PaymentCard/PaymentCard.js +14 -5
  4. package/dist/Components/Common/ErrorComponent.js +6 -5
  5. package/dist/Components/DatePicker/CalendarPanel.js +6 -7
  6. package/dist/Components/FilePreview/FilePreview.js +2 -1
  7. package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -2
  8. package/dist/Components/OrganizationDetails/OrganizationDetails.js +3 -2
  9. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +4 -3
  10. package/dist/Components/ScrollToTop/ScrollToTop.js +3 -3
  11. package/dist/Components/SelectSearch/SelectSearch.js +1 -1
  12. package/dist/Components/SideBar/SideBar.js +4 -2
  13. package/dist/Components/StageProgress/StageProgressProps.js +6 -4
  14. package/dist/Components/Table/Table.js +2 -1
  15. package/dist/Components/Table/filters/LeftFilterPane.js +1 -1
  16. package/dist/Components/Tag/Tag.styles.js +13 -9
  17. package/dist/Theme/chakra/componentStyles.js +16 -9
  18. package/dist/Theme/chakra/createBrandTheme.js +15 -9
  19. package/dist/Theme/tokens/builders/filledSurface.d.ts +29 -0
  20. package/dist/Theme/tokens/builders/filledSurface.js +74 -0
  21. package/dist/Utils/table.js +5 -2
  22. package/dist/esm/Components/Button/Button.styles.js +8 -7
  23. package/dist/esm/Components/Card/PaymentCard/PaymentCard.js +14 -5
  24. package/dist/esm/Components/Common/ErrorComponent.js +6 -5
  25. package/dist/esm/Components/DatePicker/CalendarPanel.js +6 -7
  26. package/dist/esm/Components/FilePreview/FilePreview.js +2 -1
  27. package/dist/esm/Components/KanbanBoard/KanbanActions/KanbanActions.js +1 -2
  28. package/dist/esm/Components/OrganizationDetails/OrganizationDetails.js +4 -3
  29. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -4
  30. package/dist/esm/Components/ScrollToTop/ScrollToTop.js +3 -3
  31. package/dist/esm/Components/SelectSearch/SelectSearch.js +1 -1
  32. package/dist/esm/Components/SideBar/SideBar.js +4 -2
  33. package/dist/esm/Components/StageProgress/StageProgressProps.js +7 -5
  34. package/dist/esm/Components/Table/Table.js +2 -1
  35. package/dist/esm/Components/Table/filters/LeftFilterPane.js +1 -1
  36. package/dist/esm/Components/Tag/Tag.styles.js +14 -10
  37. package/dist/esm/Theme/chakra/componentStyles.js +16 -9
  38. package/dist/esm/Theme/chakra/createBrandTheme.js +15 -9
  39. package/dist/esm/Theme/tokens/builders/filledSurface.js +67 -0
  40. package/dist/esm/Utils/table.js +5 -2
  41. package/dist/esm/index.js +3 -0
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +8 -1
  44. package/package.json +1 -1
  45. package/dist/Theme/tokens/builders/solidFillRung.d.ts +0 -4
  46. package/dist/Theme/tokens/builders/solidFillRung.js +0 -33
  47. package/dist/esm/Theme/tokens/builders/solidFillRung.js +0 -28
@@ -0,0 +1,29 @@
1
+ import type { ColorScale, PaletteProps } from "../types";
2
+ /** Resolved fill + ink for a solid surface, including hover/active steps. */
3
+ export type FilledSurface = {
4
+ rung: keyof ColorScale;
5
+ fill: string;
6
+ color: string;
7
+ hoverRung: keyof ColorScale;
8
+ hoverFill: string;
9
+ hoverColor: string;
10
+ activeRung: keyof ColorScale;
11
+ activeFill: string;
12
+ activeColor: string;
13
+ };
14
+ /**
15
+ * Lightest rung on `scale` that still carries `white` at WCAG AA. Prefers [500] when it already
16
+ * passes; otherwise walks toward darker rungs. Used for solid fills on buttons, tags, badges and
17
+ * table status pills so consumers never get black ink on a saturated fill when white is achievable.
18
+ */
19
+ export declare const solidFillRung: (scale: ColorScale, white: string) => keyof ColorScale;
20
+ /** Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. */
21
+ export declare const darkerFillRung: (scale: ColorScale, canvas: string, white: string, step: 0 | 1) => keyof ColorScale;
22
+ /** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
23
+ export declare const labelOnFill: (fill: string, white: string, black: string) => string;
24
+ /**
25
+ * Consumer-facing helper: given any `ColorScale` (primary, red, semantic.error, …), return the
26
+ * fill rung and matching ink for solid / hover / active states. Use this whenever you paint a
27
+ * `bg` from a scale — never pair `scale[500]` with `onFilled` or `colors.white` by hand.
28
+ */
29
+ export declare const resolveFilledSurface: (scale: ColorScale, colors: Pick<PaletteProps, "white" | "black" | "backgroundColor">) => FilledSurface;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveFilledSurface = exports.labelOnFill = exports.darkerFillRung = exports.solidFillRung = void 0;
4
+ const color_1 = require("./color");
5
+ const accentText_1 = require("./accentText");
6
+ const RUNGS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
7
+ /**
8
+ * The rung one/two steps DARKER than the accent — what a filled button's hover/active needs so its
9
+ * white label stays legible.
10
+ *
11
+ * Every dark scale runs dark -> light across 50 -> 900 (brand scales are rebuilt that way, utility
12
+ * hues are reversed), the mirror of light mode. So "darker than [500]" is [600]/[700] in light but
13
+ * [400]/[300] in dark.
14
+ */
15
+ const FILL_STEP_RUNGS = { light: [600, 700], dark: [400, 300] };
16
+ /**
17
+ * Lightest rung on `scale` that still carries `white` at WCAG AA. Prefers [500] when it already
18
+ * passes; otherwise walks toward darker rungs. Used for solid fills on buttons, tags, badges and
19
+ * table status pills so consumers never get black ink on a saturated fill when white is achievable.
20
+ */
21
+ const solidFillRung = (scale, white) => {
22
+ if ((0, color_1.contrastRatio)(scale[500], white) >= accentText_1.AA_NORMAL_TEXT)
23
+ return 500;
24
+ const passing = RUNGS.filter((r) => scale[r] && (0, color_1.contrastRatio)(scale[r], white) >= accentText_1.AA_NORMAL_TEXT);
25
+ if (!passing.length)
26
+ return 500;
27
+ return passing.reduce((a, b) => (0, color_1.contrastRatio)(scale[a], white) <= (0, color_1.contrastRatio)(scale[b], white) ? a : b);
28
+ };
29
+ exports.solidFillRung = solidFillRung;
30
+ const steppedRung = (base, canvas, step) => {
31
+ const dir = (0, accentText_1.isDarkCanvas)(canvas) ? -100 : 100;
32
+ return Math.min(900, Math.max(50, base + dir * step));
33
+ };
34
+ /** Hover (step 0) or active (step 1) fill rung, one step darker than `solidFillRung`. */
35
+ const darkerFillRung = (scale, canvas, white, step) => {
36
+ const base = (0, exports.solidFillRung)(scale, white);
37
+ if (base === 500) {
38
+ const mode = (0, accentText_1.isDarkCanvas)(canvas) ? "dark" : "light";
39
+ return FILL_STEP_RUNGS[mode][step];
40
+ }
41
+ const stepped = steppedRung(base, canvas, step === 0 ? 1 : 2);
42
+ return stepped;
43
+ };
44
+ exports.darkerFillRung = darkerFillRung;
45
+ /** Label ink for a specific fill swatch — always `onFilled`, exported for style configs. */
46
+ const labelOnFill = (fill, white, black) => (0, accentText_1.onFilled)(fill, white, black);
47
+ exports.labelOnFill = labelOnFill;
48
+ /**
49
+ * Consumer-facing helper: given any `ColorScale` (primary, red, semantic.error, …), return the
50
+ * fill rung and matching ink for solid / hover / active states. Use this whenever you paint a
51
+ * `bg` from a scale — never pair `scale[500]` with `onFilled` or `colors.white` by hand.
52
+ */
53
+ const resolveFilledSurface = (scale, colors) => {
54
+ const { white, black, backgroundColor } = colors;
55
+ const canvas = backgroundColor.main;
56
+ const rung = (0, exports.solidFillRung)(scale, white);
57
+ const fill = scale[rung];
58
+ const hoverRung = (0, exports.darkerFillRung)(scale, canvas, white, 0);
59
+ const hoverFill = scale[hoverRung];
60
+ const activeRung = (0, exports.darkerFillRung)(scale, canvas, white, 1);
61
+ const activeFill = scale[activeRung];
62
+ return {
63
+ rung,
64
+ fill,
65
+ color: (0, exports.labelOnFill)(fill, white, black),
66
+ hoverRung,
67
+ hoverFill,
68
+ hoverColor: (0, exports.labelOnFill)(hoverFill, white, black),
69
+ activeRung,
70
+ activeFill,
71
+ activeColor: (0, exports.labelOnFill)(activeFill, white, black),
72
+ };
73
+ };
74
+ exports.resolveFilledSurface = resolveFilledSurface;
@@ -45,6 +45,7 @@ exports.useDebounce = useDebounce;
45
45
  exports.globalSearchFilter = globalSearchFilter;
46
46
  const react_1 = __importStar(require("react"));
47
47
  const accentText_1 = require("../Theme/tokens/builders/accentText");
48
+ const filledSurface_1 = require("../Theme/tokens/builders/filledSurface");
48
49
  const statusTone_1 = require("../Theme/tokens/builders/statusTone");
49
50
  // Built once, not per comparison: sorting 10k rows runs this ~130k times, and constructing a
50
51
  // collator is orders of magnitude dearer than using one.
@@ -117,11 +118,13 @@ function buildTablePalette(theme) {
117
118
  ];
118
119
  return scales.map((scale) => {
119
120
  const tone = (0, statusTone_1.resolveStatusTone)(scale, mode);
121
+ const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white);
122
+ const solid = scale[solidRung];
120
123
  return {
121
- solid: scale[500],
124
+ solid,
122
125
  soft: tone.bg,
123
126
  text: tone.fg,
124
- onSolid: (0, accentText_1.onFilled)(scale[500], c.white, c.black),
127
+ onSolid: (0, filledSurface_1.labelOnFill)(solid, c.white, c.black),
125
128
  };
126
129
  });
127
130
  }
@@ -1,5 +1,5 @@
1
- import { accentTextOnCanvas, isDarkCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
2
- import { solidRung, darkerFillRung } from "../../Theme/tokens/builders/solidFillRung.js";
1
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
2
+ import { darkerFillRung, labelOnFill, solidFillRung, } from "../../Theme/tokens/builders/filledSurface.js";
3
3
  import { resolveGradient, gradientCss } from "../../Theme/tokens/builders/gradientInk.js";
4
4
  import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
5
5
  /**
@@ -19,14 +19,15 @@ const onCanvasHoverBg = (theme, colorScheme, step) => {
19
19
  const scale = theme.colors[colorScheme];
20
20
  return "opacity" in scale ? scale.opacity[step] : scale[50];
21
21
  };
22
- const buttonSolidRung = (theme, colorScheme) => solidRung(theme.colors[colorScheme], theme.colors.white);
22
+ const swatch = (theme, colorScheme) => theme.colors[colorScheme];
23
+ const buttonSolidRung = (theme, colorScheme) => solidFillRung(swatch(theme, colorScheme), theme.colors.white);
23
24
  const darkerFill = (theme, colorScheme, step) => {
24
- const scale = theme.colors[colorScheme];
25
- const isDark = isDarkCanvas(theme.colors.backgroundColor.main);
26
- return scale[darkerFillRung(scale, theme.colors.white, isDark, step)];
25
+ const scale = swatch(theme, colorScheme);
26
+ const rung = darkerFillRung(scale, theme.colors.backgroundColor.main, theme.colors.white, step);
27
+ return scale[rung];
27
28
  };
28
29
  /** Label for the solid variant's filled bg — derived from THAT fill, since hover/active swap it. */
29
- const labelFor = (theme, fill) => onFilled(fill, theme.colors.white, theme.colors.black);
30
+ const labelFor = (theme, fill) => labelOnFill(fill, theme.colors.white, theme.colors.black);
30
31
  /**
31
32
  * The two-tone `:focus-visible` ring, from the palette's derived `focusRing` pair.
32
33
  *
@@ -2,18 +2,24 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { Box, Badge, Flex, GridItem, Heading, Icon, Text, VStack, Skeleton, SkeletonText, } from "@chakra-ui/react";
3
3
  import { Check } from "lucide-react";
4
4
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
5
- import { onFilled } from "../../../Theme/tokens/builders/accentText.js";
5
+ import { resolveFilledSurface } from "../../../Theme/tokens/builders/filledSurface.js";
6
6
  import Button from "../../Button/Button.js";
7
7
  const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
8
- const withOnButtonColor = (styles) => ({
9
- ...styles,
10
- onButtonColor: onFilled(styles.buttonColor, theme.colors.white, theme.colors.black),
11
- });
8
+ const withOnButtonColor = (styles) => {
9
+ const scale = theme.colors[styles.buttonScale];
10
+ const solid = resolveFilledSurface(scale, theme.colors);
11
+ return {
12
+ ...styles,
13
+ buttonColor: solid.fill,
14
+ onButtonColor: solid.color,
15
+ };
16
+ };
12
17
  if (isActive) {
13
18
  return withOnButtonColor({
14
19
  badgeText: "Active Plan",
15
20
  badgeColor: `0.125rem solid ${theme.colors.green[500]}`,
16
21
  buttonColor: theme.colors.green[500],
22
+ buttonScale: "green",
17
23
  buttonColor50: theme.colors.green[50],
18
24
  colorScheme: "green",
19
25
  });
@@ -23,6 +29,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
23
29
  badgeText: "Upgrade Your Plan",
24
30
  badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
25
31
  buttonColor: theme.colors.primary[500],
32
+ buttonScale: "primary",
26
33
  buttonColor50: theme.colors.primary[50],
27
34
  colorScheme: "primary",
28
35
  });
@@ -32,6 +39,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
32
39
  badgeText: "Most Popular",
33
40
  badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
34
41
  buttonColor: theme.colors.primary[500],
42
+ buttonScale: "primary",
35
43
  buttonColor50: theme.colors.primary[50],
36
44
  colorScheme: "primary",
37
45
  });
@@ -40,6 +48,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
40
48
  badgeText: "",
41
49
  badgeColor: "",
42
50
  buttonColor: theme.colors.primary[500],
51
+ buttonScale: "primary",
43
52
  buttonColor50: theme.colors.primary[50],
44
53
  colorScheme: "primary",
45
54
  });
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { HStack, Text } from "@chakra-ui/react";
3
3
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
4
- import { onFilled } from "../../Theme/tokens/builders/accentText.js";
4
+ import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
5
5
  const ErrorComponent = ({ error, errorClassName, }) => {
6
6
  const { colors } = useCustomTheme();
7
- const errorFill = colors.semanticText.error;
8
- // errorFill is ink, not a fill tuned to carry a mark — pick the mark's ink structurally.
9
- const markInk = onFilled(errorFill, colors.white, colors.black);
10
- return (_jsxs(HStack, { as: "p", align: "flex-start", spacing: 1, mt: 1, fontSize: "sm", color: errorFill, className: errorClassName, children: [_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [_jsx("circle", { cx: "50", cy: "50", r: "50", fill: errorFill }), _jsx("rect", { x: "46", y: "40", width: "8", height: "30", rx: "2", fill: markInk }), _jsx("circle", { cx: "50", cy: "28", r: "4", fill: markInk })] }), _jsx(Text, { as: "span", children: error })] }));
7
+ const errorText = colors.semanticText.error;
8
+ const errorSolid = resolveFilledSurface(colors.semantic.error, colors);
9
+ const errorFill = errorSolid.fill;
10
+ const markInk = errorSolid.color;
11
+ return (_jsxs(HStack, { as: "p", align: "flex-start", spacing: 1, mt: 1, fontSize: "sm", color: errorText, className: errorClassName, children: [_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [_jsx("circle", { cx: "50", cy: "50", r: "50", fill: errorFill }), _jsx("rect", { x: "46", y: "40", width: "8", height: "30", rx: "2", fill: markInk }), _jsx("circle", { cx: "50", cy: "28", r: "4", fill: markInk })] }), _jsx(Text, { as: "span", children: error })] }));
11
12
  };
12
13
  export default ErrorComponent;
@@ -4,7 +4,7 @@ import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays } fro
4
4
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
5
5
  import Button from "../Button/Button.js";
6
6
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
7
- import { onFilled } from "../../Theme/tokens/builders/accentText.js";
7
+ import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
8
8
  import { DAY_CLASS, dayAccessibleName, dayStateClassName, resolveDayStateVisual, } from "./dayStates.js";
9
9
  export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, tempDate, tempRangeStart, tempRangeEnd, isSameDay, isBefore, isAfter, minDate, maxDate, disablePastDates, disableFutureDates, disableToday, onDaySelect, hoveredDate, onDayHover, renderWeekdays, dayStates, renderDayContent, }) => {
10
10
  const theme = useCustomTheme();
@@ -95,16 +95,15 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
95
95
  // Solid fill (selected/range-endpoint) needs the ink checked against that
96
96
  // specific fill — `primary[500]` doesn't reliably clear AA for white text on
97
97
  // every brand/mode (same gap the solid Button variant already accounts for).
98
- const solidFill = theme.colors.primary[500];
99
- const solidHoverFill = theme.colors.primary[600];
98
+ const primarySolid = resolveFilledSurface(theme.colors.primary, theme.colors);
99
+ const solidFill = primarySolid.fill;
100
+ const solidHoverFill = primarySolid.hoverFill;
100
101
  const circleColor = circleSolid
101
- ? onFilled(solidFill, theme.colors.white, theme.colors.black)
102
+ ? primarySolid.color
102
103
  : isInCurrentMonth
103
104
  ? theme.colors.text[700]
104
105
  : theme.colors.gray[400];
105
- const circleHoverColor = circleSolid
106
- ? onFilled(solidHoverFill, theme.colors.white, theme.colors.black)
107
- : circleColor;
106
+ const circleHoverColor = circleSolid ? primarySolid.hoverColor : circleColor;
108
107
  const circleBorder = circleSolid
109
108
  ? "1px solid transparent"
110
109
  : isTentativeEnd
@@ -4,6 +4,7 @@ import { Box, Flex, IconButton, Image, Modal, ModalBody, ModalCloseButton, Modal
4
4
  import { motion } from "framer-motion";
5
5
  import { Download, Eye, FileQuestion, Minus, Plus, RotateCw, } from "lucide-react";
6
6
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
7
+ import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
7
8
  import ToolTip from "../ToolTip/ToolTip.js";
8
9
  const MotionContent = motion(ModalContent);
9
10
  const inferKind = (url, fileName) => {
@@ -56,7 +57,7 @@ export const FilePreview = ({ isOpen, onClose, fileUrl, fileName, fileType, hide
56
57
  if (kind === "video") {
57
58
  return (_jsx(Box, { as: "video", src: fileUrl, controls: true, width: "100%", borderRadius: "lg" }));
58
59
  }
59
- return (_jsxs(Flex, { direction: "column", align: "center", justify: "center", py: 12, gap: 3, children: [_jsx(FileQuestion, { size: 48, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: "Preview isn't available for this file type." }), !hideDownload && (_jsxs(Flex, { as: "button", align: "center", gap: 2, px: 4, py: 2, borderRadius: "lg", bg: theme.colors.primary[500], color: theme.colors.onPrimary, fontSize: "sm", fontWeight: 500, onClick: () => downloadFile(fileUrl, fileName), children: [_jsx(Download, { size: 16 }), " Download file"] }))] }));
60
+ return (_jsxs(Flex, { direction: "column", align: "center", justify: "center", py: 12, gap: 3, children: [_jsx(FileQuestion, { size: 48, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: "Preview isn't available for this file type." }), !hideDownload && (_jsxs(Flex, { as: "button", align: "center", gap: 2, px: 4, py: 2, borderRadius: "lg", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), fontSize: "sm", fontWeight: 500, onClick: () => downloadFile(fileUrl, fileName), children: [_jsx(Download, { size: 16 }), " Download file"] }))] }));
60
61
  };
61
62
  return (_jsxs(Modal, { isOpen: isOpen, onClose: handleClose, size: size, isCentered: true, children: [_jsx(ModalOverlay, { bg: "blackAlpha.600", backdropFilter: "blur(4px)" }), _jsxs(MotionContent
62
63
  // Chakra's default Modal drives its bg off `--modal-bg`, which flips to
@@ -4,10 +4,9 @@ import Select from "../../Select/Select.js";
4
4
  import { CirclePlus, SquarePen } from "lucide-react";
5
5
  import VeritcalDivider from "../../Divider/Divider.js";
6
6
  import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
7
- import { onFilled } from "../../../Theme/tokens/builders/accentText.js";
8
7
  import Button from "../../Button/Button.js";
9
8
  const KanbanActions = ({ options, onSelectChange, onEdit, onCreate, }) => {
10
9
  const { colors } = useCustomTheme();
11
- return (_jsxs(Box, { display: "flex", alignItems: "center", gap: "0.625rem", children: [_jsx(Select, { options: options, placeholder: "Filter by Status", width: "12.5rem", onChange: (option) => onSelectChange && onSelectChange(option) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: "0.5rem", children: [_jsx(Button, { size: "sm", variant: "ghost", leftIcon: _jsx(SquarePen, { size: 20, color: colors.text[500] }), onClick: () => onEdit === null || onEdit === void 0 ? void 0 : onEdit(), children: "Edit Layout" }), _jsx(VeritcalDivider, {}), _jsx(Button, { size: "sm", variant: "solid", leftIcon: _jsx(CirclePlus, { size: 20, color: onFilled(colors.primary[500], colors.white, colors.black) }), onClick: () => onCreate === null || onCreate === void 0 ? void 0 : onCreate(), children: "Create New" })] })] }));
10
+ return (_jsxs(Box, { display: "flex", alignItems: "center", gap: "0.625rem", children: [_jsx(Select, { options: options, placeholder: "Filter by Status", width: "12.5rem", onChange: (option) => onSelectChange && onSelectChange(option) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: "0.5rem", children: [_jsx(Button, { size: "sm", variant: "ghost", leftIcon: _jsx(SquarePen, { size: 20, color: colors.text[500] }), onClick: () => onEdit === null || onEdit === void 0 ? void 0 : onEdit(), children: "Edit Layout" }), _jsx(VeritcalDivider, {}), _jsx(Button, { size: "sm", variant: "solid", leftIcon: _jsx(CirclePlus, { size: 20 }), onClick: () => onCreate === null || onCreate === void 0 ? void 0 : onCreate(), children: "Create New" })] })] }));
12
11
  };
13
12
  export default KanbanActions;
@@ -3,7 +3,8 @@ import { useMemo, useState } from "react";
3
3
  import { Avatar, Badge, Box, Flex, Heading, HStack, IconButton, Input, Skeleton, SkeletonText, Spinner, Text, Tooltip, VStack, } from "@chakra-ui/react";
4
4
  import { ArrowLeft, Building2, Check, CheckCircle2, Crown, Globe, Mail, Pencil, Plus, Trash2, Users, X, } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
- import { accentTextOnCanvas, isDarkCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
6
+ import { accentTextOnCanvas, isDarkCanvas } from "../../Theme/tokens/builders/accentText.js";
7
+ import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
7
8
  import { resolveStatusTone } from "../../Theme/tokens/builders/statusTone.js";
8
9
  import Button from "../Button/Button.js";
9
10
  import EmptyState from "../EmptyState/EmptyState.js";
@@ -67,7 +68,7 @@ const OrganizationDetails = ({ activeOrganizations, invitedOrganizations, isLoad
67
68
  const pageBg = colors.backgroundColor.main;
68
69
  const primary50 = colors.primary[50];
69
70
  const primary100 = colors.primary[100];
70
- const primary500 = colors.primary[500];
71
+ const primarySolid = resolveFilledSurface(colors.primary, colors);
71
72
  const onPrimary50 = accentTextOnCanvas(colors.primary, colors.primary[50]);
72
73
  const cardSx = {
73
74
  backgroundColor: surface,
@@ -153,7 +154,7 @@ const OrganizationDetails = ({ activeOrganizations, invitedOrganizations, isLoad
153
154
  width: "100%",
154
155
  };
155
156
  const hasOrganizations = activeOrganizations.length > 0 || invitedOrganizations.length > 0;
156
- return (_jsxs(Box, { backgroundColor: pageBg, minHeight: "100%", p: { base: 2, md: 3 }, children: [_jsxs(Flex, { ...cardSx, px: 3, py: 2.5, mb: 3, alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 3, bgGradient: `linear(135deg, ${primary50} 0%, ${primary100} 100%)`, children: [_jsxs(Flex, { alignItems: "center", gap: 3, children: [onBack && (_jsx(IconButton, { "aria-label": "Go back", icon: _jsx(ArrowLeft, { size: 18 }), variant: "ghost", size: "sm", color: subtle, onClick: onBack })), _jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: primary500, color: onFilled(primary500, colors.white, colors.black), children: _jsx(Building2, { size: 18 }) }), _jsxs(Box, { children: [_jsxs(HStack, { spacing: 2, children: [_jsx(Heading, { size: "sm", color: heading, fontWeight: 700, children: userName
157
+ return (_jsxs(Box, { backgroundColor: pageBg, minHeight: "100%", p: { base: 2, md: 3 }, children: [_jsxs(Flex, { ...cardSx, px: 3, py: 2.5, mb: 3, alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 3, bgGradient: `linear(135deg, ${primary50} 0%, ${primary100} 100%)`, children: [_jsxs(Flex, { alignItems: "center", gap: 3, children: [onBack && (_jsx(IconButton, { "aria-label": "Go back", icon: _jsx(ArrowLeft, { size: 18 }), variant: "ghost", size: "sm", color: subtle, onClick: onBack })), _jsx(Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: primarySolid.fill, color: primarySolid.color, children: _jsx(Building2, { size: 18 }) }), _jsxs(Box, { children: [_jsxs(HStack, { spacing: 2, children: [_jsx(Heading, { size: "sm", color: heading, fontWeight: 700, children: userName
157
158
  ? `${labels.greeting.replace(/User!?/, "")}${userName}!`.trim()
158
159
  : labels.greeting }), _jsx(Avatar, { size: "xs", name: userName, src: userAvatarUrl })] }), _jsx(Text, { fontSize: "xs", color: subtle, mt: 0.5, children: labels.manageSubtitle })] })] }), _jsx(Button, { label: labels.createNewOrganization, onClick: () => setCreateOpen(true), leftIcon: _jsx(Plus, { size: 16 }), colorScheme: "primary", size: "sm" })] }), isLoading ? (_jsx(Box, { ...gridSx, children: Array.from({ length: 6 }).map((_, idx) => (_jsxs(Box, { ...cardSx, p: 3, children: [_jsx(Skeleton, { boxSize: "36px", borderRadius: "lg", mb: 2 }), _jsx(SkeletonText, { noOfLines: 2, spacing: 2 })] }, idx))) })) : !hasOrganizations ? (_jsx(EmptyState, { icon: Building2, title: labels.noOrganizationsTitle, description: labels.noOrganizationsDescription, minH: "40vh", action: _jsx(Button, { label: labels.createOrganization, onClick: () => setCreateOpen(true), leftIcon: _jsx(Plus, { size: 16 }), colorScheme: "primary", size: "sm" }) })) : (_jsxs(VStack, { align: "stretch", spacing: 4, children: [activeOrganizations.length > 0 && (_jsxs(Box, { children: [_jsxs(Flex, { align: "center", gap: 2, mb: 2, children: [_jsx(Users, { size: 16, color: colors.accentText }), _jsx(Heading, { size: "sm", color: heading, fontWeight: 600, children: labels.activeOrganizations }), sectionBadge(activeOrganizations.length, "blue")] }), _jsx(Box, { ...gridSx, children: activeOrganizations.map(renderActiveCard) })] })), invitedOrganizations.length > 0 && (_jsxs(Box, { children: [_jsxs(Flex, { align: "center", gap: 2, mb: 2, children: [_jsx(Mail, { size: 16, color: colors.semanticText.warning }), _jsx(Heading, { size: "sm", color: heading, fontWeight: 600, children: labels.invitedOrganizations }), sectionBadge(invitedOrganizations.length, "yellow")] }), _jsx(Box, { ...gridSx, children: invitedOrganizations.map(renderInvitedCard) })] }))] })), footerSlot, _jsx(CreateOrgModal, { isOpen: isCreateOpen, onClose: () => setCreateOpen(false), isLoading: isCreating, onSubmit: async (values) => {
159
160
  await (onCreateOrganization === null || onCreateOrganization === void 0 ? void 0 : onCreateOrganization(values));
@@ -3,7 +3,8 @@ import { useRef, useState } from "react";
3
3
  import { Box, Image, IconButton, Input, Text, Tooltip, HStack, } from "@chakra-ui/react";
4
4
  import { Eye, FileText, SquarePen, User } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
- import { accentTextOnCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
6
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
7
+ import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
7
8
  export default function ProfilePhotoViewer({ photoUrl, onPhotoChange, imageWidth = "100px", imageAlt = "Profile Photo", imageObjectFit = "cover", imageBorderRadius = "full", editIconSize = "sm", editIconPositionRight = "0px", editIconPositionBottom = "0px", isRound = true, boxStyle, isEditable = false, isView = false, style, handleIsView, fallbackText, revealOnHover = true, }) {
8
9
  var _a, _b, _c, _d, _e;
9
10
  const [photo, setPhoto] = useState(photoUrl);
@@ -57,14 +58,14 @@ export default function ProfilePhotoViewer({ photoUrl, onPhotoChange, imageWidth
57
58
  "&:hover .ppv-media": {
58
59
  boxShadow: `0 0 0 0.1875rem ${c.primary.opacity[24]}`,
59
60
  },
60
- }, children: [_jsx(Box, { className: "ppv-media", borderRadius: imageBorderRadius, transition: "box-shadow 0.2s ease", children: renderMedia() }), hasActions && (_jsxs(_Fragment, { children: [_jsx(Box, { className: "ppv-overlay", position: "absolute", inset: 0, borderRadius: imageBorderRadius, bg: "blackAlpha.300", opacity: 0, transition: "opacity 0.2s ease", pointerEvents: "none" }), _jsxs(HStack, { className: "ppv-actions", position: "absolute", right: editIconPositionRight, bottom: editIconPositionBottom, transform: "translate(-15%, -15%)", spacing: 1.5, opacity: revealOnHover ? 0 : 1, transition: "opacity 0.2s ease", children: [isEditable && (_jsx(Tooltip, { label: "Edit", "aria-label": "Edit", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(SquarePen, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleClick, "aria-label": "Edit photo", bg: c.primary[500], color: onFilled(c.primary[500], c.white, c.black), border: `0.125rem solid ${c.background[50]}`, boxShadow: (_b = theme.shadows) === null || _b === void 0 ? void 0 : _b.md, style: style, transition: "transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease", _hover: {
61
+ }, children: [_jsx(Box, { className: "ppv-media", borderRadius: imageBorderRadius, transition: "box-shadow 0.2s ease", children: renderMedia() }), hasActions && (_jsxs(_Fragment, { children: [_jsx(Box, { className: "ppv-overlay", position: "absolute", inset: 0, borderRadius: imageBorderRadius, bg: "blackAlpha.300", opacity: 0, transition: "opacity 0.2s ease", pointerEvents: "none" }), _jsxs(HStack, { className: "ppv-actions", position: "absolute", right: editIconPositionRight, bottom: editIconPositionBottom, transform: "translate(-15%, -15%)", spacing: 1.5, opacity: revealOnHover ? 0 : 1, transition: "opacity 0.2s ease", children: [isEditable && (_jsx(Tooltip, { label: "Edit", "aria-label": "Edit", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(SquarePen, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleClick, "aria-label": "Edit photo", bg: c.primary[solidFillRung(c.primary, c.white)], color: labelOnFill(c.primary[solidFillRung(c.primary, c.white)], c.white, c.black), border: `0.125rem solid ${c.background[50]}`, boxShadow: (_b = theme.shadows) === null || _b === void 0 ? void 0 : _b.md, style: style, transition: "transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease", _hover: {
61
62
  bg: c.primary[600],
62
- color: onFilled(c.primary[600], c.white, c.black),
63
+ color: labelOnFill(c.primary[600], c.white, c.black),
63
64
  transform: "scale(1.1)",
64
65
  boxShadow: (_c = theme.shadows) === null || _c === void 0 ? void 0 : _c.lg,
65
66
  }, _active: {
66
67
  bg: c.primary[700],
67
- color: onFilled(c.primary[700], c.white, c.black),
68
+ color: labelOnFill(c.primary[700], c.white, c.black),
68
69
  } }) })), isView && (_jsx(Tooltip, { label: "View", "aria-label": "View", hasArrow: true, children: _jsx(IconButton, { icon: _jsx(Eye, { size: 14 }), isRound: isRound, size: editIconSize, onClick: handleIsView, "aria-label": "View photo", bg: c.background[50], color: c.text[700], border: `0.063rem solid ${border}`, boxShadow: (_d = theme.shadows) === null || _d === void 0 ? void 0 : _d.md, style: style, transition: "transform 0.2s ease, background 0.2s ease, box-shadow 0.2s ease", _hover: {
69
70
  bg: c.gray[50],
70
71
  color: accentTextOnCanvas(c.primary, c.gray[50]),
@@ -5,7 +5,7 @@ import { ChevronUp } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import ToolTip from "../ToolTip/ToolTip.js";
7
7
  import { rafThrottle } from "../../Utils/rafThrottle.js";
8
- import { onFilled } from "../../Theme/tokens/builders/accentText.js";
8
+ import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
9
9
  const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300, duration = 600, useWindow = false, bottom = "2rem", right = "2rem", }) => {
10
10
  const [visible, setVisible] = useState(false);
11
11
  const anchorRef = useRef(null);
@@ -58,9 +58,9 @@ const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300
58
58
  };
59
59
  // eslint-disable-next-line react-hooks/exhaustive-deps
60
60
  }, [useWindow, threshold]);
61
- return (_jsxs(Box, { ref: anchorRef, position: "relative", children: [children, _jsx(ToolTip, { label: tooltipLabel, placement: "left", children: _jsx(Box, { as: "button", type: "button", onClick: scrollToTop, "aria-label": tooltipLabel, border: "none", position: "fixed", bottom: bottom, right: right, zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center", boxSize: "44px", borderRadius: "full", cursor: "pointer", bg: theme.colors.primary[500], color: theme.colors.onPrimary, boxShadow: "md", opacity: visible ? 1 : 0, transform: visible ? "translateY(0) scale(1)" : "translateY(16px) scale(0.85)", pointerEvents: visible ? "auto" : "none", transition: "all 0.25s cubic-bezier(0.16, 1, 0.3, 1)", _hover: {
61
+ return (_jsxs(Box, { ref: anchorRef, position: "relative", children: [children, _jsx(ToolTip, { label: tooltipLabel, placement: "left", children: _jsx(Box, { as: "button", type: "button", onClick: scrollToTop, "aria-label": tooltipLabel, border: "none", position: "fixed", bottom: bottom, right: right, zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center", boxSize: "44px", borderRadius: "full", cursor: "pointer", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), boxShadow: "md", opacity: visible ? 1 : 0, transform: visible ? "translateY(0) scale(1)" : "translateY(16px) scale(0.85)", pointerEvents: visible ? "auto" : "none", transition: "all 0.25s cubic-bezier(0.16, 1, 0.3, 1)", _hover: {
62
62
  bg: theme.colors.primary[600],
63
- color: onFilled(theme.colors.primary[600], theme.colors.white, theme.colors.black),
63
+ color: labelOnFill(theme.colors.primary[600], theme.colors.white, theme.colors.black),
64
64
  transform: "translateY(-2px) scale(1.05)",
65
65
  boxShadow: "lg",
66
66
  }, _active: { transform: "scale(0.95)" }, children: _jsx(ChevronUp, { size: 24, strokeWidth: 2.5 }) }) })] }));
@@ -243,7 +243,7 @@ BottomIcon = false, BottomText, handleBottomClick, BottomTextColor, isColorOptio
243
243
  document.removeEventListener("mousedown", handleClickOutside);
244
244
  };
245
245
  }, [isOpen]);
246
- return (_jsx(_Fragment, { children: _jsx(FormControl, { isInvalid: error, children: _jsxs(Box, { display: "flex", flexDirection: "column", position: "relative", sx: boxStyle, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), isMultipleSelect && selectedOptions.length > 0 && (_jsx(HStack, { spacing: 2, mb: 2, children: selectedOptions.map((option) => (_jsxs(Tag, { size: "md", borderRadius: "full", variant: "solid", sx: { backgroundColor: theme.colors.primary[500] }, children: [_jsx(TagLabel, { width: "50px", children: option.label }), _jsx(TagCloseButton, { onClick: () => handleRemoveOption(option) })] }, option.id))) })), _jsxs(InputGroup, { children: [_jsx(Input, { ref: inputRef, variant: "outline", borderRadius: FIELD_RADIUS, value: inputValue ? inputValue : "", onClick: () => setIsOpen(true), onFocus: () => {
246
+ return (_jsx(_Fragment, { children: _jsx(FormControl, { isInvalid: error, children: _jsxs(Box, { display: "flex", flexDirection: "column", position: "relative", sx: boxStyle, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), isMultipleSelect && selectedOptions.length > 0 && (_jsx(HStack, { spacing: 2, mb: 2, children: selectedOptions.map((option) => (_jsxs(Tag, { size: "md", borderRadius: "full", variant: "solid", colorScheme: "primary", children: [_jsx(TagLabel, { width: "50px", children: option.label }), _jsx(TagCloseButton, { onClick: () => handleRemoveOption(option) })] }, option.id))) })), _jsxs(InputGroup, { children: [_jsx(Input, { ref: inputRef, variant: "outline", borderRadius: FIELD_RADIUS, value: inputValue ? inputValue : "", onClick: () => setIsOpen(true), onFocus: () => {
247
247
  if (skipNextInputFocusOpen.current) {
248
248
  skipNextInputFocusOpen.current = false;
249
249
  return;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { Flex, Text, Image, Box, Skeleton, useBreakpointValue } from "@chakra-ui/react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
- import { onFilled } from "../../Theme/tokens/builders/accentText.js";
5
+ import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
6
6
  import { getSidebarActiveAccent } from "./sidebarAccentColors.js";
7
7
  import { FlexCss, HEADER_HEIGHT } from "../../Constants/Sidebar.js";
8
8
  import { ArrowLeftToLine, ArrowRightToLine, ChevronLeft, Maximize2, MoreVertical, PanelLeft, Plus, X } from "lucide-react";
@@ -27,7 +27,9 @@ const SidebarHeader = ({ logo, companyName, companySubtitle, toggle, isLoading,
27
27
  if (isLoading) {
28
28
  return (_jsx(Box, { w: "100%", px: toggle ? 2 : 4, py: 2, h: HEADER_HEIGHT, display: "flex", alignItems: "center", flexShrink: 0, children: toggle ? (_jsx(Flex, { align: "center", gap: 4, justifyContent: "center", w: "100%", children: _jsx(Skeleton, { w: "28px", h: "28px", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] }) })) : (_jsxs(Flex, { align: "center", gap: 3, w: "100%", children: [_jsx(Skeleton, { w: "28px", h: "28px", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] }), _jsx(Skeleton, { h: "1.25rem", w: "60%", borderRadius: "md", startColor: theme.colors.sidebar.background[400], endColor: theme.colors.sidebar.background[300] })] })) }));
29
29
  }
30
- const logoNode = logo ? (_jsx(Image, { borderRadius: "md", boxSize: "1.75rem", src: logo, alt: "Company Logo", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined })) : (_jsx(Box, { bg: theme.colors.primary[500], color: onFilled(theme.colors.primary[500], theme.colors.white, theme.colors.black), borderRadius: "md", boxSize: "1.75rem", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: "bold", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined, children: _jsx(DefaultLogo, {}) }));
30
+ const primaryFillRung = solidFillRung(theme.colors.primary, theme.colors.white);
31
+ const primaryFill = theme.colors.primary[primaryFillRung];
32
+ const logoNode = logo ? (_jsx(Image, { borderRadius: "md", boxSize: "1.75rem", src: logo, alt: "Company Logo", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined })) : (_jsx(Box, { bg: primaryFill, color: labelOnFill(primaryFill, theme.colors.white, theme.colors.black), borderRadius: "md", boxSize: "1.75rem", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: "bold", flexShrink: 0, cursor: toggle ? "pointer" : undefined, onClick: toggle ? onToggle : undefined, children: _jsx(DefaultLogo, {}) }));
31
33
  return (_jsxs(Flex, { h: HEADER_HEIGHT, w: "100%", alignItems: "center", justifyContent: toggle ? "center" : "flex-start", gap: "8px", px: toggle ? "8px" : "10px", borderBottom: "1px solid", borderColor: "whiteAlpha.100", minW: 0, overflow: "hidden", flexShrink: 0, children: [logoNode, !toggle && (_jsxs(Box, { flex: "1", minW: 0, children: [_jsx(OverflowTooltipText, { placement: "right", fontWeight: 600, fontSize: "12.5px", textAlign: "left", color: theme.colors.white, lineHeight: "1.3", as: "p", width: "100%", children: companyName !== null && companyName !== void 0 ? companyName : "" }), companySubtitle && (_jsx(Text, { fontSize: "10px", color: theme.colors.sidebar.mutedLabel, lineHeight: "1.3", isTruncated: true, children: companySubtitle }))] })), !toggle && (_jsx(Box, { as: "button", type: "button", onClick: overlay ? onClose : onToggle, "aria-label": overlay ? "Close menu" : "Collapse sidebar", w: "22px", h: "22px", borderRadius: "base", bg: "whiteAlpha.100", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, _hover: { bg: "whiteAlpha.300" }, transition: "background 0.15s", children: overlay ? (_jsx(X, { size: 15, color: theme.colors.sidebar.mutedIcon })) : (_jsx(ChevronLeft, { size: 14, color: theme.colors.sidebar.mutedIcon })) }))] }));
32
34
  };
33
35
  const SkeletonMenuRow = ({ toggle }) => {
@@ -1,14 +1,16 @@
1
- import { accentTextOnCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
1
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
2
+ import { resolveFilledSurface } from "../../Theme/tokens/builders/filledSurface.js";
2
3
  /** Exhaustive by construction: a new scheme that maps nowhere is a compile error. */
3
4
  const scaleFor = (colors, scheme) => scheme === "primary" || scheme === "secondary" || scheme === "tertiary"
4
5
  ? colors[scheme]
5
6
  : colors.semantic[scheme];
6
7
  /** Resolve a chevron palette for a given color scheme from the theme. */
7
8
  export const resolveStagePalette = (theme, colorScheme = "primary") => {
8
- const { gray, white, black } = theme.colors;
9
+ const { gray } = theme.colors;
9
10
  const scale = scaleFor(theme.colors, colorScheme);
10
- const strong = scale[500];
11
- const onStrong = onFilled(strong, white, black);
11
+ const solid = resolveFilledSurface(scale, theme.colors);
12
+ const strong = solid.fill;
13
+ const onStrong = solid.color;
12
14
  const soft = scale[100];
13
15
  // A fixed [700] fails AA against [100] for some hues (orange 3.30, borderline green 3.58) —
14
16
  // walk the scale's own rungs against this specific tint instead.
@@ -18,7 +20,7 @@ export const resolveStagePalette = (theme, colorScheme = "primary") => {
18
20
  softText,
19
21
  strong,
20
22
  onStrong,
21
- hover: scale[600],
23
+ hover: solid.hoverFill,
22
24
  muted: gray[100],
23
25
  mutedText: gray[500],
24
26
  };
@@ -7,6 +7,7 @@ import LeftFilterPane from "./filters/LeftFilterPane.js";
7
7
  import { TABLE_VARIANTS } from "./variants/index.js";
8
8
  import { TableVariantProvider } from "./variants/TableVariantContext.js";
9
9
  import { isDarkCanvas } from "../../Theme/tokens/builders/accentText.js";
10
+ import { labelOnFill, solidFillRung } from "../../Theme/tokens/builders/filledSurface.js";
10
11
  import Pagination from "./components/Pagination.js";
11
12
  import TableHeader from "./components/TableHeader.js";
12
13
  import TableBody from "./components/TableBody.js";
@@ -365,7 +366,7 @@ export default function Table({ data, columns, onSelection, isLoading, isCheckbo
365
366
  // Square children poked past the rounded border, leaving a gap at each corner.
366
367
  overflow: "hidden", children: [filterSidebar && filterMode === "modal" && (_jsxs(Modal, { isOpen: isFilterModalOpen, onClose: onFilterModalClose, size: "4xl", scrollBehavior: "inside", children: [_jsx(ModalOverlay, {}), _jsxs(ModalContent, { bg: theme.colors.background[50], my: 0, top: "10%", position: "fixed", left: "auto", right: "auto", children: [_jsx(ModalCloseButton, { size: "sm" }), _jsx(ModalBody, { p: 0, children: _jsx(LeftFilterPane, { theme: theme, sections: (_c = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.sidebarOptions) !== null && _c !== void 0 ? _c : [], selected: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.selected, onApply: (sel) => { var _a; (_a = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onApply) === null || _a === void 0 ? void 0 : _a.call(filterSidebar, sel); onFilterModalClose(); }, onClear: () => { var _a; (_a = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler) === null || _a === void 0 ? void 0 : _a.call(filterSidebar); }, isApplyLoading: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isApplyLoading, filterMode: filterMode }) })] })] })), _jsxs(Flex, { align: "start", children: [filterMode === "sidebar" && (_jsx(MotionBox, { "data-testid": "filter-sidebar-pane", initial: { width: 0 }, animate: { width: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? 180 : 0 }, transition: { type: "tween", duration: 0.5 }, overflow: "hidden", flexShrink: 0, borderRight: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? "1px solid" : "none", borderColor: theme.colors.boxborder[200], style: { height: controlsHeight + tableMaxH }, minHeight: (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isFilterSidebar) ? "32rem" : "auto", children: _jsx(LeftFilterPane, { height: controlsHeight + tableMaxH, theme: theme, sections: (_d = filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.sidebarOptions) !== null && _d !== void 0 ? _d : [], selected: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.selected, onApply: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onApply, onClear: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler, isApplyLoading: filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.isApplyLoading, filterMode: filterMode }) })), _jsxs(Box, { flex: "1", minW: 0, children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", px: 3, py: 0, height: controlsHeight, gap: 3, flexWrap: "nowrap", bg: theme.colors.background[50], borderBottom: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [filterSidebar && (_jsxs(_Fragment, { children: [_jsx(ToolTip, { label: "Filter", placement: "top", children: _jsxs(Box, { position: "relative", display: "inline-block", children: [_jsx(Icon, { as: Filter, transform: "scaleX(-1)", cursor: "pointer", boxSize: 4, color: sidebarActiveCount > 0 ? theme.colors.accentText : theme.colors.text[500], onClick: filterMode === "modal" ? onFilterModalOpen : filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.filterSidebarToggle, _hover: {
367
368
  color: theme.colors.accentText,
368
- } }), sidebarActiveCount > 0 && (_jsx(Box, { position: "absolute", top: "-6px", right: "-10px", bg: theme.colors.primary[500], color: theme.colors.onPrimary, borderRadius: "full", p: "1px", cursor: "pointer", onClick: (e) => {
369
+ } }), sidebarActiveCount > 0 && (_jsx(Box, { position: "absolute", top: "-6px", right: "-10px", bg: theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], color: labelOnFill(theme.colors.primary[solidFillRung(theme.colors.primary, theme.colors.white)], theme.colors.white, theme.colors.black), borderRadius: "full", p: "1px", cursor: "pointer", onClick: (e) => {
369
370
  var _a;
370
371
  e.stopPropagation();
371
372
  if (filterSidebar === null || filterSidebar === void 0 ? void 0 : filterSidebar.onClearAllHandler) {
@@ -168,6 +168,6 @@ const LeftFilterPane = ({ title = "Filter", height = 300, sections, selected: se
168
168
  }
169
169
  return filteredSections.map((sec) => (_jsxs(Box, { children: [_jsx(Box, { px: 3, py: 2, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: _jsx(SectionLabel, { label: sec.label, theme: theme }) }), _jsx(Box, { px: 3, pt: 2, pb: 1, children: _jsx(SectionContent, { sec: sec, ...sectionContentProps }) })] }, sec.id)));
170
170
  };
171
- return (_jsxs(Box, { width: filterMode === "modal" ? "100%" : "180px", height: filterMode === "modal" ? "100%" : height, minHeight: "32rem", bg: theme.colors.background[50], borderRight: "1px solid", borderColor: theme.colors.boxborder[200], borderRadius: "md", overflow: "hidden", display: "flex", flexDirection: "column", marginBottom: filterMode === "modal" && hasActiveFilters ? '3.5rem' : 0, children: [_jsx(Box, { p: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: !isSearching ? (_jsxs(Flex, { align: "center", justify: "space-between", children: [_jsx(Text, { fontWeight: "semibold", fontSize: "sm", children: title }), _jsx(IconButton, { "aria-label": "Search filters", icon: _jsx(Icon, { as: Search, transform: "scaleX(-1)", boxSize: 4 }), variant: "unstyled", minW: "auto", h: "auto", display: "flex", cursor: "pointer", color: theme.colors.text[500], onClick: () => setIsSearching(true), mr: filterMode === "modal" ? 8 : 2, mt: filterMode === "modal" ? -1 : 0 })] })) : (_jsx(motion.div, { ref: searchRef, initial: { opacity: 0, x: 40 }, animate: { opacity: 1, x: 0 }, transition: { type: "tween", duration: 0.2 }, children: _jsxs(InputGroup, { size: "sm", children: [_jsx(InputLeftElement, { pointerEvents: "none", children: _jsx(Search, { size: 16, color: theme.colors.text[500] }) }), _jsx(Input, { placeholder: "Search", value: search, onChange: (e) => setSearch(e.target.value), autoFocus: true }), search.length > 0 && (_jsx(InputRightElement, { children: _jsx(IconButton, { "aria-label": "Clear", size: "xs", variant: "ghost", icon: _jsx(X, { size: 14 }), onClick: () => { setSearch(""); setIsSearching(false); } }) }))] }) })) }), _jsx(Box, { flex: "1", overflowY: "auto", children: renderSections() }), hasActiveFilters && (_jsxs(HStack, { px: 2, py: 1, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], spacing: 2, position: filterMode === "modal" ? "absolute" : "relative", bottom: 0, left: 0, right: 0, bg: theme.colors.background[50], children: [_jsx(Button, { flex: 1, variant: "outline", size: "sm", onClick: handleClear, fontSize: "xs", colorScheme: "red", children: "Clear All" }), _jsx(Button, { flex: 1, colorScheme: "primary", color: theme.colors.onPrimary, size: "sm", onClick: handleApply, fontSize: "xs", isLoading: isApplyLoading, children: "Apply" })] }))] }));
171
+ return (_jsxs(Box, { width: filterMode === "modal" ? "100%" : "180px", height: filterMode === "modal" ? "100%" : height, minHeight: "32rem", bg: theme.colors.background[50], borderRight: "1px solid", borderColor: theme.colors.boxborder[200], borderRadius: "md", overflow: "hidden", display: "flex", flexDirection: "column", marginBottom: filterMode === "modal" && hasActiveFilters ? '3.5rem' : 0, children: [_jsx(Box, { p: 3, borderBottom: "1px solid", borderColor: theme.colors.boxborder[200], children: !isSearching ? (_jsxs(Flex, { align: "center", justify: "space-between", children: [_jsx(Text, { fontWeight: "semibold", fontSize: "sm", children: title }), _jsx(IconButton, { "aria-label": "Search filters", icon: _jsx(Icon, { as: Search, transform: "scaleX(-1)", boxSize: 4 }), variant: "unstyled", minW: "auto", h: "auto", display: "flex", cursor: "pointer", color: theme.colors.text[500], onClick: () => setIsSearching(true), mr: filterMode === "modal" ? 8 : 2, mt: filterMode === "modal" ? -1 : 0 })] })) : (_jsx(motion.div, { ref: searchRef, initial: { opacity: 0, x: 40 }, animate: { opacity: 1, x: 0 }, transition: { type: "tween", duration: 0.2 }, children: _jsxs(InputGroup, { size: "sm", children: [_jsx(InputLeftElement, { pointerEvents: "none", children: _jsx(Search, { size: 16, color: theme.colors.text[500] }) }), _jsx(Input, { placeholder: "Search", value: search, onChange: (e) => setSearch(e.target.value), autoFocus: true }), search.length > 0 && (_jsx(InputRightElement, { children: _jsx(IconButton, { "aria-label": "Clear", size: "xs", variant: "ghost", icon: _jsx(X, { size: 14 }), onClick: () => { setSearch(""); setIsSearching(false); } }) }))] }) })) }), _jsx(Box, { flex: "1", overflowY: "auto", children: renderSections() }), hasActiveFilters && (_jsxs(HStack, { px: 2, py: 1, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], spacing: 2, position: filterMode === "modal" ? "absolute" : "relative", bottom: 0, left: 0, right: 0, bg: theme.colors.background[50], children: [_jsx(Button, { flex: 1, variant: "outline", size: "sm", onClick: handleClear, fontSize: "xs", colorScheme: "red", children: "Clear All" }), _jsx(Button, { flex: 1, colorScheme: "primary", size: "sm", onClick: handleApply, fontSize: "xs", isLoading: isApplyLoading, children: "Apply" })] }))] }));
172
172
  };
173
173
  export default LeftFilterPane;
@@ -1,5 +1,5 @@
1
- import { accentTextOnCanvas, isDarkCanvas, onFilled } from "../../Theme/tokens/builders/accentText.js";
2
- import { solidRung, darkerFillRung } from "../../Theme/tokens/builders/solidFillRung.js";
1
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
2
+ import { darkerFillRung, labelOnFill, solidFillRung, } from "../../Theme/tokens/builders/filledSurface.js";
3
3
  // Resolve a colorScheme key to a numeric swatch from the theme. All supported
4
4
  // colorScheme values (brand + global scales) expose a 50-900 scale; fall back to
5
5
  // gray so an unknown/missing key can never throw at render time.
@@ -39,18 +39,22 @@ export const Tag = {
39
39
  },
40
40
  variants: {
41
41
  solid: ({ theme, colorScheme = "primary" }) => {
42
+ const palette = theme.colors;
42
43
  const c = swatch(theme, colorScheme);
43
- const { white, black, backgroundColor } = theme.colors;
44
- const isDark = isDarkCanvas(backgroundColor.main);
45
- const fill = c[solidRung(c, white)];
46
- const hoverFill = c[darkerFillRung(c, white, isDark, 0)];
47
- const activeFill = c[darkerFillRung(c, white, isDark, 1)];
44
+ const { white, black, backgroundColor } = palette;
45
+ const canvas = backgroundColor.main;
46
+ const fillRung = solidFillRung(c, white);
47
+ const hoverRung = darkerFillRung(c, canvas, white, 0);
48
+ const activeRung = darkerFillRung(c, canvas, white, 1);
49
+ const fill = c[fillRung];
50
+ const hoverFill = c[hoverRung];
51
+ const activeFill = c[activeRung];
48
52
  return {
49
53
  container: {
50
54
  bg: fill,
51
- color: onFilled(fill, white, black),
52
- _hover: { bg: hoverFill, color: onFilled(hoverFill, white, black) },
53
- _active: { bg: activeFill, color: onFilled(activeFill, white, black) },
55
+ color: labelOnFill(fill, white, black),
56
+ _hover: { bg: hoverFill, color: labelOnFill(hoverFill, white, black) },
57
+ _active: { bg: activeFill, color: labelOnFill(activeFill, white, black) },
54
58
  },
55
59
  };
56
60
  },