@react-aria/color 3.0.0-beta.3 → 3.0.0-beta.30

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.
@@ -12,40 +12,39 @@
12
12
 
13
13
  import {AriaColorWheelProps} from '@react-types/color';
14
14
  import {ColorWheelState} from '@react-stately/color';
15
- import {focusWithoutScrolling, mergeProps, useGlobalListeners, useLabels} from '@react-aria/utils';
16
- import React, {ChangeEvent, HTMLAttributes, InputHTMLAttributes, RefObject, useCallback, useRef} from 'react';
15
+ import {DOMAttributes} from '@react-types/shared';
16
+ import {focusWithoutScrolling, mergeProps, useFormReset, useGlobalListeners, useLabels} from '@react-aria/utils';
17
+ import React, {ChangeEvent, InputHTMLAttributes, RefObject, useCallback, useRef} from 'react';
17
18
  import {useKeyboard, useMove} from '@react-aria/interactions';
18
19
  import {useLocale} from '@react-aria/i18n';
19
20
 
20
- interface ColorWheelAriaProps extends AriaColorWheelProps {
21
+ export interface AriaColorWheelOptions extends AriaColorWheelProps {
21
22
  /** The outer radius of the color wheel. */
22
23
  outerRadius: number,
23
24
  /** The inner radius of the color wheel. */
24
25
  innerRadius: number
25
26
  }
26
27
 
27
- interface ColorWheelAria {
28
+ export interface ColorWheelAria {
28
29
  /** Props for the track element. */
29
- trackProps: HTMLAttributes<HTMLElement>,
30
+ trackProps: DOMAttributes,
30
31
  /** Props for the thumb element. */
31
- thumbProps: HTMLAttributes<HTMLElement>,
32
+ thumbProps: DOMAttributes,
32
33
  /** Props for the visually hidden range input element. */
33
34
  inputProps: InputHTMLAttributes<HTMLInputElement>
34
35
  }
35
36
 
36
- const PAGE_MIN_STEP_SIZE = 6;
37
-
38
37
  /**
39
38
  * Provides the behavior and accessibility implementation for a color wheel component.
40
39
  * Color wheels allow users to adjust the hue of an HSL or HSB color value on a circular track.
41
40
  */
42
- export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState, inputRef: RefObject<HTMLElement>): ColorWheelAria {
41
+ export function useColorWheel(props: AriaColorWheelOptions, state: ColorWheelState, inputRef: RefObject<HTMLInputElement>): ColorWheelAria {
43
42
  let {
44
43
  isDisabled,
45
- step = 1,
46
44
  innerRadius,
47
45
  outerRadius,
48
- 'aria-label': ariaLabel
46
+ 'aria-label': ariaLabel,
47
+ name
49
48
  } = props;
50
49
 
51
50
  let {addGlobalListener, removeGlobalListener} = useGlobalListeners();
@@ -58,33 +57,58 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
58
57
  }
59
58
  }, [inputRef]);
60
59
 
61
- let stateRef = useRef<ColorWheelState>(null);
62
- stateRef.current = state;
60
+ useFormReset(inputRef, state.hue, state.setHue);
61
+
62
+ let currentPosition = useRef<{x: number, y: number} | null>(null);
63
+
64
+ let {keyboardProps} = useKeyboard({
65
+ onKeyDown(e) {
66
+ // these are the cases that useMove doesn't handle
67
+ if (!/^(PageUp|PageDown)$/.test(e.key)) {
68
+ e.continuePropagation();
69
+ return;
70
+ }
71
+ // same handling as useMove, don't need to stop propagation, useKeyboard will do that for us
72
+ e.preventDefault();
73
+ // remember to set this and unset it so that onChangeEnd is fired
74
+ state.setDragging(true);
75
+ switch (e.key) {
76
+ case 'PageUp':
77
+ e.preventDefault();
78
+ state.increment(state.pageStep);
79
+ break;
80
+ case 'PageDown':
81
+ e.preventDefault();
82
+ state.decrement(state.pageStep);
83
+ break;
84
+ }
85
+ state.setDragging(false);
86
+ }
87
+ });
63
88
 
64
- let currentPosition = useRef<{x: number, y: number}>(null);
65
89
  let moveHandler = {
66
90
  onMoveStart() {
67
91
  currentPosition.current = null;
68
92
  state.setDragging(true);
69
93
  },
70
- onMove({deltaX, deltaY, pointerType}) {
94
+ onMove({deltaX, deltaY, pointerType, shiftKey}) {
71
95
  if (currentPosition.current == null) {
72
- currentPosition.current = stateRef.current.getThumbPosition(thumbRadius);
96
+ currentPosition.current = state.getThumbPosition(thumbRadius);
73
97
  }
74
98
  currentPosition.current.x += deltaX;
75
99
  currentPosition.current.y += deltaY;
76
100
  if (pointerType === 'keyboard') {
77
101
  if (deltaX > 0 || deltaY < 0) {
78
- state.increment();
102
+ state.increment(shiftKey ? state.pageStep : state.step);
79
103
  } else if (deltaX < 0 || deltaY > 0) {
80
- state.decrement();
104
+ state.decrement(shiftKey ? state.pageStep : state.step);
81
105
  }
82
106
  } else {
83
- stateRef.current.setHueFromPoint(currentPosition.current.x, currentPosition.current.y, thumbRadius);
107
+ state.setHueFromPoint(currentPosition.current.x, currentPosition.current.y, thumbRadius);
84
108
  }
85
109
  },
86
110
  onMoveEnd() {
87
- isOnTrack.current = undefined;
111
+ isOnTrack.current = false;
88
112
  state.setDragging(false);
89
113
  focusInput();
90
114
  }
@@ -111,14 +135,18 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
111
135
  }
112
136
  });
113
137
 
114
- let onThumbDown = (id: number | null) => {
138
+ let onThumbDown = (id: number | null | undefined) => {
115
139
  if (!state.isDragging) {
116
140
  currentPointer.current = id;
117
141
  focusInput();
118
142
  state.setDragging(true);
119
- addGlobalListener(window, 'mouseup', onThumbUp, false);
120
- addGlobalListener(window, 'touchend', onThumbUp, false);
121
- addGlobalListener(window, 'pointerup', onThumbUp, false);
143
+
144
+ if (typeof PointerEvent !== 'undefined') {
145
+ addGlobalListener(window, 'pointerup', onThumbUp, false);
146
+ } else {
147
+ addGlobalListener(window, 'mouseup', onThumbUp, false);
148
+ addGlobalListener(window, 'touchend', onThumbUp, false);
149
+ }
122
150
  }
123
151
  };
124
152
 
@@ -130,13 +158,16 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
130
158
  currentPointer.current = undefined;
131
159
  isOnTrack.current = false;
132
160
 
133
- removeGlobalListener(window, 'mouseup', onThumbUp, false);
134
- removeGlobalListener(window, 'touchend', onThumbUp, false);
135
- removeGlobalListener(window, 'pointerup', onThumbUp, false);
161
+ if (typeof PointerEvent !== 'undefined') {
162
+ removeGlobalListener(window, 'pointerup', onThumbUp, false);
163
+ } else {
164
+ removeGlobalListener(window, 'mouseup', onThumbUp, false);
165
+ removeGlobalListener(window, 'touchend', onThumbUp, false);
166
+ }
136
167
  }
137
168
  };
138
169
 
139
- let onTrackDown = (track: Element, id: number | null, pageX: number, pageY: number) => {
170
+ let onTrackDown = (track: Element, id: number | null | undefined, pageX: number, pageY: number) => {
140
171
  let rect = track.getBoundingClientRect();
141
172
  let x = pageX - rect.x - rect.width / 2;
142
173
  let y = pageY - rect.y - rect.height / 2;
@@ -144,14 +175,17 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
144
175
  if (innerRadius < radius && radius < outerRadius && !state.isDragging && currentPointer.current === undefined) {
145
176
  isOnTrack.current = true;
146
177
  currentPointer.current = id;
147
- stateRef.current.setHueFromPoint(x, y, radius);
178
+ state.setHueFromPoint(x, y, radius);
148
179
 
149
180
  focusInput();
150
181
  state.setDragging(true);
151
182
 
152
- addGlobalListener(window, 'mouseup', onTrackUp, false);
153
- addGlobalListener(window, 'touchend', onTrackUp, false);
154
- addGlobalListener(window, 'pointerup', onTrackUp, false);
183
+ if (typeof PointerEvent !== 'undefined') {
184
+ addGlobalListener(window, 'pointerup', onTrackUp, false);
185
+ } else {
186
+ addGlobalListener(window, 'mouseup', onTrackUp, false);
187
+ addGlobalListener(window, 'touchend', onTrackUp, false);
188
+ }
155
189
  }
156
190
  };
157
191
 
@@ -163,43 +197,34 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
163
197
  state.setDragging(false);
164
198
  focusInput();
165
199
 
166
- removeGlobalListener(window, 'mouseup', onTrackUp, false);
167
- removeGlobalListener(window, 'touchend', onTrackUp, false);
168
- removeGlobalListener(window, 'pointerup', onTrackUp, false);
169
- }
170
- };
171
200
 
172
- let {keyboardProps} = useKeyboard({
173
- onKeyDown(e) {
174
- switch (e.key) {
175
- case 'PageUp':
176
- e.preventDefault();
177
- state.increment(PAGE_MIN_STEP_SIZE);
178
- break;
179
- case 'PageDown':
180
- e.preventDefault();
181
- state.decrement(PAGE_MIN_STEP_SIZE);
182
- break;
201
+ if (typeof PointerEvent !== 'undefined') {
202
+ removeGlobalListener(window, 'pointerup', onTrackUp, false);
203
+ } else {
204
+ removeGlobalListener(window, 'mouseup', onTrackUp, false);
205
+ removeGlobalListener(window, 'touchend', onTrackUp, false);
183
206
  }
184
207
  }
185
- });
208
+ };
186
209
 
187
210
  let trackInteractions = isDisabled ? {} : mergeProps({
188
- onMouseDown: (e: React.MouseEvent) => {
189
- if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) {
190
- return;
191
- }
192
- onTrackDown(e.currentTarget, undefined, e.clientX, e.clientY);
193
- },
194
- onPointerDown: (e: React.PointerEvent) => {
195
- if (e.pointerType === 'mouse' && (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey)) {
196
- return;
197
- }
198
- onTrackDown(e.currentTarget, e.pointerId, e.clientX, e.clientY);
199
- },
200
- onTouchStart: (e: React.TouchEvent) => {
201
- onTrackDown(e.currentTarget, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY);
202
- }
211
+ ...(typeof PointerEvent !== 'undefined' ? {
212
+ onPointerDown: (e: React.PointerEvent) => {
213
+ if (e.pointerType === 'mouse' && (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey)) {
214
+ return;
215
+ }
216
+ onTrackDown(e.currentTarget, e.pointerId, e.clientX, e.clientY);
217
+ }} : {
218
+ onMouseDown: (e: React.MouseEvent) => {
219
+ if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) {
220
+ return;
221
+ }
222
+ onTrackDown(e.currentTarget, undefined, e.clientX, e.clientY);
223
+ },
224
+ onTouchStart: (e: React.TouchEvent) => {
225
+ onTrackDown(e.currentTarget, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY);
226
+ }
227
+ })
203
228
  }, movePropsContainer);
204
229
 
205
230
  let thumbInteractions = isDisabled ? {} : mergeProps({
@@ -218,7 +243,7 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
218
243
  onTouchStart: (e: React.TouchEvent) => {
219
244
  onThumbDown(e.changedTouches[0].identifier);
220
245
  }
221
- }, movePropsThumb, keyboardProps);
246
+ }, keyboardProps, movePropsThumb);
222
247
  let {x, y} = state.getThumbPosition(thumbRadius);
223
248
 
224
249
  // Provide a default aria-label if none is given
@@ -232,6 +257,12 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
232
257
  'aria-label': ariaLabel
233
258
  });
234
259
 
260
+ let {minValue, maxValue, step} = state.value.getChannelRange('hue');
261
+
262
+ let forcedColorAdjustNoneStyle = {
263
+ forcedColorAdjust: 'none'
264
+ };
265
+
235
266
  return {
236
267
  trackProps: {
237
268
  ...trackInteractions,
@@ -258,7 +289,8 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
258
289
  hsl(360, 100%, 50%)
259
290
  )
260
291
  `,
261
- clipPath: `path(evenodd, "${circlePath(outerRadius, outerRadius, outerRadius)} ${circlePath(outerRadius, outerRadius, innerRadius)}")`
292
+ clipPath: `path(evenodd, "${circlePath(outerRadius, outerRadius, outerRadius)} ${circlePath(outerRadius, outerRadius, innerRadius)}")`,
293
+ ...forcedColorAdjustNoneStyle
262
294
  }
263
295
  },
264
296
  thumbProps: {
@@ -268,19 +300,21 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
268
300
  left: '50%',
269
301
  top: '50%',
270
302
  transform: `translate(calc(${x}px - 50%), calc(${y}px - 50%))`,
271
- touchAction: 'none'
303
+ touchAction: 'none',
304
+ ...forcedColorAdjustNoneStyle
272
305
  }
273
306
  },
274
307
  inputProps: mergeProps(
275
308
  inputLabellingProps,
276
309
  {
277
310
  type: 'range',
278
- min: '0',
279
- max: '360',
311
+ min: String(minValue),
312
+ max: String(maxValue),
280
313
  step: String(step),
281
314
  'aria-valuetext': state.value.formatChannelValue('hue', locale),
282
315
  disabled: isDisabled,
283
316
  value: `${state.value.getChannelValue('hue')}`,
317
+ name,
284
318
  onChange: (e: ChangeEvent<HTMLInputElement>) => {
285
319
  state.setHue(parseFloat(e.target.value));
286
320
  }