@zag-js/color-picker 0.22.0 → 0.24.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.d.mts +107 -32
- package/dist/index.d.ts +107 -32
- package/dist/index.js +484 -294
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +483 -297
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -12
- package/src/color-picker.anatomy.ts +11 -5
- package/src/color-picker.connect.ts +200 -125
- package/src/color-picker.dom.ts +22 -3
- package/src/color-picker.machine.ts +227 -125
- package/src/color-picker.parse.ts +4 -0
- package/src/color-picker.types.ts +116 -30
- package/src/index.ts +7 -6
- package/src/utils/get-channel-input-value.ts +45 -11
- package/src/utils/get-slider-background.ts +7 -7
- package/src/utils/get-channel-details.ts +0 -60
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { parseColor, type Color } from "@zag-js/color-utils"
|
|
2
|
-
import { createMachine } from "@zag-js/core"
|
|
2
|
+
import { createMachine, guards, ref } from "@zag-js/core"
|
|
3
|
+
import { trackDismissableElement } from "@zag-js/dismissable"
|
|
3
4
|
import { trackPointerMove } from "@zag-js/dom-event"
|
|
4
5
|
import { raf } from "@zag-js/dom-query"
|
|
5
|
-
import { trackFormControl } from "@zag-js/form-utils"
|
|
6
|
-
import {
|
|
6
|
+
import { dispatchInputValueEvent, trackFormControl } from "@zag-js/form-utils"
|
|
7
|
+
import { getPlacement } from "@zag-js/popper"
|
|
7
8
|
import { disableTextSelection } from "@zag-js/text-selection"
|
|
8
9
|
import { compact, tryCatch } from "@zag-js/utils"
|
|
9
10
|
import { dom } from "./color-picker.dom"
|
|
11
|
+
import { parse } from "./color-picker.parse"
|
|
10
12
|
import type {
|
|
11
13
|
ColorFormat,
|
|
12
14
|
ColorType,
|
|
@@ -15,87 +17,129 @@ import type {
|
|
|
15
17
|
MachineState,
|
|
16
18
|
UserDefinedContext,
|
|
17
19
|
} from "./color-picker.types"
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
+
import { getChannelValue } from "./utils/get-channel-input-value"
|
|
21
|
+
|
|
22
|
+
const { stateIn } = guards
|
|
20
23
|
|
|
21
24
|
export function machine(userContext: UserDefinedContext) {
|
|
22
25
|
const ctx = compact(userContext)
|
|
23
26
|
return createMachine<MachineContext, MachineState>(
|
|
24
27
|
{
|
|
25
28
|
id: "color-picker",
|
|
26
|
-
initial: "idle",
|
|
29
|
+
initial: ctx.open ? "open" : "idle",
|
|
27
30
|
context: {
|
|
28
31
|
dir: "ltr",
|
|
29
|
-
value: "#
|
|
32
|
+
value: parse("#000000"),
|
|
30
33
|
disabled: false,
|
|
31
34
|
...ctx,
|
|
32
35
|
activeId: null,
|
|
33
36
|
activeChannel: null,
|
|
34
37
|
activeOrientation: null,
|
|
35
38
|
fieldsetDisabled: false,
|
|
39
|
+
autoFocus: true,
|
|
40
|
+
positioning: {
|
|
41
|
+
...ctx.positioning,
|
|
42
|
+
placement: "bottom",
|
|
43
|
+
},
|
|
36
44
|
},
|
|
37
45
|
|
|
38
46
|
computed: {
|
|
39
47
|
isRtl: (ctx) => ctx.dir === "rtl",
|
|
40
48
|
isDisabled: (ctx) => !!ctx.disabled || ctx.fieldsetDisabled,
|
|
41
49
|
isInteractive: (ctx) => !(ctx.isDisabled || ctx.readOnly),
|
|
42
|
-
|
|
50
|
+
valueAsString: (ctx) => ctx.value.toString("css"),
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
activities: ["trackFormControl"],
|
|
54
|
+
|
|
55
|
+
watch: {
|
|
56
|
+
valueAsString: ["syncInputElements"],
|
|
57
|
+
open: ["toggleVisibility"],
|
|
43
58
|
},
|
|
44
59
|
|
|
45
60
|
on: {
|
|
46
61
|
"VALUE.SET": {
|
|
47
62
|
actions: ["setValue"],
|
|
48
63
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
"CHANNEL_INPUT.FOCUS": [
|
|
65
|
+
{
|
|
66
|
+
guard: stateIn("idle"),
|
|
67
|
+
target: "focused",
|
|
68
|
+
actions: ["setActiveChannel"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
actions: ["setActiveChannel"],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
"CHANNEL_INPUT.BLUR": [
|
|
75
|
+
{
|
|
76
|
+
guard: stateIn("focused"),
|
|
77
|
+
target: "idle",
|
|
78
|
+
actions: ["setChannelColorFromInput"],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
actions: ["setChannelColorFromInput"],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
"CHANNEL_INPUT.CHANGE": {
|
|
85
|
+
actions: ["setChannelColorFromInput"],
|
|
86
|
+
},
|
|
55
87
|
},
|
|
56
88
|
|
|
57
89
|
states: {
|
|
58
90
|
idle: {
|
|
91
|
+
tags: ["closed"],
|
|
92
|
+
on: {
|
|
93
|
+
OPEN: {
|
|
94
|
+
target: "open",
|
|
95
|
+
actions: ["setInitialFocus", "invokeOnOpen"],
|
|
96
|
+
},
|
|
97
|
+
"TRIGGER.CLICK": {
|
|
98
|
+
target: "open",
|
|
99
|
+
actions: ["setInitialFocus", "invokeOnOpen"],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
focused: {
|
|
105
|
+
tags: ["closed", "focused"],
|
|
59
106
|
on: {
|
|
107
|
+
OPEN: {
|
|
108
|
+
target: "open",
|
|
109
|
+
actions: ["setInitialFocus", "invokeOnOpen"],
|
|
110
|
+
},
|
|
111
|
+
"TRIGGER.CLICK": {
|
|
112
|
+
target: "open",
|
|
113
|
+
actions: ["setInitialFocus", "invokeOnOpen"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
open: {
|
|
119
|
+
tags: ["open"],
|
|
120
|
+
activities: ["trackPositioning", "trackDismissableElement"],
|
|
121
|
+
on: {
|
|
122
|
+
"TRIGGER.CLICK": {
|
|
123
|
+
target: "idle",
|
|
124
|
+
actions: ["invokeOnClose"],
|
|
125
|
+
},
|
|
60
126
|
"EYEDROPPER.CLICK": {
|
|
61
127
|
actions: ["openEyeDropper"],
|
|
62
128
|
},
|
|
63
129
|
"AREA.POINTER_DOWN": {
|
|
64
|
-
target: "dragging",
|
|
130
|
+
target: "open:dragging",
|
|
65
131
|
actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"],
|
|
66
132
|
},
|
|
67
133
|
"AREA.FOCUS": {
|
|
68
|
-
target: "focused",
|
|
69
134
|
actions: ["setActiveChannel"],
|
|
70
135
|
},
|
|
71
136
|
"CHANNEL_SLIDER.POINTER_DOWN": {
|
|
72
|
-
target: "dragging",
|
|
137
|
+
target: "open:dragging",
|
|
73
138
|
actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"],
|
|
74
139
|
},
|
|
75
140
|
"CHANNEL_SLIDER.FOCUS": {
|
|
76
|
-
target: "focused",
|
|
77
|
-
actions: ["setActiveChannel"],
|
|
78
|
-
},
|
|
79
|
-
"CHANNEL_INPUT.FOCUS": {
|
|
80
|
-
target: "focused",
|
|
81
141
|
actions: ["setActiveChannel"],
|
|
82
142
|
},
|
|
83
|
-
"CHANNEL_INPUT.CHANGE": {
|
|
84
|
-
actions: ["setChannelColorFromInput"],
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
focused: {
|
|
90
|
-
on: {
|
|
91
|
-
"AREA.POINTER_DOWN": {
|
|
92
|
-
target: "dragging",
|
|
93
|
-
actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"],
|
|
94
|
-
},
|
|
95
|
-
"CHANNEL_SLIDER.POINTER_DOWN": {
|
|
96
|
-
target: "dragging",
|
|
97
|
-
actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"],
|
|
98
|
-
},
|
|
99
143
|
"AREA.ARROW_LEFT": {
|
|
100
144
|
actions: ["decrementXChannel"],
|
|
101
145
|
},
|
|
@@ -138,45 +182,100 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
138
182
|
"CHANNEL_SLIDER.END": {
|
|
139
183
|
actions: ["setChannelToMax"],
|
|
140
184
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
185
|
+
INTERACT_OUTSIDE: [
|
|
186
|
+
{
|
|
187
|
+
guard: "shouldRestoreFocus",
|
|
188
|
+
target: "focused",
|
|
189
|
+
actions: ["setReturnFocus", "invokeOnClose"],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
target: "idle",
|
|
193
|
+
actions: ["invokeOnClose"],
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
CLOSE: {
|
|
151
197
|
target: "idle",
|
|
198
|
+
actions: ["invokeOnClose"],
|
|
152
199
|
},
|
|
153
200
|
},
|
|
154
201
|
},
|
|
155
202
|
|
|
156
|
-
dragging: {
|
|
203
|
+
"open:dragging": {
|
|
204
|
+
tags: ["open"],
|
|
157
205
|
exit: ["clearActiveChannel"],
|
|
158
|
-
activities: ["trackPointerMove", "disableTextSelection"],
|
|
206
|
+
activities: ["trackPointerMove", "disableTextSelection", "trackPositioning", "trackDismissableElement"],
|
|
159
207
|
on: {
|
|
160
208
|
"AREA.POINTER_MOVE": {
|
|
161
|
-
actions: ["setAreaColorFromPoint"],
|
|
209
|
+
actions: ["setAreaColorFromPoint", "focusAreaThumb"],
|
|
162
210
|
},
|
|
163
211
|
"AREA.POINTER_UP": {
|
|
164
|
-
target: "
|
|
212
|
+
target: "open",
|
|
165
213
|
actions: ["invokeOnChangeEnd"],
|
|
166
214
|
},
|
|
167
215
|
"CHANNEL_SLIDER.POINTER_MOVE": {
|
|
168
|
-
actions: ["setChannelColorFromPoint"],
|
|
216
|
+
actions: ["setChannelColorFromPoint", "focusChannelThumb"],
|
|
169
217
|
},
|
|
170
218
|
"CHANNEL_SLIDER.POINTER_UP": {
|
|
171
|
-
target: "
|
|
219
|
+
target: "open",
|
|
172
220
|
actions: ["invokeOnChangeEnd"],
|
|
173
221
|
},
|
|
222
|
+
INTERACT_OUTSIDE: [
|
|
223
|
+
{
|
|
224
|
+
guard: "shouldRestoreFocus",
|
|
225
|
+
target: "focused",
|
|
226
|
+
actions: ["setReturnFocus", "invokeOnClose"],
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
target: "idle",
|
|
230
|
+
actions: ["invokeOnClose"],
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
CLOSE: {
|
|
234
|
+
target: "idle",
|
|
235
|
+
actions: ["invokeOnClose"],
|
|
236
|
+
},
|
|
174
237
|
},
|
|
175
238
|
},
|
|
176
239
|
},
|
|
177
240
|
},
|
|
178
241
|
{
|
|
242
|
+
guards: {
|
|
243
|
+
isTargetFocusable: (_ctx, evt) => evt.restoreFocus,
|
|
244
|
+
},
|
|
179
245
|
activities: {
|
|
246
|
+
trackPositioning(ctx) {
|
|
247
|
+
ctx.currentPlacement = ctx.positioning.placement
|
|
248
|
+
const anchorEl = dom.getTriggerEl(ctx)
|
|
249
|
+
const getPositionerEl = () => dom.getPositionerEl(ctx)
|
|
250
|
+
return getPlacement(anchorEl, getPositionerEl, {
|
|
251
|
+
...ctx.positioning,
|
|
252
|
+
defer: true,
|
|
253
|
+
onComplete(data) {
|
|
254
|
+
ctx.currentPlacement = data.placement
|
|
255
|
+
},
|
|
256
|
+
onCleanup() {
|
|
257
|
+
ctx.currentPlacement = undefined
|
|
258
|
+
},
|
|
259
|
+
})
|
|
260
|
+
},
|
|
261
|
+
trackDismissableElement(ctx, _evt, { send }) {
|
|
262
|
+
const getContentEl = () => dom.getContentEl(ctx)
|
|
263
|
+
let restoreFocus = true
|
|
264
|
+
return trackDismissableElement(getContentEl, {
|
|
265
|
+
exclude: dom.getTriggerEl(ctx),
|
|
266
|
+
defer: true,
|
|
267
|
+
onInteractOutside(event) {
|
|
268
|
+
ctx.onInteractOutside?.(event)
|
|
269
|
+
if (event.defaultPrevented) return
|
|
270
|
+
restoreFocus = !(event.detail.focusable || event.detail.contextmenu)
|
|
271
|
+
},
|
|
272
|
+
onPointerDownOutside: ctx.onPointerDownOutside,
|
|
273
|
+
onFocusOutside: ctx.onFocusOutside,
|
|
274
|
+
onDismiss() {
|
|
275
|
+
send({ type: "INTERACT_OUTSIDE", restoreFocus })
|
|
276
|
+
},
|
|
277
|
+
})
|
|
278
|
+
},
|
|
180
279
|
trackFormControl(ctx, _evt, { send, initialContext }) {
|
|
181
280
|
const inputEl = dom.getHiddenInputEl(ctx)
|
|
182
281
|
return trackFormControl(inputEl, {
|
|
@@ -213,21 +312,17 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
213
312
|
picker
|
|
214
313
|
.open()
|
|
215
314
|
.then(({ sRGBHex }: { sRGBHex: string }) => {
|
|
216
|
-
const format = ctx.
|
|
315
|
+
const format = ctx.value.getFormat()
|
|
217
316
|
const color = parseColor(sRGBHex).toFormat(format) as Color
|
|
218
317
|
set.value(ctx, color)
|
|
219
|
-
ctx.onValueChangeEnd?.({ value: ctx.value,
|
|
318
|
+
ctx.onValueChangeEnd?.({ value: ctx.value, valueAsString: ctx.valueAsString })
|
|
220
319
|
})
|
|
221
320
|
.catch(() => void 0)
|
|
222
321
|
},
|
|
223
322
|
setActiveChannel(ctx, evt) {
|
|
224
323
|
ctx.activeId = evt.id
|
|
225
|
-
if (evt.channel)
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
if (evt.orientation) {
|
|
229
|
-
ctx.activeOrientation = evt.orientation
|
|
230
|
-
}
|
|
324
|
+
if (evt.channel) ctx.activeChannel = evt.channel
|
|
325
|
+
if (evt.orientation) ctx.activeOrientation = evt.orientation
|
|
231
326
|
},
|
|
232
327
|
clearActiveChannel(ctx) {
|
|
233
328
|
ctx.activeChannel = null
|
|
@@ -240,10 +335,10 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
240
335
|
const percent = dom.getAreaValueFromPoint(ctx, evt.point)
|
|
241
336
|
if (!percent) return
|
|
242
337
|
|
|
243
|
-
const
|
|
244
|
-
const
|
|
338
|
+
const xValue = ctx.value.getChannelPercentValue(xChannel, percent.x)
|
|
339
|
+
const yValue = ctx.value.getChannelPercentValue(yChannel, 1 - percent.y)
|
|
245
340
|
|
|
246
|
-
|
|
341
|
+
const color = ctx.value.withChannelValue(xChannel, xValue).withChannelValue(yChannel, yValue)
|
|
247
342
|
set.value(ctx, color)
|
|
248
343
|
},
|
|
249
344
|
setChannelColorFromPoint(ctx, evt) {
|
|
@@ -252,30 +347,18 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
252
347
|
const percent = dom.getChannelSliderValueFromPoint(ctx, evt.point, channel)
|
|
253
348
|
if (!percent) return
|
|
254
349
|
|
|
255
|
-
const { minValue, maxValue, step } = ctx.valueAsColor.getChannelRange(channel)
|
|
256
350
|
const orientation = ctx.activeOrientation || "horizontal"
|
|
351
|
+
const channelPercent = orientation === "horizontal" ? percent.x : percent.y
|
|
257
352
|
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
const value = snapValueToStep(channelValue - step, minValue, maxValue, step)
|
|
262
|
-
const newColor = ctx.valueAsColor.withChannelValue(channel, value)
|
|
263
|
-
|
|
264
|
-
set.value(ctx, newColor)
|
|
353
|
+
const value = ctx.value.getChannelPercentValue(channel, channelPercent)
|
|
354
|
+
const color = ctx.value.withChannelValue(channel, value)
|
|
355
|
+
set.value(ctx, color)
|
|
265
356
|
},
|
|
266
357
|
setValue(ctx, evt) {
|
|
267
358
|
set.value(ctx, evt.value)
|
|
268
359
|
},
|
|
269
360
|
syncInputElements(ctx) {
|
|
270
|
-
|
|
271
|
-
const inputs = dom.getChannelInputEls(ctx)
|
|
272
|
-
inputs.forEach((input) => {
|
|
273
|
-
const channel = input.dataset.channel as ExtendedColorChannel | null
|
|
274
|
-
dom.setValue(input, getChannelInputValue(ctx.valueAsColor, channel))
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
// sync hidden input
|
|
278
|
-
dom.setValue(dom.getHiddenInputEl(ctx), ctx.value)
|
|
361
|
+
sync.inputs(ctx)
|
|
279
362
|
},
|
|
280
363
|
invokeOnChangeEnd(ctx) {
|
|
281
364
|
invoke.changeEnd(ctx)
|
|
@@ -285,7 +368,7 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
285
368
|
|
|
286
369
|
// handle alpha channel
|
|
287
370
|
if (channel === "alpha") {
|
|
288
|
-
const newColor = ctx.
|
|
371
|
+
const newColor = ctx.value.withChannelValue("alpha", parseFloat(value))
|
|
289
372
|
set.value(ctx, newColor)
|
|
290
373
|
return
|
|
291
374
|
}
|
|
@@ -293,111 +376,130 @@ export function machine(userContext: UserDefinedContext) {
|
|
|
293
376
|
// handle other text channels
|
|
294
377
|
if (isTextField) {
|
|
295
378
|
const format: ColorFormat = "hsl"
|
|
296
|
-
const currentAlpha = ctx.
|
|
379
|
+
const currentAlpha = ctx.value.getChannelValue("alpha")
|
|
297
380
|
|
|
298
|
-
const
|
|
381
|
+
const color = tryCatch(
|
|
299
382
|
() => parseColor(value).toFormat(format).withChannelValue("alpha", currentAlpha),
|
|
300
|
-
() => ctx.
|
|
383
|
+
() => ctx.value,
|
|
301
384
|
)
|
|
302
385
|
|
|
303
386
|
// set channel input value immediately (in event user types native css color, we need to convert it to the current channel format)
|
|
304
387
|
const inputEl = dom.getChannelInputEl(ctx, channel)
|
|
305
|
-
dom.setValue(inputEl,
|
|
388
|
+
dom.setValue(inputEl, getChannelValue(color, channel))
|
|
306
389
|
|
|
307
|
-
set.value(ctx,
|
|
390
|
+
set.value(ctx, color)
|
|
308
391
|
return
|
|
309
392
|
}
|
|
310
393
|
|
|
311
394
|
// handle other channels
|
|
312
|
-
const
|
|
313
|
-
set.value(ctx,
|
|
395
|
+
const color = ctx.value.withChannelValue(channel, value)
|
|
396
|
+
set.value(ctx, color)
|
|
314
397
|
},
|
|
315
|
-
|
|
316
398
|
incrementChannel(ctx, evt) {
|
|
317
|
-
const
|
|
318
|
-
const channelValue = ctx.valueAsColor.getChannelValue(evt.channel)
|
|
319
|
-
const value = snapValueToStep(channelValue + evt.step, minValue, maxValue, step)
|
|
320
|
-
const color = ctx.valueAsColor.withChannelValue(evt.channel, clampValue(value, minValue, maxValue))
|
|
399
|
+
const color = ctx.value.incrementChannel(evt.channel, evt.step)
|
|
321
400
|
set.value(ctx, color)
|
|
322
401
|
},
|
|
323
402
|
decrementChannel(ctx, evt) {
|
|
324
|
-
const
|
|
325
|
-
const channelValue = ctx.valueAsColor.getChannelValue(evt.channel)
|
|
326
|
-
const value = snapValueToStep(channelValue - evt.step, minValue, maxValue, step)
|
|
327
|
-
const color = ctx.valueAsColor.withChannelValue(evt.channel, clampValue(value, minValue, maxValue))
|
|
403
|
+
const color = ctx.value.decrementChannel(evt.channel, evt.step)
|
|
328
404
|
set.value(ctx, color)
|
|
329
405
|
},
|
|
330
|
-
|
|
331
406
|
incrementXChannel(ctx, evt) {
|
|
332
|
-
const { xChannel
|
|
333
|
-
const
|
|
334
|
-
const color = ctx.valueAsColor.withChannelValue(xChannel, incrementX(evt.step))
|
|
407
|
+
const { xChannel } = evt.channel
|
|
408
|
+
const color = ctx.value.incrementChannel(xChannel, evt.step)
|
|
335
409
|
set.value(ctx, color)
|
|
336
410
|
},
|
|
337
411
|
decrementXChannel(ctx, evt) {
|
|
338
|
-
const { xChannel
|
|
339
|
-
const
|
|
340
|
-
const color = ctx.valueAsColor.withChannelValue(xChannel, decrementX(evt.step))
|
|
412
|
+
const { xChannel } = evt.channel
|
|
413
|
+
const color = ctx.value.decrementChannel(xChannel, evt.step)
|
|
341
414
|
set.value(ctx, color)
|
|
342
415
|
},
|
|
343
|
-
|
|
344
416
|
incrementYChannel(ctx, evt) {
|
|
345
|
-
const {
|
|
346
|
-
const
|
|
347
|
-
const color = ctx.valueAsColor.withChannelValue(yChannel, incrementY(evt.step))
|
|
417
|
+
const { yChannel } = evt.channel
|
|
418
|
+
const color = ctx.value.incrementChannel(yChannel, evt.step)
|
|
348
419
|
set.value(ctx, color)
|
|
349
420
|
},
|
|
350
421
|
decrementYChannel(ctx, evt) {
|
|
351
|
-
const {
|
|
352
|
-
const
|
|
353
|
-
const color = ctx.valueAsColor.withChannelValue(yChannel, decrementY(evt.step))
|
|
422
|
+
const { yChannel } = evt.channel
|
|
423
|
+
const color = ctx.value.decrementChannel(yChannel, evt.step)
|
|
354
424
|
set.value(ctx, color)
|
|
355
425
|
},
|
|
356
|
-
|
|
357
426
|
setChannelToMax(ctx, evt) {
|
|
358
|
-
const
|
|
359
|
-
const color = ctx.
|
|
427
|
+
const range = ctx.value.getChannelRange(evt.channel)
|
|
428
|
+
const color = ctx.value.withChannelValue(evt.channel, range.maxValue)
|
|
360
429
|
set.value(ctx, color)
|
|
361
430
|
},
|
|
362
431
|
setChannelToMin(ctx, evt) {
|
|
363
|
-
const
|
|
364
|
-
const color = ctx.
|
|
432
|
+
const range = ctx.value.getChannelRange(evt.channel)
|
|
433
|
+
const color = ctx.value.withChannelValue(evt.channel, range.minValue)
|
|
365
434
|
set.value(ctx, color)
|
|
366
435
|
},
|
|
367
436
|
focusAreaThumb(ctx) {
|
|
368
437
|
raf(() => {
|
|
369
|
-
dom.getAreaThumbEl(ctx)
|
|
438
|
+
dom?.focus(ctx, dom.getAreaThumbEl(ctx))
|
|
370
439
|
})
|
|
371
440
|
},
|
|
372
441
|
focusChannelThumb(ctx, evt) {
|
|
373
442
|
raf(() => {
|
|
374
|
-
dom.getChannelSliderThumbEl(ctx, evt.channel)
|
|
443
|
+
dom?.focus(ctx, dom.getChannelSliderThumbEl(ctx, evt.channel))
|
|
375
444
|
})
|
|
376
445
|
},
|
|
446
|
+
setInitialFocus(ctx) {
|
|
447
|
+
raf(() => {
|
|
448
|
+
dom.getInitialFocusEl(ctx)?.focus({ preventScroll: true })
|
|
449
|
+
})
|
|
450
|
+
},
|
|
451
|
+
setReturnFocus(ctx) {
|
|
452
|
+
raf(() => {
|
|
453
|
+
dom?.focus(ctx, dom.getTriggerEl(ctx))
|
|
454
|
+
})
|
|
455
|
+
},
|
|
456
|
+
invokeOnOpen(ctx) {
|
|
457
|
+
ctx.onOpenChange?.({ open: true })
|
|
458
|
+
},
|
|
459
|
+
invokeOnClose(ctx) {
|
|
460
|
+
ctx.onOpenChange?.({ open: false })
|
|
461
|
+
},
|
|
462
|
+
toggleVisibility(ctx, _evt, { send }) {
|
|
463
|
+
send({ type: ctx.open ? "OPEN" : "CLOSE", src: "controlled" })
|
|
464
|
+
},
|
|
377
465
|
},
|
|
378
466
|
},
|
|
379
467
|
)
|
|
380
468
|
}
|
|
381
469
|
|
|
470
|
+
const sync = {
|
|
471
|
+
inputs(ctx: MachineContext) {
|
|
472
|
+
// sync channel inputs
|
|
473
|
+
const channelInputs = dom.getChannelInputEls(ctx)
|
|
474
|
+
channelInputs.forEach((inputEl) => {
|
|
475
|
+
const channel = inputEl.dataset.channel as ExtendedColorChannel | null
|
|
476
|
+
dom.setValue(inputEl, getChannelValue(ctx.value, channel))
|
|
477
|
+
})
|
|
478
|
+
},
|
|
479
|
+
}
|
|
480
|
+
|
|
382
481
|
const invoke = {
|
|
383
482
|
changeEnd(ctx: MachineContext) {
|
|
384
483
|
ctx.onValueChangeEnd?.({
|
|
385
484
|
value: ctx.value,
|
|
386
|
-
|
|
485
|
+
valueAsString: ctx.valueAsString,
|
|
387
486
|
})
|
|
388
487
|
},
|
|
389
488
|
change(ctx: MachineContext) {
|
|
390
489
|
ctx.onValueChange?.({
|
|
391
490
|
value: ctx.value,
|
|
392
|
-
|
|
491
|
+
valueAsString: ctx.valueAsString,
|
|
393
492
|
})
|
|
493
|
+
|
|
494
|
+
dispatchInputValueEvent(dom.getHiddenInputEl(ctx), { value: ctx.valueAsString })
|
|
394
495
|
},
|
|
395
496
|
}
|
|
396
497
|
|
|
397
498
|
const set = {
|
|
398
|
-
value(ctx: MachineContext, color: Color | ColorType) {
|
|
399
|
-
|
|
400
|
-
ctx.value
|
|
499
|
+
value(ctx: MachineContext, color: Color | ColorType | undefined) {
|
|
500
|
+
sync.inputs(ctx)
|
|
501
|
+
if (!color || ctx.value.isEqual(color)) return
|
|
502
|
+
ctx.value = ref(color) as Color
|
|
401
503
|
invoke.change(ctx)
|
|
402
504
|
},
|
|
403
505
|
}
|