@destyler/color-picker 0.0.7-beta.7 → 0.1.0

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