@astryxdesign/core 0.7.6 → 0.7.7-canary.0eb44a2
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/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +23 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +16 -9
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +2 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +3 -2
- package/dist/Chat/ChatComposerInput.d.ts +9 -0
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +2 -0
- package/dist/Chat/ChatMessage.js +2 -2
- package/dist/Chat/chatMessage.vars.stylex.d.ts +8 -8
- package/dist/Chat/chatMessage.vars.stylex.js +8 -8
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +8 -1
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +72 -2
- package/dist/DateInput/Wheel.d.ts +17 -1
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +179 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +63 -49
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +37 -1
- package/dist/Drawer/Drawer.d.ts.map +1 -1
- package/dist/Drawer/Drawer.js +6 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
- package/dist/Drawer/useDrawerDialogPresence.js +4 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +20 -4
- package/dist/DropdownMenu/useMenuOverflow.d.ts +13 -3
- package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -1
- package/dist/DropdownMenu/useMenuOverflow.js +31 -8
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +8 -1
- package/dist/Field/textEntryTraits.d.ts +6 -6
- package/dist/Field/textEntryTraits.js +6 -6
- package/dist/Layer/layerClickBoundary.d.ts +7 -1
- package/dist/Layer/layerClickBoundary.d.ts.map +1 -1
- package/dist/Layer/layerClickBoundary.js +2 -2
- package/dist/Layer/usePressPin.d.ts +95 -0
- package/dist/Layer/usePressPin.d.ts.map +1 -0
- package/dist/Layer/usePressPin.js +365 -0
- package/dist/Layer/useTouchTrigger.d.ts +23 -1
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
- package/dist/Layer/useTouchTrigger.js +45 -7
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +2 -1
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +1 -0
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +56 -7
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +38 -30
- package/dist/ProgressBar/ProgressBar.d.ts +1 -1
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +52 -14
- package/dist/ProgressBar/ProgressBarTouch.d.ts +29 -0
- package/dist/ProgressBar/ProgressBarTouch.d.ts.map +1 -0
- package/dist/ProgressBar/ProgressBarTouch.js +91 -0
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +25 -13
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +404 -131
- package/dist/Slider/sliderTouchController.d.ts +189 -0
- package/dist/Slider/sliderTouchController.d.ts.map +1 -0
- package/dist/Slider/sliderTouchController.js +1017 -0
- package/dist/Slider/useSliderTouch.d.ts +22 -0
- package/dist/Slider/useSliderTouch.d.ts.map +1 -0
- package/dist/Slider/useSliderTouch.js +56 -0
- package/dist/Switch/Switch.d.ts +1 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +200 -46
- package/dist/Switch/switchFill.d.ts +31 -0
- package/dist/Switch/switchFill.d.ts.map +1 -0
- package/dist/Switch/switchFill.js +88 -0
- package/dist/Switch/switchTouch.d.ts +81 -0
- package/dist/Switch/switchTouch.d.ts.map +1 -0
- package/dist/Switch/switchTouch.js +133 -0
- package/dist/Switch/useSwitchTouch.d.ts +285 -0
- package/dist/Switch/useSwitchTouch.d.ts.map +1 -0
- package/dist/Switch/useSwitchTouch.js +998 -0
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +4 -3
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +12 -5
- package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts +3 -0
- package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts.map +1 -0
- package/dist/Tokenizer/TokenizerItemRemovableContext.js +17 -0
- package/dist/Tooltip/Tooltip.d.ts +30 -6
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +5 -0
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +31 -5
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +59 -18
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +19 -9
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +26 -15
- package/dist/astryx.css +91 -8
- package/dist/gestures/GestureArena.d.ts +21 -2
- package/dist/gestures/GestureArena.d.ts.map +1 -1
- package/dist/gestures/GestureArena.js +23 -3
- package/dist/gestures/GestureHost.d.ts +123 -3
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +797 -15
- package/dist/gestures/GestureRecognizer.d.ts +15 -1
- package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/GestureRecognizer.js +12 -0
- package/dist/gestures/PanGestureRecognizer.d.ts +8 -0
- package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/PinchGestureRecognizer.d.ts +5 -1
- package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/PinchGestureRecognizer.js +10 -0
- package/dist/gestures/PressTracker.d.ts +6 -0
- package/dist/gestures/PressTracker.d.ts.map +1 -1
- package/dist/gestures/PressTracker.js +3 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +3 -3
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/ScreenEdgePanGestureRecognizer.js +7 -5
- package/dist/gestures/nativeScroll.d.ts +16 -2
- package/dist/gestures/nativeScroll.d.ts.map +1 -1
- package/dist/gestures/nativeScroll.js +39 -8
- package/dist/gestures/recognizerInternals.d.ts +4 -2
- package/dist/gestures/recognizerInternals.d.ts.map +1 -1
- package/dist/gestures/types.d.ts +17 -0
- package/dist/gestures/types.d.ts.map +1 -1
- package/dist/gestures/types.js +7 -0
- package/dist/gestures/usePressTracker.d.ts.map +1 -1
- package/dist/gestures/usePressTracker.js +1 -0
- package/dist/gestures/wheelSegmenter.d.ts +56 -0
- package/dist/gestures/wheelSegmenter.d.ts.map +1 -0
- package/dist/gestures/wheelSegmenter.js +122 -0
- package/dist/hooks/useAttachment.d.ts +16 -8
- package/dist/hooks/useAttachment.d.ts.map +1 -1
- package/dist/hooks/useAttachment.js +35 -15
- package/dist/hooks/useFocusTrap.d.ts +15 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +13 -2
- package/dist/hooks/usePager.d.ts +261 -0
- package/dist/hooks/usePager.d.ts.map +1 -0
- package/dist/hooks/usePager.js +1169 -0
- package/dist/motion/animator.d.ts.map +1 -1
- package/dist/motion/animator.js +140 -19
- package/dist/motion/paging.d.ts +69 -0
- package/dist/motion/paging.d.ts.map +1 -0
- package/dist/motion/paging.js +148 -0
- package/dist/motion/uikit/index.d.ts +8 -4
- package/dist/motion/uikit/index.d.ts.map +1 -1
- package/dist/motion/uikit/index.js +8 -4
- package/dist/motion/uikit/paging.d.ts +171 -0
- package/dist/motion/uikit/paging.d.ts.map +1 -0
- package/dist/motion/uikit/paging.js +192 -0
- package/dist/motion/uikit/progressBar.d.ts +79 -0
- package/dist/motion/uikit/progressBar.d.ts.map +1 -0
- package/dist/motion/uikit/progressBar.js +102 -0
- package/dist/motion/uikit/scroll.d.ts +0 -19
- package/dist/motion/uikit/scroll.d.ts.map +1 -1
- package/dist/motion/uikit/scroll.js +2 -21
- package/dist/motion/uikit/slider.d.ts +97 -0
- package/dist/motion/uikit/slider.d.ts.map +1 -0
- package/dist/motion/uikit/slider.js +111 -0
- package/dist/motion/uikit/springs.d.ts +59 -30
- package/dist/motion/uikit/springs.d.ts.map +1 -1
- package/dist/motion/uikit/springs.js +64 -34
- package/dist/motion/uikit/switch.d.ts +166 -0
- package/dist/motion/uikit/switch.d.ts.map +1 -0
- package/dist/motion/uikit/switch.js +186 -0
- package/dist/privateAttributes/pressHoldsDrag.stylex.d.ts +18 -0
- package/dist/privateAttributes/pressHoldsDrag.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/pressHoldsDrag.stylex.js +28 -0
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +5 -0
- package/dist/utils/selectionLock.d.ts +43 -0
- package/dist/utils/selectionLock.d.ts.map +1 -1
- package/dist/utils/selectionLock.js +394 -6
- package/package.json +5 -5
- package/src/AppShell/AppShell.doc.mjs +10 -0
- package/src/AppShell/AppShell.tsx +48 -2
- package/src/Avatar/Avatar.tsx +3 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +16 -9
- package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
- package/src/Button/Button.tsx +3 -2
- package/src/Chat/Chat.doc.mjs +1 -0
- package/src/Chat/ChatComposerInput.doc.mjs +11 -0
- package/src/Chat/ChatComposerInput.tsx +11 -0
- package/src/Chat/ChatMessage.tsx +2 -2
- package/src/Chat/chatMessage.vars.stylex.ts +8 -8
- package/src/CommandPalette/CommandPaletteInput.tsx +6 -0
- package/src/DateInput/MonthScroller.tsx +63 -5
- package/src/DateInput/Wheel.tsx +174 -14
- package/src/DateRangeInput/DateRangeInput.doc.mjs +3 -2
- package/src/DateRangeInput/DateRangeInput.tsx +117 -71
- package/src/Dialog/Dialog.tsx +37 -1
- package/src/Drawer/Drawer.tsx +6 -0
- package/src/Drawer/useDrawerDialogPresence.ts +4 -0
- package/src/DropdownMenu/DropdownMenu.tsx +28 -6
- package/src/DropdownMenu/useMenuOverflow.ts +44 -8
- package/src/Field/PanelSearchInput.tsx +6 -0
- package/src/Field/textEntryTraits.ts +6 -6
- package/src/Layer/layerClickBoundary.ts +2 -2
- package/src/Layer/usePressPin.ts +516 -0
- package/src/Layer/useTouchTrigger.ts +56 -6
- package/src/Lightbox/Lightbox.tsx +2 -1
- package/src/Link/Link.tsx +3 -0
- package/src/Popover/usePopover.tsx +71 -9
- package/src/PowerSearch/PowerSearch.tsx +38 -31
- package/src/ProgressBar/ProgressBar.doc.mjs +7 -5
- package/src/ProgressBar/ProgressBar.tsx +147 -16
- package/src/ProgressBar/ProgressBarTouch.ts +109 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -1
- package/src/Selector/Selector.tsx +29 -2
- package/src/Slider/Slider.doc.mjs +11 -7
- package/src/Slider/Slider.tsx +539 -132
- package/src/Slider/sliderTouchController.ts +1209 -0
- package/src/Slider/useSliderTouch.ts +78 -0
- package/src/Switch/Switch.doc.mjs +3 -3
- package/src/Switch/Switch.tsx +412 -86
- package/src/Switch/switchFill.ts +106 -0
- package/src/Switch/switchTouch.ts +194 -0
- package/src/Switch/useSwitchTouch.ts +1121 -0
- package/src/TabList/Tab.tsx +5 -3
- package/src/Tokenizer/Tokenizer.tsx +15 -5
- package/src/Tokenizer/TokenizerItemRemovableContext.ts +22 -0
- package/src/Tooltip/Tooltip.doc.mjs +21 -6
- package/src/Tooltip/Tooltip.tsx +42 -5
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/useTooltip.doc.mjs +4 -2
- package/src/Tooltip/useTooltip.tsx +84 -21
- package/src/Typeahead/BaseTypeahead.tsx +16 -8
- package/src/Typeahead/Typeahead.tsx +29 -15
- package/src/gestures/GestureArena.ts +45 -4
- package/src/gestures/GestureHost.ts +958 -15
- package/src/gestures/GestureRecognizer.ts +28 -0
- package/src/gestures/PanGestureRecognizer.ts +8 -0
- package/src/gestures/PinchGestureRecognizer.ts +16 -1
- package/src/gestures/PressTracker.ts +10 -0
- package/src/gestures/README.md +82 -3
- package/src/gestures/ScreenEdgePanGestureRecognizer.ts +7 -5
- package/src/gestures/nativeScroll.ts +49 -9
- package/src/gestures/recognizerInternals.ts +9 -2
- package/src/gestures/types.ts +18 -0
- package/src/gestures/usePressTracker.ts +2 -0
- package/src/gestures/wheelSegmenter.ts +143 -0
- package/src/hooks/useAttachment.ts +56 -14
- package/src/hooks/useFocusTrap.ts +26 -2
- package/src/hooks/usePager.ts +1446 -0
- package/src/motion/MEASUREMENTS.md +36 -27
- package/src/motion/README.md +7 -3
- package/src/motion/animator.ts +193 -25
- package/src/motion/paging.ts +161 -0
- package/src/motion/uikit/index.ts +7 -4
- package/src/motion/uikit/paging.ts +193 -0
- package/src/motion/uikit/progressBar.ts +102 -0
- package/src/motion/uikit/scroll.ts +2 -18
- package/src/motion/uikit/slider.ts +105 -0
- package/src/motion/uikit/springs.ts +53 -32
- package/src/motion/uikit/switch.ts +174 -0
- package/src/privateAttributes/pressHoldsDrag.stylex.ts +28 -0
- package/src/utils/pressFeedback.ts +5 -0
- package/src/utils/selectionLock.ts +501 -6
- package/dist/motion/selectPage.d.ts +0 -26
- package/dist/motion/selectPage.d.ts.map +0 -1
- package/dist/motion/selectPage.js +0 -55
- package/src/motion/selectPage.ts +0 -55
package/src/Switch/Switch.tsx
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
|
+
Fragment,
|
|
20
21
|
useId,
|
|
22
|
+
useMemo,
|
|
21
23
|
useOptimistic,
|
|
22
24
|
useTransition,
|
|
23
25
|
useEffect,
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
typographyVars,
|
|
37
39
|
typeScaleVars,
|
|
38
40
|
focusVars,
|
|
41
|
+
shadowVars,
|
|
39
42
|
} from '../theme/tokens.stylex';
|
|
40
43
|
import {FieldLabel} from '../Field/FieldLabel';
|
|
41
44
|
import {FieldStatus} from '../FieldStatus/FieldStatus';
|
|
@@ -45,7 +48,6 @@ import {Spinner} from '../Spinner';
|
|
|
45
48
|
import {useTooltip} from '../Tooltip';
|
|
46
49
|
import {mergeProps, mergeRefs, rtlStyles} from '../utils';
|
|
47
50
|
import {switchFocusInput, switchScope} from './switch.markers.stylex';
|
|
48
|
-
import {interactionOverlayStyles} from '../utils/interactionOverlay.stylex';
|
|
49
51
|
import type {BaseProps} from '../BaseProps';
|
|
50
52
|
import type {SizeValue} from '../utils/types';
|
|
51
53
|
import {themeProps} from '../utils/themeProps';
|
|
@@ -61,18 +63,53 @@ import {
|
|
|
61
63
|
import english from '../i18n/generated-english/Switch/Switch.generated';
|
|
62
64
|
|
|
63
65
|
registerEnglishFallback(english);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
import {
|
|
67
|
+
interactionOverlayStyles,
|
|
68
|
+
pressConsts,
|
|
69
|
+
pressVars,
|
|
70
|
+
} from '../utils/interactionOverlay.stylex';
|
|
71
|
+
import {pressHoldsDragProps} from '../privateAttributes/pressHoldsDrag.stylex';
|
|
72
|
+
import {useSwitchTouch, type SwitchTouchParts} from './useSwitchTouch';
|
|
73
|
+
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
74
|
+
import {watchHitArea, writeHitInsets} from '../utils/hitArea';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The track box of each size, px (width × height), for the touch
|
|
78
|
+
* presentation's thumb geometry.
|
|
79
|
+
* SYNC: wrapperSizeStyles and trackSizeStyles below.
|
|
80
|
+
*/
|
|
81
|
+
const TRACK_SIZE = {sm: [32, 20], md: [40, 24]} as const;
|
|
74
82
|
|
|
75
|
-
|
|
83
|
+
/**
|
|
84
|
+
* A finger: utils/touchPresentation.ts's TOUCH_QUERY. The touch presentation
|
|
85
|
+
* is one model on every touch device: the lift, tracking, flip rule and
|
|
86
|
+
* springs sit under it alone.
|
|
87
|
+
* SYNC: utils/touchPresentation.ts TOUCH_QUERY.
|
|
88
|
+
*/
|
|
89
|
+
const TOUCH = '@media (pointer: coarse)';
|
|
90
|
+
|
|
91
|
+
/** The press controller's two states on the row it writes to. */
|
|
92
|
+
const PRESS_ON = '[data-astryx-press="on"]';
|
|
93
|
+
const PRESS_FADING = '[data-astryx-press="fading"]';
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The shared press release, for the press layers the switch fades on the
|
|
97
|
+
* compositor. The clock scales by the theme's tempo, and the curve is the
|
|
98
|
+
* controller's own. Switch.test.tsx compares the two.
|
|
99
|
+
* SYNC: utils/interactionOverlay.stylex.ts PRESS_RELEASE_DURATION,
|
|
100
|
+
* PRESS_RELEASE_DURATION_REDUCED and RELEASE_EASE.
|
|
101
|
+
*/
|
|
102
|
+
const PRESS_RELEASE_DURATION = `calc(${pressConsts.releaseMs}ms * min(var(--_astryx-motion-tempo, 1), 1.5))`;
|
|
103
|
+
const PRESS_RELEASE_DURATION_REDUCED = `min(${pressConsts.releaseMs}ms, calc(${pressConsts.releaseMs}ms * var(--_astryx-motion-tempo, 1)))`;
|
|
104
|
+
const PRESS_RELEASE_EASE = 'cubic-bezier(0, 0, 0.2, 1)';
|
|
105
|
+
|
|
106
|
+
// The measured hit insets (utils/hitArea), 0 until measured.
|
|
107
|
+
const HIT_TOP = 'var(--astryx-hit-inset-top, 0px)';
|
|
108
|
+
const HIT_RIGHT = 'var(--astryx-hit-inset-right, 0px)';
|
|
109
|
+
const HIT_BOTTOM = 'var(--astryx-hit-inset-bottom, 0px)';
|
|
110
|
+
const HIT_LEFT = 'var(--astryx-hit-inset-left, 0px)';
|
|
111
|
+
|
|
112
|
+
const wrapperSizeStyles = stylex.create({
|
|
76
113
|
sm: {
|
|
77
114
|
width: 32,
|
|
78
115
|
height: 20,
|
|
@@ -83,6 +120,9 @@ const inputSizeStyles = stylex.create({
|
|
|
83
120
|
},
|
|
84
121
|
});
|
|
85
122
|
|
|
123
|
+
// Every touch value sits in the same property as the mouse value, as a
|
|
124
|
+
// nested condition, never in a later style. A later style that names a
|
|
125
|
+
// property replaces all of it, mouse value included.
|
|
86
126
|
const trackSizeStyles = stylex.create({
|
|
87
127
|
sm: {
|
|
88
128
|
width: 32,
|
|
@@ -96,16 +136,28 @@ const trackSizeStyles = stylex.create({
|
|
|
96
136
|
},
|
|
97
137
|
});
|
|
98
138
|
|
|
139
|
+
// The thumb is one circle under any pointer, at each state's size. Under a
|
|
140
|
+
// finger it rests by insets instead of a transform, centered in the track's
|
|
141
|
+
// height at each end. So the compositor moves and lifts it with translate and
|
|
142
|
+
// scale alone; useSwitchTouch measures the box it renders.
|
|
99
143
|
const thumbOffSizeStyles = stylex.create({
|
|
100
144
|
sm: {
|
|
101
145
|
width: 14,
|
|
102
146
|
height: 14,
|
|
103
|
-
|
|
147
|
+
insetInlineStart: {default: null, [TOUCH]: 3},
|
|
148
|
+
transform: {
|
|
149
|
+
default: 'translateX(0)',
|
|
150
|
+
[TOUCH]: 'none',
|
|
151
|
+
},
|
|
104
152
|
},
|
|
105
153
|
md: {
|
|
106
154
|
width: 16,
|
|
107
155
|
height: 16,
|
|
108
|
-
|
|
156
|
+
insetInlineStart: {default: null, [TOUCH]: 4},
|
|
157
|
+
transform: {
|
|
158
|
+
default: 'translateX(0)',
|
|
159
|
+
[TOUCH]: 'none',
|
|
160
|
+
},
|
|
109
161
|
},
|
|
110
162
|
});
|
|
111
163
|
|
|
@@ -113,6 +165,8 @@ const thumbOnSizeStyles = stylex.create({
|
|
|
113
165
|
sm: {
|
|
114
166
|
width: 16,
|
|
115
167
|
height: 16,
|
|
168
|
+
insetInlineStart: {default: null, [TOUCH]: 'auto'},
|
|
169
|
+
insetInlineEnd: {default: null, [TOUCH]: 2},
|
|
116
170
|
// The thumb rests at the inline-start edge (flex-start, which flexbox
|
|
117
171
|
// already mirrors under RTL). The on-state travel toward the inline-end
|
|
118
172
|
// edge is a physical translateX, so it must flip sign under RTL — right
|
|
@@ -120,15 +174,25 @@ const thumbOnSizeStyles = stylex.create({
|
|
|
120
174
|
// iOS): off-thumb on the reading-start side, on-thumb on the reading-end.
|
|
121
175
|
transform: {
|
|
122
176
|
default: 'translateX(12px)',
|
|
123
|
-
':is([dir="rtl"] *)':
|
|
177
|
+
':is([dir="rtl"] *)': {
|
|
178
|
+
default: 'translateX(-12px)',
|
|
179
|
+
[TOUCH]: 'none',
|
|
180
|
+
},
|
|
181
|
+
[TOUCH]: 'none',
|
|
124
182
|
},
|
|
125
183
|
},
|
|
126
184
|
md: {
|
|
127
185
|
width: 20,
|
|
128
186
|
height: 20,
|
|
187
|
+
insetInlineStart: {default: null, [TOUCH]: 'auto'},
|
|
188
|
+
insetInlineEnd: {default: null, [TOUCH]: 2},
|
|
129
189
|
transform: {
|
|
130
190
|
default: 'translateX(14px)',
|
|
131
|
-
':is([dir="rtl"] *)':
|
|
191
|
+
':is([dir="rtl"] *)': {
|
|
192
|
+
default: 'translateX(-14px)',
|
|
193
|
+
[TOUCH]: 'none',
|
|
194
|
+
},
|
|
195
|
+
[TOUCH]: 'none',
|
|
132
196
|
},
|
|
133
197
|
},
|
|
134
198
|
});
|
|
@@ -141,11 +205,43 @@ const thumbOnSizeStyles = stylex.create({
|
|
|
141
205
|
// hover tint already is: pressing the input, the track or the label all
|
|
142
206
|
// activate the row.
|
|
143
207
|
const pressedImage = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
208
|
+
|
|
209
|
+
/** The touch press's release on the press layer: opacity 1 → 0. */
|
|
210
|
+
const pressLayerRelease = stylex.keyframes({
|
|
211
|
+
from: {opacity: 1},
|
|
212
|
+
to: {opacity: 0},
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const PRESS_ALPHA = pressVars['--astryx-press-alpha'];
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The shared strength's release, restated so a fine pointer keeps it: the
|
|
219
|
+
* same keyframes, so the same animation.
|
|
220
|
+
*/
|
|
221
|
+
const pressStrengthRelease = stylex.keyframes({
|
|
222
|
+
from: {[PRESS_ALPHA]: 1},
|
|
223
|
+
to: {[PRESS_ALPHA]: 0},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const pressOwnerStyles = stylex.create({
|
|
227
|
+
/**
|
|
228
|
+
* Composed after `interactionOverlayStyles.pressedAlpha` on the row. Under
|
|
229
|
+
* a coarse primary pointer the track's and thumb's layers fade the press.
|
|
230
|
+
* So the strength holds through the release, not animated on the main
|
|
231
|
+
* thread. With any other pointer the row keeps `pressedAlpha`'s release.
|
|
232
|
+
*/
|
|
233
|
+
pressedAlphaLayered: {
|
|
234
|
+
animationName: {
|
|
235
|
+
default: null,
|
|
236
|
+
[PRESS_FADING]: {
|
|
237
|
+
default: pressStrengthRelease,
|
|
238
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
239
|
+
'none',
|
|
240
|
+
'@media (pointer: coarse)': 'none',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
});
|
|
149
245
|
|
|
150
246
|
const labelWrapperSizeStyles = stylex.create({
|
|
151
247
|
sm: {
|
|
@@ -182,6 +278,13 @@ const styles = stylex.create({
|
|
|
182
278
|
flexShrink: 0,
|
|
183
279
|
isolation: 'isolate',
|
|
184
280
|
},
|
|
281
|
+
// Horizontal touch moves are the switch's drag and vertical ones the page's
|
|
282
|
+
// scroll, under any primary pointer. A touchscreen laptop's finger counts
|
|
283
|
+
// too. It is set in CSS so it holds before hydration. A disabled or loading
|
|
284
|
+
// switch takes no drag, so it leaves every move to the page.
|
|
285
|
+
switchWrapperInteractive: {
|
|
286
|
+
touchAction: 'pan-y pinch-zoom',
|
|
287
|
+
},
|
|
185
288
|
input: {
|
|
186
289
|
position: 'absolute',
|
|
187
290
|
top: '50%',
|
|
@@ -194,10 +297,24 @@ const styles = stylex.create({
|
|
|
194
297
|
},
|
|
195
298
|
zIndex: 1,
|
|
196
299
|
},
|
|
300
|
+
// The invisible input covers the track. Under a coarse pointer it is the
|
|
301
|
+
// hit area a finger needs. It grows toward 44 × 44 px by the insets
|
|
302
|
+
// utils/hitArea measures, each side stopping at half the gap to a
|
|
303
|
+
// neighbouring target. Its center moves with any uneven side, and nothing
|
|
304
|
+
// visible grows. The insets are 0 until measured. Physical left and
|
|
305
|
+
// translate, as centerInline: the insets are physical sides.
|
|
197
306
|
inputCoarse: {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
307
|
+
width: {
|
|
308
|
+
default: '100%',
|
|
309
|
+
'@media (pointer: coarse)': `calc(100% + ${HIT_LEFT} + ${HIT_RIGHT})`,
|
|
310
|
+
},
|
|
311
|
+
height: {
|
|
312
|
+
default: '100%',
|
|
313
|
+
'@media (pointer: coarse)': `calc(100% + ${HIT_TOP} + ${HIT_BOTTOM})`,
|
|
314
|
+
},
|
|
315
|
+
transform: {
|
|
316
|
+
default: 'translate(-50%, -50%)',
|
|
317
|
+
'@media (pointer: coarse)': `translate(calc(-50% + (${HIT_RIGHT} - ${HIT_LEFT}) / 2), calc(-50% + (${HIT_BOTTOM} - ${HIT_TOP}) / 2))`,
|
|
201
318
|
},
|
|
202
319
|
},
|
|
203
320
|
inputDisabled: {
|
|
@@ -209,11 +326,22 @@ const styles = stylex.create({
|
|
|
209
326
|
track: {
|
|
210
327
|
display: 'flex',
|
|
211
328
|
alignItems: 'center',
|
|
329
|
+
// Under a finger the press layer (::before), the colour fade (::after)
|
|
330
|
+
// and the thumb sit in the track, in a stacking context of its own.
|
|
331
|
+
position: {default: null, [TOUCH]: 'relative'},
|
|
332
|
+
isolation: {default: null, [TOUCH]: 'isolate'},
|
|
212
333
|
borderRadius: radiusVars['--radius-full'],
|
|
213
334
|
transitionProperty: 'background-color',
|
|
335
|
+
// Under a finger the track's fill changes at once and the fade layer
|
|
336
|
+
// crossfades it on the compositor. Reduced motion comes last so it holds
|
|
337
|
+
// everywhere: under a finger the fade layer
|
|
338
|
+
// carries the colour, and with a mouse the change is immediate.
|
|
214
339
|
transitionDuration: {
|
|
215
340
|
default: durationVars['--duration-fast'],
|
|
216
|
-
|
|
341
|
+
[TOUCH]: '0s',
|
|
342
|
+
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': '0s',
|
|
343
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
344
|
+
'0s',
|
|
217
345
|
},
|
|
218
346
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
219
347
|
boxSizing: 'border-box',
|
|
@@ -240,28 +368,102 @@ const styles = stylex.create({
|
|
|
240
368
|
default: null,
|
|
241
369
|
'@media (forced-colors: none)': {
|
|
242
370
|
default: pressedImage,
|
|
243
|
-
// Under a coarse pointer the touch press
|
|
244
|
-
// on the row instead
|
|
371
|
+
// Under a coarse pointer the touch press controller writes
|
|
372
|
+
// `data-astryx-press` on the row instead, and the press layer
|
|
373
|
+
// (::before) paints it.
|
|
245
374
|
'@media (pointer: coarse)': 'none',
|
|
246
375
|
},
|
|
247
376
|
},
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
377
|
+
},
|
|
378
|
+
// The press, under a finger: a layer over the track's fill and colour
|
|
379
|
+
// fade and under the thumb. It exists only while the row is pressed or
|
|
380
|
+
// releasing. Its opacity is the press: on at once, then the shared
|
|
381
|
+
// release's clock and curve. The release runs on the compositor, so the
|
|
382
|
+
// press never sticks while the main thread is busy.
|
|
383
|
+
'::before': {
|
|
384
|
+
content: {
|
|
251
385
|
default: null,
|
|
252
|
-
|
|
386
|
+
[stylex.when.ancestor(PRESS_ON, switchScope)]: {
|
|
253
387
|
default: null,
|
|
254
|
-
|
|
388
|
+
[TOUCH]: '""',
|
|
389
|
+
},
|
|
390
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
391
|
+
default: null,
|
|
392
|
+
[TOUCH]: '""',
|
|
255
393
|
},
|
|
256
394
|
},
|
|
257
|
-
|
|
395
|
+
position: 'absolute',
|
|
396
|
+
inset: 0,
|
|
397
|
+
zIndex: 1,
|
|
398
|
+
borderRadius: 'inherit',
|
|
399
|
+
pointerEvents: 'none',
|
|
400
|
+
backgroundColor: {
|
|
258
401
|
default: null,
|
|
259
|
-
'@media (forced-colors: none)':
|
|
402
|
+
'@media (forced-colors: none)': colorVars['--color-overlay-pressed'],
|
|
403
|
+
},
|
|
404
|
+
opacity: {
|
|
405
|
+
default: null,
|
|
406
|
+
[stylex.when.ancestor(PRESS_ON, switchScope)]: {
|
|
407
|
+
default: null,
|
|
408
|
+
[TOUCH]: 1,
|
|
409
|
+
},
|
|
410
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
411
|
+
default: null,
|
|
412
|
+
[TOUCH]: 0,
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
animationName: {
|
|
416
|
+
default: null,
|
|
417
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
260
418
|
default: null,
|
|
261
|
-
|
|
419
|
+
[TOUCH]: pressLayerRelease,
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
animationDuration: {
|
|
423
|
+
default: null,
|
|
424
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
425
|
+
default: null,
|
|
426
|
+
[TOUCH]: {
|
|
427
|
+
default: PRESS_RELEASE_DURATION,
|
|
428
|
+
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)':
|
|
429
|
+
PRESS_RELEASE_DURATION_REDUCED,
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
animationTimingFunction: {
|
|
434
|
+
default: null,
|
|
435
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
436
|
+
default: null,
|
|
437
|
+
[TOUCH]: PRESS_RELEASE_EASE,
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
animationFillMode: {
|
|
441
|
+
default: null,
|
|
442
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
443
|
+
default: null,
|
|
444
|
+
[TOUCH]: 'both',
|
|
262
445
|
},
|
|
263
446
|
},
|
|
264
447
|
},
|
|
448
|
+
// The colour fade, under a finger: a layer over the track's own fill. It
|
|
449
|
+
// shows the fill the track is leaving, or mid-drag the one it heads to,
|
|
450
|
+
// and fades it on the compositor. Its colour is the theme's, read from
|
|
451
|
+
// the track (switchFill.ts). The animator owns its opacity, and at rest it
|
|
452
|
+
// is clear.
|
|
453
|
+
'::after': {
|
|
454
|
+
content: '""',
|
|
455
|
+
display: {default: 'none', [TOUCH]: 'block'},
|
|
456
|
+
position: 'absolute',
|
|
457
|
+
inset: 0,
|
|
458
|
+
zIndex: 0,
|
|
459
|
+
borderRadius: 'inherit',
|
|
460
|
+
pointerEvents: 'none',
|
|
461
|
+
opacity: 0,
|
|
462
|
+
backgroundColor: 'var(--_switch-fade-fill, transparent)',
|
|
463
|
+
// Its own compositing layer from the start, so its fade runs off the
|
|
464
|
+
// main thread (iOS Safari otherwise animates it on the main thread).
|
|
465
|
+
willChange: {default: null, [TOUCH]: 'opacity'},
|
|
466
|
+
},
|
|
265
467
|
},
|
|
266
468
|
// The one ring in the system not drawn by focusOutlineStyles. The focusable
|
|
267
469
|
// input is the track's preceding sibling, so the condition reads that input
|
|
@@ -329,38 +531,117 @@ const styles = stylex.create({
|
|
|
329
531
|
alignItems: 'center',
|
|
330
532
|
justifyContent: 'center',
|
|
331
533
|
borderRadius: radiusVars['--radius-full'],
|
|
332
|
-
|
|
534
|
+
// Under a finger it sits in the track, centered in its height, above the
|
|
535
|
+
// colour fade (::after) and the press layer (::before). useSwitchTouch
|
|
536
|
+
// moves and lifts it on the compositor: nothing of its own transitions.
|
|
537
|
+
position: {default: null, [TOUCH]: 'absolute'},
|
|
538
|
+
insetBlock: {default: null, [TOUCH]: 0},
|
|
539
|
+
marginBlock: {default: null, [TOUCH]: 'auto'},
|
|
540
|
+
zIndex: {default: null, [TOUCH]: 2},
|
|
541
|
+
pointerEvents: {default: null, [TOUCH]: 'none'},
|
|
542
|
+
transitionProperty: {
|
|
543
|
+
default: 'transform, width, height',
|
|
544
|
+
[TOUCH]: 'none',
|
|
545
|
+
},
|
|
546
|
+
// Under reduced motion nothing slides: under a finger the thumb
|
|
547
|
+
// cross-fades through the animator, and with a mouse it moves at once.
|
|
333
548
|
transitionDuration: {
|
|
334
549
|
default: durationVars['--duration-fast'],
|
|
335
|
-
'@media (prefers-reduced-motion: reduce)': '0s',
|
|
550
|
+
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)': '0s',
|
|
551
|
+
'@media (prefers-reduced-motion: reduce) and (not (pointer: coarse))':
|
|
552
|
+
'0s',
|
|
336
553
|
},
|
|
337
554
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
555
|
+
// The lifted shadow, under a finger: the theme's elevation on a layer the
|
|
556
|
+
// thumb's size. It fades in with the lift on the compositor, and at rest
|
|
557
|
+
// it is clear. The press on the thumb too, under a finger: the same layer
|
|
558
|
+
// as the track's, over the thumb's fill.
|
|
559
|
+
'::before': {
|
|
560
|
+
content: {
|
|
344
561
|
default: null,
|
|
345
|
-
|
|
346
|
-
default:
|
|
347
|
-
|
|
562
|
+
[stylex.when.ancestor(PRESS_ON, switchScope)]: {
|
|
563
|
+
default: null,
|
|
564
|
+
[TOUCH]: '""',
|
|
565
|
+
},
|
|
566
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
567
|
+
default: null,
|
|
568
|
+
[TOUCH]: '""',
|
|
348
569
|
},
|
|
349
570
|
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
571
|
+
position: 'absolute',
|
|
572
|
+
inset: 0,
|
|
573
|
+
borderRadius: 'inherit',
|
|
574
|
+
pointerEvents: 'none',
|
|
575
|
+
backgroundColor: {
|
|
353
576
|
default: null,
|
|
354
|
-
'@media (forced-colors: none)':
|
|
577
|
+
'@media (forced-colors: none)': colorVars['--color-overlay-pressed'],
|
|
578
|
+
},
|
|
579
|
+
opacity: {
|
|
580
|
+
default: null,
|
|
581
|
+
[stylex.when.ancestor(PRESS_ON, switchScope)]: {
|
|
582
|
+
default: null,
|
|
583
|
+
[TOUCH]: 1,
|
|
584
|
+
},
|
|
585
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
355
586
|
default: null,
|
|
356
|
-
|
|
587
|
+
[TOUCH]: 0,
|
|
357
588
|
},
|
|
358
589
|
},
|
|
359
|
-
|
|
590
|
+
animationName: {
|
|
360
591
|
default: null,
|
|
361
|
-
|
|
592
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
362
593
|
default: null,
|
|
363
|
-
|
|
594
|
+
[TOUCH]: pressLayerRelease,
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
animationDuration: {
|
|
598
|
+
default: null,
|
|
599
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
600
|
+
default: null,
|
|
601
|
+
[TOUCH]: {
|
|
602
|
+
default: PRESS_RELEASE_DURATION,
|
|
603
|
+
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)':
|
|
604
|
+
PRESS_RELEASE_DURATION_REDUCED,
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
animationTimingFunction: {
|
|
609
|
+
default: null,
|
|
610
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
611
|
+
default: null,
|
|
612
|
+
[TOUCH]: PRESS_RELEASE_EASE,
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
animationFillMode: {
|
|
616
|
+
default: null,
|
|
617
|
+
[stylex.when.ancestor(PRESS_FADING, switchScope)]: {
|
|
618
|
+
default: null,
|
|
619
|
+
[TOUCH]: 'both',
|
|
620
|
+
},
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
'::after': {
|
|
624
|
+
content: '""',
|
|
625
|
+
display: {default: 'none', [TOUCH]: 'block'},
|
|
626
|
+
position: 'absolute',
|
|
627
|
+
inset: 0,
|
|
628
|
+
borderRadius: 'inherit',
|
|
629
|
+
pointerEvents: 'none',
|
|
630
|
+
opacity: 0,
|
|
631
|
+
boxShadow: shadowVars['--shadow-low'],
|
|
632
|
+
willChange: {default: null, [TOUCH]: 'opacity'},
|
|
633
|
+
},
|
|
634
|
+
// Pressed with a mouse: the same overlay as the track, so the whole
|
|
635
|
+
// control darkens rather than the thumb standing out against a darker
|
|
636
|
+
// track. Under a finger the track's press layer paints under the thumb,
|
|
637
|
+
// which lifts.
|
|
638
|
+
backgroundImage: {
|
|
639
|
+
default: null,
|
|
640
|
+
[stylex.when.ancestor(':active', switchScope)]: {
|
|
641
|
+
default: null,
|
|
642
|
+
'@media (forced-colors: none)': {
|
|
643
|
+
default: pressedImage,
|
|
644
|
+
'@media (pointer: coarse)': 'none',
|
|
364
645
|
},
|
|
365
646
|
},
|
|
366
647
|
},
|
|
@@ -519,7 +800,7 @@ export interface SwitchProps extends Omit<BaseProps, 'onChange'> {
|
|
|
519
800
|
status?: InputStatus;
|
|
520
801
|
/**
|
|
521
802
|
* Size variant controlling track and thumb dimensions.
|
|
522
|
-
* - 'sm':
|
|
803
|
+
* - 'sm': 32x20px (matches sm checkbox/radio vertical rhythm)
|
|
523
804
|
* - 'md': 40x24px (default, matches md checkbox/radio vertical rhythm)
|
|
524
805
|
* @default 'md'
|
|
525
806
|
*/
|
|
@@ -649,10 +930,68 @@ export function Switch({
|
|
|
649
930
|
const ariaDescribedBy =
|
|
650
931
|
describedByParts.length > 0 ? describedByParts.join(' ') : undefined;
|
|
651
932
|
|
|
933
|
+
// The touch presentation (coarse pointer): its parts are always rendered;
|
|
934
|
+
// CSS shows them under a finger and the hook animates and listens there.
|
|
935
|
+
const surfaceRef = useRef<HTMLDivElement>(null);
|
|
936
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
937
|
+
const thumbRef = useRef<HTMLDivElement>(null);
|
|
938
|
+
const trackRef = useRef<HTMLDivElement>(null);
|
|
939
|
+
const touchParts = useMemo<SwitchTouchParts>(
|
|
940
|
+
() => ({
|
|
941
|
+
surface: surfaceRef,
|
|
942
|
+
input: inputRef,
|
|
943
|
+
thumb: thumbRef,
|
|
944
|
+
track: trackRef,
|
|
945
|
+
}),
|
|
946
|
+
[],
|
|
947
|
+
);
|
|
948
|
+
// The track in a state: its theme target and fill. The other state's, for
|
|
949
|
+
// the fade layer's colour (switchFill.ts).
|
|
950
|
+
const trackPropsFor = (on: boolean) =>
|
|
951
|
+
mergeProps(
|
|
952
|
+
themeProps('switch', {
|
|
953
|
+
checked: on ? 'checked' : null,
|
|
954
|
+
disabled: isDisabled ? 'disabled' : null,
|
|
955
|
+
size,
|
|
956
|
+
}),
|
|
957
|
+
stylex.props(
|
|
958
|
+
styles.track,
|
|
959
|
+
trackSizeStyles[size],
|
|
960
|
+
on ? styles.trackOn : styles.trackOff,
|
|
961
|
+
styles.trackFocus,
|
|
962
|
+
isDisabled && styles.trackDisabled,
|
|
963
|
+
isDisabled && !on && styles.trackDisabledOff,
|
|
964
|
+
),
|
|
965
|
+
);
|
|
966
|
+
// Syncs the hit area's insets with the layout around the switch, through
|
|
967
|
+
// utils/hitArea's observers. Under a coarse pointer they grow toward 44 px,
|
|
968
|
+
// stopping at half the gap to each neighbouring target. A disabled switch
|
|
969
|
+
// watches nothing.
|
|
970
|
+
useIsomorphicLayoutEffect(() => {
|
|
971
|
+
const surface = surfaceRef.current;
|
|
972
|
+
if (surface == null || isDisabled) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
return watchHitArea(surface, insets => writeHitInsets(surface, insets));
|
|
976
|
+
}, [isDisabled]);
|
|
977
|
+
useSwitchTouch(touchParts, {
|
|
978
|
+
isOn,
|
|
979
|
+
isInteractive: !isDisabled && !isBusy,
|
|
980
|
+
isDisabled,
|
|
981
|
+
trackSize: TRACK_SIZE[size],
|
|
982
|
+
otherTrackProps: trackPropsFor(!isOn),
|
|
983
|
+
});
|
|
984
|
+
|
|
652
985
|
const switchElement = (
|
|
653
|
-
<div
|
|
986
|
+
<div
|
|
987
|
+
ref={surfaceRef}
|
|
988
|
+
{...stylex.props(
|
|
989
|
+
styles.switchWrapper,
|
|
990
|
+
wrapperSizeStyles[size],
|
|
991
|
+
!isDisabled && !isBusy && styles.switchWrapperInteractive,
|
|
992
|
+
)}>
|
|
654
993
|
<input
|
|
655
|
-
ref={useMergedRefs(ref, disabledMessageTooltip.positionRef)}
|
|
994
|
+
ref={useMergedRefs(ref, disabledMessageTooltip.positionRef, inputRef)}
|
|
656
995
|
id={id}
|
|
657
996
|
type="checkbox"
|
|
658
997
|
role="switch"
|
|
@@ -695,30 +1034,14 @@ export function Switch({
|
|
|
695
1034
|
styles.input,
|
|
696
1035
|
rtlStyles.centerInline('-50%'),
|
|
697
1036
|
styles.inputCoarse,
|
|
698
|
-
inputSizeStyles[size],
|
|
699
1037
|
isDisabled && styles.inputDisabled,
|
|
700
1038
|
isBusy && styles.inputBusy,
|
|
701
1039
|
switchFocusInput,
|
|
702
1040
|
)}
|
|
703
1041
|
/>
|
|
704
|
-
<div
|
|
705
|
-
aria-hidden="true"
|
|
706
|
-
{...mergeProps(
|
|
707
|
-
themeProps('switch', {
|
|
708
|
-
checked: isOn ? 'checked' : null,
|
|
709
|
-
disabled: isDisabled ? 'disabled' : null,
|
|
710
|
-
size,
|
|
711
|
-
}),
|
|
712
|
-
stylex.props(
|
|
713
|
-
styles.track,
|
|
714
|
-
trackSizeStyles[size],
|
|
715
|
-
isOn ? styles.trackOn : styles.trackOff,
|
|
716
|
-
styles.trackFocus,
|
|
717
|
-
isDisabled && styles.trackDisabled,
|
|
718
|
-
isDisabled && !isOn && styles.trackDisabledOff,
|
|
719
|
-
),
|
|
720
|
-
)}>
|
|
1042
|
+
<div ref={trackRef} aria-hidden="true" {...trackPropsFor(isOn)}>
|
|
721
1043
|
<div
|
|
1044
|
+
ref={thumbRef}
|
|
722
1045
|
{...mergeProps(
|
|
723
1046
|
themeProps('switch-thumb', {
|
|
724
1047
|
checked: isOn ? 'checked' : null,
|
|
@@ -785,6 +1108,7 @@ export function Switch({
|
|
|
785
1108
|
disabledMessageTooltip.interactionRef(el);
|
|
786
1109
|
}}
|
|
787
1110
|
{...(isDisabled ? undefined : pressable)}
|
|
1111
|
+
{...pressHoldsDragProps(!isDisabled)}
|
|
788
1112
|
{...stylex.props(
|
|
789
1113
|
styles.container,
|
|
790
1114
|
isLabelHidden && styles.containerLabelHidden,
|
|
@@ -793,19 +1117,21 @@ export function Switch({
|
|
|
793
1117
|
// The touch press's strength and release live on the row the
|
|
794
1118
|
// controller writes to; the track and thumb inherit and paint it.
|
|
795
1119
|
!isDisabled && interactionOverlayStyles.pressedAlpha,
|
|
1120
|
+
!isDisabled && pressOwnerStyles.pressedAlphaLayered,
|
|
796
1121
|
)}>
|
|
797
1122
|
{' '}
|
|
798
|
-
{labelPosition
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1123
|
+
{/* Keyed, so a labelPosition change moves the nodes instead of
|
|
1124
|
+
rebuilding them: the touch controller stays on the input, track
|
|
1125
|
+
and thumb it attached to. */}
|
|
1126
|
+
{labelPosition === 'start'
|
|
1127
|
+
? [
|
|
1128
|
+
<Fragment key="label">{labelElement}</Fragment>,
|
|
1129
|
+
<Fragment key="switch">{switchElement}</Fragment>,
|
|
1130
|
+
]
|
|
1131
|
+
: [
|
|
1132
|
+
<Fragment key="switch">{switchElement}</Fragment>,
|
|
1133
|
+
<Fragment key="label">{labelElement}</Fragment>,
|
|
1134
|
+
]}
|
|
809
1135
|
</div>
|
|
810
1136
|
{status?.message && (
|
|
811
1137
|
<FieldStatus
|