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,193 @@
1
+ "use client";
2
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
3
+ const require_context = require("../../core/context.cjs");
4
+ const require_icons = require("../../primitives/icons.cjs");
5
+ const require_SwatchGrid = require("../../primitives/SwatchGrid.cjs");
6
+ const require_extract = require("../../image/extract.cjs");
7
+ let react = require("react");
8
+ react = require_runtime.__toESM(react, 1);
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/modes/image/index.tsx
11
+ const kept = /* @__PURE__ */ new WeakMap();
12
+ const EMPTY = {
13
+ status: "idle",
14
+ message: "",
15
+ swatches: [],
16
+ preview: null
17
+ };
18
+ function ImagePanel(props) {
19
+ const { extractOptions } = props;
20
+ const { idPrefix, disabled } = require_context.usePanel();
21
+ const inputId = `${idPrefix}-image-file`;
22
+ const { store } = require_context.usePanel();
23
+ const restored = kept.get(store) ?? EMPTY;
24
+ const [status, setStatus] = react.useState(restored.status);
25
+ const [message, setMessage] = react.useState(restored.message);
26
+ const [swatches, setSwatches] = react.useState(restored.swatches);
27
+ const [preview, setPreview] = react.useState(restored.preview);
28
+ const inputRef = react.useRef(null);
29
+ react.useEffect(() => {
30
+ if (preview === null && status === "idle") kept.delete(store);
31
+ else kept.set(store, {
32
+ status,
33
+ message,
34
+ swatches,
35
+ preview
36
+ });
37
+ }, [
38
+ store,
39
+ status,
40
+ message,
41
+ swatches,
42
+ preview
43
+ ]);
44
+ const controller = react.useRef(null);
45
+ const previewUrl = react.useRef(restored.preview);
46
+ const releasePreview = react.useCallback(() => {
47
+ if (previewUrl.current !== null) {
48
+ URL.revokeObjectURL(previewUrl.current);
49
+ previewUrl.current = null;
50
+ }
51
+ }, []);
52
+ react.useEffect(() => {
53
+ return () => {
54
+ controller.current?.abort();
55
+ };
56
+ }, []);
57
+ const run = react.useCallback(async (file) => {
58
+ controller.current?.abort();
59
+ const next = new AbortController();
60
+ controller.current = next;
61
+ releasePreview();
62
+ const url = URL.createObjectURL(file);
63
+ previewUrl.current = url;
64
+ setPreview(url);
65
+ setStatus("working");
66
+ setMessage("");
67
+ try {
68
+ const result = await require_extract.extractPalette(file, {
69
+ maxColors: 10,
70
+ ...extractOptions,
71
+ signal: next.signal
72
+ });
73
+ if (next.signal.aborted) return;
74
+ setSwatches(result.swatches);
75
+ setStatus(result.swatches.length > 0 ? "ready" : "error");
76
+ if (result.swatches.length === 0) setMessage("No opaque pixels found in that image.");
77
+ } catch (error) {
78
+ if (next.signal.aborted) return;
79
+ setStatus("error");
80
+ setMessage(error instanceof Error ? error.message : "Could not read that image.");
81
+ }
82
+ }, [extractOptions, releasePreview]);
83
+ const onFiles = (files) => {
84
+ const file = files?.[0];
85
+ if (file !== void 0) run(file);
86
+ };
87
+ const clear = () => {
88
+ controller.current?.abort();
89
+ releasePreview();
90
+ setPreview(null);
91
+ setSwatches([]);
92
+ setMessage("");
93
+ setStatus("idle");
94
+ if (inputRef.current !== null) inputRef.current.value = "";
95
+ };
96
+ const dragDepth = react.useRef(0);
97
+ const [dragging, setDragging] = react.useState(false);
98
+ const endDrag = () => {
99
+ dragDepth.current = 0;
100
+ setDragging(false);
101
+ };
102
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
103
+ className: "cp-panel",
104
+ onDragEnter: (e) => {
105
+ e.preventDefault();
106
+ if (disabled) return;
107
+ dragDepth.current += 1;
108
+ setDragging(true);
109
+ },
110
+ onDragOver: (e) => e.preventDefault(),
111
+ onDragLeave: () => {
112
+ dragDepth.current -= 1;
113
+ if (dragDepth.current <= 0) endDrag();
114
+ },
115
+ onDrop: (e) => {
116
+ e.preventDefault();
117
+ endDrag();
118
+ if (!disabled) onFiles(e.dataTransfer.files);
119
+ },
120
+ children: [
121
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
122
+ role: "status",
123
+ "aria-live": "polite",
124
+ className: "cp-visually-hidden",
125
+ children: [
126
+ status === "working" ? "Extracting colours" : "",
127
+ status === "ready" ? `${swatches.length} colours extracted` : "",
128
+ status === "error" ? message : ""
129
+ ]
130
+ }),
131
+ preview === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
132
+ className: "cp-dropzone",
133
+ htmlFor: inputId,
134
+ "data-cp-dragging": dragging ? "true" : void 0,
135
+ children: [
136
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.Icon, { name: "image" }),
137
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
138
+ className: "cp-dropzone-title",
139
+ children: status === "working" ? "Reading image…" : "Drop an image here"
140
+ }),
141
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
142
+ className: "cp-dropzone-hint",
143
+ children: status === "error" ? message : "or click to choose a file"
144
+ })
145
+ ]
146
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
147
+ className: "cp-image-preview",
148
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
149
+ src: preview,
150
+ alt: ""
151
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
152
+ type: "button",
153
+ className: "cp-image-remove",
154
+ "aria-label": "Remove image",
155
+ title: "Remove image",
156
+ disabled,
157
+ onClick: clear,
158
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons.Icon, { name: "x" })
159
+ })]
160
+ }),
161
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
162
+ ref: inputRef,
163
+ id: inputId,
164
+ className: "cp-visually-hidden",
165
+ type: "file",
166
+ accept: "image/*",
167
+ disabled,
168
+ onChange: (e) => onFiles(e.currentTarget.files)
169
+ }),
170
+ preview !== null && status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
171
+ className: "cp-empty",
172
+ children: message
173
+ }),
174
+ status === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SwatchGrid.SwatchGrid, {
175
+ swatches: swatches.map((s) => ({
176
+ color: s.hex,
177
+ name: s.hex
178
+ })),
179
+ label: "Extracted colours",
180
+ columns: 5
181
+ })
182
+ ]
183
+ });
184
+ }
185
+ const imageMode = {
186
+ id: "image",
187
+ label: "Image",
188
+ icon: require_icons.ImageIcon,
189
+ Panel: ImagePanel
190
+ };
191
+ //#endregion
192
+ exports.ImagePanel = ImagePanel;
193
+ exports.imageMode = imageMode;
@@ -0,0 +1,10 @@
1
+ import { ExtractOptions } from "../../image/extract.cjs";
2
+ import { PickerMode } from "../registry.cjs";
3
+ import * as React from "react";
4
+ //#region src/modes/image/index.d.ts
5
+ export interface ImagePanelProps {
6
+ extractOptions?: ExtractOptions;
7
+ }
8
+ export declare function ImagePanel(props: ImagePanelProps): React.ReactElement;
9
+ export declare const imageMode: PickerMode;
10
+ //#endregion
@@ -0,0 +1,10 @@
1
+ import { ExtractOptions } from "../../image/extract.js";
2
+ import { PickerMode } from "../registry.js";
3
+ import * as React from "react";
4
+ //#region src/modes/image/index.d.ts
5
+ export interface ImagePanelProps {
6
+ extractOptions?: ExtractOptions;
7
+ }
8
+ export declare function ImagePanel(props: ImagePanelProps): React.ReactElement;
9
+ export declare const imageMode: PickerMode;
10
+ //#endregion
@@ -0,0 +1,191 @@
1
+ "use client";
2
+ import { usePanel } from "../../core/context.js";
3
+ import { Icon, ImageIcon } from "../../primitives/icons.js";
4
+ import { SwatchGrid } from "../../primitives/SwatchGrid.js";
5
+ import { extractPalette } from "../../image/extract.js";
6
+ import * as React from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/modes/image/index.tsx
9
+ const kept = /* @__PURE__ */ new WeakMap();
10
+ const EMPTY = {
11
+ status: "idle",
12
+ message: "",
13
+ swatches: [],
14
+ preview: null
15
+ };
16
+ function ImagePanel(props) {
17
+ const { extractOptions } = props;
18
+ const { idPrefix, disabled } = usePanel();
19
+ const inputId = `${idPrefix}-image-file`;
20
+ const { store } = usePanel();
21
+ const restored = kept.get(store) ?? EMPTY;
22
+ const [status, setStatus] = React.useState(restored.status);
23
+ const [message, setMessage] = React.useState(restored.message);
24
+ const [swatches, setSwatches] = React.useState(restored.swatches);
25
+ const [preview, setPreview] = React.useState(restored.preview);
26
+ const inputRef = React.useRef(null);
27
+ React.useEffect(() => {
28
+ if (preview === null && status === "idle") kept.delete(store);
29
+ else kept.set(store, {
30
+ status,
31
+ message,
32
+ swatches,
33
+ preview
34
+ });
35
+ }, [
36
+ store,
37
+ status,
38
+ message,
39
+ swatches,
40
+ preview
41
+ ]);
42
+ const controller = React.useRef(null);
43
+ const previewUrl = React.useRef(restored.preview);
44
+ const releasePreview = React.useCallback(() => {
45
+ if (previewUrl.current !== null) {
46
+ URL.revokeObjectURL(previewUrl.current);
47
+ previewUrl.current = null;
48
+ }
49
+ }, []);
50
+ React.useEffect(() => {
51
+ return () => {
52
+ controller.current?.abort();
53
+ };
54
+ }, []);
55
+ const run = React.useCallback(async (file) => {
56
+ controller.current?.abort();
57
+ const next = new AbortController();
58
+ controller.current = next;
59
+ releasePreview();
60
+ const url = URL.createObjectURL(file);
61
+ previewUrl.current = url;
62
+ setPreview(url);
63
+ setStatus("working");
64
+ setMessage("");
65
+ try {
66
+ const result = await extractPalette(file, {
67
+ maxColors: 10,
68
+ ...extractOptions,
69
+ signal: next.signal
70
+ });
71
+ if (next.signal.aborted) return;
72
+ setSwatches(result.swatches);
73
+ setStatus(result.swatches.length > 0 ? "ready" : "error");
74
+ if (result.swatches.length === 0) setMessage("No opaque pixels found in that image.");
75
+ } catch (error) {
76
+ if (next.signal.aborted) return;
77
+ setStatus("error");
78
+ setMessage(error instanceof Error ? error.message : "Could not read that image.");
79
+ }
80
+ }, [extractOptions, releasePreview]);
81
+ const onFiles = (files) => {
82
+ const file = files?.[0];
83
+ if (file !== void 0) run(file);
84
+ };
85
+ const clear = () => {
86
+ controller.current?.abort();
87
+ releasePreview();
88
+ setPreview(null);
89
+ setSwatches([]);
90
+ setMessage("");
91
+ setStatus("idle");
92
+ if (inputRef.current !== null) inputRef.current.value = "";
93
+ };
94
+ const dragDepth = React.useRef(0);
95
+ const [dragging, setDragging] = React.useState(false);
96
+ const endDrag = () => {
97
+ dragDepth.current = 0;
98
+ setDragging(false);
99
+ };
100
+ return /* @__PURE__ */ jsxs("div", {
101
+ className: "cp-panel",
102
+ onDragEnter: (e) => {
103
+ e.preventDefault();
104
+ if (disabled) return;
105
+ dragDepth.current += 1;
106
+ setDragging(true);
107
+ },
108
+ onDragOver: (e) => e.preventDefault(),
109
+ onDragLeave: () => {
110
+ dragDepth.current -= 1;
111
+ if (dragDepth.current <= 0) endDrag();
112
+ },
113
+ onDrop: (e) => {
114
+ e.preventDefault();
115
+ endDrag();
116
+ if (!disabled) onFiles(e.dataTransfer.files);
117
+ },
118
+ children: [
119
+ /* @__PURE__ */ jsxs("div", {
120
+ role: "status",
121
+ "aria-live": "polite",
122
+ className: "cp-visually-hidden",
123
+ children: [
124
+ status === "working" ? "Extracting colours" : "",
125
+ status === "ready" ? `${swatches.length} colours extracted` : "",
126
+ status === "error" ? message : ""
127
+ ]
128
+ }),
129
+ preview === null ? /* @__PURE__ */ jsxs("label", {
130
+ className: "cp-dropzone",
131
+ htmlFor: inputId,
132
+ "data-cp-dragging": dragging ? "true" : void 0,
133
+ children: [
134
+ /* @__PURE__ */ jsx(Icon, { name: "image" }),
135
+ /* @__PURE__ */ jsx("span", {
136
+ className: "cp-dropzone-title",
137
+ children: status === "working" ? "Reading image…" : "Drop an image here"
138
+ }),
139
+ /* @__PURE__ */ jsx("span", {
140
+ className: "cp-dropzone-hint",
141
+ children: status === "error" ? message : "or click to choose a file"
142
+ })
143
+ ]
144
+ }) : /* @__PURE__ */ jsxs("div", {
145
+ className: "cp-image-preview",
146
+ children: [/* @__PURE__ */ jsx("img", {
147
+ src: preview,
148
+ alt: ""
149
+ }), /* @__PURE__ */ jsx("button", {
150
+ type: "button",
151
+ className: "cp-image-remove",
152
+ "aria-label": "Remove image",
153
+ title: "Remove image",
154
+ disabled,
155
+ onClick: clear,
156
+ children: /* @__PURE__ */ jsx(Icon, { name: "x" })
157
+ })]
158
+ }),
159
+ /* @__PURE__ */ jsx("input", {
160
+ ref: inputRef,
161
+ id: inputId,
162
+ className: "cp-visually-hidden",
163
+ type: "file",
164
+ accept: "image/*",
165
+ disabled,
166
+ onChange: (e) => onFiles(e.currentTarget.files)
167
+ }),
168
+ preview !== null && status === "error" && /* @__PURE__ */ jsx("p", {
169
+ className: "cp-empty",
170
+ children: message
171
+ }),
172
+ status === "ready" && /* @__PURE__ */ jsx(SwatchGrid, {
173
+ swatches: swatches.map((s) => ({
174
+ color: s.hex,
175
+ name: s.hex
176
+ })),
177
+ label: "Extracted colours",
178
+ columns: 5
179
+ })
180
+ ]
181
+ });
182
+ }
183
+ const imageMode = {
184
+ id: "image",
185
+ label: "Image",
186
+ icon: ImageIcon,
187
+ Panel: ImagePanel
188
+ };
189
+ //#endregion
190
+ export { ImagePanel, imageMode };
191
+
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
3
+ const require_context = require("../../core/context.cjs");
4
+ const require_icons = require("../../primitives/icons.cjs");
5
+ const require_defaults = require("../../data/defaults.cjs");
6
+ const require_SwatchGrid = require("../../primitives/SwatchGrid.cjs");
7
+ let react = require("react");
8
+ react = require_runtime.__toESM(react, 1);
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/modes/palettes/index.tsx
11
+ function normalise(colors) {
12
+ return colors.map((entry) => typeof entry === "string" ? { color: entry } : {
13
+ color: entry.color,
14
+ name: entry.name
15
+ });
16
+ }
17
+ function PalettesPanel() {
18
+ const { options, idPrefix } = require_context.usePanel();
19
+ const [query, setQuery] = react.useState("");
20
+ const searchId = `${idPrefix}-palette-search`;
21
+ const groups = react.useMemo(() => {
22
+ const needle = query.trim().toLowerCase();
23
+ return (options.palettes ?? require_defaults.defaultPalettes()).map((palette) => ({
24
+ name: palette.name,
25
+ swatches: normalise(palette.colors).filter((s) => needle === "" || s.color.toLowerCase().includes(needle) || (s.name ?? "").toLowerCase().includes(needle))
26
+ })).filter((group) => group.swatches.length > 0);
27
+ }, [options.palettes, query]);
28
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
29
+ className: "cp-panel",
30
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
31
+ className: "cp-field",
32
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
33
+ className: "cp-field-label",
34
+ htmlFor: searchId,
35
+ children: "Search"
36
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
37
+ id: searchId,
38
+ className: "cp-input",
39
+ type: "search",
40
+ placeholder: "Name or hex",
41
+ value: query,
42
+ onChange: (e) => setQuery(e.currentTarget.value)
43
+ })]
44
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
45
+ className: "cp-scroll",
46
+ children: groups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
47
+ className: "cp-empty",
48
+ children: [
49
+ "No colours match “",
50
+ query,
51
+ "”."
52
+ ]
53
+ }) : groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
54
+ className: "cp-group",
55
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
56
+ className: "cp-group-title",
57
+ children: group.name
58
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SwatchGrid.SwatchGrid, {
59
+ swatches: group.swatches,
60
+ label: group.name,
61
+ columns: 6,
62
+ variant: "spaced"
63
+ })]
64
+ }, group.name))
65
+ })]
66
+ });
67
+ }
68
+ const palettesMode = {
69
+ id: "palettes",
70
+ label: "Palettes",
71
+ icon: require_icons.PalettesIcon,
72
+ Panel: PalettesPanel
73
+ };
74
+ //#endregion
75
+ exports.PalettesPanel = PalettesPanel;
76
+ exports.palettesMode = palettesMode;
@@ -0,0 +1,6 @@
1
+ import { PickerMode } from "../registry.cjs";
2
+ import * as React from "react";
3
+ //#region src/modes/palettes/index.d.ts
4
+ export declare function PalettesPanel(): React.ReactElement;
5
+ export declare const palettesMode: PickerMode;
6
+ //#endregion
@@ -0,0 +1,6 @@
1
+ import { PickerMode } from "../registry.js";
2
+ import * as React from "react";
3
+ //#region src/modes/palettes/index.d.ts
4
+ export declare function PalettesPanel(): React.ReactElement;
5
+ export declare const palettesMode: PickerMode;
6
+ //#endregion
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { usePanel } from "../../core/context.js";
3
+ import { PalettesIcon } from "../../primitives/icons.js";
4
+ import { defaultPalettes } from "../../data/defaults.js";
5
+ import { SwatchGrid } from "../../primitives/SwatchGrid.js";
6
+ import * as React from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/modes/palettes/index.tsx
9
+ function normalise(colors) {
10
+ return colors.map((entry) => typeof entry === "string" ? { color: entry } : {
11
+ color: entry.color,
12
+ name: entry.name
13
+ });
14
+ }
15
+ function PalettesPanel() {
16
+ const { options, idPrefix } = usePanel();
17
+ const [query, setQuery] = React.useState("");
18
+ const searchId = `${idPrefix}-palette-search`;
19
+ const groups = React.useMemo(() => {
20
+ const needle = query.trim().toLowerCase();
21
+ return (options.palettes ?? defaultPalettes()).map((palette) => ({
22
+ name: palette.name,
23
+ swatches: normalise(palette.colors).filter((s) => needle === "" || s.color.toLowerCase().includes(needle) || (s.name ?? "").toLowerCase().includes(needle))
24
+ })).filter((group) => group.swatches.length > 0);
25
+ }, [options.palettes, query]);
26
+ return /* @__PURE__ */ jsxs("div", {
27
+ className: "cp-panel",
28
+ children: [/* @__PURE__ */ jsxs("div", {
29
+ className: "cp-field",
30
+ children: [/* @__PURE__ */ jsx("label", {
31
+ className: "cp-field-label",
32
+ htmlFor: searchId,
33
+ children: "Search"
34
+ }), /* @__PURE__ */ jsx("input", {
35
+ id: searchId,
36
+ className: "cp-input",
37
+ type: "search",
38
+ placeholder: "Name or hex",
39
+ value: query,
40
+ onChange: (e) => setQuery(e.currentTarget.value)
41
+ })]
42
+ }), /* @__PURE__ */ jsx("div", {
43
+ className: "cp-scroll",
44
+ children: groups.length === 0 ? /* @__PURE__ */ jsxs("p", {
45
+ className: "cp-empty",
46
+ children: [
47
+ "No colours match “",
48
+ query,
49
+ "”."
50
+ ]
51
+ }) : groups.map((group) => /* @__PURE__ */ jsxs("section", {
52
+ className: "cp-group",
53
+ children: [/* @__PURE__ */ jsx("h3", {
54
+ className: "cp-group-title",
55
+ children: group.name
56
+ }), /* @__PURE__ */ jsx(SwatchGrid, {
57
+ swatches: group.swatches,
58
+ label: group.name,
59
+ columns: 6,
60
+ variant: "spaced"
61
+ })]
62
+ }, group.name))
63
+ })]
64
+ });
65
+ }
66
+ const palettesMode = {
67
+ id: "palettes",
68
+ label: "Palettes",
69
+ icon: PalettesIcon,
70
+ Panel: PalettesPanel
71
+ };
72
+ //#endregion
73
+ export { PalettesPanel, palettesMode };
74
+
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
3
+ const require_context = require("../../core/context.cjs");
4
+ const require_icons = require("../../primitives/icons.cjs");
5
+ const require_defaults = require("../../data/defaults.cjs");
6
+ const require_SwatchGrid = require("../../primitives/SwatchGrid.cjs");
7
+ let react = require("react");
8
+ react = require_runtime.__toESM(react, 1);
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/modes/pencils/index.tsx
11
+ function PencilsPanel() {
12
+ const { options } = require_context.usePanel();
13
+ const swatches = react.useMemo(() => (options.pencils ?? require_defaults.defaultPencils()).map((color) => ({ color })), [options.pencils]);
14
+ if (swatches.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15
+ className: "cp-empty",
16
+ children: "No pencils configured."
17
+ });
18
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
19
+ className: "cp-panel",
20
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SwatchGrid.SwatchGrid, {
21
+ swatches,
22
+ label: "Pencils",
23
+ columns: 12,
24
+ variant: "mosaic"
25
+ })
26
+ });
27
+ }
28
+ const pencilsMode = {
29
+ id: "pencils",
30
+ label: "Pencils",
31
+ icon: require_icons.PencilsIcon,
32
+ Panel: PencilsPanel
33
+ };
34
+ //#endregion
35
+ exports.PencilsPanel = PencilsPanel;
36
+ exports.pencilsMode = pencilsMode;
@@ -0,0 +1,6 @@
1
+ import { PickerMode } from "../registry.cjs";
2
+ import * as React from "react";
3
+ //#region src/modes/pencils/index.d.ts
4
+ export declare function PencilsPanel(): React.ReactElement;
5
+ export declare const pencilsMode: PickerMode;
6
+ //#endregion
@@ -0,0 +1,6 @@
1
+ import { PickerMode } from "../registry.js";
2
+ import * as React from "react";
3
+ //#region src/modes/pencils/index.d.ts
4
+ export declare function PencilsPanel(): React.ReactElement;
5
+ export declare const pencilsMode: PickerMode;
6
+ //#endregion
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { usePanel } from "../../core/context.js";
3
+ import { PencilsIcon } from "../../primitives/icons.js";
4
+ import { defaultPencils } from "../../data/defaults.js";
5
+ import { SwatchGrid } from "../../primitives/SwatchGrid.js";
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ //#region src/modes/pencils/index.tsx
9
+ function PencilsPanel() {
10
+ const { options } = usePanel();
11
+ const swatches = React.useMemo(() => (options.pencils ?? defaultPencils()).map((color) => ({ color })), [options.pencils]);
12
+ if (swatches.length === 0) return /* @__PURE__ */ jsx("p", {
13
+ className: "cp-empty",
14
+ children: "No pencils configured."
15
+ });
16
+ return /* @__PURE__ */ jsx("div", {
17
+ className: "cp-panel",
18
+ children: /* @__PURE__ */ jsx(SwatchGrid, {
19
+ swatches,
20
+ label: "Pencils",
21
+ columns: 12,
22
+ variant: "mosaic"
23
+ })
24
+ });
25
+ }
26
+ const pencilsMode = {
27
+ id: "pencils",
28
+ label: "Pencils",
29
+ icon: PencilsIcon,
30
+ Panel: PencilsPanel
31
+ };
32
+ //#endregion
33
+ export { PencilsPanel, pencilsMode };
34
+
@@ -0,0 +1,26 @@
1
+ const require_dev = require("../core/dev.cjs");
2
+ //#region src/modes/registry.ts
3
+ const registry = /* @__PURE__ */ new Map();
4
+ function registerMode(mode) {
5
+ registry.set(mode.id, mode);
6
+ }
7
+ function getMode(id) {
8
+ return registry.get(id);
9
+ }
10
+ function resolveModes(requested) {
11
+ const out = [];
12
+ for (const entry of requested) {
13
+ if (typeof entry !== "string") {
14
+ out.push(entry);
15
+ continue;
16
+ }
17
+ const found = registry.get(entry);
18
+ if (found !== void 0) out.push(found);
19
+ else require_dev.warnOnce(`unknown mode "${entry}". Known modes: ${Array.from(registry.keys()).join(", ")}.`);
20
+ }
21
+ return out;
22
+ }
23
+ //#endregion
24
+ exports.getMode = getMode;
25
+ exports.registerMode = registerMode;
26
+ exports.resolveModes = resolveModes;