@oxy.so/bloom 4.1.0 → 4.3.0
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/docs/adoption-matrix.mdx +7 -7
- package/docs/ai-chat.mdx +8 -0
- package/docs/app-shell.mdx +7 -0
- package/docs/bottom-bar.mdx +6 -0
- package/docs/settings-modal.mdx +14 -5
- package/docs/sidebar.mdx +11 -0
- package/lib/commonjs/ai-chat/AiChatContainer.js +8 -8
- package/lib/commonjs/ai-chat/AiChatContainer.js.map +1 -1
- package/lib/commonjs/app-shell/AppShellBars.js +8 -2
- package/lib/commonjs/app-shell/AppShellBars.js.map +1 -1
- package/lib/commonjs/app-shell/AppShellEngine.js +29 -6
- package/lib/commonjs/app-shell/AppShellEngine.js.map +1 -1
- package/lib/commonjs/bottom-bar/BottomBarBase.js +10 -2
- package/lib/commonjs/bottom-bar/BottomBarBase.js.map +1 -1
- package/lib/commonjs/layout/bottom-bar-slot.js +10 -0
- package/lib/commonjs/layout/bottom-bar-slot.js.map +1 -0
- package/lib/commonjs/settings-modal/SettingsModal.js +153 -230
- package/lib/commonjs/settings-modal/SettingsModal.js.map +1 -1
- package/lib/commonjs/sidebar/Sidebar.js +35 -5
- package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
- package/lib/module/ai-chat/AiChatContainer.js +8 -8
- package/lib/module/ai-chat/AiChatContainer.js.map +1 -1
- package/lib/module/app-shell/AppShellBars.js +8 -2
- package/lib/module/app-shell/AppShellBars.js.map +1 -1
- package/lib/module/app-shell/AppShellEngine.js +30 -7
- package/lib/module/app-shell/AppShellEngine.js.map +1 -1
- package/lib/module/bottom-bar/BottomBarBase.js +11 -3
- package/lib/module/bottom-bar/BottomBarBase.js.map +1 -1
- package/lib/module/layout/bottom-bar-slot.js +7 -0
- package/lib/module/layout/bottom-bar-slot.js.map +1 -0
- package/lib/module/settings-modal/SettingsModal.js +150 -227
- package/lib/module/settings-modal/SettingsModal.js.map +1 -1
- package/lib/module/sidebar/Sidebar.js +35 -5
- package/lib/module/sidebar/Sidebar.js.map +1 -1
- package/lib/typescript/commonjs/ai-chat/types.d.ts +2 -2
- package/lib/typescript/commonjs/ai-chat/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/app-shell/AppShellBars.d.ts +1 -0
- package/lib/typescript/commonjs/app-shell/AppShellBars.d.ts.map +1 -1
- package/lib/typescript/commonjs/app-shell/AppShellEngine.d.ts.map +1 -1
- package/lib/typescript/commonjs/bottom-bar/BottomBarBase.d.ts +1 -1
- package/lib/typescript/commonjs/bottom-bar/BottomBarBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/bottom-bar/types.d.ts +4 -0
- package/lib/typescript/commonjs/bottom-bar/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/layout/bottom-bar-slot.d.ts +3 -0
- package/lib/typescript/commonjs/layout/bottom-bar-slot.d.ts.map +1 -0
- package/lib/typescript/commonjs/settings-modal/SettingsModal.d.ts +1 -1
- package/lib/typescript/commonjs/settings-modal/SettingsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/settings-modal/types.d.ts +7 -2
- package/lib/typescript/commonjs/settings-modal/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/sidebar/Sidebar.d.ts.map +1 -1
- package/lib/typescript/commonjs/sidebar/types.d.ts +12 -1
- package/lib/typescript/commonjs/sidebar/types.d.ts.map +1 -1
- package/lib/typescript/module/ai-chat/types.d.ts +2 -2
- package/lib/typescript/module/ai-chat/types.d.ts.map +1 -1
- package/lib/typescript/module/app-shell/AppShellBars.d.ts +1 -0
- package/lib/typescript/module/app-shell/AppShellBars.d.ts.map +1 -1
- package/lib/typescript/module/app-shell/AppShellEngine.d.ts.map +1 -1
- package/lib/typescript/module/bottom-bar/BottomBarBase.d.ts +1 -1
- package/lib/typescript/module/bottom-bar/BottomBarBase.d.ts.map +1 -1
- package/lib/typescript/module/bottom-bar/types.d.ts +4 -0
- package/lib/typescript/module/bottom-bar/types.d.ts.map +1 -1
- package/lib/typescript/module/layout/bottom-bar-slot.d.ts +3 -0
- package/lib/typescript/module/layout/bottom-bar-slot.d.ts.map +1 -0
- package/lib/typescript/module/settings-modal/SettingsModal.d.ts +1 -1
- package/lib/typescript/module/settings-modal/SettingsModal.d.ts.map +1 -1
- package/lib/typescript/module/settings-modal/types.d.ts +7 -2
- package/lib/typescript/module/settings-modal/types.d.ts.map +1 -1
- package/lib/typescript/module/sidebar/Sidebar.d.ts.map +1 -1
- package/lib/typescript/module/sidebar/types.d.ts +12 -1
- package/lib/typescript/module/sidebar/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/support/adoption-matrix.ts +703 -0
- package/src/__tests__/support/collision-fixture-barrel.ts +20 -0
- package/src/__tests__/support/commerce-harness.tsx +97 -0
- package/src/__tests__/support/composite.ts +68 -0
- package/src/__tests__/support/constructed-style-sheets.ts +68 -0
- package/src/__tests__/support/press-host.ts +30 -0
- package/src/__tests__/support/rendered-style.ts +99 -0
- package/src/__tests__/support/unread-hook-fixture.ts +33 -0
- package/src/ai-chat/AiChatContainer.tsx +7 -7
- package/src/ai-chat/types.ts +2 -2
- package/src/app-shell/AppShellBars.tsx +5 -3
- package/src/app-shell/AppShellEngine.tsx +23 -8
- package/src/bottom-bar/BottomBarBase.tsx +7 -4
- package/src/bottom-bar/types.ts +4 -0
- package/src/layout/bottom-bar-slot.ts +4 -0
- package/src/settings-modal/SettingsModal.tsx +180 -250
- package/src/settings-modal/types.ts +7 -2
- package/src/sidebar/Sidebar.tsx +26 -5
- package/src/sidebar/types.ts +12 -1
- package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +9346 -0
- package/src/theme/__tests__/__fixtures__/tonal-glass-primary-failures.json +69 -0
- package/src/theme/__tests__/fixtures/color-engine-golden.json +1 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
4
|
-
import { BackHandler, Pressable,
|
|
5
|
-
import Animated, { Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
4
|
+
import { BackHandler, Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
|
|
5
|
+
import Animated, { Easing, useAnimatedStyle, useAnimatedScrollHandler, useReducedMotion, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
6
6
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
|
-
import { RiArrowLeftSLine } from "../icons/remix/RiArrowLeftSLine.js";
|
|
8
7
|
import { RiArrowRightSLine } from "../icons/remix/RiArrowRightSLine.js";
|
|
9
8
|
import { RiCheckboxCircleFill } from "../icons/remix/RiCheckboxCircleFill.js";
|
|
9
|
+
import { PageHeader } from "../page-header/index.js";
|
|
10
|
+
import { ButtonGroup, ButtonGroupItem } from "../button-group/index.js";
|
|
10
11
|
import { RiCloseLine } from "../icons/remix/RiCloseLine.js";
|
|
11
|
-
import { VerticalFade } from "./SettingsArt.js";
|
|
12
12
|
import { Backdrop, OverlayRoot } from "../overlay/index.js";
|
|
13
13
|
import { webDataSet } from "../styles/web-data.js";
|
|
14
14
|
import { Text } from "../typography/index.js";
|
|
@@ -28,10 +28,8 @@ import { IS_WEB, useSettingsWebCss } from "./web-css.js";
|
|
|
28
28
|
* 20px icon (icon/secondary) + 8 + body-medium label
|
|
29
29
|
* (selected: background/secondary/hover + text/primary;
|
|
30
30
|
* hover: background/secondary/hover @ 60%)
|
|
31
|
-
* content
|
|
32
|
-
*
|
|
33
|
-
* 16px glyph); the page scrolls under a 40px top fade that eases
|
|
34
|
-
* in (200ms) once it is scrolled; px 32 pb 32
|
|
31
|
+
* content one viewport with a sticky PageHeader and its scroll-linked edge;
|
|
32
|
+
* content insets belong to the page body, never the viewport
|
|
35
33
|
* toast "Saved" pill straddling the panel's bottom edge: 1px
|
|
36
34
|
* border/button, background/primary, py 4 pr 10 pl 6, gap 4,
|
|
37
35
|
* 16px lime check + body-2-medium, shadow-dropdown. Rises 12px in,
|
|
@@ -51,7 +49,7 @@ import { IS_WEB, useSettingsWebCss } from "./web-css.js";
|
|
|
51
49
|
* rank) and `Backdrop` (the pointer-events contract) — and takes Dialog's
|
|
52
50
|
* `control` from `useDialogControl()`, so it is driven exactly like one.
|
|
53
51
|
*/
|
|
54
|
-
import { jsx as _jsx,
|
|
52
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
55
53
|
const PANEL_WIDTH = 871;
|
|
56
54
|
const PANEL_HEIGHT = 614;
|
|
57
55
|
const RAIL_WIDTH = 274;
|
|
@@ -97,11 +95,13 @@ export function SettingsModal({
|
|
|
97
95
|
control,
|
|
98
96
|
open: controlledOpen,
|
|
99
97
|
onClose,
|
|
98
|
+
onBeforeLeave,
|
|
100
99
|
groups,
|
|
101
100
|
pages,
|
|
102
101
|
page: controlledPage,
|
|
103
102
|
defaultPage,
|
|
104
103
|
onPageChange,
|
|
104
|
+
initialView = 'navigation',
|
|
105
105
|
labels,
|
|
106
106
|
testID
|
|
107
107
|
}) {
|
|
@@ -125,7 +125,12 @@ export function SettingsModal({
|
|
|
125
125
|
const insets = useSafeAreaInsets();
|
|
126
126
|
|
|
127
127
|
// `compact` layout is two levels: the section list, then a page pushed over it.
|
|
128
|
-
const [compactPageOpen, setCompactPageOpen] = useState(
|
|
128
|
+
const [compactPageOpen, setCompactPageOpen] = useState(initialView === 'page');
|
|
129
|
+
const initialViewRef = useRef(initialView);
|
|
130
|
+
initialViewRef.current = initialView;
|
|
131
|
+
const beforeLeaveRef = useRef(onBeforeLeave);
|
|
132
|
+
beforeLeaveRef.current = onBeforeLeave;
|
|
133
|
+
const mayLeave = useCallback(reason => beforeLeaveRef.current?.(reason) !== false, []);
|
|
129
134
|
const onCloseRef = useRef(onClose);
|
|
130
135
|
onCloseRef.current = onClose;
|
|
131
136
|
const isControlledRef = useRef(isControlled);
|
|
@@ -134,7 +139,7 @@ export function SettingsModal({
|
|
|
134
139
|
defaultPageRef.current = defaultPage ?? firstPage(groups);
|
|
135
140
|
const show = useCallback(() => {
|
|
136
141
|
setInternalPage(defaultPageRef.current);
|
|
137
|
-
setCompactPageOpen(
|
|
142
|
+
setCompactPageOpen(initialViewRef.current === 'page');
|
|
138
143
|
setMounted(true);
|
|
139
144
|
setOpenCount(count => count + 1);
|
|
140
145
|
}, []);
|
|
@@ -171,20 +176,25 @@ export function SettingsModal({
|
|
|
171
176
|
if (controlledOpen) show();else hide();
|
|
172
177
|
}, [isControlled, controlledOpen, show, hide]);
|
|
173
178
|
const requestClose = useCallback(() => {
|
|
179
|
+
if (!mayLeave('close')) return false;
|
|
174
180
|
if (isControlledRef.current) onCloseRef.current?.();else hide();
|
|
175
|
-
|
|
181
|
+
return true;
|
|
182
|
+
}, [hide, mayLeave]);
|
|
176
183
|
useImperativeHandle(control?.ref, () => ({
|
|
177
184
|
open: show,
|
|
178
185
|
close: cb => {
|
|
179
|
-
|
|
180
|
-
if (cb) setTimeout(cb, UNMOUNT_MS);
|
|
186
|
+
if (requestClose() && cb) setTimeout(cb, UNMOUNT_MS);
|
|
181
187
|
}
|
|
182
|
-
}), [show,
|
|
188
|
+
}), [show, requestClose]);
|
|
183
189
|
const selectPage = useCallback(next => {
|
|
190
|
+
if (next !== currentPage && !mayLeave('page')) return;
|
|
184
191
|
if (controlledPage === undefined) setInternalPage(next);
|
|
185
192
|
setCompactPageOpen(true);
|
|
186
193
|
onPageChange?.(next);
|
|
187
|
-
}, [controlledPage, onPageChange]);
|
|
194
|
+
}, [controlledPage, currentPage, onPageChange, mayLeave]);
|
|
195
|
+
const requestNavigation = useCallback(() => {
|
|
196
|
+
if (mayLeave('navigation')) setCompactPageOpen(false);
|
|
197
|
+
}, [mayLeave]);
|
|
188
198
|
|
|
189
199
|
// Escape closes (web). On `window`, not `document`: a menu or popover opened
|
|
190
200
|
// inside the modal handles Escape on `document` and stops propagation there,
|
|
@@ -209,11 +219,11 @@ export function SettingsModal({
|
|
|
209
219
|
if (!mounted || IS_WEB || typeof BackHandler?.addEventListener !== 'function') return;
|
|
210
220
|
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
|
|
211
221
|
// On a pushed page (compact), back returns to the section list first.
|
|
212
|
-
if (compactPageOpenRef.current)
|
|
222
|
+
if (compactPageOpenRef.current) requestNavigation();else requestClose();
|
|
213
223
|
return true;
|
|
214
224
|
});
|
|
215
225
|
return () => sub.remove();
|
|
216
|
-
}, [mounted, requestClose]);
|
|
226
|
+
}, [mounted, requestClose, requestNavigation]);
|
|
217
227
|
|
|
218
228
|
// ----- saved toast -------------------------------------------------------
|
|
219
229
|
const [savedPhase, setSavedPhase] = useState('hidden');
|
|
@@ -323,32 +333,30 @@ export function SettingsModal({
|
|
|
323
333
|
backgroundColor: palette.full,
|
|
324
334
|
boxShadow: palette.shadowXs
|
|
325
335
|
}, ringVars(palette)],
|
|
326
|
-
children: layout === 'compact' ? compactPageOpen && pageConfig ? /*#__PURE__*/
|
|
336
|
+
children: layout === 'compact' ? compactPageOpen && pageConfig ? /*#__PURE__*/_jsx(View, {
|
|
327
337
|
style: styles.content,
|
|
328
|
-
children:
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}), /*#__PURE__*/_jsx(PageScroller, {
|
|
338
|
+
children: /*#__PURE__*/_jsx(PageScroller, {
|
|
339
|
+
header: {
|
|
340
|
+
title: pageConfig.title,
|
|
341
|
+
onBack: requestNavigation,
|
|
342
|
+
backLabel: labels?.back ?? 'Back',
|
|
343
|
+
closeLabel,
|
|
344
|
+
onClose: requestClose
|
|
345
|
+
},
|
|
337
346
|
palette: palette,
|
|
338
347
|
inset: CONTENT_INSET.compact,
|
|
339
348
|
insetTop: CONTENT_INSET.compact,
|
|
340
349
|
testID: testID,
|
|
341
350
|
children: pageConfig.content
|
|
342
|
-
}, currentPage)
|
|
343
|
-
}) : /*#__PURE__*/
|
|
351
|
+
}, currentPage)
|
|
352
|
+
}) : /*#__PURE__*/_jsx(View, {
|
|
344
353
|
style: styles.content,
|
|
345
|
-
children:
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}), /*#__PURE__*/_jsx(SettingsRail, {
|
|
354
|
+
children: /*#__PURE__*/_jsx(SettingsRail, {
|
|
355
|
+
header: {
|
|
356
|
+
title: labels?.dialog ?? 'Settings',
|
|
357
|
+
closeLabel,
|
|
358
|
+
onClose: requestClose
|
|
359
|
+
},
|
|
352
360
|
groups: groups,
|
|
353
361
|
page: currentPage,
|
|
354
362
|
onSelect: selectPage,
|
|
@@ -356,7 +364,7 @@ export function SettingsModal({
|
|
|
356
364
|
label: labels?.nav ?? 'Settings sections',
|
|
357
365
|
layout: "compact",
|
|
358
366
|
testID: testID
|
|
359
|
-
})
|
|
367
|
+
})
|
|
360
368
|
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
361
369
|
children: [/*#__PURE__*/_jsx(SettingsRail, {
|
|
362
370
|
groups: groups,
|
|
@@ -366,35 +374,20 @@ export function SettingsModal({
|
|
|
366
374
|
label: labels?.nav ?? 'Settings sections',
|
|
367
375
|
layout: layout,
|
|
368
376
|
testID: testID
|
|
369
|
-
}), /*#__PURE__*/
|
|
377
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
370
378
|
style: styles.content,
|
|
371
|
-
children:
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}],
|
|
378
|
-
testID: testID ? `${testID}-title-row` : undefined,
|
|
379
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
380
|
-
variant: "title-3-medium",
|
|
381
|
-
role: "heading",
|
|
382
|
-
style: {
|
|
383
|
-
color: palette.text
|
|
384
|
-
},
|
|
385
|
-
children: pageConfig?.title ?? ''
|
|
386
|
-
}), /*#__PURE__*/_jsx(SettingsCloseButton, {
|
|
387
|
-
label: closeLabel,
|
|
388
|
-
onPress: requestClose,
|
|
389
|
-
palette: palette,
|
|
390
|
-
testID: testID ? `${testID}-close` : undefined
|
|
391
|
-
})]
|
|
392
|
-
}), /*#__PURE__*/_jsx(PageScroller, {
|
|
379
|
+
children: /*#__PURE__*/_jsx(PageScroller, {
|
|
380
|
+
header: {
|
|
381
|
+
title: pageConfig?.title ?? '',
|
|
382
|
+
closeLabel,
|
|
383
|
+
onClose: requestClose
|
|
384
|
+
},
|
|
393
385
|
palette: palette,
|
|
394
386
|
inset: CONTENT_INSET[layout],
|
|
387
|
+
insetTop: pageConfig?.compactTitle ? 6 : 12,
|
|
395
388
|
testID: testID,
|
|
396
389
|
children: pageConfig?.content
|
|
397
|
-
}, currentPage)
|
|
390
|
+
}, currentPage)
|
|
398
391
|
})]
|
|
399
392
|
})
|
|
400
393
|
}), /*#__PURE__*/_jsx(SavedToast, {
|
|
@@ -423,6 +416,7 @@ function ringVars(palette) {
|
|
|
423
416
|
// ---------------------------------------------------------------------------
|
|
424
417
|
|
|
425
418
|
function SettingsRail({
|
|
419
|
+
header,
|
|
426
420
|
groups,
|
|
427
421
|
page,
|
|
428
422
|
onSelect,
|
|
@@ -432,7 +426,11 @@ function SettingsRail({
|
|
|
432
426
|
testID
|
|
433
427
|
}) {
|
|
434
428
|
const compact = layout === 'compact';
|
|
435
|
-
|
|
429
|
+
const scrollY = useSharedValue(0);
|
|
430
|
+
const onScroll = useAnimatedScrollHandler(event => {
|
|
431
|
+
scrollY.value = Math.max(0, event.contentOffset.y);
|
|
432
|
+
}, [scrollY]);
|
|
433
|
+
return /*#__PURE__*/_jsxs(Animated.ScrollView, {
|
|
436
434
|
role: "navigation",
|
|
437
435
|
"aria-label": label,
|
|
438
436
|
style: [compact ? styles.railCompact : [styles.rail, {
|
|
@@ -441,31 +439,47 @@ function SettingsRail({
|
|
|
441
439
|
backgroundColor: palette.secondary,
|
|
442
440
|
borderRightColor: palette.separator
|
|
443
441
|
}],
|
|
444
|
-
contentContainerStyle:
|
|
442
|
+
contentContainerStyle: header ? undefined : styles.railContent,
|
|
443
|
+
stickyHeaderIndices: header && !IS_WEB ? [0] : undefined,
|
|
444
|
+
onScroll: onScroll,
|
|
445
|
+
scrollEventThrottle: 16,
|
|
446
|
+
contentInsetAdjustmentBehavior: "never",
|
|
447
|
+
automaticallyAdjustContentInsets: false,
|
|
445
448
|
showsVerticalScrollIndicator: false,
|
|
446
449
|
testID: testID ? `${testID}-rail` : undefined,
|
|
447
|
-
children:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
,
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
450
|
+
children: [header ? /*#__PURE__*/_jsx(SettingsHeader, {
|
|
451
|
+
...header,
|
|
452
|
+
palette: palette,
|
|
453
|
+
scrimColor: palette.secondary,
|
|
454
|
+
scrollY: scrollY,
|
|
455
|
+
testID: testID
|
|
456
|
+
}) : null, /*#__PURE__*/_jsx(View, {
|
|
457
|
+
style: header ? [styles.railContent, styles.railContentCompact] : {
|
|
458
|
+
gap: 20
|
|
459
|
+
},
|
|
460
|
+
children: groups.map(group => /*#__PURE__*/_jsxs(View, {
|
|
461
|
+
style: styles.group,
|
|
462
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
463
|
+
variant: "body-medium",
|
|
464
|
+
style: [styles.groupLabel, {
|
|
465
|
+
color: palette.textSecondary
|
|
466
|
+
}],
|
|
467
|
+
children: group.label
|
|
468
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
469
|
+
style: styles.groupRows,
|
|
470
|
+
children: group.items.map(item => /*#__PURE__*/_jsx(RailRow, {
|
|
471
|
+
item: item
|
|
472
|
+
// A list, not a selection, when the rows ARE the navigation.
|
|
473
|
+
,
|
|
474
|
+
selected: !compact && item.page !== undefined && item.page === page,
|
|
475
|
+
showChevron: compact && item.page !== undefined,
|
|
476
|
+
onSelect: onSelect,
|
|
477
|
+
palette: palette,
|
|
478
|
+
testID: testID ? `${testID}-nav-${item.key}` : undefined
|
|
479
|
+
}, item.key))
|
|
480
|
+
})]
|
|
481
|
+
}, group.key ?? group.label))
|
|
482
|
+
})]
|
|
469
483
|
});
|
|
470
484
|
}
|
|
471
485
|
function RailRow({
|
|
@@ -527,124 +541,78 @@ function RailRow({
|
|
|
527
541
|
// Close button, scroller, toast
|
|
528
542
|
// ---------------------------------------------------------------------------
|
|
529
543
|
|
|
530
|
-
|
|
531
|
-
label,
|
|
532
|
-
onPress,
|
|
533
|
-
palette,
|
|
534
|
-
testID
|
|
535
|
-
}) {
|
|
536
|
-
const [hovered, setHovered] = useState(false);
|
|
537
|
-
return /*#__PURE__*/_jsx(Pressable, {
|
|
538
|
-
role: "button",
|
|
539
|
-
accessibilityLabel: label,
|
|
540
|
-
...webDataSet({
|
|
541
|
-
bloomSettingsPress: ''
|
|
542
|
-
}),
|
|
543
|
-
onPress: onPress,
|
|
544
|
-
onHoverIn: () => setHovered(true),
|
|
545
|
-
onHoverOut: () => setHovered(false),
|
|
546
|
-
testID: testID,
|
|
547
|
-
style: [styles.close, {
|
|
548
|
-
backgroundColor: hovered ? palette.tertiaryHover : palette.tertiary
|
|
549
|
-
}],
|
|
550
|
-
children: /*#__PURE__*/_jsx(RiCloseLine, {
|
|
551
|
-
width: 16,
|
|
552
|
-
height: 16,
|
|
553
|
-
fill: palette.iconSecondary
|
|
554
|
-
})
|
|
555
|
-
});
|
|
556
|
-
}
|
|
544
|
+
/** Shared header on every layout; the modal already owns safe-area insets. */
|
|
557
545
|
|
|
558
|
-
|
|
559
|
-
* The `compact` title bar: optional back chevron, the title, the close button —
|
|
560
|
-
* 56px, the page's 16px inset, hairline under it.
|
|
561
|
-
*/
|
|
562
|
-
function CompactHeader({
|
|
546
|
+
function SettingsHeader({
|
|
563
547
|
title,
|
|
564
548
|
onBack,
|
|
565
549
|
backLabel,
|
|
566
550
|
closeLabel,
|
|
567
551
|
onClose,
|
|
568
552
|
palette,
|
|
553
|
+
scrollY,
|
|
554
|
+
scrimColor = palette.full,
|
|
569
555
|
testID
|
|
570
556
|
}) {
|
|
571
|
-
return /*#__PURE__*/
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
557
|
+
return /*#__PURE__*/_jsx(PageHeader, {
|
|
558
|
+
title: title,
|
|
559
|
+
headingLevel: 2,
|
|
560
|
+
onBack: onBack,
|
|
561
|
+
backLabel: backLabel,
|
|
562
|
+
safeArea: false,
|
|
563
|
+
sticky: IS_WEB,
|
|
564
|
+
placement: "inline",
|
|
565
|
+
scrim: "auto",
|
|
566
|
+
scrimColor: scrimColor,
|
|
567
|
+
scrollY: scrollY,
|
|
568
|
+
actions: /*#__PURE__*/_jsx(ButtonGroup, {
|
|
569
|
+
accessibilityLabel: closeLabel,
|
|
570
|
+
children: /*#__PURE__*/_jsx(ButtonGroupItem, {
|
|
571
|
+
iconOnly: true,
|
|
572
|
+
leadingIcon: RiCloseLine,
|
|
573
|
+
accessibilityLabel: closeLabel,
|
|
574
|
+
onPress: onClose,
|
|
575
|
+
testID: testID ? `${testID}-close` : undefined
|
|
590
576
|
})
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
role: "heading",
|
|
594
|
-
numberOfLines: 1,
|
|
595
|
-
style: [styles.compactTitle, {
|
|
596
|
-
color: palette.text
|
|
597
|
-
}],
|
|
598
|
-
children: title
|
|
599
|
-
}), /*#__PURE__*/_jsx(SettingsCloseButton, {
|
|
600
|
-
label: closeLabel,
|
|
601
|
-
onPress: onClose,
|
|
602
|
-
palette: palette,
|
|
603
|
-
testID: testID ? `${testID}-close` : undefined
|
|
604
|
-
})]
|
|
577
|
+
}),
|
|
578
|
+
testID: testID ? `${testID}-header` : undefined
|
|
605
579
|
});
|
|
606
580
|
}
|
|
581
|
+
|
|
582
|
+
/** Each page owns one full-height viewport, including its header. */
|
|
607
583
|
function PageScroller({
|
|
608
584
|
children,
|
|
585
|
+
header,
|
|
609
586
|
palette,
|
|
610
587
|
inset,
|
|
611
588
|
insetTop = 0,
|
|
612
589
|
testID
|
|
613
590
|
}) {
|
|
614
|
-
const
|
|
615
|
-
const onScroll =
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
} :
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
591
|
+
const scrollY = useSharedValue(0);
|
|
592
|
+
const onScroll = useAnimatedScrollHandler(event => {
|
|
593
|
+
scrollY.value = Math.max(0, event.contentOffset.y);
|
|
594
|
+
}, [scrollY]);
|
|
595
|
+
return /*#__PURE__*/_jsxs(Animated.ScrollView, {
|
|
596
|
+
style: styles.scroll,
|
|
597
|
+
stickyHeaderIndices: IS_WEB ? undefined : [0],
|
|
598
|
+
onScroll: onScroll,
|
|
599
|
+
scrollEventThrottle: 16,
|
|
600
|
+
contentInsetAdjustmentBehavior: "never",
|
|
601
|
+
automaticallyAdjustContentInsets: false,
|
|
602
|
+
testID: testID ? `${testID}-page` : undefined,
|
|
603
|
+
children: [/*#__PURE__*/_jsx(SettingsHeader, {
|
|
604
|
+
...header,
|
|
605
|
+
palette: palette,
|
|
606
|
+
scrollY: scrollY,
|
|
607
|
+
testID: testID
|
|
608
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
609
|
+
style: {
|
|
632
610
|
paddingLeft: inset,
|
|
633
611
|
paddingRight: inset,
|
|
634
612
|
paddingBottom: inset,
|
|
635
613
|
paddingTop: insetTop
|
|
636
|
-
}
|
|
637
|
-
onScroll: onScroll,
|
|
638
|
-
scrollEventThrottle: 16,
|
|
639
|
-
testID: testID ? `${testID}-page` : undefined,
|
|
614
|
+
},
|
|
640
615
|
children: children
|
|
641
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
642
|
-
pointerEvents: "none",
|
|
643
|
-
style: [styles.fade, fade],
|
|
644
|
-
testID: testID ? `${testID}-fade` : undefined,
|
|
645
|
-
children: /*#__PURE__*/_jsx(VerticalFade, {
|
|
646
|
-
color: palette.primary
|
|
647
|
-
})
|
|
648
616
|
})]
|
|
649
617
|
});
|
|
650
618
|
}
|
|
@@ -741,27 +709,6 @@ const styles = StyleSheet.create({
|
|
|
741
709
|
railChevron: {
|
|
742
710
|
marginLeft: 'auto'
|
|
743
711
|
},
|
|
744
|
-
compactHeader: {
|
|
745
|
-
flexDirection: 'row',
|
|
746
|
-
alignItems: 'center',
|
|
747
|
-
gap: 8,
|
|
748
|
-
height: 56,
|
|
749
|
-
paddingLeft: 16,
|
|
750
|
-
paddingRight: 16,
|
|
751
|
-
borderBottomWidth: 1
|
|
752
|
-
},
|
|
753
|
-
compactBack: {
|
|
754
|
-
width: 32,
|
|
755
|
-
height: 32,
|
|
756
|
-
marginLeft: -8,
|
|
757
|
-
alignItems: 'center',
|
|
758
|
-
justifyContent: 'center',
|
|
759
|
-
borderRadius: 9999
|
|
760
|
-
},
|
|
761
|
-
compactTitle: {
|
|
762
|
-
flex: 1,
|
|
763
|
-
minWidth: 0
|
|
764
|
-
},
|
|
765
712
|
panel: {
|
|
766
713
|
flexDirection: 'row',
|
|
767
714
|
borderRadius: 24,
|
|
@@ -800,33 +747,9 @@ const styles = StyleSheet.create({
|
|
|
800
747
|
flex: 1,
|
|
801
748
|
minWidth: 0
|
|
802
749
|
},
|
|
803
|
-
titleRow: {
|
|
804
|
-
flexDirection: 'row',
|
|
805
|
-
alignItems: 'center',
|
|
806
|
-
justifyContent: 'space-between'
|
|
807
|
-
},
|
|
808
|
-
close: {
|
|
809
|
-
width: 24,
|
|
810
|
-
height: 24,
|
|
811
|
-
borderRadius: 9999,
|
|
812
|
-
alignItems: 'center',
|
|
813
|
-
justifyContent: 'center'
|
|
814
|
-
},
|
|
815
|
-
scrollHost: {
|
|
816
|
-
flex: 1,
|
|
817
|
-
minHeight: 0,
|
|
818
|
-
position: 'relative'
|
|
819
|
-
},
|
|
820
750
|
scroll: {
|
|
821
|
-
flex: 1
|
|
822
|
-
|
|
823
|
-
scrollContent: {},
|
|
824
|
-
fade: {
|
|
825
|
-
position: 'absolute',
|
|
826
|
-
left: 0,
|
|
827
|
-
right: 0,
|
|
828
|
-
top: 0,
|
|
829
|
-
height: 40
|
|
751
|
+
flex: 1,
|
|
752
|
+
minHeight: 0
|
|
830
753
|
},
|
|
831
754
|
toast: {
|
|
832
755
|
position: 'absolute',
|