@zag-js/color-picker 0.23.0 → 0.25.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.js CHANGED
@@ -22,46 +22,61 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  anatomy: () => anatomy,
24
24
  connect: () => connect,
25
- machine: () => machine
25
+ machine: () => machine,
26
+ parse: () => parse
26
27
  });
27
28
  module.exports = __toCommonJS(src_exports);
28
29
 
29
30
  // src/color-picker.anatomy.ts
30
31
  var import_anatomy = require("@zag-js/anatomy");
31
32
  var anatomy = (0, import_anatomy.createAnatomy)("color-picker", [
33
+ "root",
34
+ "label",
35
+ "control",
36
+ "trigger",
37
+ "positioner",
38
+ "content",
32
39
  "area",
33
40
  "areaThumb",
34
- "areaGradient",
41
+ "areaBackground",
42
+ "channelSlider",
35
43
  "channelSliderTrack",
36
- "channelSliderTrackBackground",
37
44
  "channelSliderThumb",
38
45
  "channelInput",
46
+ "transparencyGrid",
47
+ "swatchGroup",
48
+ "swatchTrigger",
39
49
  "swatch",
40
- "swatchBackground",
41
- "content",
42
- "label",
43
50
  "eyeDropperTrigger"
44
51
  ]);
45
52
  var parts = anatomy.build();
46
53
 
47
54
  // src/color-picker.connect.ts
48
- var import_color_utils2 = require("@zag-js/color-utils");
55
+ var import_color_utils3 = require("@zag-js/color-utils");
49
56
  var import_dom_event2 = require("@zag-js/dom-event");
50
57
  var import_dom_query2 = require("@zag-js/dom-query");
58
+ var import_popper = require("@zag-js/popper");
51
59
  var import_visually_hidden = require("@zag-js/visually-hidden");
52
60
 
53
61
  // src/color-picker.dom.ts
54
62
  var import_dom_event = require("@zag-js/dom-event");
55
63
  var import_dom_query = require("@zag-js/dom-query");
64
+ var import_tabbable = require("@zag-js/tabbable");
65
+ var import_utils = require("@zag-js/utils");
56
66
  var dom = (0, import_dom_query.createScope)({
67
+ getRootId: (ctx) => ctx.ids?.root ?? `color-picker:${ctx.id}`,
68
+ getLabelId: (ctx) => ctx.ids?.label ?? `color-picker:${ctx.id}:label`,
69
+ getHiddenInputId: (ctx) => `color-picker:${ctx.id}:hidden-input`,
70
+ getControlId: (ctx) => ctx.ids?.control ?? `color-picker:${ctx.id}:control`,
71
+ getTriggerId: (ctx) => ctx.ids?.trigger ?? `color-picker:${ctx.id}:trigger`,
57
72
  getContentId: (ctx) => ctx.ids?.content ?? `color-picker:${ctx.id}:content`,
73
+ getPositionerId: (ctx) => `color-picker:${ctx.id}:positioner`,
58
74
  getAreaId: (ctx) => ctx.ids?.area ?? `color-picker:${ctx.id}:area`,
59
75
  getAreaGradientId: (ctx) => ctx.ids?.areaGradient ?? `color-picker:${ctx.id}:area-gradient`,
60
76
  getAreaThumbId: (ctx) => ctx.ids?.areaThumb ?? `color-picker:${ctx.id}:area-thumb`,
61
- getChannelSliderTrackId: (ctx, channel) => ctx.ids?.channelSliderTrack?.(channel) ?? `color-picker:${ctx.id}:slider-track:${channel}`,
77
+ getChannelSliderId: (ctx, channel) => ctx.ids?.channelSliderTrack?.(channel) ?? `color-picker:${ctx.id}:slider-track:${channel}`,
62
78
  getChannelInputId: (ctx, channel) => ctx.ids?.channelInput?.(channel) ?? `color-picker:${ctx.id}:input:${channel}`,
63
79
  getChannelSliderThumbId: (ctx, channel) => ctx.ids?.channelSliderThumb?.(channel) ?? `color-picker:${ctx.id}:slider-thumb:${channel}`,
64
- getHiddenInputId: (ctx) => `color-picker:${ctx.id}:hidden-input`,
65
80
  getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
66
81
  getAreaThumbEl: (ctx) => dom.getById(ctx, dom.getAreaThumbId(ctx)),
67
82
  getChannelSliderThumbEl: (ctx, channel) => dom.getById(ctx, dom.getChannelSliderThumbId(ctx, channel)),
@@ -75,8 +90,11 @@ var dom = (0, import_dom_query.createScope)({
75
90
  const { percent } = (0, import_dom_event.getRelativePoint)(point, areaEl);
76
91
  return percent;
77
92
  },
93
+ getControlEl: (ctx) => dom.getById(ctx, dom.getControlId(ctx)),
94
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
95
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
78
96
  getChannelSliderTrackEl: (ctx, channel) => {
79
- return dom.getById(ctx, dom.getChannelSliderTrackId(ctx, channel));
97
+ return dom.getById(ctx, dom.getChannelSliderId(ctx, channel));
80
98
  },
81
99
  getChannelSliderValueFromPoint(ctx, point, channel) {
82
100
  const trackEl = dom.getChannelSliderTrackEl(ctx, channel);
@@ -86,62 +104,22 @@ var dom = (0, import_dom_query.createScope)({
86
104
  return percent;
87
105
  },
88
106
  getChannelInputEls: (ctx) => {
89
- return (0, import_dom_query.queryAll)(dom.getContentEl(ctx), "input[data-channel]");
107
+ return [
108
+ ...(0, import_dom_query.queryAll)(dom.getContentEl(ctx), "input[data-channel]"),
109
+ ...(0, import_dom_query.queryAll)(dom.getControlEl(ctx), "input[data-channel]")
110
+ ];
111
+ },
112
+ getFirstFocusableEl: (ctx) => (0, import_tabbable.getFirstFocusable)(dom.getContentEl(ctx), "if-empty"),
113
+ getInitialFocusEl: (ctx) => {
114
+ let el = (0, import_utils.runIfFn)(ctx.initialFocusEl);
115
+ if (!el && ctx.autoFocus)
116
+ el = dom.getFirstFocusableEl(ctx);
117
+ if (!el)
118
+ el = dom.getContentEl(ctx);
119
+ return el;
90
120
  }
91
121
  });
92
122
 
93
- // src/utils/get-channel-details.ts
94
- var import_numeric_range = require("@zag-js/numeric-range");
95
- function getChannelDetails(color, xChannel, yChannel) {
96
- const channels = color.getColorSpaceAxes({ xChannel, yChannel });
97
- const xChannelRange = color.getChannelRange(channels.xChannel);
98
- const yChannelRange = color.getChannelRange(channels.yChannel);
99
- const { minValue: minValueX, maxValue: maxValueX, step: stepX, pageSize: pageSizeX } = xChannelRange;
100
- const { minValue: minValueY, maxValue: maxValueY, step: stepY, pageSize: pageSizeY } = yChannelRange;
101
- const xValue = color.getChannelValue(channels.xChannel);
102
- const yValue = color.getChannelValue(channels.yChannel);
103
- return {
104
- channels,
105
- xChannelStep: stepX,
106
- yChannelStep: stepY,
107
- xChannelPageStep: pageSizeX,
108
- yChannelPageStep: pageSizeY,
109
- xValue,
110
- yValue,
111
- getThumbPosition() {
112
- let x = (xValue - minValueX) / (maxValueX - minValueX);
113
- let y = 1 - (yValue - minValueY) / (maxValueY - minValueY);
114
- return { x, y };
115
- },
116
- incrementX(stepSize) {
117
- return xValue + stepSize > maxValueX ? maxValueX : (0, import_numeric_range.snapValueToStep)(xValue + stepSize, minValueX, maxValueX, stepX);
118
- },
119
- incrementY(stepSize) {
120
- return yValue + stepSize > maxValueY ? maxValueY : (0, import_numeric_range.snapValueToStep)(yValue + stepSize, minValueY, maxValueY, stepY);
121
- },
122
- decrementX(stepSize) {
123
- return (0, import_numeric_range.snapValueToStep)(xValue - stepSize, minValueX, maxValueX, stepX);
124
- },
125
- decrementY(stepSize) {
126
- return (0, import_numeric_range.snapValueToStep)(yValue - stepSize, minValueY, maxValueY, stepY);
127
- },
128
- getColorFromPoint(x, y) {
129
- let newXValue = (0, import_numeric_range.getPercentValue)(x, minValueX, maxValueX, stepX);
130
- let newYValue = (0, import_numeric_range.getPercentValue)(1 - y, minValueY, maxValueY, stepY);
131
- let newColor;
132
- if (newXValue !== xValue) {
133
- newXValue = (0, import_numeric_range.snapValueToStep)(newXValue, minValueX, maxValueX, stepX);
134
- newColor = color.withChannelValue(channels.xChannel, newXValue);
135
- }
136
- if (newYValue !== yValue) {
137
- newYValue = (0, import_numeric_range.snapValueToStep)(newYValue, minValueY, maxValueY, stepY);
138
- newColor = (newColor || color).withChannelValue(channels.yChannel, newYValue);
139
- }
140
- return newColor;
141
- }
142
- };
143
- }
144
-
145
123
  // src/utils/get-channel-display-color.ts
146
124
  var import_color_utils = require("@zag-js/color-utils");
147
125
  function getChannelDisplayColor(color, channel) {
@@ -164,31 +142,48 @@ function getChannelDisplayColor(color, channel) {
164
142
  }
165
143
 
166
144
  // src/utils/get-channel-input-value.ts
167
- function getChannelInputValue(color, channel) {
145
+ var import_color_utils2 = require("@zag-js/color-utils");
146
+ function getChannelValue(color, channel) {
168
147
  if (channel == null)
169
- return;
148
+ return "";
149
+ if (channel === "hex") {
150
+ return color.toString("hex");
151
+ }
152
+ if (channel === "css") {
153
+ return color.toString("css");
154
+ }
155
+ if (channel in color) {
156
+ return color.getChannelValue(channel).toString();
157
+ }
158
+ const isHSL = color.getFormat() === "hsl";
170
159
  switch (channel) {
171
- case "hex":
172
- return color.toString("hex");
173
- case "css":
174
- return color.toString("css");
175
160
  case "hue":
161
+ return isHSL ? color.toFormat("hsla").getChannelValue("hue").toString() : color.toFormat("hsba").getChannelValue("hue").toString();
176
162
  case "saturation":
163
+ return isHSL ? color.toFormat("hsl").getChannelValue("saturation").toString() : color.toFormat("hsb").getChannelValue("saturation").toString();
177
164
  case "lightness":
178
- return color.toFormat("hsl").getChannelValue("lightness").toString();
165
+ return color.toFormat("hsla").getChannelValue("lightness").toString();
179
166
  case "brightness":
180
- return color.toFormat("hsb").getChannelValue("brightness").toString();
167
+ return color.toFormat("hsba").getChannelValue("brightness").toString();
181
168
  case "red":
182
169
  case "green":
183
170
  case "blue":
184
- return color.toFormat("rgb").getChannelValue(channel).toString();
171
+ return color.toFormat("rgba").getChannelValue(channel).toString();
185
172
  default:
186
173
  return color.getChannelValue(channel).toString();
187
174
  }
188
175
  }
189
- function getChannelInputRange(color, channel) {
176
+ function getChannelRange(color, channel) {
190
177
  switch (channel) {
191
178
  case "hex":
179
+ const minColor = (0, import_color_utils2.parseColor)("#000000");
180
+ const maxColor = (0, import_color_utils2.parseColor)("#FFFFFF");
181
+ return {
182
+ minValue: minColor.toHexInt(),
183
+ maxValue: maxColor.toHexInt(),
184
+ pageSize: 10,
185
+ step: 1
186
+ };
192
187
  case "css":
193
188
  return void 0;
194
189
  case "hue":
@@ -207,7 +202,7 @@ function getChannelInputRange(color, channel) {
207
202
  }
208
203
 
209
204
  // src/utils/get-slider-background.ts
210
- function getSliderBgDirection(orientation, dir) {
205
+ function getSliderBackgroundDirection(orientation, dir) {
211
206
  if (orientation === "vertical") {
212
207
  return "top";
213
208
  } else if (dir === "ltr") {
@@ -216,19 +211,18 @@ function getSliderBgDirection(orientation, dir) {
216
211
  return "left";
217
212
  }
218
213
  }
219
- var getSliderBgImage = (ctx, props) => {
220
- const { channel } = props;
221
- const dir = getSliderBgDirection(props.orientation, ctx.dir);
222
- const value = ctx.valueAsColor;
223
- const { minValue, maxValue } = ctx.valueAsColor.getChannelRange(channel);
214
+ var getSliderBackground = (props) => {
215
+ const { channel, value, dir } = props;
216
+ const bgDirection = getSliderBackgroundDirection(props.orientation, dir);
217
+ const { minValue, maxValue } = value.getChannelRange(channel);
224
218
  switch (channel) {
225
219
  case "hue":
226
- return `linear-gradient(to ${dir}, 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%)`;
220
+ 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%)`;
227
221
  case "lightness": {
228
- let start = ctx.valueAsColor.withChannelValue(channel, minValue).toString("css");
222
+ let start = value.withChannelValue(channel, minValue).toString("css");
229
223
  let middle = value.withChannelValue(channel, (maxValue - minValue) / 2).toString("css");
230
224
  let end = value.withChannelValue(channel, maxValue).toString("css");
231
- return `linear-gradient(to ${dir}, ${start}, ${middle}, ${end})`;
225
+ return `linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`;
232
226
  }
233
227
  case "saturation":
234
228
  case "brightness":
@@ -238,7 +232,7 @@ var getSliderBgImage = (ctx, props) => {
238
232
  case "alpha": {
239
233
  let start = value.withChannelValue(channel, minValue).toString("css");
240
234
  let end = value.withChannelValue(channel, maxValue).toString("css");
241
- return `linear-gradient(to ${dir}, ${start}, ${end})`;
235
+ return `linear-gradient(to ${bgDirection}, ${start}, ${end})`;
242
236
  }
243
237
  default:
244
238
  throw new Error("Unknown color channel: " + channel);
@@ -247,41 +241,113 @@ var getSliderBgImage = (ctx, props) => {
247
241
 
248
242
  // src/color-picker.connect.ts
249
243
  function connect(state, send, normalize) {
250
- const valueAsColor = state.context.valueAsColor;
251
244
  const value = state.context.value;
245
+ const valueAsString = state.context.valueAsString;
252
246
  const isDisabled = state.context.isDisabled;
253
247
  const isInteractive = state.context.isInteractive;
254
- const isDragging = state.matches("dragging");
255
- const channels = valueAsColor.getColorChannels();
248
+ const isDragging = state.hasTag("dragging");
249
+ const isOpen = state.hasTag("open");
250
+ const channels = value.getChannels();
251
+ const getAreaChannels = (props) => {
252
+ const channels2 = value.getChannels();
253
+ return {
254
+ xChannel: props.xChannel ?? channels2[1],
255
+ yChannel: props.yChannel ?? channels2[2]
256
+ };
257
+ };
258
+ const currentPlacement = state.context.currentPlacement;
259
+ const popperStyles = (0, import_popper.getPlacementStyles)({
260
+ ...state.context.positioning,
261
+ placement: currentPlacement
262
+ });
256
263
  return {
257
264
  isDragging,
265
+ isOpen,
266
+ valueAsString,
258
267
  value,
259
- valueAsColor,
260
- alpha: valueAsColor.getChannelValue("alpha"),
261
268
  channels,
262
269
  setColor(value2) {
263
- send({ type: "VALUE.SET", value: (0, import_color_utils2.normalizeColor)(value2), src: "set-color" });
270
+ send({ type: "VALUE.SET", value: (0, import_color_utils3.normalizeColor)(value2), src: "set-color" });
271
+ },
272
+ getChannelValue(channel) {
273
+ return getChannelValue(value, channel);
264
274
  },
265
- setChannelValue(channel, value2) {
266
- const color = valueAsColor.withChannelValue(channel, value2);
275
+ setChannelValue(channel, channelValue) {
276
+ const color = value.withChannelValue(channel, channelValue);
267
277
  send({ type: "VALUE.SET", value: color, src: "set-channel" });
268
278
  },
279
+ format: value.outputFormat ?? value.getFormat(),
269
280
  setFormat(format) {
270
- const value2 = valueAsColor.toFormat(format);
271
- send({ type: "VALUE.SET", value: value2, src: "set-format" });
281
+ const formatValue = value.toFormat(format);
282
+ send({ type: "VALUE.SET", value: formatValue, src: "set-format" });
272
283
  },
273
- setAlpha(value2) {
274
- const color = valueAsColor.withChannelValue("alpha", value2);
284
+ alpha: value.getChannelValue("alpha"),
285
+ setAlpha(alphaValue) {
286
+ const color = value.withChannelValue("alpha", alphaValue);
275
287
  send({ type: "VALUE.SET", value: color, src: "set-alpha" });
276
288
  },
289
+ rootProps: normalize.element({
290
+ ...parts.root.attrs,
291
+ dir: state.context.dir,
292
+ id: dom.getRootId(state.context),
293
+ "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
294
+ "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly),
295
+ style: {
296
+ "--value": value.toString("css")
297
+ }
298
+ }),
299
+ labelProps: normalize.element({
300
+ ...parts.label.attrs,
301
+ dir: state.context.dir,
302
+ id: dom.getLabelId(state.context),
303
+ htmlFor: dom.getHiddenInputId(state.context),
304
+ "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
305
+ "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly),
306
+ onClick(event) {
307
+ event.preventDefault();
308
+ const inputEl = (0, import_dom_query2.query)(dom.getControlEl(state.context), "[data-channel=hex]");
309
+ inputEl?.focus({ preventScroll: true });
310
+ }
311
+ }),
312
+ controlProps: normalize.element({
313
+ ...parts.control.attrs,
314
+ id: dom.getControlId(state.context),
315
+ dir: state.context.dir,
316
+ "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
317
+ "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly)
318
+ }),
319
+ triggerProps: normalize.button({
320
+ ...parts.trigger.attrs,
321
+ id: dom.getTriggerId(state.context),
322
+ dir: state.context.dir,
323
+ "aria-labelledby": dom.getLabelId(state.context),
324
+ "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
325
+ "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly),
326
+ "data-placement": currentPlacement,
327
+ type: "button",
328
+ onClick() {
329
+ send({ type: "TRIGGER.CLICK" });
330
+ },
331
+ style: {
332
+ position: "relative"
333
+ }
334
+ }),
335
+ positionerProps: normalize.element({
336
+ ...parts.positioner.attrs,
337
+ id: dom.getPositionerId(state.context),
338
+ dir: state.context.dir,
339
+ style: popperStyles.floating
340
+ }),
277
341
  contentProps: normalize.element({
278
342
  ...parts.content.attrs,
279
343
  id: dom.getContentId(state.context),
280
- dir: state.context.dir
344
+ dir: state.context.dir,
345
+ "data-placement": currentPlacement,
346
+ hidden: !isOpen
281
347
  }),
282
- getAreaProps(props) {
283
- const { xChannel, yChannel } = props;
284
- const { areaStyles } = (0, import_color_utils2.getColorAreaGradient)(state.context.valueAsColor, {
348
+ getAreaProps(props = {}) {
349
+ const { xChannel, yChannel } = getAreaChannels(props);
350
+ const { areaStyles } = (0, import_color_utils3.getColorAreaGradient)(value, {
285
351
  xChannel,
286
352
  yChannel,
287
353
  dir: state.context.dir
@@ -299,6 +365,7 @@ function connect(state, send, normalize) {
299
365
  const point = (0, import_dom_event2.getEventPoint)(evt);
300
366
  const channel = { xChannel, yChannel };
301
367
  send({ type: "AREA.POINTER_DOWN", point, channel, id: "area" });
368
+ event.preventDefault();
302
369
  },
303
370
  style: {
304
371
  position: "relative",
@@ -308,15 +375,15 @@ function connect(state, send, normalize) {
308
375
  }
309
376
  });
310
377
  },
311
- getAreaGradientProps(props) {
312
- const { xChannel, yChannel } = props;
313
- const { areaGradientStyles } = (0, import_color_utils2.getColorAreaGradient)(valueAsColor, {
378
+ getAreaBackgroundProps(props = {}) {
379
+ const { xChannel, yChannel } = getAreaChannels(props);
380
+ const { areaGradientStyles } = (0, import_color_utils3.getColorAreaGradient)(value, {
314
381
  xChannel,
315
382
  yChannel,
316
383
  dir: state.context.dir
317
384
  });
318
385
  return normalize.element({
319
- ...parts.areaGradient.attrs,
386
+ ...parts.areaBackground.attrs,
320
387
  id: dom.getAreaGradientId(state.context),
321
388
  style: {
322
389
  position: "relative",
@@ -326,14 +393,15 @@ function connect(state, send, normalize) {
326
393
  }
327
394
  });
328
395
  },
329
- getAreaThumbProps(props) {
330
- const { xChannel, yChannel } = props;
331
- const { getThumbPosition } = getChannelDetails(valueAsColor, xChannel, yChannel);
332
- const { x, y } = getThumbPosition();
396
+ getAreaThumbProps(props = {}) {
397
+ const { xChannel, yChannel } = getAreaChannels(props);
333
398
  const channel = { xChannel, yChannel };
399
+ const x = value.getChannelValuePercent(xChannel);
400
+ const y = 1 - value.getChannelValuePercent(yChannel);
334
401
  return normalize.element({
335
402
  ...parts.areaThumb.attrs,
336
403
  id: dom.getAreaThumbId(state.context),
404
+ dir: state.context.dir,
337
405
  tabIndex: isDisabled ? void 0 : 0,
338
406
  "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
339
407
  role: "presentation",
@@ -344,13 +412,10 @@ function connect(state, send, normalize) {
344
412
  transform: "translate(-50%, -50%)",
345
413
  touchAction: "none",
346
414
  forcedColorAdjust: "none",
347
- background: valueAsColor.withChannelValue("alpha", 1).toString("css")
348
- },
349
- onBlur() {
350
- send("AREA.BLUR");
415
+ background: value.withChannelValue("alpha", 1).toString("css")
351
416
  },
352
417
  onFocus() {
353
- send({ type: "AREA.FOCUS", id: "area" });
418
+ send({ type: "AREA.FOCUS", id: "area", channel });
354
419
  },
355
420
  onKeyDown(event) {
356
421
  if (!isInteractive)
@@ -374,6 +439,9 @@ function connect(state, send, normalize) {
374
439
  },
375
440
  PageDown() {
376
441
  send({ type: "AREA.PAGE_DOWN", channel, step });
442
+ },
443
+ Escape(event2) {
444
+ event2.stopPropagation();
377
445
  }
378
446
  };
379
447
  const exec = keyMap[(0, import_dom_event2.getEventKey)(event, state.context)];
@@ -384,14 +452,31 @@ function connect(state, send, normalize) {
384
452
  }
385
453
  });
386
454
  },
387
- getChannelSliderTrackProps(props) {
455
+ getTransparencyGridProps(props = {}) {
456
+ const { size = "12px" } = props;
457
+ return normalize.element({
458
+ ...parts.transparencyGrid.attrs,
459
+ style: {
460
+ "--size": size,
461
+ width: "100%",
462
+ height: "100%",
463
+ position: "absolute",
464
+ backgroundColor: "#fff",
465
+ backgroundImage: "conic-gradient(#eeeeee 0 25%, transparent 0 50%, #eeeeee 0 75%, transparent 0)",
466
+ backgroundSize: "var(--size) var(--size)",
467
+ inset: "0px",
468
+ zIndex: "auto",
469
+ pointerEvents: "none"
470
+ }
471
+ });
472
+ },
473
+ getChannelSliderProps(props) {
388
474
  const { orientation = "horizontal", channel } = props;
389
475
  return normalize.element({
390
- ...parts.channelSliderTrack.attrs,
391
- id: dom.getChannelSliderTrackId(state.context, channel),
392
- role: "group",
476
+ ...parts.channelSlider.attrs,
393
477
  "data-channel": channel,
394
478
  "data-orientation": orientation,
479
+ role: "presentation",
395
480
  onPointerDown(event) {
396
481
  if (!isInteractive)
397
482
  return;
@@ -400,41 +485,38 @@ function connect(state, send, normalize) {
400
485
  return;
401
486
  const point = (0, import_dom_event2.getEventPoint)(evt);
402
487
  send({ type: "CHANNEL_SLIDER.POINTER_DOWN", channel, point, id: channel, orientation });
488
+ event.preventDefault();
403
489
  },
404
490
  style: {
405
491
  position: "relative",
406
- touchAction: "none",
407
- forcedColorAdjust: "none",
408
- backgroundImage: getSliderBgImage(state.context, { orientation, channel })
492
+ touchAction: "none"
409
493
  }
410
494
  });
411
495
  },
412
- getChannelSliderBackgroundProps(props) {
496
+ getChannelSliderTrackProps(props) {
413
497
  const { orientation = "horizontal", channel } = props;
414
498
  return normalize.element({
415
- ...parts.channelSliderTrackBackground.attrs,
416
- "data-orientation": orientation,
499
+ ...parts.channelSliderTrack.attrs,
500
+ id: dom.getChannelSliderId(state.context, channel),
501
+ role: "group",
417
502
  "data-channel": channel,
503
+ "data-orientation": orientation,
418
504
  style: {
419
- position: "absolute",
420
- backgroundColor: "#fff",
421
- backgroundImage: [
422
- "linear-gradient(-45deg,#0000 75.5%,#bcbcbc 75.5%)",
423
- "linear-gradient(45deg,#0000 75.5%,#bcbcbc 75.5%)",
424
- "linear-gradient(-45deg,#bcbcbc 25.5%,#0000 25.5%)",
425
- "linear-gradient(45deg,#bcbcbc 25.5%,#0000 25.5%)"
426
- ].join(","),
427
- backgroundSize: "16px 16px",
428
- backgroundPosition: "-2px -2px,-2px 6px,6px -10px,-10px -2px",
429
- inset: 0,
430
- zIndex: -1
505
+ position: "relative",
506
+ forcedColorAdjust: "none",
507
+ backgroundImage: getSliderBackground({
508
+ orientation,
509
+ channel,
510
+ dir: state.context.dir,
511
+ value
512
+ })
431
513
  }
432
514
  });
433
515
  },
434
516
  getChannelSliderThumbProps(props) {
435
517
  const { orientation = "horizontal", channel } = props;
436
- const { minValue, maxValue, step: stepValue } = valueAsColor.getChannelRange(channel);
437
- const channelValue = valueAsColor.getChannelValue(channel);
518
+ const { minValue, maxValue, step: stepValue } = value.getChannelRange(channel);
519
+ const channelValue = value.getChannelValue(channel);
438
520
  const offset = (channelValue - minValue) / (maxValue - minValue);
439
521
  const placementStyles = orientation === "horizontal" ? { left: `${offset * 100}%`, top: "50%" } : { top: `${offset * 100}%`, left: "50%" };
440
522
  return normalize.element({
@@ -454,7 +536,7 @@ function connect(state, send, normalize) {
454
536
  style: {
455
537
  forcedColorAdjust: "none",
456
538
  position: "absolute",
457
- background: getChannelDisplayColor(valueAsColor, channel).toString("css"),
539
+ background: getChannelDisplayColor(value, channel).toString("css"),
458
540
  ...placementStyles
459
541
  },
460
542
  onFocus() {
@@ -462,11 +544,6 @@ function connect(state, send, normalize) {
462
544
  return;
463
545
  send({ type: "CHANNEL_SLIDER.FOCUS", channel });
464
546
  },
465
- onBlur() {
466
- if (!isInteractive)
467
- return;
468
- send({ type: "CHANNEL_SLIDER.BLUR", channel });
469
- },
470
547
  onKeyDown(event) {
471
548
  if (!isInteractive)
472
549
  return;
@@ -495,6 +572,9 @@ function connect(state, send, normalize) {
495
572
  },
496
573
  End() {
497
574
  send({ type: "CHANNEL_SLIDER.END", channel });
575
+ },
576
+ Escape(event2) {
577
+ event2.stopPropagation();
498
578
  }
499
579
  };
500
580
  const exec = keyMap[(0, import_dom_event2.getEventKey)(event, state.context)];
@@ -508,7 +588,7 @@ function connect(state, send, normalize) {
508
588
  getChannelInputProps(props) {
509
589
  const { channel } = props;
510
590
  const isTextField = channel === "hex" || channel === "css";
511
- const range = getChannelInputRange(valueAsColor, channel);
591
+ const range = getChannelRange(value, channel);
512
592
  return normalize.input({
513
593
  ...parts.channelInput.attrs,
514
594
  type: isTextField ? "text" : "number",
@@ -518,22 +598,31 @@ function connect(state, send, normalize) {
518
598
  "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
519
599
  readOnly: state.context.readOnly,
520
600
  id: dom.getChannelInputId(state.context, channel),
521
- defaultValue: getChannelInputValue(valueAsColor, channel),
601
+ defaultValue: getChannelValue(value, channel),
522
602
  min: range?.minValue,
523
603
  max: range?.maxValue,
524
604
  step: range?.step,
605
+ onBeforeInput(event) {
606
+ if (isTextField)
607
+ return;
608
+ const value2 = event.currentTarget.value;
609
+ if (value2.match(/[^0-9.]/g)) {
610
+ event.preventDefault();
611
+ }
612
+ },
525
613
  onFocus(event) {
526
614
  send({ type: "CHANNEL_INPUT.FOCUS", channel });
527
- (0, import_dom_query2.raf)(() => event.target.select());
615
+ event.target.select();
528
616
  },
529
617
  onBlur(event) {
530
- const value2 = event.currentTarget.value;
531
- send({ type: "CHANNEL_INPUT.CHANGE", channel, value: value2, isTextField });
618
+ const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
619
+ send({ type: "CHANNEL_INPUT.BLUR", channel, value: value2, isTextField });
532
620
  },
533
621
  onKeyDown(event) {
534
622
  if (event.key === "Enter") {
535
- const value2 = event.currentTarget.value;
623
+ const value2 = isTextField ? event.currentTarget.value : event.currentTarget.valueAsNumber;
536
624
  send({ type: "CHANNEL_INPUT.CHANGE", channel, value: value2, isTextField });
625
+ event.preventDefault();
537
626
  }
538
627
  },
539
628
  style: {
@@ -549,14 +638,11 @@ function connect(state, send, normalize) {
549
638
  name: state.context.name,
550
639
  id: dom.getHiddenInputId(state.context),
551
640
  style: import_visually_hidden.visuallyHiddenStyle,
552
- defaultValue: value,
553
- onChange(event) {
554
- const value2 = event.currentTarget.value;
555
- send({ type: "VALUE.SET", value: value2, src: "input.change" });
556
- }
641
+ defaultValue: valueAsString
557
642
  }),
558
643
  eyeDropperTriggerProps: normalize.button({
559
644
  ...parts.eyeDropperTrigger.attrs,
645
+ type: "button",
560
646
  disabled: isDisabled,
561
647
  "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
562
648
  "aria-label": "Pick a color from the screen",
@@ -566,43 +652,39 @@ function connect(state, send, normalize) {
566
652
  send("EYEDROPPER.CLICK");
567
653
  }
568
654
  }),
569
- getSwatchBackgroundProps(props) {
570
- const { value: value2 } = props;
571
- const alpha = (0, import_color_utils2.normalizeColor)(value2).getChannelValue("alpha");
572
- return normalize.element({
573
- ...parts.swatchBackground.attrs,
574
- "data-alpha": alpha,
655
+ swatchGroupProps: normalize.element({
656
+ ...parts.swatchGroup.attrs,
657
+ role: "group"
658
+ }),
659
+ getSwatchTriggerProps(props) {
660
+ const { value: valueProp } = props;
661
+ const color = (0, import_color_utils3.normalizeColor)(valueProp).toFormat(value.getFormat());
662
+ return normalize.button({
663
+ ...parts.swatchTrigger.attrs,
664
+ disabled: isDisabled,
665
+ type: "button",
666
+ "data-value": color.toString("hex"),
667
+ onClick() {
668
+ if (!isInteractive)
669
+ return;
670
+ send({ type: "VALUE.SET", value: color });
671
+ },
575
672
  style: {
576
- width: "100%",
577
- height: "100%",
578
- background: "#fff",
579
- backgroundImage: [
580
- "linear-gradient(-45deg,#0000 75.5%,#bcbcbc 75.5%)",
581
- "linear-gradient(45deg,#0000 75.5%,#bcbcbc 75.5%)",
582
- "linear-gradient(-45deg,#bcbcbc 25.5%,#0000 25.5%)",
583
- "linear-gradient(45deg,#bcbcbc 25.5%,#0000 25.5%)"
584
- ].join(","),
585
- backgroundPosition: "-2px -2px,-2px 6px,6px -10px,-10px -2px",
586
- backgroundSize: "16px 16px",
587
- position: "absolute",
588
- inset: "0px",
589
- zIndex: -1
673
+ position: "relative"
590
674
  }
591
675
  });
592
676
  },
593
677
  getSwatchProps(props) {
594
- const { value: value2, readOnly } = props;
595
- const color = (0, import_color_utils2.normalizeColor)(value2).toFormat(valueAsColor.getColorFormat());
678
+ const { value: valueProp, respectAlpha = true } = props;
679
+ const colorValue = (0, import_color_utils3.normalizeColor)(valueProp);
680
+ const color = colorValue.toFormat(value.getFormat());
596
681
  return normalize.element({
597
682
  ...parts.swatch.attrs,
598
- onClick() {
599
- if (readOnly || !isInteractive)
600
- return;
601
- send({ type: "VALUE.SET", value: color });
602
- },
683
+ "data-state": colorValue.isEqual(value) ? "selected" : "unselected",
684
+ "data-value": color.toString("hex"),
603
685
  style: {
604
686
  position: "relative",
605
- background: color.toString("css")
687
+ background: color.toString(respectAlpha ? "css" : "hex")
606
688
  }
607
689
  });
608
690
  }
@@ -610,86 +692,145 @@ function connect(state, send, normalize) {
610
692
  }
611
693
 
612
694
  // src/color-picker.machine.ts
613
- var import_color_utils3 = require("@zag-js/color-utils");
614
- var import_core = require("@zag-js/core");
695
+ var import_color_utils5 = require("@zag-js/color-utils");
696
+ var import_core2 = require("@zag-js/core");
697
+ var import_dismissable = require("@zag-js/dismissable");
615
698
  var import_dom_event3 = require("@zag-js/dom-event");
616
699
  var import_dom_query3 = require("@zag-js/dom-query");
617
700
  var import_form_utils = require("@zag-js/form-utils");
618
- var import_numeric_range2 = require("@zag-js/numeric-range");
701
+ var import_popper2 = require("@zag-js/popper");
619
702
  var import_text_selection = require("@zag-js/text-selection");
620
- var import_utils = require("@zag-js/utils");
703
+ var import_utils2 = require("@zag-js/utils");
704
+
705
+ // src/color-picker.parse.ts
706
+ var import_color_utils4 = require("@zag-js/color-utils");
707
+ var import_core = require("@zag-js/core");
708
+ var parse = (color) => {
709
+ const value = (0, import_color_utils4.parseColor)(color);
710
+ const colorFormat = value.getFormat();
711
+ const lockedFormat = colorFormat.startsWith("hsl") ? "hsla" : "hsba";
712
+ const result = value.toFormat(lockedFormat);
713
+ result.outputFormat = colorFormat;
714
+ return (0, import_core.ref)(result);
715
+ };
716
+
717
+ // src/color-picker.machine.ts
718
+ var { stateIn } = import_core2.guards;
621
719
  function machine(userContext) {
622
- const ctx = (0, import_utils.compact)(userContext);
623
- return (0, import_core.createMachine)(
720
+ const ctx = (0, import_utils2.compact)(userContext);
721
+ return (0, import_core2.createMachine)(
624
722
  {
625
723
  id: "color-picker",
626
- initial: "idle",
724
+ initial: ctx.open ? "open" : "idle",
627
725
  context: {
628
726
  dir: "ltr",
629
- value: "#D9D9D9",
727
+ value: parse("#000000"),
630
728
  disabled: false,
631
729
  ...ctx,
632
730
  activeId: null,
633
731
  activeChannel: null,
634
732
  activeOrientation: null,
635
- fieldsetDisabled: false
733
+ fieldsetDisabled: false,
734
+ autoFocus: true,
735
+ positioning: {
736
+ ...ctx.positioning,
737
+ placement: "bottom"
738
+ }
636
739
  },
637
740
  computed: {
638
741
  isRtl: (ctx2) => ctx2.dir === "rtl",
639
742
  isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
640
743
  isInteractive: (ctx2) => !(ctx2.isDisabled || ctx2.readOnly),
641
- valueAsColor: (ctx2) => (0, import_color_utils3.parseColor)(ctx2.value)
744
+ valueAsString: (ctx2) => {
745
+ const color = ctx2.value.outputFormat ? ctx2.value.toFormat(ctx2.value.outputFormat) : ctx2.value;
746
+ return color.toString("css");
747
+ }
748
+ },
749
+ activities: ["trackFormControl"],
750
+ watch: {
751
+ valueAsString: ["syncInputElements"],
752
+ open: ["toggleVisibility"]
642
753
  },
643
754
  on: {
644
755
  "VALUE.SET": {
645
756
  actions: ["setValue"]
757
+ },
758
+ "CHANNEL_INPUT.FOCUS": [
759
+ {
760
+ guard: stateIn("idle"),
761
+ target: "focused",
762
+ actions: ["setActiveChannel"]
763
+ },
764
+ {
765
+ actions: ["setActiveChannel"]
766
+ }
767
+ ],
768
+ "CHANNEL_INPUT.BLUR": [
769
+ {
770
+ guard: stateIn("focused"),
771
+ target: "idle",
772
+ actions: ["setChannelColorFromInput"]
773
+ },
774
+ {
775
+ actions: ["setChannelColorFromInput"]
776
+ }
777
+ ],
778
+ "CHANNEL_INPUT.CHANGE": {
779
+ actions: ["setChannelColorFromInput"]
646
780
  }
647
781
  },
648
- activities: ["trackFormControl"],
649
- watch: {
650
- value: ["syncInputElements"]
651
- },
652
782
  states: {
653
783
  idle: {
784
+ tags: ["closed"],
785
+ on: {
786
+ OPEN: {
787
+ target: "open",
788
+ actions: ["setInitialFocus", "invokeOnOpen"]
789
+ },
790
+ "TRIGGER.CLICK": {
791
+ target: "open",
792
+ actions: ["setInitialFocus", "invokeOnOpen"]
793
+ }
794
+ }
795
+ },
796
+ focused: {
797
+ tags: ["closed", "focused"],
654
798
  on: {
799
+ OPEN: {
800
+ target: "open",
801
+ actions: ["setInitialFocus", "invokeOnOpen"]
802
+ },
803
+ "TRIGGER.CLICK": {
804
+ target: "open",
805
+ actions: ["setInitialFocus", "invokeOnOpen"]
806
+ }
807
+ }
808
+ },
809
+ open: {
810
+ tags: ["open"],
811
+ activities: ["trackPositioning", "trackDismissableElement"],
812
+ on: {
813
+ "TRIGGER.CLICK": {
814
+ target: "idle",
815
+ actions: ["invokeOnClose"]
816
+ },
655
817
  "EYEDROPPER.CLICK": {
656
818
  actions: ["openEyeDropper"]
657
819
  },
658
820
  "AREA.POINTER_DOWN": {
659
- target: "dragging",
821
+ target: "open:dragging",
660
822
  actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"]
661
823
  },
662
824
  "AREA.FOCUS": {
663
- target: "focused",
664
825
  actions: ["setActiveChannel"]
665
826
  },
666
827
  "CHANNEL_SLIDER.POINTER_DOWN": {
667
- target: "dragging",
828
+ target: "open:dragging",
668
829
  actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"]
669
830
  },
670
831
  "CHANNEL_SLIDER.FOCUS": {
671
- target: "focused",
672
832
  actions: ["setActiveChannel"]
673
833
  },
674
- "CHANNEL_INPUT.FOCUS": {
675
- target: "focused",
676
- actions: ["setActiveChannel"]
677
- },
678
- "CHANNEL_INPUT.CHANGE": {
679
- actions: ["setChannelColorFromInput"]
680
- }
681
- }
682
- },
683
- focused: {
684
- on: {
685
- "AREA.POINTER_DOWN": {
686
- target: "dragging",
687
- actions: ["setActiveChannel", "setAreaColorFromPoint", "focusAreaThumb"]
688
- },
689
- "CHANNEL_SLIDER.POINTER_DOWN": {
690
- target: "dragging",
691
- actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"]
692
- },
693
834
  "AREA.ARROW_LEFT": {
694
835
  actions: ["decrementXChannel"]
695
836
  },
@@ -732,44 +873,100 @@ function machine(userContext) {
732
873
  "CHANNEL_SLIDER.END": {
733
874
  actions: ["setChannelToMax"]
734
875
  },
735
- "CHANNEL_INPUT.FOCUS": {
736
- actions: ["setActiveChannel"]
737
- },
738
- "CHANNEL_INPUT.CHANGE": {
739
- actions: ["setChannelColorFromInput"]
740
- },
741
- "CHANNEL_SLIDER.BLUR": {
742
- target: "idle"
743
- },
744
- "AREA.BLUR": {
745
- target: "idle"
876
+ INTERACT_OUTSIDE: [
877
+ {
878
+ guard: "shouldRestoreFocus",
879
+ target: "focused",
880
+ actions: ["setReturnFocus", "invokeOnClose"]
881
+ },
882
+ {
883
+ target: "idle",
884
+ actions: ["invokeOnClose"]
885
+ }
886
+ ],
887
+ CLOSE: {
888
+ target: "idle",
889
+ actions: ["invokeOnClose"]
746
890
  }
747
891
  }
748
892
  },
749
- dragging: {
893
+ "open:dragging": {
894
+ tags: ["open"],
750
895
  exit: ["clearActiveChannel"],
751
- activities: ["trackPointerMove", "disableTextSelection"],
896
+ activities: ["trackPointerMove", "disableTextSelection", "trackPositioning", "trackDismissableElement"],
752
897
  on: {
753
898
  "AREA.POINTER_MOVE": {
754
- actions: ["setAreaColorFromPoint"]
899
+ actions: ["setAreaColorFromPoint", "focusAreaThumb"]
755
900
  },
756
901
  "AREA.POINTER_UP": {
757
- target: "focused",
902
+ target: "open",
758
903
  actions: ["invokeOnChangeEnd"]
759
904
  },
760
905
  "CHANNEL_SLIDER.POINTER_MOVE": {
761
- actions: ["setChannelColorFromPoint"]
906
+ actions: ["setChannelColorFromPoint", "focusChannelThumb"]
762
907
  },
763
908
  "CHANNEL_SLIDER.POINTER_UP": {
764
- target: "focused",
909
+ target: "open",
765
910
  actions: ["invokeOnChangeEnd"]
911
+ },
912
+ INTERACT_OUTSIDE: [
913
+ {
914
+ guard: "shouldRestoreFocus",
915
+ target: "focused",
916
+ actions: ["setReturnFocus", "invokeOnClose"]
917
+ },
918
+ {
919
+ target: "idle",
920
+ actions: ["invokeOnClose"]
921
+ }
922
+ ],
923
+ CLOSE: {
924
+ target: "idle",
925
+ actions: ["invokeOnClose"]
766
926
  }
767
927
  }
768
928
  }
769
929
  }
770
930
  },
771
931
  {
932
+ guards: {
933
+ isTargetFocusable: (_ctx, evt) => evt.restoreFocus
934
+ },
772
935
  activities: {
936
+ trackPositioning(ctx2) {
937
+ ctx2.currentPlacement = ctx2.positioning.placement;
938
+ const anchorEl = dom.getTriggerEl(ctx2);
939
+ const getPositionerEl = () => dom.getPositionerEl(ctx2);
940
+ return (0, import_popper2.getPlacement)(anchorEl, getPositionerEl, {
941
+ ...ctx2.positioning,
942
+ defer: true,
943
+ onComplete(data) {
944
+ ctx2.currentPlacement = data.placement;
945
+ },
946
+ onCleanup() {
947
+ ctx2.currentPlacement = void 0;
948
+ }
949
+ });
950
+ },
951
+ trackDismissableElement(ctx2, _evt, { send }) {
952
+ const getContentEl = () => dom.getContentEl(ctx2);
953
+ let restoreFocus = true;
954
+ return (0, import_dismissable.trackDismissableElement)(getContentEl, {
955
+ exclude: dom.getTriggerEl(ctx2),
956
+ defer: true,
957
+ onInteractOutside(event) {
958
+ ctx2.onInteractOutside?.(event);
959
+ if (event.defaultPrevented)
960
+ return;
961
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
962
+ },
963
+ onPointerDownOutside: ctx2.onPointerDownOutside,
964
+ onFocusOutside: ctx2.onFocusOutside,
965
+ onDismiss() {
966
+ send({ type: "INTERACT_OUTSIDE", restoreFocus });
967
+ }
968
+ });
969
+ },
773
970
  trackFormControl(ctx2, _evt, { send, initialContext }) {
774
971
  const inputEl = dom.getHiddenInputEl(ctx2);
775
972
  return (0, import_form_utils.trackFormControl)(inputEl, {
@@ -805,20 +1002,18 @@ function machine(userContext) {
805
1002
  const win = dom.getWin(ctx2);
806
1003
  const picker = new win.EyeDropper();
807
1004
  picker.open().then(({ sRGBHex }) => {
808
- const format = ctx2.valueAsColor.getColorFormat();
809
- const color = (0, import_color_utils3.parseColor)(sRGBHex).toFormat(format);
1005
+ const format = ctx2.value.getFormat();
1006
+ const color = (0, import_color_utils5.parseColor)(sRGBHex).toFormat(format);
810
1007
  set.value(ctx2, color);
811
- ctx2.onValueChangeEnd?.({ value: ctx2.value, valueAsColor: color });
1008
+ ctx2.onValueChangeEnd?.({ value: ctx2.value, valueAsString: ctx2.valueAsString });
812
1009
  }).catch(() => void 0);
813
1010
  },
814
1011
  setActiveChannel(ctx2, evt) {
815
1012
  ctx2.activeId = evt.id;
816
- if (evt.channel) {
1013
+ if (evt.channel)
817
1014
  ctx2.activeChannel = evt.channel;
818
- }
819
- if (evt.orientation) {
1015
+ if (evt.orientation)
820
1016
  ctx2.activeOrientation = evt.orientation;
821
- }
822
1017
  },
823
1018
  clearActiveChannel(ctx2) {
824
1019
  ctx2.activeChannel = null;
@@ -830,10 +1025,9 @@ function machine(userContext) {
830
1025
  const percent = dom.getAreaValueFromPoint(ctx2, evt.point);
831
1026
  if (!percent)
832
1027
  return;
833
- const { getColorFromPoint } = getChannelDetails(ctx2.valueAsColor, xChannel, yChannel);
834
- const color = getColorFromPoint(percent.x, percent.y);
835
- if (!color)
836
- return;
1028
+ const xValue = ctx2.value.getChannelPercentValue(xChannel, percent.x);
1029
+ const yValue = ctx2.value.getChannelPercentValue(yChannel, 1 - percent.y);
1030
+ const color = ctx2.value.withChannelValue(xChannel, xValue).withChannelValue(yChannel, yValue);
837
1031
  set.value(ctx2, color);
838
1032
  },
839
1033
  setChannelColorFromPoint(ctx2, evt) {
@@ -841,24 +1035,17 @@ function machine(userContext) {
841
1035
  const percent = dom.getChannelSliderValueFromPoint(ctx2, evt.point, channel);
842
1036
  if (!percent)
843
1037
  return;
844
- const { minValue, maxValue, step } = ctx2.valueAsColor.getChannelRange(channel);
845
1038
  const orientation = ctx2.activeOrientation || "horizontal";
846
- const point = orientation === "horizontal" ? percent.x : percent.y;
847
- const channelValue = (0, import_numeric_range2.getPercentValue)(point, minValue, maxValue, step);
848
- const value = (0, import_numeric_range2.snapValueToStep)(channelValue - step, minValue, maxValue, step);
849
- const newColor = ctx2.valueAsColor.withChannelValue(channel, value);
850
- set.value(ctx2, newColor);
1039
+ const channelPercent = orientation === "horizontal" ? percent.x : percent.y;
1040
+ const value = ctx2.value.getChannelPercentValue(channel, channelPercent);
1041
+ const color = ctx2.value.withChannelValue(channel, value);
1042
+ set.value(ctx2, color);
851
1043
  },
852
1044
  setValue(ctx2, evt) {
853
1045
  set.value(ctx2, evt.value);
854
1046
  },
855
1047
  syncInputElements(ctx2) {
856
- const inputs = dom.getChannelInputEls(ctx2);
857
- inputs.forEach((input) => {
858
- const channel = input.dataset.channel;
859
- dom.setValue(input, getChannelInputValue(ctx2.valueAsColor, channel));
860
- });
861
- dom.setValue(dom.getHiddenInputEl(ctx2), ctx2.value);
1048
+ sync.inputs(ctx2);
862
1049
  },
863
1050
  invokeOnChangeEnd(ctx2) {
864
1051
  invoke.changeEnd(ctx2);
@@ -866,106 +1053,134 @@ function machine(userContext) {
866
1053
  setChannelColorFromInput(ctx2, evt) {
867
1054
  const { channel, isTextField, value } = evt;
868
1055
  if (channel === "alpha") {
869
- const newColor2 = ctx2.valueAsColor.withChannelValue("alpha", value);
870
- set.value(ctx2, newColor2);
1056
+ const newColor = ctx2.value.withChannelValue("alpha", parseFloat(value));
1057
+ set.value(ctx2, newColor);
871
1058
  return;
872
1059
  }
873
1060
  if (isTextField) {
874
- const format = "hsl";
875
- const currentAlpha = ctx2.valueAsColor.getChannelValue("alpha");
876
- const newColor2 = (0, import_utils.tryCatch)(
877
- () => (0, import_color_utils3.parseColor)(value).toFormat(format).withChannelValue("alpha", currentAlpha),
878
- () => ctx2.valueAsColor
1061
+ const currentAlpha = ctx2.value.getChannelValue("alpha");
1062
+ const color2 = (0, import_utils2.tryCatch)(
1063
+ () => parse(value).withChannelValue("alpha", currentAlpha),
1064
+ () => ctx2.value
879
1065
  );
880
1066
  const inputEl = dom.getChannelInputEl(ctx2, channel);
881
- dom.setValue(inputEl, getChannelInputValue(ctx2.valueAsColor, channel));
882
- set.value(ctx2, newColor2);
1067
+ dom.setValue(inputEl, getChannelValue(color2, channel));
1068
+ set.value(ctx2, color2);
883
1069
  return;
884
1070
  }
885
- const newColor = ctx2.valueAsColor.withChannelValue(channel, value);
886
- set.value(ctx2, newColor);
1071
+ const color = ctx2.value.toFormat(ctx2.value.outputFormat).withChannelValue(channel, value);
1072
+ set.value(ctx2, color);
887
1073
  },
888
1074
  incrementChannel(ctx2, evt) {
889
- const { minValue, maxValue, step } = ctx2.valueAsColor.getChannelRange(evt.channel);
890
- const channelValue = ctx2.valueAsColor.getChannelValue(evt.channel);
891
- const value = (0, import_numeric_range2.snapValueToStep)(channelValue + evt.step, minValue, maxValue, step);
892
- const color = ctx2.valueAsColor.withChannelValue(evt.channel, (0, import_numeric_range2.clampValue)(value, minValue, maxValue));
1075
+ const color = ctx2.value.incrementChannel(evt.channel, evt.step);
893
1076
  set.value(ctx2, color);
894
1077
  },
895
1078
  decrementChannel(ctx2, evt) {
896
- const { minValue, maxValue, step } = ctx2.valueAsColor.getChannelRange(evt.channel);
897
- const channelValue = ctx2.valueAsColor.getChannelValue(evt.channel);
898
- const value = (0, import_numeric_range2.snapValueToStep)(channelValue - evt.step, minValue, maxValue, step);
899
- const color = ctx2.valueAsColor.withChannelValue(evt.channel, (0, import_numeric_range2.clampValue)(value, minValue, maxValue));
1079
+ const color = ctx2.value.decrementChannel(evt.channel, evt.step);
900
1080
  set.value(ctx2, color);
901
1081
  },
902
1082
  incrementXChannel(ctx2, evt) {
903
- const { xChannel, yChannel } = evt.channel;
904
- const { incrementX } = getChannelDetails(ctx2.valueAsColor, xChannel, yChannel);
905
- const color = ctx2.valueAsColor.withChannelValue(xChannel, incrementX(evt.step));
1083
+ const { xChannel } = evt.channel;
1084
+ const color = ctx2.value.incrementChannel(xChannel, evt.step);
906
1085
  set.value(ctx2, color);
907
1086
  },
908
1087
  decrementXChannel(ctx2, evt) {
909
- const { xChannel, yChannel } = evt.channel;
910
- const { decrementX } = getChannelDetails(ctx2.valueAsColor, xChannel, yChannel);
911
- const color = ctx2.valueAsColor.withChannelValue(xChannel, decrementX(evt.step));
1088
+ const { xChannel } = evt.channel;
1089
+ const color = ctx2.value.decrementChannel(xChannel, evt.step);
912
1090
  set.value(ctx2, color);
913
1091
  },
914
1092
  incrementYChannel(ctx2, evt) {
915
- const { xChannel, yChannel } = evt.channel;
916
- const { incrementY } = getChannelDetails(ctx2.valueAsColor, xChannel, yChannel);
917
- const color = ctx2.valueAsColor.withChannelValue(yChannel, incrementY(evt.step));
1093
+ const { yChannel } = evt.channel;
1094
+ const color = ctx2.value.incrementChannel(yChannel, evt.step);
918
1095
  set.value(ctx2, color);
919
1096
  },
920
1097
  decrementYChannel(ctx2, evt) {
921
- const { xChannel, yChannel } = evt.channel;
922
- const { decrementY } = getChannelDetails(ctx2.valueAsColor, xChannel, yChannel);
923
- const color = ctx2.valueAsColor.withChannelValue(yChannel, decrementY(evt.step));
1098
+ const { yChannel } = evt.channel;
1099
+ const color = ctx2.value.decrementChannel(yChannel, evt.step);
924
1100
  set.value(ctx2, color);
925
1101
  },
926
1102
  setChannelToMax(ctx2, evt) {
927
- const { maxValue } = ctx2.valueAsColor.getChannelRange(evt.channel);
928
- const color = ctx2.valueAsColor.withChannelValue(evt.channel, maxValue);
1103
+ const range = ctx2.value.getChannelRange(evt.channel);
1104
+ const color = ctx2.value.withChannelValue(evt.channel, range.maxValue);
929
1105
  set.value(ctx2, color);
930
1106
  },
931
1107
  setChannelToMin(ctx2, evt) {
932
- const { minValue } = ctx2.valueAsColor.getChannelRange(evt.channel);
933
- const color = ctx2.valueAsColor.withChannelValue(evt.channel, minValue);
1108
+ const range = ctx2.value.getChannelRange(evt.channel);
1109
+ const color = ctx2.value.withChannelValue(evt.channel, range.minValue);
934
1110
  set.value(ctx2, color);
935
1111
  },
936
1112
  focusAreaThumb(ctx2) {
937
1113
  (0, import_dom_query3.raf)(() => {
938
- dom.getAreaThumbEl(ctx2)?.focus({ preventScroll: true });
1114
+ dom?.focus(ctx2, dom.getAreaThumbEl(ctx2));
939
1115
  });
940
1116
  },
941
1117
  focusChannelThumb(ctx2, evt) {
942
1118
  (0, import_dom_query3.raf)(() => {
943
- dom.getChannelSliderThumbEl(ctx2, evt.channel)?.focus({ preventScroll: true });
1119
+ dom?.focus(ctx2, dom.getChannelSliderThumbEl(ctx2, evt.channel));
1120
+ });
1121
+ },
1122
+ setInitialFocus(ctx2) {
1123
+ (0, import_dom_query3.raf)(() => {
1124
+ dom.getInitialFocusEl(ctx2)?.focus({ preventScroll: true });
944
1125
  });
1126
+ },
1127
+ setReturnFocus(ctx2) {
1128
+ (0, import_dom_query3.raf)(() => {
1129
+ dom?.focus(ctx2, dom.getTriggerEl(ctx2));
1130
+ });
1131
+ },
1132
+ invokeOnOpen(ctx2) {
1133
+ ctx2.onOpenChange?.({ open: true });
1134
+ },
1135
+ invokeOnClose(ctx2) {
1136
+ ctx2.onOpenChange?.({ open: false });
1137
+ },
1138
+ toggleVisibility(ctx2, _evt, { send }) {
1139
+ send({ type: ctx2.open ? "OPEN" : "CLOSE", src: "controlled" });
945
1140
  }
1141
+ },
1142
+ compareFns: {
1143
+ value: (a, b) => a.isEqual(b)
946
1144
  }
947
1145
  }
948
1146
  );
949
1147
  }
1148
+ var sync = {
1149
+ inputs(ctx) {
1150
+ const channelInputs = dom.getChannelInputEls(ctx);
1151
+ channelInputs.forEach((inputEl) => {
1152
+ const channel = inputEl.dataset.channel;
1153
+ dom.setValue(inputEl, getChannelValue(ctx.value, channel));
1154
+ });
1155
+ }
1156
+ };
950
1157
  var invoke = {
951
1158
  changeEnd(ctx) {
952
1159
  ctx.onValueChangeEnd?.({
953
1160
  value: ctx.value,
954
- valueAsColor: ctx.valueAsColor
1161
+ valueAsString: ctx.valueAsString
955
1162
  });
956
1163
  },
957
1164
  change(ctx) {
958
1165
  ctx.onValueChange?.({
959
1166
  value: ctx.value,
960
- valueAsColor: ctx.valueAsColor
1167
+ valueAsString: ctx.valueAsString
961
1168
  });
1169
+ (0, import_form_utils.dispatchInputValueEvent)(dom.getHiddenInputEl(ctx), { value: ctx.valueAsString });
962
1170
  }
963
1171
  };
964
1172
  var set = {
965
1173
  value(ctx, color) {
966
- if (ctx.valueAsColor.isEqual(color))
1174
+ sync.inputs(ctx);
1175
+ if (!color || ctx.value.isEqual(color))
967
1176
  return;
968
- ctx.value = color.toString("css");
1177
+ const currentFormat = ctx.value.getFormat();
1178
+ const outputColor = color.toFormat(currentFormat);
1179
+ try {
1180
+ outputColor.outputFormat = ctx.value.outputFormat;
1181
+ } catch {
1182
+ }
1183
+ ctx.value = (0, import_core2.ref)(outputColor);
969
1184
  invoke.change(ctx);
970
1185
  }
971
1186
  };
@@ -973,6 +1188,7 @@ var set = {
973
1188
  0 && (module.exports = {
974
1189
  anatomy,
975
1190
  connect,
976
- machine
1191
+ machine,
1192
+ parse
977
1193
  });
978
1194
  //# sourceMappingURL=index.js.map