@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
|
@@ -157,6 +157,13 @@ export const docs = {
|
|
|
157
157
|
description:
|
|
158
158
|
'Key-down handler invoked before the built-in Enter/history behavior (after any open trigger menu). The seam for platform-specific keys: call event.preventDefault() to suppress the default submit (e.g. newline on a touch keyboard), or act on the event yourself to add behavior (e.g. submit on Cmd/Ctrl+Enter). IME composition is always respected; Enter never submits mid-composition.',
|
|
159
159
|
},
|
|
160
|
+
{
|
|
161
|
+
name: 'enterKeyHint',
|
|
162
|
+
type: "'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'",
|
|
163
|
+
description:
|
|
164
|
+
'What the Return key of a touch keyboard says (the native enterkeyhint). Enter sends the message, so it defaults to send and iOS shows its Send key. When onKeyDown makes Enter insert a line break on touch keyboards, pass enter so the key shows Return again.',
|
|
165
|
+
default: "'send'",
|
|
166
|
+
},
|
|
160
167
|
],
|
|
161
168
|
};
|
|
162
169
|
|
|
@@ -187,6 +194,8 @@ export const docsZh = {
|
|
|
187
194
|
onSubmit: '用户不按 Shift 按 Enter 时调用。序列化值包含标记占位符。',
|
|
188
195
|
onKeyDown:
|
|
189
196
|
'在内置 Enter/历史处理之前(在打开的触发菜单之后)调用的按键处理器。平台特定按键的接缝:调用 event.preventDefault() 可抑制默认提交(例如触控键盘上插入换行),或自行处理事件以添加行为(例如 Cmd/Ctrl+Enter 提交)。始终尊重输入法组字状态——组字过程中 Enter 永不提交。',
|
|
197
|
+
enterKeyHint:
|
|
198
|
+
'触屏键盘回车键上显示的内容(原生 enterkeyhint)。Enter 会发送消息,因此默认为 send,iOS 显示“发送”键。当 onKeyDown 让触屏键盘上的 Enter 插入换行时,传入 enter 让按键恢复为回车。',
|
|
190
199
|
},
|
|
191
200
|
};
|
|
192
201
|
|
|
@@ -219,5 +228,7 @@ export const docsDense = {
|
|
|
219
228
|
'Enter w/o Shift handler; serialized value includes token placeholders',
|
|
220
229
|
onKeyDown:
|
|
221
230
|
'keydown handler before built-in Enter/history (after trigger menu); preventDefault() to suppress default submit (touch newline) or act on event to add behavior (Cmd/Ctrl+Enter). IME composition always respected',
|
|
231
|
+
enterKeyHint:
|
|
232
|
+
'touch keyboard Return key label (enterkeyhint); default send since Enter sends; pass enter when onKeyDown makes Enter a newline on touch',
|
|
222
233
|
},
|
|
223
234
|
};
|
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
import {Badge, type BadgeProps} from '../Badge';
|
|
69
69
|
import {useChatComposerContext} from './ChatContext';
|
|
70
70
|
import {themeProps} from '../utils/themeProps';
|
|
71
|
+
import type {EnterKeyHint} from '../Field/textEntryTraits';
|
|
71
72
|
import {
|
|
72
73
|
registerEnglishFallback,
|
|
73
74
|
useComponentTranslator,
|
|
@@ -247,6 +248,14 @@ export interface ChatComposerInputProps extends Omit<
|
|
|
247
248
|
* never submits while a composition is in progress.
|
|
248
249
|
*/
|
|
249
250
|
onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
251
|
+
/**
|
|
252
|
+
* What the Return key of a touch keyboard says (the native
|
|
253
|
+
* `enterkeyhint`). Enter sends the message, so the key says so: iOS shows
|
|
254
|
+
* its Send key. When `onKeyDown` makes Enter insert a line break on touch
|
|
255
|
+
* keyboards, pass `'enter'` so the key shows Return again.
|
|
256
|
+
* @default 'send'
|
|
257
|
+
*/
|
|
258
|
+
enterKeyHint?: EnterKeyHint;
|
|
250
259
|
}
|
|
251
260
|
|
|
252
261
|
// =============================================================================
|
|
@@ -373,6 +382,7 @@ export function ChatComposerInput(props: ChatComposerInputProps) {
|
|
|
373
382
|
onFiles,
|
|
374
383
|
onSubmit = composerCtx?.onSubmit,
|
|
375
384
|
onKeyDown: onKeyDownProp,
|
|
385
|
+
enterKeyHint = 'send',
|
|
376
386
|
xstyle,
|
|
377
387
|
className,
|
|
378
388
|
style,
|
|
@@ -941,6 +951,7 @@ export function ChatComposerInput(props: ChatComposerInputProps) {
|
|
|
941
951
|
// Explicit in both states: losing editability must not lose focus.
|
|
942
952
|
tabIndex={0}
|
|
943
953
|
contentEditable={!isDisabled}
|
|
954
|
+
enterKeyHint={enterKeyHint}
|
|
944
955
|
suppressContentEditableWarning
|
|
945
956
|
onInput={handleInput}
|
|
946
957
|
onClick={handleEditorClick}
|
package/src/Chat/ChatMessage.tsx
CHANGED
|
@@ -118,7 +118,7 @@ const styles = stylex.create({
|
|
|
118
118
|
// Judged from this article (parent-relative), never from siblings, so the
|
|
119
119
|
// global stylesheet keeps no sibling-relative :has().
|
|
120
120
|
avatarOffset: {
|
|
121
|
-
[chatMessageVars
|
|
121
|
+
[chatMessageVars['--_chat-avatar-offset']]: {
|
|
122
122
|
default: '0px',
|
|
123
123
|
':has([data-chat-name])': spacingVars['--spacing-5'],
|
|
124
124
|
},
|
|
@@ -128,7 +128,7 @@ const styles = stylex.create({
|
|
|
128
128
|
flexShrink: 0,
|
|
129
129
|
// The avatar lines up with a bubble's name row when the message holds
|
|
130
130
|
// one; the article sets the offset (see chatMessageVars).
|
|
131
|
-
marginBlockStart: chatMessageVars
|
|
131
|
+
marginBlockStart: chatMessageVars['--_chat-avatar-offset'],
|
|
132
132
|
},
|
|
133
133
|
contentColumn: {
|
|
134
134
|
display: 'flex',
|
|
@@ -5,14 +5,14 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
5
5
|
/**
|
|
6
6
|
* Per-message values ChatMessage sets on its article for its own slots.
|
|
7
7
|
*
|
|
8
|
-
* `
|
|
9
|
-
* bubble in this message renders a name, else none. Each article sets
|
|
10
|
-
* its own `:has([data-chat-name])`, a parent-relative rule: a
|
|
11
|
-
* `:has(~ …)` in the global stylesheet makes WebKit re-check
|
|
12
|
-
* sibling on each insertion into any container, so filling one
|
|
13
|
-
* quadratically. A message nested in another sets its own value, so it
|
|
14
|
-
* inherits the outer message's.
|
|
8
|
+
* `--_chat-avatar-offset` is the avatar's top spacing: the name row's spacing
|
|
9
|
+
* when a bubble in this message renders a name, else none. Each article sets
|
|
10
|
+
* it from its own `:has([data-chat-name])`, a parent-relative rule: a
|
|
11
|
+
* sibling-relative `:has(~ …)` in the global stylesheet makes WebKit re-check
|
|
12
|
+
* every earlier sibling on each insertion into any container, so filling one
|
|
13
|
+
* grows quadratically. A message nested in another sets its own value, so it
|
|
14
|
+
* never inherits the outer message's.
|
|
15
15
|
*/
|
|
16
16
|
export const chatMessageVars = stylex.defineVars({
|
|
17
|
-
|
|
17
|
+
'--_chat-avatar-offset': '0px',
|
|
18
18
|
});
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
useComponentTranslator,
|
|
47
47
|
} from '../i18n/useComponentTranslator';
|
|
48
48
|
import english from '../i18n/generated-english/CommandPalette/CommandPaletteInput.generated';
|
|
49
|
+
import {textEntryTraitAttributes} from '../Field/textEntryTraits';
|
|
49
50
|
|
|
50
51
|
registerEnglishFallback(english);
|
|
51
52
|
const styles = stylex.create({
|
|
@@ -320,6 +321,11 @@ export function CommandPaletteInput({
|
|
|
320
321
|
? focusOutlineProps.focusVisible(styles.input)
|
|
321
322
|
: focusOutlineProps.suppressed(styles.input))}
|
|
322
323
|
type="text"
|
|
324
|
+
// Autocorrect would rewrite names and identifiers.
|
|
325
|
+
{...textEntryTraitAttributes({
|
|
326
|
+
enterKeyHint: 'search',
|
|
327
|
+
hasAutoCorrect: false,
|
|
328
|
+
})}
|
|
323
329
|
role={ctx ? 'combobox' : standaloneRole}
|
|
324
330
|
aria-expanded={
|
|
325
331
|
ctx
|
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
plainDateToISO,
|
|
63
63
|
DATE_FORMAT_WITH_WEEKDAY,
|
|
64
64
|
} from '../utils';
|
|
65
|
+
import {reducedMotionFade} from '../motion/reducedMotion';
|
|
65
66
|
import {dateInputTouchSizes, dateInputTouchGeometry} from './tokens.stylex';
|
|
66
67
|
import {useOwnScrollGesture} from './useOwnScrollGesture';
|
|
67
68
|
import {useScrollSettle} from './useScrollSettle';
|
|
@@ -431,8 +432,26 @@ export function MonthScroller({
|
|
|
431
432
|
);
|
|
432
433
|
}, [paneSize, initialMonthIndex, minMonthIndex, isRTL]);
|
|
433
434
|
|
|
435
|
+
// The Reduced Motion dip of a step on a touch screen, owned here so a
|
|
436
|
+
// second step or the unmount clears it.
|
|
437
|
+
const dipRef = useRef<{animation: Animation; timer: number} | null>(null);
|
|
438
|
+
const stopDip = useCallback(() => {
|
|
439
|
+
const dip = dipRef.current;
|
|
440
|
+
if (dip != null) {
|
|
441
|
+
window.clearTimeout(dip.timer);
|
|
442
|
+
dip.animation.cancel();
|
|
443
|
+
dipRef.current = null;
|
|
444
|
+
}
|
|
445
|
+
}, []);
|
|
446
|
+
// Synchronizes with the dip's timer and animation: neither outlives the
|
|
447
|
+
// scroller.
|
|
448
|
+
useEffect(() => stopDip, [stopDip]);
|
|
449
|
+
|
|
434
450
|
const scrollToMonth = useCallback(
|
|
435
451
|
(monthIndex: number, behavior: ScrollBehavior = 'smooth') => {
|
|
452
|
+
// Every step replaces a running dip, whichever way it moves. Otherwise
|
|
453
|
+
// the dip's landing would undo a jump or an immediate step made after it.
|
|
454
|
+
stopDip();
|
|
436
455
|
const scroller = scrollerRef.current;
|
|
437
456
|
if (scroller == null || paneSize === 0) {
|
|
438
457
|
return;
|
|
@@ -458,13 +477,52 @@ export function MonthScroller({
|
|
|
458
477
|
recenter(scroller, row);
|
|
459
478
|
return;
|
|
460
479
|
}
|
|
480
|
+
const left = scrollOffsetForRow(row, paneSize, isRTL);
|
|
481
|
+
// Under reduced motion the month changes without travel: at once on a fine
|
|
482
|
+
// primary pointer, under an opacity dip on a coarse one (reducedMotionFade).
|
|
483
|
+
const fade = behavior === 'smooth' ? reducedMotionFade(scroller) : null;
|
|
484
|
+
if (fade != null) {
|
|
485
|
+
// The window mounts around the target first, and the scroll lands in
|
|
486
|
+
// the layout effect below, as a far jump does. So nothing moves the
|
|
487
|
+
// window after the jump. If the window followed the jump, WebKit would
|
|
488
|
+
// re-snap it one pane further on every frame. A scroll that lands on
|
|
489
|
+
// the centre row reports nothing.
|
|
490
|
+
const land = () => {
|
|
491
|
+
// The landing is the newest steer. An earlier steer whose scroll
|
|
492
|
+
// never arrived would otherwise hide every scroll after it, a
|
|
493
|
+
// trackpad's included. Closing the wheels makes such a steer: it
|
|
494
|
+
// re-asserts the month already in view.
|
|
495
|
+
steeredRowRef.current = null;
|
|
496
|
+
if (row === centerRowRef.current) {
|
|
497
|
+
scroller.scrollTo({left, behavior: 'auto'});
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
pendingScrollRef.current = row;
|
|
501
|
+
centerRowRef.current = row;
|
|
502
|
+
setCenterRow(row);
|
|
503
|
+
};
|
|
504
|
+
if (fade.duration === 0) {
|
|
505
|
+
land();
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
// A second step within the dip has replaced the first (above): only
|
|
509
|
+
// its scroll lands, at its own dip's middle.
|
|
510
|
+
dipRef.current = {
|
|
511
|
+
animation: scroller.animate(
|
|
512
|
+
[{opacity: 1}, {opacity: 0}, {opacity: 1}],
|
|
513
|
+
{duration: fade.duration, easing: fade.easing},
|
|
514
|
+
),
|
|
515
|
+
timer: window.setTimeout(() => {
|
|
516
|
+
dipRef.current = null;
|
|
517
|
+
land();
|
|
518
|
+
}, fade.duration / 2),
|
|
519
|
+
};
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
461
522
|
steeredRowRef.current = row;
|
|
462
|
-
scroller.scrollTo({
|
|
463
|
-
left: scrollOffsetForRow(row, paneSize, isRTL),
|
|
464
|
-
behavior,
|
|
465
|
-
});
|
|
523
|
+
scroller.scrollTo({left, behavior});
|
|
466
524
|
},
|
|
467
|
-
[paneSize, minMonthIndex, rowCount, isRTL, recenter],
|
|
525
|
+
[paneSize, minMonthIndex, rowCount, isRTL, recenter, stopDip],
|
|
468
526
|
);
|
|
469
527
|
|
|
470
528
|
// Deliberately un-keyed: it runs after every render, costs a null check, and
|
package/src/DateInput/Wheel.tsx
CHANGED
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
* browser that does not understand `animation-timeline` would otherwise run
|
|
22
22
|
* the same keyframes on the document timeline and simply play them once.
|
|
23
23
|
*
|
|
24
|
+
* Under Reduce Motion, the wheel's own scrolls (a step from a key or a click,
|
|
25
|
+
* the travel to the nearest enabled row) land without travel. They cross-fade
|
|
26
|
+
* on a touch screen and land at once otherwise. A finger's scroll and its
|
|
27
|
+
* momentum stay the platform's.
|
|
28
|
+
*
|
|
24
29
|
* Accessibility: this is a listbox, not a novel widget. It is one tab stop
|
|
25
30
|
* with arrow/Home/End/PageUp/PageDown keys, `aria-activedescendant` tracking
|
|
26
31
|
* the active row, and every row reachable by tap — none of which depends on
|
|
@@ -44,6 +49,7 @@ import {
|
|
|
44
49
|
durationVars,
|
|
45
50
|
} from '../theme/tokens.stylex';
|
|
46
51
|
import {focusOutlineStyles} from '../utils';
|
|
52
|
+
import {reducedMotionFade} from '../motion/reducedMotion';
|
|
47
53
|
import {dateInputTouchSizes, dateInputTouchGeometry} from './tokens.stylex';
|
|
48
54
|
import {useOwnScrollGesture} from './useOwnScrollGesture';
|
|
49
55
|
import {usePointerDragScroll} from './usePointerDragScroll';
|
|
@@ -209,7 +215,10 @@ export interface WheelOption {
|
|
|
209
215
|
value: number;
|
|
210
216
|
/** Row text. */
|
|
211
217
|
label: string;
|
|
212
|
-
/**
|
|
218
|
+
/**
|
|
219
|
+
* Rows outside min/max stay visible but cannot be committed: a wheel that
|
|
220
|
+
* stops on one travels on to the nearest enabled row.
|
|
221
|
+
*/
|
|
213
222
|
isDisabled?: boolean;
|
|
214
223
|
}
|
|
215
224
|
|
|
@@ -229,6 +238,46 @@ export interface WheelProps {
|
|
|
229
238
|
isActive?: boolean;
|
|
230
239
|
}
|
|
231
240
|
|
|
241
|
+
/**
|
|
242
|
+
* The enabled row nearest `index`: `index` itself when it is enabled,
|
|
243
|
+
* otherwise the closest enabled row on either side. A tie goes to the side of
|
|
244
|
+
* `towardIndex` (the committed row), and a wheel with no enabled row stays on
|
|
245
|
+
* `towardIndex`.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```
|
|
249
|
+
* // Hours 0-23 with 09:00-17:00 bounds: stopping on 7 rests on 9.
|
|
250
|
+
* nearestEnabledIndex(hourOptions, 7, 10); // 9
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
export function nearestEnabledIndex(
|
|
254
|
+
options: ReadonlyArray<WheelOption>,
|
|
255
|
+
index: number,
|
|
256
|
+
towardIndex: number,
|
|
257
|
+
): number {
|
|
258
|
+
const isEnabled = (i: number) =>
|
|
259
|
+
i >= 0 && i < options.length && !options[i].isDisabled;
|
|
260
|
+
if (isEnabled(index)) {
|
|
261
|
+
return index;
|
|
262
|
+
}
|
|
263
|
+
for (let distance = 1; distance < options.length; distance++) {
|
|
264
|
+
const below = index - distance;
|
|
265
|
+
const above = index + distance;
|
|
266
|
+
const isBelowEnabled = isEnabled(below);
|
|
267
|
+
const isAboveEnabled = isEnabled(above);
|
|
268
|
+
if (isBelowEnabled && isAboveEnabled) {
|
|
269
|
+
return towardIndex < index ? below : above;
|
|
270
|
+
}
|
|
271
|
+
if (isBelowEnabled) {
|
|
272
|
+
return below;
|
|
273
|
+
}
|
|
274
|
+
if (isAboveEnabled) {
|
|
275
|
+
return above;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return towardIndex;
|
|
279
|
+
}
|
|
280
|
+
|
|
232
281
|
/**
|
|
233
282
|
* One snap-scrolling picker column.
|
|
234
283
|
*
|
|
@@ -275,20 +324,100 @@ export function Wheel({
|
|
|
275
324
|
: 0;
|
|
276
325
|
}, []);
|
|
277
326
|
|
|
327
|
+
// What last started a scroll of the wheel: a pointer's type, or 'wheel'
|
|
328
|
+
// for a mouse wheel or trackpad. Under Reduce Motion the release of a touch
|
|
329
|
+
// drag cross-fades on any primary pointer. A key step, a row tap or a
|
|
330
|
+
// trackpad's scroll cross-fades on a coarse primary pointer and lands at
|
|
331
|
+
// once on a fine one.
|
|
332
|
+
const lastPointerRef = useRef<string | null>(null);
|
|
333
|
+
|
|
334
|
+
// A reduced-motion dip whose rows have not landed yet: its timer and the
|
|
335
|
+
// row it lands on. While one is pending the rows stay put for it, so they
|
|
336
|
+
// never move at full opacity, and a further step retargets it.
|
|
337
|
+
const pendingFadeRef = useRef<{timer: number; top: number} | null>(null);
|
|
338
|
+
// The running dip, so a step during its fade-in starts the next one where
|
|
339
|
+
// the column is.
|
|
340
|
+
const dipRef = useRef<Animation | null>(null);
|
|
341
|
+
useEffect(
|
|
342
|
+
() => () => {
|
|
343
|
+
if (pendingFadeRef.current != null) {
|
|
344
|
+
window.clearTimeout(pendingFadeRef.current.timer);
|
|
345
|
+
pendingFadeRef.current = null;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
[],
|
|
349
|
+
);
|
|
350
|
+
|
|
278
351
|
const scrollToIndex = useCallback(
|
|
279
|
-
(
|
|
352
|
+
(
|
|
353
|
+
index: number,
|
|
354
|
+
behavior: ScrollBehavior,
|
|
355
|
+
{touchRelease = false}: {touchRelease?: boolean} = {},
|
|
356
|
+
) => {
|
|
280
357
|
const scroller = scrollerRef.current;
|
|
281
358
|
const size = itemBlockSize();
|
|
282
359
|
if (scroller == null || size === 0) {
|
|
283
360
|
return;
|
|
284
361
|
}
|
|
285
|
-
|
|
362
|
+
const top = index * size;
|
|
363
|
+
// Under Reduce Motion the wheel's own scroll lands without travel. It
|
|
364
|
+
// dips on a touch screen or for a touch drag's release. Otherwise it
|
|
365
|
+
// lands at once.
|
|
366
|
+
const fadeTiming =
|
|
367
|
+
behavior === 'smooth'
|
|
368
|
+
? reducedMotionFade(scroller, {touchRelease})
|
|
369
|
+
: null;
|
|
370
|
+
const pending = pendingFadeRef.current;
|
|
371
|
+
if (fadeTiming == null) {
|
|
372
|
+
if (pending != null) {
|
|
373
|
+
window.clearTimeout(pending.timer);
|
|
374
|
+
pendingFadeRef.current = null;
|
|
375
|
+
}
|
|
376
|
+
scroller.scrollTo({top, behavior});
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (fadeTiming.duration === 0 || typeof scroller.animate !== 'function') {
|
|
380
|
+
if (pending != null) {
|
|
381
|
+
window.clearTimeout(pending.timer);
|
|
382
|
+
pendingFadeRef.current = null;
|
|
383
|
+
}
|
|
384
|
+
scroller.scrollTo({top, behavior: 'auto'});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (pending != null) {
|
|
388
|
+
// The dip is still fading out: its rows land here instead.
|
|
389
|
+
pending.top = top;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const {duration, easing} = fadeTiming;
|
|
393
|
+
// A step during the last dip's fade-in starts the new dip at the
|
|
394
|
+
// column's current opacity, not at full opacity. A leaving element fades
|
|
395
|
+
// out from where it is.
|
|
396
|
+
const shown = Number.parseFloat(getComputedStyle(scroller).opacity);
|
|
397
|
+
dipRef.current?.cancel();
|
|
398
|
+
dipRef.current = scroller.animate(
|
|
399
|
+
[
|
|
400
|
+
{opacity: Number.isFinite(shown) ? shown : 1, easing},
|
|
401
|
+
{opacity: 0, easing},
|
|
402
|
+
{opacity: 1},
|
|
403
|
+
],
|
|
404
|
+
{duration, easing: 'linear'},
|
|
405
|
+
);
|
|
406
|
+
const landing = {top, timer: 0};
|
|
407
|
+
landing.timer = window.setTimeout(() => {
|
|
408
|
+
pendingFadeRef.current = null;
|
|
409
|
+
scroller.scrollTo({top: landing.top, behavior: 'auto'});
|
|
410
|
+
}, duration / 2);
|
|
411
|
+
pendingFadeRef.current = landing;
|
|
286
412
|
},
|
|
287
413
|
[itemBlockSize],
|
|
288
414
|
);
|
|
289
415
|
|
|
290
|
-
// Commit on rest. A disabled row
|
|
291
|
-
//
|
|
416
|
+
// Commit on rest. A wheel that stops on a disabled row travels on to the
|
|
417
|
+
// nearest enabled row, as UIDatePicker does. That second rest commits it.
|
|
418
|
+
// A rest on the committed row is not a stop to correct. The park after the
|
|
419
|
+
// sheet opens rests there with no touch. A committed value outside the
|
|
420
|
+
// bounds stays until a person moves the wheel.
|
|
292
421
|
//
|
|
293
422
|
// Declared here, above the park effect, because that effect consults the
|
|
294
423
|
// `isAtRestRef` this returns before it repositions anything.
|
|
@@ -303,12 +432,18 @@ export function Wheel({
|
|
|
303
432
|
options.length - 1,
|
|
304
433
|
Math.max(0, Math.round(scroller.scrollTop / size)),
|
|
305
434
|
);
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
435
|
+
const restIndex =
|
|
436
|
+
index === selectedIndex
|
|
437
|
+
? index
|
|
438
|
+
: nearestEnabledIndex(options, index, selectedIndex);
|
|
439
|
+
if (restIndex !== index) {
|
|
440
|
+
scrollToIndex(restIndex, 'smooth', {
|
|
441
|
+
touchRelease: lastPointerRef.current === 'touch',
|
|
442
|
+
});
|
|
309
443
|
return;
|
|
310
444
|
}
|
|
311
|
-
|
|
445
|
+
const option = options[index];
|
|
446
|
+
if (option != null && !option.isDisabled && option.value !== value) {
|
|
312
447
|
onChange(option.value);
|
|
313
448
|
}
|
|
314
449
|
},
|
|
@@ -316,8 +451,11 @@ export function Wheel({
|
|
|
316
451
|
isDraggingRef,
|
|
317
452
|
);
|
|
318
453
|
|
|
319
|
-
// Park the committed row under the band whenever the wheel is
|
|
320
|
-
// value
|
|
454
|
+
// Park the committed row under the band at once whenever the wheel is
|
|
455
|
+
// shown. A value that changes from outside while the wheel is shown turns
|
|
456
|
+
// the wheel onto its row instead. UIDatePicker turns onto its maximum the
|
|
457
|
+
// same way, and never jumps there. For example, a bound clamps the time
|
|
458
|
+
// after another wheel turned, or the calendar moved to another month.
|
|
321
459
|
//
|
|
322
460
|
// NEVER while the wheel is still moving. A scroller that is mid-gesture or
|
|
323
461
|
// still carrying momentum is the user's, and repositioning it does not stop
|
|
@@ -325,8 +463,15 @@ export function Wheel({
|
|
|
325
463
|
// as a new settle, commits the next row along, and parks again. See
|
|
326
464
|
// useScrollSettle. The settle handler re-checks the position afterwards, so
|
|
327
465
|
// a correction that is genuinely needed still happens, just at rest.
|
|
466
|
+
const parkedRef = useRef(false);
|
|
328
467
|
useEffect(() => {
|
|
329
|
-
if (!isActive
|
|
468
|
+
if (!isActive) {
|
|
469
|
+
parkedRef.current = false;
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// Nor while a reduced-motion dip is still to land its rows: they land
|
|
473
|
+
// under it, on this row.
|
|
474
|
+
if (!isAtRestRef.current || pendingFadeRef.current != null) {
|
|
330
475
|
return;
|
|
331
476
|
}
|
|
332
477
|
const size = itemBlockSize();
|
|
@@ -335,11 +480,16 @@ export function Wheel({
|
|
|
335
480
|
return;
|
|
336
481
|
}
|
|
337
482
|
if (Math.round(scroller.scrollTop / size) !== selectedIndex) {
|
|
338
|
-
|
|
483
|
+
if (parkedRef.current) {
|
|
484
|
+
scrollToIndex(selectedIndex, 'smooth');
|
|
485
|
+
} else {
|
|
486
|
+
scroller.scrollTo({top: selectedIndex * size, behavior: 'auto'});
|
|
487
|
+
}
|
|
339
488
|
}
|
|
489
|
+
parkedRef.current = true;
|
|
340
490
|
// eslint-disable-next-line @eslint-react/set-state-in-effect -- the highlight follows a scroll position, which only exists after layout
|
|
341
491
|
setActiveIndex(selectedIndex);
|
|
342
|
-
}, [isActive, selectedIndex, itemBlockSize, isAtRestRef]);
|
|
492
|
+
}, [isActive, selectedIndex, itemBlockSize, isAtRestRef, scrollToIndex]);
|
|
343
493
|
|
|
344
494
|
// Highlight follows the finger. rAF-throttled: a scroll can fire far more
|
|
345
495
|
// often than the display refreshes, and this only feeds a repaint.
|
|
@@ -446,6 +596,16 @@ export function Wheel({
|
|
|
446
596
|
aria-activedescendant={`${id}-${options[activeIndex]?.value}`}
|
|
447
597
|
tabIndex={0}
|
|
448
598
|
onKeyDown={handleKeyDown}
|
|
599
|
+
// Read in the capture phase. usePointerDragScroll stops a primary
|
|
600
|
+
// mouse press from bubbling, so that it does not reach BottomSheet's
|
|
601
|
+
// drag. A bubbling handler would never see a mouse, and would keep the
|
|
602
|
+
// last touch.
|
|
603
|
+
onPointerDownCapture={event => {
|
|
604
|
+
lastPointerRef.current = event.pointerType;
|
|
605
|
+
}}
|
|
606
|
+
onWheel={() => {
|
|
607
|
+
lastPointerRef.current = 'wheel';
|
|
608
|
+
}}
|
|
449
609
|
{...stylex.props(styles.scroller, focusOutlineStyles.focusVisible)}>
|
|
450
610
|
{options.map((option, index) => (
|
|
451
611
|
<div
|
|
@@ -115,7 +115,7 @@ export const docs = {
|
|
|
115
115
|
name: 'presets',
|
|
116
116
|
type: 'Array<DateRangePreset>',
|
|
117
117
|
description:
|
|
118
|
-
'Preset ranges shown as quick-select options beside the calendar. A preset is disabled when either endpoint violates min, max, or dateConstraints, or when its span violates minRangeSpan or maxRangeSpan.',
|
|
118
|
+
'Preset ranges shown as quick-select options beside the calendar, or above it when the two do not fit side by side. A preset is disabled when either endpoint violates min, max, or dateConstraints, or when its span violates minRangeSpan or maxRangeSpan.',
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
name: 'hasClear',
|
|
@@ -277,7 +277,8 @@ export const docs = {
|
|
|
277
277
|
{
|
|
278
278
|
name: 'Preset sidebar',
|
|
279
279
|
required: false,
|
|
280
|
-
description:
|
|
280
|
+
description:
|
|
281
|
+
'A list of preset range options beside the calendar, or above it when the two do not fit side by side.',
|
|
281
282
|
},
|
|
282
283
|
{
|
|
283
284
|
name: 'Preset button',
|