@flikk/ui 1.0.0-beta.21 → 1.0.0-beta.22

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 (177) hide show
  1. package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
  2. package/dist/components/ai/PromptInput/PromptInput.theme.js +3 -3
  3. package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +1 -1
  4. package/dist/components/ai/StreamingResponse/StreamingResponse.theme.js +4 -4
  5. package/dist/components/ai/TokenCounter/TokenCounter.theme.js +6 -6
  6. package/dist/components/charts/ActivityRings/ActivityRings.theme.js +2 -2
  7. package/dist/components/charts/DonutChart/DonutChart.theme.js +2 -2
  8. package/dist/components/charts/DonutChart/MultiSegmentDonutChart.theme.js +1 -1
  9. package/dist/components/charts/Heatmap/Heatmap.theme.js +1 -1
  10. package/dist/components/charts/RadarChart/RadarChart.theme.js +2 -2
  11. package/dist/components/charts/ScatterPlot/ScatterPlot.theme.js +2 -2
  12. package/dist/components/charts/shared/ChartText/ChartText.theme.js +1 -1
  13. package/dist/components/charts/shared/ChartTooltip/ChartTooltip.theme.js +4 -4
  14. package/dist/components/core/Alert/Alert.theme.js +1 -1
  15. package/dist/components/core/Avatar/Avatar.theme.js +10 -10
  16. package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +1 -1
  17. package/dist/components/core/Badge/Badge.js +2 -12
  18. package/dist/components/core/Badge/Badge.theme.js +2 -2
  19. package/dist/components/core/Button/Button.theme.js +6 -6
  20. package/dist/components/core/ButtonGroup/ButtonGroup.theme.js +1 -1
  21. package/dist/components/core/Calendar/Calendar.theme.js +5 -5
  22. package/dist/components/core/Card/Card.theme.js +2 -2
  23. package/dist/components/core/CommandPalette/CommandPalette.theme.js +4 -4
  24. package/dist/components/core/Drawer/Drawer.animations.js +5 -4
  25. package/dist/components/core/Drawer/Drawer.theme.js +2 -2
  26. package/dist/components/core/Dropdown/Dropdown.theme.js +1 -1
  27. package/dist/components/core/Empty/Empty.theme.js +2 -2
  28. package/dist/components/core/Icon/Icon.d.ts +3 -0
  29. package/dist/components/core/Icon/Icon.js +70 -0
  30. package/dist/components/core/Icon/Icon.theme.d.ts +2 -0
  31. package/dist/components/core/Icon/Icon.theme.js +19 -0
  32. package/dist/components/core/Icon/Icon.types.d.ts +32 -0
  33. package/dist/components/core/{FileTypeIcon → Icon/data}/fileTypes.d.ts +1 -1
  34. package/dist/components/core/Icon/data/paymentMethods.d.ts +27 -0
  35. package/dist/components/core/Icon/data/paymentMethods.js +169 -0
  36. package/dist/components/core/Icon/index.d.ts +4 -0
  37. package/dist/components/core/Kbd/Kbd.theme.js +2 -2
  38. package/dist/components/core/MenuItem/MenuItem.theme.js +2 -2
  39. package/dist/components/core/Message/Message.theme.js +6 -6
  40. package/dist/components/core/Modal/Modal.animations.js +3 -1
  41. package/dist/components/core/Modal/Modal.theme.js +2 -2
  42. package/dist/components/core/Modal/ModalBody.js +7 -8
  43. package/dist/components/core/NavItem/NavItem.theme.js +1 -1
  44. package/dist/components/core/OfflineIndicator/OfflineIndicator.theme.js +2 -2
  45. package/dist/components/core/PageHeading/PageHeading.theme.js +2 -2
  46. package/dist/components/core/Pagination/Pagination.theme.js +2 -2
  47. package/dist/components/core/Pill/Pill.theme.js +3 -3
  48. package/dist/components/core/Progress/Progress.theme.js +2 -2
  49. package/dist/components/core/Segmented/Segmented.theme.js +3 -3
  50. package/dist/components/core/Tabs/Tabs.theme.js +2 -2
  51. package/dist/components/core/Tag/Tag.theme.js +2 -2
  52. package/dist/components/core/Toast/Toast.theme.js +2 -2
  53. package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
  54. package/dist/components/core/Tree/Tree.theme.js +1 -1
  55. package/dist/components/core/index.d.ts +1 -2
  56. package/dist/components/core/index.js +2 -2
  57. package/dist/components/data-display/DescriptionList/DescriptionList.theme.js +2 -2
  58. package/dist/components/data-display/Feed/Feed.theme.js +1 -1
  59. package/dist/components/data-display/GanttChart/GanttChart.theme.js +2 -2
  60. package/dist/components/data-display/KPI/KPI.theme.js +9 -9
  61. package/dist/components/data-display/Metric/Metric.theme.js +9 -9
  62. package/dist/components/data-display/Table/Table.animations.js +16 -10
  63. package/dist/components/data-display/Table/Table.filterUtils.js +8 -1
  64. package/dist/components/data-display/Table/Table.js +10 -14
  65. package/dist/components/data-display/Table/Table.theme.js +3 -3
  66. package/dist/components/data-display/Table/Table.types.d.ts +2 -0
  67. package/dist/components/data-display/Table/TableActions.js +3 -3
  68. package/dist/components/data-display/Table/TableActionsMenu.js +2 -3
  69. package/dist/components/data-display/Table/TableCell.js +6 -3
  70. package/dist/components/data-display/Table/TableDeclarative.js +5 -7
  71. package/dist/components/data-display/Table/TableHeader.js +5 -2
  72. package/dist/components/data-display/Table/TablePagination.js +2 -6
  73. package/dist/components/data-display/Table/TableRow.js +2 -6
  74. package/dist/components/data-display/Table/index.js +1 -0
  75. package/dist/components/effects/CustomCursor/CustomCursor.theme.js +1 -1
  76. package/dist/components/effects/Overlay/Overlay.js +50 -21
  77. package/dist/components/forms/Checkbox/Checkbox.theme.js +3 -3
  78. package/dist/components/forms/ColorPicker/ColorPicker.d.ts +5 -9
  79. package/dist/components/forms/ColorPicker/ColorPicker.js +126 -22
  80. package/dist/components/forms/ColorPicker/ColorPicker.theme.js +9 -6
  81. package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +99 -0
  82. package/dist/components/forms/ColorPicker/ColorPicker2DCanvas.js +43 -6
  83. package/dist/components/forms/ColorPicker/ColorPickerBody.js +1 -1
  84. package/dist/components/forms/ColorPicker/ColorPickerContext.d.ts +4 -0
  85. package/dist/components/forms/ColorPicker/ColorPickerContext.js +12 -0
  86. package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +1 -1
  87. package/dist/components/forms/ColorPicker/ColorPickerFormatSelector.js +1 -1
  88. package/dist/components/forms/ColorPicker/ColorPickerGradient.d.ts +7 -0
  89. package/dist/components/forms/ColorPicker/ColorPickerGradient.js +186 -0
  90. package/dist/components/forms/ColorPicker/ColorPickerHeader.d.ts +14 -0
  91. package/dist/components/forms/ColorPicker/ColorPickerHeader.js +31 -0
  92. package/dist/components/forms/ColorPicker/ColorPickerImage.d.ts +6 -0
  93. package/dist/components/forms/ColorPicker/ColorPickerImage.js +154 -0
  94. package/dist/components/forms/ColorPicker/ColorPickerInput.d.ts +0 -4
  95. package/dist/components/forms/ColorPicker/ColorPickerInput.js +53 -61
  96. package/dist/components/forms/ColorPicker/ColorPickerPresets.js +13 -12
  97. package/dist/components/forms/ColorPicker/ColorPickerSavedColors.d.ts +3 -0
  98. package/dist/components/forms/ColorPicker/ColorPickerSavedColors.js +69 -0
  99. package/dist/components/forms/ColorPicker/ColorPickerSliders.d.ts +1 -2
  100. package/dist/components/forms/ColorPicker/ColorPickerSliders.js +84 -23
  101. package/dist/components/forms/ColorPicker/ColorPickerSwatch.d.ts +1 -1
  102. package/dist/components/forms/ColorPicker/ColorPickerSwatch.js +10 -9
  103. package/dist/components/forms/ColorPicker/ColorPickerTrigger.js +7 -3
  104. package/dist/components/forms/ColorPicker/index.d.ts +8 -2
  105. package/dist/components/forms/CronInput/CronInput.theme.js +8 -8
  106. package/dist/components/forms/DatePicker/DatePicker.theme.js +1 -1
  107. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +3 -3
  108. package/dist/components/forms/FileUpload/FileUpload.theme.js +4 -4
  109. package/dist/components/forms/FileUpload/FileUploadProgress.js +3 -3
  110. package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
  111. package/dist/components/forms/FormLabel/FormLabel.theme.js +1 -1
  112. package/dist/components/forms/Input/Input.js +3 -3
  113. package/dist/components/forms/Input/Input.theme.js +1 -1
  114. package/dist/components/forms/Input/Input.types.d.ts +2 -0
  115. package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
  116. package/dist/components/forms/InputOTP/InputOTP.theme.js +1 -1
  117. package/dist/components/forms/Mention/Mention.theme.js +3 -3
  118. package/dist/components/forms/Radio/Radio.theme.js +3 -3
  119. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +1 -1
  120. package/dist/components/forms/Select/Select.theme.js +1 -1
  121. package/dist/components/forms/SelectableCard/SelectableCard.js +42 -27
  122. package/dist/components/forms/SelectableCard/SelectableCard.theme.js +15 -25
  123. package/dist/components/forms/SelectableCard/SelectableCard.types.d.ts +16 -3
  124. package/dist/components/forms/SelectableCard/SelectableCardContext.d.ts +1 -0
  125. package/dist/components/forms/SelectableCard/SelectableCardContext.js +4 -7
  126. package/dist/components/forms/SelectableCard/SelectableCardGroup.js +31 -10
  127. package/dist/components/forms/SelectableCard/index.d.ts +1 -1
  128. package/dist/components/forms/Signature/Signature.theme.js +1 -1
  129. package/dist/components/forms/Slider/Slider.theme.js +3 -3
  130. package/dist/components/forms/Switch/Switch.theme.js +1 -1
  131. package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
  132. package/dist/components/forms/forms.theme.js +6 -6
  133. package/dist/components/forms/index.js +6 -1
  134. package/dist/components/layout/FormLayout/FormLayout.theme.js +2 -2
  135. package/dist/hooks/useOverlay.d.ts +2 -0
  136. package/dist/hooks/useOverlay.js +34 -4
  137. package/dist/index.js +8 -3
  138. package/dist/styles.css +1 -1
  139. package/package.json +2 -1
  140. package/src/global.scss +1 -1
  141. package/dist/bg/bg/1.jpg +0 -0
  142. package/dist/bg/bg/10.jpg +0 -0
  143. package/dist/bg/bg/11.jpg +0 -0
  144. package/dist/bg/bg/14.jpg +0 -0
  145. package/dist/bg/bg/15.jpg +0 -0
  146. package/dist/bg/bg/16.jpg +0 -0
  147. package/dist/bg/bg/17.jpg +0 -0
  148. package/dist/bg/bg/18.jpg +0 -0
  149. package/dist/bg/bg/19.jpg +0 -0
  150. package/dist/bg/bg/2.jpg +0 -0
  151. package/dist/bg/bg/20.jpg +0 -0
  152. package/dist/bg/bg/21.jpg +0 -0
  153. package/dist/bg/bg/22.jpg +0 -0
  154. package/dist/bg/bg/23.jpg +0 -0
  155. package/dist/bg/bg/24.jpg +0 -0
  156. package/dist/bg/bg/3.jpg +0 -0
  157. package/dist/bg/bg/4.jpg +0 -0
  158. package/dist/bg/bg/5.jpg +0 -0
  159. package/dist/bg/bg/6.jpg +0 -0
  160. package/dist/bg/bg/7.jpg +0 -0
  161. package/dist/bg/bg/8.jpg +0 -0
  162. package/dist/bg/bg/9.jpg +0 -0
  163. package/dist/components/core/FileTypeIcon/FileTypeIcon.d.ts +0 -3
  164. package/dist/components/core/FileTypeIcon/FileTypeIcon.js +0 -33
  165. package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.d.ts +0 -2
  166. package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.js +0 -12
  167. package/dist/components/core/FileTypeIcon/FileTypeIcon.types.d.ts +0 -19
  168. package/dist/components/core/FileTypeIcon/index.d.ts +0 -2
  169. package/dist/components/core/SocialIcon/SocialIcon.d.ts +0 -3
  170. package/dist/components/core/SocialIcon/SocialIcon.js +0 -30
  171. package/dist/components/core/SocialIcon/SocialIcon.theme.d.ts +0 -2
  172. package/dist/components/core/SocialIcon/SocialIcon.theme.js +0 -12
  173. package/dist/components/core/SocialIcon/SocialIcon.types.d.ts +0 -18
  174. package/dist/components/core/SocialIcon/index.d.ts +0 -2
  175. /package/dist/components/core/{FileTypeIcon → Icon/data}/fileTypes.js +0 -0
  176. /package/dist/components/core/{SocialIcon → Icon/data}/platforms.d.ts +0 -0
  177. /package/dist/components/core/{SocialIcon → Icon/data}/platforms.js +0 -0
@@ -1,38 +1,37 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import React__default, { createContext, useMemo, useState, useRef, useEffect, useCallback } from 'react';
2
+ import React__default, { useMemo, useState, useCallback, useRef, useEffect } from 'react';
3
3
  import { cn } from '../../../utils/cn.js';
4
4
  import { FormLabel } from '../FormLabel/FormLabel.js';
5
5
  import { colorPickerTheme } from './ColorPicker.theme.js';
6
+ import { ColorPickerContext } from './ColorPickerContext.js';
6
7
  import { ColorPicker2DCanvas } from './ColorPicker2DCanvas.js';
7
8
  import { ColorPickerBody } from './ColorPickerBody.js';
8
9
  import { ColorPickerEyeDropper } from './ColorPickerEyeDropper.js';
9
10
  import { ColorPickerFormatSelector } from './ColorPickerFormatSelector.js';
11
+ import { ColorPickerGradient } from './ColorPickerGradient.js';
12
+ import { ColorPickerHeader } from './ColorPickerHeader.js';
13
+ import { ColorPickerImage } from './ColorPickerImage.js';
10
14
  import { ColorPickerInput } from './ColorPickerInput.js';
11
15
  import { ColorPickerPresets } from './ColorPickerPresets.js';
16
+ import { ColorPickerSavedColors } from './ColorPickerSavedColors.js';
12
17
  import { ColorPickerSliders } from './ColorPickerSliders.js';
13
18
  import { ColorPickerSwatch } from './ColorPickerSwatch.js';
14
19
  import { ColorPickerTrigger } from './ColorPickerTrigger.js';
15
20
  import { parseColor, formatHex, formatRgb, formatHsl } from './colorUtils.js';
16
21
 
17
- /**
18
- * ColorPicker Context
19
- */
20
- const ColorPickerContext = createContext(undefined);
21
- /**
22
- * Hook to access ColorPicker context
23
- */
24
- const useColorPicker = () => {
25
- const context = React__default.useContext(ColorPickerContext);
26
- if (!context) {
27
- throw new Error('useColorPicker must be used within a ColorPicker component');
28
- }
29
- return context;
22
+ const DEFAULT_GRADIENT = {
23
+ type: 'linear',
24
+ angle: 90,
25
+ stops: [
26
+ { id: 'stop-1', color: '#000000', position: 0 },
27
+ { id: 'stop-2', color: '#FFFFFF', position: 100 },
28
+ ],
30
29
  };
31
30
  /**
32
31
  * ColorPicker Root Component
33
32
  * Follows Flikkui compound component pattern (similar to Accordion, Tabs, Popover)
34
33
  */
35
- const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000000', onChange, format: initialFormat = 'hex', showAlpha = true, showEyeDropper = true, presetColors, size = 'md', state = 'default', disabled = false, label, helperText, required = false, theme, className, children, ...props }, ref) => {
34
+ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000000', onChange, format: initialFormat = 'hex', showAlpha = true, showEyeDropper = true, presetColors, savedColors: savedColorsProp, onSavedColorsChange, defaultMode = 'solid', mode: modeProp, onModeChange, gradientValue: gradientProp, onGradientChange, size = 'md', state = 'default', disabled = false, label, helperText, required = false, theme, className, children, ...props }, ref) => {
36
35
  // Parse initial color value
37
36
  const initialColor = useMemo(() => {
38
37
  const parsed = parseColor(value || defaultValue);
@@ -41,8 +40,75 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
41
40
  const [color, setColor] = useState(initialColor);
42
41
  const [format, setFormat] = useState(initialFormat);
43
42
  const [isOpen, setIsOpen] = useState(false);
43
+ // Mode state (controlled/uncontrolled)
44
+ const [internalMode, setInternalMode] = useState(defaultMode);
45
+ const mode = modeProp !== null && modeProp !== void 0 ? modeProp : internalMode;
46
+ const setMode = useCallback((m) => {
47
+ if (onModeChange) {
48
+ onModeChange(m);
49
+ }
50
+ else {
51
+ setInternalMode(m);
52
+ }
53
+ }, [onModeChange]);
54
+ // Gradient state (controlled/uncontrolled)
55
+ const [internalGradient, setInternalGradient] = useState(gradientProp || DEFAULT_GRADIENT);
56
+ const gradient = gradientProp !== null && gradientProp !== void 0 ? gradientProp : internalGradient;
57
+ const setGradient = useCallback((g) => {
58
+ if (onGradientChange) {
59
+ onGradientChange(g);
60
+ }
61
+ else {
62
+ setInternalGradient(g);
63
+ }
64
+ }, [onGradientChange]);
65
+ const updateGradientStop = useCallback((id, updates) => {
66
+ const newGradient = {
67
+ ...gradient,
68
+ stops: gradient.stops.map(s => s.id === id ? { ...s, ...updates } : s),
69
+ };
70
+ setGradient(newGradient);
71
+ }, [gradient, setGradient]);
72
+ const addGradientStop = useCallback((position) => {
73
+ const newStop = {
74
+ id: `stop-${Date.now()}`,
75
+ color: formatHex(color.h, color.s, color.l),
76
+ position: Math.round(position),
77
+ };
78
+ setGradient({
79
+ ...gradient,
80
+ stops: [...gradient.stops, newStop].sort((a, b) => a.position - b.position),
81
+ });
82
+ }, [gradient, setGradient, color]);
83
+ const removeGradientStop = useCallback((id) => {
84
+ if (gradient.stops.length <= 2)
85
+ return;
86
+ setGradient({
87
+ ...gradient,
88
+ stops: gradient.stops.filter(s => s.id !== id),
89
+ });
90
+ }, [gradient, setGradient]);
44
91
  // Refs for positioning (like Dropdown)
45
92
  const triggerRef = useRef(null);
93
+ // Saved colors (controlled/uncontrolled)
94
+ const [internalSavedColors, setInternalSavedColors] = useState([]);
95
+ const savedColors = savedColorsProp !== null && savedColorsProp !== void 0 ? savedColorsProp : internalSavedColors;
96
+ const setSavedColors = useCallback((colors) => {
97
+ if (onSavedColorsChange) {
98
+ onSavedColorsChange(colors);
99
+ }
100
+ else {
101
+ setInternalSavedColors(colors);
102
+ }
103
+ }, [onSavedColorsChange]);
104
+ const addSavedColor = useCallback((colorValue) => {
105
+ if (!savedColors.includes(colorValue)) {
106
+ setSavedColors([...savedColors, colorValue]);
107
+ }
108
+ }, [savedColors, setSavedColors]);
109
+ const removeSavedColor = useCallback((index) => {
110
+ setSavedColors(savedColors.filter((_, i) => i !== index));
111
+ }, [savedColors, setSavedColors]);
46
112
  // Update color when controlled value changes
47
113
  useEffect(() => {
48
114
  if (value !== undefined) {
@@ -87,15 +153,27 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
87
153
  return getHexValue();
88
154
  }
89
155
  }, [format, getHexValue, getRgbValue, getHslValue]);
156
+ // Get output value (accounts for mode)
157
+ const getOutputValue = useCallback(() => {
158
+ if (mode === 'gradient') {
159
+ const sortedStops = [...gradient.stops].sort((a, b) => a.position - b.position);
160
+ const stopStrings = sortedStops.map(s => `${s.color} ${s.position}%`).join(', ');
161
+ if (gradient.type === 'linear') {
162
+ return `linear-gradient(${gradient.angle}deg, ${stopStrings})`;
163
+ }
164
+ return `radial-gradient(circle, ${stopStrings})`;
165
+ }
166
+ return getFormattedValue();
167
+ }, [mode, gradient, getFormattedValue]);
90
168
  // Notify parent of color changes
91
- const prevFormattedRef = useRef(undefined);
169
+ const prevOutputRef = useRef(undefined);
92
170
  useEffect(() => {
93
- const formatted = getFormattedValue();
94
- if (onChange && !disabled && formatted !== prevFormattedRef.current) {
95
- prevFormattedRef.current = formatted;
96
- onChange(formatted);
171
+ const output = getOutputValue();
172
+ if (onChange && !disabled && output !== prevOutputRef.current) {
173
+ prevOutputRef.current = output;
174
+ onChange(output);
97
175
  }
98
- }, [color, format, onChange, disabled, getFormattedValue]);
176
+ }, [color, format, mode, gradient, onChange, disabled, getOutputValue]);
99
177
  // Merge theme
100
178
  const mergedTheme = useMemo(() => ({
101
179
  ...colorPickerTheme,
@@ -111,6 +189,13 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
111
189
  setAlpha,
112
190
  format,
113
191
  setFormat,
192
+ mode,
193
+ setMode,
194
+ gradient,
195
+ setGradient,
196
+ updateGradientStop,
197
+ addGradientStop,
198
+ removeGradientStop,
114
199
  isOpen,
115
200
  setIsOpen,
116
201
  triggerRef,
@@ -127,7 +212,11 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
127
212
  getRgbValue,
128
213
  getHslValue,
129
214
  getFormattedValue,
215
+ getOutputValue,
130
216
  onChange,
217
+ savedColors,
218
+ addSavedColor,
219
+ removeSavedColor,
131
220
  }), [
132
221
  color,
133
222
  setColor,
@@ -137,6 +226,13 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
137
226
  setAlpha,
138
227
  format,
139
228
  setFormat,
229
+ mode,
230
+ setMode,
231
+ gradient,
232
+ setGradient,
233
+ updateGradientStop,
234
+ addGradientStop,
235
+ removeGradientStop,
140
236
  isOpen,
141
237
  setIsOpen,
142
238
  showAlpha,
@@ -150,7 +246,11 @@ const ColorPickerRoot = React__default.forwardRef(({ value, defaultValue = '#000
150
246
  getRgbValue,
151
247
  getHslValue,
152
248
  getFormattedValue,
249
+ getOutputValue,
153
250
  onChange,
251
+ savedColors,
252
+ addSavedColor,
253
+ removeSavedColor,
154
254
  ]);
155
255
  return (jsx(ColorPickerContext.Provider, { value: contextValue, children: jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), ...props, children: [label && (jsx(FormLabel, { htmlFor: "color-picker", required: required, state: state, children: label })), children, helperText && (jsx("div", { className: cn('mt-1.5 text-sm text-[var(--color-text-secondary)]', state === 'invalid' && 'text-[var(--color-danger)]'), children: helperText }))] }) }));
156
256
  });
@@ -161,6 +261,7 @@ ColorPickerRoot.displayName = 'ColorPicker';
161
261
  */
162
262
  const ColorPicker = Object.assign(ColorPickerRoot, {
163
263
  Trigger: ColorPickerTrigger,
264
+ Header: ColorPickerHeader,
164
265
  Body: ColorPickerBody,
165
266
  Canvas: ColorPicker2DCanvas,
166
267
  Swatch: ColorPickerSwatch,
@@ -169,6 +270,9 @@ const ColorPicker = Object.assign(ColorPickerRoot, {
169
270
  FormatSelector: ColorPickerFormatSelector,
170
271
  EyeDropper: ColorPickerEyeDropper,
171
272
  Presets: ColorPickerPresets,
273
+ SavedColors: ColorPickerSavedColors,
274
+ Gradient: ColorPickerGradient,
275
+ ImagePicker: ColorPickerImage,
172
276
  });
173
277
 
174
- export { ColorPicker, ColorPickerContext, useColorPicker };
278
+ export { ColorPicker };
@@ -6,15 +6,18 @@ const colorPickerTheme = {
6
6
  baseStyle: 'relative inline-block w-full',
7
7
  triggerStyle: 'cursor-pointer',
8
8
  swatchStyle: 'relative size-5 flex-shrink-0 rounded border border-[var(--color-border)] overflow-hidden',
9
- // Content matches Dropdown menu style
10
- contentStyle: 'min-w-[min(280px,calc(100vw-2rem))] max-w-[320px] rounded-xl border border-[var(--color-border)] bg-white shadow-real-xl p-3 focus:outline-none',
11
- sliderContainerStyle: 'space-y-2',
12
- sliderLabelStyle: 'flex items-center justify-between text-sm font-medium text-[var(--color-text-secondary)]',
9
+ contentStyle: 'min-w-[min(300px,calc(100vw-2rem))] max-w-[340px] rounded-xl border border-[var(--color-border)] bg-[var(--color-surface)] shadow-real-xl p-4 space-y-3 focus:outline-none',
10
+ sliderContainerStyle: 'space-y-2.5',
11
+ sliderLabelStyle: 'flex items-center justify-between text-xs font-medium text-[var(--color-text-secondary)]',
13
12
  inputContainerStyle: 'flex items-center gap-2',
14
13
  formatSelectorStyle: 'flex-shrink-0',
15
- presetGridStyle: 'mt-3 grid grid-cols-6 sm:grid-cols-8 gap-1.5',
16
- presetSwatchStyle: 'relative size-7 cursor-pointer rounded border-2 border-transparent transition-all hover:border-[var(--color-primary)] hover:scale-110 focus:border-[var(--color-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-opacity-20 data-[selected]:border-[var(--color-primary)] data-[selected]:ring-2 data-[selected]:ring-[var(--color-primary)] data-[selected]:ring-opacity-20',
14
+ presetGridStyle: 'grid grid-cols-8 gap-2',
15
+ presetSwatchStyle: 'relative size-6 cursor-pointer rounded-md border-2 border-transparent transition-all hover:border-[var(--color-primary)] hover:scale-110 focus:border-[var(--color-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-opacity-20 data-[selected]:border-[var(--color-primary)] data-[selected]:ring-2 data-[selected]:ring-[var(--color-primary)] data-[selected]:ring-opacity-20',
17
16
  eyedropperButtonStyle: 'flex-shrink-0',
17
+ sectionLabelStyle: 'text-xs font-medium text-[var(--color-text-muted)] mb-2',
18
+ savedColorsGridStyle: 'grid grid-cols-8 gap-2',
19
+ savedColorsAddButtonStyle: 'size-6 rounded-md border-2 border-dashed border-[var(--color-border)] flex items-center justify-center hover:border-[var(--color-primary)] cursor-pointer transition-colors text-[var(--color-text-muted)] hover:text-[var(--color-primary)]',
20
+ colorPreviewStyle: 'relative size-8 flex-shrink-0 rounded-lg border border-[var(--color-border)] overflow-hidden',
18
21
  };
19
22
 
20
23
  export { colorPickerTheme };
@@ -3,6 +3,24 @@ import type { HSLA } from './colorUtils';
3
3
  export type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'hsv';
4
4
  export type ColorPickerSize = 'sm' | 'md' | 'lg';
5
5
  export type ColorPickerState = 'default' | 'invalid' | 'disabled';
6
+ export type ColorPickerMode = 'solid' | 'gradient' | 'image';
7
+ export type GradientType = 'linear' | 'radial';
8
+ /**
9
+ * A single gradient color stop
10
+ */
11
+ export interface GradientStop {
12
+ id: string;
13
+ color: string;
14
+ position: number;
15
+ }
16
+ /**
17
+ * Full gradient state
18
+ */
19
+ export interface GradientState {
20
+ type: GradientType;
21
+ angle: number;
22
+ stops: GradientStop[];
23
+ }
6
24
  /**
7
25
  * Root ColorPicker component props
8
26
  */
@@ -39,6 +57,14 @@ export interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivEleme
39
57
  * Array of preset colors to display
40
58
  */
41
59
  presetColors?: string[];
60
+ /**
61
+ * Controlled saved colors array
62
+ */
63
+ savedColors?: string[];
64
+ /**
65
+ * Callback when saved colors change
66
+ */
67
+ onSavedColorsChange?: (colors: string[]) => void;
42
68
  /**
43
69
  * Size of the color picker
44
70
  * @default 'md'
@@ -67,6 +93,27 @@ export interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivEleme
67
93
  * @default false
68
94
  */
69
95
  required?: boolean;
96
+ /**
97
+ * Default mode
98
+ * @default 'solid'
99
+ */
100
+ defaultMode?: ColorPickerMode;
101
+ /**
102
+ * Controlled mode
103
+ */
104
+ mode?: ColorPickerMode;
105
+ /**
106
+ * Callback when mode changes
107
+ */
108
+ onModeChange?: (mode: ColorPickerMode) => void;
109
+ /**
110
+ * Controlled gradient value
111
+ */
112
+ gradientValue?: GradientState;
113
+ /**
114
+ * Callback when gradient changes
115
+ */
116
+ onGradientChange?: (gradient: GradientState) => void;
70
117
  /**
71
118
  * Theme overrides
72
119
  */
@@ -92,6 +139,13 @@ export interface ColorPickerContextValue {
92
139
  setAlpha: (a: number) => void;
93
140
  format: ColorFormat;
94
141
  setFormat: (format: ColorFormat) => void;
142
+ mode: ColorPickerMode;
143
+ setMode: (mode: ColorPickerMode) => void;
144
+ gradient: GradientState;
145
+ setGradient: (gradient: GradientState) => void;
146
+ updateGradientStop: (id: string, updates: Partial<GradientStop>) => void;
147
+ addGradientStop: (position: number) => void;
148
+ removeGradientStop: (id: string) => void;
95
149
  isOpen: boolean;
96
150
  setIsOpen: (open: boolean) => void;
97
151
  triggerRef: React.RefObject<HTMLElement>;
@@ -108,7 +162,11 @@ export interface ColorPickerContextValue {
108
162
  getRgbValue: () => string;
109
163
  getHslValue: () => string;
110
164
  getFormattedValue: () => string;
165
+ getOutputValue: () => string;
111
166
  onChange?: (value: string) => void;
167
+ savedColors: string[];
168
+ addSavedColor: (color: string) => void;
169
+ removeSavedColor: (index: number) => void;
112
170
  }
113
171
  /**
114
172
  * ColorPicker theme overrides
@@ -125,6 +183,10 @@ export interface ColorPickerThemeOverrides {
125
183
  presetGridStyle?: string;
126
184
  presetSwatchStyle?: string;
127
185
  eyedropperButtonStyle?: string;
186
+ sectionLabelStyle?: string;
187
+ savedColorsGridStyle?: string;
188
+ savedColorsAddButtonStyle?: string;
189
+ colorPreviewStyle?: string;
128
190
  }
129
191
  /**
130
192
  * ColorPicker theme
@@ -141,6 +203,10 @@ export interface ColorPickerTheme {
141
203
  presetGridStyle: string;
142
204
  presetSwatchStyle: string;
143
205
  eyedropperButtonStyle: string;
206
+ sectionLabelStyle: string;
207
+ savedColorsGridStyle: string;
208
+ savedColorsAddButtonStyle: string;
209
+ colorPreviewStyle: string;
144
210
  }
145
211
  /**
146
212
  * ColorPickerTrigger props
@@ -215,5 +281,38 @@ export interface ColorPickerPresetsProps extends React.HTMLAttributes<HTMLDivEle
215
281
  * Custom preset colors (overrides context presetColors)
216
282
  */
217
283
  colors?: string[];
284
+ /**
285
+ * Section label text. Set to false to hide.
286
+ * @default "Preset colors"
287
+ */
288
+ label?: string | false;
289
+ className?: string;
290
+ }
291
+ /**
292
+ * ColorPickerSavedColors props
293
+ */
294
+ export interface ColorPickerSavedColorsProps extends React.HTMLAttributes<HTMLDivElement> {
295
+ /**
296
+ * Section label text. Set to false to hide.
297
+ * @default "Saved colors"
298
+ */
299
+ label?: string | false;
300
+ /**
301
+ * Maximum number of saved colors
302
+ * @default 16
303
+ */
304
+ maxColors?: number;
305
+ className?: string;
306
+ }
307
+ /**
308
+ * ColorPickerGradient props
309
+ */
310
+ export interface ColorPickerGradientProps extends React.HTMLAttributes<HTMLDivElement> {
311
+ className?: string;
312
+ }
313
+ /**
314
+ * ColorPickerImage props
315
+ */
316
+ export interface ColorPickerImageProps extends React.HTMLAttributes<HTMLDivElement> {
218
317
  className?: string;
219
318
  }
@@ -1,8 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { useContext, useRef, useState, useCallback, useEffect } from 'react';
3
3
  import { cn } from '../../../utils/cn.js';
4
- import { ColorPickerContext } from './ColorPicker.js';
5
- import { hslToRgb, rgbToHsv } from './colorUtils.js';
4
+ import { ColorPickerContext } from './ColorPickerContext.js';
5
+ import { hslToRgb, formatRgb, rgbToHsv } from './colorUtils.js';
6
6
 
7
7
  /**
8
8
  * ColorPicker2DCanvas - Main 2D draggable color picker
@@ -72,19 +72,56 @@ const ColorPicker2DCanvas = ({ className }) => {
72
72
  };
73
73
  }
74
74
  }, [isDragging, handlePointerMove, handlePointerUp]);
75
+ // Keyboard navigation handler
76
+ const handleKeyDown = useCallback((e) => {
77
+ const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
78
+ if (!arrowKeys.includes(e.key))
79
+ return;
80
+ e.preventDefault();
81
+ const step = e.shiftKey ? 10 : 1;
82
+ let newS = hsv.s;
83
+ let newV = hsv.v;
84
+ switch (e.key) {
85
+ case 'ArrowRight':
86
+ newS = Math.min(100, newS + step);
87
+ break;
88
+ case 'ArrowLeft':
89
+ newS = Math.max(0, newS - step);
90
+ break;
91
+ case 'ArrowUp':
92
+ newV = Math.min(100, newV + step);
93
+ break;
94
+ case 'ArrowDown':
95
+ newV = Math.max(0, newV - step);
96
+ break;
97
+ }
98
+ // Convert HSV back to HSL (same conversion as updateColorFromPosition)
99
+ color.h;
100
+ const l = ((2 - newS / 100) * newV) / 2;
101
+ const sl = l !== 0 && l !== 100
102
+ ? ((newV - l) / Math.min(l, 100 - l)) * 100
103
+ : 0;
104
+ setColor({
105
+ ...color,
106
+ s: Math.round(sl),
107
+ l: Math.round(l),
108
+ });
109
+ }, [color, setColor, hsv.s, hsv.v]);
75
110
  // Background gradient based on current hue
76
111
  const hueColor = `hsl(${color.h}, 100%, 50%)`;
77
- return (jsx("div", { ref: canvasRef, onPointerDown: handlePointerDown, className: cn('relative w-full h-48 cursor-crosshair rounded-lg overflow-hidden touch-none select-none', className), style: {
112
+ // Current picked color for the inner circle
113
+ const rgbaColor = formatRgb(color.h, color.s, color.l, color.a);
114
+ return (jsx("div", { ref: canvasRef, onPointerDown: handlePointerDown, onKeyDown: handleKeyDown, className: cn('relative w-full h-[200px] cursor-crosshair rounded-xl ring-1 ring-inset ring-black/5 overflow-hidden touch-none select-none', className), style: {
78
115
  background: `
79
116
  linear-gradient(to top, #000, transparent),
80
117
  linear-gradient(to right, #fff, ${hueColor})
81
118
  `,
82
- }, role: "slider", "aria-label": "Color saturation and brightness", "aria-valuemin": 0, "aria-valuemax": 100, tabIndex: 0, children: jsx("div", { className: "absolute w-4 h-4 border-2 border-white rounded-full shadow-lg pointer-events-none", style: {
119
+ }, role: "slider", "aria-label": "Color saturation and brightness", "aria-valuemin": 0, "aria-valuemax": 100, tabIndex: 0, children: jsx("div", { className: "absolute w-5 h-5 border-2 border-white rounded-full pointer-events-none", style: {
83
120
  left: `${positionX * 100}%`,
84
121
  top: `${positionY * 100}%`,
85
122
  transform: 'translate(-50%, -50%)',
86
- boxShadow: '0 0 0 1px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2)',
87
- } }) }));
123
+ boxShadow: '0 0 0 1.5px rgba(0,0,0,0.15), 0 2px 6px rgba(0,0,0,0.15)',
124
+ }, children: jsx("div", { className: "absolute inset-1 rounded-full", style: { backgroundColor: rgbaColor } }) }) }));
88
125
  };
89
126
  ColorPicker2DCanvas.displayName = 'ColorPicker2DCanvas';
90
127
 
@@ -6,7 +6,7 @@ import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
6
6
  import { cn } from '../../../utils/cn.js';
7
7
  import { useClickOutside } from '../../../hooks/useClickOutside.js';
8
8
  import { contentVariants } from './ColorPicker.animations.js';
9
- import { ColorPickerContext } from './ColorPicker.js';
9
+ import { ColorPickerContext } from './ColorPickerContext.js';
10
10
  import { useIsClient } from '../../../hooks/useIsClient.js';
11
11
 
12
12
  /**
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { ColorPickerContextValue } from './ColorPicker.types';
3
+ export declare const ColorPickerContext: React.Context<ColorPickerContextValue | undefined>;
4
+ export declare const useColorPicker: () => ColorPickerContextValue;
@@ -0,0 +1,12 @@
1
+ import React__default, { createContext } from 'react';
2
+
3
+ const ColorPickerContext = createContext(undefined);
4
+ const useColorPicker = () => {
5
+ const context = React__default.useContext(ColorPickerContext);
6
+ if (!context) {
7
+ throw new Error('useColorPicker must be used within a ColorPicker component');
8
+ }
9
+ return context;
10
+ };
11
+
12
+ export { ColorPickerContext, useColorPicker };
@@ -3,7 +3,7 @@ import { EyeDropperIcon } from '@heroicons/react/20/solid';
3
3
  import { useContext } from 'react';
4
4
  import { cn } from '../../../utils/cn.js';
5
5
  import { Button } from '../../core/Button/Button.js';
6
- import { ColorPickerContext } from './ColorPicker.js';
6
+ import { ColorPickerContext } from './ColorPickerContext.js';
7
7
  import { parseColor } from './colorUtils.js';
8
8
 
9
9
  // Check if browser supports EyeDropper API
@@ -3,7 +3,7 @@ import { useContext } from 'react';
3
3
  import { cn } from '../../../utils/cn.js';
4
4
  import { Select } from '../Select/Select.js';
5
5
  import '../Select/Select.theme.js';
6
- import { ColorPickerContext } from './ColorPicker.js';
6
+ import { ColorPickerContext } from './ColorPickerContext.js';
7
7
 
8
8
  /**
9
9
  * ColorPickerFormatSelector - Dropdown to select color format (HEX/RGB/HSL)
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { ColorPickerGradientProps } from './ColorPicker.types';
3
+ /**
4
+ * ColorPickerGradient - Gradient editor with canvas, sliders, stop bar, type toggle, angle control.
5
+ * The 2D canvas and hue slider pick the color for the currently selected gradient stop.
6
+ */
7
+ export declare const ColorPickerGradient: React.FC<ColorPickerGradientProps>;