@fleetia/components 1.1.1

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 (245) hide show
  1. package/dist/Badge/Badge.css.d.ts +1 -0
  2. package/dist/Badge/Badge.d.ts +7 -0
  3. package/dist/Badge/Badge.js +9 -0
  4. package/dist/Badge/Badge.styles.js +6 -0
  5. package/dist/Badge/index.d.ts +1 -0
  6. package/dist/Badge/index.js +1 -0
  7. package/dist/Box/Box.css.d.ts +4 -0
  8. package/dist/Box/Box.d.ts +8 -0
  9. package/dist/Box/Box.js +14 -0
  10. package/dist/Box/Box.styles.js +9 -0
  11. package/dist/Box/index.d.ts +1 -0
  12. package/dist/Box/index.js +1 -0
  13. package/dist/Breadcrumb/Breadcrumb.css.d.ts +4 -0
  14. package/dist/Breadcrumb/Breadcrumb.d.ts +11 -0
  15. package/dist/Breadcrumb/Breadcrumb.js +10 -0
  16. package/dist/Breadcrumb/Breadcrumb.styles.js +9 -0
  17. package/dist/Breadcrumb/index.d.ts +1 -0
  18. package/dist/Breadcrumb/index.js +1 -0
  19. package/dist/Button/Button.css.d.ts +2 -0
  20. package/dist/Button/Button.d.ts +12 -0
  21. package/dist/Button/Button.js +9 -0
  22. package/dist/Button/Button.styles.js +7 -0
  23. package/dist/Button/index.d.ts +1 -0
  24. package/dist/Button/index.js +1 -0
  25. package/dist/CardPagination/CardPagination.css.d.ts +3 -0
  26. package/dist/CardPagination/CardPagination.d.ts +9 -0
  27. package/dist/CardPagination/CardPagination.js +15 -0
  28. package/dist/CardPagination/CardPagination.styles.js +8 -0
  29. package/dist/CardPagination/index.d.ts +1 -0
  30. package/dist/CardPagination/index.js +1 -0
  31. package/dist/Checkbox/Checkbox.css.d.ts +3 -0
  32. package/dist/Checkbox/Checkbox.d.ts +9 -0
  33. package/dist/Checkbox/Checkbox.js +11 -0
  34. package/dist/Checkbox/Checkbox.styles.js +8 -0
  35. package/dist/Checkbox/index.d.ts +1 -0
  36. package/dist/Checkbox/index.js +1 -0
  37. package/dist/CollapsibleSection/CollapsibleSection.css.d.ts +3 -0
  38. package/dist/CollapsibleSection/CollapsibleSection.d.ts +8 -0
  39. package/dist/CollapsibleSection/CollapsibleSection.js +11 -0
  40. package/dist/CollapsibleSection/CollapsibleSection.styles.js +8 -0
  41. package/dist/CollapsibleSection/index.d.ts +1 -0
  42. package/dist/CollapsibleSection/index.js +1 -0
  43. package/dist/ColorPicker/ColorPicker.constants.d.ts +5 -0
  44. package/dist/ColorPicker/ColorPicker.constants.js +8 -0
  45. package/dist/ColorPicker/ColorPicker.css.d.ts +19 -0
  46. package/dist/ColorPicker/ColorPicker.d.ts +6 -0
  47. package/dist/ColorPicker/ColorPicker.js +55 -0
  48. package/dist/ColorPicker/ColorPicker.styles.js +24 -0
  49. package/dist/ColorPicker/ColorPicker.type.d.ts +8 -0
  50. package/dist/ColorPicker/ColorPicker.utils.d.ts +6 -0
  51. package/dist/ColorPicker/ColorPicker.utils.js +49 -0
  52. package/dist/ColorPicker/NativeColorPicker.d.ts +2 -0
  53. package/dist/ColorPicker/NativeColorPicker.js +13 -0
  54. package/dist/ColorPicker/index.d.ts +1 -0
  55. package/dist/ColorPicker/index.js +1 -0
  56. package/dist/ColorPicker/useColorPanel.d.ts +11 -0
  57. package/dist/ColorPicker/useColorPanel.js +38 -0
  58. package/dist/ColorPicker/useColorWheel.d.ts +18 -0
  59. package/dist/ColorPicker/useColorWheel.js +232 -0
  60. package/dist/ColorRow/ColorRow.css.d.ts +1 -0
  61. package/dist/ColorRow/ColorRow.d.ts +9 -0
  62. package/dist/ColorRow/ColorRow.js +9 -0
  63. package/dist/ColorRow/ColorRow.styles.js +5 -0
  64. package/dist/ColorRow/index.d.ts +1 -0
  65. package/dist/ColorRow/index.js +1 -0
  66. package/dist/ConfirmDialog/ConfirmDialog.css.d.ts +7 -0
  67. package/dist/ConfirmDialog/ConfirmDialog.d.ts +4 -0
  68. package/dist/ConfirmDialog/ConfirmDialog.js +22 -0
  69. package/dist/ConfirmDialog/ConfirmDialog.styles.js +12 -0
  70. package/dist/ConfirmDialog/ConfirmDialog.type.d.ts +9 -0
  71. package/dist/ConfirmDialog/index.d.ts +1 -0
  72. package/dist/ConfirmDialog/index.js +1 -0
  73. package/dist/ContextMenu/ContextMenu.css.d.ts +3 -0
  74. package/dist/ContextMenu/ContextMenu.d.ts +5 -0
  75. package/dist/ContextMenu/ContextMenu.js +16 -0
  76. package/dist/ContextMenu/ContextMenu.styles.js +8 -0
  77. package/dist/ContextMenu/ContextMenu.type.d.ts +11 -0
  78. package/dist/ContextMenu/index.d.ts +1 -0
  79. package/dist/ContextMenu/index.js +1 -0
  80. package/dist/ContextMenu/useContextMenuKeyboard.d.ts +5 -0
  81. package/dist/ContextMenu/useContextMenuKeyboard.js +63 -0
  82. package/dist/ContextMenu/useViewportClamp.d.ts +2 -0
  83. package/dist/ContextMenu/useViewportClamp.js +18 -0
  84. package/dist/DateInput/DateInput.css.d.ts +5 -0
  85. package/dist/DateInput/DateInput.d.ts +11 -0
  86. package/dist/DateInput/DateInput.js +23 -0
  87. package/dist/DateInput/DateInput.styles.js +10 -0
  88. package/dist/DateInput/index.d.ts +1 -0
  89. package/dist/DateInput/index.js +1 -0
  90. package/dist/IconButton/IconButton.css.d.ts +7 -0
  91. package/dist/IconButton/IconButton.d.ts +5 -0
  92. package/dist/IconButton/IconButton.js +22 -0
  93. package/dist/IconButton/IconButton.styles.js +12 -0
  94. package/dist/IconButton/IconButton.type.d.ts +27 -0
  95. package/dist/IconButton/index.d.ts +1 -0
  96. package/dist/IconButton/index.js +1 -0
  97. package/dist/Modal/Modal.css.d.ts +6 -0
  98. package/dist/Modal/Modal.d.ts +4 -0
  99. package/dist/Modal/Modal.js +19 -0
  100. package/dist/Modal/Modal.styles.js +11 -0
  101. package/dist/Modal/Modal.type.d.ts +9 -0
  102. package/dist/Modal/index.d.ts +1 -0
  103. package/dist/Modal/index.js +1 -0
  104. package/dist/NavigationButton/NavigationButton.css.d.ts +1 -0
  105. package/dist/NavigationButton/NavigationButton.d.ts +8 -0
  106. package/dist/NavigationButton/NavigationButton.js +14 -0
  107. package/dist/NavigationButton/NavigationButton.styles.js +6 -0
  108. package/dist/NavigationButton/index.d.ts +1 -0
  109. package/dist/NavigationButton/index.js +1 -0
  110. package/dist/PositionGrid/PositionGrid.css.d.ts +10 -0
  111. package/dist/PositionGrid/PositionGrid.d.ts +5 -0
  112. package/dist/PositionGrid/PositionGrid.js +17 -0
  113. package/dist/PositionGrid/PositionGrid.styles.js +15 -0
  114. package/dist/PositionGrid/PositionGrid.type.d.ts +13 -0
  115. package/dist/PositionGrid/index.d.ts +1 -0
  116. package/dist/PositionGrid/index.js +1 -0
  117. package/dist/RadioGroup/RadioGroup.css.d.ts +3 -0
  118. package/dist/RadioGroup/RadioGroup.d.ts +15 -0
  119. package/dist/RadioGroup/RadioGroup.js +15 -0
  120. package/dist/RadioGroup/RadioGroup.styles.js +8 -0
  121. package/dist/RadioGroup/index.d.ts +1 -0
  122. package/dist/RadioGroup/index.js +1 -0
  123. package/dist/RangeInput/RangeInput.css.d.ts +4 -0
  124. package/dist/RangeInput/RangeInput.d.ts +12 -0
  125. package/dist/RangeInput/RangeInput.js +10 -0
  126. package/dist/RangeInput/RangeInput.styles.js +9 -0
  127. package/dist/RangeInput/index.d.ts +1 -0
  128. package/dist/RangeInput/index.js +1 -0
  129. package/dist/Select/Select.css.d.ts +4 -0
  130. package/dist/Select/Select.d.ts +20 -0
  131. package/dist/Select/Select.js +15 -0
  132. package/dist/Select/Select.styles.js +8 -0
  133. package/dist/Select/index.d.ts +1 -0
  134. package/dist/Select/index.js +1 -0
  135. package/dist/Sidebar/Sidebar.css.d.ts +3 -0
  136. package/dist/Sidebar/Sidebar.d.ts +10 -0
  137. package/dist/Sidebar/Sidebar.js +9 -0
  138. package/dist/Sidebar/Sidebar.styles.js +8 -0
  139. package/dist/Sidebar/index.d.ts +1 -0
  140. package/dist/Sidebar/index.js +1 -0
  141. package/dist/Tabs/Tabs.css.d.ts +5 -0
  142. package/dist/Tabs/Tabs.d.ts +14 -0
  143. package/dist/Tabs/Tabs.js +33 -0
  144. package/dist/Tabs/Tabs.styles.js +10 -0
  145. package/dist/Tabs/index.d.ts +1 -0
  146. package/dist/Tabs/index.js +1 -0
  147. package/dist/TextInput/TextInput.css.d.ts +5 -0
  148. package/dist/TextInput/TextInput.d.ts +17 -0
  149. package/dist/TextInput/TextInput.js +14 -0
  150. package/dist/TextInput/TextInput.styles.js +10 -0
  151. package/dist/TextInput/index.d.ts +1 -0
  152. package/dist/TextInput/index.js +1 -0
  153. package/dist/Toggle/Toggle.css.d.ts +4 -0
  154. package/dist/Toggle/Toggle.d.ts +9 -0
  155. package/dist/Toggle/Toggle.js +14 -0
  156. package/dist/Toggle/Toggle.styles.js +9 -0
  157. package/dist/Toggle/index.d.ts +1 -0
  158. package/dist/Toggle/index.js +1 -0
  159. package/dist/Tree/Tree.css.d.ts +10 -0
  160. package/dist/Tree/Tree.d.ts +4 -0
  161. package/dist/Tree/Tree.js +72 -0
  162. package/dist/Tree/Tree.styles.js +15 -0
  163. package/dist/Tree/Tree.type.d.ts +26 -0
  164. package/dist/Tree/TreeLevel.d.ts +3 -0
  165. package/dist/Tree/TreeLevel.js +42 -0
  166. package/dist/Tree/index.d.ts +1 -0
  167. package/dist/Tree/index.js +1 -0
  168. package/dist/hooks/index.d.ts +2 -0
  169. package/dist/hooks/index.js +2 -0
  170. package/dist/hooks/useBodyScrollLock.d.ts +1 -0
  171. package/dist/hooks/useBodyScrollLock.js +15 -0
  172. package/dist/hooks/useFocusTrap.d.ts +7 -0
  173. package/dist/hooks/useFocusTrap.js +59 -0
  174. package/dist/i18n/I18nProvider.d.ts +8 -0
  175. package/dist/i18n/I18nProvider.js +13 -0
  176. package/dist/i18n/context.d.ts +9 -0
  177. package/dist/i18n/context.js +15 -0
  178. package/dist/i18n/index.d.ts +3 -0
  179. package/dist/i18n/index.js +2 -0
  180. package/dist/i18n/locales/en.d.ts +3 -0
  181. package/dist/i18n/locales/en.js +152 -0
  182. package/dist/i18n/locales/ja.d.ts +3 -0
  183. package/dist/i18n/locales/ja.js +152 -0
  184. package/dist/i18n/locales/ko.d.ts +3 -0
  185. package/dist/i18n/locales/ko.js +152 -0
  186. package/dist/i18n/types.d.ts +3 -0
  187. package/dist/icons/ChevronLeftIcon.d.ts +7 -0
  188. package/dist/icons/ChevronLeftIcon.js +7 -0
  189. package/dist/icons/ChevronRightIcon.d.ts +7 -0
  190. package/dist/icons/ChevronRightIcon.js +7 -0
  191. package/dist/icons/DragHandleIcon.d.ts +7 -0
  192. package/dist/icons/DragHandleIcon.js +7 -0
  193. package/dist/icons/EyeIcon.d.ts +8 -0
  194. package/dist/icons/EyeIcon.js +10 -0
  195. package/dist/icons/FolderIcon.d.ts +7 -0
  196. package/dist/icons/FolderIcon.js +7 -0
  197. package/dist/icons/GearIcon.d.ts +7 -0
  198. package/dist/icons/GearIcon.js +7 -0
  199. package/dist/icons/TriangleDownIcon.d.ts +7 -0
  200. package/dist/icons/TriangleDownIcon.js +7 -0
  201. package/dist/icons/TriangleUpIcon.d.ts +7 -0
  202. package/dist/icons/TriangleUpIcon.js +7 -0
  203. package/dist/icons/index.d.ts +8 -0
  204. package/dist/icons/index.js +8 -0
  205. package/dist/index.d.ts +5 -0
  206. package/dist/index.js +6 -0
  207. package/dist/styles/Badge/Badge.css +22 -0
  208. package/dist/styles/Box/Box.css +20 -0
  209. package/dist/styles/Breadcrumb/Breadcrumb.css +28 -0
  210. package/dist/styles/Button/Button.css +51 -0
  211. package/dist/styles/CardPagination/CardPagination.css +29 -0
  212. package/dist/styles/Checkbox/Checkbox.css +22 -0
  213. package/dist/styles/CollapsibleSection/CollapsibleSection.css +21 -0
  214. package/dist/styles/ColorPicker/ColorPicker.css +153 -0
  215. package/dist/styles/ColorRow/ColorRow.css +9 -0
  216. package/dist/styles/ConfirmDialog/ConfirmDialog.css +52 -0
  217. package/dist/styles/ContextMenu/ContextMenu.css +34 -0
  218. package/dist/styles/DateInput/DateInput.css +47 -0
  219. package/dist/styles/IconButton/IconButton.css +79 -0
  220. package/dist/styles/Modal/Modal.css +58 -0
  221. package/dist/styles/NavigationButton/NavigationButton.css +13 -0
  222. package/dist/styles/PositionGrid/PositionGrid.css +70 -0
  223. package/dist/styles/RadioGroup/RadioGroup.css +26 -0
  224. package/dist/styles/RangeInput/RangeInput.css +33 -0
  225. package/dist/styles/Select/Select.css +39 -0
  226. package/dist/styles/Sidebar/Sidebar.css +18 -0
  227. package/dist/styles/Tabs/Tabs.css +61 -0
  228. package/dist/styles/TextInput/TextInput.css +37 -0
  229. package/dist/styles/Toggle/Toggle.css +46 -0
  230. package/dist/styles/Tree/Tree.css +89 -0
  231. package/dist/styles/tokens.css +13 -0
  232. package/dist/styles/tokens.css.d.ts +15 -0
  233. package/dist/styles/tokens.styles.js +5 -0
  234. package/dist/theme/index.d.ts +2 -0
  235. package/dist/theme/index.js +1 -0
  236. package/dist/theme/presets.d.ts +3 -0
  237. package/dist/theme/presets.js +22 -0
  238. package/dist/theme/types.d.ts +10 -0
  239. package/dist/utils/colorUtils.d.ts +32 -0
  240. package/dist/utils/colorUtils.js +227 -0
  241. package/dist/utils/cssVariable.d.ts +2 -0
  242. package/dist/utils/cssVariable.js +11 -0
  243. package/dist/utils/index.d.ts +2 -0
  244. package/dist/utils/index.js +2 -0
  245. package/package.json +191 -0
@@ -0,0 +1,232 @@
1
+ import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
2
+ import { parseColor, formatColor, slToTrianglePoint, hslToRgb, rgbToHex, cartesianToAngle, clampToTriangle, trianglePointToSL, getTriangleVertices, polarToCartesian, hexToRgb, rgbToHsl } from '../utils/colorUtils.js';
3
+ import { WHEEL_SIZE, INNER_RADIUS, TRIANGLE_RADIUS, RING_WIDTH } from './ColorPicker.constants.js';
4
+ import { detectFormat, drawTriangle, drawIndicator, clamp } from './ColorPicker.utils.js';
5
+
6
+ const CX = WHEEL_SIZE / 2;
7
+ const CY = WHEEL_SIZE / 2;
8
+ function useColorWheel(value, onChange, showAlpha) {
9
+ const [hsla, setHsla] = useState(() => parseColor(value));
10
+ const [format, setFormat] = useState(() => detectFormat(value));
11
+ const dragTarget = useRef(null);
12
+ const canvasRef = useRef(null);
13
+ const hueWheelCache = useRef(null);
14
+ const prevValueRef = useRef(value);
15
+ const alphaTrackRef = useRef(null);
16
+ // Sync external value changes
17
+ useEffect(() => {
18
+ if (value !== prevValueRef.current) {
19
+ prevValueRef.current = value;
20
+ const parsed = parseColor(value);
21
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- syncing external prop to internal state
22
+ setHsla(parsed);
23
+ }
24
+ }, [value]);
25
+ const emit = useCallback((next) => {
26
+ const fmt = showAlpha && next.a < 1 ? (format === "hex" ? "rgba" : format) : format;
27
+ const str = formatColor(next, fmt);
28
+ prevValueRef.current = str;
29
+ onChange(str);
30
+ }, [format, onChange, showAlpha]);
31
+ // --- Canvas rendering ---
32
+ const drawWheel = useCallback(() => {
33
+ const canvas = canvasRef.current;
34
+ if (!canvas)
35
+ return;
36
+ const dpr = window.devicePixelRatio || 1;
37
+ const size = WHEEL_SIZE;
38
+ canvas.width = size * dpr;
39
+ canvas.height = size * dpr;
40
+ const ctx = canvas.getContext("2d");
41
+ if (!ctx)
42
+ return;
43
+ ctx.scale(dpr, dpr);
44
+ ctx.clearRect(0, 0, size, size);
45
+ // Hue ring (cache)
46
+ if (!hueWheelCache.current ||
47
+ hueWheelCache.current.width !== canvas.width) {
48
+ const offscreen = document.createElement("canvas");
49
+ offscreen.width = canvas.width;
50
+ offscreen.height = canvas.height;
51
+ const octx = offscreen.getContext("2d");
52
+ if (!octx)
53
+ return;
54
+ octx.scale(dpr, dpr);
55
+ const outerR = size / 2;
56
+ const cg = octx.createConicGradient(-Math.PI / 2, CX, CY);
57
+ for (let i = 0; i <= 360; i += 1) {
58
+ cg.addColorStop(i / 360, `hsl(${i}, 100%, 50%)`);
59
+ }
60
+ octx.beginPath();
61
+ octx.arc(CX, CY, outerR, 0, Math.PI * 2);
62
+ octx.arc(CX, CY, INNER_RADIUS, 0, Math.PI * 2, true);
63
+ octx.fillStyle = cg;
64
+ octx.fill();
65
+ hueWheelCache.current = octx.getImageData(0, 0, canvas.width, canvas.height);
66
+ }
67
+ ctx.putImageData(hueWheelCache.current, 0, 0);
68
+ // Triangle
69
+ const [v0, v1, v2] = getTriangleVertices(CX, CY, TRIANGLE_RADIUS, 0);
70
+ drawTriangle(ctx, v0, v1, v2, hsla.h);
71
+ // Hue indicator
72
+ const hueAngle = hsla.h - 90;
73
+ const hueR = INNER_RADIUS + RING_WIDTH / 2;
74
+ const hp = polarToCartesian(CX, CY, hueR, hueAngle);
75
+ drawIndicator(ctx, hp.x, hp.y, 7, `hsl(${hsla.h}, 100%, 50%)`);
76
+ // SL indicator
77
+ const slPt = slToTrianglePoint(hsla.s, hsla.l, v0, v1, v2);
78
+ const [ir, ig, ib] = hslToRgb(hsla.h, hsla.s, hsla.l);
79
+ drawIndicator(ctx, slPt.x, slPt.y, 6, rgbToHex(ir, ig, ib));
80
+ }, [hsla.h, hsla.s, hsla.l]);
81
+ // --- Drag helpers ---
82
+ const getCanvasPos = (e) => {
83
+ const canvas = canvasRef.current;
84
+ const rect = canvas.getBoundingClientRect();
85
+ const scaleX = WHEEL_SIZE / rect.width;
86
+ const scaleY = WHEEL_SIZE / rect.height;
87
+ return {
88
+ x: (e.clientX - rect.left) * scaleX,
89
+ y: (e.clientY - rect.top) * scaleY
90
+ };
91
+ };
92
+ const updateHue = useCallback((p) => {
93
+ const angle = cartesianToAngle(p.x - CX, p.y - CY);
94
+ const h = Math.round((angle + 90) % 360);
95
+ setHsla(prev => {
96
+ const next = { ...prev, h };
97
+ queueMicrotask(() => emit(next));
98
+ return next;
99
+ });
100
+ }, [emit]);
101
+ const updateTriangle = useCallback((p) => {
102
+ setHsla(prev => {
103
+ const [v0, v1, v2] = getTriangleVertices(CX, CY, TRIANGLE_RADIUS, 0);
104
+ const clamped = clampToTriangle(p, v0, v1, v2);
105
+ const { s, l } = trianglePointToSL(clamped, v0, v1, v2);
106
+ const next = { ...prev, s, l };
107
+ queueMicrotask(() => emit(next));
108
+ return next;
109
+ });
110
+ }, [emit]);
111
+ const handlePointerDown = (e) => {
112
+ const p = getCanvasPos(e);
113
+ const dx = p.x - CX, dy = p.y - CY;
114
+ const dist = Math.sqrt(dx * dx + dy * dy);
115
+ if (dist >= INNER_RADIUS && dist <= WHEEL_SIZE / 2) {
116
+ dragTarget.current = "hue";
117
+ updateHue(p);
118
+ }
119
+ else if (dist < INNER_RADIUS) {
120
+ dragTarget.current = "triangle";
121
+ updateTriangle(p);
122
+ }
123
+ canvasRef.current.setPointerCapture(e.pointerId);
124
+ };
125
+ const handlePointerMove = (e) => {
126
+ if (!dragTarget.current)
127
+ return;
128
+ const p = getCanvasPos(e);
129
+ if (dragTarget.current === "hue")
130
+ updateHue(p);
131
+ else if (dragTarget.current === "triangle")
132
+ updateTriangle(p);
133
+ };
134
+ const handlePointerUp = () => {
135
+ dragTarget.current = null;
136
+ };
137
+ // --- Alpha slider ---
138
+ const updateAlphaFromEvent = (e) => {
139
+ const track = alphaTrackRef.current;
140
+ const rect = track.getBoundingClientRect();
141
+ const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
142
+ const a = Math.round(ratio * 100) / 100;
143
+ setHsla(prev => {
144
+ const next = { ...prev, a };
145
+ queueMicrotask(() => emit(next));
146
+ return next;
147
+ });
148
+ };
149
+ const handleAlphaPointerDown = (e) => {
150
+ dragTarget.current = "alpha";
151
+ alphaTrackRef.current.setPointerCapture(e.pointerId);
152
+ updateAlphaFromEvent(e);
153
+ };
154
+ const handleAlphaPointerMove = (e) => {
155
+ if (dragTarget.current !== "alpha")
156
+ return;
157
+ updateAlphaFromEvent(e);
158
+ };
159
+ // --- Format input ---
160
+ const handleFieldChange = (field, raw) => {
161
+ const val = parseFloat(raw);
162
+ if (isNaN(val))
163
+ return;
164
+ let next = { ...hsla };
165
+ if (format === "hsla") {
166
+ if (field === "h")
167
+ next.h = clamp(val, 0, 360);
168
+ else if (field === "s")
169
+ next.s = clamp(val, 0, 100);
170
+ else if (field === "l")
171
+ next.l = clamp(val, 0, 100);
172
+ else if (field === "a")
173
+ next.a = clamp(val, 0, 1);
174
+ }
175
+ else if (format === "rgba") {
176
+ const [r, g, b] = hslToRgb(next.h, next.s, next.l);
177
+ let nr = r, ng = g, nb = b;
178
+ if (field === "r")
179
+ nr = clamp(val, 0, 255);
180
+ else if (field === "g")
181
+ ng = clamp(val, 0, 255);
182
+ else if (field === "b")
183
+ nb = clamp(val, 0, 255);
184
+ else if (field === "a") {
185
+ next.a = clamp(val, 0, 1);
186
+ setHsla(next);
187
+ emit(next);
188
+ return;
189
+ }
190
+ const [h, s, l] = rgbToHsl(nr, ng, nb);
191
+ // preserve hue when achromatic
192
+ next = { h: s === 0 ? next.h : h, s, l, a: next.a };
193
+ }
194
+ setHsla(next);
195
+ emit(next);
196
+ };
197
+ const handleHexInput = (raw) => {
198
+ const cleaned = raw.startsWith("#") ? raw : `#${raw}`;
199
+ if (!/^#[0-9a-fA-F]{6}$/.test(cleaned))
200
+ return;
201
+ const [r, g, b] = hexToRgb(cleaned);
202
+ const [h, s, l] = rgbToHsl(r, g, b);
203
+ const next = { h: s === 0 ? hsla.h : h, s, l, a: hsla.a };
204
+ setHsla(next);
205
+ emit(next);
206
+ };
207
+ // --- Display ---
208
+ const displayValue = formatColor(hsla, showAlpha ? (format === "hex" ? "rgba" : format) : format);
209
+ const swatchColor = useMemo(() => {
210
+ const [r, g, b] = hslToRgb(hsla.h, hsla.s, hsla.l);
211
+ return `rgba(${r}, ${g}, ${b}, ${hsla.a})`;
212
+ }, [hsla.h, hsla.s, hsla.l, hsla.a]);
213
+ return {
214
+ hsla,
215
+ format,
216
+ setFormat,
217
+ displayValue,
218
+ swatchColor,
219
+ canvasRef,
220
+ alphaTrackRef,
221
+ drawWheel,
222
+ handlePointerDown,
223
+ handlePointerMove,
224
+ handlePointerUp,
225
+ handleAlphaPointerDown,
226
+ handleAlphaPointerMove,
227
+ handleFieldChange,
228
+ handleHexInput
229
+ };
230
+ }
231
+
232
+ export { useColorWheel };
@@ -0,0 +1 @@
1
+ export declare const colorRow: string;
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export type ColorRowProps = {
3
+ label: string;
4
+ value: string;
5
+ showAlpha?: boolean;
6
+ onChange: (color: string) => void;
7
+ };
8
+ declare function ColorRow({ label, value, showAlpha, onChange }: ColorRowProps): React.ReactElement;
9
+ export { ColorRow };
@@ -0,0 +1,9 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { ColorPicker as MemoizedColorPicker } from '../ColorPicker/ColorPicker.js';
3
+ import { colorRow } from './ColorRow.styles.js';
4
+
5
+ function ColorRow({ label, value, showAlpha, onChange }) {
6
+ return (jsxs("div", { className: colorRow, children: [jsx("span", { children: label }), jsx(MemoizedColorPicker, { value: value, showAlpha: showAlpha, onChange: onChange })] }));
7
+ }
8
+
9
+ export { ColorRow };
@@ -0,0 +1,5 @@
1
+ import './../styles/ColorRow/ColorRow.css';
2
+
3
+ var colorRow = 'ColorRow_colorRow__1oalhfi0';
4
+
5
+ export { colorRow };
@@ -0,0 +1 @@
1
+ export { ColorRow, type ColorRowProps } from "./ColorRow";
@@ -0,0 +1 @@
1
+ export { ColorRow } from './ColorRow.js';
@@ -0,0 +1,7 @@
1
+ export declare const overlay: string;
2
+ export declare const dialog: string;
3
+ export declare const title: string;
4
+ export declare const message: string;
5
+ export declare const actions: string;
6
+ export declare const cancelButton: string;
7
+ export declare const confirmButton: string;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import type { ConfirmDialogProps } from "./ConfirmDialog.type";
3
+ export type { ConfirmDialogProps };
4
+ export declare function ConfirmDialog({ isOpen, onConfirm, onCancel, title, message, confirmLabel: confirmLabelProp, cancelLabel: cancelLabelProp }: ConfirmDialogProps): React.ReactElement | null;
@@ -0,0 +1,22 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useId } from 'react';
3
+ import { useTranslation } from '../i18n/context.js';
4
+ import { useFocusTrap } from '../hooks/useFocusTrap.js';
5
+ import { overlay, dialog, title, message, actions, cancelButton, confirmButton } from './ConfirmDialog.styles.js';
6
+
7
+ function ConfirmDialog({ isOpen, onConfirm, onCancel, title: title$1, message: message$1, confirmLabel: confirmLabelProp, cancelLabel: cancelLabelProp }) {
8
+ const { t } = useTranslation();
9
+ const messageId = useId();
10
+ const dialogRef = useFocusTrap({
11
+ enabled: isOpen,
12
+ onEscape: onCancel,
13
+ initialFocusSelector: `.${cancelButton}`
14
+ });
15
+ const confirmLabel = confirmLabelProp ?? t("confirmDialog.confirm");
16
+ const cancelLabel = cancelLabelProp ?? t("confirmDialog.cancel");
17
+ if (!isOpen)
18
+ return null;
19
+ return (jsx("div", { className: overlay, onClick: onCancel, children: jsxs("div", { ref: dialogRef, className: dialog, onClick: e => e.stopPropagation(), role: "alertdialog", "aria-modal": "true", "aria-describedby": messageId, children: [jsx("h3", { className: title, children: title$1 }), jsx("p", { id: messageId, className: message, children: message$1 }), jsxs("div", { className: actions, children: [jsx("button", { className: cancelButton, onClick: onCancel, children: cancelLabel }), jsx("button", { className: confirmButton, onClick: onConfirm, children: confirmLabel })] })] }) }));
20
+ }
21
+
22
+ export { ConfirmDialog };
@@ -0,0 +1,12 @@
1
+ import './../styles/tokens.css';
2
+ import './../styles/ConfirmDialog/ConfirmDialog.css';
3
+
4
+ var actions = 'ConfirmDialog_actions__115b6yi4';
5
+ var cancelButton = 'ConfirmDialog_cancelButton__115b6yi6 ConfirmDialog_actionButtonBase__115b6yi5';
6
+ var confirmButton = 'ConfirmDialog_confirmButton__115b6yi7 ConfirmDialog_actionButtonBase__115b6yi5';
7
+ var dialog = 'ConfirmDialog_dialog__115b6yi1';
8
+ var message = 'ConfirmDialog_message__115b6yi3';
9
+ var overlay = 'ConfirmDialog_overlay__115b6yi0';
10
+ var title = 'ConfirmDialog_title__115b6yi2';
11
+
12
+ export { actions, cancelButton, confirmButton, dialog, message, overlay, title };
@@ -0,0 +1,9 @@
1
+ export type ConfirmDialogProps = {
2
+ isOpen: boolean;
3
+ onConfirm: () => void;
4
+ onCancel: () => void;
5
+ title: string;
6
+ message: string;
7
+ confirmLabel?: string;
8
+ cancelLabel?: string;
9
+ };
@@ -0,0 +1 @@
1
+ export { ConfirmDialog, type ConfirmDialogProps } from "./ConfirmDialog";
@@ -0,0 +1 @@
1
+ export { ConfirmDialog } from './ConfirmDialog.js';
@@ -0,0 +1,3 @@
1
+ export declare const contextMenu: string;
2
+ export declare const contextMenuItem: string;
3
+ export declare const deleteVariant: string;
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ import type { ContextMenuItem, ContextMenuProps } from "./ContextMenu.type";
3
+ export type { ContextMenuItem, ContextMenuProps };
4
+ declare function ContextMenu({ x, y, items, onClose }: ContextMenuProps): React.ReactElement;
5
+ export { ContextMenu };
@@ -0,0 +1,16 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { clsx } from 'clsx';
3
+ import { useContextMenuKeyboard } from './useContextMenuKeyboard.js';
4
+ import { useViewportClamp } from './useViewportClamp.js';
5
+ import { contextMenu, contextMenuItem, deleteVariant } from './ContextMenu.styles.js';
6
+
7
+ function ContextMenu({ x, y, items, onClose }) {
8
+ const { menuRef, handleKeyDown } = useContextMenuKeyboard(onClose);
9
+ useViewportClamp(menuRef, x, y);
10
+ return (jsx("div", { ref: menuRef, className: contextMenu, style: { left: x, top: y }, role: "menu", onKeyDown: handleKeyDown, children: items.map((item, index) => (jsx("button", { role: "menuitem", tabIndex: -1, onClick: () => {
11
+ item.onClick();
12
+ onClose?.();
13
+ }, className: clsx(contextMenuItem, item.variant === "danger" && deleteVariant), children: item.label }, index))) }));
14
+ }
15
+
16
+ export { ContextMenu };
@@ -0,0 +1,8 @@
1
+ import './../styles/tokens.css';
2
+ import './../styles/ContextMenu/ContextMenu.css';
3
+
4
+ var contextMenu = 'ContextMenu_contextMenu__1hifssv0';
5
+ var contextMenuItem = 'ContextMenu_contextMenuItem__1hifssv1';
6
+ var deleteVariant = 'ContextMenu_deleteVariant__1hifssv2';
7
+
8
+ export { contextMenu, contextMenuItem, deleteVariant };
@@ -0,0 +1,11 @@
1
+ export type ContextMenuItem = {
2
+ label: string;
3
+ onClick: () => void;
4
+ variant?: "default" | "danger";
5
+ };
6
+ export type ContextMenuProps = {
7
+ x: number;
8
+ y: number;
9
+ items: ContextMenuItem[];
10
+ onClose?: () => void;
11
+ };
@@ -0,0 +1 @@
1
+ export { ContextMenu, type ContextMenuProps, type ContextMenuItem } from "./ContextMenu";
@@ -0,0 +1 @@
1
+ export { ContextMenu } from './ContextMenu.js';
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ export declare function useContextMenuKeyboard(onClose?: () => void): {
3
+ menuRef: React.RefObject<HTMLDivElement | null>;
4
+ handleKeyDown: (e: React.KeyboardEvent) => void;
5
+ };
@@ -0,0 +1,63 @@
1
+ import { useRef, useEffect } from 'react';
2
+
3
+ function useContextMenuKeyboard(onClose) {
4
+ const menuRef = useRef(null);
5
+ // Auto-focus first item
6
+ useEffect(() => {
7
+ const firstItem = menuRef.current?.querySelector('[role="menuitem"]');
8
+ firstItem?.focus();
9
+ }, []);
10
+ // Close on outside click
11
+ useEffect(() => {
12
+ const handleMouseDown = (e) => {
13
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
14
+ onClose?.();
15
+ }
16
+ };
17
+ document.addEventListener("mousedown", handleMouseDown);
18
+ return () => document.removeEventListener("mousedown", handleMouseDown);
19
+ }, [onClose]);
20
+ const handleKeyDown = (e) => {
21
+ const focusable = menuRef.current?.querySelectorAll('[role="menuitem"]');
22
+ if (!focusable || focusable.length === 0)
23
+ return;
24
+ const focusableItems = Array.from(focusable);
25
+ const currentIndex = focusableItems.indexOf(document.activeElement);
26
+ switch (e.key) {
27
+ case "ArrowDown": {
28
+ e.preventDefault();
29
+ const next = (currentIndex + 1) % focusableItems.length;
30
+ focusableItems[next].focus();
31
+ break;
32
+ }
33
+ case "ArrowUp": {
34
+ e.preventDefault();
35
+ const prev = (currentIndex - 1 + focusableItems.length) % focusableItems.length;
36
+ focusableItems[prev].focus();
37
+ break;
38
+ }
39
+ case "Home":
40
+ e.preventDefault();
41
+ focusableItems[0].focus();
42
+ break;
43
+ case "End":
44
+ e.preventDefault();
45
+ focusableItems[focusableItems.length - 1].focus();
46
+ break;
47
+ case "Escape":
48
+ e.preventDefault();
49
+ onClose?.();
50
+ break;
51
+ case "Enter": {
52
+ e.preventDefault();
53
+ if (currentIndex >= 0) {
54
+ focusableItems[currentIndex].click();
55
+ }
56
+ break;
57
+ }
58
+ }
59
+ };
60
+ return { menuRef, handleKeyDown };
61
+ }
62
+
63
+ export { useContextMenuKeyboard };
@@ -0,0 +1,2 @@
1
+ import { type RefObject } from "react";
2
+ export declare function useViewportClamp(ref: RefObject<HTMLElement | null>, x: number, y: number): void;
@@ -0,0 +1,18 @@
1
+ import { useEffect } from 'react';
2
+
3
+ function useViewportClamp(ref, x, y) {
4
+ useEffect(() => {
5
+ const el = ref.current;
6
+ if (!el)
7
+ return;
8
+ const rect = el.getBoundingClientRect();
9
+ if (rect.right > window.innerWidth) {
10
+ el.style.left = `${x - (rect.right - window.innerWidth)}px`;
11
+ }
12
+ if (rect.bottom > window.innerHeight) {
13
+ el.style.top = `${y - (rect.bottom - window.innerHeight)}px`;
14
+ }
15
+ }, [ref, x, y]);
16
+ }
17
+
18
+ export { useViewportClamp };
@@ -0,0 +1,5 @@
1
+ export declare const input: string;
2
+ export declare const inputError: string;
3
+ export declare const segment: string;
4
+ export declare const separator: string;
5
+ export declare const nativeInput: string;
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ export type DateInputProps = {
3
+ value: string;
4
+ onChange: (value: string) => void;
5
+ onFocus?: () => void;
6
+ min?: string;
7
+ max?: string;
8
+ className?: string;
9
+ hasError?: boolean;
10
+ };
11
+ export declare function DateInput({ value, onChange, onFocus, min, max, className, hasError }: DateInputProps): React.ReactElement;
@@ -0,0 +1,23 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useRef, useCallback } from 'react';
3
+ import clsx from 'clsx';
4
+ import { segment, separator, nativeInput, input, inputError } from './DateInput.styles.js';
5
+
6
+ function parse(value) {
7
+ const [y, m, d] = value.split("-").map(Number);
8
+ return { year: y || 0, month: m || 0, day: d || 0 };
9
+ }
10
+ function DateInput({ value, onChange, onFocus, min, max, className, hasError }) {
11
+ const nativeRef = useRef(null);
12
+ const { year, month, day } = parse(value);
13
+ const handleNativeChange = useCallback((e) => {
14
+ if (e.target.value)
15
+ onChange(e.target.value);
16
+ }, [onChange]);
17
+ const handleClick = useCallback(() => {
18
+ nativeRef.current?.showPicker();
19
+ }, []);
20
+ return (jsxs("div", { className: clsx(input, hasError && inputError, className), onClick: handleClick, children: [jsx("span", { className: segment, children: year || "YYYY" }), jsx("span", { className: separator, children: "." }), jsx("span", { className: segment, children: month || "MM" }), jsx("span", { className: separator, children: "." }), jsx("span", { className: segment, children: day || "DD" }), jsx("input", { ref: nativeRef, type: "date", className: nativeInput, value: value, min: min, max: max, onChange: handleNativeChange, onFocus: onFocus, tabIndex: -1, "aria-hidden": true })] }));
21
+ }
22
+
23
+ export { DateInput };
@@ -0,0 +1,10 @@
1
+ import './../styles/tokens.css';
2
+ import './../styles/DateInput/DateInput.css';
3
+
4
+ var input = 'DateInput_input__1p13e9q0';
5
+ var inputError = 'DateInput_inputError__1p13e9q1';
6
+ var nativeInput = 'DateInput_nativeInput__1p13e9q4';
7
+ var segment = 'DateInput_segment__1p13e9q2';
8
+ var separator = 'DateInput_separator__1p13e9q3';
9
+
10
+ export { input, inputError, nativeInput, segment, separator };
@@ -0,0 +1 @@
1
+ export { DateInput, type DateInputProps } from "./DateInput";
@@ -0,0 +1 @@
1
+ export { DateInput } from './DateInput.js';
@@ -0,0 +1,7 @@
1
+ export declare const IconButton: string;
2
+ export declare const icon: string;
3
+ export declare const hasIcon: string;
4
+ export declare const name: string;
5
+ export declare const horizontal: string;
6
+ export declare const folder: string;
7
+ export declare const empty: string;
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ import type { IconButtonProps } from "./IconButton.type";
3
+ export type { IconButtonProps };
4
+ declare const IconButton: React.NamedExoticComponent<IconButtonProps>;
5
+ export { IconButton };
@@ -0,0 +1,22 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { useTranslation } from '../i18n/context.js';
5
+ import { icon, hasIcon, name, IconButton as IconButton$1, folder, horizontal, empty } from './IconButton.styles.js';
6
+
7
+ const IconButton = React.memo(function IconButton(props) {
8
+ const { type, onClick, layout } = props;
9
+ const isHorizontal = layout === "horizontal";
10
+ const { t } = useTranslation();
11
+ if (type === "folder") {
12
+ const { name: name$1, iconUrl, onContextMenu, bookmarkId, folderKey } = props;
13
+ return (jsxs("button", { className: clsx(IconButton$1, folder, isHorizontal && horizontal), onClick: onClick, onContextMenu: e => onContextMenu ? onContextMenu(e) : e.preventDefault(), "aria-label": name$1, "data-bookmark-id": bookmarkId, "data-folder-key": folderKey, children: [jsx("div", { className: clsx(icon, iconUrl && hasIcon), children: iconUrl ? (jsx("img", { src: iconUrl, alt: name$1 })) : (jsx("svg", { width: "60%", height: "60%", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: jsx("path", { d: "M3 7V17C3 18.1046 3.89543 19 5 19H19C20.1046 19 21 18.1046 21 17V9C21 7.89543 20.1046 7 19 7H12L10 5H5C3.89543 5 3 5.89543 3 7Z", fill: "currentColor", opacity: "0.25", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })) }), jsx("span", { className: name, children: name$1 })] }));
14
+ }
15
+ if (type === "empty") {
16
+ return (jsxs("button", { className: clsx(IconButton$1, empty, isHorizontal && horizontal), onClick: onClick, onContextMenu: e => e.preventDefault(), "aria-label": t("iconButton.add"), children: [jsx("div", { className: icon, children: "+" }), jsx("span", { className: name, children: t("iconButton.add") })] }));
17
+ }
18
+ const { iconUrl, name: name$1, onContextMenu, bookmarkId, url, folderKey } = props;
19
+ return (jsxs("button", { className: clsx(IconButton$1, isHorizontal && horizontal), onClick: onClick, onContextMenu: e => onContextMenu ? onContextMenu(e) : e.preventDefault(), "aria-label": name$1, "data-bookmark-id": bookmarkId, "data-url": url, "data-folder-key": folderKey, children: [jsx("div", { className: clsx(icon, iconUrl && hasIcon), children: iconUrl ? (jsx("img", { src: iconUrl, alt: name$1 })) : (name$1.charAt(0).toUpperCase()) }), jsx("span", { className: name, children: name$1 })] }));
20
+ });
21
+
22
+ export { IconButton };
@@ -0,0 +1,12 @@
1
+ import './../styles/tokens.css';
2
+ import './../styles/IconButton/IconButton.css';
3
+
4
+ var IconButton = 'IconButton_IconButton__18setjd0';
5
+ var empty = 'IconButton_empty__18setjd6';
6
+ var folder = 'IconButton_folder__18setjd5';
7
+ var hasIcon = 'IconButton_hasIcon__18setjd2';
8
+ var horizontal = 'IconButton_horizontal__18setjd4';
9
+ var icon = 'IconButton_icon__18setjd1';
10
+ var name = 'IconButton_name__18setjd3';
11
+
12
+ export { IconButton, empty, folder, hasIcon, horizontal, icon, name };
@@ -0,0 +1,27 @@
1
+ import type React from "react";
2
+ type BaseIconButtonProps = {
3
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
4
+ layout?: "vertical" | "horizontal";
5
+ };
6
+ type NormalIconButtonProps = BaseIconButtonProps & {
7
+ type: "normal";
8
+ iconUrl?: string;
9
+ name: string;
10
+ bookmarkId?: string;
11
+ url?: string;
12
+ folderKey?: string;
13
+ onContextMenu?: (e: React.MouseEvent) => void;
14
+ };
15
+ type FolderIconButtonProps = BaseIconButtonProps & {
16
+ type: "folder";
17
+ name: string;
18
+ iconUrl?: string;
19
+ bookmarkId?: string;
20
+ folderKey?: string;
21
+ onContextMenu?: (e: React.MouseEvent) => void;
22
+ };
23
+ type EmptyIconButtonProps = BaseIconButtonProps & {
24
+ type: "empty";
25
+ };
26
+ export type IconButtonProps = NormalIconButtonProps | FolderIconButtonProps | EmptyIconButtonProps;
27
+ export {};
@@ -0,0 +1 @@
1
+ export { IconButton, type IconButtonProps } from "./IconButton";
@@ -0,0 +1 @@
1
+ export { IconButton } from './IconButton.js';
@@ -0,0 +1,6 @@
1
+ export declare const overlay: string;
2
+ export declare const modal: Record<"sm" | "md" | "lg", string>;
3
+ export declare const header: string;
4
+ export declare const title: string;
5
+ export declare const closeButton: string;
6
+ export declare const body: string;