chroma-panel 0.1.0

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 (202) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +119 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  4. package/dist/a11y/contrast.cjs +107 -0
  5. package/dist/a11y/contrast.d.cts +34 -0
  6. package/dist/a11y/contrast.d.ts +34 -0
  7. package/dist/a11y/contrast.js +101 -0
  8. package/dist/color/convert.cjs +162 -0
  9. package/dist/color/convert.d.cts +16 -0
  10. package/dist/color/convert.d.ts +16 -0
  11. package/dist/color/convert.js +153 -0
  12. package/dist/color/parse.cjs +153 -0
  13. package/dist/color/parse.d.cts +7 -0
  14. package/dist/color/parse.d.ts +7 -0
  15. package/dist/color/parse.js +151 -0
  16. package/dist/color/serialize.cjs +79 -0
  17. package/dist/color/serialize.d.cts +11 -0
  18. package/dist/color/serialize.d.ts +11 -0
  19. package/dist/color/serialize.js +73 -0
  20. package/dist/color/sticky.cjs +20 -0
  21. package/dist/color/sticky.d.cts +6 -0
  22. package/dist/color/sticky.d.ts +6 -0
  23. package/dist/color/sticky.js +19 -0
  24. package/dist/color/types.d.cts +43 -0
  25. package/dist/color/types.d.ts +43 -0
  26. package/dist/components/ChromaPanel.cjs +254 -0
  27. package/dist/components/ChromaPanel.d.cts +47 -0
  28. package/dist/components/ChromaPanel.d.ts +47 -0
  29. package/dist/components/ChromaPanel.js +251 -0
  30. package/dist/components/ColorInput.cjs +128 -0
  31. package/dist/components/ColorInput.d.cts +19 -0
  32. package/dist/components/ColorInput.d.ts +19 -0
  33. package/dist/components/ColorInput.js +127 -0
  34. package/dist/components/ModeToolbar.cjs +33 -0
  35. package/dist/components/ModeToolbar.d.cts +10 -0
  36. package/dist/components/ModeToolbar.d.ts +10 -0
  37. package/dist/components/ModeToolbar.js +32 -0
  38. package/dist/components/PanelFooter.cjs +82 -0
  39. package/dist/components/PanelFooter.d.cts +5 -0
  40. package/dist/components/PanelFooter.d.ts +5 -0
  41. package/dist/components/PanelFooter.js +80 -0
  42. package/dist/components/Popover.cjs +154 -0
  43. package/dist/components/Popover.d.cts +13 -0
  44. package/dist/components/Popover.d.ts +13 -0
  45. package/dist/components/Popover.js +153 -0
  46. package/dist/contrast.cjs +10 -0
  47. package/dist/contrast.d.cts +2 -0
  48. package/dist/contrast.d.ts +2 -0
  49. package/dist/contrast.js +2 -0
  50. package/dist/core/context.cjs +30 -0
  51. package/dist/core/context.d.cts +43 -0
  52. package/dist/core/context.d.ts +43 -0
  53. package/dist/core/context.js +26 -0
  54. package/dist/core/dev.cjs +11 -0
  55. package/dist/core/dev.js +11 -0
  56. package/dist/core/store.cjs +43 -0
  57. package/dist/core/store.d.cts +17 -0
  58. package/dist/core/store.d.ts +17 -0
  59. package/dist/core/store.js +44 -0
  60. package/dist/core/styleInjector.cjs +38 -0
  61. package/dist/core/styleInjector.d.cts +4 -0
  62. package/dist/core/styleInjector.d.ts +4 -0
  63. package/dist/core/styleInjector.js +38 -0
  64. package/dist/core/useColorStore.cjs +43 -0
  65. package/dist/core/useColorStore.d.cts +6 -0
  66. package/dist/core/useColorStore.d.ts +6 -0
  67. package/dist/core/useColorStore.js +41 -0
  68. package/dist/core/useFormControl.cjs +87 -0
  69. package/dist/core/useFormControl.js +82 -0
  70. package/dist/core/useMediaQuery.cjs +48 -0
  71. package/dist/core/useMediaQuery.js +46 -0
  72. package/dist/core/usePointerDrag.cjs +177 -0
  73. package/dist/core/usePointerDrag.d.cts +35 -0
  74. package/dist/core/usePointerDrag.d.ts +35 -0
  75. package/dist/core/usePointerDrag.js +175 -0
  76. package/dist/core/useScrollFade.cjs +44 -0
  77. package/dist/core/useScrollFade.js +43 -0
  78. package/dist/core.cjs +33 -0
  79. package/dist/core.d.cts +7 -0
  80. package/dist/core.d.ts +7 -0
  81. package/dist/core.js +6 -0
  82. package/dist/data/defaults.cjs +123 -0
  83. package/dist/data/defaults.d.cts +6 -0
  84. package/dist/data/defaults.d.ts +6 -0
  85. package/dist/data/defaults.js +122 -0
  86. package/dist/data/namedColors.cjs +11 -0
  87. package/dist/data/namedColors.d.cts +3 -0
  88. package/dist/data/namedColors.d.ts +3 -0
  89. package/dist/data/namedColors.js +12 -0
  90. package/dist/image/extract.cjs +98 -0
  91. package/dist/image/extract.d.cts +16 -0
  92. package/dist/image/extract.d.ts +16 -0
  93. package/dist/image/extract.js +99 -0
  94. package/dist/image/mmcq.cjs +182 -0
  95. package/dist/image/mmcq.d.cts +8 -0
  96. package/dist/image/mmcq.d.ts +8 -0
  97. package/dist/image/mmcq.js +183 -0
  98. package/dist/image-worker.js +202 -0
  99. package/dist/image.cjs +12 -0
  100. package/dist/image.d.cts +4 -0
  101. package/dist/image.d.ts +4 -0
  102. package/dist/image.js +9 -0
  103. package/dist/index.cjs +119 -0
  104. package/dist/index.d.cts +36 -0
  105. package/dist/index.d.ts +36 -0
  106. package/dist/index.js +44 -0
  107. package/dist/modes/gradients.cjs +48 -0
  108. package/dist/modes/gradients.js +43 -0
  109. package/dist/modes/image/index.cjs +193 -0
  110. package/dist/modes/image/index.d.cts +10 -0
  111. package/dist/modes/image/index.d.ts +10 -0
  112. package/dist/modes/image/index.js +191 -0
  113. package/dist/modes/palettes/index.cjs +76 -0
  114. package/dist/modes/palettes/index.d.cts +6 -0
  115. package/dist/modes/palettes/index.d.ts +6 -0
  116. package/dist/modes/palettes/index.js +74 -0
  117. package/dist/modes/pencils/index.cjs +36 -0
  118. package/dist/modes/pencils/index.d.cts +6 -0
  119. package/dist/modes/pencils/index.d.ts +6 -0
  120. package/dist/modes/pencils/index.js +34 -0
  121. package/dist/modes/registry.cjs +26 -0
  122. package/dist/modes/registry.d.cts +13 -0
  123. package/dist/modes/registry.d.ts +13 -0
  124. package/dist/modes/registry.js +25 -0
  125. package/dist/modes/sliders/index.cjs +300 -0
  126. package/dist/modes/sliders/index.d.cts +6 -0
  127. package/dist/modes/sliders/index.d.ts +6 -0
  128. package/dist/modes/sliders/index.js +298 -0
  129. package/dist/modes/wheel/index.cjs +62 -0
  130. package/dist/modes/wheel/index.d.cts +6 -0
  131. package/dist/modes/wheel/index.d.ts +6 -0
  132. package/dist/modes/wheel/index.js +60 -0
  133. package/dist/named-colors.cjs +3 -0
  134. package/dist/named-colors.d.cts +2 -0
  135. package/dist/named-colors.d.ts +2 -0
  136. package/dist/named-colors.js +2 -0
  137. package/dist/palettes.cjs +8 -0
  138. package/dist/palettes.d.cts +2 -0
  139. package/dist/palettes.d.ts +2 -0
  140. package/dist/palettes.js +7 -0
  141. package/dist/panel.cjs +80 -0
  142. package/dist/panel.d.cts +27 -0
  143. package/dist/panel.d.ts +27 -0
  144. package/dist/panel.js +27 -0
  145. package/dist/pencils.cjs +8 -0
  146. package/dist/pencils.d.cts +2 -0
  147. package/dist/pencils.d.ts +2 -0
  148. package/dist/pencils.js +7 -0
  149. package/dist/primitives/AxisInput.cjs +26 -0
  150. package/dist/primitives/AxisInput.js +25 -0
  151. package/dist/primitives/ChannelSlider.cjs +94 -0
  152. package/dist/primitives/ChannelSlider.d.cts +18 -0
  153. package/dist/primitives/ChannelSlider.d.ts +18 -0
  154. package/dist/primitives/ChannelSlider.js +93 -0
  155. package/dist/primitives/ColorArea.cjs +85 -0
  156. package/dist/primitives/ColorArea.d.cts +8 -0
  157. package/dist/primitives/ColorArea.d.ts +8 -0
  158. package/dist/primitives/ColorArea.js +84 -0
  159. package/dist/primitives/ColorDisc.cjs +95 -0
  160. package/dist/primitives/ColorDisc.d.cts +8 -0
  161. package/dist/primitives/ColorDisc.d.ts +8 -0
  162. package/dist/primitives/ColorDisc.js +94 -0
  163. package/dist/primitives/ColorField.cjs +68 -0
  164. package/dist/primitives/ColorField.d.cts +9 -0
  165. package/dist/primitives/ColorField.d.ts +9 -0
  166. package/dist/primitives/ColorField.js +67 -0
  167. package/dist/primitives/NumberField.cjs +65 -0
  168. package/dist/primitives/NumberField.d.cts +14 -0
  169. package/dist/primitives/NumberField.d.ts +14 -0
  170. package/dist/primitives/NumberField.js +64 -0
  171. package/dist/primitives/SegmentedControl.cjs +66 -0
  172. package/dist/primitives/SegmentedControl.d.cts +21 -0
  173. package/dist/primitives/SegmentedControl.d.ts +21 -0
  174. package/dist/primitives/SegmentedControl.js +65 -0
  175. package/dist/primitives/Swatch.cjs +22 -0
  176. package/dist/primitives/Swatch.d.cts +13 -0
  177. package/dist/primitives/Swatch.d.ts +13 -0
  178. package/dist/primitives/Swatch.js +21 -0
  179. package/dist/primitives/SwatchGrid.cjs +63 -0
  180. package/dist/primitives/SwatchGrid.d.cts +17 -0
  181. package/dist/primitives/SwatchGrid.d.ts +17 -0
  182. package/dist/primitives/SwatchGrid.js +62 -0
  183. package/dist/primitives/icons.cjs +149 -0
  184. package/dist/primitives/icons.d.cts +9 -0
  185. package/dist/primitives/icons.d.ts +9 -0
  186. package/dist/primitives/icons.js +141 -0
  187. package/dist/primitives/useEyedropper.cjs +30 -0
  188. package/dist/primitives/useEyedropper.d.cts +7 -0
  189. package/dist/primitives/useEyedropper.d.ts +7 -0
  190. package/dist/primitives/useEyedropper.js +29 -0
  191. package/dist/sliders.cjs +8 -0
  192. package/dist/sliders.d.cts +2 -0
  193. package/dist/sliders.d.ts +2 -0
  194. package/dist/sliders.js +7 -0
  195. package/dist/style.css +2 -0
  196. package/dist/styles/css.cjs +4 -0
  197. package/dist/styles/css.js +5 -0
  198. package/dist/wheel.cjs +8 -0
  199. package/dist/wheel.d.cts +2 -0
  200. package/dist/wheel.d.ts +2 -0
  201. package/dist/wheel.js +7 -0
  202. package/package.json +222 -0
@@ -0,0 +1,43 @@
1
+ //#region src/color/types.d.ts
2
+ export interface Hsva {
3
+ h: number;
4
+ s: number;
5
+ v: number;
6
+ a: number;
7
+ }
8
+ export interface Rgb {
9
+ r: number;
10
+ g: number;
11
+ b: number;
12
+ }
13
+ export interface Rgba extends Rgb {
14
+ a: number;
15
+ }
16
+ export interface Hsl {
17
+ h: number;
18
+ s: number;
19
+ l: number;
20
+ }
21
+ export interface Hsla extends Hsl {
22
+ a: number;
23
+ }
24
+ export interface Hwb {
25
+ h: number;
26
+ w: number;
27
+ b: number;
28
+ }
29
+ export interface Hwba extends Hwb {
30
+ a: number;
31
+ }
32
+ export type ColorFormat = "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla";
33
+ export interface ColorChangeResult {
34
+ hex: string;
35
+ hexa: string;
36
+ rgb: Rgb;
37
+ rgba: Rgba;
38
+ hsl: Hsl;
39
+ hsla: Hsla;
40
+ hsva: Hsva;
41
+ css: string;
42
+ }
43
+ //#endregion
@@ -0,0 +1,43 @@
1
+ //#region src/color/types.d.ts
2
+ export interface Hsva {
3
+ h: number;
4
+ s: number;
5
+ v: number;
6
+ a: number;
7
+ }
8
+ export interface Rgb {
9
+ r: number;
10
+ g: number;
11
+ b: number;
12
+ }
13
+ export interface Rgba extends Rgb {
14
+ a: number;
15
+ }
16
+ export interface Hsl {
17
+ h: number;
18
+ s: number;
19
+ l: number;
20
+ }
21
+ export interface Hsla extends Hsl {
22
+ a: number;
23
+ }
24
+ export interface Hwb {
25
+ h: number;
26
+ w: number;
27
+ b: number;
28
+ }
29
+ export interface Hwba extends Hwb {
30
+ a: number;
31
+ }
32
+ export type ColorFormat = "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla";
33
+ export interface ColorChangeResult {
34
+ hex: string;
35
+ hexa: string;
36
+ rgb: Rgb;
37
+ rgba: Rgba;
38
+ hsl: Hsl;
39
+ hsla: Hsla;
40
+ hsva: Hsva;
41
+ css: string;
42
+ }
43
+ //#endregion
@@ -0,0 +1,254 @@
1
+ "use client";
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
+ const require_dev = require("../core/dev.cjs");
4
+ const require_registry = require("../modes/registry.cjs");
5
+ const require_context = require("../core/context.cjs");
6
+ const require_useColorStore = require("../core/useColorStore.cjs");
7
+ const require_parse = require("../color/parse.cjs");
8
+ const require_serialize = require("../color/serialize.cjs");
9
+ const require_icons = require("../primitives/icons.cjs");
10
+ const require_sticky = require("../color/sticky.cjs");
11
+ const require_store = require("../core/store.cjs");
12
+ const require_styleInjector = require("../core/styleInjector.cjs");
13
+ const require_css = require("../styles/css.cjs");
14
+ const require_useScrollFade = require("../core/useScrollFade.cjs");
15
+ const require_ModeToolbar = require("./ModeToolbar.cjs");
16
+ const require_PanelFooter = require("./PanelFooter.cjs");
17
+ let react = require("react");
18
+ react = require_runtime.__toESM(react, 1);
19
+ let react_jsx_runtime = require("react/jsx-runtime");
20
+ //#region src/components/ChromaPanel.tsx
21
+ const DEFAULT_COLOR = "#3366cc";
22
+ const FALLBACK = {
23
+ h: 220,
24
+ s: 75,
25
+ v: 80,
26
+ a: 1
27
+ };
28
+ function ChromaPanel(props) {
29
+ const { value, defaultValue = DEFAULT_COLOR, onChange, onChangeComplete, modes = [
30
+ "wheel",
31
+ "sliders",
32
+ "palettes",
33
+ "image",
34
+ "pencils"
35
+ ], mode, defaultMode, onModeChange, format = "hex", showAlpha = true, showEyedropper = true, showRecentColors = true, recentColors, defaultRecentColors, onRecentColorsChange, palettes, pencils, modeProps, imageOptions, disabled = false, theme, showTitleBar = true, title = "Colours", onClose, collapsed, defaultCollapsed = false, onCollapsedChange, size, defaultSize = "default", onSizeChange, injectStyles: shouldInject = true, className, classNames = {}, style, store: externalStore } = props;
36
+ const rootRef = react.useRef(null);
37
+ const panelHostRef = react.useRef(null);
38
+ const idPrefix = require_context.useStableId("cp");
39
+ const initial = react.useMemo(() => {
40
+ const seed = value ?? defaultValue;
41
+ const parsed = typeof seed === "string" ? require_parse.parse(seed) : seed;
42
+ if (parsed === null) require_dev.warnOnce(`could not parse "${seed}"; falling back to ${DEFAULT_COLOR}.`);
43
+ return parsed ?? FALLBACK;
44
+ }, []);
45
+ const ownStore = react.useMemo(() => require_store.createColorStore(initial), [initial]);
46
+ const store = externalStore ?? ownStore;
47
+ react.useEffect(() => {
48
+ if (shouldInject) require_styleInjector.injectStyles(require_css.css, "v2", rootRef.current);
49
+ }, [shouldInject]);
50
+ require_useColorStore.useTransientColor(store, (c) => {
51
+ const el = rootRef.current;
52
+ if (el === null) return;
53
+ el.style.setProperty("--cp-h", String(c.h));
54
+ el.style.setProperty("--cp-s", `${c.s}%`);
55
+ el.style.setProperty("--cp-v", `${c.v}%`);
56
+ el.style.setProperty("--cp-a", String(c.a));
57
+ el.style.setProperty("--cp-preview-color", require_serialize.toRgbaString(c));
58
+ });
59
+ react.useEffect(() => {
60
+ if (value === void 0) return;
61
+ const parsed = typeof value === "string" ? require_parse.parse(value) : value;
62
+ if (parsed === null || parsed === void 0) {
63
+ require_dev.warnOnce(`could not parse value "${value}".`);
64
+ return;
65
+ }
66
+ if (require_sticky.sameRendered(parsed, store.get())) return;
67
+ store.ingest(parsed);
68
+ }, [value, store]);
69
+ const [internalRecents, setInternalRecents] = react.useState(() => defaultRecentColors ?? []);
70
+ const activeRecents = recentColors ?? internalRecents;
71
+ const callbacks = react.useRef({
72
+ onChange,
73
+ onChangeComplete,
74
+ format,
75
+ activeRecents,
76
+ onRecentColorsChange,
77
+ controlled: recentColors !== void 0
78
+ });
79
+ react.useEffect(() => {
80
+ callbacks.current = {
81
+ onChange,
82
+ onChangeComplete,
83
+ format,
84
+ activeRecents,
85
+ onRecentColorsChange,
86
+ controlled: recentColors !== void 0
87
+ };
88
+ });
89
+ react.useEffect(() => store.subscribe((c) => callbacks.current.onChange?.(require_serialize.toResult(c, callbacks.current.format))), [store]);
90
+ react.useEffect(() => store.subscribeCommit((c) => {
91
+ const { onChangeComplete: done, format: fmt, activeRecents: recents, onRecentColorsChange: notify, controlled } = callbacks.current;
92
+ done?.(require_serialize.toResult(c, fmt));
93
+ const next = require_PanelFooter.pushRecent(recents, require_serialize.toHex(c));
94
+ if (!controlled) setInternalRecents(next);
95
+ notify?.(next);
96
+ }), [store]);
97
+ const resolved = react.useMemo(() => require_registry.resolveModes(modes), [modes]);
98
+ const first = resolved[0];
99
+ const [internalMode, setInternalMode] = react.useState(() => defaultMode ?? first?.id ?? "wheel");
100
+ const activeId = mode ?? internalMode;
101
+ const active = resolved.find((m) => m.id === activeId) ?? first;
102
+ require_useScrollFade.useScrollFade(panelHostRef, activeId);
103
+ const selectMode = (id) => {
104
+ if (mode === void 0) setInternalMode(id);
105
+ onModeChange?.(id);
106
+ };
107
+ const [internalCollapsed, setInternalCollapsed] = react.useState(defaultCollapsed);
108
+ const isCollapsed = collapsed ?? internalCollapsed;
109
+ const toggleCollapsed = () => {
110
+ const next = !isCollapsed;
111
+ if (collapsed === void 0) setInternalCollapsed(next);
112
+ onCollapsedChange?.(next);
113
+ };
114
+ const [internalSize, setInternalSize] = react.useState(defaultSize);
115
+ const activeSize = size ?? internalSize;
116
+ const toggleSize = () => {
117
+ const next = activeSize === "expanded" ? "default" : "expanded";
118
+ if (size === void 0) setInternalSize(next);
119
+ onSizeChange?.(next);
120
+ };
121
+ const bodyId = `${idPrefix}-body`;
122
+ const options = react.useMemo(() => ({
123
+ modeProps: {
124
+ ...modeProps,
125
+ ...imageOptions !== void 0 ? { image: {
126
+ extractOptions: imageOptions,
127
+ ...modeProps?.image
128
+ } } : {}
129
+ },
130
+ palettes,
131
+ pencils,
132
+ showAlpha,
133
+ showEyedropper,
134
+ showRecentColors,
135
+ recentColors: activeRecents,
136
+ onRecentColorsChange
137
+ }), [
138
+ palettes,
139
+ pencils,
140
+ modeProps,
141
+ imageOptions,
142
+ showAlpha,
143
+ showEyedropper,
144
+ showRecentColors,
145
+ activeRecents,
146
+ onRecentColorsChange
147
+ ]);
148
+ const context = react.useMemo(() => ({
149
+ store,
150
+ disabled,
151
+ classNames,
152
+ options,
153
+ idPrefix
154
+ }), [
155
+ store,
156
+ disabled,
157
+ classNames,
158
+ options,
159
+ idPrefix
160
+ ]);
161
+ const seed = store.get();
162
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_context.PanelProvider, {
163
+ value: context,
164
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165
+ ref: rootRef,
166
+ className: require_context.cx("cp-root", classNames.root, className),
167
+ "data-cp-theme": theme,
168
+ "data-cp-disabled": disabled ? "true" : void 0,
169
+ "data-cp-collapsed": isCollapsed ? "true" : void 0,
170
+ "data-cp-size": activeSize === "expanded" ? "expanded" : void 0,
171
+ "data-cp-modes": resolved.length,
172
+ style: {
173
+ ["--cp-h"]: String(seed.h),
174
+ ["--cp-s"]: `${seed.s}%`,
175
+ ["--cp-v"]: `${seed.v}%`,
176
+ ["--cp-a"]: String(seed.a),
177
+ ["--cp-preview-color"]: require_serialize.toRgbaString(seed),
178
+ ...style
179
+ },
180
+ children: [showTitleBar && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
181
+ className: require_context.cx("cp-titlebar", classNames.titlebar),
182
+ children: [
183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
184
+ className: "cp-lights",
185
+ children: [
186
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
187
+ type: "button",
188
+ className: "cp-light",
189
+ "data-cp-light": "close",
190
+ "aria-label": "Close",
191
+ disabled: disabled || onClose === void 0,
192
+ onClick: () => onClose?.(),
193
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.WindowGlyph, { name: "close" })
194
+ }),
195
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
196
+ type: "button",
197
+ className: "cp-light",
198
+ "data-cp-light": "min",
199
+ "aria-label": isCollapsed ? "Expand panel" : "Collapse panel",
200
+ "aria-expanded": !isCollapsed,
201
+ "aria-controls": bodyId,
202
+ disabled,
203
+ onClick: toggleCollapsed,
204
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.WindowGlyph, { name: "collapse" })
205
+ }),
206
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
207
+ type: "button",
208
+ className: "cp-light",
209
+ "data-cp-light": "max",
210
+ "aria-label": activeSize === "expanded" ? "Restore panel width" : "Widen panel",
211
+ "aria-pressed": activeSize === "expanded",
212
+ disabled,
213
+ onClick: toggleSize,
214
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.WindowGlyph, { name: "expand" })
215
+ })
216
+ ]
217
+ }),
218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
219
+ className: "cp-title",
220
+ children: title
221
+ }),
222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
223
+ className: "cp-titlebar-spacer",
224
+ "aria-hidden": "true"
225
+ })
226
+ ]
227
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
228
+ className: "cp-body",
229
+ id: bodyId,
230
+ children: [
231
+ resolved.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ModeToolbar.ModeToolbar, {
232
+ modes: resolved,
233
+ activeId,
234
+ onSelect: selectMode
235
+ }),
236
+ active !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
237
+ role: "tabpanel",
238
+ id: `${idPrefix}-panel-${active.id}`,
239
+ "aria-labelledby": `${idPrefix}-tab-${active.id}`,
240
+ ref: panelHostRef,
241
+ tabIndex: -1,
242
+ className: require_context.cx("cp-panel-host", classNames.panel),
243
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(active.Panel, { ...options.modeProps[active.id] ?? {} })
244
+ }),
245
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PanelFooter.PanelFooter, {})
246
+ ]
247
+ })]
248
+ })
249
+ });
250
+ }
251
+ //#endregion
252
+ exports.ChromaPanel = ChromaPanel;
253
+ exports.DEFAULT_COLOR = DEFAULT_COLOR;
254
+ exports.FALLBACK = FALLBACK;
@@ -0,0 +1,47 @@
1
+ import { ColorChangeResult, ColorFormat, Hsva } from "../color/types.cjs";
2
+ import { ColorStore } from "../core/store.cjs";
3
+ import { ExtractOptions } from "../image/extract.cjs";
4
+ import { ModeId, PickerMode } from "../modes/registry.cjs";
5
+ import { ChromaClassNames, ColorPalette } from "../core/context.cjs";
6
+ import * as React from "react";
7
+ //#region src/components/ChromaPanel.d.ts
8
+ export type PanelSize = "default" | "expanded";
9
+ export interface ChromaPanelProps {
10
+ value?: string | Hsva;
11
+ defaultValue?: string | Hsva;
12
+ onChange?: (color: ColorChangeResult) => void;
13
+ onChangeComplete?: (color: ColorChangeResult) => void;
14
+ modes?: (ModeId | string | PickerMode)[];
15
+ mode?: string;
16
+ defaultMode?: string;
17
+ onModeChange?: (mode: string) => void;
18
+ format?: ColorFormat;
19
+ showAlpha?: boolean;
20
+ showEyedropper?: boolean;
21
+ showRecentColors?: boolean;
22
+ recentColors?: string[];
23
+ defaultRecentColors?: string[];
24
+ onRecentColorsChange?: (colors: string[]) => void;
25
+ palettes?: ColorPalette[];
26
+ pencils?: string[];
27
+ modeProps?: Record<string, Record<string, unknown>>;
28
+ imageOptions?: ExtractOptions;
29
+ disabled?: boolean;
30
+ theme?: "dark" | "light";
31
+ showTitleBar?: boolean;
32
+ title?: string;
33
+ onClose?: () => void;
34
+ collapsed?: boolean;
35
+ defaultCollapsed?: boolean;
36
+ onCollapsedChange?: (collapsed: boolean) => void;
37
+ size?: PanelSize;
38
+ defaultSize?: PanelSize;
39
+ onSizeChange?: (size: PanelSize) => void;
40
+ injectStyles?: boolean;
41
+ className?: string;
42
+ classNames?: ChromaClassNames;
43
+ style?: React.CSSProperties;
44
+ store?: ColorStore;
45
+ }
46
+ export declare function ChromaPanel(props: ChromaPanelProps): React.ReactElement;
47
+ //#endregion
@@ -0,0 +1,47 @@
1
+ import { ColorChangeResult, ColorFormat, Hsva } from "../color/types.js";
2
+ import { ColorStore } from "../core/store.js";
3
+ import { ExtractOptions } from "../image/extract.js";
4
+ import { ModeId, PickerMode } from "../modes/registry.js";
5
+ import { ChromaClassNames, ColorPalette } from "../core/context.js";
6
+ import * as React from "react";
7
+ //#region src/components/ChromaPanel.d.ts
8
+ export type PanelSize = "default" | "expanded";
9
+ export interface ChromaPanelProps {
10
+ value?: string | Hsva;
11
+ defaultValue?: string | Hsva;
12
+ onChange?: (color: ColorChangeResult) => void;
13
+ onChangeComplete?: (color: ColorChangeResult) => void;
14
+ modes?: (ModeId | string | PickerMode)[];
15
+ mode?: string;
16
+ defaultMode?: string;
17
+ onModeChange?: (mode: string) => void;
18
+ format?: ColorFormat;
19
+ showAlpha?: boolean;
20
+ showEyedropper?: boolean;
21
+ showRecentColors?: boolean;
22
+ recentColors?: string[];
23
+ defaultRecentColors?: string[];
24
+ onRecentColorsChange?: (colors: string[]) => void;
25
+ palettes?: ColorPalette[];
26
+ pencils?: string[];
27
+ modeProps?: Record<string, Record<string, unknown>>;
28
+ imageOptions?: ExtractOptions;
29
+ disabled?: boolean;
30
+ theme?: "dark" | "light";
31
+ showTitleBar?: boolean;
32
+ title?: string;
33
+ onClose?: () => void;
34
+ collapsed?: boolean;
35
+ defaultCollapsed?: boolean;
36
+ onCollapsedChange?: (collapsed: boolean) => void;
37
+ size?: PanelSize;
38
+ defaultSize?: PanelSize;
39
+ onSizeChange?: (size: PanelSize) => void;
40
+ injectStyles?: boolean;
41
+ className?: string;
42
+ classNames?: ChromaClassNames;
43
+ style?: React.CSSProperties;
44
+ store?: ColorStore;
45
+ }
46
+ export declare function ChromaPanel(props: ChromaPanelProps): React.ReactElement;
47
+ //#endregion
@@ -0,0 +1,251 @@
1
+ "use client";
2
+ import { warnOnce } from "../core/dev.js";
3
+ import { resolveModes } from "../modes/registry.js";
4
+ import { PanelProvider, cx, useStableId } from "../core/context.js";
5
+ import { useTransientColor } from "../core/useColorStore.js";
6
+ import { parse } from "../color/parse.js";
7
+ import { toHex, toResult, toRgbaString } from "../color/serialize.js";
8
+ import { WindowGlyph } from "../primitives/icons.js";
9
+ import { sameRendered } from "../color/sticky.js";
10
+ import { createColorStore } from "../core/store.js";
11
+ import { injectStyles } from "../core/styleInjector.js";
12
+ import { css } from "../styles/css.js";
13
+ import { useScrollFade } from "../core/useScrollFade.js";
14
+ import { ModeToolbar } from "./ModeToolbar.js";
15
+ import { PanelFooter, pushRecent } from "./PanelFooter.js";
16
+ import * as React from "react";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ //#region src/components/ChromaPanel.tsx
19
+ const DEFAULT_COLOR = "#3366cc";
20
+ const FALLBACK = {
21
+ h: 220,
22
+ s: 75,
23
+ v: 80,
24
+ a: 1
25
+ };
26
+ function ChromaPanel(props) {
27
+ const { value, defaultValue = DEFAULT_COLOR, onChange, onChangeComplete, modes = [
28
+ "wheel",
29
+ "sliders",
30
+ "palettes",
31
+ "image",
32
+ "pencils"
33
+ ], mode, defaultMode, onModeChange, format = "hex", showAlpha = true, showEyedropper = true, showRecentColors = true, recentColors, defaultRecentColors, onRecentColorsChange, palettes, pencils, modeProps, imageOptions, disabled = false, theme, showTitleBar = true, title = "Colours", onClose, collapsed, defaultCollapsed = false, onCollapsedChange, size, defaultSize = "default", onSizeChange, injectStyles: shouldInject = true, className, classNames = {}, style, store: externalStore } = props;
34
+ const rootRef = React.useRef(null);
35
+ const panelHostRef = React.useRef(null);
36
+ const idPrefix = useStableId("cp");
37
+ const initial = React.useMemo(() => {
38
+ const seed = value ?? defaultValue;
39
+ const parsed = typeof seed === "string" ? parse(seed) : seed;
40
+ if (parsed === null) warnOnce(`could not parse "${seed}"; falling back to ${DEFAULT_COLOR}.`);
41
+ return parsed ?? FALLBACK;
42
+ }, []);
43
+ const ownStore = React.useMemo(() => createColorStore(initial), [initial]);
44
+ const store = externalStore ?? ownStore;
45
+ React.useEffect(() => {
46
+ if (shouldInject) injectStyles(css, "v2", rootRef.current);
47
+ }, [shouldInject]);
48
+ useTransientColor(store, (c) => {
49
+ const el = rootRef.current;
50
+ if (el === null) return;
51
+ el.style.setProperty("--cp-h", String(c.h));
52
+ el.style.setProperty("--cp-s", `${c.s}%`);
53
+ el.style.setProperty("--cp-v", `${c.v}%`);
54
+ el.style.setProperty("--cp-a", String(c.a));
55
+ el.style.setProperty("--cp-preview-color", toRgbaString(c));
56
+ });
57
+ React.useEffect(() => {
58
+ if (value === void 0) return;
59
+ const parsed = typeof value === "string" ? parse(value) : value;
60
+ if (parsed === null || parsed === void 0) {
61
+ warnOnce(`could not parse value "${value}".`);
62
+ return;
63
+ }
64
+ if (sameRendered(parsed, store.get())) return;
65
+ store.ingest(parsed);
66
+ }, [value, store]);
67
+ const [internalRecents, setInternalRecents] = React.useState(() => defaultRecentColors ?? []);
68
+ const activeRecents = recentColors ?? internalRecents;
69
+ const callbacks = React.useRef({
70
+ onChange,
71
+ onChangeComplete,
72
+ format,
73
+ activeRecents,
74
+ onRecentColorsChange,
75
+ controlled: recentColors !== void 0
76
+ });
77
+ React.useEffect(() => {
78
+ callbacks.current = {
79
+ onChange,
80
+ onChangeComplete,
81
+ format,
82
+ activeRecents,
83
+ onRecentColorsChange,
84
+ controlled: recentColors !== void 0
85
+ };
86
+ });
87
+ React.useEffect(() => store.subscribe((c) => callbacks.current.onChange?.(toResult(c, callbacks.current.format))), [store]);
88
+ React.useEffect(() => store.subscribeCommit((c) => {
89
+ const { onChangeComplete: done, format: fmt, activeRecents: recents, onRecentColorsChange: notify, controlled } = callbacks.current;
90
+ done?.(toResult(c, fmt));
91
+ const next = pushRecent(recents, toHex(c));
92
+ if (!controlled) setInternalRecents(next);
93
+ notify?.(next);
94
+ }), [store]);
95
+ const resolved = React.useMemo(() => resolveModes(modes), [modes]);
96
+ const first = resolved[0];
97
+ const [internalMode, setInternalMode] = React.useState(() => defaultMode ?? first?.id ?? "wheel");
98
+ const activeId = mode ?? internalMode;
99
+ const active = resolved.find((m) => m.id === activeId) ?? first;
100
+ useScrollFade(panelHostRef, activeId);
101
+ const selectMode = (id) => {
102
+ if (mode === void 0) setInternalMode(id);
103
+ onModeChange?.(id);
104
+ };
105
+ const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed);
106
+ const isCollapsed = collapsed ?? internalCollapsed;
107
+ const toggleCollapsed = () => {
108
+ const next = !isCollapsed;
109
+ if (collapsed === void 0) setInternalCollapsed(next);
110
+ onCollapsedChange?.(next);
111
+ };
112
+ const [internalSize, setInternalSize] = React.useState(defaultSize);
113
+ const activeSize = size ?? internalSize;
114
+ const toggleSize = () => {
115
+ const next = activeSize === "expanded" ? "default" : "expanded";
116
+ if (size === void 0) setInternalSize(next);
117
+ onSizeChange?.(next);
118
+ };
119
+ const bodyId = `${idPrefix}-body`;
120
+ const options = React.useMemo(() => ({
121
+ modeProps: {
122
+ ...modeProps,
123
+ ...imageOptions !== void 0 ? { image: {
124
+ extractOptions: imageOptions,
125
+ ...modeProps?.image
126
+ } } : {}
127
+ },
128
+ palettes,
129
+ pencils,
130
+ showAlpha,
131
+ showEyedropper,
132
+ showRecentColors,
133
+ recentColors: activeRecents,
134
+ onRecentColorsChange
135
+ }), [
136
+ palettes,
137
+ pencils,
138
+ modeProps,
139
+ imageOptions,
140
+ showAlpha,
141
+ showEyedropper,
142
+ showRecentColors,
143
+ activeRecents,
144
+ onRecentColorsChange
145
+ ]);
146
+ const context = React.useMemo(() => ({
147
+ store,
148
+ disabled,
149
+ classNames,
150
+ options,
151
+ idPrefix
152
+ }), [
153
+ store,
154
+ disabled,
155
+ classNames,
156
+ options,
157
+ idPrefix
158
+ ]);
159
+ const seed = store.get();
160
+ return /* @__PURE__ */ jsx(PanelProvider, {
161
+ value: context,
162
+ children: /* @__PURE__ */ jsxs("div", {
163
+ ref: rootRef,
164
+ className: cx("cp-root", classNames.root, className),
165
+ "data-cp-theme": theme,
166
+ "data-cp-disabled": disabled ? "true" : void 0,
167
+ "data-cp-collapsed": isCollapsed ? "true" : void 0,
168
+ "data-cp-size": activeSize === "expanded" ? "expanded" : void 0,
169
+ "data-cp-modes": resolved.length,
170
+ style: {
171
+ ["--cp-h"]: String(seed.h),
172
+ ["--cp-s"]: `${seed.s}%`,
173
+ ["--cp-v"]: `${seed.v}%`,
174
+ ["--cp-a"]: String(seed.a),
175
+ ["--cp-preview-color"]: toRgbaString(seed),
176
+ ...style
177
+ },
178
+ children: [showTitleBar && /* @__PURE__ */ jsxs("div", {
179
+ className: cx("cp-titlebar", classNames.titlebar),
180
+ children: [
181
+ /* @__PURE__ */ jsxs("div", {
182
+ className: "cp-lights",
183
+ children: [
184
+ /* @__PURE__ */ jsx("button", {
185
+ type: "button",
186
+ className: "cp-light",
187
+ "data-cp-light": "close",
188
+ "aria-label": "Close",
189
+ disabled: disabled || onClose === void 0,
190
+ onClick: () => onClose?.(),
191
+ children: /* @__PURE__ */ jsx(WindowGlyph, { name: "close" })
192
+ }),
193
+ /* @__PURE__ */ jsx("button", {
194
+ type: "button",
195
+ className: "cp-light",
196
+ "data-cp-light": "min",
197
+ "aria-label": isCollapsed ? "Expand panel" : "Collapse panel",
198
+ "aria-expanded": !isCollapsed,
199
+ "aria-controls": bodyId,
200
+ disabled,
201
+ onClick: toggleCollapsed,
202
+ children: /* @__PURE__ */ jsx(WindowGlyph, { name: "collapse" })
203
+ }),
204
+ /* @__PURE__ */ jsx("button", {
205
+ type: "button",
206
+ className: "cp-light",
207
+ "data-cp-light": "max",
208
+ "aria-label": activeSize === "expanded" ? "Restore panel width" : "Widen panel",
209
+ "aria-pressed": activeSize === "expanded",
210
+ disabled,
211
+ onClick: toggleSize,
212
+ children: /* @__PURE__ */ jsx(WindowGlyph, { name: "expand" })
213
+ })
214
+ ]
215
+ }),
216
+ /* @__PURE__ */ jsx("span", {
217
+ className: "cp-title",
218
+ children: title
219
+ }),
220
+ /* @__PURE__ */ jsx("div", {
221
+ className: "cp-titlebar-spacer",
222
+ "aria-hidden": "true"
223
+ })
224
+ ]
225
+ }), /* @__PURE__ */ jsxs("div", {
226
+ className: "cp-body",
227
+ id: bodyId,
228
+ children: [
229
+ resolved.length > 1 && /* @__PURE__ */ jsx(ModeToolbar, {
230
+ modes: resolved,
231
+ activeId,
232
+ onSelect: selectMode
233
+ }),
234
+ active !== void 0 && /* @__PURE__ */ jsx("div", {
235
+ role: "tabpanel",
236
+ id: `${idPrefix}-panel-${active.id}`,
237
+ "aria-labelledby": `${idPrefix}-tab-${active.id}`,
238
+ ref: panelHostRef,
239
+ tabIndex: -1,
240
+ className: cx("cp-panel-host", classNames.panel),
241
+ children: /* @__PURE__ */ jsx(active.Panel, { ...options.modeProps[active.id] ?? {} })
242
+ }),
243
+ /* @__PURE__ */ jsx(PanelFooter, {})
244
+ ]
245
+ })]
246
+ })
247
+ });
248
+ }
249
+ //#endregion
250
+ export { ChromaPanel, DEFAULT_COLOR, FALLBACK };
251
+