@newtonedev/components 0.1.21 → 0.1.22
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/composites/layout/ContentCard/ContentCard.d.ts.map +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.d.ts +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.d.ts.map +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts +1 -16
- package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts.map +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.types.d.ts +0 -6
- package/dist/composites/layout/Sidebar/Sidebar.types.d.ts.map +1 -1
- package/dist/index.cjs +85 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +85 -57
- package/dist/index.js.map +1 -1
- package/dist/layout/Page/Page.d.ts +11 -21
- package/dist/layout/Page/Page.d.ts.map +1 -1
- package/dist/layout/Page/Page.types.d.ts +26 -12
- package/dist/layout/Page/Page.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/composites/layout/ContentCard/ContentCard.tsx +0 -3
- package/src/composites/layout/Sidebar/Sidebar.styles.ts +1 -19
- package/src/composites/layout/Sidebar/Sidebar.tsx +19 -15
- package/src/composites/layout/Sidebar/Sidebar.types.ts +0 -6
- package/src/layout/Page/Page.tsx +111 -37
- package/src/layout/Page/Page.types.ts +29 -12
|
@@ -1,30 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { PageProps } from './Page.types';
|
|
3
3
|
/**
|
|
4
|
-
* Page — Full-viewport layout root with optional
|
|
4
|
+
* Page — Full-viewport layout root with optional layout slots.
|
|
5
5
|
*
|
|
6
6
|
* Page fills the full screen height and arranges layout regions:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
7
|
+
* - NavHeader pinned at the top of the navigation column (brand/logo)
|
|
8
|
+
* - NavContent to the left of the main content (scrollable nav)
|
|
9
|
+
* - NavFooter pinned at the bottom of the navigation column (user menu, sign out)
|
|
10
|
+
* - Header sticky at the top of the content area
|
|
9
11
|
* - Children fill the remaining space (typically a Viewport)
|
|
12
|
+
* - Footer pinned at the bottom of the content area
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```tsx
|
|
18
|
-
* <Page navbar={<Nav />}>
|
|
19
|
-
* <Viewport>
|
|
20
|
-
* <Section size="sm" fill>
|
|
21
|
-
* <Frame elevation={1} padding={32}>
|
|
22
|
-
* <Text>Centered content</Text>
|
|
23
|
-
* </Frame>
|
|
24
|
-
* </Section>
|
|
25
|
-
* </Viewport>
|
|
26
|
-
* </Page>
|
|
27
|
-
* ```
|
|
14
|
+
* Panels are separated by 1px gaps that reveal the root background
|
|
15
|
+
* (divider color), rather than borders. The navigation column uses a
|
|
16
|
+
* sunken (elevation -1) background; the content area uses grounded
|
|
17
|
+
* (elevation 0).
|
|
28
18
|
*/
|
|
29
|
-
export declare function Page({ children, scheme,
|
|
19
|
+
export declare function Page({ children, scheme, header, navHeader, navFooter, footer, navContent, testID, nativeID, ref, style, }: PageProps): React.JSX.Element;
|
|
30
20
|
//# sourceMappingURL=Page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../src/layout/Page/Page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../src/layout/Page/Page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAyC9C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACT,SAAS,EACT,MAAM,EACN,UAAU,EACV,MAAM,EACN,QAAQ,EACR,GAAG,EACH,KAAK,GACN,EAAE,SAAS,qBAyGX"}
|
|
@@ -3,14 +3,13 @@ import type { View, ViewStyle } from 'react-native';
|
|
|
3
3
|
* Props for Page — the outermost layout container for a screen.
|
|
4
4
|
*
|
|
5
5
|
* Page fills the full viewport height and arranges optional layout slots:
|
|
6
|
-
*
|
|
7
|
-
* It can also activate a scheme from
|
|
8
|
-
*
|
|
9
|
-
* Page is invisible — no background, border, or shadow.
|
|
6
|
+
* header (top), navigation column (left with navHeader + navContent),
|
|
7
|
+
* and children (main content area). It can also activate a scheme from
|
|
8
|
+
* the parent NewtoneProvider.
|
|
10
9
|
*
|
|
11
10
|
* @example
|
|
12
11
|
* ```tsx
|
|
13
|
-
* <Page
|
|
12
|
+
* <Page header={<Nav />}>
|
|
14
13
|
* <Viewport>
|
|
15
14
|
* <Section size="md">
|
|
16
15
|
* <Text>Page content</Text>
|
|
@@ -21,7 +20,7 @@ import type { View, ViewStyle } from 'react-native';
|
|
|
21
20
|
*
|
|
22
21
|
* @example
|
|
23
22
|
* ```tsx
|
|
24
|
-
* <Page scheme="vibrant"
|
|
23
|
+
* <Page scheme="vibrant" navContent={<Sidebar />}>
|
|
25
24
|
* <Viewport>
|
|
26
25
|
* <Section size="lg">
|
|
27
26
|
* <Text>Dashboard content</Text>
|
|
@@ -39,15 +38,30 @@ export interface PageProps {
|
|
|
39
38
|
*/
|
|
40
39
|
readonly scheme?: string;
|
|
41
40
|
/**
|
|
42
|
-
*
|
|
43
|
-
* The
|
|
41
|
+
* Header element rendered at the top of the content area (sticky).
|
|
42
|
+
* The header's height is determined by its own content.
|
|
43
|
+
*/
|
|
44
|
+
readonly header?: React.ReactNode;
|
|
45
|
+
/**
|
|
46
|
+
* Nav header element pinned at the top of the navigation column.
|
|
47
|
+
* Sits above the navContent and does not scroll. Use for brand/logo.
|
|
48
|
+
*/
|
|
49
|
+
readonly navHeader?: React.ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Footer element rendered at the bottom of the content area.
|
|
52
|
+
* Pinned below the Viewport — does not scroll with content.
|
|
53
|
+
*/
|
|
54
|
+
readonly footer?: React.ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Navigation content element rendered in the navigation column.
|
|
57
|
+
* Typically a Sidebar component with scrollable nav items.
|
|
44
58
|
*/
|
|
45
|
-
readonly
|
|
59
|
+
readonly navContent?: React.ReactNode;
|
|
46
60
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
61
|
+
* Nav footer element pinned at the bottom of the navigation column.
|
|
62
|
+
* Does not scroll. Use for user menu, settings, sign out, etc.
|
|
49
63
|
*/
|
|
50
|
-
readonly
|
|
64
|
+
readonly navFooter?: React.ReactNode;
|
|
51
65
|
/** Test identifier — maps to `data-testid` on web. */
|
|
52
66
|
readonly testID?: string;
|
|
53
67
|
/** DOM id — maps to `id` attribute on web. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Page.types.d.ts","sourceRoot":"","sources":["../../../src/layout/Page/Page.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"Page.types.d.ts","sourceRoot":"","sources":["../../../src/layout/Page/Page.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,SAAS;IACxB,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEpC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAErC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAIrC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE/B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;CAC1C"}
|
package/package.json
CHANGED
|
@@ -55,9 +55,6 @@ export function ContentCard({
|
|
|
55
55
|
<Frame
|
|
56
56
|
elevation={variant === 'elevated' ? 2 : undefined}
|
|
57
57
|
appearance={variant === 'elevated' ? 'tinted' : undefined}
|
|
58
|
-
href={href}
|
|
59
|
-
onPress={onPress}
|
|
60
|
-
disabled={disabled}
|
|
61
58
|
padding={padding}
|
|
62
59
|
gap={gap}
|
|
63
60
|
style={[
|
|
@@ -1,39 +1,21 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
-
import type { ResolvedTokens, AppearanceTokens, ThemeName, AppearanceName } from 'newtone-api';
|
|
3
2
|
|
|
4
3
|
interface SidebarStyleInput {
|
|
5
|
-
readonly tokens: ResolvedTokens;
|
|
6
4
|
readonly width: number;
|
|
7
|
-
readonly bordered: boolean;
|
|
8
|
-
readonly theme?: ThemeName;
|
|
9
|
-
readonly appearance?: AppearanceName;
|
|
10
5
|
}
|
|
11
6
|
|
|
12
|
-
export function getSidebarStyles({
|
|
13
|
-
const at: AppearanceTokens = tokens.colors[theme][appearance];
|
|
14
|
-
const borderColor = at.fontSecondary;
|
|
15
|
-
|
|
7
|
+
export function getSidebarStyles({ width }: SidebarStyleInput) {
|
|
16
8
|
return StyleSheet.create({
|
|
17
9
|
container: {
|
|
18
10
|
width,
|
|
19
11
|
flexShrink: 0,
|
|
20
12
|
flexDirection: 'column',
|
|
21
|
-
backgroundColor: at.background,
|
|
22
|
-
borderRightWidth: bordered ? 1 : 0,
|
|
23
|
-
borderRightColor: borderColor,
|
|
24
|
-
},
|
|
25
|
-
header: {
|
|
26
|
-
flexShrink: 0,
|
|
27
|
-
borderBottomWidth: 1,
|
|
28
|
-
borderBottomColor: borderColor,
|
|
29
13
|
},
|
|
30
14
|
body: {
|
|
31
15
|
flex: 1,
|
|
32
16
|
},
|
|
33
17
|
footer: {
|
|
34
18
|
flexShrink: 0,
|
|
35
|
-
borderTopWidth: 1,
|
|
36
|
-
borderTopColor: borderColor,
|
|
37
19
|
},
|
|
38
20
|
});
|
|
39
21
|
}
|
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { View, ScrollView } from 'react-native';
|
|
2
|
+
import { View, ScrollView, StyleSheet } from 'react-native';
|
|
3
3
|
import type { SidebarProps } from './Sidebar.types';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
const styles = StyleSheet.create({
|
|
6
|
+
container: {
|
|
7
|
+
flex: 1,
|
|
8
|
+
flexDirection: 'column',
|
|
9
|
+
},
|
|
10
|
+
body: {
|
|
11
|
+
flex: 1,
|
|
12
|
+
padding: 8,
|
|
13
|
+
},
|
|
14
|
+
bodyContent: {
|
|
15
|
+
gap: 8,
|
|
16
|
+
},
|
|
17
|
+
footer: {
|
|
18
|
+
flexShrink: 0,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
6
21
|
|
|
7
22
|
export function Sidebar({
|
|
8
23
|
children,
|
|
9
|
-
header,
|
|
10
24
|
footer,
|
|
11
|
-
width = 260,
|
|
12
|
-
bordered = true,
|
|
13
25
|
}: SidebarProps) {
|
|
14
|
-
const tokens = useTokens();
|
|
15
|
-
const frameCtx = useFrameContext();
|
|
16
|
-
const styles = React.useMemo(
|
|
17
|
-
() => getSidebarStyles({ tokens, width, bordered, theme: frameCtx?.theme, appearance: frameCtx?.appearance }),
|
|
18
|
-
[tokens, width, bordered, frameCtx?.theme, frameCtx?.appearance]
|
|
19
|
-
);
|
|
20
|
-
|
|
21
26
|
return (
|
|
22
27
|
<View style={styles.container}>
|
|
23
|
-
|
|
24
|
-
<ScrollView style={styles.body}>{children}</ScrollView>
|
|
28
|
+
<ScrollView style={styles.body} contentContainerStyle={styles.bodyContent}>{children}</ScrollView>
|
|
25
29
|
{footer && <View style={styles.footer}>{footer}</View>}
|
|
26
30
|
</View>
|
|
27
31
|
);
|
|
@@ -3,12 +3,6 @@ import type { ReactNode } from 'react';
|
|
|
3
3
|
export interface SidebarProps {
|
|
4
4
|
/** Scrollable body content (navigation items, etc.) */
|
|
5
5
|
readonly children?: ReactNode;
|
|
6
|
-
/** Sticky header slot (logo, brand) */
|
|
7
|
-
readonly header?: ReactNode;
|
|
8
6
|
/** Sticky footer slot (user menu, settings) */
|
|
9
7
|
readonly footer?: ReactNode;
|
|
10
|
-
/** Fixed width in pixels. @default 260 */
|
|
11
|
-
readonly width?: number;
|
|
12
|
-
/** Show right border. @default true */
|
|
13
|
-
readonly bordered?: boolean;
|
|
14
8
|
}
|
package/src/layout/Page/Page.tsx
CHANGED
|
@@ -1,54 +1,70 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { Platform, View, StyleSheet } from 'react-native';
|
|
3
3
|
import type { PageProps } from './Page.types';
|
|
4
|
-
import { useNewtoneTheme, _ThemeContext } from 'newtone-api';
|
|
4
|
+
import { useNewtoneTheme, _ThemeContext, computeTokens } from 'newtone-api';
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const baseStyles = StyleSheet.create({
|
|
7
7
|
root: {
|
|
8
8
|
flex: 1,
|
|
9
|
+
flexDirection: 'row',
|
|
10
|
+
...(Platform.OS === 'web'
|
|
11
|
+
? { height: '100vh' as unknown as number, overflow: 'hidden' as any }
|
|
12
|
+
: {}),
|
|
13
|
+
},
|
|
14
|
+
navigation: {
|
|
15
|
+
width: 256,
|
|
16
|
+
flexShrink: 0,
|
|
9
17
|
flexDirection: 'column',
|
|
10
|
-
|
|
18
|
+
overflow: 'hidden' as any,
|
|
11
19
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
navHeader: {
|
|
21
|
+
flexShrink: 0,
|
|
22
|
+
height: 64,
|
|
15
23
|
},
|
|
16
24
|
content: {
|
|
17
25
|
flex: 1,
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
overflow: 'hidden' as any,
|
|
28
|
+
},
|
|
29
|
+
header: {
|
|
30
|
+
flexShrink: 0,
|
|
31
|
+
height: 64,
|
|
32
|
+
...(Platform.OS === 'web'
|
|
33
|
+
? { position: 'sticky' as any, top: 0, zIndex: 10 }
|
|
34
|
+
: {}),
|
|
35
|
+
},
|
|
36
|
+
navFooter: {
|
|
37
|
+
flexShrink: 0,
|
|
38
|
+
},
|
|
39
|
+
footer: {
|
|
40
|
+
flexShrink: 0,
|
|
18
41
|
},
|
|
19
42
|
});
|
|
20
43
|
|
|
21
44
|
/**
|
|
22
|
-
* Page — Full-viewport layout root with optional
|
|
45
|
+
* Page — Full-viewport layout root with optional layout slots.
|
|
23
46
|
*
|
|
24
47
|
* Page fills the full screen height and arranges layout regions:
|
|
25
|
-
* -
|
|
26
|
-
* -
|
|
48
|
+
* - NavHeader pinned at the top of the navigation column (brand/logo)
|
|
49
|
+
* - NavContent to the left of the main content (scrollable nav)
|
|
50
|
+
* - NavFooter pinned at the bottom of the navigation column (user menu, sign out)
|
|
51
|
+
* - Header sticky at the top of the content area
|
|
27
52
|
* - Children fill the remaining space (typically a Viewport)
|
|
53
|
+
* - Footer pinned at the bottom of the content area
|
|
28
54
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```tsx
|
|
36
|
-
* <Page navbar={<Nav />}>
|
|
37
|
-
* <Viewport>
|
|
38
|
-
* <Section size="sm" fill>
|
|
39
|
-
* <Frame elevation={1} padding={32}>
|
|
40
|
-
* <Text>Centered content</Text>
|
|
41
|
-
* </Frame>
|
|
42
|
-
* </Section>
|
|
43
|
-
* </Viewport>
|
|
44
|
-
* </Page>
|
|
45
|
-
* ```
|
|
55
|
+
* Panels are separated by 1px gaps that reveal the root background
|
|
56
|
+
* (divider color), rather than borders. The navigation column uses a
|
|
57
|
+
* sunken (elevation -1) background; the content area uses grounded
|
|
58
|
+
* (elevation 0).
|
|
46
59
|
*/
|
|
47
60
|
export function Page({
|
|
48
61
|
children,
|
|
49
62
|
scheme,
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
header,
|
|
64
|
+
navHeader,
|
|
65
|
+
navFooter,
|
|
66
|
+
footer,
|
|
67
|
+
navContent,
|
|
52
68
|
testID,
|
|
53
69
|
nativeID,
|
|
54
70
|
ref,
|
|
@@ -69,6 +85,41 @@ export function Page({
|
|
|
69
85
|
};
|
|
70
86
|
}, [scheme, themeCtx]);
|
|
71
87
|
|
|
88
|
+
const resolvedConfig = schemeThemeCtx?.config ?? themeCtx.config;
|
|
89
|
+
const { mode, gamut } = themeCtx;
|
|
90
|
+
|
|
91
|
+
// Compute tokens at sunken (elevation -1) and grounded (elevation 0)
|
|
92
|
+
// to derive panel backgrounds and the divider gap color.
|
|
93
|
+
const { dividerBg, sunkenBg, groundedBg } = useMemo(() => {
|
|
94
|
+
const groundedTokens = computeTokens(
|
|
95
|
+
resolvedConfig.colorSystem,
|
|
96
|
+
mode,
|
|
97
|
+
gamut,
|
|
98
|
+
'grounded',
|
|
99
|
+
resolvedConfig.spacing,
|
|
100
|
+
resolvedConfig.radius,
|
|
101
|
+
resolvedConfig.typography,
|
|
102
|
+
resolvedConfig.icons,
|
|
103
|
+
resolvedConfig.themeMappings,
|
|
104
|
+
);
|
|
105
|
+
const sunkenTokens = computeTokens(
|
|
106
|
+
resolvedConfig.colorSystem,
|
|
107
|
+
mode,
|
|
108
|
+
gamut,
|
|
109
|
+
'sunken',
|
|
110
|
+
resolvedConfig.spacing,
|
|
111
|
+
resolvedConfig.radius,
|
|
112
|
+
resolvedConfig.typography,
|
|
113
|
+
resolvedConfig.icons,
|
|
114
|
+
resolvedConfig.themeMappings,
|
|
115
|
+
);
|
|
116
|
+
return {
|
|
117
|
+
dividerBg: groundedTokens.colors.primary.main.divider,
|
|
118
|
+
sunkenBg: sunkenTokens.colors.primary.main.background,
|
|
119
|
+
groundedBg: groundedTokens.colors.primary.main.background,
|
|
120
|
+
};
|
|
121
|
+
}, [resolvedConfig, mode, gamut]);
|
|
122
|
+
|
|
72
123
|
const userStyles = Array.isArray(style) ? style : style ? [style] : [];
|
|
73
124
|
|
|
74
125
|
const content = (
|
|
@@ -77,17 +128,40 @@ export function Page({
|
|
|
77
128
|
testID={testID}
|
|
78
129
|
nativeID={nativeID}
|
|
79
130
|
accessibilityRole="none"
|
|
80
|
-
style={[
|
|
131
|
+
style={[baseStyles.root, { backgroundColor: dividerBg, gap: 1 } as any, ...userStyles]}
|
|
81
132
|
>
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
133
|
+
{(navHeader || navContent || navFooter) ? (
|
|
134
|
+
<View style={[baseStyles.navigation, { backgroundColor: dividerBg, gap: 1 } as any]}>
|
|
135
|
+
{navHeader ? (
|
|
136
|
+
<View style={[baseStyles.navHeader, { backgroundColor: sunkenBg }]}>
|
|
137
|
+
{navHeader}
|
|
138
|
+
</View>
|
|
139
|
+
) : null}
|
|
140
|
+
<View style={{ flex: 1, backgroundColor: sunkenBg, overflow: 'hidden' as any }}>
|
|
141
|
+
{navContent}
|
|
142
|
+
</View>
|
|
143
|
+
{navFooter ? (
|
|
144
|
+
<View style={[baseStyles.navFooter, { backgroundColor: sunkenBg }]}>
|
|
145
|
+
{navFooter}
|
|
146
|
+
</View>
|
|
147
|
+
) : null}
|
|
148
|
+
</View>
|
|
149
|
+
) : null}
|
|
150
|
+
<View style={[baseStyles.content, { backgroundColor: dividerBg, gap: 1 } as any]}>
|
|
151
|
+
{header ? (
|
|
152
|
+
<View style={[baseStyles.header, { backgroundColor: groundedBg }]}>
|
|
153
|
+
{header}
|
|
154
|
+
</View>
|
|
155
|
+
) : null}
|
|
156
|
+
<View style={{ flex: 1, backgroundColor: groundedBg, overflow: 'hidden' as any }}>
|
|
157
|
+
{children}
|
|
87
158
|
</View>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
159
|
+
{footer ? (
|
|
160
|
+
<View style={[baseStyles.footer, { backgroundColor: groundedBg }]}>
|
|
161
|
+
{footer}
|
|
162
|
+
</View>
|
|
163
|
+
) : null}
|
|
164
|
+
</View>
|
|
91
165
|
</View>
|
|
92
166
|
);
|
|
93
167
|
|
|
@@ -4,14 +4,13 @@ import type { View, ViewStyle } from 'react-native';
|
|
|
4
4
|
* Props for Page — the outermost layout container for a screen.
|
|
5
5
|
*
|
|
6
6
|
* Page fills the full viewport height and arranges optional layout slots:
|
|
7
|
-
*
|
|
8
|
-
* It can also activate a scheme from
|
|
9
|
-
*
|
|
10
|
-
* Page is invisible — no background, border, or shadow.
|
|
7
|
+
* header (top), navigation column (left with navHeader + navContent),
|
|
8
|
+
* and children (main content area). It can also activate a scheme from
|
|
9
|
+
* the parent NewtoneProvider.
|
|
11
10
|
*
|
|
12
11
|
* @example
|
|
13
12
|
* ```tsx
|
|
14
|
-
* <Page
|
|
13
|
+
* <Page header={<Nav />}>
|
|
15
14
|
* <Viewport>
|
|
16
15
|
* <Section size="md">
|
|
17
16
|
* <Text>Page content</Text>
|
|
@@ -22,7 +21,7 @@ import type { View, ViewStyle } from 'react-native';
|
|
|
22
21
|
*
|
|
23
22
|
* @example
|
|
24
23
|
* ```tsx
|
|
25
|
-
* <Page scheme="vibrant"
|
|
24
|
+
* <Page scheme="vibrant" navContent={<Sidebar />}>
|
|
26
25
|
* <Viewport>
|
|
27
26
|
* <Section size="lg">
|
|
28
27
|
* <Text>Dashboard content</Text>
|
|
@@ -42,16 +41,34 @@ export interface PageProps {
|
|
|
42
41
|
readonly scheme?: string;
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
|
-
*
|
|
46
|
-
* The
|
|
44
|
+
* Header element rendered at the top of the content area (sticky).
|
|
45
|
+
* The header's height is determined by its own content.
|
|
46
|
+
*/
|
|
47
|
+
readonly header?: React.ReactNode;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Nav header element pinned at the top of the navigation column.
|
|
51
|
+
* Sits above the navContent and does not scroll. Use for brand/logo.
|
|
52
|
+
*/
|
|
53
|
+
readonly navHeader?: React.ReactNode;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Footer element rendered at the bottom of the content area.
|
|
57
|
+
* Pinned below the Viewport — does not scroll with content.
|
|
58
|
+
*/
|
|
59
|
+
readonly footer?: React.ReactNode;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Navigation content element rendered in the navigation column.
|
|
63
|
+
* Typically a Sidebar component with scrollable nav items.
|
|
47
64
|
*/
|
|
48
|
-
readonly
|
|
65
|
+
readonly navContent?: React.ReactNode;
|
|
49
66
|
|
|
50
67
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
68
|
+
* Nav footer element pinned at the bottom of the navigation column.
|
|
69
|
+
* Does not scroll. Use for user menu, settings, sign out, etc.
|
|
53
70
|
*/
|
|
54
|
-
readonly
|
|
71
|
+
readonly navFooter?: React.ReactNode;
|
|
55
72
|
|
|
56
73
|
// ── Testing & Platform ──
|
|
57
74
|
|