@flikk/ui 1.0.0-beta.7 → 1.0.0-beta.8

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 (45) hide show
  1. package/dist/components/core/Alert/Alert.js +1 -0
  2. package/dist/components/core/Alert/Alert.theme.js +3 -7
  3. package/dist/components/core/Alert/Alert.types.d.ts +2 -1
  4. package/dist/components/core/Badge/Badge.theme.js +9 -4
  5. package/dist/components/core/Badge/Badge.types.d.ts +2 -1
  6. package/dist/components/core/Button/Button.theme.js +32 -26
  7. package/dist/components/core/Button/Button.types.d.ts +2 -1
  8. package/dist/components/core/Popover/PopoverContent.js +2 -0
  9. package/dist/components/core/Progress/Progress.theme.js +8 -5
  10. package/dist/components/core/Progress/Progress.types.d.ts +2 -1
  11. package/dist/components/core/Spinner/Spinner.theme.js +3 -5
  12. package/dist/components/core/Spinner/Spinner.types.d.ts +2 -1
  13. package/dist/components/data-display/KPI/KPI.theme.js +3 -4
  14. package/dist/components/data-display/KPI/KPI.types.d.ts +2 -1
  15. package/dist/components/data-display/Metric/Metric.theme.js +4 -0
  16. package/dist/components/data-display/Metric/Metric.types.d.ts +2 -1
  17. package/dist/components/effects/CustomCursor/CustomCursor.theme.js +2 -0
  18. package/dist/components/effects/CustomCursor/CustomCursor.types.d.ts +2 -1
  19. package/dist/components/forms/Checkbox/Checkbox.d.ts +3 -4
  20. package/dist/components/forms/Checkbox/Checkbox.js +33 -9
  21. package/dist/components/forms/Checkbox/Checkbox.theme.js +6 -0
  22. package/dist/components/forms/Checkbox/Checkbox.types.d.ts +28 -2
  23. package/dist/components/forms/Checkbox/CheckboxContext.d.ts +14 -0
  24. package/dist/components/forms/Checkbox/CheckboxContext.js +12 -0
  25. package/dist/components/forms/Checkbox/CheckboxGroup.d.ts +3 -0
  26. package/dist/components/forms/Checkbox/CheckboxGroup.js +40 -0
  27. package/dist/components/forms/Checkbox/index.d.ts +1 -1
  28. package/dist/components/forms/Radio/Radio.d.ts +3 -4
  29. package/dist/components/forms/Radio/Radio.js +21 -4
  30. package/dist/components/forms/Radio/Radio.theme.js +6 -0
  31. package/dist/components/forms/Radio/Radio.types.d.ts +30 -4
  32. package/dist/components/forms/Radio/RadioContext.d.ts +14 -0
  33. package/dist/components/forms/Radio/RadioContext.js +12 -0
  34. package/dist/components/forms/Radio/RadioGroup.d.ts +3 -0
  35. package/dist/components/forms/Radio/RadioGroup.js +36 -0
  36. package/dist/components/forms/Radio/index.d.ts +1 -1
  37. package/dist/components/forms/index.d.ts +2 -2
  38. package/dist/hooks/useSelectPortal.d.ts +3 -2
  39. package/dist/hooks/useSelectPortal.js +44 -19
  40. package/dist/styles.css +1 -1
  41. package/dist/utils/colorUtils.d.ts +23 -0
  42. package/dist/utils/colorUtils.js +45 -0
  43. package/dist/utils/index.d.ts +1 -0
  44. package/package.json +1 -1
  45. package/src/styles/theme.css +19 -0
@@ -8,6 +8,7 @@ import { Button } from '../Button/Button.js';
8
8
  const defaultIcons = {
9
9
  neutral: BellIcon,
10
10
  primary: InformationCircleIcon,
11
+ secondary: InformationCircleIcon,
11
12
  success: CheckCircleIcon,
12
13
  warning: ExclamationTriangleIcon,
13
14
  danger: XCircleIcon,
@@ -1,3 +1,5 @@
1
+ import { semanticTextColors } from '../../../utils/colorUtils.js';
2
+
1
3
  /**
2
4
  * Default theme configuration for Alert component
3
5
  * Uses flat color organization matching Badge pattern
@@ -11,13 +13,7 @@ const alertTheme = {
11
13
  glass: "glass-effect",
12
14
  },
13
15
  // Icon color styles per color
14
- iconColors: {
15
- neutral: "text-[var(--color-text-primary)]",
16
- primary: "text-[var(--color-primary)]",
17
- success: "text-[var(--color-success)]",
18
- warning: "text-[var(--color-warning)]",
19
- danger: "text-[var(--color-danger)]",
20
- },
16
+ iconColors: semanticTextColors,
21
17
  // State styles
22
18
  states: {
23
19
  dismissible: "pr-10",
@@ -1,8 +1,9 @@
1
1
  import { HTMLAttributes, ReactNode } from "react";
2
+ import { SemanticColor } from "../../../utils/colorUtils";
2
3
  /**
3
4
  * Alert semantic colors (intent)
4
5
  */
5
- export type AlertColor = "neutral" | "primary" | "success" | "warning" | "danger";
6
+ export type AlertColor = SemanticColor;
6
7
  /**
7
8
  * Alert visual variant
8
9
  */
@@ -1,3 +1,5 @@
1
+ import { semanticBgColors } from '../../../utils/colorUtils.js';
2
+
1
3
  /**
2
4
  * Default theme configuration for Badge component
3
5
  * Uses variant-first color organization for reliable dark mode and className overrides
@@ -20,6 +22,8 @@ const badgeTheme = {
20
22
  "dark:bg-[var(--color-neutral-700)] dark:ring-[var(--color-neutral-600)]",
21
23
  primary: "bg-[var(--color-primary)] text-[var(--color-primary-contrast)] ring-[var(--color-primary-400)] " +
22
24
  "dark:bg-[var(--color-primary-600)] dark:ring-[var(--color-primary-500)]",
25
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-contrast)] ring-[var(--color-secondary-400)] " +
26
+ "dark:bg-[var(--color-secondary-600)] dark:ring-[var(--color-secondary-500)]",
23
27
  success: "bg-[var(--color-success-600)] text-[var(--color-success-contrast)] ring-[var(--color-success-300)] " +
24
28
  "dark:bg-[var(--color-success-600)] dark:ring-[var(--color-success-400)]",
25
29
  warning: "bg-[var(--color-warning)] text-[var(--color-warning-contrast)] ring-[var(--color-warning-300)] " +
@@ -32,6 +36,8 @@ const badgeTheme = {
32
36
  neutral: "text-[var(--color-text-secondary)] border-[var(--color-border)] " + "",
33
37
  primary: "text-[var(--color-primary)] border-[var(--color-border)] " +
34
38
  "dark:text-[var(--color-primary-400)]",
39
+ secondary: "text-[var(--color-secondary)] border-[var(--color-border)] " +
40
+ "dark:text-[var(--color-secondary-400)]",
35
41
  success: "text-[var(--color-success)] border-[var(--color-border)] " +
36
42
  "dark:text-[var(--color-success-400)]",
37
43
  warning: "text-[var(--color-warning)] border-[var(--color-border)] " +
@@ -45,6 +51,8 @@ const badgeTheme = {
45
51
  "dark:bg-[var(--color-neutral-900)] ",
46
52
  primary: "bg-[var(--color-primary-100)] text-[var(--color-primary-700)] " +
47
53
  "dark:bg-[var(--color-primary-600)]/30 dark:text-[var(--color-primary-400)]",
54
+ secondary: "bg-[var(--color-secondary-100)] text-[var(--color-secondary-700)] " +
55
+ "dark:bg-[var(--color-secondary-600)]/30 dark:text-[var(--color-secondary-400)]",
48
56
  success: "bg-[var(--color-success-100)] text-[var(--color-success-600)] " +
49
57
  "dark:bg-[var(--color-success-600)]/30 dark:text-[var(--color-success-400)]",
50
58
  warning: "bg-[var(--color-warning-100)] text-[var(--color-warning-600)] " +
@@ -90,11 +98,8 @@ const badgeTheme = {
90
98
  },
91
99
  // Dot indicator colors (simple, no dark mode needed - inherits from parent)
92
100
  dotColors: {
101
+ ...semanticBgColors,
93
102
  neutral: "bg-[var(--color-text-secondary)]",
94
- primary: "bg-[var(--color-primary)]",
95
- success: "bg-[var(--color-success)]",
96
- warning: "bg-[var(--color-warning)]",
97
- danger: "bg-[var(--color-danger)]",
98
103
  },
99
104
  // State styles
100
105
  states: {
@@ -1,6 +1,7 @@
1
1
  import React, { ReactNode, MouseEvent } from "react";
2
+ import { SemanticColor } from "../../../utils/colorUtils";
2
3
  export type BadgeVariant = "filled" | "outline" | "ghost";
3
- export type BadgeColor = "neutral" | "primary" | "success" | "warning" | "danger";
4
+ export type BadgeColor = SemanticColor;
4
5
  export type BadgeSize = "sm" | "md";
5
6
  /**
6
7
  * Theme configuration for Badge component
@@ -6,7 +6,7 @@ const buttonTheme = {
6
6
  baseStyle: "relative inline-flex items-center justify-center gap-2 font-semibold focus:outline-none rounded-[var(--button-radius)] overflow-hidden cursor-pointer transition-all duration-300 ease-in-out min-w-fit flex-shrink-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 cursor-pointer",
7
7
  // Visual style variants - STRUCTURE only (no colors)
8
8
  variantStyles: {
9
- filled: "border",
9
+ filled: "border hover:brightness-[0.9] dark:hover:brightness-[1.15]",
10
10
  outline: "bg-transparent border",
11
11
  ghost: "border-transparent",
12
12
  link: "bg-transparent border-transparent",
@@ -16,54 +16,52 @@ const buttonTheme = {
16
16
  // Filled variant - solid backgrounds
17
17
  filled: {
18
18
  neutral: "bg-[var(--color-neutral-900)] text-white border-[var(--color-border)] " +
19
- "hover:bg-[var(--color-neutral-800)] hover:ring-2 hover:ring-[var(--color-neutral-900)]/20 " +
20
19
  "focus-visible:outline-[var(--color-neutral-800)] " +
21
- "dark:bg-[var(--color-neutral-200)] dark:text-[var(--color-neutral-900)] dark:border-[var(--color-neutral-200)] " +
22
- "dark:hover:bg-[var(--color-neutral-300)]",
20
+ "dark:bg-[var(--color-neutral-200)] dark:text-[var(--color-neutral-900)] dark:border-[var(--color-neutral-200)]",
23
21
  primary: "bg-[var(--color-primary)] text-[var(--color-primary-contrast)] border-[var(--color-primary)] " +
24
- "hover:bg-[var(--color-primary-700)] hover:ring-2 hover:ring-[var(--color-primary)]/20 " +
25
22
  "focus-visible:outline-[var(--color-primary-600)] " +
26
- "dark:text-[var(--color-primary-contrast)] dark:bg-[var(--color-primary-600)] dark:border-[var(--color-primary-600)] " +
27
- "dark:hover:bg-[var(--color-primary-500)]",
23
+ "dark:text-[var(--color-primary-contrast)] dark:bg-[var(--color-primary-600)] dark:border-[var(--color-primary-600)]",
24
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-contrast)] border-[var(--color-secondary)] " +
25
+ "focus-visible:outline-[var(--color-secondary-600)] " +
26
+ "dark:text-[var(--color-secondary-contrast)] dark:bg-[var(--color-secondary-600)] dark:border-[var(--color-secondary-600)]",
28
27
  success: "bg-[var(--color-success)] text-[var(--color-success-contrast)] border-[var(--color-success)] " +
29
- "hover:bg-[var(--color-success-600)] hover:ring-2 hover:ring-[var(--color-success)]/20 " +
30
28
  "focus-visible:outline-[var(--color-success-600)] " +
31
- "dark:bg-[var(--color-success-700)] dark:border-[var(--color-success-700)] " +
32
- "dark:hover:bg-[var(--color-success-600)]",
29
+ "dark:bg-[var(--color-success-700)] dark:border-[var(--color-success-700)]",
33
30
  warning: "bg-[var(--color-warning)] text-[var(--color-warning-contrast)] border-[var(--color-warning)] " +
34
- "hover:bg-[var(--color-warning-600)] hover:ring-2 hover:ring-[var(--color-warning)]/20 " +
35
31
  "focus-visible:outline-[var(--color-warning-600)] " +
36
- "dark:bg-[var(--color-warning-600)] dark:border-[var(--color-warning-600)] " +
37
- "dark:hover:bg-[var(--color-warning-500)]",
32
+ "dark:bg-[var(--color-warning-600)] dark:border-[var(--color-warning-600)]",
38
33
  danger: "bg-[var(--color-danger)] text-[var(--color-danger-contrast)] border-[var(--color-danger)] " +
39
- "hover:bg-[var(--color-danger-600)] hover:ring-2 hover:ring-[var(--color-danger)]/20 " +
40
34
  "focus-visible:outline-[var(--color-danger-600)] " +
41
- "dark:bg-[var(--color-danger-600)] dark:border-[var(--color-danger-600)] " +
42
- "dark:hover:bg-[var(--color-danger-500)]",
35
+ "dark:bg-[var(--color-danger-600)] dark:border-[var(--color-danger-600)]",
43
36
  },
44
37
  // Outline variant - transparent bg with colored border
45
38
  outline: {
46
39
  neutral: "text-[var(--color-text-primary)] border-[var(--color-border)] " +
47
- "hover:bg-[var(--color-neutral-100)] hover:ring-2 hover:ring-[var(--color-border)] " +
40
+ "hover:bg-[var(--color-neutral-100)] " +
48
41
  "focus-visible:outline-[var(--color-text-secondary)] " +
49
42
  "dark:hover:bg-[var(--color-background-secondary)]",
50
43
  primary: "text-[var(--color-primary-600)] border-[var(--color-primary-600)] " +
51
- "hover:bg-[var(--color-primary-50)] hover:ring-2 hover:ring-[var(--color-primary)]/30 " +
44
+ "hover:bg-[var(--color-primary-50)] " +
52
45
  "focus-visible:outline-[var(--color-primary-600)] " +
53
46
  "dark:text-[var(--color-primary-300)] dark:border-[var(--color-primary-400)] " +
54
47
  "dark:hover:bg-[var(--color-primary-900)]/30",
48
+ secondary: "text-[var(--color-secondary-600)] border-[var(--color-secondary-600)] " +
49
+ "hover:bg-[var(--color-secondary-50)] " +
50
+ "focus-visible:outline-[var(--color-secondary-600)] " +
51
+ "dark:text-[var(--color-secondary-300)] dark:border-[var(--color-secondary-400)] " +
52
+ "dark:hover:bg-[var(--color-secondary-900)]/30",
55
53
  success: "text-[var(--color-success-600)] border-[var(--color-success-600)] " +
56
- "hover:bg-[var(--color-success-50)] hover:ring-2 hover:ring-[var(--color-success)]/30 " +
54
+ "hover:bg-[var(--color-success-50)] " +
57
55
  "focus-visible:outline-[var(--color-success-600)] " +
58
56
  "dark:text-[var(--color-success-300)] dark:border-[var(--color-success-400)] " +
59
57
  "dark:hover:bg-[var(--color-success-900)]/30",
60
58
  warning: "text-[var(--color-warning-600)] border-[var(--color-warning-600)] " +
61
- "hover:bg-[var(--color-warning-50)] hover:ring-2 hover:ring-[var(--color-warning)]/30 " +
59
+ "hover:bg-[var(--color-warning-50)] " +
62
60
  "focus-visible:outline-[var(--color-warning-600)] " +
63
61
  "dark:text-[var(--color-warning-300)] dark:border-[var(--color-warning-400)] " +
64
62
  "dark:hover:bg-[var(--color-warning-900)]/30",
65
63
  danger: "text-[var(--color-danger-600)] border-[var(--color-danger-600)] " +
66
- "hover:bg-[var(--color-danger-50)] hover:ring-2 hover:ring-[var(--color-danger)]/30 " +
64
+ "hover:bg-[var(--color-danger-50)] " +
67
65
  "focus-visible:outline-[var(--color-danger-600)] " +
68
66
  "dark:text-[var(--color-danger-300)] dark:border-[var(--color-danger-400)] " +
69
67
  "dark:hover:bg-[var(--color-danger-900)]/30",
@@ -71,27 +69,32 @@ const buttonTheme = {
71
69
  // Ghost variant - subtle background tints
72
70
  ghost: {
73
71
  neutral: "text-[var(--color-text-primary)] bg-[var(--color-neutral-100)] " +
74
- "hover:bg-[var(--color-neutral-200)] hover:ring-2 hover:ring-[var(--color-border)] " +
72
+ "hover:bg-[var(--color-neutral-200)] " +
75
73
  "focus-visible:outline-[var(--color-text-secondary)] " +
76
74
  "dark:text-[var(--color-text-primary)] dark:bg-[var(--color-neutral-900)] " +
77
75
  "dark:hover:bg-[var(--color-neutral-800)]",
78
76
  primary: "text-[var(--color-primary-600)] bg-[var(--color-primary)]/10 " +
79
- "hover:bg-[var(--color-primary-50)] hover:ring-2 hover:ring-[var(--color-primary)]/10 " +
77
+ "hover:bg-[var(--color-primary-50)] " +
80
78
  "focus-visible:outline-[var(--color-primary-600)] " +
81
79
  "dark:text-[var(--color-primary-300)] dark:bg-[var(--color-primary-900)]/30 " +
82
80
  "dark:hover:bg-[var(--color-primary-900)]/50",
81
+ secondary: "text-[var(--color-secondary-600)] bg-[var(--color-secondary)]/10 " +
82
+ "hover:bg-[var(--color-secondary-50)] " +
83
+ "focus-visible:outline-[var(--color-secondary-600)] " +
84
+ "dark:text-[var(--color-secondary-300)] dark:bg-[var(--color-secondary-900)]/30 " +
85
+ "dark:hover:bg-[var(--color-secondary-900)]/50",
83
86
  success: "text-[var(--color-success-600)] bg-[var(--color-success)]/10 " +
84
- "hover:bg-[var(--color-success-50)] hover:ring-2 hover:ring-[var(--color-success)]/20 " +
87
+ "hover:bg-[var(--color-success-50)] " +
85
88
  "focus-visible:outline-[var(--color-success-600)] " +
86
89
  "dark:text-[var(--color-success-300)] dark:bg-[var(--color-success-900)]/30 " +
87
90
  "dark:hover:bg-[var(--color-success-900)]/50",
88
91
  warning: "text-[var(--color-warning-600)] bg-[var(--color-warning)]/10 " +
89
- "hover:bg-[var(--color-warning-50)] hover:ring-2 hover:ring-[var(--color-warning)]/20 " +
92
+ "hover:bg-[var(--color-warning-50)] " +
90
93
  "focus-visible:outline-[var(--color-warning-600)] " +
91
94
  "dark:text-[var(--color-warning-300)] dark:bg-[var(--color-warning-900)]/30 " +
92
95
  "dark:hover:bg-[var(--color-warning-900)]/50",
93
96
  danger: "text-[var(--color-danger-600)] bg-[var(--color-danger)]/10 " +
94
- "hover:bg-[var(--color-danger-50)] hover:ring-2 hover:ring-[var(--color-danger)]/20 " +
97
+ "hover:bg-[var(--color-danger-50)] " +
95
98
  "focus-visible:outline-[var(--color-danger-600)] " +
96
99
  "dark:text-[var(--color-danger-300)] dark:bg-[var(--color-danger-900)]/30 " +
97
100
  "dark:hover:bg-[var(--color-danger-900)]/50",
@@ -104,6 +107,9 @@ const buttonTheme = {
104
107
  primary: "text-[var(--color-primary-600)] underline-offset-4 hover:underline " +
105
108
  "focus-visible:outline-[var(--color-primary-600)] " +
106
109
  "dark:text-[var(--color-primary-300)]",
110
+ secondary: "text-[var(--color-secondary-600)] underline-offset-4 hover:underline " +
111
+ "focus-visible:outline-[var(--color-secondary-600)] " +
112
+ "dark:text-[var(--color-secondary-300)]",
107
113
  success: "text-[var(--color-success-600)] underline-offset-4 hover:underline " +
108
114
  "focus-visible:outline-[var(--color-success-600)] " +
109
115
  "dark:text-[var(--color-success-300)]",
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { RippleEffectType } from "./Button.ripple";
3
+ import { SemanticColor } from "../../../utils/colorUtils";
3
4
  /**
4
5
  * Button component props
5
6
  * @property {ButtonColor} color - The semantic color/intent of the button
@@ -49,7 +50,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
49
50
  */
50
51
  darkMode?: boolean;
51
52
  }
52
- export type ButtonColor = "neutral" | "primary" | "success" | "warning" | "danger";
53
+ export type ButtonColor = SemanticColor;
53
54
  export type ButtonVariant = "filled" | "outline" | "ghost" | "link";
54
55
  export type ButtonSize = "sm" | "md" | "lg";
55
56
  export type ButtonState = "default" | "disabled" | "error" | "loading";
@@ -61,6 +61,8 @@ const PopoverContent = React__default.forwardRef(({ children, className, animati
61
61
  placement: placement,
62
62
  offset: offset || 8,
63
63
  autoWidth: true,
64
+ onClose: () => { if (!preventClose)
65
+ onOpenChange(false); },
64
66
  });
65
67
  // Click outside detection (active when no backdrop — with backdrop, Overlay handles it)
66
68
  useClickOutside(localRef, (e) => {
@@ -1,3 +1,5 @@
1
+ import { semanticBgColors } from '../../../utils/colorUtils.js';
2
+
1
3
  /**
2
4
  * Default theme configuration for Progress component
3
5
  */
@@ -20,11 +22,12 @@ const progressTheme = {
20
22
  },
21
23
  // Color variants for the fill
22
24
  colors: {
23
- neutral: "bg-[var(--color-neutral-400)] dark:bg-[var(--color-neutral-500)]",
24
- primary: "bg-[var(--color-primary)] dark:bg-[var(--color-primary-400)]",
25
- success: "bg-[var(--color-success)] dark:bg-[var(--color-success-400)]",
26
- warning: "bg-[var(--color-warning)] dark:bg-[var(--color-warning-400)]",
27
- danger: "bg-[var(--color-danger)] dark:bg-[var(--color-danger-400)]",
25
+ neutral: semanticBgColors.neutral + " dark:bg-[var(--color-neutral-500)]",
26
+ primary: semanticBgColors.primary + " dark:bg-[var(--color-primary-400)]",
27
+ secondary: semanticBgColors.secondary + " dark:bg-[var(--color-secondary-400)]",
28
+ success: semanticBgColors.success + " dark:bg-[var(--color-success-400)]",
29
+ warning: semanticBgColors.warning + " dark:bg-[var(--color-warning-400)]",
30
+ danger: semanticBgColors.danger + " dark:bg-[var(--color-danger-400)]",
28
31
  },
29
32
  // Indeterminate animation styles
30
33
  indeterminateStyle: "animate-[progress-indeterminate_1.5s_ease-in-out_infinite]",
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
+ import { SemanticColor } from "../../../utils/colorUtils";
2
3
  export type ProgressSize = "sm" | "md" | "lg";
3
- export type ProgressColor = "neutral" | "primary" | "success" | "warning" | "danger";
4
+ export type ProgressColor = SemanticColor;
4
5
  export type ProgressLabelPosition = "right" | "top" | "bottom" | "inside";
5
6
  /**
6
7
  * Theme configuration for Progress component
@@ -1,3 +1,5 @@
1
+ import { semanticSpinnerColors } from '../../../utils/colorUtils.js';
2
+
1
3
  /**
2
4
  * Default theme for the Spinner component
3
5
  */
@@ -12,12 +14,8 @@ const spinnerTheme = {
12
14
  },
13
15
  // Color variants
14
16
  colors: {
15
- neutral: "border-[var(--color-border)] border-t-transparent",
17
+ ...semanticSpinnerColors,
16
18
  dark: "border-[var(--color-background-quinary)] border-t-transparent",
17
- primary: "border-[var(--color-primary)] border-t-transparent",
18
- success: "border-[var(--color-success)] border-t-transparent",
19
- warning: "border-[var(--color-warning)] border-t-transparent",
20
- danger: "border-[var(--color-danger)] border-t-transparent",
21
19
  },
22
20
  // Animation class with drop shadow
23
21
  animation: "animate-[spin_1s_linear_infinite] rounded-full",
@@ -21,8 +21,9 @@ export interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {
21
21
  */
22
22
  theme?: SpinnerThemeOverrides;
23
23
  }
24
+ import { SemanticColor } from "../../../utils/colorUtils";
24
25
  export type SpinnerSize = "sm" | "md" | "lg";
25
- export type SpinnerColor = "neutral" | "dark" | "primary" | "success" | "warning" | "danger";
26
+ export type SpinnerColor = SemanticColor | "dark";
26
27
  export interface SpinnerThemeOverrides {
27
28
  baseStyle?: string;
28
29
  sizes?: Partial<Record<SpinnerSize, string>>;
@@ -1,3 +1,5 @@
1
+ import { semanticBgColors } from '../../../utils/colorUtils.js';
2
+
1
3
  const kpiTheme = {
2
4
  baseStyle: "flex flex-col gap-3",
3
5
  valueSizes: {
@@ -20,10 +22,7 @@ const kpiTheme = {
20
22
  lg: "text-base",
21
23
  },
22
24
  barFilledColors: {
23
- primary: "bg-[var(--color-primary)]",
24
- success: "bg-[var(--color-success)]",
25
- warning: "bg-[var(--color-warning)]",
26
- danger: "bg-[var(--color-danger)]",
25
+ ...semanticBgColors,
27
26
  neutral: "bg-[var(--color-text-secondary)]",
28
27
  },
29
28
  barEmptyColor: "bg-[var(--color-background-tertiary)]",
@@ -1,6 +1,7 @@
1
1
  import { ReactNode, HTMLAttributes } from "react";
2
+ import { SemanticColor } from "../../../utils/colorUtils";
2
3
  export type KPISize = "sm" | "md" | "lg";
3
- export type KPIColor = "primary" | "success" | "warning" | "danger" | "neutral";
4
+ export type KPIColor = SemanticColor;
4
5
  export interface KPITheme {
5
6
  baseStyle: string;
6
7
  valueSizes: Record<KPISize, string>;
@@ -22,6 +22,8 @@ const metricTheme = {
22
22
  "dark:bg-[var(--color-background-secondary)]",
23
23
  primary: "bg-white text-[var(--color-primary)] border border-[var(--color-border)] " +
24
24
  "dark:bg-[var(--color-background-secondary)]",
25
+ secondary: "bg-white text-[var(--color-secondary)] border border-[var(--color-border)] " +
26
+ "dark:bg-[var(--color-background-secondary)]",
25
27
  success: "bg-white text-[var(--color-success)] border border-[var(--color-border)] " +
26
28
  "dark:bg-[var(--color-background-secondary)]",
27
29
  warning: "bg-white text-[var(--color-warning)] border border-[var(--color-border)] " +
@@ -33,6 +35,8 @@ const metricTheme = {
33
35
  neutral: "glass-effect-1 !ring-0 text-[var(--color-text-primary)]",
34
36
  primary: "glass-effect-2 !ring-0 shadow-lg shadow-blue-500/10 text-[var(--color-primary)] " +
35
37
  "dark:text-[var(--color-primary-400)]",
38
+ secondary: "glass-effect-2 !ring-0 shadow-lg shadow-gray-500/10 text-[var(--color-secondary)] " +
39
+ "dark:text-[var(--color-secondary-400)]",
36
40
  success: "glass-effect-2 !ring-0 shadow-lg shadow-green-500/10 text-[var(--color-success)] " +
37
41
  "dark:text-[var(--color-success-400)]",
38
42
  warning: "glass-effect-2 !ring-0 shadow-lg shadow-yellow-500/10 text-[var(--color-warning)] " +
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import { SemanticColor } from '../../../utils/colorUtils';
2
3
  export type MetricSize = 'sm' | 'md' | 'lg';
3
- export type MetricColor = 'neutral' | 'primary' | 'success' | 'warning' | 'danger';
4
+ export type MetricColor = SemanticColor;
4
5
  export type MetricVariant = 'filled' | 'glass';
5
6
  export type TrendDirection = 'up' | 'down';
6
7
  export interface MetricProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -13,6 +13,7 @@ const customCursorTheme = {
13
13
  neutral: "bg-[var(--color-background-secondary)]",
14
14
  dark: "bg-[var(--color-text-primary)]",
15
15
  primary: "bg-[var(--color-primary)]",
16
+ secondary: "bg-[var(--color-secondary)]",
16
17
  success: "bg-[var(--color-success)]",
17
18
  warning: "bg-[var(--color-warning)]",
18
19
  danger: "bg-[var(--color-danger)]",
@@ -26,6 +27,7 @@ const customCursorTheme = {
26
27
  neutral: "text-[var(--color-background-secondary)]",
27
28
  dark: "text-[var(--color-text-primary)]",
28
29
  primary: "text-[var(--color-primary)]",
30
+ secondary: "text-[var(--color-secondary)]",
29
31
  success: "text-[var(--color-success)]",
30
32
  warning: "text-[var(--color-warning)]",
31
33
  danger: "text-[var(--color-danger)]",
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import type { SpringOptions } from 'motion/react';
3
+ import { SemanticColor } from '../../../utils/colorUtils';
3
4
  /**
4
5
  * Alignment positions for CustomCursorFollow relative to the main cursor
5
6
  */
@@ -11,7 +12,7 @@ export type CustomCursorSize = 'sm' | 'md' | 'lg';
11
12
  /**
12
13
  * Color variants for the custom cursor
13
14
  */
14
- export type CustomCursorColor = 'neutral' | 'dark' | 'primary' | 'success' | 'warning' | 'danger';
15
+ export type CustomCursorColor = SemanticColor | 'dark';
15
16
  /**
16
17
  * Visual variants for the custom cursor
17
18
  */
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { CheckboxProps } from "./Checkbox.types";
3
- /**
4
- * Checkbox component for selecting one or more options
5
- */
6
- export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
3
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>> & {
4
+ Group: React.ForwardRefExoticComponent<import("./Checkbox.types").CheckboxGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
5
+ };
@@ -1,31 +1,52 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React__default, { useState, useRef, useEffect } from 'react';
2
+ import React__default, { useId, useState, useRef, useEffect } from 'react';
3
3
  import { checkboxTheme } from './Checkbox.theme.js';
4
4
  import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
5
5
  import { MinusIcon, CheckIcon } from '@heroicons/react/24/outline';
6
6
  import { cn } from '../../../utils/cn.js';
7
+ import { useCheckboxGroupContext } from './CheckboxContext.js';
8
+ import { CheckboxGroup } from './CheckboxGroup.js';
7
9
 
8
10
  /**
9
11
  * Checkbox component for selecting one or more options
10
12
  */
11
- const Checkbox = React__default.forwardRef(({ id, name, value, checked: controlledChecked, indeterminate = false, onChange, label, description, state = "default", size = "md", className, ...restProps }, ref) => {
13
+ const CheckboxComponent = React__default.forwardRef(({ id: idProp, name: nameProp, value, checked: controlledChecked, indeterminate = false, onChange, label, description, state: stateProp = "default", size: sizeProp = "md", className, ...restProps }, ref) => {
14
+ var _a, _b, _c, _d;
15
+ const autoId = useId();
16
+ const groupContext = useCheckboxGroupContext();
17
+ // Resolve props from group context or individual props
18
+ const id = idProp !== null && idProp !== void 0 ? idProp : autoId;
19
+ const name = (_b = (_a = groupContext === null || groupContext === void 0 ? void 0 : groupContext.name) !== null && _a !== void 0 ? _a : nameProp) !== null && _b !== void 0 ? _b : autoId;
20
+ const size = (_c = groupContext === null || groupContext === void 0 ? void 0 : groupContext.size) !== null && _c !== void 0 ? _c : sizeProp;
21
+ const state = stateProp === "disabled" ? "disabled" : ((_d = groupContext === null || groupContext === void 0 ? void 0 : groupContext.state) !== null && _d !== void 0 ? _d : stateProp);
22
+ const isDisabled = state === "disabled";
23
+ // Determine checked state
24
+ const isInGroup = groupContext !== undefined;
12
25
  const [internalChecked, setInternalChecked] = useState(false);
26
+ let isChecked;
27
+ if (isInGroup) {
28
+ isChecked = groupContext.value.includes(value);
29
+ }
30
+ else if (controlledChecked !== undefined) {
31
+ isChecked = controlledChecked;
32
+ }
33
+ else {
34
+ isChecked = internalChecked;
35
+ }
13
36
  const inputRef = useRef(null);
14
- // Determine if component is controlled or uncontrolled
15
- const isControlled = controlledChecked !== undefined;
16
- const isChecked = isControlled ? controlledChecked : internalChecked;
17
37
  // Set indeterminate property on the input element
18
38
  useEffect(() => {
19
39
  if (inputRef.current) {
20
40
  inputRef.current.indeterminate = indeterminate;
21
41
  }
22
42
  }, [indeterminate]);
23
- // Derive state flags
24
- const isDisabled = state === "disabled";
25
43
  const handleChange = (e) => {
26
44
  if (isDisabled)
27
45
  return;
28
- if (!isControlled) {
46
+ if (isInGroup) {
47
+ groupContext.onChange(value, e.target.checked);
48
+ }
49
+ else if (controlledChecked === undefined) {
29
50
  setInternalChecked(e.target.checked);
30
51
  }
31
52
  onChange === null || onChange === void 0 ? void 0 : onChange(e.target.checked, value);
@@ -38,6 +59,9 @@ const Checkbox = React__default.forwardRef(({ id, name, value, checked: controll
38
59
  ref.current = node;
39
60
  }, type: "checkbox", id: id, name: name, value: value, checked: isChecked, onChange: handleChange, disabled: isDisabled, "aria-describedby": description ? `${id}-description` : undefined, "data-state": isDisabled ? "disabled" : "default", className: cn(checkboxTheme.inputStyle, checkboxTheme.sizes[size], indeterminate && "bg-neutral-200") }), indeterminate && (jsx(MinusIcon, { className: cn("pointer-events-none col-start-1 row-start-1 self-center justify-self-center opacity-100 stroke-neutral-600 transition-opacity duration-200", size === "sm" ? "size-3" : "size-4"), strokeWidth: 3 })), isChecked && !indeterminate && (jsx(CheckIcon, { className: cn("pointer-events-none col-start-1 row-start-1 self-center justify-self-center opacity-100 stroke-white transition-opacity duration-200", size === "sm" ? "size-3" : "size-4"), strokeWidth: 3 }))] }), (label || description) && (jsxs("label", { htmlFor: id, className: cn("cursor-pointer", isDisabled && "cursor-not-allowed"), children: [label && (jsx("span", { className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[state], "mb-0"), children: label })), description && (jsx("div", { id: `${id}-description`, className: checkboxTheme.descriptionStyle, children: description }))] }))] }));
40
61
  });
41
- Checkbox.displayName = "Checkbox";
62
+ CheckboxComponent.displayName = "Checkbox";
63
+ const Checkbox = Object.assign(CheckboxComponent, {
64
+ Group: CheckboxGroup,
65
+ });
42
66
 
43
67
  export { Checkbox };
@@ -35,6 +35,12 @@ const checkboxTheme = {
35
35
  sm: "size-5 mt-0.25",
36
36
  md: "size-6",
37
37
  },
38
+ // Group styles
39
+ groupStyle: "flex flex-col gap-1.5",
40
+ groupHorizontalStyle: "flex-row flex-wrap gap-x-6 gap-y-3",
41
+ groupDescriptionStyle: "text-sm text-[var(--color-text-secondary)]/80 -mt-0.5 mb-1",
42
+ groupErrorStyle: "text-sm text-[var(--color-danger)] mt-1.5",
43
+ groupItemsStyle: "flex flex-col gap-3",
38
44
  };
39
45
 
40
46
  export { checkboxTheme };
@@ -7,12 +7,16 @@ export type CheckboxState = 'default' | 'disabled';
7
7
  * Size variants for the checkbox component
8
8
  */
9
9
  export type CheckboxSize = 'sm' | 'md';
10
+ /**
11
+ * Orientation for Checkbox.Group layout
12
+ */
13
+ export type CheckboxGroupOrientation = 'vertical' | 'horizontal';
10
14
  /**
11
15
  * Checkbox component props
12
16
  */
13
17
  export interface CheckboxProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
14
- id: string;
15
- name: string;
18
+ id?: string;
19
+ name?: string;
16
20
  value: string;
17
21
  checked?: boolean;
18
22
  indeterminate?: boolean;
@@ -23,6 +27,23 @@ export interface CheckboxProps extends Omit<React.HTMLAttributes<HTMLInputElemen
23
27
  size?: CheckboxSize;
24
28
  className?: string;
25
29
  }
30
+ /**
31
+ * Checkbox.Group component props
32
+ */
33
+ export interface CheckboxGroupProps extends Omit<React.HTMLAttributes<HTMLFieldSetElement>, 'onChange'> {
34
+ value?: string[];
35
+ defaultValue?: string[];
36
+ onChange?: (value: string[]) => void;
37
+ name?: string;
38
+ size?: CheckboxSize;
39
+ state?: CheckboxState;
40
+ orientation?: CheckboxGroupOrientation;
41
+ label?: string;
42
+ description?: string;
43
+ error?: string;
44
+ required?: boolean;
45
+ className?: string;
46
+ }
26
47
  /**
27
48
  * Checkbox theme configuration
28
49
  */
@@ -32,4 +53,9 @@ export interface CheckboxTheme {
32
53
  inputStyle: string;
33
54
  descriptionStyle: string;
34
55
  sizes: Record<CheckboxSize, string>;
56
+ groupStyle?: string;
57
+ groupHorizontalStyle?: string;
58
+ groupDescriptionStyle?: string;
59
+ groupErrorStyle?: string;
60
+ groupItemsStyle?: string;
35
61
  }
@@ -0,0 +1,14 @@
1
+ import type { CheckboxSize, CheckboxState } from "./Checkbox.types";
2
+ export interface CheckboxGroupContextValue {
3
+ name: string;
4
+ value: string[];
5
+ onChange: (itemValue: string, checked: boolean) => void;
6
+ size: CheckboxSize;
7
+ state: CheckboxState;
8
+ }
9
+ export declare const CheckboxGroupContext: import("react").Context<CheckboxGroupContextValue | undefined>;
10
+ /**
11
+ * Returns the group context, or undefined when used outside a Checkbox.Group.
12
+ * This allows standalone Checkbox usage without a Group wrapper.
13
+ */
14
+ export declare function useCheckboxGroupContext(): CheckboxGroupContextValue | undefined;
@@ -0,0 +1,12 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ const CheckboxGroupContext = createContext(undefined);
4
+ /**
5
+ * Returns the group context, or undefined when used outside a Checkbox.Group.
6
+ * This allows standalone Checkbox usage without a Group wrapper.
7
+ */
8
+ function useCheckboxGroupContext() {
9
+ return useContext(CheckboxGroupContext);
10
+ }
11
+
12
+ export { CheckboxGroupContext, useCheckboxGroupContext };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { CheckboxGroupProps } from "./Checkbox.types";
3
+ export declare const CheckboxGroup: React.ForwardRefExoticComponent<CheckboxGroupProps & React.RefAttributes<HTMLFieldSetElement>>;