@newtonedev/components 0.1.17 → 0.1.19
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/actions/Button/Button.d.ts.map +1 -1
- package/dist/composites/actions/Button/Button.styles.d.ts +1 -0
- package/dist/composites/actions/Button/Button.styles.d.ts.map +1 -1
- package/dist/index.cjs +850 -509
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +808 -470
- package/dist/index.js.map +1 -1
- package/dist/layout/Page/Page.d.ts +30 -0
- package/dist/layout/Page/Page.d.ts.map +1 -0
- package/dist/layout/Page/Page.types.d.ts +60 -0
- package/dist/layout/Page/Page.types.d.ts.map +1 -0
- package/dist/layout/Page/index.d.ts +3 -0
- package/dist/layout/Page/index.d.ts.map +1 -0
- package/dist/layout/Section/Section.d.ts +23 -0
- package/dist/layout/Section/Section.d.ts.map +1 -0
- package/dist/layout/Section/Section.styles.d.ts +20 -0
- package/dist/layout/Section/Section.styles.d.ts.map +1 -0
- package/dist/layout/Section/Section.types.d.ts +74 -0
- package/dist/layout/Section/Section.types.d.ts.map +1 -0
- package/dist/layout/Section/index.d.ts +3 -0
- package/dist/layout/Section/index.d.ts.map +1 -0
- package/dist/layout/Viewport/Viewport.d.ts +22 -0
- package/dist/layout/Viewport/Viewport.d.ts.map +1 -0
- package/dist/layout/Viewport/Viewport.types.d.ts +34 -0
- package/dist/layout/Viewport/Viewport.types.d.ts.map +1 -0
- package/dist/layout/Viewport/index.d.ts +3 -0
- package/dist/layout/Viewport/index.d.ts.map +1 -0
- package/dist/{primitives → layout}/Wrapper/Wrapper.d.ts +1 -16
- package/dist/layout/Wrapper/Wrapper.d.ts.map +1 -0
- package/dist/{primitives → layout}/Wrapper/Wrapper.styles.d.ts +1 -2
- package/dist/layout/Wrapper/Wrapper.styles.d.ts.map +1 -0
- package/dist/{primitives → layout}/Wrapper/Wrapper.types.d.ts +1 -3
- package/dist/layout/Wrapper/Wrapper.types.d.ts.map +1 -0
- package/dist/layout/Wrapper/index.d.ts.map +1 -0
- package/dist/layout/index.d.ts +9 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/primitives/Card/Card.d.ts +15 -0
- package/dist/primitives/Card/Card.d.ts.map +1 -0
- package/dist/primitives/Card/Card.styles.d.ts +40 -0
- package/dist/primitives/Card/Card.styles.d.ts.map +1 -0
- package/dist/primitives/Card/Card.types.d.ts +101 -0
- package/dist/primitives/Card/Card.types.d.ts.map +1 -0
- package/dist/primitives/Card/index.d.ts +3 -0
- package/dist/primitives/Card/index.d.ts.map +1 -0
- package/dist/primitives/Frame/Frame.d.ts +1 -1
- package/dist/primitives/Frame/Frame.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.styles.d.ts +0 -6
- package/dist/primitives/Frame/Frame.styles.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.types.d.ts +1 -15
- package/dist/primitives/Frame/Frame.types.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +2 -2
- package/dist/primitives/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/composites/actions/Button/Button.styles.ts +58 -19
- package/src/composites/actions/Button/Button.tsx +18 -3
- package/src/composites/display/Chip/Chip.tsx +1 -1
- package/src/composites/form-controls/TextInput/TextInput.styles.ts +4 -4
- package/src/index.ts +18 -5
- package/src/layout/Page/Page.tsx +103 -0
- package/src/layout/Page/Page.types.ts +69 -0
- package/src/layout/Page/index.ts +2 -0
- package/src/layout/Section/Section.styles.ts +90 -0
- package/src/layout/Section/Section.tsx +57 -0
- package/src/layout/Section/Section.types.ts +85 -0
- package/src/layout/Section/index.ts +2 -0
- package/src/layout/Viewport/Viewport.tsx +52 -0
- package/src/layout/Viewport/Viewport.types.ts +40 -0
- package/src/layout/Viewport/index.ts +2 -0
- package/src/{primitives → layout}/Wrapper/Wrapper.styles.ts +2 -20
- package/src/{primitives → layout}/Wrapper/Wrapper.tsx +1 -31
- package/src/{primitives → layout}/Wrapper/Wrapper.types.ts +1 -4
- package/src/layout/index.ts +15 -0
- package/src/primitives/Card/Card.styles.ts +182 -0
- package/src/primitives/Card/Card.tsx +197 -0
- package/src/primitives/Card/Card.types.ts +155 -0
- package/src/primitives/Card/index.ts +2 -0
- package/src/primitives/Frame/Frame.styles.ts +0 -32
- package/src/primitives/Frame/Frame.tsx +5 -52
- package/src/primitives/Frame/Frame.types.ts +1 -22
- package/src/primitives/Text/Text.tsx +1 -1
- package/src/primitives/index.ts +3 -3
- package/dist/primitives/Wrapper/Wrapper.d.ts.map +0 -1
- package/dist/primitives/Wrapper/Wrapper.styles.d.ts.map +0 -1
- package/dist/primitives/Wrapper/Wrapper.types.d.ts.map +0 -1
- package/dist/primitives/Wrapper/index.d.ts.map +0 -1
- /package/dist/{primitives → layout}/Wrapper/index.d.ts +0 -0
- /package/src/{primitives → layout}/Wrapper/index.ts +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import type { SectionProps } from './Section.types';
|
|
4
|
+
import { getSectionStyles } from './Section.styles';
|
|
5
|
+
import { useTokens } from 'newtone-api';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Section — Full-width layout container that constrains content width.
|
|
9
|
+
*
|
|
10
|
+
* Section fills all available horizontal space and centers its content
|
|
11
|
+
* within a maximum width determined by the `size` preset. It provides
|
|
12
|
+
* horizontal padding so content doesn't touch the viewport edges when
|
|
13
|
+
* the screen is narrower than the max width.
|
|
14
|
+
*
|
|
15
|
+
* Section is invisible — no background, border, or shadow. It is purely
|
|
16
|
+
* a layout tool for structuring page-level content regions.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <Section size="md" gap={24} padding={{ y: 48 }}>
|
|
21
|
+
* <Text role="heading">Documentation</Text>
|
|
22
|
+
* <Text role="body">Content constrained to 768px max width.</Text>
|
|
23
|
+
* </Section>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function Section({
|
|
27
|
+
children,
|
|
28
|
+
size,
|
|
29
|
+
fill,
|
|
30
|
+
gap,
|
|
31
|
+
padding,
|
|
32
|
+
testID,
|
|
33
|
+
nativeID,
|
|
34
|
+
ref,
|
|
35
|
+
style,
|
|
36
|
+
}: SectionProps) {
|
|
37
|
+
const tokens = useTokens();
|
|
38
|
+
|
|
39
|
+
const containerStyle = useMemo(
|
|
40
|
+
() => getSectionStyles({ tokens, size, fill, gap, padding }),
|
|
41
|
+
[tokens, size, fill, gap, padding],
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const userStyles = Array.isArray(style) ? style : style ? [style] : [];
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<View
|
|
48
|
+
ref={ref}
|
|
49
|
+
testID={testID}
|
|
50
|
+
nativeID={nativeID}
|
|
51
|
+
accessibilityRole="none"
|
|
52
|
+
style={[containerStyle, ...userStyles]}
|
|
53
|
+
>
|
|
54
|
+
{children}
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { View, ViewStyle } from 'react-native';
|
|
2
|
+
import type { GapProp, PaddingProp } from '../../primitives/Frame/Frame.types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Content width preset for Section.
|
|
6
|
+
*
|
|
7
|
+
* | Size | Max Width | Horizontal Padding |
|
|
8
|
+
* |:------:|:---------:|:------------------:|
|
|
9
|
+
* | `'xs'` | 480px | 24px |
|
|
10
|
+
* | `'sm'` | 640px | 24px |
|
|
11
|
+
* | `'md'` | 768px | 24px |
|
|
12
|
+
* | `'lg'` | 1024px | 32px |
|
|
13
|
+
* | `'xl'` | 1280px | 40px |
|
|
14
|
+
* | `'full'` | none | 0px |
|
|
15
|
+
*/
|
|
16
|
+
export type SectionSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for Section — a full-width layout container that constrains content width.
|
|
20
|
+
*
|
|
21
|
+
* Section fills all available horizontal space and centers its content
|
|
22
|
+
* within a maximum width. It provides horizontal padding so content
|
|
23
|
+
* doesn't touch the edges when the viewport is narrower than the max width.
|
|
24
|
+
*
|
|
25
|
+
* Section is invisible — no background, border, or shadow.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <Section size="md" gap={24}>
|
|
30
|
+
* <Text role="heading">Page Title</Text>
|
|
31
|
+
* <Text role="body">Content constrained to 768px.</Text>
|
|
32
|
+
* </Section>
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <Section size="full">
|
|
38
|
+
* <HeroImage />
|
|
39
|
+
* </Section>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export interface SectionProps {
|
|
43
|
+
/** Child elements. */
|
|
44
|
+
readonly children?: React.ReactNode;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Content width preset. Controls the maximum width and default horizontal padding.
|
|
48
|
+
*
|
|
49
|
+
* @default 'lg'
|
|
50
|
+
*/
|
|
51
|
+
readonly size?: SectionSize;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Gap between children.
|
|
55
|
+
*/
|
|
56
|
+
readonly gap?: GapProp;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* When true, the Section expands to fill all available vertical space (`flex: 1`).
|
|
60
|
+
* Useful inside a Viewport when content is shorter than the screen.
|
|
61
|
+
*
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
readonly fill?: boolean;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Vertical padding (top and bottom).
|
|
68
|
+
* Horizontal padding is determined by the size preset.
|
|
69
|
+
*/
|
|
70
|
+
readonly padding?: PaddingProp;
|
|
71
|
+
|
|
72
|
+
// ── Testing & Platform ──
|
|
73
|
+
|
|
74
|
+
/** Test identifier — maps to `data-testid` on web. */
|
|
75
|
+
readonly testID?: string;
|
|
76
|
+
|
|
77
|
+
/** DOM id — maps to `id` attribute on web. */
|
|
78
|
+
readonly nativeID?: string;
|
|
79
|
+
|
|
80
|
+
/** Ref to the underlying View element. */
|
|
81
|
+
readonly ref?: React.Ref<View>;
|
|
82
|
+
|
|
83
|
+
/** Custom style overrides (applied last). */
|
|
84
|
+
readonly style?: ViewStyle | ViewStyle[];
|
|
85
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ScrollView, StyleSheet } from 'react-native';
|
|
3
|
+
import type { ViewportProps } from './Viewport.types';
|
|
4
|
+
|
|
5
|
+
const styles = StyleSheet.create({
|
|
6
|
+
root: {
|
|
7
|
+
flex: 1,
|
|
8
|
+
},
|
|
9
|
+
content: {
|
|
10
|
+
flexGrow: 1,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Viewport — Full-height scrollable layout root.
|
|
16
|
+
*
|
|
17
|
+
* Viewport fills all available height (`flex: 1`) and scrolls vertically
|
|
18
|
+
* when content overflows. It stacks children in a column.
|
|
19
|
+
*
|
|
20
|
+
* Viewport is invisible — no background, border, or shadow. It is purely
|
|
21
|
+
* a layout tool for structuring the outermost page container.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <Viewport>
|
|
26
|
+
* <Section size="lg" padding={{ y: 48 }}>
|
|
27
|
+
* <Text role="heading">Welcome</Text>
|
|
28
|
+
* </Section>
|
|
29
|
+
* </Viewport>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function Viewport({
|
|
33
|
+
children,
|
|
34
|
+
testID,
|
|
35
|
+
nativeID,
|
|
36
|
+
ref,
|
|
37
|
+
style,
|
|
38
|
+
}: ViewportProps) {
|
|
39
|
+
const userStyles = Array.isArray(style) ? style : style ? [style] : [];
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<ScrollView
|
|
43
|
+
ref={ref}
|
|
44
|
+
testID={testID}
|
|
45
|
+
nativeID={nativeID}
|
|
46
|
+
style={styles.root}
|
|
47
|
+
contentContainerStyle={[styles.content, ...userStyles]}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</ScrollView>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ScrollView, ViewStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for Viewport — a full-height scrollable layout root.
|
|
5
|
+
*
|
|
6
|
+
* Viewport fills all available height and scrolls vertically when its
|
|
7
|
+
* content overflows. It stacks children in a column and provides no
|
|
8
|
+
* visual styling — no background, border, or shadow.
|
|
9
|
+
*
|
|
10
|
+
* Use Viewport as the outermost layout container for a page or screen.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <Viewport>
|
|
15
|
+
* <Section size="sm" fill>
|
|
16
|
+
* <Frame elevation={1}>
|
|
17
|
+
* <Text>Centered content</Text>
|
|
18
|
+
* </Frame>
|
|
19
|
+
* </Section>
|
|
20
|
+
* </Viewport>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export interface ViewportProps {
|
|
24
|
+
/** Child elements (typically Sections). */
|
|
25
|
+
readonly children?: React.ReactNode;
|
|
26
|
+
|
|
27
|
+
// ── Testing & Platform ──
|
|
28
|
+
|
|
29
|
+
/** Test identifier — maps to `data-testid` on web. */
|
|
30
|
+
readonly testID?: string;
|
|
31
|
+
|
|
32
|
+
/** DOM id — maps to `id` attribute on web. */
|
|
33
|
+
readonly nativeID?: string;
|
|
34
|
+
|
|
35
|
+
/** Ref to the underlying ScrollView element. */
|
|
36
|
+
readonly ref?: React.Ref<ScrollView>;
|
|
37
|
+
|
|
38
|
+
/** Custom style overrides applied to the scroll content container. */
|
|
39
|
+
readonly style?: ViewStyle | ViewStyle[];
|
|
40
|
+
}
|
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
PositionType,
|
|
12
12
|
OffsetValue,
|
|
13
13
|
OverflowMode,
|
|
14
|
-
} from '
|
|
14
|
+
} from '../../primitives/Frame/Frame.types';
|
|
15
15
|
import {
|
|
16
16
|
resolvePadding,
|
|
17
17
|
resolveGap,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resolveFlexDirection,
|
|
20
20
|
resolveAlignment,
|
|
21
21
|
resolveJustification,
|
|
22
|
-
} from '
|
|
22
|
+
} from '../../primitives/Frame/Frame.utils';
|
|
23
23
|
|
|
24
24
|
export interface WrapperStyleInput {
|
|
25
25
|
readonly tokens: ResolvedTokens;
|
|
@@ -45,7 +45,6 @@ export interface WrapperStyleInput {
|
|
|
45
45
|
readonly left?: OffsetValue;
|
|
46
46
|
readonly zIndex?: number;
|
|
47
47
|
readonly overflow?: OverflowMode;
|
|
48
|
-
readonly opacity?: number;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -78,28 +77,19 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
78
77
|
left,
|
|
79
78
|
zIndex,
|
|
80
79
|
overflow,
|
|
81
|
-
opacity,
|
|
82
80
|
} = input;
|
|
83
81
|
|
|
84
|
-
// We build styles as a plain object first, then validate it through
|
|
85
|
-
// StyleSheet.create() at the end. Using Record<string, unknown> allows us
|
|
86
|
-
// to set properties conditionally without TypeScript complaining.
|
|
87
82
|
const container: Record<string, unknown> = {};
|
|
88
83
|
|
|
89
84
|
// ── Layout ──
|
|
90
|
-
// Set whether children are arranged in a row or column (and optionally reversed).
|
|
91
85
|
container.flexDirection = resolveFlexDirection(direction, reverse);
|
|
92
|
-
// Allow children to flow onto multiple lines when they don't fit in one.
|
|
93
86
|
if (wrap) container.flexWrap = 'wrap';
|
|
94
87
|
|
|
95
88
|
// ── Alignment ──
|
|
96
|
-
// Cross-axis: how children are positioned perpendicular to the main direction.
|
|
97
89
|
if (align) container.alignItems = resolveAlignment(align);
|
|
98
|
-
// Main-axis: how children are distributed along the main direction.
|
|
99
90
|
if (justify) container.justifyContent = resolveJustification(justify);
|
|
100
91
|
|
|
101
92
|
// ── Padding ──
|
|
102
|
-
// Convert spacing tokens (like 'md') or pixel values into actual padding.
|
|
103
93
|
if (padding !== undefined) {
|
|
104
94
|
const p = resolvePadding(padding, tokens);
|
|
105
95
|
container.paddingTop = p.top;
|
|
@@ -109,7 +99,6 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
// ── Gap ──
|
|
112
|
-
// Space between children (row gap for vertical stacks, column gap for horizontal).
|
|
113
102
|
if (gap !== undefined) {
|
|
114
103
|
const g = resolveGap(gap, tokens);
|
|
115
104
|
container.rowGap = g.rowGap;
|
|
@@ -117,19 +106,15 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
117
106
|
}
|
|
118
107
|
|
|
119
108
|
// ── Sizing ──
|
|
120
|
-
// Merge width/height settings into the container.
|
|
121
|
-
// 'hug' = shrink to fit content, 'fill' = expand to fill parent, number = fixed pixels.
|
|
122
109
|
Object.assign(container, resolveSizing(width, height));
|
|
123
110
|
|
|
124
111
|
// ── Constraints ──
|
|
125
|
-
// Set min/max boundaries for width and height.
|
|
126
112
|
if (minWidth !== undefined) container.minWidth = minWidth;
|
|
127
113
|
if (maxWidth !== undefined) container.maxWidth = maxWidth;
|
|
128
114
|
if (minHeight !== undefined) container.minHeight = minHeight;
|
|
129
115
|
if (maxHeight !== undefined) container.maxHeight = maxHeight;
|
|
130
116
|
|
|
131
117
|
// ── Positioning ──
|
|
132
|
-
// Set CSS position mode and offsets for absolute/fixed/sticky positioning.
|
|
133
118
|
if (position) container.position = position;
|
|
134
119
|
if (top !== undefined) container.top = top;
|
|
135
120
|
if (right !== undefined) container.right = right;
|
|
@@ -137,9 +122,6 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
137
122
|
if (left !== undefined) container.left = left;
|
|
138
123
|
if (zIndex !== undefined) container.zIndex = zIndex;
|
|
139
124
|
if (overflow) container.overflow = overflow;
|
|
140
|
-
if (opacity !== undefined) container.opacity = opacity;
|
|
141
125
|
|
|
142
|
-
// Pass through StyleSheet.create() to validate and optimize the styles,
|
|
143
|
-
// then extract the single style object with `.c`.
|
|
144
126
|
return StyleSheet.create({ c: container as ViewStyle }).c;
|
|
145
127
|
}
|
|
@@ -13,21 +13,6 @@ import { useTokens } from 'newtone-api';
|
|
|
13
13
|
*
|
|
14
14
|
* Use Wrapper for structural layout. Use Frame when you need visual
|
|
15
15
|
* appearance or theme/elevation context.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* <Wrapper direction="horizontal" gap="md" align="center">
|
|
20
|
-
* <Button onPress={() => {}}>Save</Button>
|
|
21
|
-
* <Button variant="tertiary" onPress={() => {}}>Cancel</Button>
|
|
22
|
-
* </Wrapper>
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```tsx
|
|
27
|
-
* <Wrapper padding={{ x: 'lg', y: 'md' }} gap="sm">
|
|
28
|
-
* <Text>Spaced content with no background</Text>
|
|
29
|
-
* </Wrapper>
|
|
30
|
-
* ```
|
|
31
16
|
*/
|
|
32
17
|
export function Wrapper({
|
|
33
18
|
children,
|
|
@@ -44,7 +29,6 @@ export function Wrapper({
|
|
|
44
29
|
maxWidth,
|
|
45
30
|
minHeight,
|
|
46
31
|
maxHeight,
|
|
47
|
-
// Positioning
|
|
48
32
|
position,
|
|
49
33
|
top,
|
|
50
34
|
right,
|
|
@@ -53,20 +37,13 @@ export function Wrapper({
|
|
|
53
37
|
zIndex,
|
|
54
38
|
overflow,
|
|
55
39
|
pointerEvents,
|
|
56
|
-
opacity,
|
|
57
40
|
style,
|
|
58
|
-
// Testing & platform
|
|
59
41
|
testID,
|
|
60
42
|
nativeID,
|
|
61
43
|
ref,
|
|
62
44
|
}: WrapperProps) {
|
|
63
|
-
// Get the theme's design tokens so we can convert spacing names (like 'md')
|
|
64
|
-
// into pixel values. Wrapper inherits elevation from FrameContext automatically.
|
|
65
45
|
const tokens = useTokens();
|
|
66
46
|
|
|
67
|
-
// Calculate the layout styles (direction, spacing, alignment, sizing).
|
|
68
|
-
// Wrapped in useMemo so it only recalculates when one of the props changes,
|
|
69
|
-
// instead of running on every render.
|
|
70
47
|
const containerStyle = useMemo(
|
|
71
48
|
() => getWrapperStyles({
|
|
72
49
|
tokens,
|
|
@@ -90,30 +67,23 @@ export function Wrapper({
|
|
|
90
67
|
left,
|
|
91
68
|
zIndex,
|
|
92
69
|
overflow,
|
|
93
|
-
opacity,
|
|
94
70
|
}),
|
|
95
71
|
[
|
|
96
72
|
tokens, direction, wrap, reverse,
|
|
97
73
|
align, justify, padding, gap,
|
|
98
74
|
width, height, minWidth, maxWidth, minHeight, maxHeight,
|
|
99
|
-
position, top, right, bottom, left, zIndex, overflow,
|
|
75
|
+
position, top, right, bottom, left, zIndex, overflow,
|
|
100
76
|
],
|
|
101
77
|
);
|
|
102
78
|
|
|
103
|
-
// Normalize user's custom styles into an array so we can merge them.
|
|
104
|
-
// The user can pass a single style object or an array of style objects.
|
|
105
79
|
const userStyles = Array.isArray(style) ? style : style ? [style] : [];
|
|
106
80
|
|
|
107
|
-
// Render a plain View — no background, no border, no interactivity.
|
|
108
|
-
// User's custom styles are applied last so they can override layout defaults.
|
|
109
81
|
return (
|
|
110
82
|
<View
|
|
111
83
|
ref={ref}
|
|
112
84
|
testID={testID}
|
|
113
85
|
nativeID={nativeID}
|
|
114
86
|
pointerEvents={pointerEvents}
|
|
115
|
-
// Wrapper is a layout-only container with no semantic meaning.
|
|
116
|
-
// "none" tells screen readers to skip this element and read its children directly.
|
|
117
87
|
accessibilityRole="none"
|
|
118
88
|
style={[containerStyle, ...userStyles]}
|
|
119
89
|
>
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
OffsetValue,
|
|
11
11
|
OverflowMode,
|
|
12
12
|
PointerEventsMode,
|
|
13
|
-
} from '
|
|
13
|
+
} from '../../primitives/Frame/Frame.types';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Props for Wrapper — a lightweight, invisible layout container.
|
|
@@ -173,9 +173,6 @@ export interface WrapperProps {
|
|
|
173
173
|
*/
|
|
174
174
|
readonly pointerEvents?: PointerEventsMode;
|
|
175
175
|
|
|
176
|
-
/** Opacity of the element (0 = fully transparent, 1 = fully opaque). */
|
|
177
|
-
readonly opacity?: number;
|
|
178
|
-
|
|
179
176
|
// ── Testing & Platform ──
|
|
180
177
|
|
|
181
178
|
/** Test identifier — maps to `data-testid` on web. Used by testing libraries. */
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Page
|
|
2
|
+
export { Page } from './Page';
|
|
3
|
+
export type { PageProps } from './Page';
|
|
4
|
+
|
|
5
|
+
// Viewport
|
|
6
|
+
export { Viewport } from './Viewport';
|
|
7
|
+
export type { ViewportProps } from './Viewport';
|
|
8
|
+
|
|
9
|
+
// Wrapper
|
|
10
|
+
export { Wrapper } from './Wrapper';
|
|
11
|
+
export type { WrapperProps } from './Wrapper';
|
|
12
|
+
|
|
13
|
+
// Section
|
|
14
|
+
export { Section } from './Section';
|
|
15
|
+
export type { SectionProps, SectionSize } from './Section';
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { ViewStyle } from 'react-native';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import type { ResolvedTokens, AppearanceTokens } from 'newtone-api';
|
|
4
|
+
import type { ThemeName, AppearanceName } from 'newtone-api';
|
|
5
|
+
import type {
|
|
6
|
+
PaddingProp,
|
|
7
|
+
GapProp,
|
|
8
|
+
SizingMode,
|
|
9
|
+
Direction,
|
|
10
|
+
Alignment,
|
|
11
|
+
Justification,
|
|
12
|
+
RadiusProp,
|
|
13
|
+
} from '../Frame/Frame.types';
|
|
14
|
+
import {
|
|
15
|
+
resolvePadding,
|
|
16
|
+
resolveGap,
|
|
17
|
+
resolveSizing,
|
|
18
|
+
resolveFlexDirection,
|
|
19
|
+
resolveAlignment,
|
|
20
|
+
resolveJustification,
|
|
21
|
+
resolveRadiusCorners,
|
|
22
|
+
hasPositiveRadius,
|
|
23
|
+
} from '../Frame/Frame.utils';
|
|
24
|
+
|
|
25
|
+
// ── Input ────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
export interface CardStyleInput {
|
|
28
|
+
readonly tokens: ResolvedTokens;
|
|
29
|
+
|
|
30
|
+
// Theme / Appearance (theme is inherited, not user-supplied)
|
|
31
|
+
readonly theme: ThemeName;
|
|
32
|
+
readonly appearance?: AppearanceName;
|
|
33
|
+
|
|
34
|
+
// Layout
|
|
35
|
+
readonly direction?: Direction;
|
|
36
|
+
readonly wrap?: boolean;
|
|
37
|
+
readonly reverse?: boolean;
|
|
38
|
+
|
|
39
|
+
// Alignment
|
|
40
|
+
readonly align?: Alignment;
|
|
41
|
+
readonly justify?: Justification;
|
|
42
|
+
|
|
43
|
+
// Spacing
|
|
44
|
+
readonly padding?: PaddingProp;
|
|
45
|
+
readonly gap?: GapProp;
|
|
46
|
+
|
|
47
|
+
// Sizing
|
|
48
|
+
readonly width?: SizingMode;
|
|
49
|
+
readonly height?: SizingMode;
|
|
50
|
+
readonly minWidth?: number;
|
|
51
|
+
readonly maxWidth?: number;
|
|
52
|
+
readonly minHeight?: number;
|
|
53
|
+
readonly maxHeight?: number;
|
|
54
|
+
|
|
55
|
+
// Appearance
|
|
56
|
+
readonly radius?: RadiusProp;
|
|
57
|
+
|
|
58
|
+
// Interactivity
|
|
59
|
+
readonly disabled?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── Output ───────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
export interface CardStyles {
|
|
65
|
+
/** Main container style */
|
|
66
|
+
readonly container: ViewStyle;
|
|
67
|
+
/** Style applied when pressed (background shift) */
|
|
68
|
+
readonly pressed: ViewStyle;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── Builder ──────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build all visual styles for a Card.
|
|
75
|
+
*
|
|
76
|
+
* Cards are always elevated with a border and drop shadow.
|
|
77
|
+
* Takes the Card's props + design tokens and produces:
|
|
78
|
+
* - container: the main style (background, border, shadow, layout, spacing, etc.)
|
|
79
|
+
* - pressed: style override applied when the user is pressing
|
|
80
|
+
*/
|
|
81
|
+
export function getCardStyles(input: CardStyleInput): CardStyles {
|
|
82
|
+
const {
|
|
83
|
+
tokens,
|
|
84
|
+
theme,
|
|
85
|
+
appearance = 'main',
|
|
86
|
+
direction = 'vertical',
|
|
87
|
+
wrap = false,
|
|
88
|
+
reverse = false,
|
|
89
|
+
align,
|
|
90
|
+
justify,
|
|
91
|
+
padding,
|
|
92
|
+
gap,
|
|
93
|
+
width,
|
|
94
|
+
height,
|
|
95
|
+
minWidth,
|
|
96
|
+
maxWidth,
|
|
97
|
+
minHeight,
|
|
98
|
+
maxHeight,
|
|
99
|
+
radius,
|
|
100
|
+
disabled = false,
|
|
101
|
+
} = input;
|
|
102
|
+
|
|
103
|
+
const container: Record<string, unknown> = {};
|
|
104
|
+
|
|
105
|
+
// ── Background & foreground ──
|
|
106
|
+
const appearanceTokens: AppearanceTokens = tokens.colors[theme][appearance];
|
|
107
|
+
container.backgroundColor = appearanceTokens.background;
|
|
108
|
+
container.color = appearanceTokens.fontPrimary;
|
|
109
|
+
|
|
110
|
+
// ── Layout ──
|
|
111
|
+
container.display = 'flex';
|
|
112
|
+
container.flexDirection = resolveFlexDirection(direction, reverse);
|
|
113
|
+
if (wrap) container.flexWrap = 'wrap';
|
|
114
|
+
|
|
115
|
+
// ── Alignment ──
|
|
116
|
+
if (align) container.alignItems = resolveAlignment(align);
|
|
117
|
+
if (justify) container.justifyContent = resolveJustification(justify);
|
|
118
|
+
|
|
119
|
+
// ── Padding ──
|
|
120
|
+
if (padding !== undefined) {
|
|
121
|
+
const p = resolvePadding(padding, tokens);
|
|
122
|
+
container.paddingTop = p.top;
|
|
123
|
+
container.paddingRight = p.right;
|
|
124
|
+
container.paddingBottom = p.bottom;
|
|
125
|
+
container.paddingLeft = p.left;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── Gap ──
|
|
129
|
+
if (gap !== undefined) {
|
|
130
|
+
const g = resolveGap(gap, tokens);
|
|
131
|
+
container.rowGap = g.rowGap;
|
|
132
|
+
container.columnGap = g.columnGap;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── Sizing ──
|
|
136
|
+
Object.assign(container, resolveSizing(width, height));
|
|
137
|
+
|
|
138
|
+
// ── Constraints ──
|
|
139
|
+
if (minWidth !== undefined) container.minWidth = minWidth;
|
|
140
|
+
if (maxWidth !== undefined) container.maxWidth = maxWidth;
|
|
141
|
+
if (minHeight !== undefined) container.minHeight = minHeight;
|
|
142
|
+
if (maxHeight !== undefined) container.maxHeight = maxHeight;
|
|
143
|
+
|
|
144
|
+
// ── Radius ──
|
|
145
|
+
if (radius !== undefined) {
|
|
146
|
+
const corners = resolveRadiusCorners(radius, tokens);
|
|
147
|
+
container.borderTopLeftRadius = corners.topLeft;
|
|
148
|
+
container.borderTopRightRadius = corners.topRight;
|
|
149
|
+
container.borderBottomLeftRadius = corners.bottomLeft;
|
|
150
|
+
container.borderBottomRightRadius = corners.bottomRight;
|
|
151
|
+
|
|
152
|
+
if (hasPositiveRadius(corners)) {
|
|
153
|
+
container.overflow = 'hidden';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Border (always on) ──
|
|
158
|
+
container.borderWidth = 1;
|
|
159
|
+
container.borderColor = appearanceTokens.divider;
|
|
160
|
+
|
|
161
|
+
// ── Shadow (always elevated) ──
|
|
162
|
+
container.shadowColor = '#000';
|
|
163
|
+
container.shadowOffset = { width: 0, height: 2 };
|
|
164
|
+
container.shadowOpacity = 0.12;
|
|
165
|
+
container.shadowRadius = 6;
|
|
166
|
+
container.elevation = 4; // Android-specific shadow depth
|
|
167
|
+
|
|
168
|
+
// ── Disabled ──
|
|
169
|
+
if (disabled) {
|
|
170
|
+
container.opacity = 0.5;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── Pressed state ──
|
|
174
|
+
const pressed = StyleSheet.create({
|
|
175
|
+
s: { backgroundColor: appearanceTokens.fontSecondary },
|
|
176
|
+
}).s;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
container: StyleSheet.create({ c: container as ViewStyle }).c,
|
|
180
|
+
pressed,
|
|
181
|
+
};
|
|
182
|
+
}
|