@astryxdesign/core 0.7.8-canary.36cde5e → 0.7.8-canary.4934ffc
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/PowerSearch/PowerSearch.d.ts +27 -31
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +7 -11
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +1 -1
- package/dist/PowerSearch/PowerSearchBottomSheet.js +1 -1
- package/dist/PowerSearch/index.d.ts +1 -1
- package/dist/PowerSearch/index.d.ts.map +1 -1
- package/dist/Tokenizer/TokenizerBottomSheet.js +3 -5
- package/dist/hooks/scrollLockTouchGuard.d.ts.map +1 -1
- package/dist/hooks/scrollLockTouchGuard.js +9 -26
- package/dist/hooks/useScrollLock.d.ts +3 -2
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +3 -8
- package/package.json +4 -4
- package/src/Icon/Icon.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearch.doc.mjs +12 -12
- package/src/PowerSearch/PowerSearch.tsx +33 -40
- package/src/PowerSearch/PowerSearchBottomSheet.tsx +1 -1
- package/src/PowerSearch/index.ts +5 -1
- package/src/Tokenizer/TokenizerBottomSheet.tsx +8 -10
- package/src/hooks/scrollLockTouchGuard.ts +9 -42
- package/src/hooks/useScrollLock.ts +3 -7
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* useAdaptivePresentation, and PowerSearchBottomSheet (lazy)
|
|
5
5
|
* @output Structured filter bar with token-based filter management
|
|
6
6
|
* @position Main component; forwards DOM ref and exposes tokenizer control via
|
|
7
|
-
* handleRef. The
|
|
8
|
-
*
|
|
7
|
+
* handleRef. The `presentation` prop swaps the tokenizer field and editor
|
|
8
|
+
* popover for one trigger that opens PowerSearchBottomSheet.
|
|
9
9
|
*
|
|
10
10
|
* SYNC: When modified, update:
|
|
11
11
|
* - /packages/core/src/PowerSearch/index.ts
|
|
@@ -17,6 +17,7 @@ import type { BaseProps } from '../BaseProps.js';
|
|
|
17
17
|
import { type TokenizerOverflowBehavior } from '../Tokenizer/index.js';
|
|
18
18
|
import type { IconType } from '../Icon/index.js';
|
|
19
19
|
import type { InputStatus } from '../Field/index.js';
|
|
20
|
+
import { type AdaptivePresentation } from '../hooks/useAdaptivePresentation.js';
|
|
20
21
|
import type { PowerSearchConfig, PowerSearchFilter, PowerSearchChangeType, PowerSearchHandle, PowerSearchComponents } from './types.js';
|
|
21
22
|
import type { FieldStatusPlacement } from '../Field/fieldStatusPlacement.js';
|
|
22
23
|
export type PowerSearchSize = 'sm' | 'md' | 'lg';
|
|
@@ -122,36 +123,31 @@ export interface PowerSearchProps extends Omit<BaseProps<HTMLElement>, 'onChange
|
|
|
122
123
|
*/
|
|
123
124
|
components?: PowerSearchComponents;
|
|
124
125
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
126
|
+
* How the field presents filter editing.
|
|
127
|
+
* - `'popover'`: the tokenizer field with its typeahead and the editor
|
|
128
|
+
* popover, on every device.
|
|
129
|
+
* - `'bottom-sheet'`: the whole field is one trigger showing display-only
|
|
130
|
+
* filter tokens; it opens a stack of sheets. Filters lists the filters
|
|
131
|
+
* as rows that edit or remove one, with Add filter, Done, and Clear
|
|
132
|
+
* all, which asks first and keeps read-only filters. Add filter opens
|
|
133
|
+
* above it with the fields (or the content search with inline
|
|
134
|
+
* suggestions), and a value step opens above that, stages operator →
|
|
135
|
+
* value, and confirms from its footer. Dismissing a step reveals the
|
|
136
|
+
* one beneath. Suited to compact touch screens, where the editor
|
|
137
|
+
* popover competes with the software keyboard.
|
|
138
|
+
* - `'adaptive'`: the bottom sheet on compact coarse-pointer screens,
|
|
139
|
+
* otherwise the popover — the same resolution Selector uses. The server
|
|
140
|
+
* render and the hydrating render are the popover.
|
|
141
|
+
*
|
|
142
|
+
* In the sheet presentation `menuWidth` and `tokenOverflowBehavior` have
|
|
143
|
+
* no surface to act on and warn in development. Pass `'popover'` to keep
|
|
144
|
+
* the tokenizer field and the editor popover on every device.
|
|
145
|
+
* @default 'adaptive'
|
|
129
146
|
*/
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* How the field presents filter editing.
|
|
133
|
-
* - `'popover'`: the tokenizer field with its typeahead and the editor
|
|
134
|
-
* popover — the stable behavior.
|
|
135
|
-
* - `'bottom-sheet'`: the whole field is one trigger showing display-only
|
|
136
|
-
* filter tokens; it opens a stack of sheets. Filters lists the filters
|
|
137
|
-
* as rows that edit or remove one, with Add filter, Done, and Clear
|
|
138
|
-
* all, which asks first and keeps read-only filters. Add filter opens
|
|
139
|
-
* above it with the fields (or the content search with inline
|
|
140
|
-
* suggestions), and a value step opens above that, stages operator →
|
|
141
|
-
* value, and confirms from its footer. Dismissing a step reveals the
|
|
142
|
-
* one beneath. Suited to compact touch screens, where the editor
|
|
143
|
-
* popover competes with the software keyboard.
|
|
144
|
-
* - `'adaptive'`: the bottom sheet on compact coarse-pointer screens,
|
|
145
|
-
* otherwise the popover — the same resolution Selector uses.
|
|
146
|
-
*
|
|
147
|
-
* In the sheet presentation `menuWidth` and `tokenOverflowBehavior` have
|
|
148
|
-
* no surface to act on and warn in development.
|
|
149
|
-
* @experimental
|
|
150
|
-
* @default 'popover'
|
|
151
|
-
*/
|
|
152
|
-
presentation?: 'popover' | 'bottom-sheet' | 'adaptive';
|
|
153
|
-
};
|
|
147
|
+
presentation?: PowerSearchPresentation;
|
|
154
148
|
}
|
|
149
|
+
/** How PowerSearch presents filter editing; see `PowerSearchProps.presentation`. */
|
|
150
|
+
export type PowerSearchPresentation = AdaptivePresentation;
|
|
155
151
|
/**
|
|
156
152
|
* Structured filter bar where each token represents a filter (field + operator + value).
|
|
157
153
|
*
|
|
@@ -218,7 +214,7 @@ export interface PowerSearchProps extends Omit<BaseProps<HTMLElement>, 'onChange
|
|
|
218
214
|
* };
|
|
219
215
|
* ```
|
|
220
216
|
*/
|
|
221
|
-
export declare function PowerSearch({ config: configProp, filters, onChange, label: labelFromProps, isLabelHidden, placeholder: placeholderFromProps, hasAutoFocus, hasClear, isReadOnly, isDisabled, disabledMessage, startIcon, onFocus, onBlur, status, statusVariant, menuWidth, maxTokenLength, maxOperatorMenuItems, maxSearchResults, popoverSaveButtonLabel: popoverSaveButtonLabelFromProps, timezoneID, tokenOverflowBehavior, endContent, resultCount, ref, handleRef, size: sizeProp, 'data-testid': testId, xstyle, className, style, components: componentOverrides,
|
|
217
|
+
export declare function PowerSearch({ config: configProp, filters, onChange, label: labelFromProps, isLabelHidden, placeholder: placeholderFromProps, hasAutoFocus, hasClear, isReadOnly, isDisabled, disabledMessage, startIcon, onFocus, onBlur, status, statusVariant, menuWidth, maxTokenLength, maxOperatorMenuItems, maxSearchResults, popoverSaveButtonLabel: popoverSaveButtonLabelFromProps, timezoneID, tokenOverflowBehavior, endContent, resultCount, ref, handleRef, size: sizeProp, 'data-testid': testId, xstyle, className, style, components: componentOverrides, presentation, }: PowerSearchProps): React.JSX.Element;
|
|
222
218
|
export declare namespace PowerSearch {
|
|
223
219
|
var displayName: string;
|
|
224
220
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PowerSearch.d.ts","sourceRoot":"","sources":["../../src/PowerSearch/PowerSearch.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAUZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,cAAc,CAAC;AAStB,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"PowerSearch.d.ts","sourceRoot":"","sources":["../../src/PowerSearch/PowerSearch.tsx"],"names":[],"mappings":"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"}
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* useAdaptivePresentation, and PowerSearchBottomSheet (lazy)
|
|
9
9
|
* @output Structured filter bar with token-based filter management
|
|
10
10
|
* @position Main component; forwards DOM ref and exposes tokenizer control via
|
|
11
|
-
* handleRef. The
|
|
12
|
-
*
|
|
11
|
+
* handleRef. The `presentation` prop swaps the tokenizer field and editor
|
|
12
|
+
* popover for one trigger that opens PowerSearchBottomSheet.
|
|
13
13
|
*
|
|
14
14
|
* SYNC: When modified, update:
|
|
15
15
|
* - /packages/core/src/PowerSearch/index.ts
|
|
@@ -181,6 +181,8 @@ function PowerSearchTokenValue({
|
|
|
181
181
|
// Types
|
|
182
182
|
// =============================================================================
|
|
183
183
|
|
|
184
|
+
/** How PowerSearch presents filter editing; see `PowerSearchProps.presentation`. */
|
|
185
|
+
|
|
184
186
|
// =============================================================================
|
|
185
187
|
// State
|
|
186
188
|
// =============================================================================
|
|
@@ -297,7 +299,7 @@ export function PowerSearch({
|
|
|
297
299
|
className,
|
|
298
300
|
style,
|
|
299
301
|
components: componentOverrides,
|
|
300
|
-
|
|
302
|
+
presentation = 'adaptive'
|
|
301
303
|
}) {
|
|
302
304
|
const size = useSize(sizeProp, 'md');
|
|
303
305
|
const config = useInternalConfig(configProp);
|
|
@@ -308,12 +310,6 @@ export function PowerSearch({
|
|
|
308
310
|
const placeholder = placeholderFromProps ?? t('@astryx.powersearch.placeholder');
|
|
309
311
|
const popoverSaveButtonLabel = popoverSaveButtonLabelFromProps ?? t('@astryx.powersearch.editor.apply');
|
|
310
312
|
const tokenizerRef = useRef(null);
|
|
311
|
-
|
|
312
|
-
// Experimental presentation. `adaptive`
|
|
313
|
-
// resolves through the policy the selection controls share; an open flow
|
|
314
|
-
// keeps its presentation until it closes, so a resolution change mid-task
|
|
315
|
-
// cannot pull the surface out from under the person.
|
|
316
|
-
const presentation = experimental?.presentation ?? 'popover';
|
|
317
313
|
const resolvedPresentation = useAdaptivePresentation(presentation);
|
|
318
314
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
319
315
|
// Latched for the flow's lifetime: the flow stays presented after it closes
|
|
@@ -387,8 +383,8 @@ export function PowerSearch({
|
|
|
387
383
|
setIsSheetOpen(false);
|
|
388
384
|
}
|
|
389
385
|
}
|
|
390
|
-
useDevWarning('PowerSearch', '`menuWidth` has no surface in the bottom-sheet presentation: the sheet flow has no typeahead popover to size.
|
|
391
|
-
useDevWarning('PowerSearch', '`tokenOverflowBehavior` has no surface in the bottom-sheet presentation: the trigger wraps its display-only tokens.
|
|
386
|
+
useDevWarning('PowerSearch', '`menuWidth` has no surface in the bottom-sheet presentation: the sheet flow has no typeahead popover to size. Pass `presentation="popover"` to keep the popover on every device, or leave it out.', isSheetPresentation && menuWidth != null);
|
|
387
|
+
useDevWarning('PowerSearch', '`tokenOverflowBehavior` has no surface in the bottom-sheet presentation: the trigger wraps its display-only tokens. Pass `presentation="popover"` to keep the tokenizer field on every device, or leave it out.', isSheetPresentation && tokenOverflowBehavior != null);
|
|
392
388
|
const [popoverState, setPopoverStateRaw] = useState({
|
|
393
389
|
type: 'idle'
|
|
394
390
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* RadioList, Text, TextInput, PowerSearchValueEditor, the internal sheet
|
|
7
7
|
* confirmation and search-drag owners, i18n
|
|
8
8
|
* @output Exports PowerSearchBottomSheet — the touch surface of
|
|
9
|
-
* `PowerSearch
|
|
9
|
+
* `PowerSearch presentation="bottom-sheet"`: a Filters sheet
|
|
10
10
|
* with editable rows and trailing remove actions, Add filter in its fixed
|
|
11
11
|
* header and Clear all / Done in its fixed footer, an Add filter sheet with
|
|
12
12
|
* grouped field rows or the content search with inline suggestions, and a
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* RadioList, Text, TextInput, PowerSearchValueEditor, the internal sheet
|
|
11
11
|
* confirmation and search-drag owners, i18n
|
|
12
12
|
* @output Exports PowerSearchBottomSheet — the touch surface of
|
|
13
|
-
* `PowerSearch
|
|
13
|
+
* `PowerSearch presentation="bottom-sheet"`: a Filters sheet
|
|
14
14
|
* with editable rows and trailing remove actions, Add filter in its fixed
|
|
15
15
|
* header and Clear all / Done in its fixed footer, an Add filter sheet with
|
|
16
16
|
* grouped field rows or the content search with inline suggestions, and a
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* SYNC: When adding new PowerSearch files, update exports here
|
|
8
8
|
*/
|
|
9
9
|
export { PowerSearch } from './PowerSearch.js';
|
|
10
|
-
export type { PowerSearchProps, PowerSearchSize } from './PowerSearch.js';
|
|
10
|
+
export type { PowerSearchPresentation, PowerSearchProps, PowerSearchSize, } from './PowerSearch.js';
|
|
11
11
|
export { PowerSearchToken } from './PowerSearchToken.js';
|
|
12
12
|
export { PowerSearchFilterEditor } from './PowerSearchFilterEditor.js';
|
|
13
13
|
export { resolveOperatorLabel } from './resolveOperatorLabel.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/PowerSearch/index.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/PowerSearch/index.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,YAAY,EACV,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAC,uBAAuB,EAAC,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAC,eAAe,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAEvE,YAAY,EAEV,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,4BAA4B,EAC5B,8BAA8B,EAG9B,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EAGnB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAGjB,iBAAiB,EACjB,aAAa,EAGb,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EAGjB,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,SAAS,CAAC"}
|
|
@@ -419,11 +419,9 @@ function TokenizerSheetContent({
|
|
|
419
419
|
// `action` is declared on `SearchableItem` for the grid-adopting hosts; the
|
|
420
420
|
// sheet rows have not adopted it, so a row renders the item without the
|
|
421
421
|
// control and says so (`spec:AST-058` FR9), as the inline panel does.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
}, [results]);
|
|
422
|
+
if (results.some(item => item.action != null)) {
|
|
423
|
+
warnOnce('tokenizer-sheet:item-action', 'Tokenizer', 'A result carries `action`, which the bottom-sheet rows do not render ' + 'yet; the item is shown without it.');
|
|
424
|
+
}
|
|
427
425
|
|
|
428
426
|
// The pending Spinner below stays named, as the inline field's does
|
|
429
427
|
// (`family:input-fields` FR7), but is not a live region; the sheet announces
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrollLockTouchGuard.d.ts","sourceRoot":"","sources":["../../src/hooks/scrollLockTouchGuard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scrollLockTouchGuard.d.ts","sourceRoot":"","sources":["../../src/hooks/scrollLockTouchGuard.ts"],"names":[],"mappings":"AAoFA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAErD;AAWD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,OAAO,CAqCT"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @file scrollLockTouchGuard.ts
|
|
7
7
|
* @input The node under a finger and the pan's direction, while a scroll lock
|
|
8
|
-
* holds the page
|
|
8
|
+
* holds the page; the native-scroll probe's edge test (gestures/nativeScroll)
|
|
9
9
|
* @output isPanAbsorbedBeforePage and isPageZoomedIn, for the page hold
|
|
10
10
|
* @position Internal hook utility; gestures/pageHold calls it for
|
|
11
11
|
* useScrollLock.
|
|
@@ -18,41 +18,24 @@
|
|
|
18
18
|
// The walk follows flat-tree parents. It ends at a top-layer or fixed-position
|
|
19
19
|
// element, whose containing block is the viewport, so its untaken pans go to
|
|
20
20
|
// the page.
|
|
21
|
+
import { canElementScroll } from "../gestures/nativeScroll.js";
|
|
21
22
|
import { parentAcrossShadow } from "../utils/flatTree.js";
|
|
22
|
-
import { isRtlElement } from "./isRtlElement.js";
|
|
23
|
-
const SCROLLABLE = new Set(['auto', 'scroll']);
|
|
24
|
-
|
|
25
|
-
/** Overflow at or below this many px is a box that fits, not a scroller. */
|
|
26
|
-
const EDGE_TOLERANCE = 1;
|
|
27
|
-
function canMoveY(element, dy, range) {
|
|
28
|
-
// A finger moving down drags the content down: scrollTop decreases.
|
|
29
|
-
return dy > 0 ? element.scrollTop > EDGE_TOLERANCE - 0.5 : element.scrollTop < range - EDGE_TOLERANCE + 0.5;
|
|
30
|
-
}
|
|
31
|
-
function canMoveX(element, dx, range, isRtl) {
|
|
32
|
-
const min = isRtl ? -range : 0;
|
|
33
|
-
const max = isRtl ? 0 : range;
|
|
34
|
-
// A finger moving right drags the content right: scrollLeft decreases.
|
|
35
|
-
return dx > 0 ? element.scrollLeft > min + EDGE_TOLERANCE - 0.5 : element.scrollLeft < max - EDGE_TOLERANCE + 0.5;
|
|
36
|
-
}
|
|
37
23
|
|
|
38
24
|
/**
|
|
39
25
|
* Whether `element` itself takes a pan. It does when it can still scroll that
|
|
40
26
|
* way, or when its `overscroll-behavior` contains the overscroll at its edge.
|
|
41
27
|
*/
|
|
42
28
|
function takesPan(element, style, isVertical, dx, dy) {
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
const x = isVertical ? 0 : dx;
|
|
30
|
+
const y = isVertical ? dy : 0;
|
|
31
|
+
if (canElementScroll(element, x, y)) {
|
|
32
|
+
return true;
|
|
45
33
|
}
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
if (range <= EDGE_TOLERANCE) {
|
|
34
|
+
// A scroller at its edge can still move the other way. A box that does not
|
|
35
|
+
// scroll, or whose content fits, cannot. Its pan goes on along the chain.
|
|
36
|
+
if (!canElementScroll(element, -x, -y)) {
|
|
50
37
|
return false;
|
|
51
38
|
}
|
|
52
|
-
const canMove = isVertical ? canMoveY(element, dy, range) : canMoveX(element, dx, range, isRtlElement(element));
|
|
53
|
-
if (canMove) {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
39
|
const behavior = isVertical ? style.overscrollBehaviorY : style.overscrollBehaviorX;
|
|
57
40
|
return behavior === 'contain' || behavior === 'none';
|
|
58
41
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Locks page scroll while `isLocked` is true.
|
|
3
3
|
*
|
|
4
|
-
* The page keeps its scroll offset, so nothing jumps on lock or unlock.
|
|
5
|
-
*
|
|
4
|
+
* The page keeps its scroll offset, so nothing jumps on lock or unlock. iOS
|
|
5
|
+
* Safari scrolls an `overflow: hidden` page under a finger. So where the
|
|
6
|
+
* primary pointer is coarse (phones and tablets), the lock cancels a
|
|
6
7
|
* one-finger pan that would reach the page.
|
|
7
8
|
* Pans that a scroller in the overlay takes, and two-finger zoom, go through.
|
|
8
9
|
* The gutter of a classic scrollbar stays open, so the page does not shift
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollLock.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollLock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useScrollLock.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollLock.ts"],"names":[],"mappings":"AAmCA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAkDrD"}
|
|
@@ -22,20 +22,15 @@ import { claimRootScrollStyle, reportScrollLock } from "./rootScrollStyles.js";
|
|
|
22
22
|
import { holdPageScroll } from "../gestures/pageHold.js";
|
|
23
23
|
import { isPageZoomedIn, isPanAbsorbedBeforePage } from "./scrollLockTouchGuard.js";
|
|
24
24
|
import { holdScrollbarGutter } from "./scrollbarGutter.js";
|
|
25
|
-
|
|
26
|
-
// iOS Safari scrolls an `overflow: hidden` page under a finger.
|
|
27
|
-
// So the lock also cancels each one-finger pan that would reach the page. The
|
|
28
|
-
// scroll offset never changes, so unlock restores nothing, and iOS Safari's
|
|
29
|
-
// toolbar keeps its state.
|
|
30
|
-
|
|
31
25
|
let lockCount = 0;
|
|
32
26
|
let activeLock = null;
|
|
33
27
|
|
|
34
28
|
/**
|
|
35
29
|
* Locks page scroll while `isLocked` is true.
|
|
36
30
|
*
|
|
37
|
-
* The page keeps its scroll offset, so nothing jumps on lock or unlock.
|
|
38
|
-
*
|
|
31
|
+
* The page keeps its scroll offset, so nothing jumps on lock or unlock. iOS
|
|
32
|
+
* Safari scrolls an `overflow: hidden` page under a finger. So where the
|
|
33
|
+
* primary pointer is coarse (phones and tablets), the lock cancels a
|
|
39
34
|
* one-finger pan that would reach the page.
|
|
40
35
|
* Pans that a scroller in the overlay takes, and two-finger zoom, go through.
|
|
41
36
|
* The gutter of a classic scrollbar stays open, so the page does not shift
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.8-canary.
|
|
3
|
+
"version": "0.7.8-canary.4934ffc",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -870,9 +870,9 @@
|
|
|
870
870
|
"react-dom": ">=19.0.0"
|
|
871
871
|
},
|
|
872
872
|
"devDependencies": {
|
|
873
|
-
"@astryxdesign/a11y-spec": "0.7.8-canary.
|
|
874
|
-
"@astryxdesign/cli": "0.7.8-canary.
|
|
875
|
-
"@astryxdesign/interaction-harness": "0.7.8-canary.
|
|
873
|
+
"@astryxdesign/a11y-spec": "0.7.8-canary.4934ffc",
|
|
874
|
+
"@astryxdesign/cli": "0.7.8-canary.4934ffc",
|
|
875
|
+
"@astryxdesign/interaction-harness": "0.7.8-canary.4934ffc",
|
|
876
876
|
"@babel/cli": "^7.29.7",
|
|
877
877
|
"@babel/core": "^7.29.7",
|
|
878
878
|
"@babel/preset-react": "^7.29.7",
|
package/src/Icon/Icon.doc.mjs
CHANGED
|
@@ -78,7 +78,7 @@ export const docs = {
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
name: 'color',
|
|
81
|
-
type: "'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent' | 'info' | 'success' | 'error' | 'warning' | 'inherit'",
|
|
81
|
+
type: "'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent' | 'info' | 'success' | 'error' | 'warning' | 'inherit' | 'blue' | 'red' | 'green' | 'gray' | 'cyan' | 'teal' | 'yellow' | 'orange' | 'pink' | 'purple'",
|
|
82
82
|
description:
|
|
83
83
|
'Color variant mapped to Astryx icon color tokens. Semantic values (primary through warning) follow the role, and inherit uses the surrounding text color. On the web, Icon also accepts the palette values blue, red, green, gray, cyan, teal, yellow, orange, pink, and purple, which pick a non-semantic hue.',
|
|
84
84
|
default: "'inherit'",
|
|
@@ -233,7 +233,7 @@ export const docsZh = {
|
|
|
233
233
|
},
|
|
234
234
|
{
|
|
235
235
|
name: 'color',
|
|
236
|
-
type: "'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent' | 'info' | 'success' | 'error' | 'warning' | 'inherit'",
|
|
236
|
+
type: "'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent' | 'info' | 'success' | 'error' | 'warning' | 'inherit' | 'blue' | 'red' | 'green' | 'gray' | 'cyan' | 'teal' | 'yellow' | 'orange' | 'pink' | 'purple'",
|
|
237
237
|
description:
|
|
238
238
|
'映射到 Astryx 图标颜色令牌的颜色变体。语义值(primary 到 warning)跟随角色,inherit 使用周围文字的颜色。在 Web 上,Icon 还接受调色板值 blue、red、green、gray、cyan、teal、yellow、orange、pink 和 purple,它们选择非语义色相。',
|
|
239
239
|
default: "'inherit'",
|
|
@@ -208,22 +208,22 @@ export const docs = {
|
|
|
208
208
|
'StyleX styles for layout customization. Must be a stylex.create() value.',
|
|
209
209
|
},
|
|
210
210
|
{
|
|
211
|
-
name: '
|
|
212
|
-
type: "
|
|
213
|
-
stability: 'experimental',
|
|
211
|
+
name: 'presentation',
|
|
212
|
+
type: "'popover' | 'bottom-sheet' | 'adaptive'",
|
|
214
213
|
description:
|
|
215
|
-
|
|
214
|
+
'How the field presents filter editing. adaptive (the default) uses the bottom sheet on compact touch screens and the popover otherwise, resolved the same way Selector resolves it; the server render and the hydrating render are the popover. popover is the tokenizer field with its typeahead and the editor popover on every device. bottom-sheet makes the whole field, on every device, one trigger showing display-only filter tokens: it opens a Filters sheet listing the filters as rows that edit or remove a filter, with Add filter, Done, and Clear all (which asks first and keeps read-only filters); an Add filter sheet with the fields (or the content search with inline suggestions) opens above it, and a value step that stages operator → value and confirms from its footer opens above that. Dismissing a step reveals the one beneath. List values edit through the Tokenizer\'s own sheet. In the sheet presentation menuWidth and tokenOverflowBehavior have no surface to act on and warn in development. Pass presentation="popover" to keep the tokenizer field and the editor popover on every device.',
|
|
215
|
+
default: "'adaptive'",
|
|
216
216
|
},
|
|
217
217
|
],
|
|
218
218
|
examples: [
|
|
219
219
|
{
|
|
220
|
-
label: '
|
|
220
|
+
label: 'Keep the popover on every device',
|
|
221
221
|
code: `const [filters, setFilters] = useState([]);
|
|
222
222
|
<PowerSearch
|
|
223
223
|
config={config}
|
|
224
224
|
filters={filters}
|
|
225
225
|
onChange={next => setFilters(next)}
|
|
226
|
-
|
|
226
|
+
presentation="popover"
|
|
227
227
|
/>`,
|
|
228
228
|
},
|
|
229
229
|
],
|
|
@@ -481,11 +481,11 @@ export const docsZh = {
|
|
|
481
481
|
description: '用于布局自定义的 StyleX 样式。必须是 stylex.create() 值。',
|
|
482
482
|
},
|
|
483
483
|
{
|
|
484
|
-
name: '
|
|
485
|
-
type: "
|
|
486
|
-
stability: 'experimental',
|
|
484
|
+
name: 'presentation',
|
|
485
|
+
type: "'popover' | 'bottom-sheet' | 'adaptive'",
|
|
487
486
|
description:
|
|
488
|
-
|
|
487
|
+
'字段如何呈现筛选编辑。adaptive(默认)在紧凑触摸屏上使用底部面板,其他情况使用 popover,解析方式与 Selector 相同;服务端渲染和水合期间的渲染均为 popover。popover 在所有设备上为带有预输入和编辑弹出层的标记字段。bottom-sheet 在所有设备上将整个字段变为一个显示只读筛选标记的触发按钮——点按后打开列出筛选项的「筛选」面板,每行可编辑或移除筛选(含添加筛选、完成、全部清除;全部清除会先确认,并保留只读筛选);列出字段(或带内联建议的内容搜索)的「添加筛选」面板在其上方打开,按运算符 → 值暂存并在底部确认的取值步骤再在其上方打开。关闭某一步会露出下方的那一步。列表值通过 Tokenizer 自身的面板编辑。在底部面板呈现中,menuWidth 和 tokenOverflowBehavior 没有作用对象,并会在开发环境中发出警告。传入 presentation="popover" 可在所有设备上保留标记字段和编辑弹出层。',
|
|
488
|
+
default: "'adaptive'",
|
|
489
489
|
},
|
|
490
490
|
],
|
|
491
491
|
usage: {
|
|
@@ -582,7 +582,7 @@ export const docsDense = {
|
|
|
582
582
|
size: 'Search input+token size.',
|
|
583
583
|
xstyle:
|
|
584
584
|
'StyleX styles for layout customization. Must be stylex.create() value.',
|
|
585
|
-
|
|
586
|
-
"
|
|
585
|
+
presentation:
|
|
586
|
+
"'adaptive' (default: sheet on compact touch, else popover; SSR/hydration render popover) | 'popover' (tokenizer field + editor popover, every device) | 'bottom-sheet' (one trigger with display-only tokens + stacked Filters / Add filter / value sheets; rows remove inline; Clear all confirms, keeps read-only; list values via Tokenizer's sheet). Sheet: menuWidth/tokenOverflowBehavior inert (dev warning). presentation=\"popover\" keeps the popover on every device.",
|
|
587
587
|
},
|
|
588
588
|
};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* useAdaptivePresentation, and PowerSearchBottomSheet (lazy)
|
|
9
9
|
* @output Structured filter bar with token-based filter management
|
|
10
10
|
* @position Main component; forwards DOM ref and exposes tokenizer control via
|
|
11
|
-
* handleRef. The
|
|
12
|
-
*
|
|
11
|
+
* handleRef. The `presentation` prop swaps the tokenizer field and editor
|
|
12
|
+
* popover for one trigger that opens PowerSearchBottomSheet.
|
|
13
13
|
*
|
|
14
14
|
* SYNC: When modified, update:
|
|
15
15
|
* - /packages/core/src/PowerSearch/index.ts
|
|
@@ -58,7 +58,10 @@ import {usePopover} from '../Popover/usePopover';
|
|
|
58
58
|
import {useTooltip} from '../Tooltip/useTooltip';
|
|
59
59
|
import {layerViewportInset} from '../Layer/layerViewportInset.stylex';
|
|
60
60
|
import {useAnnounce} from '../hooks/useAnnounce';
|
|
61
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
type AdaptivePresentation,
|
|
63
|
+
useAdaptivePresentation,
|
|
64
|
+
} from '../hooks/useAdaptivePresentation';
|
|
62
65
|
import {useDevWarning} from '../hooks/useDevWarning';
|
|
63
66
|
import {useIsHydrating} from '../hooks/useIsHydrating';
|
|
64
67
|
import {
|
|
@@ -416,39 +419,34 @@ export interface PowerSearchProps extends Omit<
|
|
|
416
419
|
* Keys are operator value types (e.g. 'string', 'enum', 'date_absolute').
|
|
417
420
|
*/
|
|
418
421
|
components?: PowerSearchComponents;
|
|
419
|
-
|
|
420
422
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
423
|
+
* How the field presents filter editing.
|
|
424
|
+
* - `'popover'`: the tokenizer field with its typeahead and the editor
|
|
425
|
+
* popover, on every device.
|
|
426
|
+
* - `'bottom-sheet'`: the whole field is one trigger showing display-only
|
|
427
|
+
* filter tokens; it opens a stack of sheets. Filters lists the filters
|
|
428
|
+
* as rows that edit or remove one, with Add filter, Done, and Clear
|
|
429
|
+
* all, which asks first and keeps read-only filters. Add filter opens
|
|
430
|
+
* above it with the fields (or the content search with inline
|
|
431
|
+
* suggestions), and a value step opens above that, stages operator →
|
|
432
|
+
* value, and confirms from its footer. Dismissing a step reveals the
|
|
433
|
+
* one beneath. Suited to compact touch screens, where the editor
|
|
434
|
+
* popover competes with the software keyboard.
|
|
435
|
+
* - `'adaptive'`: the bottom sheet on compact coarse-pointer screens,
|
|
436
|
+
* otherwise the popover — the same resolution Selector uses. The server
|
|
437
|
+
* render and the hydrating render are the popover.
|
|
438
|
+
*
|
|
439
|
+
* In the sheet presentation `menuWidth` and `tokenOverflowBehavior` have
|
|
440
|
+
* no surface to act on and warn in development. Pass `'popover'` to keep
|
|
441
|
+
* the tokenizer field and the editor popover on every device.
|
|
442
|
+
* @default 'adaptive'
|
|
425
443
|
*/
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* How the field presents filter editing.
|
|
429
|
-
* - `'popover'`: the tokenizer field with its typeahead and the editor
|
|
430
|
-
* popover — the stable behavior.
|
|
431
|
-
* - `'bottom-sheet'`: the whole field is one trigger showing display-only
|
|
432
|
-
* filter tokens; it opens a stack of sheets. Filters lists the filters
|
|
433
|
-
* as rows that edit or remove one, with Add filter, Done, and Clear
|
|
434
|
-
* all, which asks first and keeps read-only filters. Add filter opens
|
|
435
|
-
* above it with the fields (or the content search with inline
|
|
436
|
-
* suggestions), and a value step opens above that, stages operator →
|
|
437
|
-
* value, and confirms from its footer. Dismissing a step reveals the
|
|
438
|
-
* one beneath. Suited to compact touch screens, where the editor
|
|
439
|
-
* popover competes with the software keyboard.
|
|
440
|
-
* - `'adaptive'`: the bottom sheet on compact coarse-pointer screens,
|
|
441
|
-
* otherwise the popover — the same resolution Selector uses.
|
|
442
|
-
*
|
|
443
|
-
* In the sheet presentation `menuWidth` and `tokenOverflowBehavior` have
|
|
444
|
-
* no surface to act on and warn in development.
|
|
445
|
-
* @experimental
|
|
446
|
-
* @default 'popover'
|
|
447
|
-
*/
|
|
448
|
-
presentation?: 'popover' | 'bottom-sheet' | 'adaptive';
|
|
449
|
-
};
|
|
444
|
+
presentation?: PowerSearchPresentation;
|
|
450
445
|
}
|
|
451
446
|
|
|
447
|
+
/** How PowerSearch presents filter editing; see `PowerSearchProps.presentation`. */
|
|
448
|
+
export type PowerSearchPresentation = AdaptivePresentation;
|
|
449
|
+
|
|
452
450
|
// =============================================================================
|
|
453
451
|
// State
|
|
454
452
|
// =============================================================================
|
|
@@ -583,7 +581,7 @@ export function PowerSearch({
|
|
|
583
581
|
className,
|
|
584
582
|
style,
|
|
585
583
|
components: componentOverrides,
|
|
586
|
-
|
|
584
|
+
presentation = 'adaptive',
|
|
587
585
|
}: PowerSearchProps) {
|
|
588
586
|
const size = useSize(sizeProp, 'md');
|
|
589
587
|
const config = useInternalConfig(configProp);
|
|
@@ -597,11 +595,6 @@ export function PowerSearch({
|
|
|
597
595
|
popoverSaveButtonLabelFromProps ?? t('@astryx.powersearch.editor.apply');
|
|
598
596
|
const tokenizerRef = useRef<TokenizerHandle>(null);
|
|
599
597
|
|
|
600
|
-
// Experimental presentation. `adaptive`
|
|
601
|
-
// resolves through the policy the selection controls share; an open flow
|
|
602
|
-
// keeps its presentation until it closes, so a resolution change mid-task
|
|
603
|
-
// cannot pull the surface out from under the person.
|
|
604
|
-
const presentation = experimental?.presentation ?? 'popover';
|
|
605
598
|
const resolvedPresentation = useAdaptivePresentation(presentation);
|
|
606
599
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
607
600
|
// Latched for the flow's lifetime: the flow stays presented after it closes
|
|
@@ -687,12 +680,12 @@ export function PowerSearch({
|
|
|
687
680
|
}
|
|
688
681
|
useDevWarning(
|
|
689
682
|
'PowerSearch',
|
|
690
|
-
'`menuWidth` has no surface in the bottom-sheet presentation: the sheet flow has no typeahead popover to size.
|
|
683
|
+
'`menuWidth` has no surface in the bottom-sheet presentation: the sheet flow has no typeahead popover to size. Pass `presentation="popover"` to keep the popover on every device, or leave it out.',
|
|
691
684
|
isSheetPresentation && menuWidth != null,
|
|
692
685
|
);
|
|
693
686
|
useDevWarning(
|
|
694
687
|
'PowerSearch',
|
|
695
|
-
'`tokenOverflowBehavior` has no surface in the bottom-sheet presentation: the trigger wraps its display-only tokens.
|
|
688
|
+
'`tokenOverflowBehavior` has no surface in the bottom-sheet presentation: the trigger wraps its display-only tokens. Pass `presentation="popover"` to keep the tokenizer field on every device, or leave it out.',
|
|
696
689
|
isSheetPresentation && tokenOverflowBehavior != null,
|
|
697
690
|
);
|
|
698
691
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* RadioList, Text, TextInput, PowerSearchValueEditor, the internal sheet
|
|
11
11
|
* confirmation and search-drag owners, i18n
|
|
12
12
|
* @output Exports PowerSearchBottomSheet — the touch surface of
|
|
13
|
-
* `PowerSearch
|
|
13
|
+
* `PowerSearch presentation="bottom-sheet"`: a Filters sheet
|
|
14
14
|
* with editable rows and trailing remove actions, Add filter in its fixed
|
|
15
15
|
* header and Clear all / Done in its fixed footer, an Add filter sheet with
|
|
16
16
|
* grouped field rows or the content search with inline suggestions, and a
|
package/src/PowerSearch/index.ts
CHANGED
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
export {PowerSearch} from './PowerSearch';
|
|
15
|
-
export type {
|
|
15
|
+
export type {
|
|
16
|
+
PowerSearchPresentation,
|
|
17
|
+
PowerSearchProps,
|
|
18
|
+
PowerSearchSize,
|
|
19
|
+
} from './PowerSearch';
|
|
16
20
|
|
|
17
21
|
export {PowerSearchToken} from './PowerSearchToken';
|
|
18
22
|
export {PowerSearchFilterEditor} from './PowerSearchFilterEditor';
|
|
@@ -614,16 +614,14 @@ function TokenizerSheetContent<T extends SearchableItem>({
|
|
|
614
614
|
// `action` is declared on `SearchableItem` for the grid-adopting hosts; the
|
|
615
615
|
// sheet rows have not adopted it, so a row renders the item without the
|
|
616
616
|
// control and says so (`spec:AST-058` FR9), as the inline panel does.
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
'
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
}, [results]);
|
|
617
|
+
if (results.some(item => item.action != null)) {
|
|
618
|
+
warnOnce(
|
|
619
|
+
'tokenizer-sheet:item-action',
|
|
620
|
+
'Tokenizer',
|
|
621
|
+
'A result carries `action`, which the bottom-sheet rows do not render ' +
|
|
622
|
+
'yet; the item is shown without it.',
|
|
623
|
+
);
|
|
624
|
+
}
|
|
627
625
|
|
|
628
626
|
// The pending Spinner below stays named, as the inline field's does
|
|
629
627
|
// (`family:input-fields` FR7), but is not a live region; the sheet announces
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @file scrollLockTouchGuard.ts
|
|
7
7
|
* @input The node under a finger and the pan's direction, while a scroll lock
|
|
8
|
-
* holds the page
|
|
8
|
+
* holds the page; the native-scroll probe's edge test (gestures/nativeScroll)
|
|
9
9
|
* @output isPanAbsorbedBeforePage and isPageZoomedIn, for the page hold
|
|
10
10
|
* @position Internal hook utility; gestures/pageHold calls it for
|
|
11
11
|
* useScrollLock.
|
|
@@ -19,34 +19,8 @@
|
|
|
19
19
|
// element, whose containing block is the viewport, so its untaken pans go to
|
|
20
20
|
// the page.
|
|
21
21
|
|
|
22
|
+
import {canElementScroll} from '../gestures/nativeScroll';
|
|
22
23
|
import {parentAcrossShadow} from '../utils/flatTree';
|
|
23
|
-
import {isRtlElement} from './isRtlElement';
|
|
24
|
-
|
|
25
|
-
const SCROLLABLE = new Set(['auto', 'scroll']);
|
|
26
|
-
|
|
27
|
-
/** Overflow at or below this many px is a box that fits, not a scroller. */
|
|
28
|
-
const EDGE_TOLERANCE = 1;
|
|
29
|
-
|
|
30
|
-
function canMoveY(element: Element, dy: number, range: number): boolean {
|
|
31
|
-
// A finger moving down drags the content down: scrollTop decreases.
|
|
32
|
-
return dy > 0
|
|
33
|
-
? element.scrollTop > EDGE_TOLERANCE - 0.5
|
|
34
|
-
: element.scrollTop < range - EDGE_TOLERANCE + 0.5;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function canMoveX(
|
|
38
|
-
element: Element,
|
|
39
|
-
dx: number,
|
|
40
|
-
range: number,
|
|
41
|
-
isRtl: boolean,
|
|
42
|
-
): boolean {
|
|
43
|
-
const min = isRtl ? -range : 0;
|
|
44
|
-
const max = isRtl ? 0 : range;
|
|
45
|
-
// A finger moving right drags the content right: scrollLeft decreases.
|
|
46
|
-
return dx > 0
|
|
47
|
-
? element.scrollLeft > min + EDGE_TOLERANCE - 0.5
|
|
48
|
-
: element.scrollLeft < max - EDGE_TOLERANCE + 0.5;
|
|
49
|
-
}
|
|
50
24
|
|
|
51
25
|
/**
|
|
52
26
|
* Whether `element` itself takes a pan. It does when it can still scroll that
|
|
@@ -59,23 +33,16 @@ function takesPan(
|
|
|
59
33
|
dx: number,
|
|
60
34
|
dy: number,
|
|
61
35
|
): boolean {
|
|
62
|
-
|
|
63
|
-
|
|
36
|
+
const x = isVertical ? 0 : dx;
|
|
37
|
+
const y = isVertical ? dy : 0;
|
|
38
|
+
if (canElementScroll(element, x, y)) {
|
|
39
|
+
return true;
|
|
64
40
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// Content that fits has nothing to scroll. The pan goes on to the next
|
|
69
|
-
// scroller in the chain, and at last to the page.
|
|
70
|
-
if (range <= EDGE_TOLERANCE) {
|
|
41
|
+
// A scroller at its edge can still move the other way. A box that does not
|
|
42
|
+
// scroll, or whose content fits, cannot. Its pan goes on along the chain.
|
|
43
|
+
if (!canElementScroll(element, -x, -y)) {
|
|
71
44
|
return false;
|
|
72
45
|
}
|
|
73
|
-
const canMove = isVertical
|
|
74
|
-
? canMoveY(element, dy, range)
|
|
75
|
-
: canMoveX(element, dx, range, isRtlElement(element as HTMLElement));
|
|
76
|
-
if (canMove) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
46
|
const behavior = isVertical
|
|
80
47
|
? style.overscrollBehaviorY
|
|
81
48
|
: style.overscrollBehaviorX;
|
|
@@ -24,11 +24,6 @@ import {holdPageScroll} from '../gestures/pageHold';
|
|
|
24
24
|
import {isPageZoomedIn, isPanAbsorbedBeforePage} from './scrollLockTouchGuard';
|
|
25
25
|
import {holdScrollbarGutter, type ScrollbarGutterHold} from './scrollbarGutter';
|
|
26
26
|
|
|
27
|
-
// iOS Safari scrolls an `overflow: hidden` page under a finger.
|
|
28
|
-
// So the lock also cancels each one-finger pan that would reach the page. The
|
|
29
|
-
// scroll offset never changes, so unlock restores nothing, and iOS Safari's
|
|
30
|
-
// toolbar keeps its state.
|
|
31
|
-
|
|
32
27
|
interface ActiveLock {
|
|
33
28
|
releaseRootStyle: () => void;
|
|
34
29
|
releasePageHold: () => void;
|
|
@@ -41,8 +36,9 @@ let activeLock: ActiveLock | null = null;
|
|
|
41
36
|
/**
|
|
42
37
|
* Locks page scroll while `isLocked` is true.
|
|
43
38
|
*
|
|
44
|
-
* The page keeps its scroll offset, so nothing jumps on lock or unlock.
|
|
45
|
-
*
|
|
39
|
+
* The page keeps its scroll offset, so nothing jumps on lock or unlock. iOS
|
|
40
|
+
* Safari scrolls an `overflow: hidden` page under a finger. So where the
|
|
41
|
+
* primary pointer is coarse (phones and tablets), the lock cancels a
|
|
46
42
|
* one-finger pan that would reach the page.
|
|
47
43
|
* Pans that a scroller in the overlay takes, and two-finger zoom, go through.
|
|
48
44
|
* The gutter of a classic scrollbar stays open, so the page does not shift
|