@astryxdesign/core 0.7.8-canary.ffd29c5 → 0.7.8
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/CHANGELOG.md +132 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +30 -14
- package/dist/BottomSheet/bottomSheetStack.js +1 -1
- package/dist/BottomSheet/useSheetGestures.d.ts +3 -1
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +4 -0
- package/dist/CheckboxList/CheckboxList.d.ts +13 -2
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +10 -4
- package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListContext.js +2 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +14 -2
- package/dist/CheckboxList/requiredGroup.d.ts +22 -0
- package/dist/CheckboxList/requiredGroup.d.ts.map +1 -0
- package/dist/CheckboxList/requiredGroup.js +52 -0
- package/dist/DateInput/PickerWheel.d.ts +1 -1
- package/dist/DateInput/PickerWheel.d.ts.map +1 -1
- package/dist/DateInput/PickerWheel.js +27 -6
- package/dist/DateInput/Wheel.d.ts +2 -2
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +20 -6
- package/dist/DateInput/datePickerTouch.d.ts +13 -0
- package/dist/DateInput/datePickerTouch.d.ts.map +1 -0
- package/dist/DateInput/datePickerTouch.js +14 -0
- package/dist/DateInput/wheelOptions.d.ts +22 -2
- package/dist/DateInput/wheelOptions.d.ts.map +1 -1
- package/dist/DateInput/wheelOptions.js +14 -2
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +62 -119
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +6 -1
- package/dist/Overlay/Overlay.d.ts.map +1 -1
- package/dist/Overlay/Overlay.js +7 -2
- package/dist/PowerSearch/PowerSearch.d.ts +4 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +24 -1
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchBottomSheet.js +172 -50
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +15 -15
- package/dist/Resizable/createResizable.d.ts +70 -16
- package/dist/Resizable/createResizable.d.ts.map +1 -1
- package/dist/Resizable/createResizable.js +180 -22
- package/dist/Resizable/separatorAttributes.d.ts +45 -0
- package/dist/Resizable/separatorAttributes.d.ts.map +1 -0
- package/dist/Resizable/separatorAttributes.js +35 -0
- package/dist/Resizable/useResizable.js +2 -2
- package/dist/TimeInput/TimeWheels.d.ts +32 -0
- package/dist/TimeInput/TimeWheels.d.ts.map +1 -0
- package/dist/TimeInput/TimeWheels.js +144 -0
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +63 -118
- package/dist/TimeInput/timeWheelRules.d.ts +124 -0
- package/dist/TimeInput/timeWheelRules.d.ts.map +1 -0
- package/dist/TimeInput/timeWheelRules.js +277 -0
- package/dist/Tokenizer/TokenizerBottomSheet.js +8 -12
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +6 -0
- package/dist/astryx.css +3 -1
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +3 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +1 -1
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +5 -2
- package/dist/i18n/generated-english/Resizable/createResizable.generated.d.ts +8 -0
- package/dist/i18n/generated-english/Resizable/createResizable.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/Resizable/createResizable.generated.js +13 -0
- package/dist/i18n/generated-english/TimeInput/TimeWheels.generated.d.ts +8 -0
- package/dist/i18n/generated-english/TimeInput/TimeWheels.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/TimeInput/TimeWheels.generated.js +17 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +5 -2
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +5 -2
- package/dist/keyboard/index.d.ts +17 -0
- package/dist/keyboard/index.d.ts.map +1 -0
- package/dist/keyboard/index.js +19 -0
- package/dist/keyboard/keyboardHeight.d.ts +149 -0
- package/dist/keyboard/keyboardHeight.d.ts.map +1 -0
- package/dist/keyboard/keyboardHeight.js +432 -0
- package/dist/keyboard/keyboardLayoutGuide.d.ts +59 -0
- package/dist/keyboard/keyboardLayoutGuide.d.ts.map +1 -0
- package/dist/keyboard/keyboardLayoutGuide.js +207 -0
- package/dist/keyboard/keyboardModel.d.ts +93 -0
- package/dist/keyboard/keyboardModel.d.ts.map +1 -0
- package/dist/keyboard/keyboardModel.js +220 -0
- package/dist/keyboard/rideKeyboard.d.ts +42 -0
- package/dist/keyboard/rideKeyboard.d.ts.map +1 -0
- package/dist/keyboard/rideKeyboard.js +77 -0
- package/dist/keyboard/useMobileKeyboard.d.ts +61 -0
- package/dist/keyboard/useMobileKeyboard.d.ts.map +1 -0
- package/dist/keyboard/useMobileKeyboard.js +699 -0
- package/dist/motion/android/index.d.ts +16 -0
- package/dist/motion/android/index.d.ts.map +1 -0
- package/dist/motion/android/index.js +18 -0
- package/dist/motion/android/keyboard.d.ts +83 -0
- package/dist/motion/android/keyboard.d.ts.map +1 -0
- package/dist/motion/android/keyboard.js +96 -0
- package/dist/motion/uikit/datePicker.d.ts +58 -0
- package/dist/motion/uikit/datePicker.d.ts.map +1 -0
- package/dist/motion/uikit/datePicker.js +60 -0
- package/dist/motion/uikit/index.d.ts +4 -3
- package/dist/motion/uikit/index.d.ts.map +1 -1
- package/dist/motion/uikit/index.js +4 -3
- package/dist/utils/interactionOverlay.stylex.d.ts +3 -2
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +3 -2
- package/dist/utils/layoutViewport.d.ts +25 -0
- package/dist/utils/layoutViewport.d.ts.map +1 -0
- package/dist/utils/layoutViewport.js +102 -0
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +74 -9
- package/dist/utils/pressGesture.d.ts +4 -2
- package/dist/utils/pressGesture.d.ts.map +1 -1
- package/dist/utils/pressGesture.js +3 -1
- package/dist/utils/selectionLock.d.ts +10 -1
- package/dist/utils/selectionLock.d.ts.map +1 -1
- package/dist/utils/selectionLock.js +31 -5
- package/dist/utils/sharedMutationObserver.d.ts +2 -1
- package/dist/utils/sharedMutationObserver.d.ts.map +1 -1
- package/dist/utils/sharedMutationObserver.js +2 -1
- package/dist/utils/timeParser.d.ts +2 -1
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +29 -3
- package/locales/en.json +21 -9
- package/locales/pseudo.json +15 -6
- package/package.json +5 -5
- package/src/BottomSheet/BottomSheet.doc.mjs +1 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +41 -13
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +5 -0
- package/src/BottomSheet/bottomSheetStack.ts +1 -1
- package/src/BottomSheet/useSheetGestures.ts +6 -0
- package/src/CheckboxList/CheckboxList.doc.mjs +7 -0
- package/src/CheckboxList/CheckboxList.tsx +34 -2
- package/src/CheckboxList/CheckboxListContext.tsx +9 -1
- package/src/CheckboxList/CheckboxListItem.tsx +23 -2
- package/src/CheckboxList/requiredGroup.ts +77 -0
- package/src/DateInput/PickerWheel.tsx +37 -4
- package/src/DateInput/Wheel.tsx +30 -3
- package/src/DateInput/datePickerTouch.ts +15 -0
- package/src/DateInput/wheelOptions.ts +31 -2
- package/src/DateTimeInput/TouchDateTimeField.tsx +94 -178
- package/src/HoverCard/useHoverCard.tsx +6 -1
- package/src/Overlay/Overlay.tsx +7 -2
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearch.tsx +4 -2
- package/src/PowerSearch/PowerSearchBottomSheet.tsx +237 -62
- package/src/Resizable/ResizeHandle.tsx +18 -26
- package/src/Resizable/createResizable.ts +242 -27
- package/src/Resizable/separatorAttributes.ts +73 -0
- package/src/Resizable/useResizable.ts +2 -2
- package/src/TimeInput/TimeWheels.tsx +218 -0
- package/src/TimeInput/TouchTimeField.tsx +93 -157
- package/src/TimeInput/timeWheelRules.ts +352 -0
- package/src/Tokenizer/TokenizerBottomSheet.tsx +8 -12
- package/src/Tooltip/useTooltip.tsx +6 -0
- package/src/gestures/GestureHost.ts +5 -4
- package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +5 -2
- package/src/i18n/generated-english/Resizable/createResizable.generated.ts +14 -0
- package/src/i18n/generated-english/TimeInput/TimeWheels.generated.ts +18 -0
- package/src/i18n/generated-locales/en.generated.ts +6 -4
- package/src/i18n/generated-locales/pseudo.generated.ts +6 -4
- package/src/keyboard/README.md +197 -0
- package/src/keyboard/index.ts +48 -0
- package/src/keyboard/keyboardHeight.ts +543 -0
- package/src/keyboard/keyboardLayoutGuide.ts +266 -0
- package/src/keyboard/keyboardModel.ts +301 -0
- package/src/keyboard/rideKeyboard.ts +100 -0
- package/src/keyboard/useMobileKeyboard.ts +866 -0
- package/src/motion/MEASUREMENTS.md +10 -0
- package/src/motion/README.md +2 -0
- package/src/motion/android/index.ts +18 -0
- package/src/motion/android/keyboard.ts +96 -0
- package/src/motion/uikit/datePicker.ts +60 -0
- package/src/motion/uikit/index.ts +4 -3
- package/src/utils/interactionOverlay.stylex.ts +3 -2
- package/src/utils/layoutViewport.ts +104 -0
- package/src/utils/pressFeedback.ts +99 -21
- package/src/utils/pressGesture.ts +4 -2
- package/src/utils/selectionLock.ts +40 -6
- package/src/utils/sharedMutationObserver.ts +2 -1
- package/src/utils/timeParser.ts +40 -3
- package/dist/BottomSheet/useMobileKeyboard.d.ts +0 -21
- package/dist/BottomSheet/useMobileKeyboard.d.ts.map +0 -1
- package/dist/BottomSheet/useMobileKeyboard.js +0 -413
- package/src/BottomSheet/useMobileKeyboard.ts +0 -542
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file createResizable.ts
|
|
5
|
-
* @input A region
|
|
5
|
+
* @input A handle element, or null for a region with no handle yet, and the
|
|
6
|
+
* region's options
|
|
6
7
|
* @output createResizable; readInitialResizableState for the hook's first
|
|
7
|
-
* render; createResizableAs and the internal channel for the
|
|
8
|
-
* @position The Resizable family's
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* render; createResizableAs and the internal channel for the hooks
|
|
9
|
+
* @position The Resizable family's factory, internal to the package. Its
|
|
10
|
+
* input is resizeGesture.ts: it listens with it on a plain handle, and
|
|
11
|
+
* ResizeHandle drives the region through its model. The
|
|
12
|
+
* configuration-object useResizable builds on it. No DOM work on import
|
|
11
13
|
*/
|
|
12
14
|
|
|
15
|
+
import {registerEnglishFallback} from '../i18n/englishFallback';
|
|
16
|
+
import english from '../i18n/generated-english/Resizable/createResizable.generated';
|
|
13
17
|
import {observeResize} from '../utils/sharedResizeObserver';
|
|
14
18
|
import {devWarn} from '../utils/devWarning';
|
|
15
19
|
import type {SizeValue} from '../utils/types';
|
|
@@ -29,9 +33,26 @@ import {
|
|
|
29
33
|
type PersistedResizableState,
|
|
30
34
|
type ResizableDirection,
|
|
31
35
|
} from './resizableModel';
|
|
32
|
-
import
|
|
36
|
+
import {
|
|
37
|
+
createResizeGesture,
|
|
38
|
+
type ResizeGesture,
|
|
39
|
+
type ResizeGestureModel,
|
|
40
|
+
type ResizeGestureState,
|
|
41
|
+
} from './resizeGesture';
|
|
42
|
+
import {separatorAttributes} from './separatorAttributes';
|
|
33
43
|
import type {ResizableSize} from './utils';
|
|
34
44
|
|
|
45
|
+
// The English for the two messages it names, and nothing more of the catalog.
|
|
46
|
+
registerEnglishFallback(english);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The catalog's messages for a plain handle: its name and what it announces
|
|
50
|
+
* while collapsed, when the options give neither `label` nor
|
|
51
|
+
* `collapsedLabel`. The factory uses the shipped English messages.
|
|
52
|
+
*/
|
|
53
|
+
const LABEL_KEY = '@astryx.resizable.handle.label';
|
|
54
|
+
const COLLAPSED_LABEL_KEY = '@astryx.resizable.collapsed';
|
|
55
|
+
|
|
35
56
|
export interface CreateResizableOptions {
|
|
36
57
|
/**
|
|
37
58
|
* Initial size. A number or an exact `Npx` is pixels, and an exact `N%` is
|
|
@@ -72,6 +93,31 @@ export interface CreateResizableOptions {
|
|
|
72
93
|
onSizeChange?: (size: number) => void;
|
|
73
94
|
/** Called when an interaction collapses or expands the region. */
|
|
74
95
|
onCollapseChange?: (isCollapsed: boolean) => void;
|
|
96
|
+
/**
|
|
97
|
+
* The handle sits before the panel it resizes (the panel is at the end), so
|
|
98
|
+
* a drag toward the start grows it.
|
|
99
|
+
* @default false
|
|
100
|
+
*/
|
|
101
|
+
isReversed?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Ignores pointer and keyboard input and says so; a plain element keeps its
|
|
104
|
+
* tab stop.
|
|
105
|
+
* @default false
|
|
106
|
+
*/
|
|
107
|
+
isDisabled?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* A plain element's accessible name, when it has none of its own. Without
|
|
110
|
+
* it, the factory uses the message catalog's English message.
|
|
111
|
+
* @default 'Resize handle'
|
|
112
|
+
*/
|
|
113
|
+
label?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Replaces the catalog's "Collapsed" that the handle announces as its
|
|
116
|
+
* `aria-valuetext` while the region is collapsed. Absent, the factory
|
|
117
|
+
* announces the shipped English message.
|
|
118
|
+
* @default 'Collapsed'
|
|
119
|
+
*/
|
|
120
|
+
collapsedLabel?: string;
|
|
75
121
|
}
|
|
76
122
|
|
|
77
123
|
export interface ResizableController {
|
|
@@ -96,7 +142,10 @@ export interface ResizableController {
|
|
|
96
142
|
* that stops it.
|
|
97
143
|
*/
|
|
98
144
|
subscribe(listener: () => void): () => void;
|
|
99
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Removes every listener, observer and attribute the factory added and the
|
|
147
|
+
* body's drag cursor; a drag in flight ends as cancelled.
|
|
148
|
+
*/
|
|
100
149
|
destroy(): void;
|
|
101
150
|
}
|
|
102
151
|
|
|
@@ -113,12 +162,12 @@ function readWindowExtent(direction: ResizableDirection): number | null {
|
|
|
113
162
|
return direction === 'vertical' ? window.innerHeight : window.innerWidth;
|
|
114
163
|
}
|
|
115
164
|
|
|
116
|
-
/**
|
|
165
|
+
/** Starts as warned: the factory warns, and this first-render read does not. */
|
|
117
166
|
const QUIET = {current: true};
|
|
118
167
|
|
|
119
168
|
/**
|
|
120
|
-
* The state a region with `options` starts in
|
|
121
|
-
* hook's first render. A container is not measured
|
|
169
|
+
* The state a region with `options` starts in, before its handle exists: the
|
|
170
|
+
* server's render and a hook's first render. A container is not measured
|
|
122
171
|
* yet, so a percentage of it resolves against the deterministic 1200px basis
|
|
123
172
|
* until the factory measures it. `'server'` reads the state the server
|
|
124
173
|
* rendered, for a render that hydrates it: the 1200px basis for a viewport
|
|
@@ -239,16 +288,16 @@ interface ResizableInternals {
|
|
|
239
288
|
syncContainer(): void;
|
|
240
289
|
/**
|
|
241
290
|
* Lets go of the page and keeps the region. A gesture in flight ends as
|
|
242
|
-
* cancelled, and the
|
|
243
|
-
* and report. For a React caller
|
|
244
|
-
* `<Activity>` hides.
|
|
291
|
+
* cancelled, and the handle's listeners, its attributes and the observers
|
|
292
|
+
* go. Collapse, expand and resize still apply and report. For a React caller
|
|
293
|
+
* whose component unmounts or an `<Activity>` hides.
|
|
245
294
|
*/
|
|
246
295
|
suspend(): void;
|
|
247
|
-
/** Takes the page back after `suspend`: the observers. */
|
|
296
|
+
/** Takes the page back after `suspend`: the handle, and the observers. */
|
|
248
297
|
resume(): void;
|
|
249
298
|
/**
|
|
250
|
-
* The region's side of a
|
|
251
|
-
* ResizeHandle given the configuration object's props.
|
|
299
|
+
* The region's side of a gesture the factory does not own: the drag and
|
|
300
|
+
* keys of a ResizeHandle given the configuration object's props.
|
|
252
301
|
*/
|
|
253
302
|
model: ResizeGestureModel;
|
|
254
303
|
}
|
|
@@ -262,16 +311,64 @@ export function readResizableInternals(
|
|
|
262
311
|
return internals.get(controller);
|
|
263
312
|
}
|
|
264
313
|
|
|
314
|
+
/** An attribute's value as the DOM takes it; undefined removes it. */
|
|
315
|
+
function toAttribute(
|
|
316
|
+
value: string | number | boolean | undefined,
|
|
317
|
+
): string | null {
|
|
318
|
+
return value == null ? null : String(value);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** The attributes the factory writes on a handle, restored by `destroy`. */
|
|
322
|
+
const MANAGED_ATTRIBUTES = [
|
|
323
|
+
'role',
|
|
324
|
+
'tabindex',
|
|
325
|
+
'aria-label',
|
|
326
|
+
'aria-orientation',
|
|
327
|
+
'aria-valuenow',
|
|
328
|
+
'aria-valuemin',
|
|
329
|
+
'aria-valuemax',
|
|
330
|
+
'aria-valuetext',
|
|
331
|
+
'aria-disabled',
|
|
332
|
+
'data-resizing',
|
|
333
|
+
] as const;
|
|
334
|
+
|
|
265
335
|
/**
|
|
266
|
-
*
|
|
267
|
-
* reports the size, and the caller applies it.
|
|
268
|
-
*
|
|
269
|
-
* `
|
|
336
|
+
* Make `handle` a window splitter that resizes a region. The factory never
|
|
337
|
+
* sizes the panel: it reports the size, and the caller applies it.
|
|
338
|
+
*
|
|
339
|
+
* It gives the handle `role="separator"`, its orientation and its value. It
|
|
340
|
+
* adds a tab stop and an accessible name when the handle has none. It answers
|
|
341
|
+
* a pointer drag, the arrow keys, Home and End, and holds the pointer for a
|
|
342
|
+
* whole drag. Enter and a double-click collapse and restore. A horizontal
|
|
343
|
+
* region resizes along the inline axis, and under right-to-left the drag
|
|
344
|
+
* follows the pointer. `destroy` takes all of it away. With a null handle the
|
|
345
|
+
* region still answers collapse, expand, resize and subscribe, and touches no
|
|
346
|
+
* element. Outside a provider, its name and its collapsed text are the
|
|
347
|
+
* shipped English messages. `label` names it, and `collapsedLabel` replaces
|
|
348
|
+
* its collapsed text in another language.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```
|
|
352
|
+
* const sidebar = document.querySelector('#sidebar');
|
|
353
|
+
* const resizable = createResizable(document.querySelector('#divider'), {
|
|
354
|
+
* defaultSize: 260,
|
|
355
|
+
* minSize: 180,
|
|
356
|
+
* maxSize: 480,
|
|
357
|
+
* collapsible: true,
|
|
358
|
+
* autoSaveId: 'sidebar',
|
|
359
|
+
* });
|
|
360
|
+
* const paint = () => {
|
|
361
|
+
* sidebar.style.width = `${resizable.size}px`;
|
|
362
|
+
* };
|
|
363
|
+
* paint();
|
|
364
|
+
* resizable.subscribe(paint);
|
|
365
|
+
* ```
|
|
270
366
|
*/
|
|
271
367
|
export function createResizable(
|
|
368
|
+
handle: HTMLElement | null,
|
|
272
369
|
options: CreateResizableOptions = {},
|
|
273
370
|
): ResizableController {
|
|
274
|
-
return createResizableAs('createResizable', options);
|
|
371
|
+
return createResizableAs('createResizable', handle, options);
|
|
275
372
|
}
|
|
276
373
|
|
|
277
374
|
/**
|
|
@@ -287,6 +384,7 @@ export type ResizableWarningSource = 'createResizable' | 'useResizable';
|
|
|
287
384
|
*/
|
|
288
385
|
export function createResizableAs(
|
|
289
386
|
source: ResizableWarningSource,
|
|
387
|
+
handle: HTMLElement | null,
|
|
290
388
|
options: CreateResizableOptions = {},
|
|
291
389
|
): ResizableController {
|
|
292
390
|
// The configuration-object useResizable keeps its warnings word for word.
|
|
@@ -296,6 +394,8 @@ export function createResizableAs(
|
|
|
296
394
|
// Let go of the page by `suspend`, with the region kept.
|
|
297
395
|
let isSuspended = false;
|
|
298
396
|
const listeners = new Set<() => void>();
|
|
397
|
+
const isReversed = (): boolean => opts.isReversed ?? false;
|
|
398
|
+
const isDisabled = (): boolean => opts.isDisabled ?? false;
|
|
299
399
|
const didWarn = {
|
|
300
400
|
min: {current: false},
|
|
301
401
|
max: {current: false},
|
|
@@ -330,7 +430,6 @@ export function createResizableAs(
|
|
|
330
430
|
let uncontrolledIsCollapsed =
|
|
331
431
|
persisted?.isCollapsed ?? opts.defaultIsCollapsed ?? false;
|
|
332
432
|
|
|
333
|
-
// What the region last computed, notified and wrote.
|
|
334
433
|
let derived = {
|
|
335
434
|
size: 0,
|
|
336
435
|
isCollapsed: false,
|
|
@@ -518,13 +617,13 @@ export function createResizableAs(
|
|
|
518
617
|
derived = {size, isCollapsed, min, max, effectiveMax, isBasisMeasured};
|
|
519
618
|
}
|
|
520
619
|
|
|
521
|
-
/** Recompute, then bring the observers, storage and subscribers along. */
|
|
620
|
+
/** Recompute, then bring the observers, the handle, storage and subscribers along. */
|
|
522
621
|
function commit(): void {
|
|
523
622
|
if (isDestroyed) {
|
|
524
623
|
return;
|
|
525
624
|
}
|
|
526
625
|
if (isSuspended) {
|
|
527
|
-
// No observers: the last measured basis stands.
|
|
626
|
+
// No observers and no handle: the last measured basis stands.
|
|
528
627
|
compute();
|
|
529
628
|
} else {
|
|
530
629
|
// The observation a computation needs can change with it (a default
|
|
@@ -542,6 +641,9 @@ export function createResizableAs(
|
|
|
542
641
|
}
|
|
543
642
|
}
|
|
544
643
|
}
|
|
644
|
+
if (handle != null && !isSuspended) {
|
|
645
|
+
announce();
|
|
646
|
+
}
|
|
545
647
|
persist();
|
|
546
648
|
const reported = {
|
|
547
649
|
size: derived.isCollapsed ? 0 : derived.size,
|
|
@@ -606,6 +708,59 @@ export function createResizableAs(
|
|
|
606
708
|
}
|
|
607
709
|
}
|
|
608
710
|
|
|
711
|
+
const original = new Map<string, string | null>();
|
|
712
|
+
if (handle != null) {
|
|
713
|
+
for (const name of MANAGED_ATTRIBUTES) {
|
|
714
|
+
original.set(name, handle.getAttribute(name));
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const hasOwnName =
|
|
718
|
+
handle != null &&
|
|
719
|
+
(handle.hasAttribute('aria-label') ||
|
|
720
|
+
handle.hasAttribute('aria-labelledby'));
|
|
721
|
+
|
|
722
|
+
const setAttribute = (name: string, value: string | null) => {
|
|
723
|
+
if (handle == null) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
if (value == null) {
|
|
727
|
+
handle.removeAttribute(name);
|
|
728
|
+
} else if (handle.getAttribute(name) !== value) {
|
|
729
|
+
handle.setAttribute(name, value);
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
function announce(): void {
|
|
734
|
+
if (original.get('role') == null) {
|
|
735
|
+
setAttribute('role', 'separator');
|
|
736
|
+
}
|
|
737
|
+
if (!hasOwnName) {
|
|
738
|
+
setAttribute('aria-label', opts.label ?? english[LABEL_KEY]);
|
|
739
|
+
}
|
|
740
|
+
const {size, isCollapsed, min, effectiveMax} = derived;
|
|
741
|
+
// The attributes ResizeHandle renders, from the same derivation.
|
|
742
|
+
const aria = separatorAttributes({
|
|
743
|
+
direction: direction(),
|
|
744
|
+
isDisabled: isDisabled(),
|
|
745
|
+
value: {
|
|
746
|
+
size: isCollapsed ? 0 : size,
|
|
747
|
+
minPx: min,
|
|
748
|
+
maxPx: effectiveMax,
|
|
749
|
+
isCollapsed,
|
|
750
|
+
collapsedText: opts.collapsedLabel ?? english[COLLAPSED_LABEL_KEY],
|
|
751
|
+
},
|
|
752
|
+
});
|
|
753
|
+
if (original.get('tabindex') == null) {
|
|
754
|
+
setAttribute('tabindex', String(aria.tabIndex));
|
|
755
|
+
}
|
|
756
|
+
setAttribute('aria-orientation', aria['aria-orientation']);
|
|
757
|
+
setAttribute('aria-valuenow', toAttribute(aria['aria-valuenow']));
|
|
758
|
+
setAttribute('aria-valuemin', toAttribute(aria['aria-valuemin']));
|
|
759
|
+
setAttribute('aria-valuemax', toAttribute(aria['aria-valuemax']));
|
|
760
|
+
setAttribute('aria-valuetext', toAttribute(aria['aria-valuetext']));
|
|
761
|
+
setAttribute('aria-disabled', toAttribute(aria['aria-disabled']));
|
|
762
|
+
}
|
|
763
|
+
|
|
609
764
|
const setCollapsed = (value: boolean) => {
|
|
610
765
|
if (!isControlled()) {
|
|
611
766
|
uncontrolledIsCollapsed = value;
|
|
@@ -736,8 +891,59 @@ export function createResizableAs(
|
|
|
736
891
|
commit();
|
|
737
892
|
}
|
|
738
893
|
|
|
739
|
-
|
|
894
|
+
const gesture: ResizeGesture = createResizeGesture(
|
|
895
|
+
() => handle,
|
|
896
|
+
model,
|
|
897
|
+
() => ({
|
|
898
|
+
direction: direction(),
|
|
899
|
+
isReversed: isReversed(),
|
|
900
|
+
isDisabled: isDisabled(),
|
|
901
|
+
}),
|
|
902
|
+
dragging => {
|
|
903
|
+
setAttribute('data-resizing', dragging ? '' : null);
|
|
904
|
+
},
|
|
905
|
+
);
|
|
906
|
+
|
|
907
|
+
const onPointerDown = (event: PointerEvent) => {
|
|
908
|
+
gesture.pointerDown(event);
|
|
909
|
+
};
|
|
910
|
+
const onPointerMove = (event: PointerEvent) => {
|
|
911
|
+
gesture.pointerMove(event);
|
|
912
|
+
};
|
|
913
|
+
const onPointerUp = (event: PointerEvent) => {
|
|
914
|
+
gesture.pointerUp(event);
|
|
915
|
+
};
|
|
916
|
+
const onPointerCancel = (event: PointerEvent) => {
|
|
917
|
+
gesture.pointerCancel(event);
|
|
918
|
+
};
|
|
919
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
920
|
+
gesture.keyDown(event);
|
|
921
|
+
};
|
|
922
|
+
const onDoubleClick = () => {
|
|
923
|
+
gesture.doubleClick();
|
|
924
|
+
};
|
|
925
|
+
function bindHandle(): void {
|
|
926
|
+
handle?.addEventListener('pointerdown', onPointerDown);
|
|
927
|
+
handle?.addEventListener('pointermove', onPointerMove);
|
|
928
|
+
handle?.addEventListener('pointerup', onPointerUp);
|
|
929
|
+
handle?.addEventListener('pointercancel', onPointerCancel);
|
|
930
|
+
handle?.addEventListener('lostpointercapture', onPointerCancel);
|
|
931
|
+
handle?.addEventListener('keydown', onKeyDown);
|
|
932
|
+
handle?.addEventListener('dblclick', onDoubleClick);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* The handle's listeners and the observers go, and the handle gets its own
|
|
937
|
+
* attributes back; a gesture in flight has ended first.
|
|
938
|
+
*/
|
|
740
939
|
function letGoOfPage(): void {
|
|
940
|
+
handle?.removeEventListener('pointerdown', onPointerDown);
|
|
941
|
+
handle?.removeEventListener('pointermove', onPointerMove);
|
|
942
|
+
handle?.removeEventListener('pointerup', onPointerUp);
|
|
943
|
+
handle?.removeEventListener('pointercancel', onPointerCancel);
|
|
944
|
+
handle?.removeEventListener('lostpointercapture', onPointerCancel);
|
|
945
|
+
handle?.removeEventListener('keydown', onKeyDown);
|
|
946
|
+
handle?.removeEventListener('dblclick', onDoubleClick);
|
|
741
947
|
stopObservingContainer?.();
|
|
742
948
|
stopObservingContainer = null;
|
|
743
949
|
containerElement = null;
|
|
@@ -745,8 +951,12 @@ export function createResizableAs(
|
|
|
745
951
|
window.removeEventListener('resize', onViewportResize);
|
|
746
952
|
isObservingViewport = false;
|
|
747
953
|
}
|
|
954
|
+
for (const [name, value] of original) {
|
|
955
|
+
setAttribute(name, value);
|
|
956
|
+
}
|
|
748
957
|
}
|
|
749
958
|
|
|
959
|
+
bindHandle();
|
|
750
960
|
commit();
|
|
751
961
|
|
|
752
962
|
const controller: ResizableController = {
|
|
@@ -780,8 +990,11 @@ export function createResizableAs(
|
|
|
780
990
|
if (isDestroyed) {
|
|
781
991
|
return;
|
|
782
992
|
}
|
|
783
|
-
// A
|
|
784
|
-
//
|
|
993
|
+
// A drag in flight ends first, as cancelled, so the size it reached is
|
|
994
|
+
// saved and the pointer and the body's cursor are released.
|
|
995
|
+
gesture.interrupt();
|
|
996
|
+
// A gesture a ResizeHandle drove through the region's model, rather
|
|
997
|
+
// than the factory's own, ends the same way.
|
|
785
998
|
endGesture();
|
|
786
999
|
isDestroyed = true;
|
|
787
1000
|
if (!isSuspended) {
|
|
@@ -804,6 +1017,7 @@ export function createResizableAs(
|
|
|
804
1017
|
if (isDestroyed || isSuspended) {
|
|
805
1018
|
return;
|
|
806
1019
|
}
|
|
1020
|
+
gesture.interrupt();
|
|
807
1021
|
endGesture();
|
|
808
1022
|
isSuspended = true;
|
|
809
1023
|
letGoOfPage();
|
|
@@ -813,6 +1027,7 @@ export function createResizableAs(
|
|
|
813
1027
|
return;
|
|
814
1028
|
}
|
|
815
1029
|
isSuspended = false;
|
|
1030
|
+
bindHandle();
|
|
816
1031
|
commit();
|
|
817
1032
|
},
|
|
818
1033
|
syncContainer() {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file separatorAttributes.ts
|
|
5
|
+
* @input A window splitter's axis and disabled state, and its region's size,
|
|
6
|
+
* bounds, collapse state and collapsed text
|
|
7
|
+
* @output separatorAttributes: the separator's ARIA attributes and tab stop,
|
|
8
|
+
* which ResizeHandle renders and createResizable writes on a plain element
|
|
9
|
+
* @position Internal to the Resizable family. No React, and no DOM work on
|
|
10
|
+
* import
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type {ResizableDirection} from './resizableModel';
|
|
14
|
+
|
|
15
|
+
/** The region a separator resizes, as it announces it. */
|
|
16
|
+
export interface SeparatorValue {
|
|
17
|
+
/** The region's size in px, 0 while it is collapsed. */
|
|
18
|
+
readonly size: number;
|
|
19
|
+
readonly minPx: number;
|
|
20
|
+
/** The maximum to announce, or undefined when the region has none. */
|
|
21
|
+
readonly maxPx: number | undefined;
|
|
22
|
+
readonly isCollapsed: boolean;
|
|
23
|
+
/** The value text a collapsed separator announces. */
|
|
24
|
+
readonly collapsedText: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SeparatorState {
|
|
28
|
+
readonly direction: ResizableDirection;
|
|
29
|
+
readonly isDisabled: boolean;
|
|
30
|
+
/** The region's value; a separator with no region has none. */
|
|
31
|
+
readonly value?: SeparatorValue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface SeparatorAttributes {
|
|
35
|
+
readonly 'aria-orientation': 'horizontal' | 'vertical';
|
|
36
|
+
readonly 'aria-valuenow': number | undefined;
|
|
37
|
+
readonly 'aria-valuemin': number | undefined;
|
|
38
|
+
readonly 'aria-valuemax': number | undefined;
|
|
39
|
+
readonly 'aria-valuetext': string | undefined;
|
|
40
|
+
readonly 'aria-disabled': true | undefined;
|
|
41
|
+
readonly tabIndex: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The separator's ARIA attributes and tab stop. A collapsed region's real
|
|
46
|
+
* size, 0, sits below aria-valuemin, which is invalid. So a collapsed
|
|
47
|
+
* separator announces its minimum, and its value text says it is collapsed.
|
|
48
|
+
* A disabled separator keeps its tab stop, so keyboard users can reach it and
|
|
49
|
+
* hear that it is disabled.
|
|
50
|
+
*/
|
|
51
|
+
export function separatorAttributes(
|
|
52
|
+
state: SeparatorState,
|
|
53
|
+
): SeparatorAttributes {
|
|
54
|
+
const {value} = state;
|
|
55
|
+
return {
|
|
56
|
+
'aria-orientation':
|
|
57
|
+
state.direction === 'horizontal' ? 'vertical' : 'horizontal',
|
|
58
|
+
'aria-valuenow':
|
|
59
|
+
value == null
|
|
60
|
+
? undefined
|
|
61
|
+
: value.isCollapsed
|
|
62
|
+
? Math.max(value.size, value.minPx)
|
|
63
|
+
: value.size,
|
|
64
|
+
'aria-valuemin': value?.minPx,
|
|
65
|
+
'aria-valuemax':
|
|
66
|
+
value?.maxPx != null && Number.isFinite(value.maxPx)
|
|
67
|
+
? value.maxPx
|
|
68
|
+
: undefined,
|
|
69
|
+
'aria-valuetext': value?.isCollapsed ? value.collapsedText : undefined,
|
|
70
|
+
'aria-disabled': state.isDisabled || undefined,
|
|
71
|
+
tabIndex: 0,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -521,7 +521,7 @@ function useResizableController(
|
|
|
521
521
|
return;
|
|
522
522
|
}
|
|
523
523
|
const passed = optionsRef.current;
|
|
524
|
-
const resizable = createResizableAs('useResizable', passed);
|
|
524
|
+
const resizable = createResizableAs('useResizable', null, passed);
|
|
525
525
|
slot.set({resizable, passed});
|
|
526
526
|
}, [slot]);
|
|
527
527
|
useIsomorphicLayoutEffect(() => {
|
|
@@ -598,7 +598,7 @@ function useResizableController(
|
|
|
598
598
|
return entry.resizable;
|
|
599
599
|
}
|
|
600
600
|
const passed = optionsRef.current;
|
|
601
|
-
const resizable = createResizableAs('useResizable', passed);
|
|
601
|
+
const resizable = createResizableAs('useResizable', null, passed);
|
|
602
602
|
readResizableInternals(resizable)?.suspend();
|
|
603
603
|
slot.set({resizable, passed});
|
|
604
604
|
return resizable;
|