@zag-js/color-picker 0.24.0 → 0.26.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 CHANGED
@@ -8,7 +8,7 @@ import { InteractOutsideHandlers } from '@zag-js/dismissable';
8
8
  import { PositioningOptions } from '@zag-js/popper';
9
9
  import { MaybeFunction } from '@zag-js/utils';
10
10
 
11
- declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "areaBackground" | "channelSlider" | "channelSliderTrack" | "channelSliderThumb" | "channelInput" | "transparancyGrid" | "swatchGroup" | "swatchTrigger" | "swatch" | "eyeDropperTrigger">;
11
+ declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "areaBackground" | "channelSlider" | "channelSliderTrack" | "channelSliderThumb" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatch" | "eyeDropperTrigger">;
12
12
 
13
13
  interface ValueChangeDetails {
14
14
  value: Color;
@@ -69,16 +69,6 @@ interface PublicContext extends CommonProperties, InteractOutsideHandlers {
69
69
  * The name for the form input
70
70
  */
71
71
  name?: string;
72
- /**
73
- * The color format to use (rgb, hsl, hsb)
74
- * @default "hsl"
75
- */
76
- format?: ColorFormat;
77
- /**
78
- * The alpha format to use (decimal, percent)
79
- * @default "decimal"
80
- */
81
- alphaFormat?: "decimal" | "percent";
82
72
  /**
83
73
  * The positioning options for the color picker
84
74
  */
@@ -157,8 +147,8 @@ interface SwatchProps {
157
147
  */
158
148
  respectAlpha?: boolean;
159
149
  }
160
- interface TransparancyGridProps {
161
- size: string;
150
+ interface TransparencyGridProps {
151
+ size?: string;
162
152
  }
163
153
  interface MachineApi<T extends PropTypes = PropTypes> {
164
154
  /**
@@ -193,6 +183,10 @@ interface MachineApi<T extends PropTypes = PropTypes> {
193
183
  * Function to set the color value of a specific channel
194
184
  */
195
185
  setChannelValue(channel: ColorChannel, value: number): void;
186
+ /**
187
+ * The current color format
188
+ */
189
+ format: ColorFormat;
196
190
  /**
197
191
  * Function to set the color format
198
192
  */
@@ -200,7 +194,7 @@ interface MachineApi<T extends PropTypes = PropTypes> {
200
194
  /**
201
195
  * The alpha value of the color
202
196
  */
203
- getAlpha(): number;
197
+ alpha: number;
204
198
  /**
205
199
  * Function to set the color alpha
206
200
  */
@@ -219,7 +213,7 @@ interface MachineApi<T extends PropTypes = PropTypes> {
219
213
  getChannelSliderTrackProps(props: ChannelProps): T["element"];
220
214
  getChannelSliderThumbProps(props: ChannelProps): T["element"];
221
215
  getChannelInputProps(props: ChannelInputProps): T["input"];
222
- getTransparencyGridProps(props: TransparancyGridProps): T["element"];
216
+ getTransparencyGridProps(props?: TransparencyGridProps): T["element"];
223
217
  eyeDropperTriggerProps: T["button"];
224
218
  swatchGroupProps: T["element"];
225
219
  getSwatchTriggerProps(props: SwatchTriggerProps): T["button"];
@@ -232,4 +226,4 @@ declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<
232
226
 
233
227
  declare const parse: (color: string) => Color;
234
228
 
235
- export { MachineApi as Api, AreaProps, ChannelInputProps, ChannelProps, UserDefinedContext as Context, SwatchProps, anatomy, connect, machine, parse };
229
+ export { MachineApi as Api, AreaProps, ChannelInputProps, ChannelProps, UserDefinedContext as Context, SwatchProps, SwatchTriggerProps, TransparencyGridProps, anatomy, connect, machine, parse };
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ import { InteractOutsideHandlers } from '@zag-js/dismissable';
8
8
  import { PositioningOptions } from '@zag-js/popper';
9
9
  import { MaybeFunction } from '@zag-js/utils';
10
10
 
11
- declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "areaBackground" | "channelSlider" | "channelSliderTrack" | "channelSliderThumb" | "channelInput" | "transparancyGrid" | "swatchGroup" | "swatchTrigger" | "swatch" | "eyeDropperTrigger">;
11
+ declare const anatomy: _zag_js_anatomy.Anatomy<"root" | "label" | "control" | "trigger" | "positioner" | "content" | "area" | "areaThumb" | "areaBackground" | "channelSlider" | "channelSliderTrack" | "channelSliderThumb" | "channelInput" | "transparencyGrid" | "swatchGroup" | "swatchTrigger" | "swatch" | "eyeDropperTrigger">;
12
12
 
13
13
  interface ValueChangeDetails {
14
14
  value: Color;
@@ -69,16 +69,6 @@ interface PublicContext extends CommonProperties, InteractOutsideHandlers {
69
69
  * The name for the form input
70
70
  */
71
71
  name?: string;
72
- /**
73
- * The color format to use (rgb, hsl, hsb)
74
- * @default "hsl"
75
- */
76
- format?: ColorFormat;
77
- /**
78
- * The alpha format to use (decimal, percent)
79
- * @default "decimal"
80
- */
81
- alphaFormat?: "decimal" | "percent";
82
72
  /**
83
73
  * The positioning options for the color picker
84
74
  */
@@ -157,8 +147,8 @@ interface SwatchProps {
157
147
  */
158
148
  respectAlpha?: boolean;
159
149
  }
160
- interface TransparancyGridProps {
161
- size: string;
150
+ interface TransparencyGridProps {
151
+ size?: string;
162
152
  }
163
153
  interface MachineApi<T extends PropTypes = PropTypes> {
164
154
  /**
@@ -193,6 +183,10 @@ interface MachineApi<T extends PropTypes = PropTypes> {
193
183
  * Function to set the color value of a specific channel
194
184
  */
195
185
  setChannelValue(channel: ColorChannel, value: number): void;
186
+ /**
187
+ * The current color format
188
+ */
189
+ format: ColorFormat;
196
190
  /**
197
191
  * Function to set the color format
198
192
  */
@@ -200,7 +194,7 @@ interface MachineApi<T extends PropTypes = PropTypes> {
200
194
  /**
201
195
  * The alpha value of the color
202
196
  */
203
- getAlpha(): number;
197
+ alpha: number;
204
198
  /**
205
199
  * Function to set the color alpha
206
200
  */
@@ -219,7 +213,7 @@ interface MachineApi<T extends PropTypes = PropTypes> {
219
213
  getChannelSliderTrackProps(props: ChannelProps): T["element"];
220
214
  getChannelSliderThumbProps(props: ChannelProps): T["element"];
221
215
  getChannelInputProps(props: ChannelInputProps): T["input"];
222
- getTransparencyGridProps(props: TransparancyGridProps): T["element"];
216
+ getTransparencyGridProps(props?: TransparencyGridProps): T["element"];
223
217
  eyeDropperTriggerProps: T["button"];
224
218
  swatchGroupProps: T["element"];
225
219
  getSwatchTriggerProps(props: SwatchTriggerProps): T["button"];
@@ -232,4 +226,4 @@ declare function machine(userContext: UserDefinedContext): _zag_js_core.Machine<
232
226
 
233
227
  declare const parse: (color: string) => Color;
234
228
 
235
- export { MachineApi as Api, AreaProps, ChannelInputProps, ChannelProps, UserDefinedContext as Context, SwatchProps, anatomy, connect, machine, parse };
229
+ export { MachineApi as Api, AreaProps, ChannelInputProps, ChannelProps, UserDefinedContext as Context, SwatchProps, SwatchTriggerProps, TransparencyGridProps, anatomy, connect, machine, parse };
package/dist/index.js CHANGED
@@ -43,7 +43,7 @@ var anatomy = (0, import_anatomy.createAnatomy)("color-picker", [
43
43
  "channelSliderTrack",
44
44
  "channelSliderThumb",
45
45
  "channelInput",
46
- "transparancyGrid",
46
+ "transparencyGrid",
47
47
  "swatchGroup",
48
48
  "swatchTrigger",
49
49
  "swatch",
@@ -104,7 +104,10 @@ var dom = (0, import_dom_query.createScope)({
104
104
  return percent;
105
105
  },
106
106
  getChannelInputEls: (ctx) => {
107
- 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
+ ];
108
111
  },
109
112
  getFirstFocusableEl: (ctx) => (0, import_tabbable.getFirstFocusable)(dom.getContentEl(ctx), "if-empty"),
110
113
  getInitialFocusEl: (ctx) => {
@@ -208,19 +211,18 @@ function getSliderBackgroundDirection(orientation, dir) {
208
211
  return "left";
209
212
  }
210
213
  }
211
- var getSliderBackground = (ctx, props) => {
212
- const { channel } = props;
213
- const dir = getSliderBackgroundDirection(props.orientation, ctx.dir);
214
- const value = ctx.value;
214
+ var getSliderBackground = (props) => {
215
+ const { channel, value, dir } = props;
216
+ const bgDirection = getSliderBackgroundDirection(props.orientation, dir);
215
217
  const { minValue, maxValue } = value.getChannelRange(channel);
216
218
  switch (channel) {
217
219
  case "hue":
218
- 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%)`;
219
221
  case "lightness": {
220
222
  let start = value.withChannelValue(channel, minValue).toString("css");
221
223
  let middle = value.withChannelValue(channel, (maxValue - minValue) / 2).toString("css");
222
224
  let end = value.withChannelValue(channel, maxValue).toString("css");
223
- return `linear-gradient(to ${dir}, ${start}, ${middle}, ${end})`;
225
+ return `linear-gradient(to ${bgDirection}, ${start}, ${middle}, ${end})`;
224
226
  }
225
227
  case "saturation":
226
228
  case "brightness":
@@ -230,7 +232,7 @@ var getSliderBackground = (ctx, props) => {
230
232
  case "alpha": {
231
233
  let start = value.withChannelValue(channel, minValue).toString("css");
232
234
  let end = value.withChannelValue(channel, maxValue).toString("css");
233
- return `linear-gradient(to ${dir}, ${start}, ${end})`;
235
+ return `linear-gradient(to ${bgDirection}, ${start}, ${end})`;
234
236
  }
235
237
  default:
236
238
  throw new Error("Unknown color channel: " + channel);
@@ -246,11 +248,13 @@ function connect(state, send, normalize) {
246
248
  const isDragging = state.hasTag("dragging");
247
249
  const isOpen = state.hasTag("open");
248
250
  const channels = value.getChannels();
249
- const getAreaChannels = (props) => ({
250
- value: value.toFormat("hsl"),
251
- xChannel: props.xChannel ?? "saturation",
252
- yChannel: props.yChannel ?? "lightness"
253
- });
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
+ };
254
258
  const currentPlacement = state.context.currentPlacement;
255
259
  const popperStyles = (0, import_popper.getPlacementStyles)({
256
260
  ...state.context.positioning,
@@ -272,13 +276,12 @@ function connect(state, send, normalize) {
272
276
  const color = value.withChannelValue(channel, channelValue);
273
277
  send({ type: "VALUE.SET", value: color, src: "set-channel" });
274
278
  },
279
+ format: value.outputFormat ?? value.getFormat(),
275
280
  setFormat(format) {
276
281
  const formatValue = value.toFormat(format);
277
282
  send({ type: "VALUE.SET", value: formatValue, src: "set-format" });
278
283
  },
279
- getAlpha() {
280
- return value.getChannelValue("alpha");
281
- },
284
+ alpha: value.getChannelValue("alpha"),
282
285
  setAlpha(alphaValue) {
283
286
  const color = value.withChannelValue("alpha", alphaValue);
284
287
  send({ type: "VALUE.SET", value: color, src: "set-alpha" });
@@ -391,10 +394,10 @@ function connect(state, send, normalize) {
391
394
  });
392
395
  },
393
396
  getAreaThumbProps(props = {}) {
394
- const { xChannel, yChannel, value: valueAsHSL } = getAreaChannels(props);
397
+ const { xChannel, yChannel } = getAreaChannels(props);
395
398
  const channel = { xChannel, yChannel };
396
- const x = valueAsHSL.getChannelValuePercent(xChannel);
397
- const y = 1 - valueAsHSL.getChannelValuePercent(yChannel);
399
+ const x = value.getChannelValuePercent(xChannel);
400
+ const y = 1 - value.getChannelValuePercent(yChannel);
398
401
  return normalize.element({
399
402
  ...parts.areaThumb.attrs,
400
403
  id: dom.getAreaThumbId(state.context),
@@ -449,10 +452,10 @@ function connect(state, send, normalize) {
449
452
  }
450
453
  });
451
454
  },
452
- getTransparencyGridProps(props) {
453
- const { size } = props;
455
+ getTransparencyGridProps(props = {}) {
456
+ const { size = "12px" } = props;
454
457
  return normalize.element({
455
- ...parts.transparancyGrid.attrs,
458
+ ...parts.transparencyGrid.attrs,
456
459
  style: {
457
460
  "--size": size,
458
461
  width: "100%",
@@ -501,7 +504,12 @@ function connect(state, send, normalize) {
501
504
  style: {
502
505
  position: "relative",
503
506
  forcedColorAdjust: "none",
504
- backgroundImage: getSliderBackground(state.context, { orientation, channel })
507
+ backgroundImage: getSliderBackground({
508
+ orientation,
509
+ channel,
510
+ dir: state.context.dir,
511
+ value
512
+ })
505
513
  }
506
514
  });
507
515
  },
@@ -583,6 +591,7 @@ function connect(state, send, normalize) {
583
591
  const range = getChannelRange(value, channel);
584
592
  return normalize.input({
585
593
  ...parts.channelInput.attrs,
594
+ dir: state.context.dir,
586
595
  type: isTextField ? "text" : "number",
587
596
  "data-channel": channel,
588
597
  "aria-label": channel,
@@ -635,6 +644,7 @@ function connect(state, send, normalize) {
635
644
  eyeDropperTriggerProps: normalize.button({
636
645
  ...parts.eyeDropperTrigger.attrs,
637
646
  type: "button",
647
+ dir: state.context.dir,
638
648
  disabled: isDisabled,
639
649
  "data-disabled": (0, import_dom_query2.dataAttr)(isDisabled),
640
650
  "aria-label": "Pick a color from the screen",
@@ -654,6 +664,7 @@ function connect(state, send, normalize) {
654
664
  return normalize.button({
655
665
  ...parts.swatchTrigger.attrs,
656
666
  disabled: isDisabled,
667
+ dir: state.context.dir,
657
668
  type: "button",
658
669
  "data-value": color.toString("hex"),
659
670
  onClick() {
@@ -672,6 +683,7 @@ function connect(state, send, normalize) {
672
683
  const color = colorValue.toFormat(value.getFormat());
673
684
  return normalize.element({
674
685
  ...parts.swatch.attrs,
686
+ dir: state.context.dir,
675
687
  "data-state": colorValue.isEqual(value) ? "selected" : "unselected",
676
688
  "data-value": color.toString("hex"),
677
689
  style: {
@@ -697,7 +709,14 @@ var import_utils2 = require("@zag-js/utils");
697
709
  // src/color-picker.parse.ts
698
710
  var import_color_utils4 = require("@zag-js/color-utils");
699
711
  var import_core = require("@zag-js/core");
700
- var parse = (color) => (0, import_core.ref)((0, import_color_utils4.parseColor)(color));
712
+ var parse = (color) => {
713
+ const value = (0, import_color_utils4.parseColor)(color);
714
+ const colorFormat = value.getFormat();
715
+ const lockedFormat = colorFormat.startsWith("hsl") ? "hsla" : "hsba";
716
+ const result = value.toFormat(lockedFormat);
717
+ result.outputFormat = colorFormat;
718
+ return (0, import_core.ref)(result);
719
+ };
701
720
 
702
721
  // src/color-picker.machine.ts
703
722
  var { stateIn } = import_core2.guards;
@@ -726,7 +745,10 @@ function machine(userContext) {
726
745
  isRtl: (ctx2) => ctx2.dir === "rtl",
727
746
  isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
728
747
  isInteractive: (ctx2) => !(ctx2.isDisabled || ctx2.readOnly),
729
- valueAsString: (ctx2) => ctx2.value.toString("css")
748
+ valueAsString: (ctx2) => {
749
+ const color = ctx2.value.outputFormat ? ctx2.value.toFormat(ctx2.value.outputFormat) : ctx2.value;
750
+ return color.toString("css");
751
+ }
730
752
  },
731
753
  activities: ["trackFormControl"],
732
754
  watch: {
@@ -1040,10 +1062,9 @@ function machine(userContext) {
1040
1062
  return;
1041
1063
  }
1042
1064
  if (isTextField) {
1043
- const format = "hsl";
1044
1065
  const currentAlpha = ctx2.value.getChannelValue("alpha");
1045
1066
  const color2 = (0, import_utils2.tryCatch)(
1046
- () => (0, import_color_utils5.parseColor)(value).toFormat(format).withChannelValue("alpha", currentAlpha),
1067
+ () => parse(value).withChannelValue("alpha", currentAlpha),
1047
1068
  () => ctx2.value
1048
1069
  );
1049
1070
  const inputEl = dom.getChannelInputEl(ctx2, channel);
@@ -1051,7 +1072,7 @@ function machine(userContext) {
1051
1072
  set.value(ctx2, color2);
1052
1073
  return;
1053
1074
  }
1054
- const color = ctx2.value.withChannelValue(channel, value);
1075
+ const color = ctx2.value.toFormat(ctx2.value.outputFormat).withChannelValue(channel, value);
1055
1076
  set.value(ctx2, color);
1056
1077
  },
1057
1078
  incrementChannel(ctx2, evt) {
@@ -1121,6 +1142,9 @@ function machine(userContext) {
1121
1142
  toggleVisibility(ctx2, _evt, { send }) {
1122
1143
  send({ type: ctx2.open ? "OPEN" : "CLOSE", src: "controlled" });
1123
1144
  }
1145
+ },
1146
+ compareFns: {
1147
+ value: (a, b) => a.isEqual(b)
1124
1148
  }
1125
1149
  }
1126
1150
  );
@@ -1154,7 +1178,13 @@ var set = {
1154
1178
  sync.inputs(ctx);
1155
1179
  if (!color || ctx.value.isEqual(color))
1156
1180
  return;
1157
- ctx.value = (0, import_core2.ref)(color);
1181
+ const currentFormat = ctx.value.getFormat();
1182
+ const outputColor = color.toFormat(currentFormat);
1183
+ try {
1184
+ outputColor.outputFormat = ctx.value.outputFormat;
1185
+ } catch {
1186
+ }
1187
+ ctx.value = (0, import_core2.ref)(outputColor);
1158
1188
  invoke.change(ctx);
1159
1189
  }
1160
1190
  };