@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
|
@@ -88,6 +88,7 @@ import {
|
|
|
88
88
|
useComponentTranslator,
|
|
89
89
|
} from '../i18n/useComponentTranslator';
|
|
90
90
|
import english from '../i18n/generated-english/DateRangeInput/DateRangeInput.generated';
|
|
91
|
+
import {layerViewportInset} from '../Layer/layerViewportInset.stylex';
|
|
91
92
|
|
|
92
93
|
registerEnglishFallback(english);
|
|
93
94
|
|
|
@@ -160,8 +161,28 @@ const styles = stylex.create({
|
|
|
160
161
|
iconButtonDisabled: {
|
|
161
162
|
cursor: 'default',
|
|
162
163
|
},
|
|
164
|
+
// The popover content scrolls inside the layer's block cap, so a stacked
|
|
165
|
+
// calendar stays reachable on a short screen.
|
|
166
|
+
popoverScroll: {
|
|
167
|
+
overflowY: 'auto',
|
|
168
|
+
overscrollBehavior: 'contain',
|
|
169
|
+
maxBlockSize: stylex.firstThatWorks(
|
|
170
|
+
`calc(${layerViewportInset.maxBlockSize})`,
|
|
171
|
+
`calc(${layerViewportInset.maxBlockSizeFallback})`,
|
|
172
|
+
),
|
|
173
|
+
},
|
|
174
|
+
// When the presets and a one-month calendar do not fit side by side, the
|
|
175
|
+
// row wraps and the presets stack above the calendar, in DOM order. The
|
|
176
|
+
// preset group draws a divider on its inline end and its block end. A
|
|
177
|
+
// negative margin moves each divider 1 border width past the group's margin
|
|
178
|
+
// box, and this row clips at its edges. Thus only the divider between the
|
|
179
|
+
// two parts shows: the inline-end one side by side, the block-end one when
|
|
180
|
+
// stacked. The row clips, not the scroller, so the overhang is never
|
|
181
|
+
// scrollable overflow.
|
|
163
182
|
popoverLayout: {
|
|
164
183
|
display: 'flex',
|
|
184
|
+
flexWrap: 'wrap',
|
|
185
|
+
overflow: 'clip',
|
|
165
186
|
},
|
|
166
187
|
presetSidebar: {
|
|
167
188
|
display: 'flex',
|
|
@@ -171,8 +192,26 @@ const styles = stylex.create({
|
|
|
171
192
|
borderInlineEndWidth: borderVars['--border-width'],
|
|
172
193
|
borderInlineEndStyle: 'solid',
|
|
173
194
|
borderInlineEndColor: colorVars['--color-border-emphasized'],
|
|
195
|
+
borderBlockEndWidth: borderVars['--border-width'],
|
|
196
|
+
borderBlockEndStyle: 'solid',
|
|
197
|
+
borderBlockEndColor: colorVars['--color-border-emphasized'],
|
|
198
|
+
marginInlineEnd: `calc(-1 * ${borderVars['--border-width']})`,
|
|
199
|
+
marginBlockEnd: `calc(-1 * ${borderVars['--border-width']})`,
|
|
200
|
+
// Alone on its line, the group fills the line, so its inline-end divider
|
|
201
|
+
// reaches the clipped edge.
|
|
202
|
+
flexGrow: 1,
|
|
174
203
|
minWidth: 140,
|
|
175
204
|
},
|
|
205
|
+
calendarPane: {
|
|
206
|
+
// Gives back the border width the preset group's margin takes, so the
|
|
207
|
+
// calendar keeps its side-by-side position.
|
|
208
|
+
marginInlineStart: borderVars['--border-width'],
|
|
209
|
+
// The row wraps on the calendar's one-month width, and the calendar then
|
|
210
|
+
// takes the free space, so its months sit in a row where they fit. The
|
|
211
|
+
// large factor keeps the preset group at its own width beside it.
|
|
212
|
+
flexBasis: 'min-content',
|
|
213
|
+
flexGrow: 1_000_000,
|
|
214
|
+
},
|
|
176
215
|
presetButton: {
|
|
177
216
|
display: 'block',
|
|
178
217
|
width: '100%',
|
|
@@ -805,79 +844,86 @@ export function DateRangeInput({
|
|
|
805
844
|
</VisuallyHidden>
|
|
806
845
|
)}
|
|
807
846
|
{popover.render(
|
|
808
|
-
<div {...stylex.props(styles.
|
|
809
|
-
{
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
847
|
+
<div {...stylex.props(styles.popoverScroll)}>
|
|
848
|
+
<div {...stylex.props(styles.popoverLayout)}>
|
|
849
|
+
{presets && presets.length > 0 && (
|
|
850
|
+
<div
|
|
851
|
+
role="group"
|
|
852
|
+
aria-label={t('@astryx.dateRangeInput.presetDateRanges')}
|
|
853
|
+
{...mergeProps(
|
|
854
|
+
themeProps('date-range-input-presets'),
|
|
855
|
+
stylex.props(styles.presetSidebar),
|
|
856
|
+
)}>
|
|
857
|
+
{presets.map(preset => {
|
|
858
|
+
const presetRange = preset.getRange();
|
|
859
|
+
const isActive = isRangeEqual(value, presetRange);
|
|
860
|
+
const isPresetDisabled =
|
|
861
|
+
isDisabled ||
|
|
862
|
+
!isRangeWithinSpan(
|
|
863
|
+
presetRange,
|
|
864
|
+
maxRangeSpan,
|
|
865
|
+
minRangeSpan,
|
|
866
|
+
) ||
|
|
867
|
+
isDateDisabled(plainDateFromISO(presetRange.start)) ||
|
|
868
|
+
isDateDisabled(plainDateFromISO(presetRange.end));
|
|
869
|
+
return (
|
|
870
|
+
<button
|
|
871
|
+
key={preset.label}
|
|
872
|
+
type="button"
|
|
873
|
+
// These presets are independent action buttons navigated by
|
|
874
|
+
// Tab, not a single-tab-stop listbox — so they are a labeled
|
|
875
|
+
// group of buttons, and the currently-applied preset is
|
|
876
|
+
// marked with aria-current (not aria-selected, a listbox
|
|
877
|
+
// concept that contradicted the Tab interaction) (forms-5).
|
|
878
|
+
aria-current={isActive ? 'true' : undefined}
|
|
879
|
+
// Focusable while disabled (AR3, spec:AST-085 FR1).
|
|
880
|
+
aria-disabled={isPresetDisabled || undefined}
|
|
881
|
+
aria-describedby={
|
|
882
|
+
showsDisabledMessage
|
|
883
|
+
? disabledMessageTooltip.describedBy
|
|
884
|
+
: undefined
|
|
845
885
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
886
|
+
onClick={() => {
|
|
887
|
+
if (!isPresetDisabled) {
|
|
888
|
+
handleRangeSelect(presetRange);
|
|
889
|
+
}
|
|
890
|
+
}}
|
|
891
|
+
{...mergeProps(
|
|
892
|
+
themeProps('date-range-input-preset', {
|
|
893
|
+
selected: isActive ? 'selected' : null,
|
|
894
|
+
disabled: isPresetDisabled ? 'disabled' : null,
|
|
895
|
+
}),
|
|
896
|
+
stylex.props(
|
|
897
|
+
focusOutlineStyles.focusVisible,
|
|
898
|
+
styles.presetButton,
|
|
899
|
+
isActive && styles.presetButtonActive,
|
|
900
|
+
isPresetDisabled && styles.presetButtonDisabled,
|
|
901
|
+
),
|
|
902
|
+
)}>
|
|
903
|
+
{preset.label}
|
|
904
|
+
</button>
|
|
905
|
+
);
|
|
906
|
+
})}
|
|
907
|
+
</div>
|
|
908
|
+
)}
|
|
909
|
+
{/* The layer renders its children open or closed, so mount the
|
|
866
910
|
calendar only while it is open. */}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
911
|
+
{popover.isOpen && (
|
|
912
|
+
<Calendar
|
|
913
|
+
mode="range"
|
|
914
|
+
value={optimisticValue}
|
|
915
|
+
onChange={handleRangeSelect}
|
|
916
|
+
min={min}
|
|
917
|
+
max={max}
|
|
918
|
+
dateConstraints={dateConstraints}
|
|
919
|
+
maxRangeSpan={maxRangeSpan}
|
|
920
|
+
minRangeSpan={minRangeSpan}
|
|
921
|
+
numberOfMonths={numberOfMonths}
|
|
922
|
+
weekStartsOn={weekStartsOn}
|
|
923
|
+
xstyle={presets && presets.length > 0 && styles.calendarPane}
|
|
924
|
+
/>
|
|
925
|
+
)}
|
|
926
|
+
</div>
|
|
881
927
|
</div>,
|
|
882
928
|
{placement: 'below', alignment: 'start'},
|
|
883
929
|
)}
|
package/src/Dialog/Dialog.tsx
CHANGED
|
@@ -80,7 +80,7 @@ import {themeProps} from '../utils/themeProps';
|
|
|
80
80
|
import type {DialogVariantMap} from './index';
|
|
81
81
|
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
82
82
|
import {useInteractionModalityTracking} from '../utils/interactionModality';
|
|
83
|
-
import {focusForLastInput} from '../utils/focusReturn';
|
|
83
|
+
import {focusForLastInput, isFocusLost} from '../utils/focusReturn';
|
|
84
84
|
import {ModalAnnounceProvider} from '../hooks/ModalAnnounceProvider';
|
|
85
85
|
|
|
86
86
|
import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
@@ -634,6 +634,42 @@ export function Dialog({
|
|
|
634
634
|
}
|
|
635
635
|
}, [isOpen, isInline]);
|
|
636
636
|
|
|
637
|
+
// A dialog that unmounts while open (rendered only while open, or removed
|
|
638
|
+
// with the rest of a view) never runs the close branch above, and removing a
|
|
639
|
+
// <dialog> does not run the browser's own focus return. Focus left inside
|
|
640
|
+
// it, or dropped to the body by the removal, goes back to the opener.
|
|
641
|
+
useEffect(() => {
|
|
642
|
+
if (isInline) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const dialog = dialogRef.current;
|
|
646
|
+
// Read now: a removed iframe's document has no window, so its frame
|
|
647
|
+
// element can no longer be found once the dialog is gone.
|
|
648
|
+
const host = dialog?.ownerDocument.defaultView?.frameElement ?? null;
|
|
649
|
+
return () => {
|
|
650
|
+
const trigger = triggerElementRef.current;
|
|
651
|
+
if (dialog == null || trigger == null) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
// Checked once the commit has finished: StrictMode's simulated unmount
|
|
655
|
+
// leaves the dialog in the document, and only a real removal returns
|
|
656
|
+
// focus.
|
|
657
|
+
queueMicrotask(() => {
|
|
658
|
+
if (dialog.isConnected || !trigger.isConnected) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
// isFocusLost reads the dialog's own document. For a dialog in an
|
|
662
|
+
// iframe, the document that hosts the frame must also have lost focus
|
|
663
|
+
// or keep it on that frame, wherever the opener is: a control the
|
|
664
|
+
// user pressed outside the frame to remove the dialog, or the frame
|
|
665
|
+
// itself, keeps its focus.
|
|
666
|
+
if (isFocusLost(dialog) && (host == null || isFocusLost(host))) {
|
|
667
|
+
focusForLastInput(trigger);
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
}, [isInline]);
|
|
672
|
+
|
|
637
673
|
// Host app-global surfaces (toasts) inside this modal while it is open, so
|
|
638
674
|
// they stay visible and operable above it.
|
|
639
675
|
useModalOutlet(dialogRef, isOpen && !isInline);
|
package/src/Drawer/Drawer.tsx
CHANGED
|
@@ -77,6 +77,7 @@ import {LayerDepthProvider, useLayerDismissal} from '../Layer';
|
|
|
77
77
|
import {layerTextReset} from '../Layer/layerTextReset.stylex';
|
|
78
78
|
import {layerStructureReset} from '../Layer/layerStructureReset.stylex';
|
|
79
79
|
import {LayerContentBoundary} from '../Layer/layerScopedContext';
|
|
80
|
+
import {useModalOutlet} from '../Layer/modalOutlet';
|
|
80
81
|
import {layerClickBoundary} from '../Layer/layerClickBoundary';
|
|
81
82
|
import {ModalAnnounceProvider} from '../hooks/ModalAnnounceProvider';
|
|
82
83
|
import {composeEventHandlers, mergeProps, themeProps} from '../utils';
|
|
@@ -497,6 +498,11 @@ export function Drawer({
|
|
|
497
498
|
setIsRendered,
|
|
498
499
|
});
|
|
499
500
|
|
|
501
|
+
// Toasts outside an open modal are inert, so the open drawer hosts them.
|
|
502
|
+
// It releases them when its exit starts.
|
|
503
|
+
// showModal() must run first, so keep this call after useDrawerDialogPresence.
|
|
504
|
+
useModalOutlet(dialogRef, isOpen && hasScrim);
|
|
505
|
+
|
|
500
506
|
const handleDismiss = useCallback(() => {
|
|
501
507
|
onOpenChange(false);
|
|
502
508
|
}, [onOpenChange]);
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
type SetStateAction,
|
|
33
33
|
} from 'react';
|
|
34
34
|
import {flushSync} from 'react-dom';
|
|
35
|
+
import {notifyTopLayerEntry} from '../Layer/modalOutlet';
|
|
35
36
|
|
|
36
37
|
/** Slack past the computed transition before the backstop gives up waiting. */
|
|
37
38
|
const EXIT_BACKSTOP_BUFFER_MS = 50;
|
|
@@ -71,6 +72,9 @@ function showDrawerHost(dialog: HTMLDialogElement, isModal: boolean): void {
|
|
|
71
72
|
dialog.showModal();
|
|
72
73
|
} else if (typeof dialog.showPopover === 'function') {
|
|
73
74
|
dialog.showPopover();
|
|
75
|
+
// The drawer is now the newest top-layer entry: global hosts shown before
|
|
76
|
+
// it (the toast viewport) re-enter above it, as they do above a modal.
|
|
77
|
+
notifyTopLayerEntry();
|
|
74
78
|
} else {
|
|
75
79
|
// Reduced fallback for browsers below the Popover API support floor.
|
|
76
80
|
dialog.show();
|
|
@@ -533,6 +533,20 @@ function holdInvokerThroughPress(
|
|
|
533
533
|
doc.addEventListener('pointercancel', onPressEnd, true);
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
+
/**
|
|
537
|
+
* The name of a menu opened from a custom trigger: the caller's `aria-label`
|
|
538
|
+
* when it is a non-empty string, else the trigger's own accessible name. The
|
|
539
|
+
* popover and the bottom sheet both name the menu through this.
|
|
540
|
+
*/
|
|
541
|
+
function resolveCustomTriggerMenuName(
|
|
542
|
+
callerLabel: unknown,
|
|
543
|
+
triggerName: string | undefined,
|
|
544
|
+
): string | undefined {
|
|
545
|
+
return typeof callerLabel === 'string' && callerLabel.trim() !== ''
|
|
546
|
+
? callerLabel
|
|
547
|
+
: triggerName;
|
|
548
|
+
}
|
|
549
|
+
|
|
536
550
|
function DropdownMenuBottomSheet({
|
|
537
551
|
button: buttonFromProps,
|
|
538
552
|
renderTrigger,
|
|
@@ -596,11 +610,22 @@ function DropdownMenuBottomSheet({
|
|
|
596
610
|
useEffect(() => {
|
|
597
611
|
void preloadMenuBottomSheetActionList();
|
|
598
612
|
}, []);
|
|
613
|
+
// The control's name is only readable from the DOM once it is rendered.
|
|
614
|
+
const [triggerName, setTriggerName] = useState<string | undefined>(undefined);
|
|
615
|
+
useIsomorphicLayoutEffect(() => {
|
|
616
|
+
if (renderTrigger != null && isOpen) {
|
|
617
|
+
setTriggerName(readAccessibleName(buttonRef.current));
|
|
618
|
+
}
|
|
619
|
+
}, [renderTrigger, isOpen]);
|
|
620
|
+
const rootTitle =
|
|
621
|
+
(renderTrigger != null
|
|
622
|
+
? resolveCustomTriggerMenuName(rest['aria-label'], triggerName)
|
|
623
|
+
: undefined) ?? button.label;
|
|
599
624
|
const currentSubmenu = submenuPath.at(-1);
|
|
600
625
|
const currentItems = currentSubmenu?.items ?? items;
|
|
601
|
-
const currentTitle = currentSubmenu?.label ??
|
|
626
|
+
const currentTitle = currentSubmenu?.label ?? rootTitle;
|
|
602
627
|
const sheetLabel =
|
|
603
|
-
typeof currentTitle === 'string' ? currentTitle :
|
|
628
|
+
typeof currentTitle === 'string' ? currentTitle : rootTitle;
|
|
604
629
|
|
|
605
630
|
const setOpen = useCallback(
|
|
606
631
|
(nextIsOpen: boolean) => {
|
|
@@ -1040,12 +1065,9 @@ function DropdownMenuPopover({
|
|
|
1040
1065
|
// The design system's button names the menu by its label. A custom trigger
|
|
1041
1066
|
// names it by reference (or the caller's `aria-label` does), so that name
|
|
1042
1067
|
// is read off the control as the menu opens.
|
|
1043
|
-
const callerMenuLabel = rest['aria-label'];
|
|
1044
1068
|
const menuLabel =
|
|
1045
1069
|
renderTrigger != null
|
|
1046
|
-
?
|
|
1047
|
-
? callerMenuLabel
|
|
1048
|
-
: triggerName
|
|
1070
|
+
? resolveCustomTriggerMenuName(rest['aria-label'], triggerName)
|
|
1049
1071
|
: typeof button.label === 'string'
|
|
1050
1072
|
? button.label
|
|
1051
1073
|
: undefined;
|
|
@@ -4,31 +4,62 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file useMenuOverflow.ts
|
|
7
|
-
* @input Menu element ref, rendered content, and
|
|
7
|
+
* @input Menu element ref, rendered content, open state, and optionally the
|
|
8
|
+
* overflow its owner expects from the content alone
|
|
8
9
|
* @output Returns whether the open menu overflows its block-size constraint
|
|
9
10
|
* @position Shared responsive helper for DropdownMenu and DropdownMenuSubMenu
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
useCallback,
|
|
15
|
+
useRef,
|
|
16
|
+
useState,
|
|
17
|
+
type ReactNode,
|
|
18
|
+
type RefObject,
|
|
19
|
+
} from 'react';
|
|
13
20
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
14
21
|
|
|
15
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Detect block-axis overflow without making a fitting menu a scroll container.
|
|
24
|
+
*
|
|
25
|
+
* `expectedOverflow` is the answer the owner can give before any measure (a
|
|
26
|
+
* long option list cannot fit). Until a measure of the same `content` says
|
|
27
|
+
* otherwise, it is the result, so the first open already renders the right
|
|
28
|
+
* class: a class that flips after the open measure restyles the whole list
|
|
29
|
+
* a second time. A measure still runs on every open and corrects a wrong
|
|
30
|
+
* guess.
|
|
31
|
+
*/
|
|
16
32
|
export function useMenuOverflow(
|
|
17
33
|
menuRef: RefObject<HTMLElement | null>,
|
|
18
34
|
content: ReactNode,
|
|
19
35
|
isOpen: boolean,
|
|
36
|
+
expectedOverflow?: boolean,
|
|
20
37
|
): boolean {
|
|
21
|
-
|
|
38
|
+
// The content each measure stands for, kept only for an owner that gives
|
|
39
|
+
// an expected answer (a caller whose content is a new element on every
|
|
40
|
+
// render compares nothing); set before the measuring effects run.
|
|
41
|
+
const contentRef = useRef<ReactNode>(null);
|
|
42
|
+
useIsomorphicLayoutEffect(() => {
|
|
43
|
+
contentRef.current = expectedOverflow === undefined ? null : content;
|
|
44
|
+
});
|
|
45
|
+
const [measured, setMeasured] = useState<{
|
|
46
|
+
content: ReactNode;
|
|
47
|
+
hasOverflow: boolean;
|
|
48
|
+
} | null>(null);
|
|
22
49
|
|
|
23
50
|
const measureOverflow = useCallback(() => {
|
|
24
51
|
const menu = menuRef.current;
|
|
25
52
|
if (!menu) {
|
|
26
53
|
return;
|
|
27
54
|
}
|
|
28
|
-
const
|
|
55
|
+
const hasOverflow = menu.scrollHeight > menu.clientHeight + 1;
|
|
29
56
|
// eslint-disable-next-line @eslint-react/set-state-in-effect -- DOM overflow measurement controls whether this menu becomes a scroll container
|
|
30
|
-
|
|
31
|
-
current
|
|
57
|
+
setMeasured(current =>
|
|
58
|
+
current != null &&
|
|
59
|
+
current.hasOverflow === hasOverflow &&
|
|
60
|
+
Object.is(current.content, contentRef.current)
|
|
61
|
+
? current
|
|
62
|
+
: {content: contentRef.current, hasOverflow},
|
|
32
63
|
);
|
|
33
64
|
}, [menuRef]);
|
|
34
65
|
|
|
@@ -73,5 +104,10 @@ export function useMenuOverflow(
|
|
|
73
104
|
}
|
|
74
105
|
}, [content, isOpen, measureOverflow]);
|
|
75
106
|
|
|
76
|
-
|
|
107
|
+
if (expectedOverflow === undefined) {
|
|
108
|
+
return measured?.hasOverflow ?? false;
|
|
109
|
+
}
|
|
110
|
+
return measured != null && Object.is(measured.content, content)
|
|
111
|
+
? measured.hasOverflow
|
|
112
|
+
: expectedOverflow;
|
|
77
113
|
}
|
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
typographyVars,
|
|
58
58
|
} from '../theme/tokens.stylex';
|
|
59
59
|
import type {BaseProps} from '../BaseProps';
|
|
60
|
+
import {textEntryTraitAttributes} from './textEntryTraits';
|
|
60
61
|
|
|
61
62
|
const styles = stylex.create({
|
|
62
63
|
// Gutter only. Matches the option list's own padding so the field below
|
|
@@ -273,6 +274,11 @@ export function PanelSearchInput({
|
|
|
273
274
|
<input
|
|
274
275
|
ref={mergedInputRef}
|
|
275
276
|
type="text"
|
|
277
|
+
// Autocorrect would rewrite names and identifiers.
|
|
278
|
+
{...textEntryTraitAttributes({
|
|
279
|
+
enterKeyHint: 'search',
|
|
280
|
+
hasAutoCorrect: false,
|
|
281
|
+
})}
|
|
276
282
|
aria-label={label}
|
|
277
283
|
placeholder={placeholder}
|
|
278
284
|
value={value}
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file textEntryTraits.ts
|
|
5
5
|
* @input The keyboard-trait props a text field accepts
|
|
6
|
-
* @output
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @position Shared by TextInput and TextArea: the one place that says how a
|
|
11
|
-
* field tells a touch keyboard what it holds
|
|
6
|
+
* @output EnterKeyHint, InputMode and AutoCapitalize (the package entry exports
|
|
7
|
+
* these), TextEntryTraitProps and textEntryTraitAttributes
|
|
8
|
+
* @position Shared by TextInput, TextArea and the search inputs: the one place
|
|
9
|
+
* that says how a field tells a touch keyboard what it holds
|
|
12
10
|
*
|
|
13
11
|
* SYNC: When modified, update:
|
|
14
12
|
* - /packages/core/src/TextInput/TextInput.tsx and TextInput.doc.mjs
|
|
15
13
|
* - /packages/core/src/TextArea/TextArea.tsx and TextArea.doc.mjs
|
|
14
|
+
* - /packages/core/src/Typeahead/BaseTypeahead.tsx, Field/PanelSearchInput.tsx
|
|
15
|
+
* and CommandPalette/CommandPaletteInput.tsx (the search inputs)
|
|
16
16
|
* - /packages/core/src/Field/index.ts (type exports)
|
|
17
17
|
*/
|
|
18
18
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @file layerClickBoundary.ts
|
|
7
7
|
* @input React pointer, mouse, touch and click events on a layer root
|
|
8
8
|
* @output Exports layerClickBoundary, the props every layer content root
|
|
9
|
-
* spreads, including the layer-root mark
|
|
9
|
+
* spreads, including the layer-root mark; also stopInReactTree
|
|
10
10
|
* @position Internal to Layer; used by useLayer's renderers and the Dialog,
|
|
11
11
|
* Drawer, Lightbox, MobileNav, BottomSheetPanel and ToastViewport roots.
|
|
12
12
|
* Not exported from the package.
|
|
@@ -61,7 +61,7 @@ const returnTrue = () => true;
|
|
|
61
61
|
* React's dispatch asks `isPropagationStopped()` before each further
|
|
62
62
|
* listener; the native event is left alone.
|
|
63
63
|
*/
|
|
64
|
-
function stopInReactTree(event: SyntheticEvent): void {
|
|
64
|
+
export function stopInReactTree(event: SyntheticEvent): void {
|
|
65
65
|
event.isPropagationStopped = returnTrue;
|
|
66
66
|
}
|
|
67
67
|
|