@andreagiugni/tailwind-dashboard-ui 0.3.0 → 0.5.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.
- package/README.md +16 -3
- package/dist/chunk-3T6AZMUZ.cjs +158 -0
- package/dist/chunk-3T6AZMUZ.cjs.map +1 -0
- package/dist/chunk-AGRX5ZR6.js +156 -0
- package/dist/chunk-AGRX5ZR6.js.map +1 -0
- package/dist/components/ColorPicker/ColorPicker.cjs +14 -0
- package/dist/components/ColorPicker/ColorPicker.cjs.map +1 -0
- package/dist/components/ColorPicker/ColorPicker.d.cts +23 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +23 -0
- package/dist/components/ColorPicker/ColorPicker.js +5 -0
- package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
- package/dist/index.cjs +108 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -9
- package/dist/index.d.ts +26 -9
- package/dist/index.js +104 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -47,6 +47,17 @@ npm i @tiptap/react @tiptap/pm @tiptap/starter-kit @tiptap/extension-link @tipta
|
|
|
47
47
|
> They are code-split into their own chunks and never executed unless you actually import them, so
|
|
48
48
|
> the rest of the library stays SSR-safe and light.
|
|
49
49
|
|
|
50
|
+
### `ColorPicker`
|
|
51
|
+
|
|
52
|
+
The `ColorPicker` is built on [`react-beautiful-color`](https://www.npmjs.com/package/react-beautiful-color),
|
|
53
|
+
which is a **bundled dependency** (installed automatically — you don't add it yourself). It is
|
|
54
|
+
client-only and code-split like the data-viz widgets, so render it client-only under SSR. It ships
|
|
55
|
+
its own stylesheet — import it once in your app:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import 'react-beautiful-color/dist/react-beautiful-color.css';
|
|
59
|
+
```
|
|
60
|
+
|
|
50
61
|
## Tailwind setup
|
|
51
62
|
|
|
52
63
|
The library ships its design tokens as an importable stylesheet. Add this line to your app's
|
|
@@ -153,8 +164,8 @@ Legend: **(+native)** = also extends the element's native HTML attributes.
|
|
|
153
164
|
| `DropdownItem` | `variant` (default/primary/outline, like Button), `bgColor`/`textColor`/`borderColor` overrides, `tag` (a/button), `href`, `onClick`, `onItemClick`, `baseClassName` (full override) |
|
|
154
165
|
| `Modal` | `isOpen`, `onClose`, `showCloseButton`, `isFullscreen`, `closeOnBackdrop?`, `closeOnEsc?`; **alert preset** → `variant` (`success`/`info`/`warning`/`danger`) + `title`, `description`, `actionText?`, `onAction?`; (+native div) |
|
|
155
166
|
| `Table` (composable) | `TableHeader` / `TableBody` / `TableRow` / `TableCell` with `children`, `isHeader` (cell), (+native table elements; `onClick` / `onDoubleClick` on rows & cells) |
|
|
156
|
-
| `Table` (data-driven) | pass `data` + `columns` (`key`, `header`, `sortable?`, `align?`, `render?`, `className?`) to get search + per-column sort + pagination: `rowsPerPage?` (max rows/page, default 10), `rowsPerPageOptions?`, `searchKeys?` (**search box shown only when provided**), `searchPlaceholder?`, `defaultSortKey?` / `defaultSortDirection?`, `pagination?`, `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` |
|
|
157
|
-
| `Pagination` | `currentPage`, `totalPages`, `onPageChange` |
|
|
167
|
+
| `Table` (data-driven) | pass `data` + `columns` (`key`, `header`, `sortable?`, `align?`, `render?`, `className?`) to get search + per-column sort + pagination: `rowsPerPage?` (max rows/page, default 10), `rowsPerPageOptions?`, `searchKeys?` (**search box shown only when provided**), `searchPlaceholder?`, `defaultSortKey?` / `defaultSortDirection?`, `pagination?`, `paginationAlign?` (`left`/`center`/`right`/`full`, default `right`), `showSizeSelector?`, `onRowClick?`, `getRowId?`, `emptyContent?` |
|
|
168
|
+
| `Pagination` | `currentPage`, `totalPages`, `onPageChange`, `align?` (`left`/`center`/`right`/`full` — `full` pins Previous/Next to the edges with page indices centered) |
|
|
158
169
|
| `Breadcrumb` | `pageTitle`, `items?`, (+native) |
|
|
159
170
|
| `ThemeToggleButton` | `theme?` (controlled), `onToggle?`, (+native button) |
|
|
160
171
|
| `Card` | `title?`, `description?`, `icon?`, `image?`, `imageAlt?`, `horizontal?`, `footer?`, `children?`, (+native div) (+override) |
|
|
@@ -194,6 +205,7 @@ Legend: **(+native)** = also extends the element's native HTML attributes.
|
|
|
194
205
|
| `DatePicker` | `id`, `mode` (single/multiple/range/time), `defaultDate`, `onChange`, `label`, `placeholder` |
|
|
195
206
|
| `DateTimePicker` | `id`, `label?`, `placeholder?`, `defaultDate?`, `defaultTime?` (`"HH:MM"`), `onChange?({ date, time })` — flatpickr date calendar + a compact `HH:MM` time input |
|
|
196
207
|
| `Slider` | `value` / `defaultValue`, `onChange(value)`, `min`, `max`, `step`, `color`, `label?`, `showValue?`, `disabled` |
|
|
208
|
+
| `ColorPicker` | `defaultValue?` (hex), `defaultFormat?` / `formats?` (`hex`/`rgb`/`rgba`/`hsl`/`hsla`), `showInput?`, `withEyeDropper?`, `label?`, `onChange?(value, color)` — saturation/hue/alpha picker + value input with a format switcher; built on `react-beautiful-color` (bundled), client-only, **import its CSS** (see ColorPicker note above) |
|
|
197
209
|
| `Editor` (WYSIWYG) | `content`, `onChange(html)`, `placeholder?`, `editable?`, `toolbar?` (ordered tool ids or custom buttons), `editorClassName?` — optional Tiptap peers; render client-only (see Data viz) |
|
|
198
210
|
|
|
199
211
|
### Data viz
|
|
@@ -279,7 +291,8 @@ const columns: TableColumn<Person>[] = [
|
|
|
279
291
|
Key data-driven props: `data`, `columns` (each: `key`, `header`, `sortable?`, `align?`, `render?`,
|
|
280
292
|
`className?`), `rowsPerPage` (default 10), `rowsPerPageOptions` (default `[5,10,25,50]`),
|
|
281
293
|
`searchKeys` / `searchPlaceholder`, `defaultSortKey` / `defaultSortDirection`, `pagination`,
|
|
282
|
-
`
|
|
294
|
+
`paginationAlign` (`left` / `center` / `right` / `full`, default `right`), `showSizeSelector`,
|
|
295
|
+
`onRowClick`, `getRowId`, `emptyContent`.
|
|
283
296
|
|
|
284
297
|
> **Search visibility:** the search input renders **only** when you pass a non-empty `searchKeys`
|
|
285
298
|
> array — those are also the exact fields the query matches. Omit `searchKeys` (or pass `[]`) to
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunkYERNSNT4_cjs = require('./chunk-YERNSNT4.cjs');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var reactBeautifulColor = require('react-beautiful-color');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
var ALL_FORMATS = ["hex", "rgb", "rgba", "hsl", "hsla"];
|
|
10
|
+
function parseValue(text, format) {
|
|
11
|
+
const t = text.trim();
|
|
12
|
+
if (format === "hex") {
|
|
13
|
+
return /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t) ? { type: "hex", value: t } : null;
|
|
14
|
+
}
|
|
15
|
+
const n = t.match(/-?\d*\.?\d+/g)?.map(Number) ?? [];
|
|
16
|
+
if (format === "rgb" && n.length >= 3) return { type: "rgb", r: n[0], g: n[1], b: n[2] };
|
|
17
|
+
if (format === "rgba" && n.length >= 4)
|
|
18
|
+
return { type: "rgba", r: n[0], g: n[1], b: n[2], a: n[3] };
|
|
19
|
+
if (format === "hsl" && n.length >= 3) return { type: "hsl", h: n[0], s: n[1], l: n[2] };
|
|
20
|
+
if (format === "hsla" && n.length >= 4)
|
|
21
|
+
return { type: "hsla", h: n[0], s: n[1], l: n[2], a: n[3] };
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function inputToString(input) {
|
|
25
|
+
switch (input.type) {
|
|
26
|
+
case "hex":
|
|
27
|
+
return input.value;
|
|
28
|
+
case "rgb":
|
|
29
|
+
return `rgb(${input.r}, ${input.g}, ${input.b})`;
|
|
30
|
+
case "rgba":
|
|
31
|
+
return `rgba(${input.r}, ${input.g}, ${input.b}, ${input.a})`;
|
|
32
|
+
case "hsl":
|
|
33
|
+
return `hsl(${input.h}, ${input.s}%, ${input.l}%)`;
|
|
34
|
+
case "hsla":
|
|
35
|
+
return `hsla(${input.h}, ${input.s}%, ${input.l}%, ${input.a})`;
|
|
36
|
+
case "hsv":
|
|
37
|
+
return `hsv(${input.h}, ${input.s}%, ${input.v}%)`;
|
|
38
|
+
case "hsva":
|
|
39
|
+
return `hsva(${input.h}, ${input.s}%, ${input.v}%, ${input.a})`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function stateToString(state, format) {
|
|
43
|
+
switch (format) {
|
|
44
|
+
case "hex":
|
|
45
|
+
return state.hex;
|
|
46
|
+
case "rgb":
|
|
47
|
+
return `rgb(${state.rgb.r}, ${state.rgb.g}, ${state.rgb.b})`;
|
|
48
|
+
case "rgba":
|
|
49
|
+
return `rgba(${state.rgba.r}, ${state.rgba.g}, ${state.rgba.b}, ${state.rgba.a})`;
|
|
50
|
+
case "hsl":
|
|
51
|
+
return `hsl(${state.hsl.h}, ${state.hsl.s}%, ${state.hsl.l}%)`;
|
|
52
|
+
case "hsla":
|
|
53
|
+
return `hsla(${state.hsla.h}, ${state.hsla.s}%, ${state.hsla.l}%, ${state.hsla.a})`;
|
|
54
|
+
default:
|
|
55
|
+
return state.hex;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
var pipetteIcon = /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
59
|
+
"path",
|
|
60
|
+
{
|
|
61
|
+
d: "M19.5 3.5a2.12 2.12 0 0 0-3 0l-2.3 2.3-1-1-1.4 1.4 1 1L4 14.9V19h4.1l7.7-7.7 1 1 1.4-1.4-1-1 2.3-2.3a2.12 2.12 0 0 0 0-3ZM7.3 17.6H6v-1.3l6.6-6.6 1.3 1.3-6.6 6.6Z",
|
|
62
|
+
fill: "currentColor"
|
|
63
|
+
}
|
|
64
|
+
) });
|
|
65
|
+
var ColorPicker = ({
|
|
66
|
+
defaultValue = "#3641f5",
|
|
67
|
+
defaultFormat = "hex",
|
|
68
|
+
formats = ALL_FORMATS,
|
|
69
|
+
showInput = true,
|
|
70
|
+
withEyeDropper = false,
|
|
71
|
+
label,
|
|
72
|
+
onChange,
|
|
73
|
+
className,
|
|
74
|
+
...rest
|
|
75
|
+
}) => {
|
|
76
|
+
const [{ colorInput, colorState }, setColor] = reactBeautifulColor.useColorState({
|
|
77
|
+
type: "hex",
|
|
78
|
+
value: defaultValue
|
|
79
|
+
});
|
|
80
|
+
const [format, setFormat] = react.useState(defaultFormat);
|
|
81
|
+
const [draft, setDraft] = react.useState(null);
|
|
82
|
+
const currentColor = react.useMemo(() => new reactBeautifulColor.Color(colorInput), [colorInput]);
|
|
83
|
+
const display = colorInput.type === format ? inputToString(colorInput) : stateToString(colorState, format);
|
|
84
|
+
const inputValue = draft ?? display;
|
|
85
|
+
const apply = (input) => {
|
|
86
|
+
setColor(input);
|
|
87
|
+
onChange?.(inputToString(input), new reactBeautifulColor.Color(input));
|
|
88
|
+
};
|
|
89
|
+
const handlePickerChange = (next) => {
|
|
90
|
+
setColor(next);
|
|
91
|
+
onChange?.(next.format(format), next);
|
|
92
|
+
};
|
|
93
|
+
const handleFormatChange = (f) => {
|
|
94
|
+
setFormat(f);
|
|
95
|
+
setDraft(null);
|
|
96
|
+
onChange?.(stateToString(colorState, f), currentColor);
|
|
97
|
+
};
|
|
98
|
+
const handleInputChange = (text) => {
|
|
99
|
+
setDraft(text);
|
|
100
|
+
const parsed = parseValue(text, format);
|
|
101
|
+
if (parsed) apply(parsed);
|
|
102
|
+
};
|
|
103
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkYERNSNT4_cjs.cn("w-full max-w-xs", className), ...rest, children: [
|
|
104
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400", children: label }),
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
106
|
+
reactBeautifulColor.ColorPicker,
|
|
107
|
+
{
|
|
108
|
+
color: colorInput,
|
|
109
|
+
onChange: handlePickerChange,
|
|
110
|
+
className: "rounded-2xl border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-white/[0.03]",
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactBeautifulColor.ColorPicker.Saturation, { className: "mb-3 h-40 overflow-hidden rounded-lg" }),
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
114
|
+
withEyeDropper && /* @__PURE__ */ jsxRuntime.jsx(reactBeautifulColor.ColorPicker.EyeDropper, { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-white/[0.03]", children: pipetteIcon }),
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
116
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactBeautifulColor.ColorPicker.Hue, { className: "h-3 overflow-hidden rounded-full" }),
|
|
117
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactBeautifulColor.ColorPicker.Alpha, { className: "h-3 overflow-hidden rounded-full" })
|
|
118
|
+
] })
|
|
119
|
+
] })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
showInput && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-stretch gap-2", children: [
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
125
|
+
"span",
|
|
126
|
+
{
|
|
127
|
+
"aria-hidden": "true",
|
|
128
|
+
className: "h-11 w-11 shrink-0 rounded-lg border border-gray-200 dark:border-gray-700",
|
|
129
|
+
style: { backgroundColor: currentColor.format("rgba") }
|
|
130
|
+
}
|
|
131
|
+
),
|
|
132
|
+
formats.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
133
|
+
"select",
|
|
134
|
+
{
|
|
135
|
+
"aria-label": "Color format",
|
|
136
|
+
value: format,
|
|
137
|
+
onChange: (e) => handleFormatChange(e.target.value),
|
|
138
|
+
className: "h-11 shrink-0 rounded-lg border border-gray-300 bg-transparent px-2 text-sm text-gray-700 focus:outline-hidden dark:border-gray-700 dark:text-gray-300",
|
|
139
|
+
children: formats.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f, children: f.toUpperCase() }, f))
|
|
140
|
+
}
|
|
141
|
+
),
|
|
142
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
143
|
+
"input",
|
|
144
|
+
{
|
|
145
|
+
"aria-label": "Color value",
|
|
146
|
+
value: inputValue,
|
|
147
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
148
|
+
onBlur: () => setDraft(null),
|
|
149
|
+
className: "h-11 w-full rounded-lg border border-gray-300 bg-transparent px-3 text-sm text-gray-800 focus:outline-hidden dark:border-gray-700 dark:text-white/90"
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
] })
|
|
153
|
+
] });
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
exports.ColorPicker = ColorPicker;
|
|
157
|
+
//# sourceMappingURL=chunk-3T6AZMUZ.cjs.map
|
|
158
|
+
//# sourceMappingURL=chunk-3T6AZMUZ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ColorPicker/ColorPicker.tsx"],"names":["jsx","useColorState","useState","useMemo","Color","jsxs","cn","RBColorPicker"],"mappings":"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","file":"chunk-3T6AZMUZ.cjs","sourcesContent":["\"use client\";\nimport React, { useMemo, useState } from \"react\";\nimport {\n ColorPicker as RBColorPicker,\n useColorState,\n Color,\n} from \"react-beautiful-color\";\nimport { cn } from \"../../lib/cn\";\n\n// `react-beautiful-color` doesn't re-export these from its entry, so derive them\n// from the hook's inferred return type.\ntype ColorInput = ReturnType<typeof useColorState>[0][\"colorInput\"];\ntype ColorState = ReturnType<typeof useColorState>[0][\"colorState\"];\n\nexport type ColorPickerFormat = \"hex\" | \"rgb\" | \"rgba\" | \"hsl\" | \"hsla\";\n\nexport interface ColorPickerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** Initial color (uncontrolled). Any hex string, e.g. `\"#3641f5\"`. */\n defaultValue?: string;\n /** Format selected on first render. Default: `\"hex\"`. */\n defaultFormat?: ColorPickerFormat;\n /** Formats offered in the switcher. Default: all five. */\n formats?: ColorPickerFormat[];\n /** Render the value input + format switcher. Default: `true`. */\n showInput?: boolean;\n /** Show the native eye-dropper button (browser support varies). */\n withEyeDropper?: boolean;\n /** Optional label rendered above the picker. */\n label?: string;\n /** Fires on every change with the formatted string and the `Color` instance. */\n onChange?: (value: string, color: Color) => void;\n}\n\nconst ALL_FORMATS: ColorPickerFormat[] = [\"hex\", \"rgb\", \"rgba\", \"hsl\", \"hsla\"];\n\n/** Parse the text in the input back into a `ColorInput`, or `null` if invalid. */\nfunction parseValue(text: string, format: ColorPickerFormat): ColorInput | null {\n const t = text.trim();\n if (format === \"hex\") {\n return /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t)\n ? { type: \"hex\", value: t }\n : null;\n }\n const n = t.match(/-?\\d*\\.?\\d+/g)?.map(Number) ?? [];\n if (format === \"rgb\" && n.length >= 3) return { type: \"rgb\", r: n[0], g: n[1], b: n[2] };\n if (format === \"rgba\" && n.length >= 4)\n return { type: \"rgba\", r: n[0], g: n[1], b: n[2], a: n[3] };\n if (format === \"hsl\" && n.length >= 3) return { type: \"hsl\", h: n[0], s: n[1], l: n[2] };\n if (format === \"hsla\" && n.length >= 4)\n return { type: \"hsla\", h: n[0], s: n[1], l: n[2], a: n[3] };\n return null;\n}\n\n/** Format a `ColorInput` (preserving the user's exact values) into a CSS string. */\nfunction inputToString(input: ColorInput): string {\n switch (input.type) {\n case \"hex\":\n return input.value;\n case \"rgb\":\n return `rgb(${input.r}, ${input.g}, ${input.b})`;\n case \"rgba\":\n return `rgba(${input.r}, ${input.g}, ${input.b}, ${input.a})`;\n case \"hsl\":\n return `hsl(${input.h}, ${input.s}%, ${input.l}%)`;\n case \"hsla\":\n return `hsla(${input.h}, ${input.s}%, ${input.l}%, ${input.a})`;\n case \"hsv\":\n return `hsv(${input.h}, ${input.s}%, ${input.v}%)`;\n case \"hsva\":\n return `hsva(${input.h}, ${input.s}%, ${input.v}%, ${input.a})`;\n }\n}\n\n/** Format the resolved `ColorState` into the requested CSS string. */\nfunction stateToString(state: ColorState, format: ColorPickerFormat): string {\n switch (format) {\n case \"hex\":\n return state.hex;\n case \"rgb\":\n return `rgb(${state.rgb.r}, ${state.rgb.g}, ${state.rgb.b})`;\n case \"rgba\":\n return `rgba(${state.rgba.r}, ${state.rgba.g}, ${state.rgba.b}, ${state.rgba.a})`;\n case \"hsl\":\n return `hsl(${state.hsl.h}, ${state.hsl.s}%, ${state.hsl.l}%)`;\n case \"hsla\":\n return `hsla(${state.hsla.h}, ${state.hsla.s}%, ${state.hsla.l}%, ${state.hsla.a})`;\n default:\n return state.hex;\n }\n}\n\nconst pipetteIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M19.5 3.5a2.12 2.12 0 0 0-3 0l-2.3 2.3-1-1-1.4 1.4 1 1L4 14.9V19h4.1l7.7-7.7 1 1 1.4-1.4-1-1 2.3-2.3a2.12 2.12 0 0 0 0-3ZM7.3 17.6H6v-1.3l6.6-6.6 1.3 1.3-6.6 6.6Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const ColorPicker: React.FC<ColorPickerProps> = ({\n defaultValue = \"#3641f5\",\n defaultFormat = \"hex\",\n formats = ALL_FORMATS,\n showInput = true,\n withEyeDropper = false,\n label,\n onChange,\n className,\n ...rest\n}) => {\n const [{ colorInput, colorState }, setColor] = useColorState({\n type: \"hex\",\n value: defaultValue,\n });\n const [format, setFormat] = useState<ColorPickerFormat>(defaultFormat);\n // While the input is focused we keep a raw draft so partial/invalid typing\n // isn't clobbered by the normalized value.\n const [draft, setDraft] = useState<string | null>(null);\n\n const currentColor = useMemo(() => new Color(colorInput), [colorInput]);\n // Prefer the user's exact input when it's already in the selected format\n // (avoids lossy hex<->hsv round-tripping); otherwise convert via colorState.\n const display =\n colorInput.type === format\n ? inputToString(colorInput)\n : stateToString(colorState, format);\n const inputValue = draft ?? display;\n\n const apply = (input: ColorInput) => {\n setColor(input);\n onChange?.(inputToString(input), new Color(input));\n };\n\n const handlePickerChange = (next: Color) => {\n setColor(next);\n onChange?.(next.format(format), next);\n };\n\n const handleFormatChange = (f: ColorPickerFormat) => {\n setFormat(f);\n setDraft(null);\n onChange?.(stateToString(colorState, f), currentColor);\n };\n\n const handleInputChange = (text: string) => {\n setDraft(text);\n const parsed = parseValue(text, format);\n if (parsed) apply(parsed);\n };\n\n return (\n <div className={cn(\"w-full max-w-xs\", className)} {...rest}>\n {label && (\n <span className=\"mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400\">\n {label}\n </span>\n )}\n <RBColorPicker\n color={colorInput}\n onChange={handlePickerChange}\n className=\"rounded-2xl border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-white/[0.03]\"\n >\n <RBColorPicker.Saturation className=\"mb-3 h-40 overflow-hidden rounded-lg\" />\n <div className=\"flex items-center gap-3\">\n {withEyeDropper && (\n <RBColorPicker.EyeDropper className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-white/[0.03]\">\n {pipetteIcon}\n </RBColorPicker.EyeDropper>\n )}\n <div className=\"flex flex-1 flex-col gap-2\">\n <RBColorPicker.Hue className=\"h-3 overflow-hidden rounded-full\" />\n <RBColorPicker.Alpha className=\"h-3 overflow-hidden rounded-full\" />\n </div>\n </div>\n </RBColorPicker>\n\n {showInput && (\n <div className=\"mt-3 flex items-stretch gap-2\">\n <span\n aria-hidden=\"true\"\n className=\"h-11 w-11 shrink-0 rounded-lg border border-gray-200 dark:border-gray-700\"\n style={{ backgroundColor: currentColor.format(\"rgba\") }}\n />\n {formats.length > 1 && (\n <select\n aria-label=\"Color format\"\n value={format}\n onChange={(e) => handleFormatChange(e.target.value as ColorPickerFormat)}\n className=\"h-11 shrink-0 rounded-lg border border-gray-300 bg-transparent px-2 text-sm text-gray-700 focus:outline-hidden dark:border-gray-700 dark:text-gray-300\"\n >\n {formats.map((f) => (\n <option key={f} value={f}>\n {f.toUpperCase()}\n </option>\n ))}\n </select>\n )}\n <input\n aria-label=\"Color value\"\n value={inputValue}\n onChange={(e) => handleInputChange(e.target.value)}\n onBlur={() => setDraft(null)}\n className=\"h-11 w-full rounded-lg border border-gray-300 bg-transparent px-3 text-sm text-gray-800 focus:outline-hidden dark:border-gray-700 dark:text-white/90\"\n />\n </div>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from './chunk-ZLIYUUA4.js';
|
|
3
|
+
import { useState, useMemo } from 'react';
|
|
4
|
+
import { useColorState, Color, ColorPicker as ColorPicker$1 } from 'react-beautiful-color';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var ALL_FORMATS = ["hex", "rgb", "rgba", "hsl", "hsla"];
|
|
8
|
+
function parseValue(text, format) {
|
|
9
|
+
const t = text.trim();
|
|
10
|
+
if (format === "hex") {
|
|
11
|
+
return /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t) ? { type: "hex", value: t } : null;
|
|
12
|
+
}
|
|
13
|
+
const n = t.match(/-?\d*\.?\d+/g)?.map(Number) ?? [];
|
|
14
|
+
if (format === "rgb" && n.length >= 3) return { type: "rgb", r: n[0], g: n[1], b: n[2] };
|
|
15
|
+
if (format === "rgba" && n.length >= 4)
|
|
16
|
+
return { type: "rgba", r: n[0], g: n[1], b: n[2], a: n[3] };
|
|
17
|
+
if (format === "hsl" && n.length >= 3) return { type: "hsl", h: n[0], s: n[1], l: n[2] };
|
|
18
|
+
if (format === "hsla" && n.length >= 4)
|
|
19
|
+
return { type: "hsla", h: n[0], s: n[1], l: n[2], a: n[3] };
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function inputToString(input) {
|
|
23
|
+
switch (input.type) {
|
|
24
|
+
case "hex":
|
|
25
|
+
return input.value;
|
|
26
|
+
case "rgb":
|
|
27
|
+
return `rgb(${input.r}, ${input.g}, ${input.b})`;
|
|
28
|
+
case "rgba":
|
|
29
|
+
return `rgba(${input.r}, ${input.g}, ${input.b}, ${input.a})`;
|
|
30
|
+
case "hsl":
|
|
31
|
+
return `hsl(${input.h}, ${input.s}%, ${input.l}%)`;
|
|
32
|
+
case "hsla":
|
|
33
|
+
return `hsla(${input.h}, ${input.s}%, ${input.l}%, ${input.a})`;
|
|
34
|
+
case "hsv":
|
|
35
|
+
return `hsv(${input.h}, ${input.s}%, ${input.v}%)`;
|
|
36
|
+
case "hsva":
|
|
37
|
+
return `hsva(${input.h}, ${input.s}%, ${input.v}%, ${input.a})`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function stateToString(state, format) {
|
|
41
|
+
switch (format) {
|
|
42
|
+
case "hex":
|
|
43
|
+
return state.hex;
|
|
44
|
+
case "rgb":
|
|
45
|
+
return `rgb(${state.rgb.r}, ${state.rgb.g}, ${state.rgb.b})`;
|
|
46
|
+
case "rgba":
|
|
47
|
+
return `rgba(${state.rgba.r}, ${state.rgba.g}, ${state.rgba.b}, ${state.rgba.a})`;
|
|
48
|
+
case "hsl":
|
|
49
|
+
return `hsl(${state.hsl.h}, ${state.hsl.s}%, ${state.hsl.l}%)`;
|
|
50
|
+
case "hsla":
|
|
51
|
+
return `hsla(${state.hsla.h}, ${state.hsla.s}%, ${state.hsla.l}%, ${state.hsla.a})`;
|
|
52
|
+
default:
|
|
53
|
+
return state.hex;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var pipetteIcon = /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
57
|
+
"path",
|
|
58
|
+
{
|
|
59
|
+
d: "M19.5 3.5a2.12 2.12 0 0 0-3 0l-2.3 2.3-1-1-1.4 1.4 1 1L4 14.9V19h4.1l7.7-7.7 1 1 1.4-1.4-1-1 2.3-2.3a2.12 2.12 0 0 0 0-3ZM7.3 17.6H6v-1.3l6.6-6.6 1.3 1.3-6.6 6.6Z",
|
|
60
|
+
fill: "currentColor"
|
|
61
|
+
}
|
|
62
|
+
) });
|
|
63
|
+
var ColorPicker = ({
|
|
64
|
+
defaultValue = "#3641f5",
|
|
65
|
+
defaultFormat = "hex",
|
|
66
|
+
formats = ALL_FORMATS,
|
|
67
|
+
showInput = true,
|
|
68
|
+
withEyeDropper = false,
|
|
69
|
+
label,
|
|
70
|
+
onChange,
|
|
71
|
+
className,
|
|
72
|
+
...rest
|
|
73
|
+
}) => {
|
|
74
|
+
const [{ colorInput, colorState }, setColor] = useColorState({
|
|
75
|
+
type: "hex",
|
|
76
|
+
value: defaultValue
|
|
77
|
+
});
|
|
78
|
+
const [format, setFormat] = useState(defaultFormat);
|
|
79
|
+
const [draft, setDraft] = useState(null);
|
|
80
|
+
const currentColor = useMemo(() => new Color(colorInput), [colorInput]);
|
|
81
|
+
const display = colorInput.type === format ? inputToString(colorInput) : stateToString(colorState, format);
|
|
82
|
+
const inputValue = draft ?? display;
|
|
83
|
+
const apply = (input) => {
|
|
84
|
+
setColor(input);
|
|
85
|
+
onChange?.(inputToString(input), new Color(input));
|
|
86
|
+
};
|
|
87
|
+
const handlePickerChange = (next) => {
|
|
88
|
+
setColor(next);
|
|
89
|
+
onChange?.(next.format(format), next);
|
|
90
|
+
};
|
|
91
|
+
const handleFormatChange = (f) => {
|
|
92
|
+
setFormat(f);
|
|
93
|
+
setDraft(null);
|
|
94
|
+
onChange?.(stateToString(colorState, f), currentColor);
|
|
95
|
+
};
|
|
96
|
+
const handleInputChange = (text) => {
|
|
97
|
+
setDraft(text);
|
|
98
|
+
const parsed = parseValue(text, format);
|
|
99
|
+
if (parsed) apply(parsed);
|
|
100
|
+
};
|
|
101
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("w-full max-w-xs", className), ...rest, children: [
|
|
102
|
+
label && /* @__PURE__ */ jsx("span", { className: "mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400", children: label }),
|
|
103
|
+
/* @__PURE__ */ jsxs(
|
|
104
|
+
ColorPicker$1,
|
|
105
|
+
{
|
|
106
|
+
color: colorInput,
|
|
107
|
+
onChange: handlePickerChange,
|
|
108
|
+
className: "rounded-2xl border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-white/[0.03]",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsx(ColorPicker$1.Saturation, { className: "mb-3 h-40 overflow-hidden rounded-lg" }),
|
|
111
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
112
|
+
withEyeDropper && /* @__PURE__ */ jsx(ColorPicker$1.EyeDropper, { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-white/[0.03]", children: pipetteIcon }),
|
|
113
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
114
|
+
/* @__PURE__ */ jsx(ColorPicker$1.Hue, { className: "h-3 overflow-hidden rounded-full" }),
|
|
115
|
+
/* @__PURE__ */ jsx(ColorPicker$1.Alpha, { className: "h-3 overflow-hidden rounded-full" })
|
|
116
|
+
] })
|
|
117
|
+
] })
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
showInput && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-stretch gap-2", children: [
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
"span",
|
|
124
|
+
{
|
|
125
|
+
"aria-hidden": "true",
|
|
126
|
+
className: "h-11 w-11 shrink-0 rounded-lg border border-gray-200 dark:border-gray-700",
|
|
127
|
+
style: { backgroundColor: currentColor.format("rgba") }
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
formats.length > 1 && /* @__PURE__ */ jsx(
|
|
131
|
+
"select",
|
|
132
|
+
{
|
|
133
|
+
"aria-label": "Color format",
|
|
134
|
+
value: format,
|
|
135
|
+
onChange: (e) => handleFormatChange(e.target.value),
|
|
136
|
+
className: "h-11 shrink-0 rounded-lg border border-gray-300 bg-transparent px-2 text-sm text-gray-700 focus:outline-hidden dark:border-gray-700 dark:text-gray-300",
|
|
137
|
+
children: formats.map((f) => /* @__PURE__ */ jsx("option", { value: f, children: f.toUpperCase() }, f))
|
|
138
|
+
}
|
|
139
|
+
),
|
|
140
|
+
/* @__PURE__ */ jsx(
|
|
141
|
+
"input",
|
|
142
|
+
{
|
|
143
|
+
"aria-label": "Color value",
|
|
144
|
+
value: inputValue,
|
|
145
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
146
|
+
onBlur: () => setDraft(null),
|
|
147
|
+
className: "h-11 w-full rounded-lg border border-gray-300 bg-transparent px-3 text-sm text-gray-800 focus:outline-hidden dark:border-gray-700 dark:text-white/90"
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
] })
|
|
151
|
+
] });
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export { ColorPicker };
|
|
155
|
+
//# sourceMappingURL=chunk-AGRX5ZR6.js.map
|
|
156
|
+
//# sourceMappingURL=chunk-AGRX5ZR6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ColorPicker/ColorPicker.tsx"],"names":["RBColorPicker"],"mappings":"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","file":"chunk-AGRX5ZR6.js","sourcesContent":["\"use client\";\nimport React, { useMemo, useState } from \"react\";\nimport {\n ColorPicker as RBColorPicker,\n useColorState,\n Color,\n} from \"react-beautiful-color\";\nimport { cn } from \"../../lib/cn\";\n\n// `react-beautiful-color` doesn't re-export these from its entry, so derive them\n// from the hook's inferred return type.\ntype ColorInput = ReturnType<typeof useColorState>[0][\"colorInput\"];\ntype ColorState = ReturnType<typeof useColorState>[0][\"colorState\"];\n\nexport type ColorPickerFormat = \"hex\" | \"rgb\" | \"rgba\" | \"hsl\" | \"hsla\";\n\nexport interface ColorPickerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** Initial color (uncontrolled). Any hex string, e.g. `\"#3641f5\"`. */\n defaultValue?: string;\n /** Format selected on first render. Default: `\"hex\"`. */\n defaultFormat?: ColorPickerFormat;\n /** Formats offered in the switcher. Default: all five. */\n formats?: ColorPickerFormat[];\n /** Render the value input + format switcher. Default: `true`. */\n showInput?: boolean;\n /** Show the native eye-dropper button (browser support varies). */\n withEyeDropper?: boolean;\n /** Optional label rendered above the picker. */\n label?: string;\n /** Fires on every change with the formatted string and the `Color` instance. */\n onChange?: (value: string, color: Color) => void;\n}\n\nconst ALL_FORMATS: ColorPickerFormat[] = [\"hex\", \"rgb\", \"rgba\", \"hsl\", \"hsla\"];\n\n/** Parse the text in the input back into a `ColorInput`, or `null` if invalid. */\nfunction parseValue(text: string, format: ColorPickerFormat): ColorInput | null {\n const t = text.trim();\n if (format === \"hex\") {\n return /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t)\n ? { type: \"hex\", value: t }\n : null;\n }\n const n = t.match(/-?\\d*\\.?\\d+/g)?.map(Number) ?? [];\n if (format === \"rgb\" && n.length >= 3) return { type: \"rgb\", r: n[0], g: n[1], b: n[2] };\n if (format === \"rgba\" && n.length >= 4)\n return { type: \"rgba\", r: n[0], g: n[1], b: n[2], a: n[3] };\n if (format === \"hsl\" && n.length >= 3) return { type: \"hsl\", h: n[0], s: n[1], l: n[2] };\n if (format === \"hsla\" && n.length >= 4)\n return { type: \"hsla\", h: n[0], s: n[1], l: n[2], a: n[3] };\n return null;\n}\n\n/** Format a `ColorInput` (preserving the user's exact values) into a CSS string. */\nfunction inputToString(input: ColorInput): string {\n switch (input.type) {\n case \"hex\":\n return input.value;\n case \"rgb\":\n return `rgb(${input.r}, ${input.g}, ${input.b})`;\n case \"rgba\":\n return `rgba(${input.r}, ${input.g}, ${input.b}, ${input.a})`;\n case \"hsl\":\n return `hsl(${input.h}, ${input.s}%, ${input.l}%)`;\n case \"hsla\":\n return `hsla(${input.h}, ${input.s}%, ${input.l}%, ${input.a})`;\n case \"hsv\":\n return `hsv(${input.h}, ${input.s}%, ${input.v}%)`;\n case \"hsva\":\n return `hsva(${input.h}, ${input.s}%, ${input.v}%, ${input.a})`;\n }\n}\n\n/** Format the resolved `ColorState` into the requested CSS string. */\nfunction stateToString(state: ColorState, format: ColorPickerFormat): string {\n switch (format) {\n case \"hex\":\n return state.hex;\n case \"rgb\":\n return `rgb(${state.rgb.r}, ${state.rgb.g}, ${state.rgb.b})`;\n case \"rgba\":\n return `rgba(${state.rgba.r}, ${state.rgba.g}, ${state.rgba.b}, ${state.rgba.a})`;\n case \"hsl\":\n return `hsl(${state.hsl.h}, ${state.hsl.s}%, ${state.hsl.l}%)`;\n case \"hsla\":\n return `hsla(${state.hsla.h}, ${state.hsla.s}%, ${state.hsla.l}%, ${state.hsla.a})`;\n default:\n return state.hex;\n }\n}\n\nconst pipetteIcon = (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M19.5 3.5a2.12 2.12 0 0 0-3 0l-2.3 2.3-1-1-1.4 1.4 1 1L4 14.9V19h4.1l7.7-7.7 1 1 1.4-1.4-1-1 2.3-2.3a2.12 2.12 0 0 0 0-3ZM7.3 17.6H6v-1.3l6.6-6.6 1.3 1.3-6.6 6.6Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const ColorPicker: React.FC<ColorPickerProps> = ({\n defaultValue = \"#3641f5\",\n defaultFormat = \"hex\",\n formats = ALL_FORMATS,\n showInput = true,\n withEyeDropper = false,\n label,\n onChange,\n className,\n ...rest\n}) => {\n const [{ colorInput, colorState }, setColor] = useColorState({\n type: \"hex\",\n value: defaultValue,\n });\n const [format, setFormat] = useState<ColorPickerFormat>(defaultFormat);\n // While the input is focused we keep a raw draft so partial/invalid typing\n // isn't clobbered by the normalized value.\n const [draft, setDraft] = useState<string | null>(null);\n\n const currentColor = useMemo(() => new Color(colorInput), [colorInput]);\n // Prefer the user's exact input when it's already in the selected format\n // (avoids lossy hex<->hsv round-tripping); otherwise convert via colorState.\n const display =\n colorInput.type === format\n ? inputToString(colorInput)\n : stateToString(colorState, format);\n const inputValue = draft ?? display;\n\n const apply = (input: ColorInput) => {\n setColor(input);\n onChange?.(inputToString(input), new Color(input));\n };\n\n const handlePickerChange = (next: Color) => {\n setColor(next);\n onChange?.(next.format(format), next);\n };\n\n const handleFormatChange = (f: ColorPickerFormat) => {\n setFormat(f);\n setDraft(null);\n onChange?.(stateToString(colorState, f), currentColor);\n };\n\n const handleInputChange = (text: string) => {\n setDraft(text);\n const parsed = parseValue(text, format);\n if (parsed) apply(parsed);\n };\n\n return (\n <div className={cn(\"w-full max-w-xs\", className)} {...rest}>\n {label && (\n <span className=\"mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-400\">\n {label}\n </span>\n )}\n <RBColorPicker\n color={colorInput}\n onChange={handlePickerChange}\n className=\"rounded-2xl border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-white/[0.03]\"\n >\n <RBColorPicker.Saturation className=\"mb-3 h-40 overflow-hidden rounded-lg\" />\n <div className=\"flex items-center gap-3\">\n {withEyeDropper && (\n <RBColorPicker.EyeDropper className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-white/[0.03]\">\n {pipetteIcon}\n </RBColorPicker.EyeDropper>\n )}\n <div className=\"flex flex-1 flex-col gap-2\">\n <RBColorPicker.Hue className=\"h-3 overflow-hidden rounded-full\" />\n <RBColorPicker.Alpha className=\"h-3 overflow-hidden rounded-full\" />\n </div>\n </div>\n </RBColorPicker>\n\n {showInput && (\n <div className=\"mt-3 flex items-stretch gap-2\">\n <span\n aria-hidden=\"true\"\n className=\"h-11 w-11 shrink-0 rounded-lg border border-gray-200 dark:border-gray-700\"\n style={{ backgroundColor: currentColor.format(\"rgba\") }}\n />\n {formats.length > 1 && (\n <select\n aria-label=\"Color format\"\n value={format}\n onChange={(e) => handleFormatChange(e.target.value as ColorPickerFormat)}\n className=\"h-11 shrink-0 rounded-lg border border-gray-300 bg-transparent px-2 text-sm text-gray-700 focus:outline-hidden dark:border-gray-700 dark:text-gray-300\"\n >\n {formats.map((f) => (\n <option key={f} value={f}>\n {f.toUpperCase()}\n </option>\n ))}\n </select>\n )}\n <input\n aria-label=\"Color value\"\n value={inputValue}\n onChange={(e) => handleInputChange(e.target.value)}\n onBlur={() => setDraft(null)}\n className=\"h-11 w-full rounded-lg border border-gray-300 bg-transparent px-3 text-sm text-gray-800 focus:outline-hidden dark:border-gray-700 dark:text-white/90\"\n />\n </div>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk3T6AZMUZ_cjs = require('../../chunk-3T6AZMUZ.cjs');
|
|
5
|
+
require('../../chunk-YERNSNT4.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "ColorPicker", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return chunk3T6AZMUZ_cjs.ColorPicker; }
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=ColorPicker.cjs.map
|
|
14
|
+
//# sourceMappingURL=ColorPicker.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ColorPicker.cjs"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Color } from 'react-beautiful-color';
|
|
3
|
+
|
|
4
|
+
type ColorPickerFormat = "hex" | "rgb" | "rgba" | "hsl" | "hsla";
|
|
5
|
+
interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
6
|
+
/** Initial color (uncontrolled). Any hex string, e.g. `"#3641f5"`. */
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
/** Format selected on first render. Default: `"hex"`. */
|
|
9
|
+
defaultFormat?: ColorPickerFormat;
|
|
10
|
+
/** Formats offered in the switcher. Default: all five. */
|
|
11
|
+
formats?: ColorPickerFormat[];
|
|
12
|
+
/** Render the value input + format switcher. Default: `true`. */
|
|
13
|
+
showInput?: boolean;
|
|
14
|
+
/** Show the native eye-dropper button (browser support varies). */
|
|
15
|
+
withEyeDropper?: boolean;
|
|
16
|
+
/** Optional label rendered above the picker. */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** Fires on every change with the formatted string and the `Color` instance. */
|
|
19
|
+
onChange?: (value: string, color: Color) => void;
|
|
20
|
+
}
|
|
21
|
+
declare const ColorPicker: React.FC<ColorPickerProps>;
|
|
22
|
+
|
|
23
|
+
export { ColorPicker, type ColorPickerFormat, type ColorPickerProps };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Color } from 'react-beautiful-color';
|
|
3
|
+
|
|
4
|
+
type ColorPickerFormat = "hex" | "rgb" | "rgba" | "hsl" | "hsla";
|
|
5
|
+
interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
6
|
+
/** Initial color (uncontrolled). Any hex string, e.g. `"#3641f5"`. */
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
/** Format selected on first render. Default: `"hex"`. */
|
|
9
|
+
defaultFormat?: ColorPickerFormat;
|
|
10
|
+
/** Formats offered in the switcher. Default: all five. */
|
|
11
|
+
formats?: ColorPickerFormat[];
|
|
12
|
+
/** Render the value input + format switcher. Default: `true`. */
|
|
13
|
+
showInput?: boolean;
|
|
14
|
+
/** Show the native eye-dropper button (browser support varies). */
|
|
15
|
+
withEyeDropper?: boolean;
|
|
16
|
+
/** Optional label rendered above the picker. */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** Fires on every change with the formatted string and the `Color` instance. */
|
|
19
|
+
onChange?: (value: string, color: Color) => void;
|
|
20
|
+
}
|
|
21
|
+
declare const ColorPicker: React.FC<ColorPickerProps>;
|
|
22
|
+
|
|
23
|
+
export { ColorPicker, type ColorPickerFormat, type ColorPickerProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ColorPicker.js"}
|