@react-aria/color 3.0.0-beta.0 → 3.0.0-beta.11

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.
@@ -15,11 +15,14 @@ import {ColorFieldState} from '@react-stately/color';
15
15
  import {
16
16
  HTMLAttributes,
17
17
  LabelHTMLAttributes,
18
- RefObject
18
+ RefObject,
19
+ useCallback,
20
+ useState
19
21
  } from 'react';
20
22
  import {mergeProps, useId} from '@react-aria/utils';
23
+ import {useFocusWithin, useScrollWheel} from '@react-aria/interactions';
24
+ import {useFormattedTextField} from '@react-aria/textfield';
21
25
  import {useSpinButton} from '@react-aria/spinbutton';
22
- import {useTextField} from '@react-aria/textfield';
23
26
 
24
27
  interface ColorFieldAria {
25
28
  /** Props for the label element. */
@@ -46,7 +49,6 @@ export function useColorField(
46
49
  let {
47
50
  colorValue,
48
51
  inputValue,
49
- setInputValue,
50
52
  commit,
51
53
  increment,
52
54
  decrement,
@@ -71,37 +73,48 @@ export function useColorField(
71
73
  }
72
74
  );
73
75
 
74
- let onWheel = (e) => {
75
- if (isDisabled || isReadOnly) {
76
+ let [focusWithin, setFocusWithin] = useState(false);
77
+ let {focusWithinProps} = useFocusWithin({isDisabled, onFocusWithinChange: setFocusWithin});
78
+
79
+ let onWheel = useCallback((e) => {
80
+ if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) {
76
81
  return;
77
82
  }
78
- if (e.deltaY < 0) {
83
+ if (e.deltaY > 0) {
79
84
  increment();
80
- } else {
85
+ } else if (e.deltaY < 0) {
81
86
  decrement();
82
87
  }
88
+ }, [decrement, increment]);
89
+ // If the input isn't supposed to receive input, disable scrolling.
90
+ let scrollingDisabled = isDisabled || isReadOnly || !focusWithin;
91
+ useScrollWheel({onScroll: onWheel, isDisabled: scrollingDisabled}, ref);
92
+
93
+ let onChange = value => {
94
+ state.setInputValue(value);
83
95
  };
84
96
 
85
- let {labelProps, inputProps} = useTextField(
97
+ let {labelProps, inputProps} = useFormattedTextField(
86
98
  mergeProps(props, {
87
99
  id: inputId,
88
100
  value: inputValue,
101
+ defaultValue: undefined,
89
102
  type: 'text',
90
103
  autoComplete: 'off',
91
- onChange: setInputValue
92
- }), ref);
104
+ onChange
105
+ }), state, ref);
93
106
 
94
107
  return {
95
108
  labelProps,
96
- inputProps: mergeProps(inputProps, spinButtonProps, {
109
+ inputProps: mergeProps(inputProps, spinButtonProps, focusWithinProps, {
97
110
  role: 'textbox',
98
111
  'aria-valuemax': null,
99
112
  'aria-valuemin': null,
100
113
  'aria-valuenow': null,
101
114
  'aria-valuetext': null,
102
115
  autoCorrect: 'off',
103
- onBlur: commit,
104
- onWheel
116
+ spellCheck: 'false',
117
+ onBlur: commit
105
118
  })
106
119
  };
107
120
  }
@@ -33,8 +33,6 @@ interface ColorWheelAria {
33
33
  inputProps: InputHTMLAttributes<HTMLInputElement>
34
34
  }
35
35
 
36
- const PAGE_MIN_STEP_SIZE = 6;
37
-
38
36
  /**
39
37
  * Provides the behavior and accessibility implementation for a color wheel component.
40
38
  * Color wheels allow users to adjust the hue of an HSL or HSB color value on a circular track.
@@ -42,7 +40,6 @@ const PAGE_MIN_STEP_SIZE = 6;
42
40
  export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState, inputRef: RefObject<HTMLElement>): ColorWheelAria {
43
41
  let {
44
42
  isDisabled,
45
- step = 1,
46
43
  innerRadius,
47
44
  outerRadius,
48
45
  'aria-label': ariaLabel
@@ -62,12 +59,38 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
62
59
  stateRef.current = state;
63
60
 
64
61
  let currentPosition = useRef<{x: number, y: number}>(null);
62
+
63
+ let {keyboardProps} = useKeyboard({
64
+ onKeyDown(e) {
65
+ // these are the cases that useMove doesn't handle
66
+ if (!/^(PageUp|PageDown)$/.test(e.key)) {
67
+ e.continuePropagation();
68
+ return;
69
+ }
70
+ // same handling as useMove, don't need to stop propagation, useKeyboard will do that for us
71
+ e.preventDefault();
72
+ // remember to set this and unset it so that onChangeEnd is fired
73
+ stateRef.current.setDragging(true);
74
+ switch (e.key) {
75
+ case 'PageUp':
76
+ e.preventDefault();
77
+ state.increment(stateRef.current.pageStep);
78
+ break;
79
+ case 'PageDown':
80
+ e.preventDefault();
81
+ state.decrement(stateRef.current.pageStep);
82
+ break;
83
+ }
84
+ stateRef.current.setDragging(false);
85
+ }
86
+ });
87
+
65
88
  let moveHandler = {
66
89
  onMoveStart() {
67
90
  currentPosition.current = null;
68
91
  state.setDragging(true);
69
92
  },
70
- onMove({deltaX, deltaY, pointerType}) {
93
+ onMove({deltaX, deltaY, pointerType, shiftKey}) {
71
94
  if (currentPosition.current == null) {
72
95
  currentPosition.current = stateRef.current.getThumbPosition(thumbRadius);
73
96
  }
@@ -75,9 +98,9 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
75
98
  currentPosition.current.y += deltaY;
76
99
  if (pointerType === 'keyboard') {
77
100
  if (deltaX > 0 || deltaY < 0) {
78
- state.increment();
101
+ state.increment(shiftKey ? stateRef.current.pageStep : stateRef.current.step);
79
102
  } else if (deltaX < 0 || deltaY > 0) {
80
- state.decrement();
103
+ state.decrement(shiftKey ? stateRef.current.pageStep : stateRef.current.step);
81
104
  }
82
105
  } else {
83
106
  stateRef.current.setHueFromPoint(currentPosition.current.x, currentPosition.current.y, thumbRadius);
@@ -116,9 +139,13 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
116
139
  currentPointer.current = id;
117
140
  focusInput();
118
141
  state.setDragging(true);
119
- addGlobalListener(window, 'mouseup', onThumbUp, false);
120
- addGlobalListener(window, 'touchend', onThumbUp, false);
121
- addGlobalListener(window, 'pointerup', onThumbUp, false);
142
+
143
+ if (typeof PointerEvent !== 'undefined') {
144
+ addGlobalListener(window, 'pointerup', onThumbUp, false);
145
+ } else {
146
+ addGlobalListener(window, 'mouseup', onThumbUp, false);
147
+ addGlobalListener(window, 'touchend', onThumbUp, false);
148
+ }
122
149
  }
123
150
  };
124
151
 
@@ -130,9 +157,12 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
130
157
  currentPointer.current = undefined;
131
158
  isOnTrack.current = false;
132
159
 
133
- removeGlobalListener(window, 'mouseup', onThumbUp, false);
134
- removeGlobalListener(window, 'touchend', onThumbUp, false);
135
- removeGlobalListener(window, 'pointerup', onThumbUp, false);
160
+ if (typeof PointerEvent !== 'undefined') {
161
+ removeGlobalListener(window, 'pointerup', onThumbUp, false);
162
+ } else {
163
+ removeGlobalListener(window, 'mouseup', onThumbUp, false);
164
+ removeGlobalListener(window, 'touchend', onThumbUp, false);
165
+ }
136
166
  }
137
167
  };
138
168
 
@@ -149,9 +179,12 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
149
179
  focusInput();
150
180
  state.setDragging(true);
151
181
 
152
- addGlobalListener(window, 'mouseup', onTrackUp, false);
153
- addGlobalListener(window, 'touchend', onTrackUp, false);
154
- addGlobalListener(window, 'pointerup', onTrackUp, false);
182
+ if (typeof PointerEvent !== 'undefined') {
183
+ addGlobalListener(window, 'pointerup', onTrackUp, false);
184
+ } else {
185
+ addGlobalListener(window, 'mouseup', onTrackUp, false);
186
+ addGlobalListener(window, 'touchend', onTrackUp, false);
187
+ }
155
188
  }
156
189
  };
157
190
 
@@ -163,43 +196,34 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
163
196
  state.setDragging(false);
164
197
  focusInput();
165
198
 
166
- removeGlobalListener(window, 'mouseup', onTrackUp, false);
167
- removeGlobalListener(window, 'touchend', onTrackUp, false);
168
- removeGlobalListener(window, 'pointerup', onTrackUp, false);
169
- }
170
- };
171
199
 
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;
200
+ if (typeof PointerEvent !== 'undefined') {
201
+ removeGlobalListener(window, 'pointerup', onTrackUp, false);
202
+ } else {
203
+ removeGlobalListener(window, 'mouseup', onTrackUp, false);
204
+ removeGlobalListener(window, 'touchend', onTrackUp, false);
183
205
  }
184
206
  }
185
- });
207
+ };
186
208
 
187
209
  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
- }
210
+ ...(typeof PointerEvent !== 'undefined' ? {
211
+ onPointerDown: (e: React.PointerEvent) => {
212
+ if (e.pointerType === 'mouse' && (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey)) {
213
+ return;
214
+ }
215
+ onTrackDown(e.currentTarget, e.pointerId, e.clientX, e.clientY);
216
+ }} : {
217
+ onMouseDown: (e: React.MouseEvent) => {
218
+ if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) {
219
+ return;
220
+ }
221
+ onTrackDown(e.currentTarget, undefined, e.clientX, e.clientY);
222
+ },
223
+ onTouchStart: (e: React.TouchEvent) => {
224
+ onTrackDown(e.currentTarget, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY);
225
+ }
226
+ })
203
227
  }, movePropsContainer);
204
228
 
205
229
  let thumbInteractions = isDisabled ? {} : mergeProps({
@@ -218,7 +242,7 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
218
242
  onTouchStart: (e: React.TouchEvent) => {
219
243
  onThumbDown(e.changedTouches[0].identifier);
220
244
  }
221
- }, movePropsThumb, keyboardProps);
245
+ }, keyboardProps, movePropsThumb);
222
246
  let {x, y} = state.getThumbPosition(thumbRadius);
223
247
 
224
248
  // Provide a default aria-label if none is given
@@ -232,6 +256,7 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
232
256
  'aria-label': ariaLabel
233
257
  });
234
258
 
259
+ let {minValue, maxValue, step} = state.value.getChannelRange('hue');
235
260
  return {
236
261
  trackProps: {
237
262
  ...trackInteractions,
@@ -275,8 +300,8 @@ export function useColorWheel(props: ColorWheelAriaProps, state: ColorWheelState
275
300
  inputLabellingProps,
276
301
  {
277
302
  type: 'range',
278
- min: '0',
279
- max: '360',
303
+ min: String(minValue),
304
+ max: String(maxValue),
280
305
  step: String(step),
281
306
  'aria-valuetext': state.value.formatChannelValue('hue', locale),
282
307
  disabled: isDisabled,