@zag-js/color-picker 1.43.0 → 2.0.0-next.1

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.
Files changed (49) hide show
  1. package/dist/color-picker.anatomy.d.mts +2 -2
  2. package/dist/color-picker.anatomy.d.ts +2 -2
  3. package/dist/color-picker.anatomy.js +1 -0
  4. package/dist/color-picker.anatomy.mjs +1 -0
  5. package/dist/color-picker.connect.d.mts +1 -0
  6. package/dist/color-picker.connect.d.ts +1 -0
  7. package/dist/color-picker.connect.js +130 -58
  8. package/dist/color-picker.connect.mjs +139 -60
  9. package/dist/color-picker.dom.js +23 -22
  10. package/dist/color-picker.dom.mjs +23 -22
  11. package/dist/color-picker.machine.d.mts +1 -0
  12. package/dist/color-picker.machine.d.ts +1 -0
  13. package/dist/color-picker.machine.js +43 -16
  14. package/dist/color-picker.machine.mjs +43 -16
  15. package/dist/color-picker.props.d.mts +1 -0
  16. package/dist/color-picker.props.d.ts +1 -0
  17. package/dist/color-picker.types.d.mts +115 -3
  18. package/dist/color-picker.types.d.ts +115 -3
  19. package/dist/index.d.mts +2 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/utils/get-area-format.d.mts +6 -0
  22. package/dist/utils/get-area-format.d.ts +6 -0
  23. package/dist/utils/get-area-format.js +37 -0
  24. package/dist/utils/get-area-format.mjs +12 -0
  25. package/dist/utils/get-channel-display-color.d.mts +2 -1
  26. package/dist/utils/get-channel-display-color.d.ts +2 -1
  27. package/dist/utils/get-channel-display-color.js +7 -0
  28. package/dist/utils/get-channel-display-color.mjs +7 -0
  29. package/dist/utils/get-channel-input-value.d.mts +1 -0
  30. package/dist/utils/get-channel-input-value.d.ts +1 -0
  31. package/dist/utils/get-channel-input-value.js +39 -8
  32. package/dist/utils/get-channel-input-value.mjs +39 -8
  33. package/dist/utils/get-gamut-overlay-path.d.mts +33 -0
  34. package/dist/utils/get-gamut-overlay-path.d.ts +33 -0
  35. package/dist/utils/get-gamut-overlay-path.js +81 -0
  36. package/dist/utils/get-gamut-overlay-path.mjs +55 -0
  37. package/dist/utils/get-gamut-overlay-path.test.d.mts +2 -0
  38. package/dist/utils/get-gamut-overlay-path.test.d.ts +2 -0
  39. package/dist/utils/get-gamut-overlay-path.test.js +35 -0
  40. package/dist/utils/get-gamut-overlay-path.test.mjs +33 -0
  41. package/dist/utils/get-slider-background.d.mts +1 -0
  42. package/dist/utils/get-slider-background.d.ts +1 -0
  43. package/dist/utils/get-slider-background.js +16 -1
  44. package/dist/utils/get-slider-background.mjs +16 -1
  45. package/dist/utils/is-srgb-gamut.d.mts +6 -0
  46. package/dist/utils/is-srgb-gamut.d.ts +6 -0
  47. package/dist/utils/is-srgb-gamut.js +33 -0
  48. package/dist/utils/is-srgb-gamut.mjs +8 -0
  49. package/package.json +9 -9
@@ -1,6 +1,6 @@
1
1
  import * as _zag_js_anatomy from '@zag-js/anatomy';
2
2
 
3
- declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect">;
4
- declare const parts: Record<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect", _zag_js_anatomy.AnatomyPart>;
3
+ declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "gamutOverlay" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect">;
4
+ declare const parts: Record<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "gamutOverlay" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect", _zag_js_anatomy.AnatomyPart>;
5
5
 
6
6
  export { anatomy, parts };
@@ -1,6 +1,6 @@
1
1
  import * as _zag_js_anatomy from '@zag-js/anatomy';
2
2
 
3
- declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect">;
4
- declare const parts: Record<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect", _zag_js_anatomy.AnatomyPart>;
3
+ declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "gamutOverlay" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect">;
4
+ declare const parts: Record<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "gamutOverlay" | "valueText" | "areaBackground" | "channelSlider" | "channelSliderLabel" | "channelSliderTrack" | "channelSliderThumb" | "channelSliderValueText" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatchIndicator" | "swatch" | "eyeDropperTrigger" | "formatTrigger" | "formatSelect", _zag_js_anatomy.AnatomyPart>;
5
5
 
6
6
  export { anatomy, parts };
@@ -34,6 +34,7 @@ var anatomy = (0, import_anatomy.createAnatomy)("color-picker", [
34
34
  "content",
35
35
  "area",
36
36
  "areaThumb",
37
+ "gamutOverlay",
37
38
  "valueText",
38
39
  "areaBackground",
39
40
  "channelSlider",
@@ -9,6 +9,7 @@ var anatomy = createAnatomy("color-picker", [
9
9
  "content",
10
10
  "area",
11
11
  "areaThumb",
12
+ "gamutOverlay",
12
13
  "valueText",
13
14
  "areaBackground",
14
15
  "channelSlider",
@@ -1,6 +1,7 @@
1
1
  import { PropTypes, NormalizeProps } from '@zag-js/types';
2
2
  import { ColorPickerService, ColorPickerApi } from './color-picker.types.mjs';
3
3
  import '@zag-js/color-utils';
4
+ import './utils/get-gamut-overlay-path.mjs';
4
5
  import '@zag-js/core';
5
6
  import '@zag-js/dismissable';
6
7
  import '@zag-js/popper';
@@ -1,6 +1,7 @@
1
1
  import { PropTypes, NormalizeProps } from '@zag-js/types';
2
2
  import { ColorPickerService, ColorPickerApi } from './color-picker.types.js';
3
3
  import '@zag-js/color-utils';
4
+ import './utils/get-gamut-overlay-path.js';
4
5
  import '@zag-js/core';
5
6
  import '@zag-js/dismissable';
6
7
  import '@zag-js/popper';
@@ -34,6 +34,7 @@ __export(color_picker_connect_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(color_picker_connect_exports);
36
36
  var import_color_utils = require("@zag-js/color-utils");
37
+ var import_dismissable = require("@zag-js/dismissable");
37
38
  var import_dom_query = require("@zag-js/dom-query");
38
39
  var import_dom_query2 = require("@zag-js/dom-query");
39
40
  var import_popper = require("@zag-js/popper");
@@ -41,12 +42,20 @@ var import_color_picker = require("./color-picker.anatomy.js");
41
42
  var dom = __toESM(require("./color-picker.dom.js"));
42
43
  var import_get_channel_display_color = require("./utils/get-channel-display-color.js");
43
44
  var import_get_channel_input_value = require("./utils/get-channel-input-value.js");
45
+ var import_get_gamut_overlay_path = require("./utils/get-gamut-overlay-path.js");
44
46
  var import_get_slider_background = require("./utils/get-slider-background.js");
47
+ function getDefaultDevicePixelRatio() {
48
+ if (typeof globalThis === "undefined") return 1;
49
+ const dpr = globalThis.devicePixelRatio;
50
+ return typeof dpr === "number" && Number.isFinite(dpr) ? dpr : 1;
51
+ }
45
52
  function connect(service, normalize) {
46
53
  const { context, send, prop, computed, state, scope } = service;
54
+ const layer = context.get("layer");
47
55
  const value = context.get("value");
48
56
  const format = context.get("format");
49
57
  const areaValue = computed("areaValue");
58
+ const stableAreaValue = context.get("areaBaseColor") ?? areaValue;
50
59
  const valueAsString = computed("valueAsString");
51
60
  const disabled = computed("disabled");
52
61
  const readOnly = !!prop("readOnly");
@@ -63,6 +72,10 @@ function connect(service, normalize) {
63
72
  yChannel: props.yChannel ?? channels[2]
64
73
  };
65
74
  };
75
+ function resolveGamutOverlay(props = {}) {
76
+ const pixelRatio = props.pixelRatio ?? getDefaultDevicePixelRatio();
77
+ return (0, import_get_gamut_overlay_path.getGamutOverlayData)(stableAreaValue, getAreaChannels(props), format, { pixelRatio });
78
+ }
66
79
  const currentPlacement = context.get("currentPlacement");
67
80
  const currentPlacementSide = currentPlacement ? (0, import_popper.getPlacementSide)(currentPlacement) : void 0;
68
81
  const popperStyles = (0, import_popper.getPlacementStyles)({
@@ -78,11 +91,38 @@ function connect(service, normalize) {
78
91
  disabled: props.disabled || !interactive
79
92
  };
80
93
  }
94
+ function getRootState() {
95
+ return { disabled, readOnly, invalid };
96
+ }
97
+ function getTriggerState() {
98
+ return {
99
+ open,
100
+ focused,
101
+ disabled,
102
+ invalid,
103
+ readOnly,
104
+ placement: currentPlacement,
105
+ side: currentPlacementSide
106
+ };
107
+ }
108
+ function getContentState() {
109
+ return {
110
+ open,
111
+ nested: !!layer?.nested,
112
+ hasNested: !!layer?.hasNested,
113
+ placement: currentPlacement,
114
+ side: currentPlacementSide
115
+ };
116
+ }
81
117
  return {
82
118
  dragging,
83
119
  open,
84
120
  valueAsString,
85
121
  value,
122
+ isInSrgbGamut: (0, import_color_utils.isInSrgbGamut)(value),
123
+ getGamutOverlay(props = {}) {
124
+ return resolveGamutOverlay(props);
125
+ },
86
126
  inline: !!prop("inline"),
87
127
  setOpen(nextOpen) {
88
128
  if (prop("inline")) return;
@@ -104,23 +144,23 @@ function connect(service, normalize) {
104
144
  send({ type: "VALUE.SET", value: color, src: "set-channel" });
105
145
  },
106
146
  format: context.get("format"),
107
- setFormat(format2) {
108
- const formatValue = value.toFormat(format2);
109
- send({ type: "VALUE.SET", value: formatValue, src: "set-format" });
147
+ setFormat(nextFormat) {
148
+ send({ type: "FORMAT.SET", format: nextFormat, src: "set-format" });
110
149
  },
111
150
  alpha: value.getChannelValue("alpha"),
112
151
  setAlpha(alphaValue) {
113
152
  const color = value.withChannelValue("alpha", alphaValue);
114
153
  send({ type: "VALUE.SET", value: color, src: "set-alpha" });
115
154
  },
155
+ getRootState,
116
156
  getRootProps() {
157
+ const rootState = getRootState();
117
158
  return normalize.element({
118
- ...import_color_picker.parts.root.attrs,
159
+ ...import_color_picker.parts.root.attrs(scope.id),
119
160
  dir: prop("dir"),
120
- id: dom.getRootId(scope),
121
- "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
122
- "data-readonly": (0, import_dom_query2.dataAttr)(readOnly),
123
- "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
161
+ "data-disabled": (0, import_dom_query2.dataAttr)(rootState.disabled),
162
+ "data-readonly": (0, import_dom_query2.dataAttr)(rootState.readOnly),
163
+ "data-invalid": (0, import_dom_query2.dataAttr)(rootState.invalid),
124
164
  style: {
125
165
  "--value": value.toString("css")
126
166
  }
@@ -128,7 +168,7 @@ function connect(service, normalize) {
128
168
  },
129
169
  getLabelProps() {
130
170
  return normalize.element({
131
- ...import_color_picker.parts.label.attrs,
171
+ ...import_color_picker.parts.label.attrs(scope.id),
132
172
  dir: prop("dir"),
133
173
  id: dom.getLabelId(scope),
134
174
  htmlFor: dom.getHiddenInputId(scope),
@@ -146,8 +186,7 @@ function connect(service, normalize) {
146
186
  },
147
187
  getControlProps() {
148
188
  return normalize.element({
149
- ...import_color_picker.parts.control.attrs,
150
- id: dom.getControlId(scope),
189
+ ...import_color_picker.parts.control.attrs(scope.id),
151
190
  dir: prop("dir"),
152
191
  "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
153
192
  "data-readonly": (0, import_dom_query2.dataAttr)(readOnly),
@@ -156,24 +195,26 @@ function connect(service, normalize) {
156
195
  "data-focus": (0, import_dom_query2.dataAttr)(focused)
157
196
  });
158
197
  },
198
+ getTriggerState,
159
199
  getTriggerProps() {
200
+ const triggerState = getTriggerState();
160
201
  return normalize.button({
161
- ...import_color_picker.parts.trigger.attrs,
202
+ ...import_color_picker.parts.trigger.attrs(scope.id),
162
203
  id: dom.getTriggerId(scope),
163
204
  dir: prop("dir"),
164
- disabled,
205
+ disabled: triggerState.disabled,
165
206
  "aria-label": `select color. current color is ${valueAsString}`,
166
207
  "aria-controls": dom.getContentId(scope),
167
208
  "aria-labelledby": dom.getLabelId(scope),
168
209
  "aria-haspopup": prop("inline") ? void 0 : "dialog",
169
- "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
170
- "data-readonly": (0, import_dom_query2.dataAttr)(readOnly),
171
- "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
172
- "data-placement": currentPlacement,
173
- "data-side": currentPlacementSide,
174
- "aria-expanded": open,
175
- "data-state": open ? "open" : "closed",
176
- "data-focus": (0, import_dom_query2.dataAttr)(focused),
210
+ "data-disabled": (0, import_dom_query2.dataAttr)(triggerState.disabled),
211
+ "data-readonly": (0, import_dom_query2.dataAttr)(triggerState.readOnly),
212
+ "data-invalid": (0, import_dom_query2.dataAttr)(triggerState.invalid),
213
+ "data-placement": triggerState.placement,
214
+ "data-side": triggerState.side,
215
+ "aria-expanded": triggerState.open,
216
+ "data-state": triggerState.open ? "open" : "closed",
217
+ "data-focus": (0, import_dom_query2.dataAttr)(triggerState.focused),
177
218
  type: "button",
178
219
  onClick() {
179
220
  if (!interactive) return;
@@ -190,28 +231,35 @@ function connect(service, normalize) {
190
231
  },
191
232
  getPositionerProps() {
192
233
  return normalize.element({
193
- ...import_color_picker.parts.positioner.attrs,
194
- id: dom.getPositionerId(scope),
234
+ ...import_color_picker.parts.positioner.attrs(scope.id),
195
235
  dir: prop("dir"),
196
- style: popperStyles.floating
236
+ ...(0, import_dismissable.getDismissableLayerAttrs)(layer),
237
+ style: {
238
+ ...popperStyles.floating,
239
+ ...(0, import_dismissable.getDismissableLayerStyle)(layer, { zIndex: true })
240
+ }
197
241
  });
198
242
  },
243
+ getContentState,
199
244
  getContentProps() {
245
+ const contentState = getContentState();
200
246
  return normalize.element({
201
- ...import_color_picker.parts.content.attrs,
247
+ ...import_color_picker.parts.content.attrs(scope.id),
202
248
  id: dom.getContentId(scope),
203
249
  dir: prop("dir"),
204
250
  role: prop("inline") ? void 0 : "dialog",
205
251
  tabIndex: -1,
206
- "data-placement": currentPlacement,
207
- "data-side": currentPlacementSide,
208
- "data-state": open ? "open" : "closed",
209
- hidden: !open
252
+ "data-placement": contentState.placement,
253
+ "data-side": contentState.side,
254
+ "data-state": contentState.open ? "open" : "closed",
255
+ hidden: !contentState.open,
256
+ ...(0, import_dismissable.getDismissableLayerAttrs)(layer),
257
+ style: (0, import_dismissable.getDismissableLayerStyle)(layer, { pointerEvents: true })
210
258
  });
211
259
  },
212
260
  getValueTextProps() {
213
261
  return normalize.element({
214
- ...import_color_picker.parts.valueText.attrs,
262
+ ...import_color_picker.parts.valueText.attrs(scope.id),
215
263
  dir: prop("dir"),
216
264
  "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
217
265
  "data-focus": (0, import_dom_query2.dataAttr)(focused)
@@ -219,14 +267,13 @@ function connect(service, normalize) {
219
267
  },
220
268
  getAreaProps(props = {}) {
221
269
  const { xChannel, yChannel } = getAreaChannels(props);
222
- const { areaStyles } = (0, import_color_utils.getColorAreaGradient)(areaValue, {
270
+ const { areaStyles } = (0, import_color_utils.getColorAreaGradient)(stableAreaValue, {
223
271
  xChannel,
224
272
  yChannel,
225
273
  dir: prop("dir")
226
274
  });
227
275
  return normalize.element({
228
- ...import_color_picker.parts.area.attrs,
229
- id: dom.getAreaId(scope),
276
+ ...import_color_picker.parts.area.attrs(scope.id),
230
277
  role: "group",
231
278
  "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
232
279
  "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
@@ -250,14 +297,13 @@ function connect(service, normalize) {
250
297
  },
251
298
  getAreaBackgroundProps(props = {}) {
252
299
  const { xChannel, yChannel } = getAreaChannels(props);
253
- const { areaGradientStyles } = (0, import_color_utils.getColorAreaGradient)(areaValue, {
300
+ const { areaGradientStyles } = (0, import_color_utils.getColorAreaGradient)(stableAreaValue, {
254
301
  xChannel,
255
302
  yChannel,
256
303
  dir: prop("dir")
257
304
  });
258
305
  return normalize.element({
259
- ...import_color_picker.parts.areaBackground.attrs,
260
- id: dom.getAreaGradientId(scope),
306
+ ...import_color_picker.parts.areaBackground.attrs(scope.id),
261
307
  "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
262
308
  "data-disabled": (0, import_dom_query2.dataAttr)(disabled),
263
309
  "data-readonly": (0, import_dom_query2.dataAttr)(readOnly),
@@ -269,18 +315,45 @@ function connect(service, normalize) {
269
315
  }
270
316
  });
271
317
  },
318
+ getGamutOverlayProps(props = {}) {
319
+ const data = resolveGamutOverlay(props);
320
+ return normalize.element({
321
+ ...import_color_picker.parts.gamutOverlay.attrs(scope.id),
322
+ viewBox: "0 0 100 100",
323
+ preserveAspectRatio: "none",
324
+ xmlns: "http://www.w3.org/2000/svg",
325
+ "aria-hidden": true,
326
+ "data-state": data ? "visible" : "hidden",
327
+ style: {
328
+ position: "absolute",
329
+ inset: "0",
330
+ width: "100%",
331
+ height: "100%",
332
+ overflow: "hidden",
333
+ pointerEvents: "none"
334
+ }
335
+ });
336
+ },
272
337
  getAreaThumbProps(props = {}) {
273
338
  const { xChannel, yChannel } = getAreaChannels(props);
274
339
  const channel = { xChannel, yChannel };
275
- const xPercent = areaValue.getChannelValuePercent(xChannel);
276
- const yPercent = 1 - areaValue.getChannelValuePercent(yChannel);
340
+ const dragPos = context.get("areaDragPosition");
277
341
  const isRtl = prop("dir") === "rtl";
342
+ let xPercent;
343
+ let yPercent;
344
+ if (dragPos) {
345
+ xPercent = dragPos.x;
346
+ yPercent = dragPos.y;
347
+ } else {
348
+ xPercent = areaValue.getChannelValuePercent(xChannel);
349
+ yPercent = 1 - areaValue.getChannelValuePercent(yChannel);
350
+ }
278
351
  const finalXPercent = isRtl ? 1 - xPercent : xPercent;
279
352
  const xValue = areaValue.getChannelValue(xChannel);
280
353
  const yValue = areaValue.getChannelValue(yChannel);
281
354
  const color = areaValue.withChannelValue("alpha", 1).toString("css");
282
355
  return normalize.element({
283
- ...import_color_picker.parts.areaThumb.attrs,
356
+ ...import_color_picker.parts.areaThumb.attrs(scope.id),
284
357
  id: dom.getAreaThumbId(scope),
285
358
  dir: prop("dir"),
286
359
  tabIndex: disabled ? void 0 : 0,
@@ -348,7 +421,7 @@ function connect(service, normalize) {
348
421
  getTransparencyGridProps(props = {}) {
349
422
  const { size = "12px" } = props;
350
423
  return normalize.element({
351
- ...import_color_picker.parts.transparencyGrid.attrs,
424
+ ...import_color_picker.parts.transparencyGrid.attrs(scope.id),
352
425
  style: {
353
426
  "--size": size,
354
427
  width: "100%",
@@ -366,7 +439,7 @@ function connect(service, normalize) {
366
439
  getChannelSliderProps(props) {
367
440
  const { orientation = "horizontal", channel, format: format2 } = props;
368
441
  return normalize.element({
369
- ...import_color_picker.parts.channelSlider.attrs,
442
+ ...import_color_picker.parts.channelSlider.attrs(scope.id),
370
443
  "data-channel": channel,
371
444
  "data-orientation": orientation,
372
445
  role: "presentation",
@@ -386,10 +459,9 @@ function connect(service, normalize) {
386
459
  },
387
460
  getChannelSliderTrackProps(props) {
388
461
  const { orientation = "horizontal", channel, format: format2 } = props;
389
- const normalizedValue = format2 ? value.toFormat(format2) : areaValue;
462
+ const normalizedValue = format2 ? value.toFormat(format2) : stableAreaValue;
390
463
  return normalize.element({
391
- ...import_color_picker.parts.channelSliderTrack.attrs,
392
- id: dom.getChannelSliderTrackId(scope, channel),
464
+ ...import_color_picker.parts.channelSliderTrack.attrs(scope.id),
393
465
  role: "group",
394
466
  "data-channel": channel,
395
467
  "data-orientation": orientation,
@@ -408,7 +480,7 @@ function connect(service, normalize) {
408
480
  getChannelSliderLabelProps(props) {
409
481
  const { channel } = props;
410
482
  return normalize.element({
411
- ...import_color_picker.parts.channelSliderLabel.attrs,
483
+ ...import_color_picker.parts.channelSliderLabel.attrs(scope.id),
412
484
  "data-channel": channel,
413
485
  onClick(event) {
414
486
  if (!interactive) return;
@@ -424,13 +496,13 @@ function connect(service, normalize) {
424
496
  },
425
497
  getChannelSliderValueTextProps(props) {
426
498
  return normalize.element({
427
- ...import_color_picker.parts.channelSliderValueText.attrs,
499
+ ...import_color_picker.parts.channelSliderValueText.attrs(scope.id),
428
500
  "data-channel": props.channel
429
501
  });
430
502
  },
431
503
  getChannelSliderThumbProps(props) {
432
504
  const { orientation = "horizontal", channel, format: format2 } = props;
433
- const normalizedValue = format2 ? value.toFormat(format2) : areaValue;
505
+ const normalizedValue = format2 ? value.toFormat(format2) : stableAreaValue;
434
506
  const channelRange = normalizedValue.getChannelRange(channel);
435
507
  const channelValue = normalizedValue.getChannelValue(channel);
436
508
  const offset = (channelValue - channelRange.minValue) / (channelRange.maxValue - channelRange.minValue);
@@ -438,7 +510,7 @@ function connect(service, normalize) {
438
510
  const finalOffset = orientation === "horizontal" && isRtl ? 1 - offset : offset;
439
511
  const placementStyles = orientation === "horizontal" ? { left: `${finalOffset * 100}%`, top: "50%" } : { top: `${offset * 100}%`, left: "50%" };
440
512
  return normalize.element({
441
- ...import_color_picker.parts.channelSliderThumb.attrs,
513
+ ...import_color_picker.parts.channelSliderThumb.attrs(scope.id),
442
514
  id: dom.getChannelSliderThumbId(scope, channel),
443
515
  role: "slider",
444
516
  "aria-label": channel,
@@ -455,7 +527,7 @@ function connect(service, normalize) {
455
527
  style: {
456
528
  forcedColorAdjust: "none",
457
529
  position: "absolute",
458
- background: (0, import_get_channel_display_color.getChannelDisplayColor)(areaValue, channel).toString("css"),
530
+ background: (0, import_get_channel_display_color.getChannelDisplayColor)(stableAreaValue, channel).toString("css"),
459
531
  ...placementStyles
460
532
  },
461
533
  onFocus() {
@@ -510,7 +582,7 @@ function connect(service, normalize) {
510
582
  const isTextField = channel === "hex" || channel === "css";
511
583
  const channelRange = (0, import_get_channel_input_value.getChannelRange)(value, channel);
512
584
  return normalize.input({
513
- ...import_color_picker.parts.channelInput.attrs,
585
+ ...import_color_picker.parts.channelInput.attrs(scope.id),
514
586
  dir: prop("dir"),
515
587
  type: isTextField ? "text" : "number",
516
588
  "data-channel": channel,
@@ -575,7 +647,7 @@ function connect(service, normalize) {
575
647
  },
576
648
  getEyeDropperTriggerProps() {
577
649
  return normalize.button({
578
- ...import_color_picker.parts.eyeDropperTrigger.attrs,
650
+ ...import_color_picker.parts.eyeDropperTrigger.attrs(scope.id),
579
651
  type: "button",
580
652
  dir: prop("dir"),
581
653
  disabled,
@@ -591,7 +663,7 @@ function connect(service, normalize) {
591
663
  },
592
664
  getSwatchGroupProps() {
593
665
  return normalize.element({
594
- ...import_color_picker.parts.swatchGroup.attrs,
666
+ ...import_color_picker.parts.swatchGroup.attrs(scope.id),
595
667
  role: "group"
596
668
  });
597
669
  },
@@ -599,7 +671,7 @@ function connect(service, normalize) {
599
671
  getSwatchTriggerProps(props) {
600
672
  const swatchState = getSwatchTriggerState(props);
601
673
  return normalize.button({
602
- ...import_color_picker.parts.swatchTrigger.attrs,
674
+ ...import_color_picker.parts.swatchTrigger.attrs(scope.id),
603
675
  disabled: swatchState.disabled,
604
676
  dir: prop("dir"),
605
677
  type: "button",
@@ -620,7 +692,7 @@ function connect(service, normalize) {
620
692
  getSwatchIndicatorProps(props) {
621
693
  const swatchState = getSwatchTriggerState(props);
622
694
  return normalize.element({
623
- ...import_color_picker.parts.swatchIndicator.attrs,
695
+ ...import_color_picker.parts.swatchIndicator.attrs(scope.id),
624
696
  dir: prop("dir"),
625
697
  hidden: !swatchState.checked
626
698
  });
@@ -630,7 +702,7 @@ function connect(service, normalize) {
630
702
  const swatchState = getSwatchTriggerState(props);
631
703
  const color = swatchState.value.toString(respectAlpha ? "css" : "hex");
632
704
  return normalize.element({
633
- ...import_color_picker.parts.swatch.attrs,
705
+ ...import_color_picker.parts.swatch.attrs(scope.id),
634
706
  dir: prop("dir"),
635
707
  "data-state": swatchState.checked ? "checked" : "unchecked",
636
708
  "data-value": swatchState.valueAsString,
@@ -643,7 +715,7 @@ function connect(service, normalize) {
643
715
  },
644
716
  getFormatTriggerProps() {
645
717
  return normalize.button({
646
- ...import_color_picker.parts.formatTrigger.attrs,
718
+ ...import_color_picker.parts.formatTrigger.attrs(scope.id),
647
719
  dir: prop("dir"),
648
720
  type: "button",
649
721
  "aria-label": `change color format to ${getNextFormat(format)}`,
@@ -656,7 +728,7 @@ function connect(service, normalize) {
656
728
  },
657
729
  getFormatSelectProps() {
658
730
  return normalize.select({
659
- ...import_color_picker.parts.formatSelect.attrs,
731
+ ...import_color_picker.parts.formatSelect.attrs(scope.id),
660
732
  "aria-label": "change color format",
661
733
  dir: prop("dir"),
662
734
  defaultValue: prop("format"),
@@ -669,7 +741,7 @@ function connect(service, normalize) {
669
741
  }
670
742
  };
671
743
  }
672
- var formats = ["hsba", "hsla", "rgba"];
744
+ var formats = ["hsba", "hsla", "rgba", "oklab", "oklch"];
673
745
  var formatRegex = new RegExp(`^(${formats.join("|")})$`);
674
746
  function getNextFormat(format) {
675
747
  const index = formats.indexOf(format);