@astryxdesign/core 0.7.8 → 0.7.9-canary.0a64fdb
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/observeMainOverflow.d.ts.map +1 -1
- package/dist/AppShell/observeMainOverflow.js +9 -6
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +5 -0
- package/dist/Calendar/styles.d.ts +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +54 -11
- package/dist/ClickableCard/ClickableCard.d.ts +1 -1
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +5 -1
- package/dist/DateInput/PickerWheel.d.ts.map +1 -1
- package/dist/DateInput/PickerWheel.js +7 -1
- package/dist/DateRangeInput/DateRangeInput.js +1 -1
- package/dist/Dialog/Dialog.d.ts +2 -1
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -1
- package/dist/Drawer/useDrawerDialogPresence.d.ts +2 -1
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
- package/dist/Drawer/useDrawerDialogPresence.js +11 -2
- package/dist/DropdownMenu/DropdownMenu.d.ts +9 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +9 -4
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +3 -2
- package/dist/Field/inputDisabledFocus.d.ts +4 -4
- package/dist/Field/inputStyles.stylex.d.ts +1 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +16 -2
- package/dist/Icon/Icon.d.ts +1 -1
- package/dist/InfoTip/InfoTip.d.ts +1 -0
- package/dist/InfoTip/InfoTip.d.ts.map +1 -1
- package/dist/InfoTip/InfoTip.js +1 -0
- package/dist/InputGroup/InputGroup.d.ts +4 -3
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +2 -2
- package/dist/InputGroup/groupStyles.d.ts +1 -1
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +1 -1
- package/dist/Item/Item.d.ts +2 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +29 -6
- package/dist/Layer/holdEntranceInput.d.ts +24 -0
- package/dist/Layer/holdEntranceInput.d.ts.map +1 -0
- package/dist/Layer/holdEntranceInput.js +65 -0
- package/dist/Layer/inputHold.d.ts +49 -0
- package/dist/Layer/inputHold.d.ts.map +1 -0
- package/dist/Layer/inputHold.js +636 -0
- package/dist/Layer/preserveAnimations.d.ts +1 -5
- package/dist/Layer/preserveAnimations.d.ts.map +1 -1
- package/dist/Layer/preserveAnimations.js +12 -214
- package/dist/Layout/LayoutContent.d.ts +3 -1
- package/dist/Layout/LayoutContent.d.ts.map +1 -1
- package/dist/Layout/LayoutContent.js +12 -4
- package/dist/Layout/LayoutPanel.d.ts +4 -1
- package/dist/Layout/LayoutPanel.d.ts.map +1 -1
- package/dist/Layout/LayoutPanel.js +13 -4
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -0
- package/dist/MetadataList/MetadataList.js +1 -1
- package/dist/MobileNav/MobileNav.d.ts +11 -1
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +39 -1
- package/dist/MoreMenu/MoreMenu.d.ts +5 -3
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +22 -4
- package/dist/SelectableCard/SelectableCard.d.ts +1 -1
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +5 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +12 -2
- package/dist/Stack/StackItem.d.ts +8 -4
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +17 -4
- package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +9 -0
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +4 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +162 -59
- package/dist/TreeList/TreeListItem.d.ts +2 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +27 -3
- package/dist/astryx.css +35 -8
- package/dist/gestures/GestureHost.d.ts +2 -2
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +21 -6
- package/dist/gestures/PanGestureRecognizer.d.ts +11 -1
- package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/PanGestureRecognizer.js +15 -1
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +6 -1
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/nativeScroll.d.ts +3 -6
- package/dist/gestures/nativeScroll.d.ts.map +1 -1
- package/dist/gestures/nativeScroll.js +7 -52
- package/dist/gestures/wheelSegmenter.d.ts +68 -1
- package/dist/gestures/wheelSegmenter.d.ts.map +1 -1
- package/dist/gestures/wheelSegmenter.js +199 -10
- package/dist/hooks/StackItemScrollRegion.d.ts +31 -0
- package/dist/hooks/StackItemScrollRegion.d.ts.map +1 -0
- package/dist/hooks/StackItemScrollRegion.js +40 -0
- package/dist/hooks/menuPressGesture.d.ts +133 -21
- package/dist/hooks/menuPressGesture.d.ts.map +1 -1
- package/dist/hooks/menuPressGesture.js +155 -30
- package/dist/hooks/menuPressValues.d.ts +16 -0
- package/dist/hooks/menuPressValues.d.ts.map +1 -0
- package/dist/hooks/menuPressValues.js +18 -0
- package/dist/hooks/useClickableContainer.d.ts +27 -5
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +41 -5
- package/dist/hooks/useFocusTrap.d.ts +10 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +225 -132
- package/dist/hooks/useMenuPress.d.ts +34 -1
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +93 -5
- package/dist/hooks/usePressFeedback.d.ts +6 -6
- package/dist/hooks/usePressFeedback.js +6 -6
- package/dist/hooks/useScrollRegionProps.d.ts +35 -0
- package/dist/hooks/useScrollRegionProps.d.ts.map +1 -0
- package/dist/hooks/useScrollRegionProps.js +51 -0
- package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts +8 -0
- package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.js +12 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +1 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
- package/dist/motion/carryAnimations.d.ts +58 -0
- package/dist/motion/carryAnimations.d.ts.map +1 -0
- package/dist/motion/carryAnimations.js +305 -0
- package/dist/motion/transientCopy.d.ts +4 -2
- package/dist/motion/transientCopy.d.ts.map +1 -1
- package/dist/motion/transientCopy.js +34 -5
- package/dist/motion/uikit/gestures.d.ts +41 -0
- package/dist/motion/uikit/gestures.d.ts.map +1 -1
- package/dist/motion/uikit/gestures.js +25 -0
- package/dist/motion/uikit/index.d.ts +1 -1
- package/dist/motion/uikit/index.d.ts.map +1 -1
- package/dist/motion/uikit/index.js +1 -1
- package/dist/privateAttributes/menuPressLit.stylex.d.ts +52 -0
- package/dist/privateAttributes/menuPressLit.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/menuPressLit.stylex.js +99 -0
- package/dist/privateAttributes/press.stylex.d.ts +139 -0
- package/dist/privateAttributes/press.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/press.stylex.js +98 -0
- package/dist/theme/tokens.stylex.d.ts +2 -2
- package/dist/theme/tokens.stylex.js +1 -1
- package/dist/utils/flatTree.d.ts +6 -3
- package/dist/utils/flatTree.d.ts.map +1 -1
- package/dist/utils/flatTree.js +13 -3
- package/dist/utils/hitArea.d.ts.map +1 -1
- package/dist/utils/hitArea.js +82 -5
- package/dist/utils/inputStream.d.ts +14 -1
- package/dist/utils/inputStream.d.ts.map +1 -1
- package/dist/utils/inputStream.js +40 -9
- package/dist/utils/interactionOverlay.stylex.d.ts +2 -1
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +7 -2
- package/dist/utils/pressFeedback.d.ts +7 -0
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +32 -7
- package/dist/utils/pressGesture.d.ts +6 -0
- package/dist/utils/pressGesture.d.ts.map +1 -1
- package/dist/utils/pressGesture.js +17 -0
- package/dist/utils/rowPressLayer.stylex.d.ts +14 -0
- package/dist/utils/rowPressLayer.stylex.d.ts.map +1 -0
- package/dist/utils/rowPressLayer.stylex.js +25 -0
- package/dist/utils/scrollView.d.ts +25 -0
- package/dist/utils/scrollView.d.ts.map +1 -0
- package/dist/utils/scrollView.js +108 -0
- package/dist/utils/selectionLock.d.ts.map +1 -1
- package/dist/utils/selectionLock.js +1 -10
- package/dist/utils/touchHitArea.stylex.d.ts +35 -0
- package/dist/utils/touchHitArea.stylex.d.ts.map +1 -0
- package/dist/utils/touchHitArea.stylex.js +32 -0
- package/dist/utils/triggerFocus.d.ts +5 -0
- package/dist/utils/triggerFocus.d.ts.map +1 -1
- package/dist/utils/triggerFocus.js +9 -2
- package/locales/en.json +4 -0
- package/locales/pseudo.json +3 -0
- package/package.json +5 -5
- package/src/AppShell/observeMainOverflow.ts +9 -6
- package/src/BottomSheet/BottomSheet.tsx +5 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -2
- package/src/CheckboxInput/CheckboxInput.tsx +71 -9
- package/src/ClickableCard/ClickableCard.tsx +8 -1
- package/src/DateInput/PickerWheel.tsx +7 -2
- package/src/DateRangeInput/DateRangeInput.tsx +1 -1
- package/src/Dialog/Dialog.doc.mjs +1 -1
- package/src/Dialog/Dialog.tsx +12 -1
- package/src/Drawer/Drawer.doc.mjs +1 -1
- package/src/Drawer/useDrawerDialogPresence.ts +9 -2
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -2
- package/src/DropdownMenu/DropdownMenu.tsx +29 -5
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -1
- package/src/DropdownMenu/DropdownMenuItem.tsx +8 -4
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -1
- package/src/FileInput/FileInput.tsx +16 -2
- package/src/InfoTip/InfoTip.doc.mjs +26 -2
- package/src/InfoTip/InfoTip.tsx +1 -0
- package/src/InputGroup/InputGroup.doc.mjs +4 -3
- package/src/InputGroup/InputGroup.tsx +4 -3
- package/src/InputGroup/groupStyles.ts +3 -1
- package/src/Item/Item.tsx +51 -9
- package/src/Layer/holdEntranceInput.ts +84 -0
- package/src/Layer/inputHold.ts +734 -0
- package/src/Layer/preserveAnimations.ts +12 -275
- package/src/Layout/LayoutContent.doc.mjs +6 -3
- package/src/Layout/LayoutContent.tsx +10 -4
- package/src/Layout/LayoutPanel.doc.mjs +6 -3
- package/src/Layout/LayoutPanel.tsx +11 -4
- package/src/Lightbox/Lightbox.tsx +4 -0
- package/src/MetadataList/MetadataList.tsx +1 -1
- package/src/MobileNav/MobileNav.doc.mjs +3 -3
- package/src/MobileNav/MobileNav.tsx +39 -1
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -4
- package/src/MoreMenu/MoreMenu.tsx +5 -3
- package/src/RadioList/RadioListItem.doc.mjs +3 -2
- package/src/RadioList/RadioListItem.tsx +25 -7
- package/src/SelectableCard/SelectableCard.tsx +8 -1
- package/src/Spinner/Spinner.tsx +13 -3
- package/src/Stack/Stack.doc.mjs +1 -1
- package/src/Stack/StackItem.tsx +27 -13
- package/src/Table/plugins/sortable/useTableSortable.tsx +1 -1
- package/src/Token/Token.tsx +18 -1
- package/src/Token/TokenLink.tsx +7 -1
- package/src/Tooltip/useTooltip.tsx +175 -79
- package/src/TreeList/TreeListItem.tsx +36 -2
- package/src/gestures/GestureHost.ts +21 -5
- package/src/gestures/PanGestureRecognizer.ts +19 -2
- package/src/gestures/README.md +14 -5
- package/src/gestures/ScreenEdgePanGestureRecognizer.ts +6 -1
- package/src/gestures/nativeScroll.ts +12 -68
- package/src/gestures/wheelSegmenter.ts +243 -10
- package/src/hooks/StackItemScrollRegion.tsx +57 -0
- package/src/hooks/menuPressGesture.ts +244 -38
- package/src/hooks/menuPressValues.ts +18 -0
- package/src/hooks/useClickableContainer.doc.mjs +8 -2
- package/src/hooks/useClickableContainer.ts +72 -6
- package/src/hooks/useFocusTrap.ts +268 -151
- package/src/hooks/useMenuPress.ts +118 -11
- package/src/hooks/usePressFeedback.doc.mjs +3 -3
- package/src/hooks/usePressFeedback.ts +6 -6
- package/src/hooks/useScrollRegionProps.ts +76 -0
- package/src/i18n/generated-english/hooks/useScrollRegionProps.generated.ts +13 -0
- package/src/i18n/generated-locales/en.generated.ts +1 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
- package/src/motion/MEASUREMENTS.md +11 -0
- package/src/motion/carryAnimations.ts +389 -0
- package/src/motion/transientCopy.ts +45 -5
- package/src/motion/uikit/gestures.ts +22 -0
- package/src/motion/uikit/index.ts +1 -0
- package/src/privateAttributes/menuPressLit.stylex.ts +104 -0
- package/src/privateAttributes/press.stylex.ts +244 -0
- package/src/theme/tokens.stylex.ts +1 -1
- package/src/utils/flatTree.ts +15 -3
- package/src/utils/hitArea.ts +107 -5
- package/src/utils/inputStream.ts +47 -10
- package/src/utils/interactionOverlay.stylex.ts +7 -2
- package/src/utils/pressFeedback.ts +31 -6
- package/src/utils/pressGesture.ts +24 -1
- package/src/utils/rowPressLayer.stylex.ts +27 -0
- package/src/utils/scrollView.ts +135 -0
- package/src/utils/selectionLock.ts +5 -10
- package/src/utils/touchHitArea.stylex.ts +41 -0
- package/src/utils/triggerFocus.ts +17 -4
|
@@ -251,6 +251,27 @@ export const UIKIT_PRESS = {
|
|
|
251
251
|
momentumMemory: {value: 3000, unit: 'ms'},
|
|
252
252
|
} as const satisfies Record<string, GestureConstant>;
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* UIMenu presented by a button whose menu is its primary action: how far the
|
|
256
|
+
* finger that opened it travels before it picks. DropdownMenu's press model
|
|
257
|
+
* reads a copy in `hooks/menuPressValues.ts`.
|
|
258
|
+
*/
|
|
259
|
+
export const UIKIT_MENU_PRESS = {
|
|
260
|
+
/**
|
|
261
|
+
* After the menu opens under a still-held finger, the finger travels this
|
|
262
|
+
* far before it starts picking. The distance is a straight line from the
|
|
263
|
+
* first sample the menu receives after it opened. Until then nothing is
|
|
264
|
+
* lit, and lifting acts on nothing.
|
|
265
|
+
* @source measured: UIKit lab (injected host app), iOS 26.2 simulator,
|
|
266
|
+
* iPhone 17 Pro, gesture-state hook, steps 150 ms apart, Oct 23 2026
|
|
267
|
+
* (M-MN2): with the menu open under a held finger and a 1 pt first step,
|
|
268
|
+
* moves of (0, 9) and (7, 7) picked nothing; (0, 10), (0, 11), (10, 0),
|
|
269
|
+
* (9, 9) and (10, 10) picked; a 9 pt step followed by 3 pt more picked
|
|
270
|
+
* nothing
|
|
271
|
+
*/
|
|
272
|
+
handoff: {value: 10, unit: 'px'},
|
|
273
|
+
} as const satisfies Record<string, GestureConstant>;
|
|
274
|
+
|
|
254
275
|
export const UIKIT_VELOCITY = {
|
|
255
276
|
/**
|
|
256
277
|
* UIPanGestureRecognizer.velocity(in:) is this times the newest event's
|
|
@@ -318,6 +339,7 @@ export const UIKIT_GESTURES = {
|
|
|
318
339
|
screenEdgePan: UIKIT_SCREEN_EDGE_PAN,
|
|
319
340
|
control: UIKIT_CONTROL,
|
|
320
341
|
press: UIKIT_PRESS,
|
|
342
|
+
menuPress: UIKIT_MENU_PRESS,
|
|
321
343
|
velocity: UIKIT_VELOCITY,
|
|
322
344
|
} as const;
|
|
323
345
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
/**
|
|
3
|
+
* @file privateAttributes/menuPressLit.stylex.ts
|
|
4
|
+
* @input The row that a held finger or pen lights in a menu
|
|
5
|
+
* @output Exports markMenuPressLit and clearMenuPressLit, which mark that row,
|
|
6
|
+
* and isMenuPressLit, which reads the mark. It also exports
|
|
7
|
+
* menuPressLitRowStyle, which paints the marked row. The hold pair,
|
|
8
|
+
* holdMenuPressPaint and releaseMenuPressPaint, keeps the other rows off
|
|
9
|
+
* their pressed paint, and isMenuPressPaintHeld reads that hold.
|
|
10
|
+
* @position Owner module of the private menu-press-lit attribute: the only
|
|
11
|
+
* file that writes its name. The menu press model (hooks/useMenuPress.ts)
|
|
12
|
+
* marks the row; DropdownMenu's rows compose the styles. No package entry
|
|
13
|
+
* exports it.
|
|
14
|
+
*
|
|
15
|
+
* SYNC: Each row that composes menuPressLitRowStyle reads
|
|
16
|
+
* `--_menu-row-focus-paint` in its `:focus` background, and a row with an
|
|
17
|
+
* `:active` background reads `--_menu-row-active-paint` there:
|
|
18
|
+
* - /packages/core/src/DropdownMenu/DropdownMenuItem.tsx
|
|
19
|
+
* - /packages/core/src/DropdownMenu/DropdownMenuCheckboxItem.tsx
|
|
20
|
+
* - /packages/core/src/DropdownMenu/DropdownMenuRadioItem.tsx
|
|
21
|
+
* - /packages/core/src/DropdownMenu/DropdownMenuSubMenu.tsx
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as stylex from '@stylexjs/stylex';
|
|
25
|
+
import type {StyleXStyles} from '@stylexjs/stylex';
|
|
26
|
+
import {colorVars} from '../theme/tokens.stylex';
|
|
27
|
+
|
|
28
|
+
const MENU_PRESS_LIT = 'data-astryx-menu-press-lit';
|
|
29
|
+
const ACTIVE_PAINT = '--_menu-row-active-paint';
|
|
30
|
+
|
|
31
|
+
/** Marks `row` as the row that a held finger or pen lights. */
|
|
32
|
+
export function markMenuPressLit(row: Element): void {
|
|
33
|
+
row.setAttribute(MENU_PRESS_LIT, '');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Removes the mark from `row`. */
|
|
37
|
+
export function clearMenuPressLit(row: Element): void {
|
|
38
|
+
row.removeAttribute(MENU_PRESS_LIT);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Whether a held finger or pen lights `row`. */
|
|
42
|
+
export function isMenuPressLit(row: Element): boolean {
|
|
43
|
+
return row.hasAttribute(MENU_PRESS_LIT);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Keeps `menu`'s rows off their `:active` paint while a held finger or pen
|
|
48
|
+
* presses in it. The row the press began on stays `:active` as the press
|
|
49
|
+
* moves on. The lit row keeps the pressed overlay through its own mark.
|
|
50
|
+
*/
|
|
51
|
+
export function holdMenuPressPaint(menu: HTMLElement): void {
|
|
52
|
+
menu.style.setProperty(ACTIVE_PAINT, 'transparent');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Gives `menu`'s rows their `:active` paint back. */
|
|
56
|
+
export function releaseMenuPressPaint(menu: HTMLElement): void {
|
|
57
|
+
menu.style.removeProperty(ACTIVE_PAINT);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Whether a held finger or pen keeps `menu`'s rows off their `:active` paint. */
|
|
61
|
+
export function isMenuPressPaintHeld(menu: HTMLElement): boolean {
|
|
62
|
+
return menu.style.getPropertyValue(ACTIVE_PAINT) !== '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A value for each attribute state. The index signature gives StyleX the value
|
|
67
|
+
* type, which it cannot read from a literal attribute key.
|
|
68
|
+
*/
|
|
69
|
+
type ByAttribute<Value> = Readonly<{
|
|
70
|
+
default: null;
|
|
71
|
+
[attribute: string]: Value | null;
|
|
72
|
+
}>;
|
|
73
|
+
|
|
74
|
+
const litRowPaint: Readonly<{
|
|
75
|
+
'--_menu-row-focus-paint': ByAttribute<string>;
|
|
76
|
+
'--_menu-row-active-paint': ByAttribute<string>;
|
|
77
|
+
}> = {
|
|
78
|
+
'--_menu-row-focus-paint': {
|
|
79
|
+
default: null,
|
|
80
|
+
'[data-astryx-menu-press-lit]': colorVars['--color-overlay-pressed'],
|
|
81
|
+
},
|
|
82
|
+
'--_menu-row-active-paint': {
|
|
83
|
+
default: null,
|
|
84
|
+
'[data-astryx-menu-press-lit]': colorVars['--color-overlay-pressed'],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const styles = stylex.create({
|
|
89
|
+
row: {...litRowPaint},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Compose on a menu row whose `:focus` background is
|
|
94
|
+
* `var(--_menu-row-focus-paint, <hover overlay>)`, and whose `:active`
|
|
95
|
+
* background, if any, is `var(--_menu-row-active-paint, <pressed overlay>)`.
|
|
96
|
+
* The row paints the hover overlay on focus, and the pressed overlay while a
|
|
97
|
+
* held finger or pen lights it.
|
|
98
|
+
* Under a finger, the hover overlay is too faint to follow. The variable has
|
|
99
|
+
* no default: a layered stylesheet emits a default unlayered, and it would
|
|
100
|
+
* beat the attribute arm. The value resolves on the row, so a theme set on any
|
|
101
|
+
* ancestor applies. The style sets only a custom property, which shares no
|
|
102
|
+
* key with StyleX's CSS property type, so TypeScript needs the wider type.
|
|
103
|
+
*/
|
|
104
|
+
export const menuPressLitRowStyle = styles.row as StyleXStyles;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/* eslint-disable @astryx/no-hover-on-disabled -- Every hover branch is
|
|
4
|
+
* nested beneath ENABLED below, as in interactionOverlay.stylex.ts. */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @file privateAttributes/press.stylex.ts
|
|
8
|
+
* @input StyleX, the semantic overlay color tokens, the touch press strength
|
|
9
|
+
* (`pressVars`, utils/interactionOverlay.stylex.ts) and the row layer's
|
|
10
|
+
* clocks (utils/rowPressLayer.stylex.ts)
|
|
11
|
+
* @output `rowPressLayerStyles`: the compositor press layer for list rows
|
|
12
|
+
* (`cell`) and its own-image arms for a row on the `backgroundImage`
|
|
13
|
+
* variant (`cellOnImage`)
|
|
14
|
+
* @position Owner module of the private press attribute for the row layer:
|
|
15
|
+
* the press controller (utils/pressFeedback.ts) writes the attribute, and
|
|
16
|
+
* this file reads it. No package entry exports it. Item and TreeList
|
|
17
|
+
* compose these styles after their overlay variant;
|
|
18
|
+
* utils/interactionOverlay.cell.test.ts tests them.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import * as stylex from '@stylexjs/stylex';
|
|
22
|
+
import {colorVars} from '../theme/tokens.stylex';
|
|
23
|
+
import {pressVars} from '../utils/interactionOverlay.stylex';
|
|
24
|
+
import {cellPressConsts} from '../utils/rowPressLayer.stylex';
|
|
25
|
+
|
|
26
|
+
// The overlay's arm selectors (interactionOverlay.stylex.ts), restated here:
|
|
27
|
+
// StyleX resolves a style's keys within its own file.
|
|
28
|
+
const ENABLED = ':where(:not(:disabled,[aria-disabled="true"]))';
|
|
29
|
+
const HOVER_HOVER = '@media (hover: hover)';
|
|
30
|
+
const COARSE = '@media (pointer: coarse)';
|
|
31
|
+
const PRESSED_ON = '[data-astryx-press="on"]';
|
|
32
|
+
const PRESSED_FADING = '[data-astryx-press="fading"]';
|
|
33
|
+
/**
|
|
34
|
+
* A press in any of its states: the row layer exists only then, so at rest a
|
|
35
|
+
* row's own `::before` and its stacking are untouched.
|
|
36
|
+
*/
|
|
37
|
+
const PRESSED_ANY =
|
|
38
|
+
':is([data-astryx-press="on"],[data-astryx-press="fading"])';
|
|
39
|
+
|
|
40
|
+
const PRESS_ALPHA = pressVars['--astryx-press-alpha'];
|
|
41
|
+
|
|
42
|
+
const hoverImage = `linear-gradient(${colorVars['--color-overlay-hover']}, ${colorVars['--color-overlay-hover']})`;
|
|
43
|
+
const pressedImage = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
|
|
44
|
+
/** The overlay's paint, read back off the element (its gradient layer). */
|
|
45
|
+
const pressedOverlayImage = 'var(--_press-paint-image)';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The overlay's strength release (interactionOverlay.stylex.ts), restated so
|
|
49
|
+
* a fine pointer keeps it: the same keyframes, so the same animation.
|
|
50
|
+
*/
|
|
51
|
+
const pressRelease = stylex.keyframes({
|
|
52
|
+
from: {[PRESS_ALPHA]: 1},
|
|
53
|
+
to: {[PRESS_ALPHA]: 0},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The row layer's clock as CSS. It is the strength release's clock, scaled
|
|
58
|
+
* by the theme's `--_astryx-motion-tempo` up to 1.5, so the layer and the
|
|
59
|
+
* strength land together.
|
|
60
|
+
*/
|
|
61
|
+
const CELL_RELEASE = `calc(${cellPressConsts.cellReleaseMs}ms * min(var(--_astryx-motion-tempo, 1), 1.5))`;
|
|
62
|
+
/** The same clock under Reduce Motion: a tempo may shorten it, never lengthen it. */
|
|
63
|
+
const CELL_RELEASE_REDUCED = `min(${cellPressConsts.cellReleaseMs}ms, calc(${cellPressConsts.cellReleaseMs}ms * var(--_astryx-motion-tempo, 1)))`;
|
|
64
|
+
const REDUCED_MOTION = '@media (prefers-reduced-motion: reduce)';
|
|
65
|
+
|
|
66
|
+
/** Opacity 1 → 0: the row layer leaves; its fading arm runs it. */
|
|
67
|
+
const cellRelease = stylex.keyframes({
|
|
68
|
+
from: {opacity: 1},
|
|
69
|
+
to: {opacity: 0},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** The release's curve: the table's gentle ease-out. */
|
|
73
|
+
const RELEASE_EASE = cellPressConsts.cellReleaseEase;
|
|
74
|
+
|
|
75
|
+
export const rowPressLayerStyles = stylex.create({
|
|
76
|
+
/**
|
|
77
|
+
* A list row's touch press on a compositor layer (Item, and TreeList's row
|
|
78
|
+
* box), composed AFTER the row's overlay variant (StyleX is last-wins per
|
|
79
|
+
* property). The variant's own touch paint, a gradient whose strength is a
|
|
80
|
+
* registered custom property, animates on the main thread: while script
|
|
81
|
+
* runs, a pressed row would stay at full strength and every frame of the
|
|
82
|
+
* fade would paint. Here the press is an element-sized `::before` under the
|
|
83
|
+
* row's content whose OPACITY is the strength: `on` shows it at once and
|
|
84
|
+
* `fading` runs a keyframe animation of its opacity, 1 → 0, on the cell's
|
|
85
|
+
* release clock (`timing.press`), which engines run on the compositor:
|
|
86
|
+
* it keeps advancing while the main thread is blocked and lays out and
|
|
87
|
+
* paints nothing. Same pixels as the variant's paint at that strength. The
|
|
88
|
+
* variant keeps the hover and a mouse's `:active`. The row must be
|
|
89
|
+
* positioned (the layer is placed absolutely); `isolation: isolate` keeps
|
|
90
|
+
* the layer above the row's background (a selected fill) and below its
|
|
91
|
+
* content. The layer exists only while a press is on or releasing: at rest
|
|
92
|
+
* a row's own `::before` and its stacking are as they were; during a press
|
|
93
|
+
* the layer is the row's `::before`, so a caller's decoration there merges
|
|
94
|
+
* into the layer for that time (decorate with `::after` or a child).
|
|
95
|
+
*
|
|
96
|
+
* Under a finger only (a coarse primary pointer): a fine pointer keeps the
|
|
97
|
+
* variant exactly, with no layer, no stacking context and its own touch
|
|
98
|
+
* paint, so a desktop row is as it was.
|
|
99
|
+
*/
|
|
100
|
+
cell: {
|
|
101
|
+
// The `backgroundColor` variant's own image arms (Item's), its touch
|
|
102
|
+
// paint yielding to the layer under a finger. Only the row's own image
|
|
103
|
+
// turns off: the press paint (`--_press-paint`) stays the variant's, so
|
|
104
|
+
// what a row's descendants paint from it still paints. A fine pointer
|
|
105
|
+
// keeps the arms exactly. `cellOnImage` is the same for the
|
|
106
|
+
// `backgroundImage` variant (TreeList's row box).
|
|
107
|
+
backgroundImage: {
|
|
108
|
+
default: null,
|
|
109
|
+
[ENABLED]: {
|
|
110
|
+
default: null,
|
|
111
|
+
[PRESSED_ON]: {default: pressedOverlayImage, [COARSE]: 'none'},
|
|
112
|
+
[PRESSED_FADING]: {default: pressedOverlayImage, [COARSE]: 'none'},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
// Under a finger the strength's own release (a main-thread animation)
|
|
116
|
+
// is dropped: the layer fades instead, on the compositor. A row whose
|
|
117
|
+
// descendant fades at the row's strength (a radio row's circle) brings
|
|
118
|
+
// it back with `pressedAlpha`. A fine pointer keeps it as the variant
|
|
119
|
+
// declares it (its clock and curve are untouched).
|
|
120
|
+
animationName: {
|
|
121
|
+
default: null,
|
|
122
|
+
[PRESSED_FADING]: {default: pressRelease, [COARSE]: 'none'},
|
|
123
|
+
},
|
|
124
|
+
// The stacking context the layer needs, for a press only.
|
|
125
|
+
isolation: {
|
|
126
|
+
default: null,
|
|
127
|
+
[COARSE]: {default: null, [PRESSED_ANY]: 'isolate'},
|
|
128
|
+
},
|
|
129
|
+
// The whole layer is under a finger only, and only while a press is on
|
|
130
|
+
// or releasing: with a fine pointer none of it applies, and at rest a
|
|
131
|
+
// row's own `::before` is exactly as it was.
|
|
132
|
+
'::before': {
|
|
133
|
+
content: {
|
|
134
|
+
default: null,
|
|
135
|
+
[COARSE]: {
|
|
136
|
+
default: null,
|
|
137
|
+
[ENABLED]: {default: null, [PRESSED_ANY]: '""'},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
position: {
|
|
141
|
+
default: null,
|
|
142
|
+
[COARSE]: {default: null, [PRESSED_ANY]: 'absolute'},
|
|
143
|
+
},
|
|
144
|
+
inset: {default: null, [COARSE]: {default: null, [PRESSED_ANY]: 0}},
|
|
145
|
+
zIndex: {default: null, [COARSE]: {default: null, [PRESSED_ANY]: -1}},
|
|
146
|
+
borderRadius: {
|
|
147
|
+
default: null,
|
|
148
|
+
[COARSE]: {default: null, [PRESSED_ANY]: 'inherit'},
|
|
149
|
+
},
|
|
150
|
+
pointerEvents: {
|
|
151
|
+
default: null,
|
|
152
|
+
[COARSE]: {default: null, [PRESSED_ANY]: 'none'},
|
|
153
|
+
},
|
|
154
|
+
backgroundColor: {
|
|
155
|
+
default: null,
|
|
156
|
+
[COARSE]: {
|
|
157
|
+
default: null,
|
|
158
|
+
[PRESSED_ANY]: colorVars['--color-overlay-pressed'],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
// On at once while the press is believed; nothing transitions it.
|
|
162
|
+
opacity: {
|
|
163
|
+
default: null,
|
|
164
|
+
[COARSE]: {default: null, [PRESSED_ON]: 1, [PRESSED_FADING]: 0},
|
|
165
|
+
},
|
|
166
|
+
animationName: {
|
|
167
|
+
default: null,
|
|
168
|
+
[COARSE]: {
|
|
169
|
+
default: null,
|
|
170
|
+
[ENABLED]: {default: null, [PRESSED_FADING]: cellRelease},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
animationDuration: {
|
|
174
|
+
default: null,
|
|
175
|
+
[COARSE]: {
|
|
176
|
+
default: null,
|
|
177
|
+
[PRESSED_FADING]: {
|
|
178
|
+
default: CELL_RELEASE,
|
|
179
|
+
[REDUCED_MOTION]: CELL_RELEASE_REDUCED,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
animationTimingFunction: {
|
|
184
|
+
default: null,
|
|
185
|
+
[COARSE]: {
|
|
186
|
+
default: null,
|
|
187
|
+
[PRESSED_FADING]: RELEASE_EASE,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
animationFillMode: {
|
|
191
|
+
default: null,
|
|
192
|
+
[COARSE]: {default: null, [PRESSED_FADING]: 'both'},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* A row that keeps no press paint of its own, composed after `cell`: a
|
|
198
|
+
* radio row, whose circle paints the press. The row paints no overlay
|
|
199
|
+
* image, keeps the strength's own release (the circle's layer reads the
|
|
200
|
+
* strength), and under a finger has no `::before` box and is no stacking
|
|
201
|
+
* context during a press.
|
|
202
|
+
*/
|
|
203
|
+
cellWithoutLayer: {
|
|
204
|
+
backgroundImage: 'none',
|
|
205
|
+
animationName: {default: null, [PRESSED_FADING]: pressRelease},
|
|
206
|
+
isolation: {
|
|
207
|
+
default: null,
|
|
208
|
+
[COARSE]: {default: null, [PRESSED_ANY]: 'auto'},
|
|
209
|
+
},
|
|
210
|
+
'::before': {
|
|
211
|
+
content: {
|
|
212
|
+
default: null,
|
|
213
|
+
[COARSE]: {
|
|
214
|
+
default: null,
|
|
215
|
+
[ENABLED]: {default: null, [PRESSED_ANY]: 'none'},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
/**
|
|
221
|
+
* `cell`'s own-image arms for a row on the `backgroundImage` variant
|
|
222
|
+
* (TreeList's row box), composed after `cell`: the variant's arms, its
|
|
223
|
+
* touch press paint yielding to the layer under a coarse primary pointer.
|
|
224
|
+
*/
|
|
225
|
+
cellOnImage: {
|
|
226
|
+
backgroundImage: {
|
|
227
|
+
default: null,
|
|
228
|
+
[ENABLED]: {
|
|
229
|
+
default: null,
|
|
230
|
+
':active': {
|
|
231
|
+
default: pressedImage,
|
|
232
|
+
[COARSE]: 'none',
|
|
233
|
+
},
|
|
234
|
+
[HOVER_HOVER]: {
|
|
235
|
+
default: null,
|
|
236
|
+
':hover': hoverImage,
|
|
237
|
+
':active': pressedImage,
|
|
238
|
+
},
|
|
239
|
+
[PRESSED_ON]: {default: pressedOverlayImage, [COARSE]: 'none'},
|
|
240
|
+
[PRESSED_FADING]: {default: pressedOverlayImage, [COARSE]: 'none'},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
});
|
|
@@ -24,7 +24,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
24
24
|
|
|
25
25
|
export const colorDefaults = {
|
|
26
26
|
// Core semantic
|
|
27
|
-
'--color-accent': 'light-dark(#0064E0, #
|
|
27
|
+
'--color-accent': 'light-dark(#0064E0, #0171E3)',
|
|
28
28
|
'--color-accent-muted': 'light-dark(#0082FB33, #0082FB3F)',
|
|
29
29
|
'--color-on-accent': 'light-dark(#FFFFFF, #FFFFFF)',
|
|
30
30
|
'--color-neutral':
|
package/src/utils/flatTree.ts
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file flatTree.ts
|
|
5
5
|
* @input A DOM node
|
|
6
|
-
* @output Exports parentAcrossShadow,
|
|
6
|
+
* @output Exports parentAcrossShadow, containsAlongFlatTree, which walks it,
|
|
7
|
+
* and deepActiveElement
|
|
7
8
|
* @position The flat-tree parent the browser scrolls and dispatches
|
|
8
|
-
* through, shared by the gesture host's native-scroll probe
|
|
9
|
+
* through, shared by the gesture host's native-scroll probe, the
|
|
9
10
|
* selection lock (which the press feedback controller uses without the
|
|
10
|
-
* gesture system)
|
|
11
|
+
* gesture system) and the Layer module's input hold
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/** The node's parent, crossing out of shadow roots. */
|
|
@@ -38,3 +39,14 @@ export function containsAlongFlatTree(ancestor: Node, node: Node): boolean {
|
|
|
38
39
|
}
|
|
39
40
|
return false;
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
/** The focused element of `doc`, inside open shadow roots too. */
|
|
44
|
+
export function deepActiveElement(
|
|
45
|
+
doc: Document | null | undefined,
|
|
46
|
+
): Element | null {
|
|
47
|
+
let active = doc?.activeElement ?? null;
|
|
48
|
+
while (active?.shadowRoot?.activeElement != null) {
|
|
49
|
+
active = active.shadowRoot.activeElement;
|
|
50
|
+
}
|
|
51
|
+
return active;
|
|
52
|
+
}
|
package/src/utils/hitArea.ts
CHANGED
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
// live control measures: only under a coarse primary pointer (AST-094), only on
|
|
25
25
|
// screen, and in one read pass per frame within a 4 ms budget. Until the first
|
|
26
26
|
// pass the insets are 0, so first paint never overlaps anything.
|
|
27
|
+
// The insets are lengths in the control's own box, so a pass measures in its
|
|
28
|
+
// layout px. A layer that opens from a smaller scale then keeps the insets of
|
|
29
|
+
// the size it settles at.
|
|
27
30
|
|
|
28
31
|
import {observeContent} from './sharedMutationObserver';
|
|
29
32
|
|
|
@@ -330,6 +333,95 @@ function plainRect(element: Element): HitRect {
|
|
|
330
333
|
return {left, top, right, bottom};
|
|
331
334
|
}
|
|
332
335
|
|
|
336
|
+
/** A box that the transforms around it leave at its layout size. */
|
|
337
|
+
const UNSCALED = {x: 1, y: 1} as const;
|
|
338
|
+
|
|
339
|
+
/** One axis of a box's scale on screen: its client size over its layout size. */
|
|
340
|
+
function axisScale(onScreen: number, layout: number): number {
|
|
341
|
+
if (!(layout > 0) || !(onScreen > 0)) {
|
|
342
|
+
return 1;
|
|
343
|
+
}
|
|
344
|
+
const scale = onScreen / layout;
|
|
345
|
+
// Within rounding of 1 the box is at its layout size: no change to the rects.
|
|
346
|
+
return Math.abs(scale - 1) < 1e-3 ? 1 : scale;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* How far the transforms around `element` scale its box on screen, per axis.
|
|
351
|
+
* A layer that opens from a smaller scale scales every rect inside it, while
|
|
352
|
+
* the layout box keeps the size the layer settles at. Only a scale is
|
|
353
|
+
* expected: a rotated or skewed box would read as a larger scale.
|
|
354
|
+
*/
|
|
355
|
+
function screenScale(
|
|
356
|
+
element: Element,
|
|
357
|
+
onScreen: HitRect,
|
|
358
|
+
): {x: number; y: number} {
|
|
359
|
+
// The offset size is the layout size in whole pixels, unaffected by
|
|
360
|
+
// transforms, and costs no style resolution. A box with none, such as an SVG
|
|
361
|
+
// element or a jsdom box, reads as unscaled.
|
|
362
|
+
const box = element as Partial<HTMLElement>;
|
|
363
|
+
const offsetWidth = box.offsetWidth ?? 0;
|
|
364
|
+
const offsetHeight = box.offsetHeight ?? 0;
|
|
365
|
+
if (offsetWidth === 0 || offsetHeight === 0) {
|
|
366
|
+
return UNSCALED;
|
|
367
|
+
}
|
|
368
|
+
// Within a pixel of its layout size the box reads as unscaled, which bounds
|
|
369
|
+
// the inset error at about a pixel. Only a box that a transform shrinks or
|
|
370
|
+
// grows reads its exact size from the computed style.
|
|
371
|
+
if (
|
|
372
|
+
Math.abs(onScreen.right - onScreen.left - offsetWidth) <= 1 &&
|
|
373
|
+
Math.abs(onScreen.bottom - onScreen.top - offsetHeight) <= 1
|
|
374
|
+
) {
|
|
375
|
+
return UNSCALED;
|
|
376
|
+
}
|
|
377
|
+
const style = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
378
|
+
if (style == null || !style.width.endsWith('px')) {
|
|
379
|
+
return UNSCALED;
|
|
380
|
+
}
|
|
381
|
+
const px = (value: string) => Number.parseFloat(value) || 0;
|
|
382
|
+
const isContentBox = style.boxSizing !== 'border-box';
|
|
383
|
+
const width =
|
|
384
|
+
px(style.width) +
|
|
385
|
+
(isContentBox
|
|
386
|
+
? px(style.paddingLeft) +
|
|
387
|
+
px(style.paddingRight) +
|
|
388
|
+
px(style.borderLeftWidth) +
|
|
389
|
+
px(style.borderRightWidth)
|
|
390
|
+
: 0);
|
|
391
|
+
const height =
|
|
392
|
+
px(style.height) +
|
|
393
|
+
(isContentBox
|
|
394
|
+
? px(style.paddingTop) +
|
|
395
|
+
px(style.paddingBottom) +
|
|
396
|
+
px(style.borderTopWidth) +
|
|
397
|
+
px(style.borderBottomWidth)
|
|
398
|
+
: 0);
|
|
399
|
+
return {
|
|
400
|
+
x: axisScale(onScreen.right - onScreen.left, width),
|
|
401
|
+
y: axisScale(onScreen.bottom - onScreen.top, height),
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* `rect` in the layout px of the box at `origin`: its offset from `origin`,
|
|
407
|
+
* divided by that box's scale on screen.
|
|
408
|
+
*/
|
|
409
|
+
function inLayout(
|
|
410
|
+
rect: HitRect,
|
|
411
|
+
origin: HitRect,
|
|
412
|
+
scale: {x: number; y: number},
|
|
413
|
+
): HitRect {
|
|
414
|
+
if (scale.x === 1 && scale.y === 1) {
|
|
415
|
+
return rect;
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
left: origin.left + (rect.left - origin.left) / scale.x,
|
|
419
|
+
top: origin.top + (rect.top - origin.top) / scale.y,
|
|
420
|
+
right: origin.left + (rect.right - origin.left) / scale.x,
|
|
421
|
+
bottom: origin.top + (rect.bottom - origin.top) / scale.y,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
333
425
|
interface Candidate {
|
|
334
426
|
readonly element: Element;
|
|
335
427
|
readonly rect: HitRect;
|
|
@@ -373,14 +465,15 @@ function measureOne(
|
|
|
373
465
|
candidates: ReadonlyArray<Candidate>,
|
|
374
466
|
): {target: HitRect; insets: HitInsets; neighbours: HitRect[]} {
|
|
375
467
|
const target = plainRect(watch.element);
|
|
468
|
+
const scale = screenScale(watch.element, target);
|
|
376
469
|
// Two targets each growing up to half the minimum reach each other from a
|
|
377
470
|
// minimum apart.
|
|
378
471
|
const reach = Math.max(0, watch.minSize);
|
|
379
472
|
const band = grown(target, {
|
|
380
|
-
top: reach,
|
|
381
|
-
right: reach,
|
|
382
|
-
bottom: reach,
|
|
383
|
-
left: reach,
|
|
473
|
+
top: reach * scale.y,
|
|
474
|
+
right: reach * scale.x,
|
|
475
|
+
bottom: reach * scale.y,
|
|
476
|
+
left: reach * scale.x,
|
|
384
477
|
});
|
|
385
478
|
const neighbours = candidates
|
|
386
479
|
.filter(
|
|
@@ -393,7 +486,16 @@ function measureOne(
|
|
|
393
486
|
.map(({rect}) => rect);
|
|
394
487
|
return {
|
|
395
488
|
target,
|
|
396
|
-
insets
|
|
489
|
+
// The insets are in the control's layout px. The returned rects stay in
|
|
490
|
+
// screen px for a touch's distance checks. A neighbour maps by the
|
|
491
|
+
// control's scale, as if it is in the same layer. A neighbour outside that
|
|
492
|
+
// layer then reads farther away. A touch compares screen distances, so it
|
|
493
|
+
// still counts that neighbour.
|
|
494
|
+
insets: clampedHitInsets(
|
|
495
|
+
inLayout(target, target, scale),
|
|
496
|
+
neighbours.map(rect => inLayout(rect, target, scale)),
|
|
497
|
+
watch.minSize,
|
|
498
|
+
),
|
|
397
499
|
neighbours,
|
|
398
500
|
};
|
|
399
501
|
}
|