@zag-js/color-picker 0.12.0 → 0.14.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.
@@ -1,7 +1,8 @@
1
- import { type Color, parseColor } from "@zag-js/color-utils"
1
+ import { parseColor, type Color } from "@zag-js/color-utils"
2
2
  import { createMachine } from "@zag-js/core"
3
3
  import { trackPointerMove } from "@zag-js/dom-event"
4
4
  import { raf } from "@zag-js/dom-query"
5
+ import { trackFormControl } from "@zag-js/form-utils"
5
6
  import { clampValue, getPercentValue, snapValueToStep } from "@zag-js/numeric-range"
6
7
  import { disableTextSelection } from "@zag-js/text-selection"
7
8
  import { compact } from "@zag-js/utils"
@@ -24,12 +25,12 @@ export function machine(userContext: UserDefinedContext) {
24
25
  activeOrientation: null,
25
26
  value: "#D9D9D9",
26
27
  ...ctx,
27
- valueAsColor: parseColor(ctx.value || "#D9D9D9"),
28
28
  },
29
29
 
30
30
  computed: {
31
31
  isRtl: (ctx) => ctx.dir === "rtl",
32
32
  isInteractive: (ctx) => !(ctx.disabled || ctx.readOnly),
33
+ valueAsColor: (ctx) => parseColor(ctx.value),
33
34
  },
34
35
 
35
36
  on: {
@@ -38,10 +39,10 @@ export function machine(userContext: UserDefinedContext) {
38
39
  },
39
40
  },
40
41
 
41
- created: ["setValueAsColor"],
42
+ activities: ["trackFormControl"],
42
43
 
43
44
  watch: {
44
- value: ["setValueAsColor", "syncChannelInputs", "invokeOnChange"],
45
+ value: ["syncInputElements", "invokeOnChange"],
45
46
  },
46
47
 
47
48
  states: {
@@ -62,6 +63,10 @@ export function machine(userContext: UserDefinedContext) {
62
63
  target: "dragging",
63
64
  actions: ["setActiveChannel", "setChannelColorFromPoint", "focusChannelThumb"],
64
65
  },
66
+ "CHANNEL_SLIDER.FOCUS": {
67
+ target: "focused",
68
+ actions: ["setActiveChannel"],
69
+ },
65
70
  "CHANNEL_INPUT.FOCUS": {
66
71
  target: "focused",
67
72
  actions: ["setActiveChannel"],
@@ -174,6 +179,17 @@ export function machine(userContext: UserDefinedContext) {
174
179
  isTextField: (_ctx, evt) => !!evt.isTextField,
175
180
  },
176
181
  activities: {
182
+ trackFormControl(ctx, _evt, { send, initialContext }) {
183
+ const inputEl = dom.getHiddenInputEl(ctx)
184
+ return trackFormControl(inputEl, {
185
+ onFieldsetDisabled() {
186
+ ctx.disabled = true
187
+ },
188
+ onFormReset() {
189
+ send({ type: "VALUE.SET", value: initialContext.value, src: "form.reset" })
190
+ },
191
+ })
192
+ },
177
193
  trackPointerMove(ctx, _evt, { send }) {
178
194
  return trackPointerMove(dom.getDoc(ctx), {
179
195
  onPointerMove({ point }) {
@@ -224,6 +240,8 @@ export function machine(userContext: UserDefinedContext) {
224
240
  const { xChannel, yChannel } = evt.channel || ctx.activeChannel
225
241
 
226
242
  const percent = dom.getAreaValueFromPoint(ctx, evt.point)
243
+ if (!percent) return
244
+
227
245
  const { getColorFromPoint } = getChannelDetails(ctx.valueAsColor, xChannel, yChannel)
228
246
  const color = getColorFromPoint(percent.x, percent.y)
229
247
 
@@ -232,7 +250,9 @@ export function machine(userContext: UserDefinedContext) {
232
250
  },
233
251
  setChannelColorFromPoint(ctx, evt) {
234
252
  const channel = evt.channel || ctx.activeId
253
+
235
254
  const percent = dom.getChannelSliderValueFromPoint(ctx, evt.point, channel)
255
+ if (!percent) return
236
256
 
237
257
  const { minValue, maxValue, step } = ctx.valueAsColor.getChannelRange(channel)
238
258
  const orientation = ctx.activeOrientation || "horizontal"
@@ -248,21 +268,19 @@ export function machine(userContext: UserDefinedContext) {
248
268
  setValue(ctx, evt) {
249
269
  setColor(ctx, evt.value)
250
270
  },
251
- setValueAsColor(ctx) {
252
- try {
253
- const color = parseColor(ctx.value)
254
- if (color.isEqual(ctx.valueAsColor)) return
255
- ctx.valueAsColor = color
256
- } catch {}
257
- },
258
- syncChannelInputs(ctx) {
271
+ syncInputElements(ctx) {
272
+ // sync channel inputs
259
273
  const inputs = dom.getChannelInputEls(ctx)
260
274
  inputs.forEach((input) => {
261
- const channel = input.getAttribute("data-channel") as ExtendedColorChannel | null
275
+ const channel = input.dataset.channel as ExtendedColorChannel | null
262
276
  if (!channel) return
263
- const value = getChannelInputValue(ctx.valueAsColor, channel)
264
- input.value = value.toString()
277
+ input.value = getChannelInputValue(ctx.valueAsColor, channel)
265
278
  })
279
+
280
+ // sync hidden input
281
+ const hiddenInput = dom.getHiddenInputEl(ctx)
282
+ if (!hiddenInput) return
283
+ hiddenInput.value = ctx.value
266
284
  },
267
285
  setChannelColorFromInput(ctx, evt) {
268
286
  const { channel, isTextField, value } = evt
@@ -358,5 +376,4 @@ export function machine(userContext: UserDefinedContext) {
358
376
 
359
377
  const setColor = (ctx: MachineContext, color: Color) => {
360
378
  ctx.value = color.toString("css")
361
- ctx.valueAsColor = color
362
379
  }
@@ -39,6 +39,8 @@ type ElementIds = Partial<{
39
39
  channelSliderThumb(id: ColorChannel): string
40
40
  }>
41
41
 
42
+ export type { Color, ColorAxes, ColorChannel, ColorFormat, ColorType }
43
+
42
44
  type PublicContext = CommonProperties & {
43
45
  /**
44
46
  * The ids of the elements in the color picker. Useful for composition.
@@ -68,8 +70,54 @@ type PublicContext = CommonProperties & {
68
70
  * Handler that is called when the user stops dragging.
69
71
  */
70
72
  onChangeEnd?: (details: ChangeDetails) => void
73
+ /**
74
+ * The name for the form input
75
+ */
76
+ name?: string
71
77
  }
72
78
 
79
+ type PrivateContext = Context<{
80
+ /**
81
+ * The id of the thumb that is currently being dragged
82
+ */
83
+ activeId: string | null
84
+ /**
85
+ * The channel that is currently being interacted with
86
+ */
87
+ activeChannel: Partial<ColorAxes> | null
88
+ /**
89
+ * The orientation of the channel that is currently being interacted with
90
+ */
91
+ activeOrientation: Orientation | null
92
+ }>
93
+
94
+ type ComputedContext = Readonly<{
95
+ /**
96
+ * Whether the color picker is in RTL mode
97
+ */
98
+ isRtl: boolean
99
+ /**
100
+ * Whether the color picker is interactive
101
+ */
102
+ isInteractive: boolean
103
+ /**
104
+ * The color value as a Color object
105
+ */
106
+ valueAsColor: Color
107
+ }>
108
+
109
+ export type UserDefinedContext = RequiredBy<PublicContext, "id">
110
+
111
+ export type MachineContext = PublicContext & PrivateContext & ComputedContext
112
+
113
+ export type MachineState = {
114
+ value: "idle" | "focused" | "dragging"
115
+ }
116
+
117
+ export type State = S.State<MachineContext, MachineState>
118
+
119
+ export type Send = S.Send<S.AnyEventObject>
120
+
73
121
  export type PublicApi<T extends PropTypes = PropTypes> = {
74
122
  /**
75
123
  * Whether the color picker is being dragged
@@ -83,6 +131,10 @@ export type PublicApi<T extends PropTypes = PropTypes> = {
83
131
  * The current color value (as a Color object)
84
132
  */
85
133
  valueAsColor: Color
134
+ /**
135
+ * The alpha value of the color
136
+ */
137
+ alpha: number
86
138
  /**
87
139
  * The current color channels of the color
88
140
  */
@@ -99,7 +151,12 @@ export type PublicApi<T extends PropTypes = PropTypes> = {
99
151
  * Function to set the color format
100
152
  */
101
153
  setFormat(format: ColorFormat): void
154
+ /**
155
+ * Function to set the color alpha
156
+ */
157
+ setAlpha(value: number): void
102
158
  contentProps: T["element"]
159
+ hiddenInputProps: T["input"]
103
160
  getAreaProps(props: ColorAreaProps): T["element"]
104
161
  getAreaGradientProps(props: ColorAreaProps): T["element"]
105
162
  getAreaThumbProps(props: ColorAreaProps): T["element"]
@@ -111,47 +168,3 @@ export type PublicApi<T extends PropTypes = PropTypes> = {
111
168
  getSwatchBackgroundProps(props: ColorSwatchProps): T["element"]
112
169
  getSwatchProps(props: ColorSwatchProps): T["element"]
113
170
  }
114
-
115
- type PrivateContext = Context<{
116
- /**
117
- * The id of the thumb that is currently being dragged
118
- */
119
- activeId: string | null
120
- /**
121
- * The color value as a Color object
122
- */
123
- valueAsColor: Color
124
- /**
125
- * The channel that is currently being interacted with
126
- */
127
- activeChannel: Partial<ColorAxes> | null
128
- /**
129
- * The orientation of the channel that is currently being interacted with
130
- */
131
- activeOrientation: Orientation | null
132
- }>
133
-
134
- type ComputedContext = Readonly<{
135
- /**
136
- * Whether the color picker is in RTL mode
137
- */
138
- isRtl: boolean
139
- /**
140
- * Whether the color picker is interactive
141
- */
142
- isInteractive: boolean
143
- }>
144
-
145
- export type UserDefinedContext = RequiredBy<PublicContext, "id">
146
-
147
- export type MachineContext = PublicContext & PrivateContext & ComputedContext
148
-
149
- export type MachineState = {
150
- value: "idle" | "focused" | "dragging"
151
- }
152
-
153
- export type State = S.State<MachineContext, MachineState>
154
-
155
- export type Send = S.Send<S.AnyEventObject>
156
-
157
- export type { Color, ColorAxes, ColorChannel, ColorFormat, ColorType }