pixelize-design-library 2.4.2-beta.25 → 2.4.2-beta.26

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 (74) hide show
  1. package/dist/Components/Accordion/Accordion.js +3 -1
  2. package/dist/Components/Button/Button.js +2 -1
  3. package/dist/Components/Button/Button.styles.js +7 -7
  4. package/dist/Components/Card/PaymentCard/PaymentCard.js +7 -7
  5. package/dist/Components/Checkbox/Checkbox.styles.js +10 -7
  6. package/dist/Components/CopyButton/CopyButton.js +5 -1
  7. package/dist/Components/Dropdown/DropDown.js +4 -2
  8. package/dist/Components/EmptyState/EmptyState.js +2 -1
  9. package/dist/Components/FileUpload/FileUpload.js +2 -2
  10. package/dist/Components/FilterSidebar/filterHoverStyle.d.ts +0 -9
  11. package/dist/Components/FilterSidebar/filterHoverStyle.js +4 -10
  12. package/dist/Components/Header/components/mobileMenu.js +12 -3
  13. package/dist/Components/Loading/Loading.js +15 -14
  14. package/dist/Components/NoteTextArea/NoteTextArea.js +5 -2
  15. package/dist/Components/PdfViewer/PdfViewer.js +6 -1
  16. package/dist/Components/ProductCard/ProductReview.js +6 -1
  17. package/dist/Components/ProductCard/ProductTags.js +1 -1
  18. package/dist/Components/RadioButton/RadioButton.js +2 -1
  19. package/dist/Components/ScrollToTop/ScrollToTop.js +2 -0
  20. package/dist/Components/SearchSelect/SearchSelect.js +10 -6
  21. package/dist/Components/SegmentedControl/SegmentedControl.d.ts +2 -0
  22. package/dist/Components/SegmentedControl/SegmentedControl.js +58 -0
  23. package/dist/Components/SegmentedControl/SegmentedControlProps.d.ts +16 -0
  24. package/dist/Components/SegmentedControl/SegmentedControlProps.js +2 -0
  25. package/dist/Components/SelectSearch/SelectSearch.js +4 -1
  26. package/dist/Components/SelectV2/SelectV2.js +5 -3
  27. package/dist/Components/SideBar/components/MenuPopoverContent.js +2 -2
  28. package/dist/Components/Slider/Slider.js +8 -1
  29. package/dist/Components/StageProgress/StepperStage.js +2 -2
  30. package/dist/Components/Table/settings/ManageColumns.js +2 -1
  31. package/dist/Components/Tag/Tag.styles.js +3 -4
  32. package/dist/Components/Toggle/TableToggle.js +11 -7
  33. package/dist/Components/ToggleSwitch/ToggleSwitch.d.ts +2 -0
  34. package/dist/Components/ToggleSwitch/ToggleSwitch.js +18 -0
  35. package/dist/Components/ToggleSwitch/ToggleSwitchProps.d.ts +11 -0
  36. package/dist/Components/ToggleSwitch/ToggleSwitchProps.js +2 -0
  37. package/dist/Components/ToolTip/ToolTip.js +6 -6
  38. package/dist/Components/ToolTip/ToolTipProps.d.ts +3 -1
  39. package/dist/esm/Components/Accordion/Accordion.js +3 -1
  40. package/dist/esm/Components/Button/Button.js +2 -1
  41. package/dist/esm/Components/Button/Button.styles.js +7 -7
  42. package/dist/esm/Components/Card/PaymentCard/PaymentCard.js +7 -7
  43. package/dist/esm/Components/Checkbox/Checkbox.styles.js +11 -8
  44. package/dist/esm/Components/CopyButton/CopyButton.js +6 -2
  45. package/dist/esm/Components/Dropdown/DropDown.js +4 -2
  46. package/dist/esm/Components/EmptyState/EmptyState.js +2 -1
  47. package/dist/esm/Components/FileUpload/FileUpload.js +2 -2
  48. package/dist/esm/Components/FilterSidebar/filterHoverStyle.js +4 -10
  49. package/dist/esm/Components/Header/components/mobileMenu.js +12 -3
  50. package/dist/esm/Components/Loading/Loading.js +12 -11
  51. package/dist/esm/Components/NoteTextArea/NoteTextArea.js +5 -2
  52. package/dist/esm/Components/PdfViewer/PdfViewer.js +6 -1
  53. package/dist/esm/Components/ProductCard/ProductReview.js +6 -1
  54. package/dist/esm/Components/ProductCard/ProductTags.js +1 -1
  55. package/dist/esm/Components/RadioButton/RadioButton.js +2 -1
  56. package/dist/esm/Components/ScrollToTop/ScrollToTop.js +2 -0
  57. package/dist/esm/Components/SearchSelect/SearchSelect.js +10 -6
  58. package/dist/esm/Components/SegmentedControl/SegmentedControl.js +55 -0
  59. package/dist/esm/Components/SegmentedControl/SegmentedControlProps.js +1 -0
  60. package/dist/esm/Components/SelectSearch/SelectSearch.js +4 -1
  61. package/dist/esm/Components/SelectV2/SelectV2.js +5 -3
  62. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +2 -2
  63. package/dist/esm/Components/Slider/Slider.js +8 -1
  64. package/dist/esm/Components/StageProgress/StepperStage.js +2 -2
  65. package/dist/esm/Components/Table/settings/ManageColumns.js +2 -1
  66. package/dist/esm/Components/Tag/Tag.styles.js +3 -4
  67. package/dist/esm/Components/Toggle/TableToggle.js +11 -7
  68. package/dist/esm/Components/ToggleSwitch/ToggleSwitch.js +15 -0
  69. package/dist/esm/Components/ToggleSwitch/ToggleSwitchProps.js +1 -0
  70. package/dist/esm/Components/ToolTip/ToolTip.js +6 -6
  71. package/dist/esm/index.js +3 -1
  72. package/dist/index.d.ts +5 -1
  73. package/dist/index.js +7 -3
  74. package/package.json +1 -1
@@ -15,6 +15,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
15
15
  badgeColor: `0.125rem solid ${theme.colors.green[500]}`,
16
16
  buttonColor: theme.colors.green[500],
17
17
  buttonColor50: theme.colors.green[50],
18
+ colorScheme: "green",
18
19
  });
19
20
  }
20
21
  if (isNextUpgrade) {
@@ -23,6 +24,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
23
24
  badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
24
25
  buttonColor: theme.colors.primary[500],
25
26
  buttonColor50: theme.colors.primary[50],
27
+ colorScheme: "primary",
26
28
  });
27
29
  }
28
30
  if (popular) {
@@ -31,6 +33,7 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
31
33
  badgeColor: `0.125rem solid ${theme.colors.primary[500]}`,
32
34
  buttonColor: theme.colors.primary[500],
33
35
  buttonColor50: theme.colors.primary[50],
36
+ colorScheme: "primary",
34
37
  });
35
38
  }
36
39
  return withOnButtonColor({
@@ -38,17 +41,14 @@ const getCardStyles = (isActive, isNextUpgrade, popular, theme) => {
38
41
  badgeColor: "",
39
42
  buttonColor: theme.colors.primary[500],
40
43
  buttonColor50: theme.colors.primary[50],
44
+ colorScheme: "primary",
41
45
  });
42
46
  };
43
47
  const PaymentCard = ({ plan, isActive = false, isNextUpgrade = false, billingCycle, onSelect, onHover, buttonLoading, isLoading = false, isRenewal = false, }) => {
44
48
  const theme = useCustomTheme();
45
- const { badgeText, badgeColor, buttonColor, buttonColor50, onButtonColor } = getCardStyles(isActive, isNextUpgrade, !!plan.popular, theme);
49
+ const { badgeText, badgeColor, buttonColor, buttonColor50, onButtonColor, colorScheme } = getCardStyles(isActive, isNextUpgrade, !!plan.popular, theme);
46
50
  const variantStyles = plan.buttonVariant === "outline"
47
- ? {
48
- borderColor: buttonColor,
49
- color: buttonColor,
50
- _hover: { bg: buttonColor50 },
51
- }
51
+ ? {}
52
52
  : {
53
53
  bg: buttonColor,
54
54
  color: onButtonColor,
@@ -60,6 +60,6 @@ const PaymentCard = ({ plan, isActive = false, isNextUpgrade = false, billingCyc
60
60
  // 🔹 Actual Card Content
61
61
  _jsxs(_Fragment, { children: [badgeText && (_jsx(Badge, { position: "absolute", top: "-0.75rem", left: "50%", transform: "translateX(-50%)", bg: buttonColor, color: onButtonColor, fontSize: "sm", px: 4, py: 1, borderRadius: "full", children: badgeText })), _jsxs(Box, { textAlign: "center", mb: 6, children: [_jsx(Flex, { justify: "center", align: "center", w: "3.125rem", h: "3.125rem", borderRadius: "lg", bg: buttonColor50, color: buttonColor, mx: "auto", mb: 4, children: plan.icon }), _jsx(Heading, { as: "h3", size: "lg", mb: 4, color: theme.colors.gray[800], children: plan.name }), (plan.yearlyPrice !== 0 || plan.monthlyPrice !== 0) && (_jsxs(Heading, { as: "h4", size: "2xl", mb: 1, color: theme.colors.gray[800], display: "flex", justifyContent: "center", children: [_jsx(Box, { fontSize: "1.5rem", children: "\u20B9" }), billingCycle === "yearly"
62
62
  ? plan.yearlyPrice
63
- : plan.monthlyPrice, _jsxs(Box, { display: "flex", flexDirection: "column", justifyContent: "end", ml: 1, children: [_jsx(Text, { fontSize: "0.9rem", fontWeight: "normal", color: theme.colors.gray[600], children: plan.billing }), _jsx(Text, { fontSize: "0.7rem", fontWeight: "normal", color: theme.colors.gray[600], children: plan.tax })] })] })), plan.priceDescription && (_jsx(Text, { color: theme.colors.green[800], mt: 2, children: plan === null || plan === void 0 ? void 0 : plan.priceDescription })), _jsx(Text, { color: theme.colors.gray[600], mt: 2, children: plan.description })] }), ((!isActive && plan.buttonText) || isRenewal) && (_jsx(Button, { isLoading: plan.plan_id === buttonLoading, loadingText: plan.buttonLoadingText, width: "full", variant: plan.buttonVariant, size: "lg", onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(plan.plan_id), onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(plan.plan_id, "button", true), onMouseLeave: () => onHover === null || onHover === void 0 ? void 0 : onHover(plan.plan_id, "button", false), ...variantStyles, children: plan.buttonText })), _jsx(VStack, { align: "start", spacing: 3, mt: 6, children: plan.features.map((feature, i) => (_jsxs(Flex, { align: "center", children: [_jsx(Icon, { as: Check, color: theme.colors.green[500], mr: 2 }), _jsx(Text, { fontSize: "sm", children: feature })] }, i))) })] })) }) }));
63
+ : plan.monthlyPrice, _jsxs(Box, { display: "flex", flexDirection: "column", justifyContent: "end", ml: 1, children: [_jsx(Text, { fontSize: "0.9rem", fontWeight: "normal", color: theme.colors.gray[600], children: plan.billing }), _jsx(Text, { fontSize: "0.7rem", fontWeight: "normal", color: theme.colors.gray[600], children: plan.tax })] })] })), plan.priceDescription && (_jsx(Text, { color: theme.colors.green[800], mt: 2, children: plan === null || plan === void 0 ? void 0 : plan.priceDescription })), _jsx(Text, { color: theme.colors.gray[600], mt: 2, children: plan.description })] }), ((!isActive && plan.buttonText) || isRenewal) && (_jsx(Button, { isLoading: plan.plan_id === buttonLoading, loadingText: plan.buttonLoadingText, width: "full", variant: plan.buttonVariant, colorScheme: colorScheme, size: "lg", onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(plan.plan_id), onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(plan.plan_id, "button", true), onMouseLeave: () => onHover === null || onHover === void 0 ? void 0 : onHover(plan.plan_id, "button", false), ...variantStyles, children: plan.buttonText })), _jsx(VStack, { align: "start", spacing: 3, mt: 6, children: plan.features.map((feature, i) => (_jsxs(Flex, { align: "center", children: [_jsx(Icon, { as: Check, color: theme.colors.green[500], mr: 2 }), _jsx(Text, { fontSize: "sm", children: feature })] }, i))) })] })) }) }));
64
64
  };
65
65
  export default PaymentCard;
@@ -1,14 +1,14 @@
1
- import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
1
+ import { AA_NON_TEXT, liftToContrast, resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
2
+ import { onFilled } from "../../Theme/tokens/builders/accentText.js";
2
3
  export const Checkbox = {
3
4
  baseStyle: ({ theme, colorScheme = "primary" }) => {
4
5
  var _a;
5
6
  const palette = (_a = theme.colors[colorScheme]) !== null && _a !== void 0 ? _a : theme.colors.primary;
6
- // A browser probe found the checked checkbox's hover repeating its own resting `[600]` fill.
7
- // Chakra's stock control also carries a checked-hover at `_checked._hover` (this override
8
- // nests the other way, `_hover._checked`) — two different key paths landing on the same
9
- // selector, so whichever one the cascade picks must still differ from resting. Setting both
10
- // paths to the same lifted value removes that ambiguity outright.
7
+ // Both `_checked._hover` and `_hover._checked` paths get the same lifted value.
11
8
  const hoverChecked = resolveHoverTint(palette[600], palette[600]);
9
+ const checkedIcon = onFilled(palette[600], theme.colors.white, theme.colors.black);
10
+ const hoverCheckedIcon = onFilled(hoverChecked, theme.colors.white, theme.colors.black);
11
+ const focusRing = liftToContrast(palette[300], theme.colors.backgroundColor.main, AA_NON_TEXT);
12
12
  return {
13
13
  control: {
14
14
  width: "1.25rem",
@@ -51,7 +51,7 @@ export const Checkbox = {
51
51
  },
52
52
  },
53
53
  _focus: {
54
- boxShadow: `0 0 0 2px ${palette[300]}`,
54
+ boxShadow: `0 0 0 2px ${focusRing}`,
55
55
  borderColor: palette[500],
56
56
  },
57
57
  _active: {
@@ -60,7 +60,10 @@ export const Checkbox = {
60
60
  },
61
61
  },
62
62
  icon: {
63
- color: theme.colors.background[50],
63
+ color: checkedIcon,
64
+ _hover: {
65
+ color: hoverCheckedIcon,
66
+ },
64
67
  },
65
68
  };
66
69
  },
@@ -3,7 +3,8 @@ import { useEffect, useRef, useState } from "react";
3
3
  import { Box, Flex, IconButton, Text } from "@chakra-ui/react";
4
4
  import { Check, Copy } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
- import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
6
+ import { accentTextOnCanvas, AA_NORMAL_TEXT } from "../../Theme/tokens/builders/accentText.js";
7
+ import { liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
7
8
  import ToolTip from "../ToolTip/ToolTip.js";
8
9
  const CopyButton = ({ value, variant = "icon", label = "Copy", copiedLabel = "Copied!", tooltip = "Copy", feedbackDuration = 1500, iconSize = 16, size = "sm", onCopy, }) => {
9
10
  const theme = useCustomTheme();
@@ -29,7 +30,10 @@ const CopyButton = ({ value, variant = "icon", label = "Copy", copiedLabel = "Co
29
30
  const accent = accentTextOnCanvas(theme.colors.primary, theme.colors.backgroundColor.main);
30
31
  const success = theme.colors.semanticText.success;
31
32
  if (variant === "menu-item") {
32
- return (_jsxs(Flex, { align: "center", gap: "0.5rem", px: "12px", py: "8px", width: "100%", cursor: "pointer", borderRadius: "md", transition: "background 0.15s ease", _hover: { bg: theme.colors.gray[100] }, onClick: handleCopy, children: [copied ? _jsx(Check, { size: iconSize, color: success }) : _jsx(Copy, { size: iconSize, color: accent }), _jsx(Box, { fontSize: "14px", fontWeight: 500, color: copied ? success : accent, children: copied ? copiedLabel : label })] }));
33
+ // Ink also sits on the row's own hover fill (gray[100]), not just the canvas resolve against it.
34
+ const hoverAccent = accentTextOnCanvas(theme.colors.primary, theme.colors.gray[100]);
35
+ const hoverSuccess = liftToContrast(theme.colors.semantic.success[500], theme.colors.gray[100], AA_NORMAL_TEXT);
36
+ return (_jsxs(Flex, { align: "center", gap: "0.5rem", px: "12px", py: "8px", width: "100%", cursor: "pointer", borderRadius: "md", transition: "background 0.15s ease", _hover: { bg: theme.colors.gray[100] }, onClick: handleCopy, children: [copied ? (_jsx(Check, { size: iconSize, color: hoverSuccess })) : (_jsx(Copy, { size: iconSize, color: hoverAccent })), _jsx(Box, { fontSize: "14px", fontWeight: 500, color: copied ? hoverSuccess : hoverAccent, children: copied ? copiedLabel : label })] }));
33
37
  }
34
38
  if (variant === "button") {
35
39
  return (_jsxs(Flex, { as: "button", align: "center", gap: "6px", px: "12px", py: "6px", borderRadius: "lg", border: "1px solid",
@@ -4,6 +4,7 @@ import { Box, Flex, Button, useDisclosure, List, ListItem, Portal, } from "@chak
4
4
  import { motion } from "framer-motion";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { scrollbarStyles } from "../../Theme/tokens/builders/scrollbar.js";
7
+ import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
7
8
  import { ChevronDown } from "lucide-react";
8
9
  import { rafThrottle } from "../../Utils/rafThrottle.js";
9
10
  const MotionBox = motion(forwardRef((props, ref) => (_jsx(Box, { ref: ref, ...props }))));
@@ -212,16 +213,17 @@ const Dropdown = forwardRef(({ dropDownButtonStyle, ButtonText, options, handleO
212
213
  };
213
214
  const DropdownContentRender = () => {
214
215
  var _a;
216
+ const hoverTint = resolveHoverTint(theme.colors.primary[500], theme.colors.background[50]);
215
217
  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) => {
216
218
  itemRefs.current[index] = node;
217
219
  }, role: "menuitem", tabIndex: index === activeIndex ? 0 : -1, onClick: () => {
218
220
  handleListItemClick(option.id, option.label);
219
221
  focusTrigger();
220
222
  }, onKeyDown: (e) => handleItemKeyDown(e, option.id, option.label), mx: 1.5, px: s.px, py: s.py, borderRadius: "md", display: "flex", alignItems: "center", gap: 2, cursor: "pointer", color: theme.colors.text[700], transition: "background 0.12s ease, color 0.12s ease", _hover: {
221
- bg: theme.colors.primary.opacity[8],
223
+ bg: hoverTint,
222
224
  color: theme.colors.accentText,
223
225
  }, _focus: {
224
- bg: theme.colors.primary.opacity[8],
226
+ bg: hoverTint,
225
227
  color: theme.colors.accentText,
226
228
  }, borderBottom: divider
227
229
  ? `0.063rem solid ${theme.colors.boxborder[200]}`
@@ -3,6 +3,7 @@ import { Box, Flex, Image, Text } from "@chakra-ui/react";
3
3
  import { Inbox } from "lucide-react";
4
4
  import { keyframes } from "@emotion/react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
6
7
  const float = keyframes `
7
8
  0%, 100% { transform: translateY(0); }
8
9
  50% { transform: translateY(-8px); }
@@ -21,8 +22,8 @@ const EmptyState = ({ title = "No data found", description, icon: IconComp = Inb
21
22
  const theme = useCustomTheme();
22
23
  const s = sizeMap[size];
23
24
  const palette = scaleFor(theme.colors, colorScheme);
24
- const accent = palette[500];
25
25
  const accentSoft = palette[50];
26
+ const accent = accentTextOnCanvas(palette, accentSoft);
26
27
  const containerStyles = variant === "subtle"
27
28
  ? { bg: theme.colors.gray[50], borderRadius: "2xl" }
28
29
  : variant === "dashed"
@@ -57,7 +57,7 @@ const FileUpload = ({ onFilesUploaded, uploadedFiles, onRemoveFile, acceptTypes
57
57
  return (_jsxs(_Fragment, { children: [_jsxs(VStack, { spacing: 4, align: "stretch", children: [_jsxs(Box, { ...getRootProps(), border: "2px dashed", borderColor: border, borderRadius: "md", p: compact ? 3 : 10, textAlign: "center", bg: bg, cursor: "pointer", transition: "all 0.2s", _hover: { bg: colors.gray[100] }, position: "relative", children: [_jsx("input", { ...getInputProps({ "aria-label": inputAriaLabel }) }), _jsxs(Stack, { direction: compact ? "row" : "column", spacing: compact ? 3 : 2, align: "center", justify: "center", children: [_jsx(Icon, { as: Upload, boxSize: compact ? 4 : 6 }), _jsxs(Stack, { spacing: 0, align: compact ? "start" : "center", children: [_jsx(Text, { fontWeight: "medium", fontSize: compact ? "sm" : "md", color: colors.textMuted, children: "Drag and drop files here" }), _jsxs(Text, { fontSize: compact ? "xs" : "sm", color: colors.textMuted, children: [acceptTypes.join(", "), " up to ", toMB(maxSizeKB), " ", maxFiles ? `- ${maxFiles} file(s) max` : ""] })] })] })] }), errors.length > 0 && (_jsx(Box, { children: errors.map((err, idx) => (_jsx(Text, { fontSize: "sm", color: colors.semanticText.error, children: err }, idx))) })), uploadedFiles.length > 0 && (_jsxs(Box, { children: [_jsx(Box, { display: "flex", alignItems: "center", gap: 2, children: _jsx(Text, { fontFamily: "open-sans, sans-serif", fontWeight: 600, fontSize: 14, lineHeight: "100%", letterSpacing: "4%", textTransform: "uppercase", py: 4, children: "Uploaded Files" }) }), _jsx(List, { spacing: 2, children: uploadedFiles.map((file, index) => (_jsxs(Box, { borderWidth: "0.063rem", borderRadius: "md", px: 3, py: 2, bg: colors.background[50], children: [_jsxs(ListItem, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [_jsxs(HStack, { spacing: 3, flex: "1", children: [file.type.startsWith("image/") ? (_jsxs(Box, { boxSize: "2.5rem", cursor: "pointer", position: "relative", _hover: {
58
58
  ".hover-icon": {
59
59
  opacity: 1,
60
- bg: colors.secondary.opacity[16],
60
+ bg: "blackAlpha.500",
61
61
  },
62
62
  }, onClick: () => {
63
63
  setPreviewUrl(URL.createObjectURL(file));
@@ -68,7 +68,7 @@ const FileUpload = ({ onFilesUploaded, uploadedFiles, onRemoveFile, acceptTypes
68
68
  height: "100%",
69
69
  objectFit: "cover",
70
70
  borderRadius: radii.base,
71
- } }), _jsx(Box, { className: "hover-icon", position: "absolute", top: "0.5rem", left: "0.5rem", opacity: 0, children: _jsx(Eye, { color: colors.background[100] }) })] })) : (_jsx(ListIcon, { as: FileText, color: accentTextOnCanvas(colors.blue, colors.background[50]), boxSize: 8 })), _jsxs(VStack, { align: "start", spacing: 0, flex: "1", children: [_jsx(Text, { fontSize: "sm", noOfLines: 1, children: file.name }), _jsxs(Text, { fontSize: "xs", color: colors.textMuted, children: [toMB(file.size / 1024), " \u2022", " ", file.type || "Unknown type"] })] })] }), onRemoveFile && (_jsx(CloseButton, { onClick: () => onRemoveFile(file), size: "sm", color: colors.semanticText.error }))] }), (progress === null || progress === void 0 ? void 0 : progress[file.name]) !== undefined && (_jsx(Progress, { value: progress === null || progress === void 0 ? void 0 : progress[file.name], size: "xs", mt: 1, hasStripe: (progress === null || progress === void 0 ? void 0 : progress[file.name]) < 100, isAnimated: (progress === null || progress === void 0 ? void 0 : progress[file.name]) < 100, colorScheme: (progress === null || progress === void 0 ? void 0 : progress[file.name]) >= 100 ? "green" : "blue", borderRadius: "md" }))] }, index))) })] }))] }), _jsxs(Modal, { isOpen: isOpen, onClose: () => {
71
+ } }), _jsx(Box, { className: "hover-icon", position: "absolute", top: "0.5rem", left: "0.5rem", opacity: 0, children: _jsx(Eye, { color: "white" }) })] })) : (_jsx(ListIcon, { as: FileText, color: accentTextOnCanvas(colors.blue, colors.background[50]), boxSize: 8 })), _jsxs(VStack, { align: "start", spacing: 0, flex: "1", children: [_jsx(Text, { fontSize: "sm", noOfLines: 1, children: file.name }), _jsxs(Text, { fontSize: "xs", color: colors.textMuted, children: [toMB(file.size / 1024), " \u2022", " ", file.type || "Unknown type"] })] })] }), onRemoveFile && (_jsx(CloseButton, { onClick: () => onRemoveFile(file), size: "sm", color: colors.semanticText.error }))] }), (progress === null || progress === void 0 ? void 0 : progress[file.name]) !== undefined && (_jsx(Progress, { value: progress === null || progress === void 0 ? void 0 : progress[file.name], size: "xs", mt: 1, hasStripe: (progress === null || progress === void 0 ? void 0 : progress[file.name]) < 100, isAnimated: (progress === null || progress === void 0 ? void 0 : progress[file.name]) < 100, colorScheme: (progress === null || progress === void 0 ? void 0 : progress[file.name]) >= 100 ? "green" : "blue", borderRadius: "md" }))] }, index))) })] }))] }), _jsxs(Modal, { isOpen: isOpen, onClose: () => {
72
72
  onClose();
73
73
  setPreviewUrl(null);
74
74
  setPreviewTitle(null);
@@ -1,10 +1,4 @@
1
- /**
2
- * FilterSidebar's hover fill for option rows, popover list items, and the accordion trigger.
3
- * `gray[50]` (a pale near-white tint in light mode) sits within ~1 lightness point of the
4
- * dark-mode canvas once the whole scale flips (~1.08:1 contrast) invisible, the QA-reported
5
- * "checkbox hover invisible" bug. `gray[300]` clears the resting canvas (~2.3:1, a clear visible
6
- * cue) while staying dark enough that the existing `gray[700]`/`gray[800]` row text (tuned for a
7
- * near-black canvas) still reads at/above AA (~4.9:1+) on top of it — no text-color flip needed
8
- * here, unlike the Table row hover fix.
9
- */
10
- export const getFilterHoverBg = (colors, isDark) => isDark ? colors.gray[300] : colors.gray[50];
1
+ import { liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
2
+ import { AA_NORMAL_TEXT } from "../../Theme/tokens/builders/accentText.js";
3
+ // The fill itself must clear AA against `text[500]`, the only ink these rows ever use.
4
+ export const getFilterHoverBg = (colors, isDark) => isDark ? liftToContrast(colors.gray[300], colors.text[500], AA_NORMAL_TEXT) : colors.gray[50];
@@ -2,7 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Stack, Button, Badge, Text, VStack, Collapse, HStack, } from "@chakra-ui/react";
3
3
  import React from "react";
4
4
  import { ChevronDown, ChevronRight } from "lucide-react";
5
+ import { useCustomTheme } from "../../../Theme/useCustomTheme.js";
6
+ import { onFilled } from "../../../Theme/tokens/builders/accentText.js";
5
7
  const MobileMenu = ({ menuItems, isOpen, isActive, hoverBg, activeBg, color, rightSlot, onClose, }) => {
8
+ const { colors } = useCustomTheme();
6
9
  const [openMenuLabel, setOpenMenuLabel] = React.useState(null);
7
10
  React.useEffect(() => {
8
11
  if (!isOpen)
@@ -10,7 +13,9 @@ const MobileMenu = ({ menuItems, isOpen, isActive, hoverBg, activeBg, color, rig
10
13
  }, [isOpen]);
11
14
  return (_jsx(Collapse, { in: isOpen, animateOpacity: true, children: _jsx(Box, { pb: 4, display: { md: "none" }, children: _jsxs(Stack, { spacing: 4, children: [menuItems.map((item) => {
12
15
  var _a, _b, _c, _d, _e;
13
- return item.children ? (_jsxs(Box, { px: 2, children: [_jsx(Button, { onClick: () => setOpenMenuLabel((prev) => (prev === item.label ? null : item.label)), variant: "ghost", w: "full", justifyContent: "flex-start", color: color, bg: item.children.some((subItem) => isActive(subItem.href))
16
+ return item.children ? (_jsxs(Box, { px: 2, children: [_jsx(Button, { onClick: () => setOpenMenuLabel((prev) => (prev === item.label ? null : item.label)), variant: "ghost", w: "full", justifyContent: "flex-start", color: item.children.some((subItem) => isActive(subItem.href))
17
+ ? onFilled(activeBg, colors.white, colors.black)
18
+ : color, bg: item.children.some((subItem) => isActive(subItem.href))
14
19
  ? activeBg
15
20
  : "transparent", _hover: { bg: hoverBg }, rightIcon: openMenuLabel === item.label ? (_jsx(ChevronDown, { size: 16 })) : (_jsx(ChevronRight, { size: 16 })), px: 2, children: _jsx(HStack, { w: "full", justify: "space-between", align: "center", children: _jsxs(VStack, { spacing: 0, align: "start", children: [item.badge && (_jsx(Badge, { colorScheme: (_b = (_a = item === null || item === void 0 ? void 0 : item.badge) === null || _a === void 0 ? void 0 : _a.colorScheme) !== null && _b !== void 0 ? _b : "blue", variant: "subtle", fontSize: "0.65em", borderRadius: "md", boxShadow: "sm", px: 2, py: 0.5, children: item.badge.label })), _jsx(Text, { fontWeight: "bold", children: item.label })] }) }) }), _jsx(Collapse, { in: openMenuLabel === item.label, animateOpacity: true, children: _jsx(Stack, { pl: 4, mt: 1, spacing: 1, children: item.children.map((subItem) => {
16
21
  var _a, _b, _c;
@@ -18,8 +23,12 @@ const MobileMenu = ({ menuItems, isOpen, isActive, hoverBg, activeBg, color, rig
18
23
  var _a;
19
24
  (_a = subItem.onClick) === null || _a === void 0 ? void 0 : _a.call(subItem);
20
25
  onClose === null || onClose === void 0 ? void 0 : onClose();
21
- }, variant: "ghost", w: "full", justifyContent: "flex-start", color: color, bg: isActive(subItem.href) ? activeBg : "transparent", _hover: { bg: hoverBg }, children: _jsxs(VStack, { spacing: 0, align: "start", children: [subItem.badge && (_jsx(Badge, { colorScheme: (_b = (_a = subItem === null || subItem === void 0 ? void 0 : subItem.badge) === null || _a === void 0 ? void 0 : _a.colorScheme) !== null && _b !== void 0 ? _b : "blue", variant: "subtle", fontSize: "0.65em", borderRadius: "md", boxShadow: "sm", px: 2, py: 0.5, children: (_c = subItem.badge) === null || _c === void 0 ? void 0 : _c.label })), _jsxs(HStack, { spacing: 2, align: "center", children: [_jsx(Box, { boxSize: "0.4rem", borderRadius: "full", bg: "currentColor" }), _jsx(Text, { fontSize: "sm", children: subItem.label })] })] }) }, subItem.label));
22
- }) }) })] }, item.label)) : (_jsx(Button, { onClick: () => { var _a; (_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item); onClose === null || onClose === void 0 ? void 0 : onClose(); }, variant: "ghost", w: "full", justifyContent: "flex-start", color: color, bg: isActive(item.href) ? activeBg : "transparent", _hover: { bg: hoverBg }, children: _jsxs(VStack, { spacing: 0, align: "start", children: [item.badge && (_jsx(Badge, { colorScheme: (_d = (_c = item === null || item === void 0 ? void 0 : item.badge) === null || _c === void 0 ? void 0 : _c.colorScheme) !== null && _d !== void 0 ? _d : "blue", variant: "subtle", fontSize: "0.65em", borderRadius: "md", boxShadow: "sm", px: 2, py: 0.5, children: (_e = item.badge) === null || _e === void 0 ? void 0 : _e.label })), _jsx(Text, { children: item.label })] }) }, item.label));
26
+ }, variant: "ghost", w: "full", justifyContent: "flex-start", color: isActive(subItem.href)
27
+ ? onFilled(activeBg, colors.white, colors.black)
28
+ : color, bg: isActive(subItem.href) ? activeBg : "transparent", _hover: { bg: hoverBg }, children: _jsxs(VStack, { spacing: 0, align: "start", children: [subItem.badge && (_jsx(Badge, { colorScheme: (_b = (_a = subItem === null || subItem === void 0 ? void 0 : subItem.badge) === null || _a === void 0 ? void 0 : _a.colorScheme) !== null && _b !== void 0 ? _b : "blue", variant: "subtle", fontSize: "0.65em", borderRadius: "md", boxShadow: "sm", px: 2, py: 0.5, children: (_c = subItem.badge) === null || _c === void 0 ? void 0 : _c.label })), _jsxs(HStack, { spacing: 2, align: "center", children: [_jsx(Box, { boxSize: "0.4rem", borderRadius: "full", bg: "currentColor" }), _jsx(Text, { fontSize: "sm", children: subItem.label })] })] }) }, subItem.label));
29
+ }) }) })] }, item.label)) : (_jsx(Button, { onClick: () => { var _a; (_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item); onClose === null || onClose === void 0 ? void 0 : onClose(); }, variant: "ghost", w: "full", justifyContent: "flex-start", color: isActive(item.href)
30
+ ? onFilled(activeBg, colors.white, colors.black)
31
+ : color, bg: isActive(item.href) ? activeBg : "transparent", _hover: { bg: hoverBg }, children: _jsxs(VStack, { spacing: 0, align: "start", children: [item.badge && (_jsx(Badge, { colorScheme: (_d = (_c = item === null || item === void 0 ? void 0 : item.badge) === null || _c === void 0 ? void 0 : _c.colorScheme) !== null && _d !== void 0 ? _d : "blue", variant: "subtle", fontSize: "0.65em", borderRadius: "md", boxShadow: "sm", px: 2, py: 0.5, children: (_e = item.badge) === null || _e === void 0 ? void 0 : _e.label })), _jsx(Text, { children: item.label })] }) }, item.label));
23
32
  }), rightSlot && _jsx(Box, { mt: 4, children: rightSlot })] }) }) }));
24
33
  };
25
34
  export default MobileMenu;
@@ -1,20 +1,21 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
2
3
  import { Box, Center, Spinner, Text } from "@chakra-ui/react";
3
4
  import { css, keyframes } from "@emotion/react";
4
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
- const colorTransition = keyframes `
6
- 0% {
7
- color: black;
8
- }
9
- 50% {
10
- color: gray;
11
- }
12
- 100% {
13
- color: black;
14
- }
15
- `;
16
6
  export default function Loading({ text, isLoading, onlytext, container }) {
17
7
  const theme = useCustomTheme();
8
+ const colorTransition = useMemo(() => keyframes `
9
+ 0% {
10
+ color: ${theme.colors.text[900]};
11
+ }
12
+ 50% {
13
+ color: ${theme.colors.textMuted};
14
+ }
15
+ 100% {
16
+ color: ${theme.colors.text[900]};
17
+ }
18
+ `, [theme.colors.text, theme.colors.textMuted]);
18
19
  if (!isLoading) {
19
20
  return null;
20
21
  }
@@ -4,6 +4,7 @@ import { Box, Flex, Text, Input, Textarea, Button, Divider, Spinner, Tooltip, }
4
4
  import { Paperclip, X, SquarePen, File as FileIcon } from "lucide-react";
5
5
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
6
  import { placeholderInk } from "../../Theme/tokens/builders/placeholderInk.js";
7
+ import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
7
8
  import { FIELD_RADIUS } from "../Common/fieldStyles.js";
8
9
  const countWords = (text = "") => {
9
10
  const t = text.trim();
@@ -115,7 +116,9 @@ export default function NoteTextArea({ width = "100%", handleSubmit, handleCance
115
116
  };
116
117
  const noteWordCount = countWords(noteValue);
117
118
  const isOverLimit = noteWordCount > maxNoteWordCount;
118
- return (_jsxs(Box, { w: width, borderRadius: FIELD_RADIUS, overflow: "hidden", border: "1px solid", borderColor: isActive ? theme.colors.primary[500] : theme.colors.boxborder[500], bg: isActive ? theme.colors.gray[50] : theme.colors.background[50], transition: "border-color 0.2s", children: [!isActive && (_jsxs(Flex, { px: 3, gap: 2, align: "center", cursor: "text", onClick: handleTextArea, bg: theme.colors.background[50], borderRadius: FIELD_RADIUS, minH: "2.5rem", transition: "background 0.15s", _hover: { bg: theme.colors.gray[50] }, children: [_jsx(SquarePen, { size: 16, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: customPlaceholder })] })), isActive && (_jsxs(_Fragment, { children: [_jsxs(Box, { bg: theme.colors.background[50], children: [titleShow && (_jsxs(_Fragment, { children: [_jsx(Input, { ref: inputRef, value: titleValue, onChange: (e) => {
119
+ const collapsedHoverBg = resolveHoverTint(theme.colors.gray[50], theme.colors.background[50]);
120
+ const activeControlHoverBg = resolveHoverTint(theme.colors.gray[100], theme.colors.gray[50]);
121
+ return (_jsxs(Box, { w: width, borderRadius: FIELD_RADIUS, overflow: "hidden", border: "1px solid", borderColor: isActive ? theme.colors.primary[500] : theme.colors.boxborder[500], bg: isActive ? theme.colors.gray[50] : theme.colors.background[50], transition: "border-color 0.2s", children: [!isActive && (_jsxs(Flex, { px: 3, gap: 2, align: "center", cursor: "text", onClick: handleTextArea, bg: theme.colors.background[50], borderRadius: FIELD_RADIUS, minH: "2.5rem", transition: "background 0.15s", _hover: { bg: collapsedHoverBg }, children: [_jsx(SquarePen, { size: 16, color: theme.colors.textMuted }), _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", children: customPlaceholder })] })), isActive && (_jsxs(_Fragment, { children: [_jsxs(Box, { bg: theme.colors.background[50], children: [titleShow && (_jsxs(_Fragment, { children: [_jsx(Input, { ref: inputRef, value: titleValue, onChange: (e) => {
119
122
  if (e.target.value.length === 0)
120
123
  setTitleShow(false);
121
124
  setTitleValue(e.target.value);
@@ -123,7 +126,7 @@ export default function NoteTextArea({ width = "100%", handleSubmit, handleCance
123
126
  color: placeholderInk(theme.colors),
124
127
  } }), _jsx(Divider, { borderColor: theme.colors.gray[200] })] })), _jsx(Box, { bg: theme.colors.background[50], minH: "76px", px: 3, pt: 2.5, position: "relative", children: _jsx(Textarea, { ref: noteAreaRef, value: noteValue, onChange: handleNoteChange, placeholder: customPlaceholder, variant: "unstyled", resize: "none", minH: "76px", fontSize: "0.75rem", color: theme.colors.text[700], _placeholder: {
125
128
  color: placeholderInk(theme.colors),
126
- }, style: { overflow: "hidden" }, p: 0 }) })] }), _jsx(Divider, { borderColor: theme.colors.gray[200] }), _jsxs(Box, { px: 3, py: 2.5, children: [_jsxs(Flex, { align: "center", justify: "space-between", w: "100%", gap: 3, children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(Tooltip, { label: "Attach files", hasArrow: true, placement: "top", children: _jsx(Box, { as: "label", htmlFor: "file-upload", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", w: "1.75rem", h: "1.75rem", borderRadius: "md", color: theme.colors.textMuted, transition: "background 0.15s", _hover: { bg: theme.colors.gray[100] }, children: _jsx(Paperclip, { size: 16 }) }) }), _jsx(Box, { h: "1rem", w: "1px", bg: theme.colors.gray[200] }), !titleShow ? (_jsx(Box, { as: "button", type: "button", onClick: () => setTitleShow(true), px: 2, py: 1, borderRadius: "md", color: theme.colors.textMuted, fontWeight: 500, fontSize: "sm", transition: "background 0.15s", _hover: { bg: theme.colors.gray[100] }, children: "+ Add a title" })) : (_jsx(Tooltip, { label: titleValue, hasArrow: true, isDisabled: !titleValue, children: _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", fontWeight: 500, isTruncated: true, maxW: "180px", children: titleValue || "Title" }) }))] }), _jsxs(Flex, { gap: 2.5, align: "center", ml: "auto", flexShrink: 0, children: [_jsxs(Text, { fontSize: "xs", fontWeight: 500, color: isOverLimit ? theme.colors.semanticText.error : theme.colors.textMuted, whiteSpace: "nowrap", children: [noteWordCount, "/", maxNoteWordCount] }), cancelButtonHide ? null : (_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleCloseTextArea, children: "Cancel" })), _jsxs(Button, { size: "sm", variant: "solid", isLoading: !!saveButtonLoading, isDisabled: !noteValue || isSaveDisabled, onClick: () => handleSubmit(noteValue, titleValue, files), children: [saveButtonLoading ? (_jsx(Spinner, { size: "xs", thickness: "2px", mr: 2 })) : null, "Save"] })] })] }), _jsx("input", { id: "file-upload", type: "file", style: { display: "none" }, onChange: (e) => {
129
+ }, style: { overflow: "hidden" }, p: 0 }) })] }), _jsx(Divider, { borderColor: theme.colors.gray[200] }), _jsxs(Box, { px: 3, py: 2.5, children: [_jsxs(Flex, { align: "center", justify: "space-between", w: "100%", gap: 3, children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(Tooltip, { label: "Attach files", hasArrow: true, placement: "top", children: _jsx(Box, { as: "label", htmlFor: "file-upload", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", w: "1.75rem", h: "1.75rem", borderRadius: "md", color: theme.colors.textMuted, transition: "background 0.15s", _hover: { bg: activeControlHoverBg }, children: _jsx(Paperclip, { size: 16 }) }) }), _jsx(Box, { h: "1rem", w: "1px", bg: theme.colors.gray[200] }), !titleShow ? (_jsx(Box, { as: "button", type: "button", onClick: () => setTitleShow(true), px: 2, py: 1, borderRadius: "md", color: theme.colors.textMuted, fontWeight: 500, fontSize: "sm", transition: "background 0.15s", _hover: { bg: activeControlHoverBg }, children: "+ Add a title" })) : (_jsx(Tooltip, { label: titleValue, hasArrow: true, isDisabled: !titleValue, children: _jsx(Text, { color: theme.colors.textMuted, fontSize: "sm", fontWeight: 500, isTruncated: true, maxW: "180px", children: titleValue || "Title" }) }))] }), _jsxs(Flex, { gap: 2.5, align: "center", ml: "auto", flexShrink: 0, children: [_jsxs(Text, { fontSize: "xs", fontWeight: 500, color: isOverLimit ? theme.colors.semanticText.error : theme.colors.textMuted, whiteSpace: "nowrap", children: [noteWordCount, "/", maxNoteWordCount] }), cancelButtonHide ? null : (_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleCloseTextArea, children: "Cancel" })), _jsxs(Button, { size: "sm", variant: "solid", isLoading: !!saveButtonLoading, isDisabled: !noteValue || isSaveDisabled, onClick: () => handleSubmit(noteValue, titleValue, files), children: [saveButtonLoading ? (_jsx(Spinner, { size: "xs", thickness: "2px", mr: 2 })) : null, "Save"] })] })] }), _jsx("input", { id: "file-upload", type: "file", style: { display: "none" }, onChange: (e) => {
127
130
  const newFiles = Array.from(e.target.files || []);
128
131
  const validFiles = newFiles.filter((f) => f.size <= maxFileSize);
129
132
  const invalidFiles = newFiles.filter((f) => f.size > maxFileSize);
@@ -2,9 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Flex, Text } from "@chakra-ui/react";
3
3
  import { Download, ExternalLink, FileText } from "lucide-react";
4
4
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ import { accentTextOnCanvas } from "../../Theme/tokens/builders/accentText.js";
6
+ import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
5
7
  import ToolTip from "../ToolTip/ToolTip.js";
6
8
  const PdfViewer = ({ pdfUrl, fileName = "Document.pdf", height = "480px", showToolbar = true, borderRadius = "xl", }) => {
7
9
  const theme = useCustomTheme();
8
- return (_jsxs(Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], children: [showToolbar && (_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.gray[50], children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(FileText, { size: 18, color: theme.colors.accentText }), _jsx(Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), _jsxs(Flex, { align: "center", gap: 1, children: [_jsx(ToolTip, { label: "Open in new tab", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: theme.colors.primary[50], color: theme.colors.primary[500] }, children: _jsx(ExternalLink, { size: 16 }) }) }), _jsx(ToolTip, { label: "Download", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, download: fileName, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: theme.colors.primary[50], color: theme.colors.primary[500] }, children: _jsx(Download, { size: 16 }) }) })] })] })), _jsx(Box, { as: "embed", src: pdfUrl, type: "application/pdf", width: "100%", height: height, display: "block" })] }));
10
+ const toolbarSurface = theme.colors.gray[50];
11
+ const iconHoverInk = accentTextOnCanvas(theme.colors.primary, toolbarSurface);
12
+ const iconHoverBg = resolveHoverTint(theme.colors.primary[50], toolbarSurface);
13
+ return (_jsxs(Box, { border: "1px solid", borderColor: theme.colors.gray[200], borderRadius: borderRadius, overflow: "hidden", bg: theme.colors.background[50], children: [showToolbar && (_jsxs(Flex, { align: "center", justify: "space-between", px: 4, py: 2.5, borderBottom: "1px solid", borderColor: theme.colors.gray[100], bg: theme.colors.gray[50], children: [_jsxs(Flex, { align: "center", gap: 2, minW: 0, children: [_jsx(FileText, { size: 18, color: theme.colors.accentText }), _jsx(Text, { fontSize: "sm", fontWeight: 500, color: theme.colors.gray[700], overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName })] }), _jsxs(Flex, { align: "center", gap: 1, children: [_jsx(ToolTip, { label: "Open in new tab", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, target: "_blank", rel: "noopener noreferrer", p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(ExternalLink, { size: 16 }) }) }), _jsx(ToolTip, { label: "Download", placement: "top", children: _jsx(Box, { as: "a", href: pdfUrl, download: fileName, p: 2, borderRadius: "lg", color: theme.colors.gray[600], _hover: { bg: iconHoverBg, color: iconHoverInk }, children: _jsx(Download, { size: 16 }) }) })] })] })), _jsx(Box, { as: "embed", src: pdfUrl, type: "application/pdf", width: "100%", height: height, display: "block" })] }));
9
14
  };
10
15
  export default PdfViewer;
@@ -3,6 +3,8 @@ import { Box, Flex, Text, Icon } from '@chakra-ui/react';
3
3
  import { BookCheck, Star } from 'lucide-react';
4
4
  import { useCustomTheme } from '../../Theme/useCustomTheme.js';
5
5
  import { accentTextOnCanvas } from '../../Theme/tokens/builders/accentText.js';
6
+ import { contrastRatio } from '../../Theme/tokens/builders/color.js';
7
+ import { AA_NON_TEXT } from '../../Theme/tokens/builders/outlineRung.js';
6
8
  // The theme's `yellow` scale reverses index roles in dark mode (like every utility hue), so
7
9
  // pulling it through the theme would silently flip this decorative "filled star" from gold to
8
10
  // pale. A rating star is a universal, brand-independent gold — not something that should follow
@@ -17,6 +19,9 @@ const ProductReview = ({ rating, reviewCount, mb = 0 }) => {
17
19
  // Calculate fill percentage: (rating / 5) * 100%
18
20
  const numericRating = hasRating ? Math.min(Math.max(Number(rating), 0), 5) : 0;
19
21
  const fillPercentage = (numericRating / 6) * 100;
20
- return (_jsxs(Flex, { align: "center", gap: 2, mb: mb, children: [hasRating && (_jsxs(Flex, { align: "center", gap: 1, bg: colors.teal[50], color: accentTextOnCanvas(colors.teal, colors.teal[50]), px: 2, borderRadius: "md", children: [_jsxs(Box, { position: "relative", flexShrink: 0, display: "inline-block", width: "14px", height: "14px", lineHeight: 0, children: [_jsx(Box, { position: "absolute", top: 0, left: 0, width: "14px", height: "14px", children: _jsx(Star, { size: 14, fill: "none", strokeWidth: 1.5 }) }), fillPercentage > 0 && (_jsx(Box, { position: "absolute", top: 0, left: 0, width: `${fillPercentage}%`, height: "100%", overflow: "hidden", children: _jsx(Star, { size: 14, color: RATING_STAR_FILL, fill: RATING_STAR_FILL }) }))] }), _jsx(Text, { fontSize: "sm", fontWeight: "bold", children: numericRating })] })), hasRating && hasReviewCount && _jsx(Box, { h: "4", w: "0.063rem", bg: colors.boxborder[500] }), hasReviewCount && (_jsxs(Flex, { align: "center", gap: "1", children: [_jsx(Icon, { as: BookCheck, boxSize: 3.5 }), _jsxs(Text, { fontSize: "sm", color: colors.textMuted, children: ["(", reviewCount, ")"] })] }))] }));
22
+ const chipBg = colors.teal[50];
23
+ const chipInk = accentTextOnCanvas(colors.teal, chipBg);
24
+ const starFill = contrastRatio(RATING_STAR_FILL, chipBg) >= AA_NON_TEXT ? RATING_STAR_FILL : chipInk;
25
+ return (_jsxs(Flex, { align: "center", gap: 2, mb: mb, children: [hasRating && (_jsxs(Flex, { align: "center", gap: 1, bg: chipBg, color: chipInk, px: 2, borderRadius: "md", children: [_jsxs(Box, { position: "relative", flexShrink: 0, display: "inline-block", width: "14px", height: "14px", lineHeight: 0, children: [_jsx(Box, { position: "absolute", top: 0, left: 0, width: "14px", height: "14px", children: _jsx(Star, { size: 14, fill: "none", strokeWidth: 1.5 }) }), fillPercentage > 0 && (_jsx(Box, { position: "absolute", top: 0, left: 0, width: `${fillPercentage}%`, height: "100%", overflow: "hidden", children: _jsx(Star, { size: 14, color: starFill, fill: starFill }) }))] }), _jsx(Text, { fontSize: "sm", fontWeight: "bold", children: numericRating })] })), hasRating && hasReviewCount && _jsx(Box, { h: "4", w: "0.063rem", bg: colors.boxborder[500] }), hasReviewCount && (_jsxs(Flex, { align: "center", gap: "1", children: [_jsx(Icon, { as: BookCheck, boxSize: 3.5 }), _jsxs(Text, { fontSize: "sm", color: colors.textMuted, children: ["(", reviewCount, ")"] })] }))] }));
21
26
  };
22
27
  export default ProductReview;
@@ -20,8 +20,8 @@ const ProductTags = ({ tags, className, size = 'sm' }) => {
20
20
  };
21
21
  const Tag = ({ children, fullWidth = false, size = 'sm', }) => {
22
22
  const { colors } = useCustomTheme();
23
- const tagBorder = colors.semanticText.error;
24
23
  const tagText = colors.text[900];
24
+ const tagBorder = colors.boxborder[500];
25
25
  // Size map for tags
26
26
  const tagSizes = {
27
27
  xs: { fontSize: '0.625rem', px: '0.5rem', py: '0.125rem' },
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Radio as ChakraRadio, RadioGroup as ChakraRadioGroup, Stack, } from "@chakra-ui/react";
3
3
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
4
4
  import { TextLabel } from "../Common/FormLabel.js";
5
+ import { liftToContrast, AA_NON_TEXT } from "../../Theme/tokens/builders/outlineRung.js";
5
6
  const RadioButton = ({ label, colorScheme, isChecked, onChange, isDisabled, size, value, defaultChecked, labelFontSize = "0.75rem", labelClampLines = 2, showLabelTooltip = (label || "").length > 18, labelTooltip = label, }) => {
6
7
  const theme = useCustomTheme();
7
8
  return (_jsx(ChakraRadio, { colorScheme: colorScheme, isChecked: isChecked, onChange: onChange, isDisabled: isDisabled, size: size, value: value, defaultChecked: defaultChecked, borderColor: theme.colors.boxborder[500], borderWidth: "1.6px", _hover: {
@@ -15,7 +16,7 @@ const RadioButton = ({ label, colorScheme, isChecked, onChange, isDisabled, size
15
16
  "&[data-checked]:hover": {
16
17
  backgroundColor: theme.colors.primary[500],
17
18
  borderColor: theme.colors.primary[500],
18
- boxShadow: `0 0 0 2px ${theme.colors.primary[200]}`,
19
+ boxShadow: `0 0 0 2px ${liftToContrast(theme.colors.primary[200], theme.colors.backgroundColor.main, AA_NON_TEXT)}`,
19
20
  },
20
21
  }, children: _jsx(TextLabel, { label: label, fontSize: labelFontSize, showTooltip: showLabelTooltip, tooltipLabel: labelTooltip, clampLines: labelClampLines, inline: true }) }));
21
22
  };
@@ -5,6 +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
9
  const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300, duration = 600, useWindow = false, bottom = "2rem", right = "2rem", }) => {
9
10
  const [visible, setVisible] = useState(false);
10
11
  const anchorRef = useRef(null);
@@ -59,6 +60,7 @@ const ScrollToTop = ({ children, tooltipLabel = "Scroll to top", threshold = 300
59
60
  }, [useWindow, threshold]);
60
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
62
  bg: theme.colors.primary[600],
63
+ color: onFilled(theme.colors.primary[600], theme.colors.white, theme.colors.black),
62
64
  transform: "translateY(-2px) scale(1.05)",
63
65
  boxShadow: "lg",
64
66
  }, _active: { transform: "scale(0.95)" }, children: _jsx(ChevronUp, { size: 24, strokeWidth: 2.5 }) }) })] }));
@@ -6,6 +6,7 @@ import { TextLabel } from "../Common/FormLabel.js";
6
6
  import Tag from "../Tag/Tag.js";
7
7
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
8
8
  import { placeholderInk } from "../../Theme/tokens/builders/placeholderInk.js";
9
+ import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
9
10
  import ErrorMessage from "../Common/ErrorMessage.js";
10
11
  import HelperText from "../Common/HelperText.js";
11
12
  import ToolTip from "../ToolTip/ToolTip.js";
@@ -50,6 +51,9 @@ const SearchSelect = ({ id, label, options, onSelect, onSearch, isOptionLoading
50
51
  width: 0,
51
52
  });
52
53
  const theme = useCustomTheme();
54
+ const customSelectActiveTint = useMemo(() => resolveHoverTint(theme.colors.primary[500], theme.colors.background[400]), [theme.colors.primary, theme.colors.background]);
55
+ const dropdownActiveTint = useMemo(() => resolveHoverTint(theme.colors.primary[500], theme.colors.background[50]), [theme.colors.primary, theme.colors.background]);
56
+ const dropdownHoverTint = useMemo(() => resolveHoverTint(theme.colors.gray[50], theme.colors.background[50]), [theme.colors.gray, theme.colors.background]);
53
57
  // `searchselect-dropdown-portal` is also the DOM id an existing outside-click check and
54
58
  // several tests look up directly — kept as a literal constant, not derived from `baseId`,
55
59
  // so those keep working unchanged.
@@ -451,7 +455,7 @@ const SearchSelect = ({ id, label, options, onSelect, onSearch, isOptionLoading
451
455
  const insideLabel = (_a = insideSelect.value) === null || _a === void 0 ? void 0 : _a.label;
452
456
  const insidePlaceholder = (_b = insideSelect.placeholder) !== null && _b !== void 0 ? _b : "Select";
453
457
  return (_jsxs(Box, { position: "relative", ref: customSelectRef, flexShrink: 0, ml: s.insideSelectMarginLeft, h: "-webkit-fill-available", borderRight: "0.063rem solid", borderColor: theme.colors.boxborder[200], bg: customSelectOpen
454
- ? theme.colors.primary.opacity[8]
458
+ ? customSelectActiveTint
455
459
  : theme.colors.background[400], borderLeftRadius: "md", borderRightRadius: 0, transition: "background 0.15s ease, box-shadow 0.15s ease", boxShadow: customSelectOpen
456
460
  ? `inset 0 0 0 0.063rem ${theme.colors.primary[500]}`
457
461
  : "none", onClick: (e) => {
@@ -464,11 +468,11 @@ const SearchSelect = ({ id, label, options, onSelect, onSearch, isOptionLoading
464
468
  return (_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, minH: s.optionRowMinH, py: s.optionRowPy, px: "0.75rem", fontSize: s.dropdownTextFontSize, fontWeight: selected ? 600 : 500, color: selected
465
469
  ? theme.colors.accentText
466
470
  : theme.colors.text[700], bg: selected
467
- ? theme.colors.primary.opacity[8]
471
+ ? dropdownActiveTint
468
472
  : "transparent", _hover: {
469
473
  bg: selected
470
- ? theme.colors.primary.opacity[8]
471
- : theme.colors.gray[50],
474
+ ? dropdownActiveTint
475
+ : dropdownHoverTint,
472
476
  }, cursor: "pointer", onClick: (e) => {
473
477
  e.stopPropagation();
474
478
  handleCustomSelect(item);
@@ -508,9 +512,9 @@ const SearchSelect = ({ id, label, options, onSelect, onSearch, isOptionLoading
508
512
  return !prev;
509
513
  });
510
514
  }, "aria-label": "toggle-dropdown", display: "flex", alignItems: "center", children: isOpen ? (_jsx(ChevronUp, { size: s.chevronSize })) : (_jsx(ChevronDown, { size: s.chevronSize })) }))] })] }) }), isOpen && (_jsx(Portal, { children: _jsxs(Box, { ref: setDropdownMenuRef, id: listboxId, role: "listbox", "aria-multiselectable": isMultiple || undefined, position: "fixed", top: `${dropdownPos.top}px`, left: `${dropdownPos.left}px`, width: `${dropdownPos.width}px`, zIndex: 1500, maxH: "20rem", borderWidth: 1, borderColor: theme.colors.boxborder[200], borderRadius: "sm", bg: theme.colors.background[50], boxShadow: "md", display: "flex", flexDirection: "column", children: [isMultiple && isSelectAll && (_jsxs(Box, { py: s.optionRowPy, px: 3, cursor: "pointer", onClick: handleSelectAll, display: "flex", alignItems: "center", gap: 2, borderBottom: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [_jsx(Checkbox, { isChecked: allFilteredSelected, sx: { pointerEvents: "none" }, size: s.checkboxSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: allFilteredSelected ? "Unselect All" : "Select All" })] })), _jsx(Box, { flex: "1", overflowY: "auto", onScroll: handleScroll, maxH: "15rem", borderBottom: "0.063rem solid", borderColor: theme.colors.boxborder[200], children: isOptionLoading && filteredOptions.length === 0 ? (_jsxs(Box, { py: s.optionRowPy, px: 3, display: "flex", alignItems: "center", gap: 2, minH: s.optionRowMinH, children: [_jsx(Spinner, { size: s.spinnerSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: loadingText })] })) : !isOptionLoading && filteredOptions.length === 0 ? (_jsx(Text, { p: 3, fontSize: s.dropdownTextFontSize, color: theme.colors.textMuted, children: "No results found" })) : (_jsxs(_Fragment, { children: [filteredOptions.map((option, index) => (_jsxs(Box, { id: getOptionId(index), role: "option", "aria-selected": isSelected(option.id), py: s.optionRowPy, px: 3, minH: s.optionRowMinH, cursor: "pointer", bg: index === activeIndex
511
- ? theme.colors.primary.opacity[8]
515
+ ? dropdownActiveTint
512
516
  : isSelected(option.id)
513
517
  ? theme.colors.gray[100]
514
- : "transparent", _hover: { bg: theme.colors.gray[50] }, onClick: () => handleSelect(option), onMouseEnter: () => setActiveIndex(index), display: "flex", alignItems: "center", gap: 2, borderBottom: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [isMultiple && (_jsx(Checkbox, { isChecked: isSelected(option.id), sx: { pointerEvents: "none" }, size: s.checkboxSize })), option.view ? (_jsx(_Fragment, { children: option.view })) : (_jsx(Text, { fontSize: s.dropdownTextFontSize, children: option.label }))] }, option.id))), ((pagination === null || pagination === void 0 ? void 0 : pagination.scrollLoading) || (isOptionLoading && filteredOptions.length > 0)) && (_jsxs(Box, { py: s.optionRowPy, px: 3, display: "flex", alignItems: "center", justifyContent: "center", gap: 2, minH: s.optionRowMinH, children: [_jsx(Spinner, { size: s.spinnerSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: loadingText })] }))] })) }), (addNew === null || addNew === void 0 ? void 0 : addNew.enabled) && (_jsxs(Box, { py: s.optionRowPy, px: 3, borderTop: "0.063rem solid", borderColor: theme.colors.boxborder[200], bg: theme.colors.background[50], display: "flex", alignItems: "center", gap: 2, minH: s.optionRowMinH, cursor: "pointer", onClick: addNew.onClick, _hover: { bg: theme.colors.gray[50] }, children: [addNew.icon || _jsx(Plus, { size: s.addNewIconSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: addNew.text || "Add New" })] }))] }) })), helperText && !error && _jsx(HelperText, { helperText: helperText }), error && _jsx(ErrorMessage, { errorMessage: errorMessage })] }));
518
+ : "transparent", _hover: { bg: dropdownHoverTint }, onClick: () => handleSelect(option), onMouseEnter: () => setActiveIndex(index), display: "flex", alignItems: "center", gap: 2, borderBottom: `0.063rem solid ${theme.colors.boxborder[200]}`, children: [isMultiple && (_jsx(Checkbox, { isChecked: isSelected(option.id), sx: { pointerEvents: "none" }, size: s.checkboxSize })), option.view ? (_jsx(_Fragment, { children: option.view })) : (_jsx(Text, { fontSize: s.dropdownTextFontSize, children: option.label }))] }, option.id))), ((pagination === null || pagination === void 0 ? void 0 : pagination.scrollLoading) || (isOptionLoading && filteredOptions.length > 0)) && (_jsxs(Box, { py: s.optionRowPy, px: 3, display: "flex", alignItems: "center", justifyContent: "center", gap: 2, minH: s.optionRowMinH, children: [_jsx(Spinner, { size: s.spinnerSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: loadingText })] }))] })) }), (addNew === null || addNew === void 0 ? void 0 : addNew.enabled) && (_jsxs(Box, { py: s.optionRowPy, px: 3, borderTop: "0.063rem solid", borderColor: theme.colors.boxborder[200], bg: theme.colors.background[50], display: "flex", alignItems: "center", gap: 2, minH: s.optionRowMinH, cursor: "pointer", onClick: addNew.onClick, _hover: { bg: dropdownHoverTint }, children: [addNew.icon || _jsx(Plus, { size: s.addNewIconSize }), _jsx(Text, { fontSize: s.dropdownTextFontSize, children: addNew.text || "Add New" })] }))] }) })), helperText && !error && _jsx(HelperText, { helperText: helperText }), error && _jsx(ErrorMessage, { errorMessage: errorMessage })] }));
515
519
  };
516
520
  export default SearchSelect;
@@ -0,0 +1,55 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef } from "react";
3
+ import { Box, Flex } from "@chakra-ui/react";
4
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ const SIZES = {
6
+ sm: { h: "1.625rem", px: "0.625rem", fontSize: "0.75rem" },
7
+ md: { h: "2rem", px: "0.875rem", fontSize: "0.8125rem" },
8
+ };
9
+ export default function SegmentedControl({ options, value, onChange, size = "md", isFullWidth = false, "aria-label": ariaLabel, }) {
10
+ const { colors } = useCustomTheme();
11
+ const dims = SIZES[size];
12
+ const refs = useRef([]);
13
+ const selectedIndex = options.findIndex((o) => o.value === value);
14
+ const enabled = options.reduce((acc, o, i) => (o.isDisabled ? acc : [...acc, i]), []);
15
+ // WAI-APG: with nothing selected, the first enabled segment owns the tab stop.
16
+ const tabIndex = selectedIndex >= 0 ? selectedIndex : enabled[0];
17
+ const selectAt = (index) => {
18
+ var _a;
19
+ (_a = refs.current[index]) === null || _a === void 0 ? void 0 : _a.focus();
20
+ onChange(options[index].value);
21
+ };
22
+ const handleKeyDown = (event) => {
23
+ if (enabled.length === 0)
24
+ return;
25
+ const step = (delta) => {
26
+ const position = enabled.indexOf(tabIndex);
27
+ selectAt(enabled[(position + delta + enabled.length) % enabled.length]);
28
+ };
29
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
30
+ event.preventDefault();
31
+ step(1);
32
+ }
33
+ else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
34
+ event.preventDefault();
35
+ step(-1);
36
+ }
37
+ else if (event.key === "Home") {
38
+ event.preventDefault();
39
+ selectAt(enabled[0]);
40
+ }
41
+ else if (event.key === "End") {
42
+ event.preventDefault();
43
+ selectAt(enabled[enabled.length - 1]);
44
+ }
45
+ };
46
+ return (_jsx(Flex, { role: "radiogroup", "aria-label": ariaLabel, onKeyDown: handleKeyDown, display: "inline-flex", align: "center", gap: "0.125rem", p: "0.125rem", borderRadius: "md", bg: colors.background[600], w: isFullWidth ? "100%" : "fit-content", children: options.map((option, index) => {
47
+ const isSelected = option.value === value;
48
+ return (_jsxs(Box, { as: "button", type: "button", ref: (node) => {
49
+ refs.current[index] = node;
50
+ }, role: "radio", "aria-checked": isSelected, disabled: option.isDisabled, tabIndex: index === tabIndex ? 0 : -1, onClick: () => onChange(option.value), display: "inline-flex", alignItems: "center", justifyContent: "center", gap: "0.375rem", flex: isFullWidth ? "1" : undefined, h: dims.h, px: dims.px, borderRadius: "base", borderWidth: "1px", borderStyle: "solid", borderColor: isSelected ? colors.background[400] : "transparent", bg: isSelected ? colors.background[50] : "transparent", boxShadow: isSelected ? "sm" : "none", color: isSelected ? colors.text[900] : colors.text[600], fontSize: dims.fontSize, fontWeight: isSelected ? 600 : 500, whiteSpace: "nowrap", opacity: option.isDisabled ? 0.5 : 1, cursor: option.isDisabled ? "not-allowed" : "pointer", transition: "background-color 0.2s ease, color 0.2s ease", _hover: option.isDisabled || isSelected ? undefined : { color: colors.text[900] }, _focusVisible: {
51
+ outline: "none",
52
+ boxShadow: `0 0 0 2px ${colors.primary[300]}`,
53
+ }, children: [option.icon, option.label] }, option.value));
54
+ }) }));
55
+ }
@@ -4,6 +4,7 @@ import { Box, Input, Spinner, VStack, Text, InputGroup, InputRightElement, HStac
4
4
  import { TextLabel } from "../Common/FormLabel.js";
5
5
  import { FIELD_RADIUS, fieldFocusRing } from "../Common/fieldStyles.js";
6
6
  import { useCustomTheme } from "../../Theme/useCustomTheme.js";
7
+ import { resolveHoverTint } from "../../Theme/tokens/builders/outlineRung.js";
7
8
  import { PlusIcon } from "lucide-react";
8
9
  import ErrorMessage from "../Common/ErrorMessage.js";
9
10
  const RenderOptions = ({ isOptionLoading, filteredOptions, loadingText, handleOptionClick, isProfile, isColorOptions, isOptionSelected, activeIndex, optionRefs, }) => {
@@ -14,7 +15,9 @@ const RenderOptions = ({ isOptionLoading, filteredOptions, loadingText, handleOp
14
15
  if (filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.length) {
15
16
  return (_jsx(_Fragment, { children: filteredOptions.map((option, index) => (_jsxs(Box, { as: "button", type: "button", ref: (el) => {
16
17
  optionRefs.current[index] = el;
17
- }, role: "option", "aria-selected": isOptionSelected(option), tabIndex: index === activeIndex ? 0 : -1, w: "100%", textAlign: "left", border: "none", fontFamily: "inherit", bg: "transparent", px: 4, py: 2, cursor: "pointer", _hover: { backgroundColor: theme.colors.primary[50] }, onClick: () => handleOptionClick(option), onKeyDown: (e) => {
18
+ }, role: "option", "aria-selected": isOptionSelected(option), tabIndex: index === activeIndex ? 0 : -1, w: "100%", textAlign: "left", border: "none", fontFamily: "inherit", bg: "transparent", px: 4, py: 2, cursor: "pointer", _hover: {
19
+ backgroundColor: resolveHoverTint(theme.colors.primary[500], theme.colors.background[50]),
20
+ }, onClick: () => handleOptionClick(option), onKeyDown: (e) => {
18
21
  if (e.key === "Enter" || e.key === " ") {
19
22
  e.preventDefault();
20
23
  handleOptionClick(option);