@oxy.so/bloom 7.1.5 → 7.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 +18 -17
- package/docs/app-shell.mdx +48 -2
- package/docs/appearance.mdx +16 -1
- package/docs/chip.mdx +5 -0
- package/docs/content-panel.mdx +9 -0
- package/docs/error-boundary.mdx +35 -0
- package/docs/mail-thread.mdx +8 -0
- package/docs/page-footer.mdx +60 -0
- package/docs/settings-modal.mdx +5 -0
- package/docs/sidebar.mdx +1 -1
- package/lib/commonjs/app-shell/AppShell.js +3 -2
- package/lib/commonjs/app-shell/AppShell.js.map +1 -1
- package/lib/commonjs/app-shell/AppShellBars.js +8 -5
- package/lib/commonjs/app-shell/AppShellBars.js.map +1 -1
- package/lib/commonjs/app-shell/AppShellEngine.js +81 -36
- package/lib/commonjs/app-shell/AppShellEngine.js.map +1 -1
- package/lib/commonjs/app-shell/AppShellSplit.js +26 -14
- package/lib/commonjs/app-shell/AppShellSplit.js.map +1 -1
- package/lib/commonjs/appearance/BloomScope.js +8 -3
- package/lib/commonjs/appearance/BloomScope.js.map +1 -1
- package/lib/commonjs/appearance/context.js.map +1 -1
- package/lib/commonjs/chip/Chip.js +51 -7
- package/lib/commonjs/chip/Chip.js.map +1 -1
- package/lib/commonjs/content-panel/ContentPanel.js +40 -24
- package/lib/commonjs/content-panel/ContentPanel.js.map +1 -1
- package/lib/commonjs/content-panel/ContentPanel.web.js +45 -18
- package/lib/commonjs/content-panel/ContentPanel.web.js.map +1 -1
- package/lib/commonjs/design-tokens/shapes.js +2 -2
- package/lib/commonjs/design-tokens/shapes.js.map +1 -1
- package/lib/commonjs/design-tokens/tokens.json +2 -2
- package/lib/commonjs/error-boundary/ErrorBoundary.js +10 -0
- package/lib/commonjs/error-boundary/ErrorBoundary.js.map +1 -1
- package/lib/commonjs/error-boundary/PanelErrorBoundary.js +64 -0
- package/lib/commonjs/error-boundary/PanelErrorBoundary.js.map +1 -0
- package/lib/commonjs/error-boundary/index.js +7 -0
- package/lib/commonjs/error-boundary/index.js.map +1 -1
- package/lib/commonjs/index.js +946 -927
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +946 -927
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/mail-thread/MailMessage.js +8 -14
- package/lib/commonjs/mail-thread/MailMessage.js.map +1 -1
- package/lib/commonjs/mail-thread/MailThread.js +6 -2
- package/lib/commonjs/mail-thread/MailThread.js.map +1 -1
- package/lib/commonjs/mail-thread/shared.js +2 -1
- package/lib/commonjs/mail-thread/shared.js.map +1 -1
- package/lib/commonjs/page-footer/PageFooter.js +137 -0
- package/lib/commonjs/page-footer/PageFooter.js.map +1 -0
- package/lib/commonjs/page-footer/PageFooterProvider.js +22 -0
- package/lib/commonjs/page-footer/PageFooterProvider.js.map +1 -0
- package/lib/commonjs/page-footer/context.js +11 -0
- package/lib/commonjs/page-footer/context.js.map +1 -0
- package/lib/commonjs/page-footer/index.js +27 -0
- package/lib/commonjs/page-footer/index.js.map +1 -0
- package/lib/commonjs/page-footer/types.js +6 -0
- package/lib/commonjs/page-footer/types.js.map +1 -0
- package/lib/commonjs/page-footer/use-page-footer-inset.js +19 -0
- package/lib/commonjs/page-footer/use-page-footer-inset.js.map +1 -0
- package/lib/commonjs/settings-modal/SettingsPlanCard.js +11 -7
- package/lib/commonjs/settings-modal/SettingsPlanCard.js.map +1 -1
- package/lib/commonjs/sidebar/Sidebar.js +6 -5
- package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
- package/lib/commonjs/styles/panel-chrome.js +15 -1
- package/lib/commonjs/styles/panel-chrome.js.map +1 -1
- package/lib/module/app-shell/AppShell.js +3 -2
- package/lib/module/app-shell/AppShell.js.map +1 -1
- package/lib/module/app-shell/AppShellBars.js +8 -5
- package/lib/module/app-shell/AppShellBars.js.map +1 -1
- package/lib/module/app-shell/AppShellEngine.js +81 -36
- package/lib/module/app-shell/AppShellEngine.js.map +1 -1
- package/lib/module/app-shell/AppShellSplit.js +26 -14
- package/lib/module/app-shell/AppShellSplit.js.map +1 -1
- package/lib/module/appearance/BloomScope.js +8 -3
- package/lib/module/appearance/BloomScope.js.map +1 -1
- package/lib/module/appearance/context.js.map +1 -1
- package/lib/module/chip/Chip.js +51 -7
- package/lib/module/chip/Chip.js.map +1 -1
- package/lib/module/content-panel/ContentPanel.js +41 -25
- package/lib/module/content-panel/ContentPanel.js.map +1 -1
- package/lib/module/content-panel/ContentPanel.web.js +47 -20
- package/lib/module/content-panel/ContentPanel.web.js.map +1 -1
- package/lib/module/design-tokens/shapes.js +2 -2
- package/lib/module/design-tokens/shapes.js.map +1 -1
- package/lib/module/design-tokens/tokens.json +2 -2
- package/lib/module/error-boundary/ErrorBoundary.js +10 -0
- package/lib/module/error-boundary/ErrorBoundary.js.map +1 -1
- package/lib/module/error-boundary/PanelErrorBoundary.js +59 -0
- package/lib/module/error-boundary/PanelErrorBoundary.js.map +1 -0
- package/lib/module/error-boundary/index.js +1 -0
- package/lib/module/error-boundary/index.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +2 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/mail-thread/MailMessage.js +8 -14
- package/lib/module/mail-thread/MailMessage.js.map +1 -1
- package/lib/module/mail-thread/MailThread.js +6 -2
- package/lib/module/mail-thread/MailThread.js.map +1 -1
- package/lib/module/mail-thread/shared.js +2 -1
- package/lib/module/mail-thread/shared.js.map +1 -1
- package/lib/module/page-footer/PageFooter.js +132 -0
- package/lib/module/page-footer/PageFooter.js.map +1 -0
- package/lib/module/page-footer/PageFooterProvider.js +18 -0
- package/lib/module/page-footer/PageFooterProvider.js.map +1 -0
- package/lib/module/page-footer/context.js +7 -0
- package/lib/module/page-footer/context.js.map +1 -0
- package/lib/module/page-footer/index.js +6 -0
- package/lib/module/page-footer/index.js.map +1 -0
- package/lib/module/page-footer/types.js +4 -0
- package/lib/module/page-footer/types.js.map +1 -0
- package/lib/module/page-footer/use-page-footer-inset.js +16 -0
- package/lib/module/page-footer/use-page-footer-inset.js.map +1 -0
- package/lib/module/settings-modal/SettingsPlanCard.js +7 -3
- package/lib/module/settings-modal/SettingsPlanCard.js.map +1 -1
- package/lib/module/sidebar/Sidebar.js +6 -5
- package/lib/module/sidebar/Sidebar.js.map +1 -1
- package/lib/module/styles/panel-chrome.js +14 -1
- package/lib/module/styles/panel-chrome.js.map +1 -1
- package/lib/typescript/commonjs/app-shell/AppShellBars.d.ts +4 -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/app-shell/AppShellSplit.d.ts.map +1 -1
- package/lib/typescript/commonjs/app-shell/types.d.ts +16 -3
- package/lib/typescript/commonjs/app-shell/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/appearance/BloomScope.d.ts +1 -1
- package/lib/typescript/commonjs/appearance/BloomScope.d.ts.map +1 -1
- package/lib/typescript/commonjs/appearance/context.d.ts +2 -2
- package/lib/typescript/commonjs/appearance/context.d.ts.map +1 -1
- package/lib/typescript/commonjs/appearance/types.d.ts +4 -1
- package/lib/typescript/commonjs/appearance/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/chip/Chip.d.ts.map +1 -1
- package/lib/typescript/commonjs/content-panel/ContentPanel.d.ts +3 -4
- package/lib/typescript/commonjs/content-panel/ContentPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/content-panel/ContentPanel.web.d.ts +1 -1
- package/lib/typescript/commonjs/content-panel/ContentPanel.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/content-panel/types.d.ts +5 -2
- package/lib/typescript/commonjs/content-panel/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/design-tokens/shapes.d.ts +2 -2
- package/lib/typescript/commonjs/error-boundary/ErrorBoundary.d.ts +1 -0
- package/lib/typescript/commonjs/error-boundary/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/error-boundary/PanelErrorBoundary.d.ts +4 -0
- package/lib/typescript/commonjs/error-boundary/PanelErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/commonjs/error-boundary/index.d.ts +2 -1
- package/lib/typescript/commonjs/error-boundary/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/error-boundary/types.d.ts +16 -0
- package/lib/typescript/commonjs/error-boundary/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +3 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +3 -2
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/mail-thread/MailMessage.d.ts.map +1 -1
- package/lib/typescript/commonjs/mail-thread/MailThread.d.ts +1 -1
- package/lib/typescript/commonjs/mail-thread/MailThread.d.ts.map +1 -1
- package/lib/typescript/commonjs/mail-thread/shared.d.ts +1 -1
- package/lib/typescript/commonjs/mail-thread/shared.d.ts.map +1 -1
- package/lib/typescript/commonjs/mail-thread/types.d.ts +2 -0
- package/lib/typescript/commonjs/mail-thread/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/page-footer/PageFooter.d.ts +7 -0
- package/lib/typescript/commonjs/page-footer/PageFooter.d.ts.map +1 -0
- package/lib/typescript/commonjs/page-footer/PageFooterProvider.d.ts +4 -0
- package/lib/typescript/commonjs/page-footer/PageFooterProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/page-footer/context.d.ts +3 -0
- package/lib/typescript/commonjs/page-footer/context.d.ts.map +1 -0
- package/lib/typescript/commonjs/page-footer/index.d.ts +5 -0
- package/lib/typescript/commonjs/page-footer/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/page-footer/types.d.ts +26 -0
- package/lib/typescript/commonjs/page-footer/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/page-footer/use-page-footer-inset.d.ts +7 -0
- package/lib/typescript/commonjs/page-footer/use-page-footer-inset.d.ts.map +1 -0
- package/lib/typescript/commonjs/settings-modal/SettingsPlanCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/settings-modal/types.d.ts +3 -0
- 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 +1 -1
- package/lib/typescript/commonjs/styles/panel-chrome.d.ts +5 -0
- package/lib/typescript/commonjs/styles/panel-chrome.d.ts.map +1 -1
- package/lib/typescript/module/app-shell/AppShellBars.d.ts +4 -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/app-shell/AppShellSplit.d.ts.map +1 -1
- package/lib/typescript/module/app-shell/types.d.ts +16 -3
- package/lib/typescript/module/app-shell/types.d.ts.map +1 -1
- package/lib/typescript/module/appearance/BloomScope.d.ts +1 -1
- package/lib/typescript/module/appearance/BloomScope.d.ts.map +1 -1
- package/lib/typescript/module/appearance/context.d.ts +2 -2
- package/lib/typescript/module/appearance/context.d.ts.map +1 -1
- package/lib/typescript/module/appearance/types.d.ts +4 -1
- package/lib/typescript/module/appearance/types.d.ts.map +1 -1
- package/lib/typescript/module/chip/Chip.d.ts.map +1 -1
- package/lib/typescript/module/content-panel/ContentPanel.d.ts +3 -4
- package/lib/typescript/module/content-panel/ContentPanel.d.ts.map +1 -1
- package/lib/typescript/module/content-panel/ContentPanel.web.d.ts +1 -1
- package/lib/typescript/module/content-panel/ContentPanel.web.d.ts.map +1 -1
- package/lib/typescript/module/content-panel/types.d.ts +5 -2
- package/lib/typescript/module/content-panel/types.d.ts.map +1 -1
- package/lib/typescript/module/design-tokens/shapes.d.ts +2 -2
- package/lib/typescript/module/error-boundary/ErrorBoundary.d.ts +1 -0
- package/lib/typescript/module/error-boundary/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/module/error-boundary/PanelErrorBoundary.d.ts +4 -0
- package/lib/typescript/module/error-boundary/PanelErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/module/error-boundary/index.d.ts +2 -1
- package/lib/typescript/module/error-boundary/index.d.ts.map +1 -1
- package/lib/typescript/module/error-boundary/types.d.ts +16 -0
- package/lib/typescript/module/error-boundary/types.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +3 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +3 -2
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/mail-thread/MailMessage.d.ts.map +1 -1
- package/lib/typescript/module/mail-thread/MailThread.d.ts +1 -1
- package/lib/typescript/module/mail-thread/MailThread.d.ts.map +1 -1
- package/lib/typescript/module/mail-thread/shared.d.ts +1 -1
- package/lib/typescript/module/mail-thread/shared.d.ts.map +1 -1
- package/lib/typescript/module/mail-thread/types.d.ts +2 -0
- package/lib/typescript/module/mail-thread/types.d.ts.map +1 -1
- package/lib/typescript/module/page-footer/PageFooter.d.ts +7 -0
- package/lib/typescript/module/page-footer/PageFooter.d.ts.map +1 -0
- package/lib/typescript/module/page-footer/PageFooterProvider.d.ts +4 -0
- package/lib/typescript/module/page-footer/PageFooterProvider.d.ts.map +1 -0
- package/lib/typescript/module/page-footer/context.d.ts +3 -0
- package/lib/typescript/module/page-footer/context.d.ts.map +1 -0
- package/lib/typescript/module/page-footer/index.d.ts +5 -0
- package/lib/typescript/module/page-footer/index.d.ts.map +1 -0
- package/lib/typescript/module/page-footer/types.d.ts +26 -0
- package/lib/typescript/module/page-footer/types.d.ts.map +1 -0
- package/lib/typescript/module/page-footer/use-page-footer-inset.d.ts +7 -0
- package/lib/typescript/module/page-footer/use-page-footer-inset.d.ts.map +1 -0
- package/lib/typescript/module/settings-modal/SettingsPlanCard.d.ts.map +1 -1
- package/lib/typescript/module/settings-modal/types.d.ts +3 -0
- 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 +1 -1
- package/lib/typescript/module/styles/panel-chrome.d.ts +5 -0
- package/lib/typescript/module/styles/panel-chrome.d.ts.map +1 -1
- package/package.json +18 -1
- package/src/__tests__/support/adoption-matrix.ts +683 -0
- package/src/__tests__/support/card-surface.ts +25 -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/messages-in.ts +10 -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/__tests__/support/worklet-capture-fixture.tsx +28 -0
- package/src/agent-avatar/__tests__/artwork-golden.json +774 -0
- package/src/agent-creator/__tests__/support/character-runtime-fixture.tsx +26 -0
- package/src/app-shell/AppShell.tsx +2 -2
- package/src/app-shell/AppShellBars.tsx +6 -4
- package/src/app-shell/AppShellEngine.tsx +51 -18
- package/src/app-shell/AppShellSplit.tsx +16 -7
- package/src/app-shell/types.ts +16 -3
- package/src/appearance/BloomScope.tsx +5 -2
- package/src/appearance/context.ts +2 -2
- package/src/appearance/types.ts +4 -1
- package/src/chip/Chip.tsx +26 -5
- package/src/content-panel/ContentPanel.tsx +35 -26
- package/src/content-panel/ContentPanel.web.tsx +35 -24
- package/src/content-panel/types.ts +5 -2
- package/src/design-tokens/shapes.ts +1 -1
- package/src/design-tokens/tokens.json +2 -2
- package/src/error-boundary/ErrorBoundary.tsx +6 -0
- package/src/error-boundary/PanelErrorBoundary.tsx +38 -0
- package/src/error-boundary/index.ts +3 -0
- package/src/error-boundary/types.ts +18 -0
- package/src/index.ts +4 -1
- package/src/index.web.ts +4 -1
- package/src/mail-thread/MailMessage.tsx +9 -11
- package/src/mail-thread/MailThread.tsx +3 -1
- package/src/mail-thread/shared.ts +2 -1
- package/src/mail-thread/types.ts +2 -0
- package/src/page-footer/PageFooter.tsx +96 -0
- package/src/page-footer/PageFooterProvider.tsx +9 -0
- package/src/page-footer/context.ts +6 -0
- package/src/page-footer/index.ts +4 -0
- package/src/page-footer/types.ts +26 -0
- package/src/page-footer/use-page-footer-inset.ts +17 -0
- package/src/settings-modal/SettingsPlanCard.tsx +2 -0
- package/src/settings-modal/types.ts +3 -0
- package/src/sidebar/Sidebar.tsx +5 -4
- package/src/sidebar/types.ts +1 -1
- package/src/styles/panel-chrome.ts +9 -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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { memo, useContext, useEffect, useId, useState } from 'react';
|
|
2
|
+
import { Platform, StyleSheet, View, useWindowDimensions, type LayoutChangeEvent } from 'react-native';
|
|
3
|
+
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
|
|
4
|
+
import { BloomScope } from '../appearance';
|
|
5
|
+
import { useBottomEdgeInset } from '../layout/bottom-edge';
|
|
6
|
+
import { EdgeScrim, SCRIM_TAIL_RATIO } from '../page-header/EdgeScrim';
|
|
7
|
+
import { BREAKPOINTS } from '../styles/breakpoints';
|
|
8
|
+
import { useSurfaceFill } from '../styles/surface-levels';
|
|
9
|
+
import { Z_INDEX } from '../styles/z-index';
|
|
10
|
+
import { useTheme } from '../theme/use-theme';
|
|
11
|
+
import { PageFooterContext } from './context';
|
|
12
|
+
import type { PageFooterProps } from './types';
|
|
13
|
+
|
|
14
|
+
const BAR_HEIGHT = 56;
|
|
15
|
+
|
|
16
|
+
/** Page-local controls floating over a bounded scroller, above app navigation. */
|
|
17
|
+
function PageFooterComponent({
|
|
18
|
+
children, actions, bottomInset, safeArea, scrim = 'always', scrimColor, style, testID,
|
|
19
|
+
}: PageFooterProps) {
|
|
20
|
+
const theme = useTheme();
|
|
21
|
+
const fill = useSurfaceFill() ?? theme.colors.background;
|
|
22
|
+
const occupied = useBottomEdgeInset();
|
|
23
|
+
const rawBottom = bottomInset ?? occupied;
|
|
24
|
+
const bottom = Number.isFinite(rawBottom) ? Math.max(0, rawBottom) : 0;
|
|
25
|
+
const insets = useContext(SafeAreaInsetsContext);
|
|
26
|
+
const padBottom = (safeArea ?? Platform.OS !== 'web') && bottom === 0 ? insets?.bottom ?? 0 : 0;
|
|
27
|
+
const windowWidth = useWindowDimensions().width;
|
|
28
|
+
const [width, setWidth] = useState<number | null>(null);
|
|
29
|
+
// Measure the row, not the outer box: a safe-area change can then update the
|
|
30
|
+
// published clearance immediately rather than waiting for another onLayout.
|
|
31
|
+
const [rowHeight, setRowHeight] = useState(BAR_HEIGHT);
|
|
32
|
+
const height = rowHeight + padBottom;
|
|
33
|
+
const sideInset = (width ?? windowWidth) >= BREAKPOINTS.sm ? 24 : 16;
|
|
34
|
+
const store = useContext(PageFooterContext);
|
|
35
|
+
const id = useId();
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
store?.claim(id, height + bottom);
|
|
38
|
+
return () => store?.release(id);
|
|
39
|
+
}, [store, id, height, bottom]);
|
|
40
|
+
|
|
41
|
+
const onLayout = (event: LayoutChangeEvent) => {
|
|
42
|
+
const layout = event.nativeEvent.layout;
|
|
43
|
+
if (Number.isFinite(layout.width)) setWidth(Math.max(0, layout.width));
|
|
44
|
+
if (Number.isFinite(layout.height)) setRowHeight(Math.max(0, layout.height));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<View
|
|
49
|
+
testID={testID}
|
|
50
|
+
pointerEvents="box-none"
|
|
51
|
+
style={[styles.container, { bottom, paddingBottom: padBottom }, style]}
|
|
52
|
+
>
|
|
53
|
+
{scrim !== 'none' ? (
|
|
54
|
+
<View
|
|
55
|
+
pointerEvents="none"
|
|
56
|
+
style={[styles.scrim, { height: height * (1 + SCRIM_TAIL_RATIO) }]}
|
|
57
|
+
testID={testID ? `${testID}-scrim` : undefined}
|
|
58
|
+
>
|
|
59
|
+
<EdgeScrim edge="bottom" color={scrimColor ?? fill} testID={testID ? `${testID}-scrim-gradient` : undefined} />
|
|
60
|
+
</View>
|
|
61
|
+
) : null}
|
|
62
|
+
<View
|
|
63
|
+
onLayout={onLayout}
|
|
64
|
+
pointerEvents="box-none"
|
|
65
|
+
style={[styles.row, { paddingLeft: sideInset, paddingRight: sideInset }]}
|
|
66
|
+
testID={testID ? `${testID}-row` : undefined}
|
|
67
|
+
>
|
|
68
|
+
<BloomScope>
|
|
69
|
+
{children != null ? <View pointerEvents="box-none" style={styles.content}>{children}</View> : null}
|
|
70
|
+
{actions != null ? (
|
|
71
|
+
<View pointerEvents="box-none" style={styles.actions} testID={testID ? `${testID}-actions` : undefined}>
|
|
72
|
+
{actions}
|
|
73
|
+
</View>
|
|
74
|
+
) : null}
|
|
75
|
+
</BloomScope>
|
|
76
|
+
</View>
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const styles = StyleSheet.create({
|
|
82
|
+
container: {
|
|
83
|
+
position: 'absolute', left: 0, right: 0, zIndex: Z_INDEX.floating,
|
|
84
|
+
...(Platform.OS !== 'web' ? { elevation: Z_INDEX.floating } : {}),
|
|
85
|
+
},
|
|
86
|
+
scrim: { position: 'absolute', bottom: 0, left: 0, right: 0 },
|
|
87
|
+
row: {
|
|
88
|
+
minHeight: BAR_HEIGHT, flexDirection: 'row', alignItems: 'center',
|
|
89
|
+
gap: 8, paddingTop: 8, paddingBottom: 8,
|
|
90
|
+
},
|
|
91
|
+
content: { flex: 1, minWidth: 0 },
|
|
92
|
+
actions: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: 8, flexShrink: 1 },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export const PageFooter = memo(PageFooterComponent);
|
|
96
|
+
PageFooter.displayName = 'PageFooter';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, { useState, type PropsWithChildren } from 'react';
|
|
2
|
+
import { createEdgeStore } from '../layout/edge-store';
|
|
3
|
+
import { PageFooterContext } from './context';
|
|
4
|
+
|
|
5
|
+
/** Scope a page's footer measurement to its sibling scroller. Adds no layout. */
|
|
6
|
+
export function PageFooterProvider({ children }: PropsWithChildren) {
|
|
7
|
+
const [store] = useState(createEdgeStore);
|
|
8
|
+
return <PageFooterContext.Provider value={store}>{children}</PageFooterContext.Provider>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
import type { EdgeStore } from '../layout/edge-store';
|
|
3
|
+
|
|
4
|
+
// Local scroll clearance, deliberately separate from the global bottom edge
|
|
5
|
+
// that positions this footer. Publishing there would make it avoid itself.
|
|
6
|
+
export const PageFooterContext = createContext<EdgeStore | null>(null);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface PageFooterProps {
|
|
5
|
+
/** Optional content before the actions, for example a selection summary. */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
/** Controls grouped by the caller; inherits the surrounding Bloom size. */
|
|
8
|
+
actions?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Distance from the containing frame's bottom. Defaults to the occupied
|
|
11
|
+
* bottom edge (for example AppShell's measured bottom bar). Pass 0 when the
|
|
12
|
+
* frame already ends above navigation, or the footer is in a desktop pane.
|
|
13
|
+
*/
|
|
14
|
+
bottomInset?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Include the bottom safe area when no bottom edge is occupied. Defaults to
|
|
17
|
+
* true on native, false on web. Disable when the containing shell owns it.
|
|
18
|
+
*/
|
|
19
|
+
safeArea?: boolean;
|
|
20
|
+
/** The PageHeader gradient, mirrored upward. Default always. */
|
|
21
|
+
scrim?: 'always' | 'none';
|
|
22
|
+
/** Opaque gradient color; defaults to the containing surface's fill. */
|
|
23
|
+
scrimColor?: string;
|
|
24
|
+
style?: StyleProp<ViewStyle>;
|
|
25
|
+
testID?: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useContext, useSyncExternalStore } from 'react';
|
|
2
|
+
import { NO_INSET, NO_SUBSCRIPTION } from '../layout/edge-store';
|
|
3
|
+
import { PageFooterContext } from './context';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Clearance for the last scroll item: measured footer height plus bottomInset.
|
|
7
|
+
* Use as contentContainerStyle.paddingBottom. Returns 0 without a provider or
|
|
8
|
+
* once the footer unmounts; does not include the decorative gradient tail.
|
|
9
|
+
*/
|
|
10
|
+
export function usePageFooterInset(): number {
|
|
11
|
+
const store = useContext(PageFooterContext);
|
|
12
|
+
return useSyncExternalStore(
|
|
13
|
+
store?.subscribe ?? NO_SUBSCRIPTION,
|
|
14
|
+
store?.getInset ?? NO_INSET,
|
|
15
|
+
store?.getInset ?? NO_INSET,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { EmptyState } from '../empty-state';
|
|
2
3
|
import { StyleSheet, View } from 'react-native';
|
|
3
4
|
|
|
4
5
|
import { useMessages } from '../locale/messages';
|
|
@@ -81,6 +82,7 @@ function Sections({ sections }: { sections: SettingsPageSection[] }) {
|
|
|
81
82
|
{sections.map((section) => {
|
|
82
83
|
const card = (
|
|
83
84
|
<SettingsCard>
|
|
85
|
+
{section.rows.length === 0 && section.emptyState ? <EmptyState variant="compact" {...section.emptyState} /> : null}
|
|
84
86
|
{section.rows.map((row) => (
|
|
85
87
|
<SettingsRow key={row.key} label={row.label} description={row.description}>
|
|
86
88
|
{row.control}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EmptyStateProps } from '../empty-state/types';
|
|
1
2
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
3
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
4
|
|
|
@@ -212,6 +213,8 @@ export interface SettingsPageSection {
|
|
|
212
213
|
description?: string;
|
|
213
214
|
action?: ReactNode;
|
|
214
215
|
rows: SettingsRowData[];
|
|
216
|
+
/** Rendered inside the section card only when rows is empty. */
|
|
217
|
+
emptyState?: EmptyStateProps;
|
|
215
218
|
}
|
|
216
219
|
|
|
217
220
|
export interface SettingsGeneralPageProps {
|
package/src/sidebar/Sidebar.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { resolveSurfaceMaterial } from '../surface/resolve-surface-material';
|
|
|
3
3
|
import { SurfacePaint } from '../surface/SurfacePaint';
|
|
4
4
|
import { parseRgba } from '../theme/color-utils';
|
|
5
5
|
import { surfaceStyle } from '../shapes/surface-style';
|
|
6
|
-
import {
|
|
6
|
+
import { usePanelShape } from '../styles/panel-chrome';
|
|
7
7
|
import { useBloomAppearance } from '../appearance';
|
|
8
8
|
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
9
9
|
import {
|
|
@@ -62,7 +62,7 @@ import { SIDEBAR_MESSAGES } from './messages';
|
|
|
62
62
|
* panel `size` wide expanded (p12), its collapsed width at px7 py12 —
|
|
63
63
|
* with the 1px border that leaves exactly the size's item column
|
|
64
64
|
* (`metrics.ts`; `md` is the historical 260 / 52 / 36)
|
|
65
|
-
* surface `card` radius
|
|
65
|
+
* surface `card` shared panel radius, 1px border-button-white, shadow-sidebar,
|
|
66
66
|
* background-secondary; `plain` drops the chrome onto
|
|
67
67
|
* background-full; `docked` keeps the fill, squares the corners
|
|
68
68
|
* and leaves one hairline on the inner edge, full height
|
|
@@ -219,6 +219,7 @@ const SidebarPanel: React.FC<SidebarProps> = ({
|
|
|
219
219
|
const palette = useSidebarPalette();
|
|
220
220
|
const parentFill = useSurfaceFill();
|
|
221
221
|
const parentLevel = useSurfaceLevelValue();
|
|
222
|
+
const panelShape = usePanelShape();
|
|
222
223
|
const customSurface = StyleSheet.flatten(style);
|
|
223
224
|
const surfaceFill = customSurface?.backgroundColor ?? (surface === 'plain' ? undefined : (palette.panel));
|
|
224
225
|
const hasFill = typeof surfaceFill === 'string' && surfaceFill !== 'transparent' && parseRgba(surfaceFill)?.a !== 0;
|
|
@@ -444,7 +445,7 @@ const SidebarPanel: React.FC<SidebarProps> = ({
|
|
|
444
445
|
borderEndColor: palette.dockedEdge,
|
|
445
446
|
}
|
|
446
447
|
: {
|
|
447
|
-
...surfaceStyle(
|
|
448
|
+
...surfaceStyle(panelShape),
|
|
448
449
|
borderWidth: 1,
|
|
449
450
|
borderColor: palette.panelBorder,
|
|
450
451
|
backgroundColor: 'transparent',
|
|
@@ -709,7 +710,7 @@ const SidebarPanel: React.FC<SidebarProps> = ({
|
|
|
709
710
|
surfaceFillVars(publishedFill),
|
|
710
711
|
]}
|
|
711
712
|
>
|
|
712
|
-
{paintsSurface ? <SurfacePaint fill={surfaceFill} shape={{ curve:
|
|
713
|
+
{paintsSurface ? <SurfacePaint fill={surfaceFill} shape={{ curve: panelShape.curve }} radius={customSurface?.borderRadius ?? (surface === 'card' ? panelShape.radius : 0)} /> : null}
|
|
713
714
|
<View testID={`${testID ?? 'sidebar'}-main-region`} style={{ width: '100%', minHeight: 0, flexShrink: 1, ...(contentAlignment === 'center' ? { flex: 1, justifyContent: 'center' as const } : {}) }}>
|
|
714
715
|
<View style={{ width: '100%', minHeight: 0, flexShrink: 1 }}>
|
|
715
716
|
{/* Fixed chrome shares the panel's morph, never the destination scroll.
|
package/src/sidebar/types.ts
CHANGED
|
@@ -151,7 +151,7 @@ export type SidebarVariant = 'panel' | 'rail';
|
|
|
151
151
|
* page, independent of what it contains. It is the axis two apps differ on
|
|
152
152
|
* most: the same rows read as a different product behind a different edge.
|
|
153
153
|
*
|
|
154
|
-
* - `card` (default) the floating panel: radius
|
|
154
|
+
* - `card` (default) the floating panel: shared panel radius (28 by default), a hairline and the panel
|
|
155
155
|
* shadow, on the panel fill. A sidebar that sits IN the page.
|
|
156
156
|
* - `plain` no edge at all — no radius, no border, no shadow: the rows sit
|
|
157
157
|
* straight on the page. The social/reader look, and what a revealed mobile
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The FLOATING PANEL chrome — the edge Bloom's big surfaces wear: a hairline
|
|
3
|
-
* plus the soft three-part shadow that lifts a panel off the page background.
|
|
3
|
+
* plus the shared corner shape and soft three-part shadow that lifts a panel off the page background.
|
|
4
4
|
*
|
|
5
5
|
* It lives here because two surfaces wear the same thing and had it written
|
|
6
6
|
* twice: the `Sidebar`'s panel and the framed `ContentPanel`. A panel that only
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* border the canonical subtle border role in both modes
|
|
13
13
|
*/
|
|
14
14
|
import { useContext } from 'react';
|
|
15
|
+
import { BloomAppearanceContext } from '../appearance/context';
|
|
16
|
+
import { SURFACE_SHAPES } from '../design-tokens/shapes';
|
|
15
17
|
|
|
16
18
|
import { BloomThemeContext } from '../theme/BloomThemeProvider';
|
|
17
19
|
import type { Theme } from '../theme/types';
|
|
@@ -51,3 +53,9 @@ export function useOptionalPanelChrome(): PanelChrome | null {
|
|
|
51
53
|
const ctx = useContext(BloomThemeContext);
|
|
52
54
|
return ctx ? resolvePanelChrome(ctx.theme) : null;
|
|
53
55
|
}
|
|
56
|
+
|
|
57
|
+
/** Shared panel geometry, independently configurable from control size. */
|
|
58
|
+
export function usePanelShape() {
|
|
59
|
+
const { panelRadius } = useContext(BloomAppearanceContext);
|
|
60
|
+
return { ...SURFACE_SHAPES.sidebar, radius: panelRadius ?? SURFACE_SHAPES.sidebar.radius };
|
|
61
|
+
}
|