@zag-js/color-picker 0.50.0 → 0.51.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/dist/index.mjs CHANGED
@@ -1,1380 +1,2 @@
1
- // src/color-picker.anatomy.ts
2
- import { createAnatomy } from "@zag-js/anatomy";
3
- var anatomy = createAnatomy("color-picker", [
4
- "root",
5
- "label",
6
- "control",
7
- "trigger",
8
- "positioner",
9
- "content",
10
- "area",
11
- "areaThumb",
12
- "areaBackground",
13
- "channelSlider",
14
- "channelSliderTrack",
15
- "channelSliderThumb",
16
- "channelInput",
17
- "transparencyGrid",
18
- "swatchGroup",
19
- "swatchTrigger",
20
- "swatchIndicator",
21
- "swatch",
22
- "eyeDropperTrigger",
23
- "formatTrigger",
24
- "formatSelect"
25
- ]);
26
- var parts = anatomy.build();
27
-
28
- // src/color-picker.connect.ts
29
- import { getColorAreaGradient, normalizeColor } from "@zag-js/color-utils";
30
- import {
31
- getEventKey,
32
- getEventPoint,
33
- getEventStep,
34
- getNativeEvent,
35
- isLeftClick,
36
- isModifierKey
37
- } from "@zag-js/dom-event";
38
- import { dataAttr, query, visuallyHiddenStyle } from "@zag-js/dom-query";
39
- import { getPlacementStyles } from "@zag-js/popper";
40
-
41
- // src/color-picker.dom.ts
42
- import { getRelativePoint } from "@zag-js/dom-event";
43
- import { createScope, queryAll } from "@zag-js/dom-query";
44
- var dom = createScope({
45
- getRootId: (ctx) => ctx.ids?.root ?? `color-picker:${ctx.id}`,
46
- getLabelId: (ctx) => ctx.ids?.label ?? `color-picker:${ctx.id}:label`,
47
- getHiddenInputId: (ctx) => `color-picker:${ctx.id}:hidden-input`,
48
- getControlId: (ctx) => ctx.ids?.control ?? `color-picker:${ctx.id}:control`,
49
- getTriggerId: (ctx) => ctx.ids?.trigger ?? `color-picker:${ctx.id}:trigger`,
50
- getContentId: (ctx) => ctx.ids?.content ?? `color-picker:${ctx.id}:content`,
51
- getPositionerId: (ctx) => `color-picker:${ctx.id}:positioner`,
52
- getFormatSelectId: (ctx) => `color-picker:${ctx.id}:format-select`,
53
- getAreaId: (ctx) => ctx.ids?.area ?? `color-picker:${ctx.id}:area`,
54
- getAreaGradientId: (ctx) => ctx.ids?.areaGradient ?? `color-picker:${ctx.id}:area-gradient`,
55
- getAreaThumbId: (ctx) => ctx.ids?.areaThumb ?? `color-picker:${ctx.id}:area-thumb`,
56
- getChannelSliderId: (ctx, channel) => ctx.ids?.channelSliderTrack?.(channel) ?? `color-picker:${ctx.id}:slider-track:${channel}`,
57
- getChannelSliderThumbId: (ctx, channel) => ctx.ids?.channelSliderThumb?.(channel) ?? `color-picker:${ctx.id}:slider-thumb:${channel}`,
58
- getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
59
- getAreaThumbEl: (ctx) => dom.getById(ctx, dom.getAreaThumbId(ctx)),
60
- getChannelSliderThumbEl: (ctx, channel) => dom.getById(ctx, dom.getChannelSliderThumbId(ctx, channel)),
61
- getChannelInputEl: (ctx, channel) => {
62
- return [
63
- ...queryAll(dom.getContentEl(ctx), `input[data-channel="${channel}"]`),
64
- ...queryAll(dom.getControlEl(ctx), `input[data-channel="${channel}"]`)
65
- ];
66
- },
67
- getFormatSelectEl: (ctx) => dom.getById(ctx, dom.getFormatSelectId(ctx)),
68
- getHiddenInputEl: (ctx) => dom.getById(ctx, dom.getHiddenInputId(ctx)),
69
- getAreaEl: (ctx) => dom.getById(ctx, dom.getAreaId(ctx)),
70
- getAreaValueFromPoint(ctx, point) {
71
- const areaEl = dom.getAreaEl(ctx);
72
- if (!areaEl)
73
- return;
74
- const { percent } = getRelativePoint(point, areaEl);
75
- return percent;
76
- },
77
- getControlEl: (ctx) => dom.getById(ctx, dom.getControlId(ctx)),
78
- getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
79
- getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
80
- getChannelSliderTrackEl: (ctx, channel) => {
81
- return dom.getById(ctx, dom.getChannelSliderId(ctx, channel));
82
- },
83
- getChannelSliderValueFromPoint(ctx, point, channel) {
84
- const trackEl = dom.getChannelSliderTrackEl(ctx, channel);
85
- if (!trackEl)
86
- return;
87
- const { percent } = getRelativePoint(point, trackEl);
88
- return percent;
89
- },
90
- getChannelInputEls: (ctx) => {
91
- return [
92
- ...queryAll(dom.getContentEl(ctx), "input[data-channel]"),
93
- ...queryAll(dom.getControlEl(ctx), "input[data-channel]")
94
- ];
95
- }
96
- });
97
-
98
- // src/utils/get-channel-display-color.ts
99
- import { parseColor } from "@zag-js/color-utils";
100
- function getChannelDisplayColor(color, channel) {
101
- switch (channel) {
102
- case "hue":
103
- return parseColor(`hsl(${color.getChannelValue("hue")}, 100%, 50%)`);
104
- case "lightness":
105
- case "brightness":
106
- case "saturation":
107
- case "red":
108
- case "green":
109
- case "blue":
110
- return color.withChannelValue("alpha", 1);
111
- case "alpha": {
112
- return color;
113
- }
114
- default:
115
- throw new Error("Unknown color channel: " + channel);
116
- }
117
- }
118
-
119
- // src/utils/get-channel-input-value.ts
120
- import { parseColor as parseColor2 } from "@zag-js/color-utils";
121
- function getChannelValue(color, channel) {
122
- if (channel == null)
123
- return "";
124
- if (channel === "hex") {
125
- return color.toString("hex");
126
- }
127
- if (channel === "css") {
128
- return color.toString("css");
129
- }
130
- if (channel in color) {
131
- return color.getChannelValue(channel).toString();
132
- }
133
- const isHSL = color.getFormat() === "hsla";
134
- switch (channel) {
135
- case "hue":
136
- return isHSL ? color.toFormat("hsla").getChannelValue("hue").toString() : color.toFormat("hsba").getChannelValue("hue").toString();
137
- case "saturation":
138
- return isHSL ? color.toFormat("hsla").getChannelValue("saturation").toString() : color.toFormat("hsba").getChannelValue("saturation").toString();
139
- case "lightness":
140
- return color.toFormat("hsla").getChannelValue("lightness").toString();
141
- case "brightness":
142
- return color.toFormat("hsba").getChannelValue("brightness").toString();
143
- case "red":
144
- case "green":
145
- case "blue":
146
- return color.toFormat("rgba").getChannelValue(channel).toString();
147
- default:
148
- return color.getChannelValue(channel).toString();
149
- }
150
- }
151
- function getChannelRange(color, channel) {
152
- switch (channel) {
153
- case "hex":
154
- const minColor = parseColor2("#000000");
155
- const maxColor = parseColor2("#FFFFFF");
156
- return {
157
- minValue: minColor.toHexInt(),
158
- maxValue: maxColor.toHexInt(),
159
- pageSize: 10,
160
- step: 1
161
- };
162
- case "css":
163
- return void 0;
164
- case "hue":
165
- case "saturation":
166
- case "lightness":
167
- return color.toFormat("hsla").getChannelRange(channel);
168
- case "brightness":
169
- return color.toFormat("hsba").getChannelRange(channel);
170
- case "red":
171
- case "green":
172
- case "blue":
173
- return color.toFormat("rgba").getChannelRange(channel);
174
- default:
175
- return color.getChannelRange(channel);
176
- }
177
- }
178
-
179
- // src/utils/get-slider-background.ts
180
- function getSliderBackgroundDirection(orientation, dir) {
181
- if (orientation === "vertical") {
182
- return "top";
183
- } else if (dir === "ltr") {
184
- return "right";
185
- } else {
186
- return "left";
187
- }
188
- }
189
- var getSliderBackground = (props) => {
190
- const { channel, value, dir } = props;
191
- const bgDirection = getSliderBackgroundDirection(props.orientation, dir);
192
- const { minValue, maxValue } = value.getChannelRange(channel);
193
- switch (channel) {
194
- case "hue":
195
- return `linear-gradient(to ${bgDirection}, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0) 33%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 83%, rgb(255, 0, 0) 100%)`;
196
- case "lightness": {
197
- let start = value.withChannelValue(channel, minValue).toString("css");
198
- let middle = value.withChannelValue(channel, (maxValue - minValue) / 2).toString("css");
199
- let end = value.withChannelValue(channel, maxValue).toString("css");
200
- return `linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`;
201
- }
202
- case "saturation":
203
- case "brightness":
204
- case "red":
205
- case "green":
206
- case "blue":
207
- case "alpha": {
208
- let start = value.withChannelValue(channel, minValue).toString("css");
209
- let end = value.withChannelValue(channel, maxValue).toString("css");
210
- return `linear-gradient(to ${bgDirection}, ${start}, ${end})`;
211
- }
212
- default:
213
- throw new Error("Unknown color channel: " + channel);
214
- }
215
- };
216
-
217
- // src/color-picker.connect.ts
218
- function connect(state, send, normalize) {
219
- const value = state.context.value;
220
- const areaValue = state.context.areaValue;
221
- const valueAsString = state.context.valueAsString;
222
- const disabled = state.context.isDisabled;
223
- const interactive = state.context.isInteractive;
224
- const dragging = state.hasTag("dragging");
225
- const open = state.hasTag("open");
226
- const focused = state.hasTag("focused");
227
- const getAreaChannels = (props) => {
228
- const channels = areaValue.getChannels();
229
- return {
230
- xChannel: props.xChannel ?? channels[1],
231
- yChannel: props.yChannel ?? channels[2]
232
- };
233
- };
234
- const currentPlacement = state.context.currentPlacement;
235
- const popperStyles = getPlacementStyles({
236
- ...state.context.positioning,
237
- placement: currentPlacement
238
- });
239
- function getSwatchTriggerState(props) {
240
- const color = normalizeColor(props.value).toFormat(state.context.format);
241
- return {
242
- value: color,
243
- valueAsString: color.toString("hex"),
244
- checked: color.isEqual(value),
245
- disabled: props.disabled || !interactive
246
- };
247
- }
248
- return {
249
- dragging,
250
- open,
251
- valueAsString,
252
- value,
253
- setOpen(nextOpen) {
254
- if (nextOpen === open)
255
- return;
256
- send({ type: nextOpen ? "OPEN" : "CLOSE" });
257
- },
258
- setValue(value2) {
259
- send({ type: "VALUE.SET", value: normalizeColor(value2), src: "set-color" });
260
- },
261
- getChannelValue(channel) {
262
- return getChannelValue(value, channel);
263
- },
264
- setChannelValue(channel, channelValue) {
265
- const color = value.withChannelValue(channel, channelValue);
266
- send({ type: "VALUE.SET", value: color, src: "set-channel" });
267
- },
268
- format: state.context.format,
269
- setFormat(format) {
270
- const formatValue = value.toFormat(format);
271
- send({ type: "VALUE.SET", value: formatValue, src: "set-format" });
272
- },
273
- alpha: value.getChannelValue("alpha"),
274
- setAlpha(alphaValue) {
275
- const color = value.withChannelValue("alpha", alphaValue);
276
- send({ type: "VALUE.SET", value: color, src: "set-alpha" });
277
- },
278
- rootProps: normalize.element({
279
- ...parts.root.attrs,
280
- dir: state.context.dir,
281
- id: dom.getRootId(state.context),
282
- "data-disabled": dataAttr(disabled),
283
- "data-readonly": dataAttr(state.context.readOnly),
284
- style: {
285
- "--value": value.toString("css")
286
- }
287
- }),
288
- labelProps: normalize.element({
289
- ...parts.label.attrs,
290
- dir: state.context.dir,
291
- id: dom.getLabelId(state.context),
292
- htmlFor: dom.getHiddenInputId(state.context),
293
- "data-disabled": dataAttr(disabled),
294
- "data-readonly": dataAttr(state.context.readOnly),
295
- "data-focus": dataAttr(focused),
296
- onClick(event) {
297
- event.preventDefault();
298
- const inputEl = query(dom.getControlEl(state.context), "[data-channel=hex]");
299
- inputEl?.focus({ preventScroll: true });
300
- }
301
- }),
302
- controlProps: normalize.element({
303
- ...parts.control.attrs,
304
- id: dom.getControlId(state.context),
305
- dir: state.context.dir,
306
- "data-disabled": dataAttr(disabled),
307
- "data-readonly": dataAttr(state.context.readOnly),
308
- "data-state": open ? "open" : "closed",
309
- "data-focus": dataAttr(focused)
310
- }),
311
- triggerProps: normalize.button({
312
- ...parts.trigger.attrs,
313
- id: dom.getTriggerId(state.context),
314
- dir: state.context.dir,
315
- disabled,
316
- "aria-label": `select color. current color is ${valueAsString}`,
317
- "aria-controls": dom.getContentId(state.context),
318
- "aria-labelledby": dom.getLabelId(state.context),
319
- "data-disabled": dataAttr(disabled),
320
- "data-readonly": dataAttr(state.context.readOnly),
321
- "data-placement": currentPlacement,
322
- "aria-expanded": dataAttr(open),
323
- "data-state": open ? "open" : "closed",
324
- "data-focus": dataAttr(focused),
325
- type: "button",
326
- onClick() {
327
- if (!interactive)
328
- return;
329
- send({ type: "TRIGGER.CLICK" });
330
- },
331
- onBlur() {
332
- if (!interactive)
333
- return;
334
- send({ type: "TRIGGER.BLUR" });
335
- },
336
- style: {
337
- position: "relative"
338
- }
339
- }),
340
- positionerProps: normalize.element({
341
- ...parts.positioner.attrs,
342
- id: dom.getPositionerId(state.context),
343
- dir: state.context.dir,
344
- style: popperStyles.floating
345
- }),
346
- contentProps: normalize.element({
347
- ...parts.content.attrs,
348
- id: dom.getContentId(state.context),
349
- dir: state.context.dir,
350
- "data-placement": currentPlacement,
351
- "data-state": open ? "open" : "closed",
352
- hidden: !open
353
- }),
354
- getAreaProps(props = {}) {
355
- const { xChannel, yChannel } = getAreaChannels(props);
356
- const { areaStyles } = getColorAreaGradient(areaValue, {
357
- xChannel,
358
- yChannel,
359
- dir: state.context.dir
360
- });
361
- return normalize.element({
362
- ...parts.area.attrs,
363
- id: dom.getAreaId(state.context),
364
- role: "group",
365
- onPointerDown(event) {
366
- if (!interactive)
367
- return;
368
- const evt = getNativeEvent(event);
369
- if (!isLeftClick(evt) || isModifierKey(evt))
370
- return;
371
- const point = getEventPoint(evt);
372
- const channel = { xChannel, yChannel };
373
- send({ type: "AREA.POINTER_DOWN", point, channel, id: "area" });
374
- event.preventDefault();
375
- },
376
- style: {
377
- position: "relative",
378
- touchAction: "none",
379
- forcedColorAdjust: "none",
380
- ...areaStyles
381
- }
382
- });
383
- },
384
- getAreaBackgroundProps(props = {}) {
385
- const { xChannel, yChannel } = getAreaChannels(props);
386
- const { areaGradientStyles } = getColorAreaGradient(areaValue, {
387
- xChannel,
388
- yChannel,
389
- dir: state.context.dir
390
- });
391
- return normalize.element({
392
- ...parts.areaBackground.attrs,
393
- id: dom.getAreaGradientId(state.context),
394
- style: {
395
- position: "relative",
396
- touchAction: "none",
397
- forcedColorAdjust: "none",
398
- ...areaGradientStyles
399
- }
400
- });
401
- },
402
- getAreaThumbProps(props = {}) {
403
- const { xChannel, yChannel } = getAreaChannels(props);
404
- const channel = { xChannel, yChannel };
405
- const xPercent = areaValue.getChannelValuePercent(xChannel);
406
- const yPercent = 1 - areaValue.getChannelValuePercent(yChannel);
407
- const xValue = areaValue.getChannelValue(xChannel);
408
- const yValue = areaValue.getChannelValue(yChannel);
409
- return normalize.element({
410
- ...parts.areaThumb.attrs,
411
- id: dom.getAreaThumbId(state.context),
412
- dir: state.context.dir,
413
- tabIndex: disabled ? void 0 : 0,
414
- "data-disabled": dataAttr(disabled),
415
- role: "slider",
416
- "aria-valuemin": 0,
417
- "aria-valuemax": 100,
418
- "aria-valuenow": xValue,
419
- "aria-label": `${xChannel} and ${yChannel}`,
420
- "aria-roledescription": "2d slider",
421
- "aria-valuetext": `${xChannel} ${xValue}, ${yChannel} ${yValue}`,
422
- style: {
423
- position: "absolute",
424
- left: `${xPercent * 100}%`,
425
- top: `${yPercent * 100}%`,
426
- transform: "translate(-50%, -50%)",
427
- touchAction: "none",
428
- forcedColorAdjust: "none",
429
- background: areaValue.withChannelValue("alpha", 1).toString("css")
430
- },
431
- onFocus() {
432
- if (!interactive)
433
- return;
434
- send({ type: "AREA.FOCUS", id: "area", channel });
435
- },
436
- onKeyDown(event) {
437
- if (event.defaultPrevented)
438
- return;
439
- if (!interactive)
440
- return;
441
- const step = getEventStep(event);
442
- const keyMap = {
443
- ArrowUp() {
444
- send({ type: "AREA.ARROW_UP", channel, step });
445
- },
446
- ArrowDown() {
447
- send({ type: "AREA.ARROW_DOWN", channel, step });
448
- },
449
- ArrowLeft() {
450
- send({ type: "AREA.ARROW_LEFT", channel, step });
451
- },
452
- ArrowRight() {
453
- send({ type: "AREA.ARROW_RIGHT", channel, step });
454
- },
455
- PageUp() {
456
- send({ type: "AREA.PAGE_UP", channel, step });
457
- },
458
- PageDown() {
459
- send({ type: "AREA.PAGE_DOWN", channel, step });
460
- },
461
- Escape(event2) {
462
- event2.stopPropagation();
463
- }
464
- };
465
- const exec = keyMap[getEventKey(event, state.context)];
466
- if (exec) {
467
- exec(event);
468
- event.preventDefault();
469
- }
470
- }
471
- });
472
- },
473
- getTransparencyGridProps(props = {}) {
474
- const { size = "12px" } = props;
475
- return normalize.element({
476
- ...parts.transparencyGrid.attrs,
477
- style: {
478
- "--size": size,
479
- width: "100%",
480
- height: "100%",
481
- position: "absolute",
482
- backgroundColor: "#fff",
483
- backgroundImage: "conic-gradient(#eeeeee 0 25%, transparent 0 50%, #eeeeee 0 75%, transparent 0)",
484
- backgroundSize: "var(--size) var(--size)",
485
- inset: "0px",
486
- zIndex: "auto",
487
- pointerEvents: "none"
488
- }
489
- });
490
- },
491
- getChannelSliderProps(props) {
492
- const { orientation = "horizontal", channel } = props;
493
- return normalize.element({
494
- ...parts.channelSlider.attrs,
495
- "data-channel": channel,
496
- "data-orientation": orientation,
497
- role: "presentation",
498
- onPointerDown(event) {
499
- if (!interactive)
500
- return;
501
- const evt = getNativeEvent(event);
502
- if (!isLeftClick(evt) || isModifierKey(evt))
503
- return;
504
- const point = getEventPoint(evt);
505
- send({ type: "CHANNEL_SLIDER.POINTER_DOWN", channel, point, id: channel, orientation });
506
- event.preventDefault();
507
- },
508
- style: {
509
- position: "relative",
510
- touchAction: "none"
511
- }
512
- });
513
- },
514
- getChannelSliderTrackProps(props) {
515
- const { orientation = "horizontal", channel } = props;
516
- return normalize.element({
517
- ...parts.channelSliderTrack.attrs,
518
- id: dom.getChannelSliderId(state.context, channel),
519
- role: "group",
520
- "data-channel": channel,
521
- "data-orientation": orientation,
522
- style: {
523
- position: "relative",
524
- forcedColorAdjust: "none",
525
- backgroundImage: getSliderBackground({
526
- orientation,
527
- channel,
528
- dir: state.context.dir,
529
- value: areaValue
530
- })
531
- }
532
- });
533
- },
534
- getChannelSliderThumbProps(props) {
535
- const { orientation = "horizontal", channel } = props;
536
- const { minValue, maxValue, step: stepValue } = areaValue.getChannelRange(channel);
537
- const channelValue = areaValue.getChannelValue(channel);
538
- const offset = (channelValue - minValue) / (maxValue - minValue);
539
- const placementStyles = orientation === "horizontal" ? { left: `${offset * 100}%`, top: "50%" } : { top: `${offset * 100}%`, left: "50%" };
540
- return normalize.element({
541
- ...parts.channelSliderThumb.attrs,
542
- id: dom.getChannelSliderThumbId(state.context, channel),
543
- role: "slider",
544
- "aria-label": channel,
545
- tabIndex: disabled ? void 0 : 0,
546
- "data-channel": channel,
547
- "data-disabled": dataAttr(disabled),
548
- "data-orientation": orientation,
549
- "aria-disabled": dataAttr(disabled),
550
- "aria-orientation": orientation,
551
- "aria-valuemax": maxValue,
552
- "aria-valuemin": minValue,
553
- "aria-valuenow": channelValue,
554
- "aria-valuetext": `${channel} ${channelValue}`,
555
- style: {
556
- forcedColorAdjust: "none",
557
- position: "absolute",
558
- background: getChannelDisplayColor(areaValue, channel).toString("css"),
559
- ...placementStyles
560
- },
561
- onFocus() {
562
- if (!interactive)
563
- return;
564
- send({ type: "CHANNEL_SLIDER.FOCUS", channel });
565
- },
566
- onKeyDown(event) {
567
- if (event.defaultPrevented)
568
- return;
569
- if (!interactive)
570
- return;
571
- const step = getEventStep(event) * stepValue;
572
- const keyMap = {
573
- ArrowUp() {
574
- send({ type: "CHANNEL_SLIDER.ARROW_UP", channel, step });
575
- },
576
- ArrowDown() {
577
- send({ type: "CHANNEL_SLIDER.ARROW_DOWN", channel, step });
578
- },
579
- ArrowLeft() {
580
- send({ type: "CHANNEL_SLIDER.ARROW_LEFT", channel, step });
581
- },
582
- ArrowRight() {
583
- send({ type: "CHANNEL_SLIDER.ARROW_RIGHT", channel, step });
584
- },
585
- PageUp() {
586
- send({ type: "CHANNEL_SLIDER.PAGE_UP", channel });
587
- },
588
- PageDown() {
589
- send({ type: "CHANNEL_SLIDER.PAGE_DOWN", channel });
590
- },
591
- Home() {
592
- send({ type: "CHANNEL_SLIDER.HOME", channel });
593
- },
594
- End() {
595
- send({ type: "CHANNEL_SLIDER.END", channel });
596
- },
597
- Escape(event2) {
598
- event2.stopPropagation();
599
- }
600
- };
601
- const exec = keyMap[getEventKey(event, state.context)];
602
- if (exec) {
603
- exec(event);
604
- event.preventDefault();
605
- }
606
- }
607
- });
608
- },
609
- getChannelInputProps(props) {
610
- const { channel } = props;
611
- const isTextField = channel === "hex" || channel === "css";
612
- const range = getChannelRange(value, channel);
613
- return normalize.input({
614
- ...parts.channelInput.attrs,
615
- dir: state.context.dir,
616
- type: isTextField ? "text" : "number",
617
- "data-channel": channel,
618
- "aria-label": channel,
619
- spellCheck: false,
620
- autoComplete: "off",
621
- disabled,
622
- "data-disabled": dataAttr(disabled),
623
- readOnly: state.context.readOnly,
624
- defaultValue: getChannelValue(value, channel),
625
- min: range?.minValue,
626
- max: range?.maxValue,
627
- step: range?.step,
628
- onBeforeInput(event) {
629
- if (isTextField || !interactive)
630
- return;
631
- const value2 = event.currentTarget.value;
632
- if (value2.match(/[^0-9.]/g)) {
633
- event.preventDefault();
634
- }
635
- },
636
- onFocus(event) {
637
- if (!interactive)
638
- return;
639
- send({ type: "CHANNEL_INPUT.FOCUS", channel });
640
- event.target.select();
641
- },
642
- onBlur(event) {
643
- if (!interactive)
644
- return;
645
- const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
646
- send({ type: "CHANNEL_INPUT.BLUR", channel, value: value2, isTextField });
647
- },
648
- onKeyDown(event) {
649
- if (event.defaultPrevented)
650
- return;
651
- if (!interactive)
652
- return;
653
- if (event.key === "Enter") {
654
- const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
655
- send({ type: "CHANNEL_INPUT.CHANGE", channel, value: value2, isTextField });
656
- event.preventDefault();
657
- }
658
- },
659
- style: {
660
- appearance: "none",
661
- WebkitAppearance: "none",
662
- MozAppearance: "textfield"
663
- }
664
- });
665
- },
666
- hiddenInputProps: normalize.input({
667
- type: "text",
668
- disabled,
669
- name: state.context.name,
670
- id: dom.getHiddenInputId(state.context),
671
- style: visuallyHiddenStyle,
672
- defaultValue: valueAsString
673
- }),
674
- eyeDropperTriggerProps: normalize.button({
675
- ...parts.eyeDropperTrigger.attrs,
676
- type: "button",
677
- dir: state.context.dir,
678
- disabled,
679
- "data-disabled": dataAttr(disabled),
680
- "aria-label": "Pick a color from the screen",
681
- onClick() {
682
- if (!interactive)
683
- return;
684
- send("EYEDROPPER.CLICK");
685
- }
686
- }),
687
- swatchGroupProps: normalize.element({
688
- ...parts.swatchGroup.attrs,
689
- role: "group"
690
- }),
691
- getSwatchTriggerState,
692
- getSwatchTriggerProps(props) {
693
- const triggerState = getSwatchTriggerState(props);
694
- return normalize.button({
695
- ...parts.swatchTrigger.attrs,
696
- disabled: triggerState.disabled,
697
- dir: state.context.dir,
698
- type: "button",
699
- "aria-label": `select ${triggerState.valueAsString} as the color`,
700
- "data-state": triggerState.checked ? "checked" : "unchecked",
701
- "data-value": triggerState.valueAsString,
702
- "data-disabled": dataAttr(triggerState.disabled),
703
- onClick() {
704
- if (triggerState.disabled)
705
- return;
706
- send({ type: "SWATCH_TRIGGER.CLICK", value: triggerState.value });
707
- },
708
- style: {
709
- position: "relative"
710
- }
711
- });
712
- },
713
- getSwatchIndicatorProps(props) {
714
- const triggerState = getSwatchTriggerState(props);
715
- return normalize.element({
716
- ...parts.swatchIndicator.attrs,
717
- dir: state.context.dir,
718
- hidden: !triggerState.checked
719
- });
720
- },
721
- getSwatchProps(props) {
722
- const { respectAlpha = true } = props;
723
- const triggerState = getSwatchTriggerState(props);
724
- return normalize.element({
725
- ...parts.swatch.attrs,
726
- dir: state.context.dir,
727
- "data-state": triggerState.checked ? "checked" : "unchecked",
728
- "data-value": triggerState.valueAsString,
729
- style: {
730
- position: "relative",
731
- background: triggerState.value.toString(respectAlpha ? "css" : "hex")
732
- }
733
- });
734
- },
735
- formatTriggerProps: normalize.button({
736
- ...parts.formatTrigger.attrs,
737
- dir: state.context.dir,
738
- type: "button",
739
- "aria-label": `change color format to ${getNextFormat(state.context.format)}`,
740
- onClick(event) {
741
- if (event.currentTarget.disabled)
742
- return;
743
- const nextFormat = getNextFormat(state.context.format);
744
- send({ type: "FORMAT.SET", format: nextFormat, src: "format-trigger" });
745
- }
746
- }),
747
- formatSelectProps: normalize.select({
748
- ...parts.formatSelect.attrs,
749
- "aria-label": "change color format",
750
- dir: state.context.dir,
751
- defaultValue: state.context.format,
752
- disabled,
753
- onChange(event) {
754
- const format = assertFormat(event.currentTarget.value);
755
- send({ type: "FORMAT.SET", format, src: "format-select" });
756
- }
757
- })
758
- };
759
- }
760
- var formats = ["hsba", "hsla", "rgba"];
761
- var formatRegex = new RegExp(`^(${formats.join("|")})$`);
762
- function getNextFormat(format) {
763
- const index = formats.indexOf(format);
764
- return formats[index + 1] ?? formats[0];
765
- }
766
- function assertFormat(format) {
767
- if (formatRegex.test(format))
768
- return format;
769
- throw new Error(`Unsupported color format: ${format}`);
770
- }
771
-
772
- // src/color-picker.machine.ts
773
- import { parseColor as parseColor4 } from "@zag-js/color-utils";
774
- import { createMachine, guards } from "@zag-js/core";
775
- import { trackDismissableElement } from "@zag-js/dismissable";
776
- import { trackPointerMove } from "@zag-js/dom-event";
777
- import { getInitialFocus, raf } from "@zag-js/dom-query";
778
- import { dispatchInputValueEvent, trackFormControl } from "@zag-js/form-utils";
779
- import { getPlacement } from "@zag-js/popper";
780
- import { disableTextSelection } from "@zag-js/text-selection";
781
- import { compact, tryCatch } from "@zag-js/utils";
782
-
783
- // src/color-picker.parse.ts
784
- import { parseColor as parseColor3 } from "@zag-js/color-utils";
785
- var parse = (colorString) => {
786
- return parseColor3(colorString);
787
- };
788
-
789
- // src/color-picker.machine.ts
790
- var { and } = guards;
791
- function machine(userContext) {
792
- const ctx = compact(userContext);
793
- return createMachine(
794
- {
795
- id: "color-picker",
796
- initial: ctx.open ? "open" : "idle",
797
- context: {
798
- dir: "ltr",
799
- value: parse("#000000"),
800
- format: "rgba",
801
- disabled: false,
802
- closeOnSelect: false,
803
- ...ctx,
804
- activeId: null,
805
- activeChannel: null,
806
- activeOrientation: null,
807
- fieldsetDisabled: false,
808
- restoreFocus: true,
809
- positioning: {
810
- ...ctx.positioning,
811
- placement: "bottom"
812
- }
813
- },
814
- computed: {
815
- isRtl: (ctx2) => ctx2.dir === "rtl",
816
- isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
817
- isInteractive: (ctx2) => !(ctx2.isDisabled || ctx2.readOnly),
818
- valueAsString: (ctx2) => ctx2.value.toString(ctx2.format),
819
- areaValue: (ctx2) => {
820
- const format = ctx2.format.startsWith("hsl") ? "hsla" : "hsba";
821
- return ctx2.value.toFormat(format);
822
- }
823
- },
824
- activities: ["trackFormControl"],
825
- watch: {
826
- value: ["syncInputElements"],
827
- format: ["syncFormatSelectElement"],
828
- open: ["toggleVisibility"]
829
- },
830
- on: {
831
- "VALUE.SET": {
832
- actions: ["setValue"]
833
- },
834
- "FORMAT.SET": {
835
- actions: ["setFormat"]
836
- },
837
- "CHANNEL_INPUT.CHANGE": {
838
- actions: ["setChannelColorFromInput"]
839
- },
840
- "EYEDROPPER.CLICK": {
841
- actions: ["openEyeDropper"]
842
- }
843
- },
844
- states: {
845
- idle: {
846
- tags: ["closed"],
847
- on: {
848
- "CONTROLLED.OPEN": {
849
- target: "open",
850
- actions: ["setInitialFocus"]
851
- },
852
- OPEN: [
853
- {
854
- guard: "isOpenControlled",
855
- actions: ["invokeOnOpen"]
856
- },
857
- {
858
- target: "open",
859
- actions: ["invokeOnOpen", "setInitialFocus"]
860
- }
861
- ],
862
- "TRIGGER.CLICK": [
863
- {
864
- guard: "isOpenControlled",
865
- actions: ["invokeOnOpen"]
866
- },
867
- {
868
- target: "open",
869
- actions: ["invokeOnOpen", "setInitialFocus"]
870
- }
871
- ],
872
- "CHANNEL_INPUT.FOCUS": {
873
- target: "focused",
874
- actions: ["setActiveChannel"]
875
- }
876
- }
877
- },
878
- focused: {
879
- tags: ["closed", "focused"],
880
- on: {
881
- "CONTROLLED.OPEN": {
882
- target: "open",
883
- actions: ["setInitialFocus"]
884
- },
885
- OPEN: [
886
- {
887
- guard: "isOpenControlled",
888
- actions: ["invokeOnOpen"]
889
- },
890
- {
891
- target: "open",
892
- actions: ["invokeOnOpen", "setInitialFocus"]
893
- }
894
- ],
895
- "TRIGGER.CLICK": [
896
- {
897
- guard: "isOpenControlled",
898
- actions: ["invokeOnOpen"]
899
- },
900
- {
901
- target: "open",
902
- actions: ["invokeOnOpen", "setInitialFocus"]
903
- }
904
- ],
905
- "CHANNEL_INPUT.FOCUS": {
906
- actions: ["setActiveChannel"]
907
- },
908
- "CHANNEL_INPUT.BLUR": {
909
- target: "idle",
910
- actions: ["setChannelColorFromInput"]
911
- },
912
- "TRIGGER.BLUR": {
913
- target: "idle"
914
- }
915
- }
916
- },
917
- open: {
918
- tags: ["open"],
919
- activities: ["trackPositioning", "trackDismissableElement"],
920
- on: {
921
- "CONTROLLED.CLOSE": [
922
- {
923
- guard: "shouldRestoreFocus",
924
- target: "focused",
925
- actions: ["setReturnFocus"]
926
- },
927
- {
928
- target: "idle"
929
- }
930
- ],
931
- "TRIGGER.CLICK": [
932
- {
933
- guard: "isOpenControlled",
934
- actions: ["invokeOnClose"]
935
- },
936
- {
937
- target: "idle",
938
- actions: ["invokeOnClose"]
939
- }
940
- ],
941
- "AREA.POINTER_DOWN": {
942
- target: "open:dragging",
943
- actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"]
944
- },
945
- "AREA.FOCUS": {
946
- actions: ["setActiveChannel"]
947
- },
948
- "CHANNEL_SLIDER.POINTER_DOWN": {
949
- target: "open:dragging",
950
- actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"]
951
- },
952
- "CHANNEL_SLIDER.FOCUS": {
953
- actions: ["setActiveChannel"]
954
- },
955
- "AREA.ARROW_LEFT": {
956
- actions: ["decrementXChannel"]
957
- },
958
- "AREA.ARROW_RIGHT": {
959
- actions: ["incrementXChannel"]
960
- },
961
- "AREA.ARROW_UP": {
962
- actions: ["incrementYChannel"]
963
- },
964
- "AREA.ARROW_DOWN": {
965
- actions: ["decrementYChannel"]
966
- },
967
- "AREA.PAGE_UP": {
968
- actions: ["incrementXChannel"]
969
- },
970
- "AREA.PAGE_DOWN": {
971
- actions: ["decrementXChannel"]
972
- },
973
- "CHANNEL_SLIDER.ARROW_LEFT": {
974
- actions: ["decrementChannel"]
975
- },
976
- "CHANNEL_SLIDER.ARROW_RIGHT": {
977
- actions: ["incrementChannel"]
978
- },
979
- "CHANNEL_SLIDER.ARROW_UP": {
980
- actions: ["incrementChannel"]
981
- },
982
- "CHANNEL_SLIDER.ARROW_DOWN": {
983
- actions: ["decrementChannel"]
984
- },
985
- "CHANNEL_SLIDER.PAGE_UP": {
986
- actions: ["incrementChannel"]
987
- },
988
- "CHANNEL_SLIDER.PAGE_DOWN": {
989
- actions: ["decrementChannel"]
990
- },
991
- "CHANNEL_SLIDER.HOME": {
992
- actions: ["setChannelToMin"]
993
- },
994
- "CHANNEL_SLIDER.END": {
995
- actions: ["setChannelToMax"]
996
- },
997
- "CHANNEL_INPUT.BLUR": {
998
- actions: ["setChannelColorFromInput"]
999
- },
1000
- INTERACT_OUTSIDE: [
1001
- {
1002
- guard: "isOpenControlled",
1003
- actions: ["invokeOnClose"]
1004
- },
1005
- {
1006
- guard: "shouldRestoreFocus",
1007
- target: "focused",
1008
- actions: ["invokeOnClose", "setReturnFocus"]
1009
- },
1010
- {
1011
- target: "idle",
1012
- actions: ["invokeOnClose"]
1013
- }
1014
- ],
1015
- CLOSE: [
1016
- {
1017
- guard: "isOpenControlled",
1018
- actions: ["invokeOnClose"]
1019
- },
1020
- {
1021
- target: "idle",
1022
- actions: ["invokeOnClose"]
1023
- }
1024
- ],
1025
- "SWATCH_TRIGGER.CLICK": [
1026
- {
1027
- guard: and("isOpenControlled", "closeOnSelect"),
1028
- actions: ["setValue", "invokeOnClose"]
1029
- },
1030
- {
1031
- guard: "closeOnSelect",
1032
- target: "focused",
1033
- actions: ["setValue", "invokeOnClose", "setReturnFocus"]
1034
- },
1035
- {
1036
- actions: ["setValue"]
1037
- }
1038
- ]
1039
- }
1040
- },
1041
- "open:dragging": {
1042
- tags: ["open"],
1043
- exit: ["clearActiveChannel"],
1044
- activities: ["trackPointerMove", "disableTextSelection", "trackPositioning", "trackDismissableElement"],
1045
- on: {
1046
- "CONTROLLED.CLOSE": [
1047
- {
1048
- guard: "shouldRestoreFocus",
1049
- target: "focused",
1050
- actions: ["setReturnFocus"]
1051
- },
1052
- {
1053
- target: "idle"
1054
- }
1055
- ],
1056
- "AREA.POINTER_MOVE": {
1057
- actions: ["setAreaColorFromPoint", "focusAreaThumb"]
1058
- },
1059
- "AREA.POINTER_UP": {
1060
- target: "open",
1061
- actions: ["invokeOnChangeEnd"]
1062
- },
1063
- "CHANNEL_SLIDER.POINTER_MOVE": {
1064
- actions: ["setChannelColorFromPoint", "focusChannelThumb"]
1065
- },
1066
- "CHANNEL_SLIDER.POINTER_UP": {
1067
- target: "open",
1068
- actions: ["invokeOnChangeEnd"]
1069
- },
1070
- INTERACT_OUTSIDE: [
1071
- {
1072
- guard: "isOpenControlled",
1073
- actions: ["invokeOnClose"]
1074
- },
1075
- {
1076
- guard: "shouldRestoreFocus",
1077
- target: "focused",
1078
- actions: ["invokeOnClose", "setReturnFocus"]
1079
- },
1080
- {
1081
- target: "idle",
1082
- actions: ["invokeOnClose"]
1083
- }
1084
- ],
1085
- CLOSE: [
1086
- {
1087
- guard: "isOpenControlled",
1088
- actions: ["invokeOnClose"]
1089
- },
1090
- {
1091
- target: "idle",
1092
- actions: ["invokeOnClose"]
1093
- }
1094
- ]
1095
- }
1096
- }
1097
- }
1098
- },
1099
- {
1100
- guards: {
1101
- closeOnSelect: (ctx2) => !!ctx2.closeOnSelect,
1102
- isOpenControlled: (ctx2) => !!ctx2["open.controlled"],
1103
- shouldRestoreFocus: (ctx2) => !!ctx2.restoreFocus
1104
- },
1105
- activities: {
1106
- trackPositioning(ctx2) {
1107
- ctx2.currentPlacement = ctx2.positioning.placement;
1108
- const anchorEl = dom.getTriggerEl(ctx2);
1109
- const getPositionerEl = () => dom.getPositionerEl(ctx2);
1110
- return getPlacement(anchorEl, getPositionerEl, {
1111
- ...ctx2.positioning,
1112
- defer: true,
1113
- onComplete(data) {
1114
- ctx2.currentPlacement = data.placement;
1115
- }
1116
- });
1117
- },
1118
- trackDismissableElement(ctx2, _evt, { send }) {
1119
- const getContentEl = () => dom.getContentEl(ctx2);
1120
- return trackDismissableElement(getContentEl, {
1121
- exclude: dom.getTriggerEl(ctx2),
1122
- defer: true,
1123
- onInteractOutside(event) {
1124
- ctx2.onInteractOutside?.(event);
1125
- if (event.defaultPrevented)
1126
- return;
1127
- ctx2.restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
1128
- },
1129
- onPointerDownOutside: ctx2.onPointerDownOutside,
1130
- onFocusOutside: ctx2.onFocusOutside,
1131
- onDismiss() {
1132
- send({ type: "INTERACT_OUTSIDE" });
1133
- }
1134
- });
1135
- },
1136
- trackFormControl(ctx2, _evt, { send, initialContext }) {
1137
- const inputEl = dom.getHiddenInputEl(ctx2);
1138
- return trackFormControl(inputEl, {
1139
- onFieldsetDisabledChange(disabled) {
1140
- ctx2.fieldsetDisabled = disabled;
1141
- },
1142
- onFormReset() {
1143
- send({ type: "VALUE.SET", value: initialContext.value, src: "form.reset" });
1144
- }
1145
- });
1146
- },
1147
- trackPointerMove(ctx2, _evt, { send }) {
1148
- return trackPointerMove(dom.getDoc(ctx2), {
1149
- onPointerMove({ point }) {
1150
- const type = ctx2.activeId === "area" ? "AREA.POINTER_MOVE" : "CHANNEL_SLIDER.POINTER_MOVE";
1151
- send({ type, point });
1152
- },
1153
- onPointerUp() {
1154
- const type = ctx2.activeId === "area" ? "AREA.POINTER_UP" : "CHANNEL_SLIDER.POINTER_UP";
1155
- send({ type });
1156
- }
1157
- });
1158
- },
1159
- disableTextSelection(ctx2) {
1160
- return disableTextSelection({ doc: dom.getDoc(ctx2), target: dom.getContentEl(ctx2) });
1161
- }
1162
- },
1163
- actions: {
1164
- openEyeDropper(ctx2) {
1165
- const isSupported = "EyeDropper" in dom.getWin(ctx2);
1166
- if (!isSupported)
1167
- return;
1168
- const win = dom.getWin(ctx2);
1169
- const picker = new win.EyeDropper();
1170
- picker.open().then(({ sRGBHex }) => {
1171
- const format = ctx2.value.getFormat();
1172
- const color = parseColor4(sRGBHex).toFormat(format);
1173
- set.value(ctx2, color);
1174
- ctx2.onValueChangeEnd?.({ value: ctx2.value, valueAsString: ctx2.valueAsString });
1175
- }).catch(() => void 0);
1176
- },
1177
- setActiveChannel(ctx2, evt) {
1178
- ctx2.activeId = evt.id;
1179
- if (evt.channel)
1180
- ctx2.activeChannel = evt.channel;
1181
- if (evt.orientation)
1182
- ctx2.activeOrientation = evt.orientation;
1183
- },
1184
- clearActiveChannel(ctx2) {
1185
- ctx2.activeChannel = null;
1186
- ctx2.activeId = null;
1187
- ctx2.activeOrientation = null;
1188
- },
1189
- setAreaColorFromPoint(ctx2, evt) {
1190
- const { xChannel, yChannel } = evt.channel || ctx2.activeChannel;
1191
- const percent = dom.getAreaValueFromPoint(ctx2, evt.point);
1192
- if (!percent)
1193
- return;
1194
- const xValue = ctx2.areaValue.getChannelPercentValue(xChannel, percent.x);
1195
- const yValue = ctx2.areaValue.getChannelPercentValue(yChannel, 1 - percent.y);
1196
- const color = ctx2.areaValue.withChannelValue(xChannel, xValue).withChannelValue(yChannel, yValue);
1197
- set.value(ctx2, color);
1198
- },
1199
- setChannelColorFromPoint(ctx2, evt) {
1200
- const channel = evt.channel || ctx2.activeId;
1201
- const percent = dom.getChannelSliderValueFromPoint(ctx2, evt.point, channel);
1202
- if (!percent)
1203
- return;
1204
- const orientation = ctx2.activeOrientation || "horizontal";
1205
- const channelPercent = orientation === "horizontal" ? percent.x : percent.y;
1206
- const value = ctx2.areaValue.getChannelPercentValue(channel, channelPercent);
1207
- const color = ctx2.areaValue.withChannelValue(channel, value);
1208
- set.value(ctx2, color);
1209
- },
1210
- setValue(ctx2, evt) {
1211
- set.value(ctx2, evt.value);
1212
- },
1213
- setFormat(ctx2, evt) {
1214
- set.format(ctx2, evt.format);
1215
- },
1216
- syncInputElements(ctx2) {
1217
- sync.inputs(ctx2);
1218
- },
1219
- invokeOnChangeEnd(ctx2) {
1220
- invoke.changeEnd(ctx2);
1221
- },
1222
- setChannelColorFromInput(ctx2, evt) {
1223
- const { channel, isTextField, value } = evt;
1224
- const currentAlpha = ctx2.value.getChannelValue("alpha");
1225
- let color;
1226
- if (channel === "alpha") {
1227
- let valueAsNumber = parseFloat(value);
1228
- valueAsNumber = Number.isNaN(valueAsNumber) ? currentAlpha : valueAsNumber;
1229
- color = ctx2.value.withChannelValue("alpha", valueAsNumber);
1230
- } else if (isTextField) {
1231
- color = tryCatch(
1232
- () => parse(value).withChannelValue("alpha", currentAlpha),
1233
- () => ctx2.value
1234
- );
1235
- } else {
1236
- const current = ctx2.value.toFormat(ctx2.format);
1237
- const valueAsNumber = Number.isNaN(value) ? current.getChannelValue(channel) : value;
1238
- color = current.withChannelValue(channel, valueAsNumber);
1239
- }
1240
- sync.inputs(ctx2, color);
1241
- set.value(ctx2, color);
1242
- },
1243
- incrementChannel(ctx2, evt) {
1244
- const color = ctx2.value.incrementChannel(evt.channel, evt.step);
1245
- set.value(ctx2, color);
1246
- },
1247
- decrementChannel(ctx2, evt) {
1248
- const color = ctx2.value.decrementChannel(evt.channel, evt.step);
1249
- set.value(ctx2, color);
1250
- },
1251
- incrementXChannel(ctx2, evt) {
1252
- const { xChannel } = evt.channel;
1253
- const color = ctx2.areaValue.incrementChannel(xChannel, evt.step);
1254
- set.value(ctx2, color);
1255
- },
1256
- decrementXChannel(ctx2, evt) {
1257
- const { xChannel } = evt.channel;
1258
- const color = ctx2.areaValue.decrementChannel(xChannel, evt.step);
1259
- set.value(ctx2, color);
1260
- },
1261
- incrementYChannel(ctx2, evt) {
1262
- const { yChannel } = evt.channel;
1263
- const color = ctx2.areaValue.incrementChannel(yChannel, evt.step);
1264
- set.value(ctx2, color);
1265
- },
1266
- decrementYChannel(ctx2, evt) {
1267
- const { yChannel } = evt.channel;
1268
- const color = ctx2.areaValue.decrementChannel(yChannel, evt.step);
1269
- set.value(ctx2, color);
1270
- },
1271
- setChannelToMax(ctx2, evt) {
1272
- const range = ctx2.value.getChannelRange(evt.channel);
1273
- const color = ctx2.value.withChannelValue(evt.channel, range.maxValue);
1274
- set.value(ctx2, color);
1275
- },
1276
- setChannelToMin(ctx2, evt) {
1277
- const range = ctx2.value.getChannelRange(evt.channel);
1278
- const color = ctx2.value.withChannelValue(evt.channel, range.minValue);
1279
- set.value(ctx2, color);
1280
- },
1281
- focusAreaThumb(ctx2) {
1282
- raf(() => {
1283
- dom.getAreaThumbEl(ctx2)?.focus({ preventScroll: true });
1284
- });
1285
- },
1286
- focusChannelThumb(ctx2, evt) {
1287
- raf(() => {
1288
- dom.getChannelSliderThumbEl(ctx2, evt.channel)?.focus({ preventScroll: true });
1289
- });
1290
- },
1291
- setInitialFocus(ctx2) {
1292
- raf(() => {
1293
- const element = getInitialFocus(dom.getContentEl(ctx2), ctx2.initialFocusEl);
1294
- element?.focus({ preventScroll: true });
1295
- });
1296
- },
1297
- setReturnFocus(ctx2) {
1298
- raf(() => {
1299
- dom.getTriggerEl(ctx2)?.focus({ preventScroll: true });
1300
- });
1301
- },
1302
- syncFormatSelectElement(ctx2) {
1303
- sync.formatSelect(ctx2);
1304
- },
1305
- invokeOnOpen(ctx2) {
1306
- ctx2.onOpenChange?.({ open: true });
1307
- },
1308
- invokeOnClose(ctx2) {
1309
- ctx2.onOpenChange?.({ open: false });
1310
- },
1311
- toggleVisibility(ctx2, evt, { send }) {
1312
- send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
1313
- }
1314
- },
1315
- compareFns: {
1316
- value: (a, b) => a.isEqual(b)
1317
- }
1318
- }
1319
- );
1320
- }
1321
- var sync = {
1322
- // sync channel inputs
1323
- inputs(ctx, color) {
1324
- const channelInputs = dom.getChannelInputEls(ctx);
1325
- raf(() => {
1326
- channelInputs.forEach((inputEl) => {
1327
- const channel = inputEl.dataset.channel;
1328
- dom.setValue(inputEl, getChannelValue(color || ctx.value, channel));
1329
- });
1330
- });
1331
- },
1332
- // sync format select
1333
- formatSelect(ctx) {
1334
- const selectEl = dom.getFormatSelectEl(ctx);
1335
- raf(() => {
1336
- dom.setValue(selectEl, ctx.format);
1337
- });
1338
- }
1339
- };
1340
- var invoke = {
1341
- changeEnd(ctx) {
1342
- const value = ctx.value.toFormat(ctx.format);
1343
- ctx.onValueChangeEnd?.({
1344
- value,
1345
- valueAsString: ctx.valueAsString
1346
- });
1347
- },
1348
- change(ctx) {
1349
- const value = ctx.value.toFormat(ctx.format);
1350
- ctx.onValueChange?.({
1351
- value,
1352
- valueAsString: ctx.valueAsString
1353
- });
1354
- dispatchInputValueEvent(dom.getHiddenInputEl(ctx), { value: ctx.valueAsString });
1355
- },
1356
- formatChange(ctx) {
1357
- ctx.onFormatChange?.({ format: ctx.format });
1358
- }
1359
- };
1360
- var set = {
1361
- value(ctx, color) {
1362
- if (!color || ctx.value.isEqual(color))
1363
- return;
1364
- ctx.value = color;
1365
- invoke.change(ctx);
1366
- },
1367
- format(ctx, format) {
1368
- if (ctx.format === format)
1369
- return;
1370
- ctx.format = format;
1371
- invoke.formatChange(ctx);
1372
- }
1373
- };
1374
- export {
1375
- anatomy,
1376
- connect,
1377
- machine,
1378
- parse
1379
- };
1
+ import{createAnatomy}from"@zag-js/anatomy";var anatomy=createAnatomy("color-picker",["root","label","control","trigger","positioner","content","area","areaThumb","areaBackground","channelSlider","channelSliderTrack","channelSliderThumb","channelInput","transparencyGrid","swatchGroup","swatchTrigger","swatchIndicator","swatch","eyeDropperTrigger","formatTrigger","formatSelect"]);var parts=anatomy.build();import{getColorAreaGradient,normalizeColor}from"@zag-js/color-utils";import{getEventKey,getEventPoint,getEventStep,getNativeEvent,isLeftClick,isModifierKey}from"@zag-js/dom-event";import{dataAttr,query,visuallyHiddenStyle}from"@zag-js/dom-query";import{getPlacementStyles}from"@zag-js/popper";import{getRelativePoint}from"@zag-js/dom-event";import{createScope,queryAll}from"@zag-js/dom-query";var dom=createScope({getRootId:ctx=>ctx.ids?.root??`color-picker:${ctx.id}`,getLabelId:ctx=>ctx.ids?.label??`color-picker:${ctx.id}:label`,getHiddenInputId:ctx=>`color-picker:${ctx.id}:hidden-input`,getControlId:ctx=>ctx.ids?.control??`color-picker:${ctx.id}:control`,getTriggerId:ctx=>ctx.ids?.trigger??`color-picker:${ctx.id}:trigger`,getContentId:ctx=>ctx.ids?.content??`color-picker:${ctx.id}:content`,getPositionerId:ctx=>`color-picker:${ctx.id}:positioner`,getFormatSelectId:ctx=>`color-picker:${ctx.id}:format-select`,getAreaId:ctx=>ctx.ids?.area??`color-picker:${ctx.id}:area`,getAreaGradientId:ctx=>ctx.ids?.areaGradient??`color-picker:${ctx.id}:area-gradient`,getAreaThumbId:ctx=>ctx.ids?.areaThumb??`color-picker:${ctx.id}:area-thumb`,getChannelSliderId:(ctx,channel)=>ctx.ids?.channelSliderTrack?.(channel)??`color-picker:${ctx.id}:slider-track:${channel}`,getChannelSliderThumbId:(ctx,channel)=>ctx.ids?.channelSliderThumb?.(channel)??`color-picker:${ctx.id}:slider-thumb:${channel}`,getContentEl:ctx=>dom.getById(ctx,dom.getContentId(ctx)),getAreaThumbEl:ctx=>dom.getById(ctx,dom.getAreaThumbId(ctx)),getChannelSliderThumbEl:(ctx,channel)=>dom.getById(ctx,dom.getChannelSliderThumbId(ctx,channel)),getChannelInputEl:(ctx,channel)=>{return[...queryAll(dom.getContentEl(ctx),`input[data-channel="${channel}"]`),...queryAll(dom.getControlEl(ctx),`input[data-channel="${channel}"]`)]},getFormatSelectEl:ctx=>dom.getById(ctx,dom.getFormatSelectId(ctx)),getHiddenInputEl:ctx=>dom.getById(ctx,dom.getHiddenInputId(ctx)),getAreaEl:ctx=>dom.getById(ctx,dom.getAreaId(ctx)),getAreaValueFromPoint(ctx,point){const areaEl=dom.getAreaEl(ctx);if(!areaEl)return;const{percent}=getRelativePoint(point,areaEl);return percent},getControlEl:ctx=>dom.getById(ctx,dom.getControlId(ctx)),getTriggerEl:ctx=>dom.getById(ctx,dom.getTriggerId(ctx)),getPositionerEl:ctx=>dom.getById(ctx,dom.getPositionerId(ctx)),getChannelSliderTrackEl:(ctx,channel)=>{return dom.getById(ctx,dom.getChannelSliderId(ctx,channel))},getChannelSliderValueFromPoint(ctx,point,channel){const trackEl=dom.getChannelSliderTrackEl(ctx,channel);if(!trackEl)return;const{percent}=getRelativePoint(point,trackEl);return percent},getChannelInputEls:ctx=>{return[...queryAll(dom.getContentEl(ctx),"input[data-channel]"),...queryAll(dom.getControlEl(ctx),"input[data-channel]")]}});import{parseColor}from"@zag-js/color-utils";function getChannelDisplayColor(color,channel){switch(channel){case"hue":return parseColor(`hsl(${color.getChannelValue("hue")}, 100%, 50%)`);case"lightness":case"brightness":case"saturation":case"red":case"green":case"blue":return color.withChannelValue("alpha",1);case"alpha":{return color}default:throw new Error("Unknown color channel: "+channel)}}import{parseColor as parseColor2}from"@zag-js/color-utils";function getChannelValue(color,channel){if(channel==null)return"";if(channel==="hex"){return color.toString("hex")}if(channel==="css"){return color.toString("css")}if(channel in color){return color.getChannelValue(channel).toString()}const isHSL=color.getFormat()==="hsla";switch(channel){case"hue":return isHSL?color.toFormat("hsla").getChannelValue("hue").toString():color.toFormat("hsba").getChannelValue("hue").toString();case"saturation":return isHSL?color.toFormat("hsla").getChannelValue("saturation").toString():color.toFormat("hsba").getChannelValue("saturation").toString();case"lightness":return color.toFormat("hsla").getChannelValue("lightness").toString();case"brightness":return color.toFormat("hsba").getChannelValue("brightness").toString();case"red":case"green":case"blue":return color.toFormat("rgba").getChannelValue(channel).toString();default:return color.getChannelValue(channel).toString()}}function getChannelRange(color,channel){switch(channel){case"hex":const minColor=parseColor2("#000000");const maxColor=parseColor2("#FFFFFF");return{minValue:minColor.toHexInt(),maxValue:maxColor.toHexInt(),pageSize:10,step:1};case"css":return void 0;case"hue":case"saturation":case"lightness":return color.toFormat("hsla").getChannelRange(channel);case"brightness":return color.toFormat("hsba").getChannelRange(channel);case"red":case"green":case"blue":return color.toFormat("rgba").getChannelRange(channel);default:return color.getChannelRange(channel)}}function getSliderBackgroundDirection(orientation,dir){if(orientation==="vertical"){return"top"}else if(dir==="ltr"){return"right"}else{return"left"}}var getSliderBackground=props=>{const{channel,value,dir}=props;const bgDirection=getSliderBackgroundDirection(props.orientation,dir);const{minValue,maxValue}=value.getChannelRange(channel);switch(channel){case"hue":return`linear-gradient(to ${bgDirection}, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0) 33%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 83%, rgb(255, 0, 0) 100%)`;case"lightness":{let start=value.withChannelValue(channel,minValue).toString("css");let middle=value.withChannelValue(channel,(maxValue-minValue)/2).toString("css");let end=value.withChannelValue(channel,maxValue).toString("css");return`linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`}case"saturation":case"brightness":case"red":case"green":case"blue":case"alpha":{let start=value.withChannelValue(channel,minValue).toString("css");let end=value.withChannelValue(channel,maxValue).toString("css");return`linear-gradient(to ${bgDirection}, ${start}, ${end})`}default:throw new Error("Unknown color channel: "+channel)}};function connect(state,send,normalize){const value=state.context.value;const areaValue=state.context.areaValue;const valueAsString=state.context.valueAsString;const disabled=state.context.isDisabled;const interactive=state.context.isInteractive;const dragging=state.hasTag("dragging");const open=state.hasTag("open");const focused=state.hasTag("focused");const getAreaChannels=props=>{const channels=areaValue.getChannels();return{xChannel:props.xChannel??channels[1],yChannel:props.yChannel??channels[2]}};const currentPlacement=state.context.currentPlacement;const popperStyles=getPlacementStyles({...state.context.positioning,placement:currentPlacement});function getSwatchTriggerState(props){const color=normalizeColor(props.value).toFormat(state.context.format);return{value:color,valueAsString:color.toString("hex"),checked:color.isEqual(value),disabled:props.disabled||!interactive}}return{dragging,open,valueAsString,value,setOpen(nextOpen){if(nextOpen===open)return;send({type:nextOpen?"OPEN":"CLOSE"})},setValue(value2){send({type:"VALUE.SET",value:normalizeColor(value2),src:"set-color"})},getChannelValue(channel){return getChannelValue(value,channel)},setChannelValue(channel,channelValue){const color=value.withChannelValue(channel,channelValue);send({type:"VALUE.SET",value:color,src:"set-channel"})},format:state.context.format,setFormat(format){const formatValue=value.toFormat(format);send({type:"VALUE.SET",value:formatValue,src:"set-format"})},alpha:value.getChannelValue("alpha"),setAlpha(alphaValue){const color=value.withChannelValue("alpha",alphaValue);send({type:"VALUE.SET",value:color,src:"set-alpha"})},rootProps:normalize.element({...parts.root.attrs,dir:state.context.dir,id:dom.getRootId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),style:{"--value":value.toString("css")}}),labelProps:normalize.element({...parts.label.attrs,dir:state.context.dir,id:dom.getLabelId(state.context),htmlFor:dom.getHiddenInputId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-focus":dataAttr(focused),onClick(event){event.preventDefault();const inputEl=query(dom.getControlEl(state.context),"[data-channel=hex]");inputEl?.focus({preventScroll:true})}}),controlProps:normalize.element({...parts.control.attrs,id:dom.getControlId(state.context),dir:state.context.dir,"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-state":open?"open":"closed","data-focus":dataAttr(focused)}),triggerProps:normalize.button({...parts.trigger.attrs,id:dom.getTriggerId(state.context),dir:state.context.dir,disabled,"aria-label":`select color. current color is ${valueAsString}`,"aria-controls":dom.getContentId(state.context),"aria-labelledby":dom.getLabelId(state.context),"data-disabled":dataAttr(disabled),"data-readonly":dataAttr(state.context.readOnly),"data-placement":currentPlacement,"aria-expanded":dataAttr(open),"data-state":open?"open":"closed","data-focus":dataAttr(focused),type:"button",onClick(){if(!interactive)return;send({type:"TRIGGER.CLICK"})},onBlur(){if(!interactive)return;send({type:"TRIGGER.BLUR"})},style:{position:"relative"}}),positionerProps:normalize.element({...parts.positioner.attrs,id:dom.getPositionerId(state.context),dir:state.context.dir,style:popperStyles.floating}),contentProps:normalize.element({...parts.content.attrs,id:dom.getContentId(state.context),dir:state.context.dir,"data-placement":currentPlacement,"data-state":open?"open":"closed",hidden:!open}),getAreaProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const{areaStyles}=getColorAreaGradient(areaValue,{xChannel,yChannel,dir:state.context.dir});return normalize.element({...parts.area.attrs,id:dom.getAreaId(state.context),role:"group",onPointerDown(event){if(!interactive)return;const evt=getNativeEvent(event);if(!isLeftClick(evt)||isModifierKey(evt))return;const point=getEventPoint(evt);const channel={xChannel,yChannel};send({type:"AREA.POINTER_DOWN",point,channel,id:"area"});event.preventDefault()},style:{position:"relative",touchAction:"none",forcedColorAdjust:"none",...areaStyles}})},getAreaBackgroundProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const{areaGradientStyles}=getColorAreaGradient(areaValue,{xChannel,yChannel,dir:state.context.dir});return normalize.element({...parts.areaBackground.attrs,id:dom.getAreaGradientId(state.context),style:{position:"relative",touchAction:"none",forcedColorAdjust:"none",...areaGradientStyles}})},getAreaThumbProps(props={}){const{xChannel,yChannel}=getAreaChannels(props);const channel={xChannel,yChannel};const xPercent=areaValue.getChannelValuePercent(xChannel);const yPercent=1-areaValue.getChannelValuePercent(yChannel);const xValue=areaValue.getChannelValue(xChannel);const yValue=areaValue.getChannelValue(yChannel);return normalize.element({...parts.areaThumb.attrs,id:dom.getAreaThumbId(state.context),dir:state.context.dir,tabIndex:disabled?void 0:0,"data-disabled":dataAttr(disabled),role:"slider","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":xValue,"aria-label":`${xChannel} and ${yChannel}`,"aria-roledescription":"2d slider","aria-valuetext":`${xChannel} ${xValue}, ${yChannel} ${yValue}`,style:{position:"absolute",left:`${xPercent*100}%`,top:`${yPercent*100}%`,transform:"translate(-50%, -50%)",touchAction:"none",forcedColorAdjust:"none",background:areaValue.withChannelValue("alpha",1).toString("css")},onFocus(){if(!interactive)return;send({type:"AREA.FOCUS",id:"area",channel})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;const step=getEventStep(event);const keyMap={ArrowUp(){send({type:"AREA.ARROW_UP",channel,step})},ArrowDown(){send({type:"AREA.ARROW_DOWN",channel,step})},ArrowLeft(){send({type:"AREA.ARROW_LEFT",channel,step})},ArrowRight(){send({type:"AREA.ARROW_RIGHT",channel,step})},PageUp(){send({type:"AREA.PAGE_UP",channel,step})},PageDown(){send({type:"AREA.PAGE_DOWN",channel,step})},Escape(event2){event2.stopPropagation()}};const exec=keyMap[getEventKey(event,state.context)];if(exec){exec(event);event.preventDefault()}}})},getTransparencyGridProps(props={}){const{size="12px"}=props;return normalize.element({...parts.transparencyGrid.attrs,style:{"--size":size,width:"100%",height:"100%",position:"absolute",backgroundColor:"#fff",backgroundImage:"conic-gradient(#eeeeee 0 25%, transparent 0 50%, #eeeeee 0 75%, transparent 0)",backgroundSize:"var(--size) var(--size)",inset:"0px",zIndex:"auto",pointerEvents:"none"}})},getChannelSliderProps(props){const{orientation="horizontal",channel}=props;return normalize.element({...parts.channelSlider.attrs,"data-channel":channel,"data-orientation":orientation,role:"presentation",onPointerDown(event){if(!interactive)return;const evt=getNativeEvent(event);if(!isLeftClick(evt)||isModifierKey(evt))return;const point=getEventPoint(evt);send({type:"CHANNEL_SLIDER.POINTER_DOWN",channel,point,id:channel,orientation});event.preventDefault()},style:{position:"relative",touchAction:"none"}})},getChannelSliderTrackProps(props){const{orientation="horizontal",channel}=props;return normalize.element({...parts.channelSliderTrack.attrs,id:dom.getChannelSliderId(state.context,channel),role:"group","data-channel":channel,"data-orientation":orientation,style:{position:"relative",forcedColorAdjust:"none",backgroundImage:getSliderBackground({orientation,channel,dir:state.context.dir,value:areaValue})}})},getChannelSliderThumbProps(props){const{orientation="horizontal",channel}=props;const{minValue,maxValue,step:stepValue}=areaValue.getChannelRange(channel);const channelValue=areaValue.getChannelValue(channel);const offset=(channelValue-minValue)/(maxValue-minValue);const placementStyles=orientation==="horizontal"?{left:`${offset*100}%`,top:"50%"}:{top:`${offset*100}%`,left:"50%"};return normalize.element({...parts.channelSliderThumb.attrs,id:dom.getChannelSliderThumbId(state.context,channel),role:"slider","aria-label":channel,tabIndex:disabled?void 0:0,"data-channel":channel,"data-disabled":dataAttr(disabled),"data-orientation":orientation,"aria-disabled":dataAttr(disabled),"aria-orientation":orientation,"aria-valuemax":maxValue,"aria-valuemin":minValue,"aria-valuenow":channelValue,"aria-valuetext":`${channel} ${channelValue}`,style:{forcedColorAdjust:"none",position:"absolute",background:getChannelDisplayColor(areaValue,channel).toString("css"),...placementStyles},onFocus(){if(!interactive)return;send({type:"CHANNEL_SLIDER.FOCUS",channel})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;const step=getEventStep(event)*stepValue;const keyMap={ArrowUp(){send({type:"CHANNEL_SLIDER.ARROW_UP",channel,step})},ArrowDown(){send({type:"CHANNEL_SLIDER.ARROW_DOWN",channel,step})},ArrowLeft(){send({type:"CHANNEL_SLIDER.ARROW_LEFT",channel,step})},ArrowRight(){send({type:"CHANNEL_SLIDER.ARROW_RIGHT",channel,step})},PageUp(){send({type:"CHANNEL_SLIDER.PAGE_UP",channel})},PageDown(){send({type:"CHANNEL_SLIDER.PAGE_DOWN",channel})},Home(){send({type:"CHANNEL_SLIDER.HOME",channel})},End(){send({type:"CHANNEL_SLIDER.END",channel})},Escape(event2){event2.stopPropagation()}};const exec=keyMap[getEventKey(event,state.context)];if(exec){exec(event);event.preventDefault()}}})},getChannelInputProps(props){const{channel}=props;const isTextField=channel==="hex"||channel==="css";const range=getChannelRange(value,channel);return normalize.input({...parts.channelInput.attrs,dir:state.context.dir,type:isTextField?"text":"number","data-channel":channel,"aria-label":channel,spellCheck:false,autoComplete:"off",disabled,"data-disabled":dataAttr(disabled),readOnly:state.context.readOnly,defaultValue:getChannelValue(value,channel),min:range?.minValue,max:range?.maxValue,step:range?.step,onBeforeInput(event){if(isTextField||!interactive)return;const value2=event.currentTarget.value;if(value2.match(/[^0-9.]/g)){event.preventDefault()}},onFocus(event){if(!interactive)return;send({type:"CHANNEL_INPUT.FOCUS",channel});event.target.select()},onBlur(event){if(!interactive)return;const value2=isTextField?event.currentTarget.value:event.currentTarget.valueAsNumber;send({type:"CHANNEL_INPUT.BLUR",channel,value:value2,isTextField})},onKeyDown(event){if(event.defaultPrevented)return;if(!interactive)return;if(event.key==="Enter"){const value2=isTextField?event.currentTarget.value:event.currentTarget.valueAsNumber;send({type:"CHANNEL_INPUT.CHANGE",channel,value:value2,isTextField});event.preventDefault()}},style:{appearance:"none",WebkitAppearance:"none",MozAppearance:"textfield"}})},hiddenInputProps:normalize.input({type:"text",disabled,name:state.context.name,id:dom.getHiddenInputId(state.context),style:visuallyHiddenStyle,defaultValue:valueAsString}),eyeDropperTriggerProps:normalize.button({...parts.eyeDropperTrigger.attrs,type:"button",dir:state.context.dir,disabled,"data-disabled":dataAttr(disabled),"aria-label":"Pick a color from the screen",onClick(){if(!interactive)return;send("EYEDROPPER.CLICK")}}),swatchGroupProps:normalize.element({...parts.swatchGroup.attrs,role:"group"}),getSwatchTriggerState,getSwatchTriggerProps(props){const triggerState=getSwatchTriggerState(props);return normalize.button({...parts.swatchTrigger.attrs,disabled:triggerState.disabled,dir:state.context.dir,type:"button","aria-label":`select ${triggerState.valueAsString} as the color`,"data-state":triggerState.checked?"checked":"unchecked","data-value":triggerState.valueAsString,"data-disabled":dataAttr(triggerState.disabled),onClick(){if(triggerState.disabled)return;send({type:"SWATCH_TRIGGER.CLICK",value:triggerState.value})},style:{position:"relative"}})},getSwatchIndicatorProps(props){const triggerState=getSwatchTriggerState(props);return normalize.element({...parts.swatchIndicator.attrs,dir:state.context.dir,hidden:!triggerState.checked})},getSwatchProps(props){const{respectAlpha=true}=props;const triggerState=getSwatchTriggerState(props);return normalize.element({...parts.swatch.attrs,dir:state.context.dir,"data-state":triggerState.checked?"checked":"unchecked","data-value":triggerState.valueAsString,style:{position:"relative",background:triggerState.value.toString(respectAlpha?"css":"hex")}})},formatTriggerProps:normalize.button({...parts.formatTrigger.attrs,dir:state.context.dir,type:"button","aria-label":`change color format to ${getNextFormat(state.context.format)}`,onClick(event){if(event.currentTarget.disabled)return;const nextFormat=getNextFormat(state.context.format);send({type:"FORMAT.SET",format:nextFormat,src:"format-trigger"})}}),formatSelectProps:normalize.select({...parts.formatSelect.attrs,"aria-label":"change color format",dir:state.context.dir,defaultValue:state.context.format,disabled,onChange(event){const format=assertFormat(event.currentTarget.value);send({type:"FORMAT.SET",format,src:"format-select"})}})}}var formats=["hsba","hsla","rgba"];var formatRegex=new RegExp(`^(${formats.join("|")})$`);function getNextFormat(format){const index=formats.indexOf(format);return formats[index+1]??formats[0]}function assertFormat(format){if(formatRegex.test(format))return format;throw new Error(`Unsupported color format: ${format}`)}import{parseColor as parseColor4}from"@zag-js/color-utils";import{createMachine,guards}from"@zag-js/core";import{trackDismissableElement}from"@zag-js/dismissable";import{trackPointerMove}from"@zag-js/dom-event";import{getInitialFocus,raf}from"@zag-js/dom-query";import{dispatchInputValueEvent,trackFormControl}from"@zag-js/form-utils";import{getPlacement}from"@zag-js/popper";import{disableTextSelection}from"@zag-js/text-selection";import{compact,tryCatch}from"@zag-js/utils";import{parseColor as parseColor3}from"@zag-js/color-utils";var parse=colorString=>{return parseColor3(colorString)};var{and}=guards;function machine(userContext){const ctx=compact(userContext);return createMachine({id:"color-picker",initial:ctx.open?"open":"idle",context:{dir:"ltr",value:parse("#000000"),format:"rgba",disabled:false,closeOnSelect:false,...ctx,activeId:null,activeChannel:null,activeOrientation:null,fieldsetDisabled:false,restoreFocus:true,positioning:{...ctx.positioning,placement:"bottom"}},computed:{isRtl:ctx2=>ctx2.dir==="rtl",isDisabled:ctx2=>!!ctx2.disabled||ctx2.fieldsetDisabled,isInteractive:ctx2=>!(ctx2.isDisabled||ctx2.readOnly),valueAsString:ctx2=>ctx2.value.toString(ctx2.format),areaValue:ctx2=>{const format=ctx2.format.startsWith("hsl")?"hsla":"hsba";return ctx2.value.toFormat(format)}},activities:["trackFormControl"],watch:{value:["syncInputElements"],format:["syncFormatSelectElement"],open:["toggleVisibility"]},on:{"VALUE.SET":{actions:["setValue"]},"FORMAT.SET":{actions:["setFormat"]},"CHANNEL_INPUT.CHANGE":{actions:["setChannelColorFromInput"]},"EYEDROPPER.CLICK":{actions:["openEyeDropper"]}},states:{idle:{tags:["closed"],on:{"CONTROLLED.OPEN":{target:"open",actions:["setInitialFocus"]},OPEN:[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"CHANNEL_INPUT.FOCUS":{target:"focused",actions:["setActiveChannel"]}}},focused:{tags:["closed","focused"],on:{"CONTROLLED.OPEN":{target:"open",actions:["setInitialFocus"]},OPEN:[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnOpen"]},{target:"open",actions:["invokeOnOpen","setInitialFocus"]}],"CHANNEL_INPUT.FOCUS":{actions:["setActiveChannel"]},"CHANNEL_INPUT.BLUR":{target:"idle",actions:["setChannelColorFromInput"]},"TRIGGER.BLUR":{target:"idle"}}},open:{tags:["open"],activities:["trackPositioning","trackDismissableElement"],on:{"CONTROLLED.CLOSE":[{guard:"shouldRestoreFocus",target:"focused",actions:["setReturnFocus"]},{target:"idle"}],"TRIGGER.CLICK":[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}],"AREA.POINTER_DOWN":{target:"open:dragging",actions:["setActiveChannel","setAreaColorFromPoint","focusAreaThumb"]},"AREA.FOCUS":{actions:["setActiveChannel"]},"CHANNEL_SLIDER.POINTER_DOWN":{target:"open:dragging",actions:["setActiveChannel","setChannelColorFromPoint","focusChannelThumb"]},"CHANNEL_SLIDER.FOCUS":{actions:["setActiveChannel"]},"AREA.ARROW_LEFT":{actions:["decrementXChannel"]},"AREA.ARROW_RIGHT":{actions:["incrementXChannel"]},"AREA.ARROW_UP":{actions:["incrementYChannel"]},"AREA.ARROW_DOWN":{actions:["decrementYChannel"]},"AREA.PAGE_UP":{actions:["incrementXChannel"]},"AREA.PAGE_DOWN":{actions:["decrementXChannel"]},"CHANNEL_SLIDER.ARROW_LEFT":{actions:["decrementChannel"]},"CHANNEL_SLIDER.ARROW_RIGHT":{actions:["incrementChannel"]},"CHANNEL_SLIDER.ARROW_UP":{actions:["incrementChannel"]},"CHANNEL_SLIDER.ARROW_DOWN":{actions:["decrementChannel"]},"CHANNEL_SLIDER.PAGE_UP":{actions:["incrementChannel"]},"CHANNEL_SLIDER.PAGE_DOWN":{actions:["decrementChannel"]},"CHANNEL_SLIDER.HOME":{actions:["setChannelToMin"]},"CHANNEL_SLIDER.END":{actions:["setChannelToMax"]},"CHANNEL_INPUT.BLUR":{actions:["setChannelColorFromInput"]},INTERACT_OUTSIDE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{guard:"shouldRestoreFocus",target:"focused",actions:["invokeOnClose","setReturnFocus"]},{target:"idle",actions:["invokeOnClose"]}],CLOSE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}],"SWATCH_TRIGGER.CLICK":[{guard:and("isOpenControlled","closeOnSelect"),actions:["setValue","invokeOnClose"]},{guard:"closeOnSelect",target:"focused",actions:["setValue","invokeOnClose","setReturnFocus"]},{actions:["setValue"]}]}},"open:dragging":{tags:["open"],exit:["clearActiveChannel"],activities:["trackPointerMove","disableTextSelection","trackPositioning","trackDismissableElement"],on:{"CONTROLLED.CLOSE":[{guard:"shouldRestoreFocus",target:"focused",actions:["setReturnFocus"]},{target:"idle"}],"AREA.POINTER_MOVE":{actions:["setAreaColorFromPoint","focusAreaThumb"]},"AREA.POINTER_UP":{target:"open",actions:["invokeOnChangeEnd"]},"CHANNEL_SLIDER.POINTER_MOVE":{actions:["setChannelColorFromPoint","focusChannelThumb"]},"CHANNEL_SLIDER.POINTER_UP":{target:"open",actions:["invokeOnChangeEnd"]},INTERACT_OUTSIDE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{guard:"shouldRestoreFocus",target:"focused",actions:["invokeOnClose","setReturnFocus"]},{target:"idle",actions:["invokeOnClose"]}],CLOSE:[{guard:"isOpenControlled",actions:["invokeOnClose"]},{target:"idle",actions:["invokeOnClose"]}]}}}},{guards:{closeOnSelect:ctx2=>!!ctx2.closeOnSelect,isOpenControlled:ctx2=>!!ctx2["open.controlled"],shouldRestoreFocus:ctx2=>!!ctx2.restoreFocus},activities:{trackPositioning(ctx2){ctx2.currentPlacement=ctx2.positioning.placement;const anchorEl=dom.getTriggerEl(ctx2);const getPositionerEl=()=>dom.getPositionerEl(ctx2);return getPlacement(anchorEl,getPositionerEl,{...ctx2.positioning,defer:true,onComplete(data){ctx2.currentPlacement=data.placement}})},trackDismissableElement(ctx2,_evt,{send}){const getContentEl=()=>dom.getContentEl(ctx2);return trackDismissableElement(getContentEl,{exclude:dom.getTriggerEl(ctx2),defer:true,onInteractOutside(event){ctx2.onInteractOutside?.(event);if(event.defaultPrevented)return;ctx2.restoreFocus=!(event.detail.focusable||event.detail.contextmenu)},onPointerDownOutside:ctx2.onPointerDownOutside,onFocusOutside:ctx2.onFocusOutside,onDismiss(){send({type:"INTERACT_OUTSIDE"})}})},trackFormControl(ctx2,_evt,{send,initialContext}){const inputEl=dom.getHiddenInputEl(ctx2);return trackFormControl(inputEl,{onFieldsetDisabledChange(disabled){ctx2.fieldsetDisabled=disabled},onFormReset(){send({type:"VALUE.SET",value:initialContext.value,src:"form.reset"})}})},trackPointerMove(ctx2,_evt,{send}){return trackPointerMove(dom.getDoc(ctx2),{onPointerMove({point}){const type=ctx2.activeId==="area"?"AREA.POINTER_MOVE":"CHANNEL_SLIDER.POINTER_MOVE";send({type,point})},onPointerUp(){const type=ctx2.activeId==="area"?"AREA.POINTER_UP":"CHANNEL_SLIDER.POINTER_UP";send({type})}})},disableTextSelection(ctx2){return disableTextSelection({doc:dom.getDoc(ctx2),target:dom.getContentEl(ctx2)})}},actions:{openEyeDropper(ctx2){const isSupported="EyeDropper"in dom.getWin(ctx2);if(!isSupported)return;const win=dom.getWin(ctx2);const picker=new win.EyeDropper;picker.open().then(({sRGBHex})=>{const format=ctx2.value.getFormat();const color=parseColor4(sRGBHex).toFormat(format);set.value(ctx2,color);ctx2.onValueChangeEnd?.({value:ctx2.value,valueAsString:ctx2.valueAsString})}).catch(()=>void 0)},setActiveChannel(ctx2,evt){ctx2.activeId=evt.id;if(evt.channel)ctx2.activeChannel=evt.channel;if(evt.orientation)ctx2.activeOrientation=evt.orientation},clearActiveChannel(ctx2){ctx2.activeChannel=null;ctx2.activeId=null;ctx2.activeOrientation=null},setAreaColorFromPoint(ctx2,evt){const{xChannel,yChannel}=evt.channel||ctx2.activeChannel;const percent=dom.getAreaValueFromPoint(ctx2,evt.point);if(!percent)return;const xValue=ctx2.areaValue.getChannelPercentValue(xChannel,percent.x);const yValue=ctx2.areaValue.getChannelPercentValue(yChannel,1-percent.y);const color=ctx2.areaValue.withChannelValue(xChannel,xValue).withChannelValue(yChannel,yValue);set.value(ctx2,color)},setChannelColorFromPoint(ctx2,evt){const channel=evt.channel||ctx2.activeId;const percent=dom.getChannelSliderValueFromPoint(ctx2,evt.point,channel);if(!percent)return;const orientation=ctx2.activeOrientation||"horizontal";const channelPercent=orientation==="horizontal"?percent.x:percent.y;const value=ctx2.areaValue.getChannelPercentValue(channel,channelPercent);const color=ctx2.areaValue.withChannelValue(channel,value);set.value(ctx2,color)},setValue(ctx2,evt){set.value(ctx2,evt.value)},setFormat(ctx2,evt){set.format(ctx2,evt.format)},syncInputElements(ctx2){sync.inputs(ctx2)},invokeOnChangeEnd(ctx2){invoke.changeEnd(ctx2)},setChannelColorFromInput(ctx2,evt){const{channel,isTextField,value}=evt;const currentAlpha=ctx2.value.getChannelValue("alpha");let color;if(channel==="alpha"){let valueAsNumber=parseFloat(value);valueAsNumber=Number.isNaN(valueAsNumber)?currentAlpha:valueAsNumber;color=ctx2.value.withChannelValue("alpha",valueAsNumber)}else if(isTextField){color=tryCatch(()=>parse(value).withChannelValue("alpha",currentAlpha),()=>ctx2.value)}else{const current=ctx2.value.toFormat(ctx2.format);const valueAsNumber=Number.isNaN(value)?current.getChannelValue(channel):value;color=current.withChannelValue(channel,valueAsNumber)}sync.inputs(ctx2,color);set.value(ctx2,color)},incrementChannel(ctx2,evt){const color=ctx2.value.incrementChannel(evt.channel,evt.step);set.value(ctx2,color)},decrementChannel(ctx2,evt){const color=ctx2.value.decrementChannel(evt.channel,evt.step);set.value(ctx2,color)},incrementXChannel(ctx2,evt){const{xChannel}=evt.channel;const color=ctx2.areaValue.incrementChannel(xChannel,evt.step);set.value(ctx2,color)},decrementXChannel(ctx2,evt){const{xChannel}=evt.channel;const color=ctx2.areaValue.decrementChannel(xChannel,evt.step);set.value(ctx2,color)},incrementYChannel(ctx2,evt){const{yChannel}=evt.channel;const color=ctx2.areaValue.incrementChannel(yChannel,evt.step);set.value(ctx2,color)},decrementYChannel(ctx2,evt){const{yChannel}=evt.channel;const color=ctx2.areaValue.decrementChannel(yChannel,evt.step);set.value(ctx2,color)},setChannelToMax(ctx2,evt){const range=ctx2.value.getChannelRange(evt.channel);const color=ctx2.value.withChannelValue(evt.channel,range.maxValue);set.value(ctx2,color)},setChannelToMin(ctx2,evt){const range=ctx2.value.getChannelRange(evt.channel);const color=ctx2.value.withChannelValue(evt.channel,range.minValue);set.value(ctx2,color)},focusAreaThumb(ctx2){raf(()=>{dom.getAreaThumbEl(ctx2)?.focus({preventScroll:true})})},focusChannelThumb(ctx2,evt){raf(()=>{dom.getChannelSliderThumbEl(ctx2,evt.channel)?.focus({preventScroll:true})})},setInitialFocus(ctx2){raf(()=>{const element=getInitialFocus(dom.getContentEl(ctx2),ctx2.initialFocusEl);element?.focus({preventScroll:true})})},setReturnFocus(ctx2){raf(()=>{dom.getTriggerEl(ctx2)?.focus({preventScroll:true})})},syncFormatSelectElement(ctx2){sync.formatSelect(ctx2)},invokeOnOpen(ctx2){ctx2.onOpenChange?.({open:true})},invokeOnClose(ctx2){ctx2.onOpenChange?.({open:false})},toggleVisibility(ctx2,evt,{send}){send({type:ctx2.open?"CONTROLLED.OPEN":"CONTROLLED.CLOSE",previousEvent:evt})}},compareFns:{value:(a,b)=>a.isEqual(b)}})}var sync={inputs(ctx,color){const channelInputs=dom.getChannelInputEls(ctx);raf(()=>{channelInputs.forEach(inputEl=>{const channel=inputEl.dataset.channel;dom.setValue(inputEl,getChannelValue(color||ctx.value,channel))})})},formatSelect(ctx){const selectEl=dom.getFormatSelectEl(ctx);raf(()=>{dom.setValue(selectEl,ctx.format)})}};var invoke={changeEnd(ctx){const value=ctx.value.toFormat(ctx.format);ctx.onValueChangeEnd?.({value,valueAsString:ctx.valueAsString})},change(ctx){const value=ctx.value.toFormat(ctx.format);ctx.onValueChange?.({value,valueAsString:ctx.valueAsString});dispatchInputValueEvent(dom.getHiddenInputEl(ctx),{value:ctx.valueAsString})},formatChange(ctx){ctx.onFormatChange?.({format:ctx.format})}};var set={value(ctx,color){if(!color||ctx.value.isEqual(color))return;ctx.value=color;invoke.change(ctx)},format(ctx,format){if(ctx.format===format)return;ctx.format=format;invoke.formatChange(ctx)}};export{anatomy,connect,machine,parse};
1380
2
  //# sourceMappingURL=index.mjs.map