@kayord/ui 2.1.8 → 2.1.10
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/dist/components/custom/combobox/Combobox.svelte.d.ts +1 -1
- package/dist/components/ui/accordion/accordion-root.svelte.d.ts +1 -1
- package/dist/components/ui/accordion/accordion.svelte.d.ts +1 -1
- package/dist/components/ui/audio-wave/audio-wave.svelte +58 -0
- package/dist/components/ui/audio-wave/audio-wave.svelte.d.ts +10 -0
- package/dist/components/ui/audio-wave/index.d.ts +2 -0
- package/dist/components/ui/audio-wave/index.js +2 -0
- package/dist/components/ui/calendar/calendar-month-select.svelte +5 -1
- package/dist/components/ui/calendar/calendar-year-select.svelte +5 -1
- package/dist/components/ui/calendar/calendar.svelte.d.ts +1 -1
- package/dist/components/ui/chip/chip-group.svelte +10 -0
- package/dist/components/ui/chip/chip-group.svelte.d.ts +8 -0
- package/dist/components/ui/chip/chip.svelte +132 -0
- package/dist/components/ui/chip/chip.svelte.d.ts +18 -0
- package/dist/components/ui/chip/index.d.ts +3 -0
- package/dist/components/ui/chip/index.js +3 -0
- package/dist/components/ui/color-picker/color-picker.svelte +474 -0
- package/dist/components/ui/color-picker/color-picker.svelte.d.ts +11 -0
- package/dist/components/ui/color-picker/index.d.ts +2 -0
- package/dist/components/ui/color-picker/index.js +2 -0
- package/dist/components/ui/command/command-dialog.svelte.d.ts +1 -1
- package/dist/components/ui/command/command-input.svelte.d.ts +1 -1
- package/dist/components/ui/command/command.svelte.d.ts +1 -1
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/data-table/data-table.svelte.js +2 -3
- package/dist/components/ui/date-strip/ctx.d.ts +10 -0
- package/dist/components/ui/date-strip/ctx.js +8 -0
- package/dist/components/ui/date-strip/date-strip-item.svelte +52 -0
- package/dist/components/ui/date-strip/date-strip-item.svelte.d.ts +8 -0
- package/dist/components/ui/date-strip/date-strip.svelte +65 -0
- package/dist/components/ui/date-strip/date-strip.svelte.d.ts +15 -0
- package/dist/components/ui/date-strip/index.d.ts +3 -0
- package/dist/components/ui/date-strip/index.js +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/dynamic-select/ctx.d.ts +15 -0
- package/dist/components/ui/dynamic-select/ctx.js +8 -0
- package/dist/components/ui/dynamic-select/dynamic-select-content.svelte +42 -0
- package/dist/components/ui/dynamic-select/dynamic-select-content.svelte.d.ts +7 -0
- package/dist/components/ui/dynamic-select/dynamic-select-item.svelte +16 -0
- package/dist/components/ui/dynamic-select/dynamic-select-item.svelte.d.ts +8 -0
- package/dist/components/ui/dynamic-select/dynamic-select-trigger.svelte +20 -0
- package/dist/components/ui/dynamic-select/dynamic-select-trigger.svelte.d.ts +8 -0
- package/dist/components/ui/dynamic-select/dynamic-select.svelte +37 -0
- package/dist/components/ui/dynamic-select/dynamic-select.svelte.d.ts +9 -0
- package/dist/components/ui/dynamic-select/index.d.ts +18 -0
- package/dist/components/ui/dynamic-select/index.js +7 -0
- package/dist/components/ui/field/field-error.svelte +1 -1
- package/dist/components/ui/index.d.ts +7 -0
- package/dist/components/ui/index.js +8 -0
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +2 -2
- package/dist/components/ui/input-group/input-group-textarea.svelte.d.ts +1 -1
- package/dist/components/ui/input-otp/input-otp.svelte.d.ts +1 -1
- package/dist/components/ui/menubar/menubar-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/native-select/native-select.svelte.d.ts +1 -1
- package/dist/components/ui/radio-group/radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +2 -2
- package/dist/components/ui/slider/slider.svelte.d.ts +1 -1
- package/dist/components/ui/status-dot/index.d.ts +2 -0
- package/dist/components/ui/status-dot/index.js +2 -0
- package/dist/components/ui/status-dot/status-dot.svelte +56 -0
- package/dist/components/ui/status-dot/status-dot.svelte.d.ts +9 -0
- package/dist/components/ui/tabs/tabs.svelte.d.ts +1 -1
- package/dist/components/ui/textarea/textarea.svelte.d.ts +1 -1
- package/dist/components/ui/timeline/index.d.ts +8 -0
- package/dist/components/ui/timeline/index.js +8 -0
- package/dist/components/ui/timeline/timeline-content.svelte +16 -0
- package/dist/components/ui/timeline/timeline-content.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline-date.svelte +10 -0
- package/dist/components/ui/timeline/timeline-date.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline-description.svelte +10 -0
- package/dist/components/ui/timeline/timeline-description.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline-item.svelte +16 -0
- package/dist/components/ui/timeline/timeline-item.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline-separator.svelte +25 -0
- package/dist/components/ui/timeline/timeline-separator.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline-title.svelte +10 -0
- package/dist/components/ui/timeline/timeline-title.svelte.d.ts +8 -0
- package/dist/components/ui/timeline/timeline.svelte +17 -0
- package/dist/components/ui/timeline/timeline.svelte.d.ts +8 -0
- package/dist/components/ui/toggle-group/toggle-group-item.svelte.d.ts +1 -1
- package/dist/components/ui/toggle-group/toggle-group.svelte.d.ts +1 -1
- package/package.json +17 -12
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../utils";
|
|
3
|
+
import { Button } from "../button";
|
|
4
|
+
import { ChevronDown } from "lucide-svelte";
|
|
5
|
+
import * as Popover from "../popover";
|
|
6
|
+
import * as Command from "../command";
|
|
7
|
+
import * as ButtonGroup from "../button-group";
|
|
8
|
+
import { Input } from "../input";
|
|
9
|
+
|
|
10
|
+
type ColorFormat = "hex" | "rgb" | "hsl" | "oklch";
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
value = $bindable("#000000"),
|
|
14
|
+
class: className,
|
|
15
|
+
allowOpacity = false,
|
|
16
|
+
defaultFormat = "hex",
|
|
17
|
+
formats = ["hex", "rgb", "hsl", "oklch"],
|
|
18
|
+
}: {
|
|
19
|
+
value?: string;
|
|
20
|
+
class?: string;
|
|
21
|
+
allowOpacity?: boolean;
|
|
22
|
+
defaultFormat?: ColorFormat;
|
|
23
|
+
formats?: ColorFormat[];
|
|
24
|
+
} = $props();
|
|
25
|
+
|
|
26
|
+
let h = $state(0);
|
|
27
|
+
let s = $state(0);
|
|
28
|
+
let v = $state(0);
|
|
29
|
+
let a = $state(1);
|
|
30
|
+
let activeFormat = $state<ColorFormat>(defaultFormat);
|
|
31
|
+
let isDragging = $state(false);
|
|
32
|
+
|
|
33
|
+
let sbRef: HTMLDivElement | undefined = $state();
|
|
34
|
+
let hueRef: HTMLDivElement | undefined = $state();
|
|
35
|
+
let alphaRef: HTMLDivElement | undefined = $state();
|
|
36
|
+
let formatOpen = $state(false);
|
|
37
|
+
|
|
38
|
+
$effect(() => {
|
|
39
|
+
if (!isDragging) {
|
|
40
|
+
const parsed = parseColor(value);
|
|
41
|
+
if (parsed) {
|
|
42
|
+
const currentStr = formatOutput(h, s, v, a, activeFormat);
|
|
43
|
+
const parsedStr = formatOutput(parsed.h, parsed.s, parsed.v, parsed.a, activeFormat);
|
|
44
|
+
|
|
45
|
+
if (currentStr !== parsedStr) {
|
|
46
|
+
h = parsed.h;
|
|
47
|
+
s = parsed.s;
|
|
48
|
+
v = parsed.v;
|
|
49
|
+
a = parsed.a;
|
|
50
|
+
if (value.startsWith("rgb")) activeFormat = "rgb";
|
|
51
|
+
else if (value.startsWith("hsl")) activeFormat = "hsl";
|
|
52
|
+
else if (value.startsWith("oklch")) activeFormat = "oklch";
|
|
53
|
+
else activeFormat = "hex";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function updateExternal() {
|
|
60
|
+
value = formatOutput(h, s, v, a, activeFormat);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function setFormat(fmt: ColorFormat) {
|
|
64
|
+
activeFormat = fmt;
|
|
65
|
+
updateExternal();
|
|
66
|
+
formatOpen = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseColor(str: string) {
|
|
70
|
+
str = str.trim().toLowerCase();
|
|
71
|
+
if (str.startsWith("#")) {
|
|
72
|
+
let hex = str.replace("#", "");
|
|
73
|
+
let r = 0,
|
|
74
|
+
g = 0,
|
|
75
|
+
b = 0,
|
|
76
|
+
alpha = 1;
|
|
77
|
+
if (hex.length === 3) {
|
|
78
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
79
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
80
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
81
|
+
} else if (hex.length === 6) {
|
|
82
|
+
r = parseInt(hex.substring(0, 2), 16);
|
|
83
|
+
g = parseInt(hex.substring(2, 4), 16);
|
|
84
|
+
b = parseInt(hex.substring(4, 6), 16);
|
|
85
|
+
} else if (hex.length === 8) {
|
|
86
|
+
r = parseInt(hex.substring(0, 2), 16);
|
|
87
|
+
g = parseInt(hex.substring(2, 4), 16);
|
|
88
|
+
b = parseInt(hex.substring(4, 6), 16);
|
|
89
|
+
alpha = parseInt(hex.substring(6, 8), 16) / 255;
|
|
90
|
+
}
|
|
91
|
+
return { ...rgbToHsv(r, g, b), a: alpha };
|
|
92
|
+
}
|
|
93
|
+
if (str.startsWith("rgb")) {
|
|
94
|
+
const values = str.match(/[\d.]+/g)?.map(Number);
|
|
95
|
+
if (values && values.length >= 3) return { ...rgbToHsv(values[0], values[1], values[2]), a: values[3] ?? 1 };
|
|
96
|
+
}
|
|
97
|
+
if (str.startsWith("hsl")) {
|
|
98
|
+
const values = str.match(/[\d.]+/g)?.map(Number);
|
|
99
|
+
if (values && values.length >= 3) {
|
|
100
|
+
const sNorm = values[1] / 100,
|
|
101
|
+
lNorm = values[2] / 100;
|
|
102
|
+
let vNorm = lNorm + sNorm * Math.min(lNorm, 1 - lNorm);
|
|
103
|
+
let sHsv = vNorm === 0 ? 0 : 2 * (1 - lNorm / vNorm);
|
|
104
|
+
return { h: values[0], s: sHsv * 100, v: vNorm * 100, a: values[3] ?? 1 };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (str.startsWith("oklch")) {
|
|
108
|
+
const values = str.match(/[\d.%]+/g)?.map((s) => (s.includes("%") ? parseFloat(s) / 100 : parseFloat(s)));
|
|
109
|
+
if (values && values.length >= 3) {
|
|
110
|
+
const rgb = oklchToRgb(values[0], values[1], values[2]);
|
|
111
|
+
return { ...rgbToHsv(rgb.r, rgb.g, rgb.b), a: values[3] ?? 1 };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function formatOutput(h: number, s: number, v: number, a: number, format: ColorFormat): string {
|
|
118
|
+
if (format === "hex") return hsvToHex(h, s, v, a);
|
|
119
|
+
if (format === "rgb") return hsvToRgbString(h, s, v, a);
|
|
120
|
+
if (format === "hsl") return hsvToHslString(h, s, v, a);
|
|
121
|
+
if (format === "oklch") return hsvToOklchString(h, s, v, a);
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function rgbToHsv(r: number, g: number, b: number) {
|
|
126
|
+
r /= 255;
|
|
127
|
+
g /= 255;
|
|
128
|
+
b /= 255;
|
|
129
|
+
const max = Math.max(r, g, b),
|
|
130
|
+
min = Math.min(r, g, b);
|
|
131
|
+
let h = 0,
|
|
132
|
+
s = 0,
|
|
133
|
+
v = max;
|
|
134
|
+
const d = max - min;
|
|
135
|
+
s = max === 0 ? 0 : d / max;
|
|
136
|
+
if (max !== min) {
|
|
137
|
+
switch (max) {
|
|
138
|
+
case r:
|
|
139
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
140
|
+
break;
|
|
141
|
+
case g:
|
|
142
|
+
h = (b - r) / d + 2;
|
|
143
|
+
break;
|
|
144
|
+
case b:
|
|
145
|
+
h = (r - g) / d + 4;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
h /= 6;
|
|
149
|
+
}
|
|
150
|
+
return { h: h * 360, s: s * 100, v: v * 100 };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function hsvToRgb(h: number, s: number, v: number) {
|
|
154
|
+
let sNorm = s / 100,
|
|
155
|
+
vNorm = v / 100;
|
|
156
|
+
let r = 0,
|
|
157
|
+
g = 0,
|
|
158
|
+
b = 0;
|
|
159
|
+
const i = Math.floor(h / 60),
|
|
160
|
+
f = h / 60 - i,
|
|
161
|
+
p = vNorm * (1 - sNorm),
|
|
162
|
+
q = vNorm * (1 - f * sNorm),
|
|
163
|
+
t = vNorm * (1 - (1 - f) * sNorm);
|
|
164
|
+
switch (i % 6) {
|
|
165
|
+
case 0:
|
|
166
|
+
r = vNorm;
|
|
167
|
+
g = t;
|
|
168
|
+
b = p;
|
|
169
|
+
break;
|
|
170
|
+
case 1:
|
|
171
|
+
r = q;
|
|
172
|
+
g = vNorm;
|
|
173
|
+
b = p;
|
|
174
|
+
break;
|
|
175
|
+
case 2:
|
|
176
|
+
r = p;
|
|
177
|
+
g = vNorm;
|
|
178
|
+
b = t;
|
|
179
|
+
break;
|
|
180
|
+
case 3:
|
|
181
|
+
r = p;
|
|
182
|
+
g = q;
|
|
183
|
+
b = vNorm;
|
|
184
|
+
break;
|
|
185
|
+
case 4:
|
|
186
|
+
r = t;
|
|
187
|
+
g = p;
|
|
188
|
+
b = vNorm;
|
|
189
|
+
break;
|
|
190
|
+
case 5:
|
|
191
|
+
r = vNorm;
|
|
192
|
+
g = p;
|
|
193
|
+
b = q;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function hsvToOklchString(h: number, s: number, v: number, a: number) {
|
|
200
|
+
const rgb = hsvToRgb(h, s, v);
|
|
201
|
+
const oklch = rgbToOklch(rgb.r, rgb.g, rgb.b);
|
|
202
|
+
const L = (oklch.l * 100).toFixed(1) + "%";
|
|
203
|
+
const C = oklch.c.toFixed(3);
|
|
204
|
+
const H = (oklch.h || 0).toFixed(1);
|
|
205
|
+
|
|
206
|
+
if (allowOpacity && a < 1) return `oklch(${L} ${C} ${H} / ${parseFloat(a.toFixed(2))})`;
|
|
207
|
+
return `oklch(${L} ${C} ${H})`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function rgbToOklch(r: number, g: number, b: number) {
|
|
211
|
+
r /= 255;
|
|
212
|
+
g /= 255;
|
|
213
|
+
b /= 255;
|
|
214
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
215
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
216
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
217
|
+
|
|
218
|
+
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
219
|
+
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
220
|
+
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
221
|
+
|
|
222
|
+
const l_ = Math.cbrt(l),
|
|
223
|
+
m_ = Math.cbrt(m),
|
|
224
|
+
s_ = Math.cbrt(s);
|
|
225
|
+
|
|
226
|
+
const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
|
|
227
|
+
const A = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
|
|
228
|
+
const B = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
|
|
229
|
+
|
|
230
|
+
const C = Math.sqrt(A * A + B * B);
|
|
231
|
+
let H = (Math.atan2(B, A) * 180) / Math.PI;
|
|
232
|
+
if (H < 0) H += 360;
|
|
233
|
+
|
|
234
|
+
return { l: L, c: C, h: H };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function oklchToRgb(l: number, c: number, h: number) {
|
|
238
|
+
const hRad = h * (Math.PI / 180);
|
|
239
|
+
const A = c * Math.cos(hRad);
|
|
240
|
+
const B = c * Math.sin(hRad);
|
|
241
|
+
const L = l;
|
|
242
|
+
|
|
243
|
+
const l_ = L + 0.3963377774 * A + 0.2158037573 * B;
|
|
244
|
+
const m_ = L - 0.1055613458 * A - 0.0638541728 * B;
|
|
245
|
+
const s_ = L - 0.0894841775 * A - 1.291485548 * B;
|
|
246
|
+
|
|
247
|
+
const lLin = l_ * l_ * l_;
|
|
248
|
+
const mLin = m_ * m_ * m_;
|
|
249
|
+
const sLin = s_ * s_ * s_;
|
|
250
|
+
|
|
251
|
+
let r = +4.0767416621 * lLin - 3.3077115913 * mLin + 0.2309699292 * sLin;
|
|
252
|
+
let g = -1.2684380046 * lLin + 2.6097574011 * mLin - 0.3413193965 * sLin;
|
|
253
|
+
let b = -0.0041960863 * lLin - 0.7034186147 * mLin + 1.707614701 * sLin;
|
|
254
|
+
|
|
255
|
+
r = r >= 0.0031308 ? 1.055 * Math.pow(r, 1.0 / 2.4) - 0.055 : 12.92 * r;
|
|
256
|
+
g = g >= 0.0031308 ? 1.055 * Math.pow(g, 1.0 / 2.4) - 0.055 : 12.92 * g;
|
|
257
|
+
b = b >= 0.0031308 ? 1.055 * Math.pow(b, 1.0 / 2.4) - 0.055 : 12.92 * b;
|
|
258
|
+
|
|
259
|
+
r = Math.min(Math.max(0, r), 1) * 255;
|
|
260
|
+
g = Math.min(Math.max(0, g), 1) * 255;
|
|
261
|
+
b = Math.min(Math.max(0, b), 1) * 255;
|
|
262
|
+
return { r, g, b };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function hsvToHex(h: number, s: number, v: number, a: number) {
|
|
266
|
+
const { r, g, b } = hsvToRgb(h, s, v);
|
|
267
|
+
const toHex = (x: number) => {
|
|
268
|
+
const hex = x.toString(16);
|
|
269
|
+
return hex.length === 1 ? "0" + hex : hex;
|
|
270
|
+
};
|
|
271
|
+
let hex = `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
272
|
+
if (allowOpacity && a < 1) hex += toHex(Math.round(a * 255));
|
|
273
|
+
return hex.toUpperCase();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function hsvToRgbString(h: number, s: number, v: number, a: number) {
|
|
277
|
+
const { r, g, b } = hsvToRgb(h, s, v);
|
|
278
|
+
if (allowOpacity && a < 1) return `rgba(${r}, ${g}, ${b}, ${parseFloat(a.toFixed(2))})`;
|
|
279
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function hsvToHslString(h: number, s: number, v: number, a: number) {
|
|
283
|
+
const sNorm = s / 100,
|
|
284
|
+
vNorm = v / 100;
|
|
285
|
+
let l = ((2 - sNorm) * vNorm) / 2;
|
|
286
|
+
let sHsl = l && l < 1 ? (sNorm * vNorm) / (l < 0.5 ? l * 2 : 2 - l * 2) : sNorm;
|
|
287
|
+
if (allowOpacity && a < 1)
|
|
288
|
+
return `hsla(${Math.round(h)}, ${Math.round(sHsl * 100)}%, ${Math.round(l * 100)}%, ${parseFloat(a.toFixed(2))})`;
|
|
289
|
+
return `hsl(${Math.round(h)}, ${Math.round(sHsl * 100)}%, ${Math.round(l * 100)}%)`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function handleDragStart(e: MouseEvent | TouchEvent, fn: (e: MouseEvent | TouchEvent) => void) {
|
|
293
|
+
isDragging = true;
|
|
294
|
+
fn(e);
|
|
295
|
+
const move = (e: MouseEvent | TouchEvent) => fn(e);
|
|
296
|
+
const stop = () => {
|
|
297
|
+
isDragging = false;
|
|
298
|
+
window.removeEventListener("mousemove", move);
|
|
299
|
+
window.removeEventListener("touchmove", move);
|
|
300
|
+
window.removeEventListener("mouseup", stop);
|
|
301
|
+
window.removeEventListener("touchend", stop);
|
|
302
|
+
};
|
|
303
|
+
window.addEventListener("mousemove", move);
|
|
304
|
+
window.addEventListener("touchmove", move);
|
|
305
|
+
window.addEventListener("mouseup", stop);
|
|
306
|
+
window.addEventListener("touchend", stop);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function handleSbChange(e: MouseEvent | TouchEvent) {
|
|
310
|
+
if (!sbRef) return;
|
|
311
|
+
const rect = sbRef.getBoundingClientRect();
|
|
312
|
+
const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
|
|
313
|
+
const clientY = "touches" in e ? e.touches[0].clientY : e.clientY;
|
|
314
|
+
const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
315
|
+
const y = Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
|
|
316
|
+
s = x * 100;
|
|
317
|
+
v = (1 - y) * 100;
|
|
318
|
+
updateExternal();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function handleHueChange(e: MouseEvent | TouchEvent) {
|
|
322
|
+
if (!hueRef) return;
|
|
323
|
+
const rect = hueRef.getBoundingClientRect();
|
|
324
|
+
const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
|
|
325
|
+
const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
326
|
+
h = x * 360;
|
|
327
|
+
updateExternal();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function handleAlphaChange(e: MouseEvent | TouchEvent) {
|
|
331
|
+
if (!alphaRef) return;
|
|
332
|
+
const rect = alphaRef.getBoundingClientRect();
|
|
333
|
+
const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
|
|
334
|
+
const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
335
|
+
a = Math.round(x * 100) / 100;
|
|
336
|
+
updateExternal();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function handleAlphaInput(e: Event & { currentTarget: HTMLInputElement }) {
|
|
340
|
+
let val = parseInt(e.currentTarget.value);
|
|
341
|
+
if (isNaN(val)) return;
|
|
342
|
+
val = Math.max(0, Math.min(100, val));
|
|
343
|
+
a = val / 100;
|
|
344
|
+
updateExternal();
|
|
345
|
+
}
|
|
346
|
+
</script>
|
|
347
|
+
|
|
348
|
+
<div class={cn("bg-popover flex w-[350px] flex-col gap-3 rounded-lg border p-3 shadow-sm", className)}>
|
|
349
|
+
<div
|
|
350
|
+
bind:this={sbRef}
|
|
351
|
+
class="relative h-56 w-full cursor-crosshair touch-none overflow-hidden rounded-md shadow-sm"
|
|
352
|
+
style:background-color={`hsl(${h}, 100%, 50%)`}
|
|
353
|
+
role="slider"
|
|
354
|
+
aria-label="Saturation and Brightness"
|
|
355
|
+
aria-valuenow={s}
|
|
356
|
+
tabindex="0"
|
|
357
|
+
onmousedown={(e) => handleDragStart(e, handleSbChange)}
|
|
358
|
+
ontouchstart={(e) => handleDragStart(e, handleSbChange)}
|
|
359
|
+
>
|
|
360
|
+
<div class="pointer-events-none absolute inset-0 bg-gradient-to-r from-white to-transparent" />
|
|
361
|
+
<div class="pointer-events-none absolute inset-0 bg-gradient-to-t from-black to-transparent" />
|
|
362
|
+
<div
|
|
363
|
+
class="pointer-events-none absolute h-3 w-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/20"
|
|
364
|
+
style:left={`${s}%`}
|
|
365
|
+
style:top={`${100 - v}%`}
|
|
366
|
+
/>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<div class="flex items-center gap-3">
|
|
370
|
+
<div
|
|
371
|
+
class="relative mt-1 h-8 w-8 shrink-0 overflow-hidden rounded-md border bg-[url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==')] shadow-sm"
|
|
372
|
+
>
|
|
373
|
+
<div class="absolute inset-0" style:background-color={hsvToHex(h, s, v, a)} />
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<div class="flex flex-1 flex-col justify-center gap-3">
|
|
377
|
+
<div
|
|
378
|
+
bind:this={hueRef}
|
|
379
|
+
class="relative h-3 w-full cursor-pointer touch-none rounded-full shadow-sm ring-1 ring-black/5"
|
|
380
|
+
style:background={"linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)"}
|
|
381
|
+
role="slider"
|
|
382
|
+
aria-valuenow={h}
|
|
383
|
+
tabindex="0"
|
|
384
|
+
onmousedown={(e) => handleDragStart(e, handleHueChange)}
|
|
385
|
+
ontouchstart={(e) => handleDragStart(e, handleHueChange)}
|
|
386
|
+
>
|
|
387
|
+
<div
|
|
388
|
+
class="pointer-events-none absolute top-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white"
|
|
389
|
+
style:left={`${(h / 360) * 100}%`}
|
|
390
|
+
/>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
{#if allowOpacity}
|
|
394
|
+
<div
|
|
395
|
+
bind:this={alphaRef}
|
|
396
|
+
class="relative h-3 w-full cursor-pointer touch-none rounded-full bg-[url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==')] shadow-sm ring-1 ring-black/5"
|
|
397
|
+
role="slider"
|
|
398
|
+
aria-valuenow={a}
|
|
399
|
+
tabindex="0"
|
|
400
|
+
onmousedown={(e) => handleDragStart(e, handleAlphaChange)}
|
|
401
|
+
ontouchstart={(e) => handleDragStart(e, handleAlphaChange)}
|
|
402
|
+
>
|
|
403
|
+
<div
|
|
404
|
+
class="absolute inset-0 rounded-full"
|
|
405
|
+
style:background={`linear-gradient(to right, transparent, ${hsvToHex(h, s, v, 1)})`}
|
|
406
|
+
/>
|
|
407
|
+
<div
|
|
408
|
+
class="pointer-events-none absolute top-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white"
|
|
409
|
+
style:left={`${a * 100}%`}
|
|
410
|
+
/>
|
|
411
|
+
</div>
|
|
412
|
+
{/if}
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<ButtonGroup.Root class="w-full">
|
|
417
|
+
{#if formats.length > 1}
|
|
418
|
+
<Popover.Root bind:open={formatOpen}>
|
|
419
|
+
<Popover.Trigger>
|
|
420
|
+
{#snippet child({ props })}
|
|
421
|
+
<Button {...props} variant="outline" class="h-9 max-w-[5rem] justify-between px-2 text-[10px]">
|
|
422
|
+
{activeFormat.toUpperCase()}
|
|
423
|
+
<ChevronDown class="h-3 w-3 opacity-50" />
|
|
424
|
+
</Button>
|
|
425
|
+
{/snippet}
|
|
426
|
+
</Popover.Trigger>
|
|
427
|
+
<Popover.Content class="w-[4.5rem] p-0" align="start">
|
|
428
|
+
<Command.Root>
|
|
429
|
+
<Command.List>
|
|
430
|
+
<Command.Group>
|
|
431
|
+
{#each ["hex", "rgb", "hsl", "oklch"] as fmt}
|
|
432
|
+
<Command.Item
|
|
433
|
+
value={fmt}
|
|
434
|
+
onSelect={() => setFormat(fmt as ColorFormat)}
|
|
435
|
+
class="flex h-7 justify-center text-[10px]"
|
|
436
|
+
>
|
|
437
|
+
{fmt.toUpperCase()}
|
|
438
|
+
</Command.Item>
|
|
439
|
+
{/each}
|
|
440
|
+
</Command.Group>
|
|
441
|
+
</Command.List>
|
|
442
|
+
</Command.Root>
|
|
443
|
+
</Popover.Content>
|
|
444
|
+
</Popover.Root>
|
|
445
|
+
{:else}
|
|
446
|
+
<Button variant="outline" class="h-9 max-w-[5rem] justify-between px-2 text-[10px]">
|
|
447
|
+
{activeFormat.toUpperCase()}
|
|
448
|
+
</Button>
|
|
449
|
+
{/if}
|
|
450
|
+
<Input
|
|
451
|
+
class="h-9 flex-1 font-mono text-[10px] uppercase"
|
|
452
|
+
{value}
|
|
453
|
+
oninput={(e) => {
|
|
454
|
+
const parsed = parseColor(e.currentTarget.value);
|
|
455
|
+
if (parsed) {
|
|
456
|
+
h = parsed.h;
|
|
457
|
+
s = parsed.s;
|
|
458
|
+
v = parsed.v;
|
|
459
|
+
a = parsed.a;
|
|
460
|
+
updateExternal();
|
|
461
|
+
}
|
|
462
|
+
}}
|
|
463
|
+
/>
|
|
464
|
+
|
|
465
|
+
{#if allowOpacity}
|
|
466
|
+
<Input
|
|
467
|
+
class="h-9 max-w-[4.2rem] text-right font-mono text-[10px]"
|
|
468
|
+
value={Math.round(a * 100) + "%"}
|
|
469
|
+
oninput={handleAlphaInput}
|
|
470
|
+
maxlength={3}
|
|
471
|
+
/>
|
|
472
|
+
{/if}
|
|
473
|
+
</ButtonGroup.Root>
|
|
474
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ColorFormat = "hex" | "rgb" | "hsl" | "oklch";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
value?: string;
|
|
4
|
+
class?: string;
|
|
5
|
+
allowOpacity?: boolean;
|
|
6
|
+
defaultFormat?: ColorFormat;
|
|
7
|
+
formats?: ColorFormat[];
|
|
8
|
+
};
|
|
9
|
+
declare const ColorPicker: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
10
|
+
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
11
|
+
export default ColorPicker;
|
|
@@ -7,6 +7,6 @@ type $$ComponentProps = WithoutChildrenOrChild<DialogPrimitive.RootProps> & With
|
|
|
7
7
|
title?: string;
|
|
8
8
|
description?: string;
|
|
9
9
|
};
|
|
10
|
-
declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "
|
|
10
|
+
declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "ref" | "value" | "open">;
|
|
11
11
|
type CommandDialog = ReturnType<typeof CommandDialog>;
|
|
12
12
|
export default CommandDialog;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Command as CommandPrimitive } from "bits-ui";
|
|
2
|
-
declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "
|
|
2
|
+
declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "ref" | "value">;
|
|
3
3
|
type CommandInput = ReturnType<typeof CommandInput>;
|
|
4
4
|
export default CommandInput;
|
|
@@ -3,6 +3,6 @@ export type CommandRootApi = CommandPrimitive.Root;
|
|
|
3
3
|
type $$ComponentProps = CommandPrimitive.RootProps & {
|
|
4
4
|
api?: CommandRootApi | null;
|
|
5
5
|
};
|
|
6
|
-
declare const Command: import("svelte").Component<$$ComponentProps, {}, "
|
|
6
|
+
declare const Command: import("svelte").Component<$$ComponentProps, {}, "ref" | "value" | "api">;
|
|
7
7
|
type Command = ReturnType<typeof Command>;
|
|
8
8
|
export default Command;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ContextMenu as ContextMenuPrimitive } from "bits-ui";
|
|
2
|
-
declare const ContextMenuRadioGroup: import("svelte").Component<ContextMenuPrimitive.RadioGroupProps, {}, "
|
|
2
|
+
declare const ContextMenuRadioGroup: import("svelte").Component<ContextMenuPrimitive.RadioGroupProps, {}, "ref" | "value">;
|
|
3
3
|
type ContextMenuRadioGroup = ReturnType<typeof ContextMenuRadioGroup>;
|
|
4
4
|
export default ContextMenuRadioGroup;
|
|
@@ -37,10 +37,9 @@ export function createSvelteTable(options) {
|
|
|
37
37
|
const table = createTable(resolvedOptions);
|
|
38
38
|
let state = $state(table.initialState);
|
|
39
39
|
function updateOptions() {
|
|
40
|
-
table.setOptions((
|
|
41
|
-
return mergeObjects(
|
|
40
|
+
table.setOptions(() => {
|
|
41
|
+
return mergeObjects(resolvedOptions, options, {
|
|
42
42
|
state: mergeObjects(state, options.state || {}),
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
43
|
onStateChange: (updater) => {
|
|
45
44
|
if (updater instanceof Function)
|
|
46
45
|
state = updater(state);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DateValue } from "@internationalized/date";
|
|
2
|
+
type DateStripContext = {
|
|
3
|
+
selectedValue: () => DateValue | undefined;
|
|
4
|
+
onSelect: (date: DateValue) => void;
|
|
5
|
+
isDateDisabled: (date: DateValue) => boolean;
|
|
6
|
+
direction: () => "start" | "end";
|
|
7
|
+
};
|
|
8
|
+
export declare function setDateStripContext(props: DateStripContext): void;
|
|
9
|
+
export declare function getDateStripContext(): DateStripContext;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../utils";
|
|
3
|
+
import { getDateStripContext } from "./ctx";
|
|
4
|
+
import { type DateValue, getLocalTimeZone, isToday } from "@internationalized/date";
|
|
5
|
+
import { DateFormatter } from "@internationalized/date";
|
|
6
|
+
import { Button } from "../button";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
date,
|
|
10
|
+
class: className,
|
|
11
|
+
}: {
|
|
12
|
+
date: DateValue;
|
|
13
|
+
class?: string;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
const ctx = getDateStripContext();
|
|
17
|
+
const formatterMonth = new DateFormatter("en-US", { month: "short" });
|
|
18
|
+
const formatterDay = new DateFormatter("en-US", { day: "numeric" });
|
|
19
|
+
|
|
20
|
+
let isSelected = $derived(ctx.selectedValue()?.compare(date) === 0);
|
|
21
|
+
let isDisabled = $derived(ctx.isDateDisabled(date));
|
|
22
|
+
let direction = $derived(ctx.direction());
|
|
23
|
+
|
|
24
|
+
function handleClick() {
|
|
25
|
+
if (!isDisabled) {
|
|
26
|
+
ctx.onSelect(date);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dateObj = $derived(date.toDate("UTC"));
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<Button
|
|
34
|
+
variant="ghost"
|
|
35
|
+
onclick={handleClick}
|
|
36
|
+
class={cn(
|
|
37
|
+
"animate-in fade-in-5 flex flex-col items-center justify-center -space-y-1",
|
|
38
|
+
"h-12 w-12 shrink-0 rounded-lg",
|
|
39
|
+
direction === "end" ? "slide-in-from-right-12" : "slide-in-from-left-12",
|
|
40
|
+
isToday(date, getLocalTimeZone()) && "bg-accent",
|
|
41
|
+
isSelected && "bg-primary text-primary-foreground",
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
disabled={isDisabled}
|
|
45
|
+
>
|
|
46
|
+
<span class="text-[8px] font-medium uppercase opacity-70">
|
|
47
|
+
{formatterMonth.format(dateObj)}
|
|
48
|
+
</span>
|
|
49
|
+
<span class="text-base leading-none font-bold">
|
|
50
|
+
{formatterDay.format(dateObj)}
|
|
51
|
+
</span>
|
|
52
|
+
</Button>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type DateValue } from "@internationalized/date";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
date: DateValue;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const DateStripItem: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type DateStripItem = ReturnType<typeof DateStripItem>;
|
|
8
|
+
export default DateStripItem;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../utils";
|
|
3
|
+
import { setDateStripContext } from "./ctx";
|
|
4
|
+
import { Button } from "../button";
|
|
5
|
+
import { ChevronLeft, ChevronRight } from "lucide-svelte";
|
|
6
|
+
import type { Snippet } from "svelte";
|
|
7
|
+
import { type DateValue, getLocalTimeZone, today, startOfWeek } from "@internationalized/date";
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
value = $bindable(),
|
|
11
|
+
class: className,
|
|
12
|
+
daysToShow = 5,
|
|
13
|
+
isDateDisabled = () => false,
|
|
14
|
+
onDateChange,
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
value?: DateValue | undefined;
|
|
18
|
+
class?: string;
|
|
19
|
+
daysToShow?: number;
|
|
20
|
+
isDateDisabled?: (date: DateValue) => boolean;
|
|
21
|
+
onDateChange?: (date: DateValue) => void;
|
|
22
|
+
children: Snippet<[{ date: DateValue }]>;
|
|
23
|
+
} = $props();
|
|
24
|
+
|
|
25
|
+
let startDate = $state(startOfWeek(today(getLocalTimeZone()), "en-US"));
|
|
26
|
+
let slideDirection = $state<"start" | "end">("end");
|
|
27
|
+
|
|
28
|
+
const displayedDates = $derived(Array.from({ length: daysToShow }, (_, i) => startDate.add({ days: i })));
|
|
29
|
+
|
|
30
|
+
function handlePrev() {
|
|
31
|
+
slideDirection = "start";
|
|
32
|
+
startDate = startDate.add({ days: -daysToShow });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleNext() {
|
|
36
|
+
slideDirection = "end";
|
|
37
|
+
startDate = startDate.add({ days: daysToShow });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setDateStripContext({
|
|
41
|
+
selectedValue: () => value,
|
|
42
|
+
onSelect: (d) => {
|
|
43
|
+
value = d;
|
|
44
|
+
onDateChange?.(d);
|
|
45
|
+
},
|
|
46
|
+
isDateDisabled,
|
|
47
|
+
direction: () => slideDirection,
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<div class={cn("bg-card flex items-center gap-2 rounded-xl border p-1 shadow-sm", className)}>
|
|
52
|
+
<Button variant="ghost" size="icon" class="h-7 w-7 shrink-0" onclick={handlePrev}>
|
|
53
|
+
<ChevronLeft class="h-4 w-4" />
|
|
54
|
+
</Button>
|
|
55
|
+
|
|
56
|
+
<div class="flex flex-1 justify-between gap-1 overflow-hidden">
|
|
57
|
+
{#each displayedDates as date (date.toString())}
|
|
58
|
+
{@render children({ date })}
|
|
59
|
+
{/each}
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<Button variant="ghost" size="icon" class="h-7 w-7 shrink-0" onclick={handleNext}>
|
|
63
|
+
<ChevronRight class="h-4 w-4" />
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|