@newtonedev/components 0.1.12 → 0.1.14
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/_COMPONENT_TEMPLATE/ComponentName.styles.d.ts +4 -3
- package/dist/_COMPONENT_TEMPLATE/ComponentName.styles.d.ts.map +1 -1
- package/dist/_COMPONENT_TEMPLATE/ComponentName.types.d.ts +1 -1
- package/dist/_COMPONENT_TEMPLATE/ComponentName.types.d.ts.map +1 -1
- package/dist/composites/actions/Button/Button.d.ts +11 -1
- package/dist/composites/actions/Button/Button.d.ts.map +1 -1
- package/dist/composites/actions/Button/Button.styles.d.ts +1 -1
- package/dist/composites/actions/Button/Button.styles.d.ts.map +1 -1
- package/dist/composites/actions/Button/Button.types.d.ts +11 -1
- package/dist/composites/actions/Button/Button.types.d.ts.map +1 -1
- package/dist/composites/branding/LogoMonogram/LogoMonogram.d.ts +10 -0
- package/dist/composites/branding/LogoMonogram/LogoMonogram.d.ts.map +1 -0
- package/dist/composites/branding/LogoMonogram/LogoMonogram.types.d.ts +35 -0
- package/dist/composites/branding/LogoMonogram/LogoMonogram.types.d.ts.map +1 -0
- package/dist/composites/branding/LogoMonogram/index.d.ts +3 -0
- package/dist/composites/branding/LogoMonogram/index.d.ts.map +1 -0
- package/dist/composites/branding/LogoWordmark/LogoWordmark.d.ts +9 -0
- package/dist/composites/branding/LogoWordmark/LogoWordmark.d.ts.map +1 -0
- package/dist/composites/branding/LogoWordmark/LogoWordmark.types.d.ts +26 -0
- package/dist/composites/branding/LogoWordmark/LogoWordmark.types.d.ts.map +1 -0
- package/dist/composites/branding/LogoWordmark/index.d.ts +3 -0
- package/dist/composites/branding/LogoWordmark/index.d.ts.map +1 -0
- package/dist/composites/display/Chip/Chip.d.ts +25 -0
- package/dist/composites/display/Chip/Chip.d.ts.map +1 -0
- package/dist/composites/display/Chip/Chip.styles.d.ts +29 -0
- package/dist/composites/display/Chip/Chip.styles.d.ts.map +1 -0
- package/dist/composites/display/Chip/Chip.types.d.ts +63 -0
- package/dist/composites/display/Chip/Chip.types.d.ts.map +1 -0
- package/dist/composites/display/Chip/index.d.ts +3 -0
- package/dist/composites/display/Chip/index.d.ts.map +1 -0
- package/dist/composites/form-controls/Select/Select.d.ts.map +1 -1
- package/dist/composites/form-controls/Select/Select.styles.d.ts +2 -2
- package/dist/composites/form-controls/Select/Select.styles.d.ts.map +1 -1
- package/dist/composites/form-controls/Select/SelectOption.d.ts.map +1 -1
- package/dist/composites/form-controls/TextInput/TextInput.d.ts.map +1 -1
- package/dist/composites/form-controls/TextInput/TextInput.styles.d.ts +2 -2
- package/dist/composites/form-controls/TextInput/TextInput.styles.d.ts.map +1 -1
- package/dist/composites/form-controls/Toggle/Toggle.d.ts.map +1 -1
- package/dist/composites/form-controls/Toggle/Toggle.styles.d.ts +2 -2
- package/dist/composites/form-controls/Toggle/Toggle.styles.d.ts.map +1 -1
- package/dist/composites/layout/AppShell/AppShell.d.ts.map +1 -1
- package/dist/composites/layout/AppShell/AppShell.styles.d.ts +2 -2
- package/dist/composites/layout/AppShell/AppShell.styles.d.ts.map +1 -1
- package/dist/composites/layout/Card/Card.d.ts.map +1 -1
- package/dist/composites/layout/Card/Card.styles.d.ts +2 -2
- package/dist/composites/layout/Card/Card.styles.d.ts.map +1 -1
- package/dist/composites/layout/Card/Card.types.d.ts +1 -1
- package/dist/composites/layout/Card/Card.types.d.ts.map +1 -1
- package/dist/composites/layout/ContentCard/ContentCard.d.ts +33 -0
- package/dist/composites/layout/ContentCard/ContentCard.d.ts.map +1 -0
- package/dist/composites/layout/ContentCard/ContentCard.styles.d.ts +10 -0
- package/dist/composites/layout/ContentCard/ContentCard.styles.d.ts.map +1 -0
- package/dist/composites/layout/ContentCard/ContentCard.types.d.ts +52 -0
- package/dist/composites/layout/ContentCard/ContentCard.types.d.ts.map +1 -0
- package/dist/composites/layout/ContentCard/index.d.ts +3 -0
- package/dist/composites/layout/ContentCard/index.d.ts.map +1 -0
- package/dist/composites/layout/Divider/Divider.d.ts +25 -0
- package/dist/composites/layout/Divider/Divider.d.ts.map +1 -0
- package/dist/composites/layout/Divider/Divider.styles.d.ts +8 -0
- package/dist/composites/layout/Divider/Divider.styles.d.ts.map +1 -0
- package/dist/composites/layout/Divider/Divider.types.d.ts +25 -0
- package/dist/composites/layout/Divider/Divider.types.d.ts.map +1 -0
- package/dist/composites/layout/Divider/index.d.ts +3 -0
- package/dist/composites/layout/Divider/index.d.ts.map +1 -0
- package/dist/composites/layout/Navbar/Navbar.d.ts.map +1 -1
- package/dist/composites/layout/Navbar/Navbar.styles.d.ts +4 -2
- package/dist/composites/layout/Navbar/Navbar.styles.d.ts.map +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.d.ts.map +1 -1
- package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts +4 -2
- package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts.map +1 -1
- package/dist/composites/overlays/Popover/Popover.d.ts.map +1 -1
- package/dist/composites/overlays/Popover/Popover.styles.d.ts +2 -2
- package/dist/composites/overlays/Popover/Popover.styles.d.ts.map +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.d.ts +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.d.ts.map +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts.map +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.d.ts +2 -0
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.d.ts.map +1 -1
- package/dist/composites/range-inputs/HueSlider/HueSlider.d.ts +3 -4
- package/dist/composites/range-inputs/HueSlider/HueSlider.d.ts.map +1 -1
- package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts +3 -3
- package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts.map +1 -1
- package/dist/composites/range-inputs/Slider/Slider.styles.d.ts +1 -1
- package/dist/composites/range-inputs/Slider/Slider.styles.d.ts.map +1 -1
- package/dist/index.cjs +1609 -1693
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +22 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1454 -1621
- package/dist/index.js.map +1 -1
- package/dist/primitives/Frame/Frame.d.ts +1 -35
- package/dist/primitives/Frame/Frame.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.styles.d.ts +13 -3
- package/dist/primitives/Frame/Frame.styles.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.types.d.ts +99 -1
- package/dist/primitives/Frame/Frame.types.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.utils.d.ts +1 -1
- package/dist/primitives/Frame/Frame.utils.d.ts.map +1 -1
- package/dist/primitives/Frame/index.d.ts +1 -1
- package/dist/primitives/Frame/index.d.ts.map +1 -1
- package/dist/primitives/Icon/Icon.d.ts.map +1 -1
- package/dist/primitives/Icon/Icon.types.d.ts +2 -2
- package/dist/primitives/Icon/Icon.types.d.ts.map +1 -1
- package/dist/primitives/Text/Text.d.ts +6 -4
- package/dist/primitives/Text/Text.d.ts.map +1 -1
- package/dist/primitives/Text/Text.spans.d.ts.map +1 -1
- package/dist/primitives/Text/Text.types.d.ts +4 -7
- package/dist/primitives/Text/Text.types.d.ts.map +1 -1
- package/dist/primitives/Wrapper/Wrapper.d.ts +1 -1
- package/dist/primitives/Wrapper/Wrapper.d.ts.map +1 -1
- package/dist/primitives/Wrapper/Wrapper.styles.d.ts +10 -2
- package/dist/primitives/Wrapper/Wrapper.styles.d.ts.map +1 -1
- package/dist/primitives/Wrapper/Wrapper.types.d.ts +31 -1
- package/dist/primitives/Wrapper/Wrapper.types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/_COMPONENT_TEMPLATE/ComponentName.styles.ts +4 -4
- package/src/_COMPONENT_TEMPLATE/ComponentName.tsx +2 -2
- package/src/_COMPONENT_TEMPLATE/ComponentName.types.ts +1 -1
- package/src/composites/actions/Button/Button.styles.ts +72 -55
- package/src/composites/actions/Button/Button.tsx +35 -14
- package/src/composites/actions/Button/Button.types.ts +13 -1
- package/src/composites/branding/LogoMonogram/LogoMonogram.tsx +29 -0
- package/src/composites/branding/LogoMonogram/LogoMonogram.types.ts +35 -0
- package/src/composites/branding/LogoMonogram/index.ts +2 -0
- package/src/composites/branding/LogoWordmark/LogoWordmark.tsx +29 -0
- package/src/composites/branding/LogoWordmark/LogoWordmark.types.ts +25 -0
- package/src/composites/branding/LogoWordmark/index.ts +2 -0
- package/src/composites/display/Chip/Chip.styles.ts +189 -0
- package/src/composites/display/Chip/Chip.tsx +97 -0
- package/src/composites/display/Chip/Chip.types.ts +74 -0
- package/src/composites/display/Chip/index.ts +2 -0
- package/src/composites/form-controls/Select/Select.styles.ts +10 -10
- package/src/composites/form-controls/Select/Select.tsx +9 -7
- package/src/composites/form-controls/Select/SelectOption.tsx +10 -8
- package/src/composites/form-controls/TextInput/TextInput.styles.ts +12 -9
- package/src/composites/form-controls/TextInput/TextInput.tsx +7 -5
- package/src/composites/form-controls/Toggle/Toggle.styles.ts +10 -7
- package/src/composites/form-controls/Toggle/Toggle.tsx +4 -3
- package/src/composites/layout/AppShell/AppShell.styles.ts +8 -4
- package/src/composites/layout/AppShell/AppShell.tsx +6 -2
- package/src/composites/layout/Card/Card.styles.ts +10 -5
- package/src/composites/layout/Card/Card.tsx +4 -3
- package/src/composites/layout/Card/Card.types.ts +1 -1
- package/src/composites/layout/ContentCard/ContentCard.styles.ts +44 -0
- package/src/composites/layout/ContentCard/ContentCard.tsx +71 -0
- package/src/composites/layout/ContentCard/ContentCard.types.ts +60 -0
- package/src/composites/layout/ContentCard/index.ts +2 -0
- package/src/composites/layout/Divider/Divider.styles.ts +30 -0
- package/src/composites/layout/Divider/Divider.tsx +46 -0
- package/src/composites/layout/Divider/Divider.types.ts +28 -0
- package/src/composites/layout/Divider/index.ts +2 -0
- package/src/composites/layout/Navbar/Navbar.styles.ts +7 -5
- package/src/composites/layout/Navbar/Navbar.tsx +4 -3
- package/src/composites/layout/Sidebar/Sidebar.styles.ts +7 -5
- package/src/composites/layout/Sidebar/Sidebar.tsx +4 -3
- package/src/composites/overlays/Popover/Popover.styles.ts +7 -5
- package/src/composites/overlays/Popover/Popover.tsx +4 -3
- package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.ts +4 -5
- package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.tsx +6 -2
- package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.ts +2 -0
- package/src/composites/range-inputs/HueSlider/HueSlider.styles.ts +13 -20
- package/src/composites/range-inputs/HueSlider/HueSlider.tsx +7 -8
- package/src/composites/range-inputs/Slider/Slider.styles.ts +8 -9
- package/src/composites/range-inputs/Slider/Slider.tsx +1 -1
- package/src/index.ts +108 -61
- package/src/primitives/Frame/Frame.styles.ts +55 -11
- package/src/primitives/Frame/Frame.tsx +140 -142
- package/src/primitives/Frame/Frame.types.ts +119 -1
- package/src/primitives/Frame/Frame.utils.ts +1 -1
- package/src/primitives/Frame/index.ts +4 -0
- package/src/primitives/Icon/Icon.tsx +9 -7
- package/src/primitives/Icon/Icon.types.ts +2 -2
- package/src/primitives/Text/Text.spans.ts +9 -5
- package/src/primitives/Text/Text.tsx +33 -22
- package/src/primitives/Text/Text.types.ts +4 -7
- package/src/primitives/Wrapper/Wrapper.styles.ts +33 -1
- package/src/primitives/Wrapper/Wrapper.tsx +23 -4
- package/src/primitives/Wrapper/Wrapper.types.ts +45 -0
- package/dist/fonts/GoogleFontLoader.d.ts +0 -20
- package/dist/fonts/GoogleFontLoader.d.ts.map +0 -1
- package/dist/fonts/IconFontLoader.d.ts +0 -13
- package/dist/fonts/IconFontLoader.d.ts.map +0 -1
- package/dist/fonts/SelfHostedFontLoader.d.ts +0 -14
- package/dist/fonts/SelfHostedFontLoader.d.ts.map +0 -1
- package/dist/fonts/buildGoogleFontsUrl.d.ts +0 -2
- package/dist/fonts/buildGoogleFontsUrl.d.ts.map +0 -1
- package/dist/fonts/measureFont.d.ts +0 -19
- package/dist/fonts/measureFont.d.ts.map +0 -1
- package/dist/fonts/reportQueue.d.ts +0 -7
- package/dist/fonts/reportQueue.d.ts.map +0 -1
- package/dist/fonts/useLocalCalibration.d.ts +0 -19
- package/dist/fonts/useLocalCalibration.d.ts.map +0 -1
- package/dist/fonts/useTypographyCalibrations.d.ts +0 -11
- package/dist/fonts/useTypographyCalibrations.d.ts.map +0 -1
- package/dist/theme/FrameContext.d.ts +0 -26
- package/dist/theme/FrameContext.d.ts.map +0 -1
- package/dist/theme/NewtoneProvider.d.ts +0 -40
- package/dist/theme/NewtoneProvider.d.ts.map +0 -1
- package/dist/theme/defaults.d.ts +0 -8
- package/dist/theme/defaults.d.ts.map +0 -1
- package/dist/theme/types.d.ts +0 -156
- package/dist/theme/types.d.ts.map +0 -1
- package/dist/theme/useBreakpoint.d.ts +0 -9
- package/dist/theme/useBreakpoint.d.ts.map +0 -1
- package/dist/tokens/computeTokens.d.ts +0 -151
- package/dist/tokens/computeTokens.d.ts.map +0 -1
- package/dist/tokens/types.d.ts +0 -162
- package/dist/tokens/types.d.ts.map +0 -1
- package/dist/tokens/useTokens.d.ts +0 -26
- package/dist/tokens/useTokens.d.ts.map +0 -1
- package/src/fonts/GoogleFontLoader.tsx +0 -80
- package/src/fonts/IconFontLoader.tsx +0 -51
- package/src/fonts/SelfHostedFontLoader.tsx +0 -44
- package/src/fonts/buildGoogleFontsUrl.ts +0 -2
- package/src/fonts/measureFont.ts +0 -55
- package/src/fonts/reportQueue.ts +0 -54
- package/src/fonts/useLocalCalibration.ts +0 -97
- package/src/fonts/useTypographyCalibrations.ts +0 -15
- package/src/theme/FrameContext.tsx +0 -31
- package/src/theme/NewtoneProvider.tsx +0 -84
- package/src/theme/defaults.ts +0 -71
- package/src/theme/types.ts +0 -191
- package/src/theme/useBreakpoint.ts +0 -14
- package/src/tokens/computeTokens.ts +0 -516
- package/src/tokens/types.ts +0 -146
- package/src/tokens/useTokens.ts +0 -62
|
@@ -2,20 +2,15 @@ import React, { useMemo } from 'react';
|
|
|
2
2
|
import { View, Pressable, Text } from 'react-native';
|
|
3
3
|
import type { ViewStyle, TextStyle } from 'react-native';
|
|
4
4
|
import type { FrameProps } from './Frame.types';
|
|
5
|
-
import type { ElevationLevel, FrameElevation } from '
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { computeTokens } from '../../tokens/computeTokens';
|
|
5
|
+
import type { ElevationLevel, FrameElevation, ElevationName, ThemeName, AppearanceName } from 'newtone-api';
|
|
6
|
+
import { FrameContext, useFrameContext } from 'newtone-api';
|
|
7
|
+
import { useNewtoneTheme, _ThemeContext } from 'newtone-api';
|
|
8
|
+
import { computeTokens } from 'newtone-api';
|
|
10
9
|
import { getFrameStyles } from './Frame.styles';
|
|
11
10
|
import { useFocusVisible } from '../useFocusVisible';
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Wrap raw string/number children in <Text> so they display correctly.
|
|
15
|
-
*
|
|
16
|
-
* In React Native, raw text like <View>"hello"</View> will crash on native
|
|
17
|
-
* and show console warnings on web. All text must be inside a <Text> element.
|
|
18
|
-
* This helper scans children and auto-wraps any bare strings or numbers.
|
|
19
14
|
*/
|
|
20
15
|
function wrapTextChildren(
|
|
21
16
|
children: React.ReactNode,
|
|
@@ -29,16 +24,15 @@ function wrapTextChildren(
|
|
|
29
24
|
});
|
|
30
25
|
}
|
|
31
26
|
|
|
27
|
+
/** Map numeric elevation levels to named elevations for the swatches layer. */
|
|
28
|
+
const ELEVATION_MAP: Record<ElevationLevel, ElevationName> = {
|
|
29
|
+
0: 'sunken',
|
|
30
|
+
1: 'grounded',
|
|
31
|
+
2: 'elevated',
|
|
32
|
+
};
|
|
33
|
+
|
|
32
34
|
/**
|
|
33
35
|
* Convert user-facing FrameElevation (-2..2) to internal ElevationLevel (0..2).
|
|
34
|
-
*
|
|
35
|
-
* | Frame | Internal | Background |
|
|
36
|
-
* |:-----:|:--------:|:-----------|
|
|
37
|
-
* | -2 | 0 | Sunken |
|
|
38
|
-
* | -1 | 0 | Sunken |
|
|
39
|
-
* | 0 | 1 | Default |
|
|
40
|
-
* | 1 | 2 | Elevated |
|
|
41
|
-
* | 2 | 2 | Elevated |
|
|
42
36
|
*/
|
|
43
37
|
function toElevationLevel(frameElevation: FrameElevation): ElevationLevel {
|
|
44
38
|
if (frameElevation <= -1) return 0;
|
|
@@ -54,45 +48,16 @@ function toElevationLevel(frameElevation: FrameElevation): ElevationLevel {
|
|
|
54
48
|
* and interactivity capabilities.
|
|
55
49
|
*
|
|
56
50
|
* Frames can be nested. Inner frames override outer frames for their subtree.
|
|
57
|
-
* Unspecified props inherit from the nearest parent Frame.
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```tsx
|
|
61
|
-
* // Basic layout
|
|
62
|
-
* <Frame direction="horizontal" gap="md" padding="lg" align="center">
|
|
63
|
-
* <Button onPress={() => {}}>Save</Button>
|
|
64
|
-
* <Button variant="tertiary" onPress={() => {}}>Cancel</Button>
|
|
65
|
-
* </Frame>
|
|
66
|
-
* ```
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* ```tsx
|
|
70
|
-
* // Card-like frame
|
|
71
|
-
* <Frame
|
|
72
|
-
* elevation={2}
|
|
73
|
-
* radius="lg"
|
|
74
|
-
* padding="xl"
|
|
75
|
-
* bordered
|
|
76
|
-
* onPress={() => navigate('/details')}
|
|
77
|
-
* >
|
|
78
|
-
* <Text>Clickable card</Text>
|
|
79
|
-
* </Frame>
|
|
80
|
-
* ```
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```tsx
|
|
84
|
-
* // Grid layout (web)
|
|
85
|
-
* <Frame layout="grid" columns={3} gap="md" padding="lg">
|
|
86
|
-
* <Frame radius="md" padding="md" bordered>Cell 1</Frame>
|
|
87
|
-
* <Frame radius="md" padding="md" bordered>Cell 2</Frame>
|
|
88
|
-
* <Frame radius="md" padding="md" bordered>Cell 3</Frame>
|
|
89
|
-
* </Frame>
|
|
90
|
-
* ```
|
|
91
51
|
*/
|
|
92
52
|
export function Frame({
|
|
93
53
|
children,
|
|
94
54
|
// Elevation
|
|
95
55
|
elevation,
|
|
56
|
+
// Scheme
|
|
57
|
+
scheme,
|
|
58
|
+
// Theme / Appearance
|
|
59
|
+
theme,
|
|
60
|
+
appearance,
|
|
96
61
|
// Layout
|
|
97
62
|
layout,
|
|
98
63
|
direction,
|
|
@@ -113,6 +78,16 @@ export function Frame({
|
|
|
113
78
|
maxWidth,
|
|
114
79
|
minHeight,
|
|
115
80
|
maxHeight,
|
|
81
|
+
// Positioning
|
|
82
|
+
position,
|
|
83
|
+
top,
|
|
84
|
+
right,
|
|
85
|
+
bottom,
|
|
86
|
+
left,
|
|
87
|
+
zIndex,
|
|
88
|
+
overflow,
|
|
89
|
+
pointerEvents,
|
|
90
|
+
opacity,
|
|
116
91
|
// Appearance
|
|
117
92
|
radius,
|
|
118
93
|
bordered,
|
|
@@ -130,44 +105,54 @@ export function Frame({
|
|
|
130
105
|
// Style override
|
|
131
106
|
style,
|
|
132
107
|
}: FrameProps) {
|
|
133
|
-
|
|
134
|
-
const {
|
|
135
|
-
// Read the elevation from the nearest parent Frame (if nested).
|
|
108
|
+
const themeCtx = useNewtoneTheme();
|
|
109
|
+
const { mode, gamut } = themeCtx;
|
|
136
110
|
const parentFrameCtx = useFrameContext();
|
|
137
111
|
|
|
138
|
-
//
|
|
112
|
+
// Resolve which config to use: explicit scheme > inherited from parent > default.
|
|
113
|
+
const resolvedConfig = useMemo(() => {
|
|
114
|
+
if (scheme && themeCtx.schemes) {
|
|
115
|
+
const schemeConfig = themeCtx.schemes[scheme];
|
|
116
|
+
if (schemeConfig) return schemeConfig;
|
|
117
|
+
}
|
|
118
|
+
return themeCtx.config;
|
|
119
|
+
}, [scheme, themeCtx.schemes, themeCtx.config]);
|
|
120
|
+
|
|
121
|
+
// Track whether this Frame switches the scheme (needs theme context override).
|
|
122
|
+
const isSchemeOverride = resolvedConfig !== themeCtx.config;
|
|
123
|
+
|
|
124
|
+
// Resolve theme/appearance: explicit prop > parent Frame > defaults.
|
|
125
|
+
const resolvedTheme: ThemeName = theme ?? parentFrameCtx?.theme ?? 'primary';
|
|
126
|
+
const resolvedAppearance: AppearanceName = appearance ?? parentFrameCtx?.appearance ?? 'main';
|
|
127
|
+
|
|
139
128
|
const resolvedFrameElevation: FrameElevation = elevation ?? 0;
|
|
140
129
|
|
|
141
|
-
// Convert user-facing elevation to internal level (0-2) for token computation.
|
|
142
|
-
// When no elevation is set, inherit from parent Frame or default to 1.
|
|
143
130
|
const resolvedElevation: ElevationLevel = elevation !== undefined
|
|
144
131
|
? toElevationLevel(elevation)
|
|
145
132
|
: parentFrameCtx?.elevation ?? 1;
|
|
146
133
|
|
|
147
|
-
//
|
|
148
|
-
// Frame computes its own tokens instead of using useTokens() because
|
|
149
|
-
// useTokens() reads from FrameContext — but this Frame IS the provider,
|
|
150
|
-
// so it needs to compute fresh tokens from the resolved theme/elevation.
|
|
151
|
-
// Wrapped in useMemo so it only recalculates when the theme/mode/elevation changes.
|
|
134
|
+
// Compute tokens with gamut pre-applied (no [gamut] indexing needed downstream).
|
|
152
135
|
const tokens = useMemo(() => {
|
|
153
136
|
return computeTokens(
|
|
154
|
-
|
|
137
|
+
resolvedConfig.colorSystem,
|
|
155
138
|
mode,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
139
|
+
gamut,
|
|
140
|
+
ELEVATION_MAP[resolvedElevation],
|
|
141
|
+
resolvedConfig.spacing,
|
|
142
|
+
resolvedConfig.radius,
|
|
143
|
+
resolvedConfig.typography,
|
|
144
|
+
resolvedConfig.icons,
|
|
145
|
+
resolvedConfig.themeMappings,
|
|
146
|
+
resolvedConfig.swatchDefaults,
|
|
162
147
|
);
|
|
163
|
-
}, [
|
|
148
|
+
}, [resolvedConfig, mode, gamut, resolvedElevation]);
|
|
164
149
|
|
|
165
|
-
// Calculate all visual styles (background, layout, border, shadow, etc.).
|
|
166
|
-
// Only recalculates when one of the style-related props changes.
|
|
167
150
|
const styles = useMemo(
|
|
168
151
|
() => getFrameStyles({
|
|
169
152
|
tokens,
|
|
170
153
|
frameElevation: resolvedFrameElevation,
|
|
154
|
+
theme: resolvedTheme,
|
|
155
|
+
appearance: resolvedAppearance,
|
|
171
156
|
layout,
|
|
172
157
|
direction,
|
|
173
158
|
wrap,
|
|
@@ -184,29 +169,53 @@ export function Frame({
|
|
|
184
169
|
maxWidth,
|
|
185
170
|
minHeight,
|
|
186
171
|
maxHeight,
|
|
172
|
+
position,
|
|
173
|
+
top,
|
|
174
|
+
right,
|
|
175
|
+
bottom,
|
|
176
|
+
left,
|
|
177
|
+
zIndex,
|
|
178
|
+
overflow,
|
|
179
|
+
opacity,
|
|
187
180
|
radius,
|
|
188
181
|
bordered,
|
|
189
182
|
disabled,
|
|
190
183
|
}),
|
|
191
184
|
[
|
|
192
|
-
tokens, resolvedFrameElevation,
|
|
185
|
+
tokens, resolvedFrameElevation, resolvedTheme, resolvedAppearance,
|
|
193
186
|
layout, direction, wrap, reverse, columns, rows,
|
|
194
187
|
align, justify, padding, gap,
|
|
195
188
|
width, height, minWidth, maxWidth, minHeight, maxHeight,
|
|
189
|
+
position, top, right, bottom, left, zIndex, overflow, opacity,
|
|
196
190
|
radius, bordered, disabled,
|
|
197
191
|
],
|
|
198
192
|
);
|
|
199
193
|
|
|
200
|
-
//
|
|
201
|
-
|
|
194
|
+
// Resolved scheme name: explicit prop > inherited from parent Frame.
|
|
195
|
+
const resolvedScheme = scheme ?? parentFrameCtx?.scheme;
|
|
196
|
+
|
|
202
197
|
const contextValue = useMemo(
|
|
203
|
-
() => ({
|
|
204
|
-
|
|
198
|
+
() => ({
|
|
199
|
+
elevation: resolvedElevation,
|
|
200
|
+
tokens,
|
|
201
|
+
scheme: resolvedScheme,
|
|
202
|
+
theme: resolvedTheme,
|
|
203
|
+
appearance: resolvedAppearance,
|
|
204
|
+
}),
|
|
205
|
+
[resolvedElevation, tokens, resolvedScheme, resolvedTheme, resolvedAppearance],
|
|
205
206
|
);
|
|
206
207
|
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
|
|
208
|
+
// When this Frame switches the scheme, override ThemeContext so that
|
|
209
|
+
// useNewtoneTheme().config returns the scheme's config for descendants.
|
|
210
|
+
const schemeThemeCtx = useMemo(() => {
|
|
211
|
+
if (!isSchemeOverride) return null;
|
|
212
|
+
return {
|
|
213
|
+
...themeCtx,
|
|
214
|
+
config: resolvedConfig,
|
|
215
|
+
activeScheme: scheme ?? themeCtx.activeScheme,
|
|
216
|
+
};
|
|
217
|
+
}, [isSchemeOverride, themeCtx, resolvedConfig, scheme]);
|
|
218
|
+
|
|
210
219
|
const webOverrides: ViewStyle[] = [];
|
|
211
220
|
if (styles.gridWebStyle) {
|
|
212
221
|
webOverrides.push(styles.gridWebStyle as unknown as ViewStyle);
|
|
@@ -215,94 +224,83 @@ export function Frame({
|
|
|
215
224
|
webOverrides.push({ boxShadow: styles.insetBoxShadow } as unknown as ViewStyle);
|
|
216
225
|
}
|
|
217
226
|
|
|
218
|
-
// Normalize user's custom styles into an array for merging.
|
|
219
227
|
const userStyles = Array.isArray(style) ? style : style ? [style] : [];
|
|
220
228
|
|
|
221
|
-
|
|
222
|
-
// In that case we render a Pressable (tappable); otherwise a plain View.
|
|
229
|
+
|
|
223
230
|
const isInteractive = onPress !== undefined || href !== undefined;
|
|
224
231
|
|
|
225
|
-
// Detect keyboard-only focus (Tab, arrows) vs mouse/touch focus.
|
|
226
|
-
// Only shows a visible focus ring when the user navigated via keyboard,
|
|
227
|
-
// matching the browser's native :focus-visible behavior.
|
|
228
232
|
const { isFocusVisible, focusProps } = useFocusVisible();
|
|
229
233
|
|
|
230
|
-
// Focus ring
|
|
231
|
-
// offset by 2px so it doesn't overlap the Frame's border.
|
|
232
|
-
// Uses CSS outline properties — silently ignored on native platforms.
|
|
234
|
+
// Focus ring: uses the emphasis background of the resolved theme as the outline color.
|
|
233
235
|
const focusRingStyle = isFocusVisible && !disabled ? {
|
|
234
236
|
outlineWidth: 2,
|
|
235
237
|
outlineStyle: 'solid',
|
|
236
|
-
outlineColor:
|
|
238
|
+
outlineColor: tokens.colors[resolvedTheme].emphasis.background,
|
|
237
239
|
outlineOffset: 2,
|
|
238
|
-
} as unknown as ViewStyle : undefined;
|
|
240
|
+
} as unknown as ViewStyle : undefined;
|
|
239
241
|
|
|
240
|
-
|
|
241
|
-
// handlers supported by react-native-web — silently ignored on native.
|
|
242
|
-
const webFocusProps = isInteractive ? focusProps as any : {}; // web-only
|
|
242
|
+
const webFocusProps = isInteractive ? focusProps as any : {};
|
|
243
243
|
|
|
244
|
-
// Default text style for any raw strings/numbers passed as children.
|
|
245
|
-
// Uses the theme's primary text color, default font, and base size.
|
|
246
244
|
const textStyle = useMemo<TextStyle>(
|
|
247
245
|
() => ({
|
|
248
|
-
color:
|
|
246
|
+
color: tokens.colors[resolvedTheme][resolvedAppearance].fontPrimary,
|
|
249
247
|
fontSize: tokens.typography.fontSizes['05'],
|
|
250
248
|
fontFamily: tokens.typography.fonts.main.family,
|
|
251
249
|
lineHeight: tokens.typography.lineHeights['06'],
|
|
252
250
|
}),
|
|
253
|
-
[tokens],
|
|
251
|
+
[tokens, resolvedTheme, resolvedAppearance],
|
|
254
252
|
);
|
|
255
|
-
// Auto-wrap bare text ("hello") in <Text> elements (required by React Native).
|
|
256
|
-
// Wrapped in useMemo so it only re-scans children when they or the text style changes.
|
|
257
253
|
const wrappedChildren = useMemo(
|
|
258
254
|
() => wrapTextChildren(children, textStyle),
|
|
259
255
|
[children, textStyle],
|
|
260
256
|
);
|
|
261
257
|
|
|
262
|
-
|
|
263
|
-
|
|
258
|
+
const content = isInteractive ? (
|
|
259
|
+
<Pressable
|
|
260
|
+
ref={ref}
|
|
261
|
+
testID={testID}
|
|
262
|
+
nativeID={nativeID}
|
|
263
|
+
pointerEvents={pointerEvents}
|
|
264
|
+
accessibilityLabel={accessibilityLabel}
|
|
265
|
+
accessibilityHint={accessibilityHint}
|
|
266
|
+
accessibilityState={disabled ? { disabled: true } : undefined}
|
|
267
|
+
onPress={onPress}
|
|
268
|
+
disabled={disabled}
|
|
269
|
+
{...(href ? { href, accessibilityRole: 'link' as const } : { accessibilityRole: 'button' as const })}
|
|
270
|
+
{...webFocusProps}
|
|
271
|
+
style={({ pressed }) => [
|
|
272
|
+
styles.container,
|
|
273
|
+
pressed && !disabled && styles.pressed,
|
|
274
|
+
focusRingStyle,
|
|
275
|
+
...webOverrides,
|
|
276
|
+
...userStyles,
|
|
277
|
+
]}
|
|
278
|
+
>
|
|
279
|
+
{wrappedChildren}
|
|
280
|
+
</Pressable>
|
|
281
|
+
) : (
|
|
282
|
+
<View
|
|
283
|
+
ref={ref}
|
|
284
|
+
testID={testID}
|
|
285
|
+
nativeID={nativeID}
|
|
286
|
+
pointerEvents={pointerEvents}
|
|
287
|
+
accessibilityLabel={accessibilityLabel}
|
|
288
|
+
accessibilityHint={accessibilityHint}
|
|
289
|
+
style={[styles.container, ...webOverrides, ...userStyles]}
|
|
290
|
+
>
|
|
291
|
+
{wrappedChildren}
|
|
292
|
+
</View>
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const wrappedContent = schemeThemeCtx ? (
|
|
296
|
+
<_ThemeContext.Provider value={schemeThemeCtx}>
|
|
297
|
+
{content}
|
|
298
|
+
</_ThemeContext.Provider>
|
|
299
|
+
) : content;
|
|
300
|
+
|
|
264
301
|
return (
|
|
265
302
|
<FrameContext.Provider value={contextValue}>
|
|
266
|
-
{
|
|
267
|
-
// Pressable handles taps. When href is set, react-native-web renders
|
|
268
|
-
// it as an <a> tag so it works like a regular link on the web.
|
|
269
|
-
<Pressable
|
|
270
|
-
ref={ref}
|
|
271
|
-
testID={testID}
|
|
272
|
-
nativeID={nativeID}
|
|
273
|
-
accessibilityLabel={accessibilityLabel}
|
|
274
|
-
accessibilityHint={accessibilityHint}
|
|
275
|
-
// Tell screen readers this is disabled so assistive technology can announce it.
|
|
276
|
-
accessibilityState={disabled ? { disabled: true } : undefined}
|
|
277
|
-
onPress={onPress}
|
|
278
|
-
disabled={disabled}
|
|
279
|
-
{...(href ? { href, accessibilityRole: 'link' as const } : { accessibilityRole: 'button' as const })}
|
|
280
|
-
{...webFocusProps}
|
|
281
|
-
// The style callback receives { pressed: true/false } so we can
|
|
282
|
-
// change the background when the user is actively pressing.
|
|
283
|
-
style={({ pressed }) => [
|
|
284
|
-
styles.container,
|
|
285
|
-
pressed && !disabled && styles.pressed,
|
|
286
|
-
focusRingStyle,
|
|
287
|
-
...webOverrides,
|
|
288
|
-
...userStyles,
|
|
289
|
-
]}
|
|
290
|
-
>
|
|
291
|
-
{wrappedChildren}
|
|
292
|
-
</Pressable>
|
|
293
|
-
) : (
|
|
294
|
-
// Non-interactive Frame: just a plain View with no tap handling.
|
|
295
|
-
<View
|
|
296
|
-
ref={ref}
|
|
297
|
-
testID={testID}
|
|
298
|
-
nativeID={nativeID}
|
|
299
|
-
accessibilityLabel={accessibilityLabel}
|
|
300
|
-
accessibilityHint={accessibilityHint}
|
|
301
|
-
style={[styles.container, ...webOverrides, ...userStyles]}
|
|
302
|
-
>
|
|
303
|
-
{wrappedChildren}
|
|
304
|
-
</View>
|
|
305
|
-
)}
|
|
303
|
+
{wrappedContent}
|
|
306
304
|
</FrameContext.Provider>
|
|
307
305
|
);
|
|
308
306
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { View, ViewStyle, GestureResponderEvent } from 'react-native';
|
|
2
|
-
import type { FrameElevation } from '
|
|
2
|
+
import type { FrameElevation, ThemeName, AppearanceName } from 'newtone-api';
|
|
3
3
|
|
|
4
4
|
// ── Spacing Types ──────────────────────────────────────────────
|
|
5
5
|
|
|
@@ -76,6 +76,20 @@ export interface RadiusCorners {
|
|
|
76
76
|
*/
|
|
77
77
|
export type RadiusProp = RadiusValue | RadiusCorners;
|
|
78
78
|
|
|
79
|
+
// ── Positioning Types ──────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/** CSS position mode. `'fixed'` and `'sticky'` are web-only (via react-native-web). */
|
|
82
|
+
export type PositionType = 'absolute' | 'relative' | 'fixed' | 'sticky';
|
|
83
|
+
|
|
84
|
+
/** Position offset value: pixels (number) or percentage string (e.g. `'50%'`). */
|
|
85
|
+
export type OffsetValue = number | string;
|
|
86
|
+
|
|
87
|
+
/** Overflow clipping mode. */
|
|
88
|
+
export type OverflowMode = 'visible' | 'hidden' | 'scroll';
|
|
89
|
+
|
|
90
|
+
/** Pointer-events mode (View prop, not a style). */
|
|
91
|
+
export type PointerEventsMode = 'auto' | 'none' | 'box-none' | 'box-only';
|
|
92
|
+
|
|
79
93
|
// ── Sizing Types ───────────────────────────────────────────────
|
|
80
94
|
|
|
81
95
|
/**
|
|
@@ -159,6 +173,23 @@ export interface FrameProps {
|
|
|
159
173
|
*/
|
|
160
174
|
readonly elevation?: FrameElevation;
|
|
161
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Named scheme to use for this Frame's subtree.
|
|
178
|
+
* Looks up the scheme's config from the ancestor NewtoneProvider's `schemes` map
|
|
179
|
+
* and uses it instead of the default for token computation and context.
|
|
180
|
+
* Ignored when the provider is in single-config mode.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```tsx
|
|
184
|
+
* <NewtoneProvider schemes={{ Default: config1, Dark: config2 }} defaultScheme="Default">
|
|
185
|
+
* <Frame scheme="Dark">
|
|
186
|
+
* {/* Children here get the "Dark" scheme's tokens */}
|
|
187
|
+
* </Frame>
|
|
188
|
+
* </NewtoneProvider>
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
readonly scheme?: string;
|
|
192
|
+
|
|
162
193
|
// ── Layout ──
|
|
163
194
|
|
|
164
195
|
/** Layout mode. @default 'flex' */
|
|
@@ -248,8 +279,95 @@ export interface FrameProps {
|
|
|
248
279
|
/** Maximum height in pixels. */
|
|
249
280
|
readonly maxHeight?: number;
|
|
250
281
|
|
|
282
|
+
// ── Positioning ──
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* CSS position mode.
|
|
286
|
+
*
|
|
287
|
+
* `'fixed'` and `'sticky'` are web-only (supported via react-native-web).
|
|
288
|
+
* React Native natively supports `'absolute'` and `'relative'`.
|
|
289
|
+
*/
|
|
290
|
+
readonly position?: PositionType;
|
|
291
|
+
|
|
292
|
+
/** Offset from the top edge. Accepts pixels (number) or percentage string. */
|
|
293
|
+
readonly top?: OffsetValue;
|
|
294
|
+
|
|
295
|
+
/** Offset from the right edge. Accepts pixels (number) or percentage string. */
|
|
296
|
+
readonly right?: OffsetValue;
|
|
297
|
+
|
|
298
|
+
/** Offset from the bottom edge. Accepts pixels (number) or percentage string. */
|
|
299
|
+
readonly bottom?: OffsetValue;
|
|
300
|
+
|
|
301
|
+
/** Offset from the left edge. Accepts pixels (number) or percentage string. */
|
|
302
|
+
readonly left?: OffsetValue;
|
|
303
|
+
|
|
304
|
+
/** Stacking order. Higher values render above lower values. */
|
|
305
|
+
readonly zIndex?: number;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Content overflow behavior.
|
|
309
|
+
*
|
|
310
|
+
* When `radius` is set with positive values, Frame auto-applies `overflow: 'hidden'`
|
|
311
|
+
* to clip content at rounded corners. Setting `overflow` explicitly overrides this.
|
|
312
|
+
*/
|
|
313
|
+
readonly overflow?: OverflowMode;
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Controls whether the element can be the target of touch/pointer events.
|
|
317
|
+
*
|
|
318
|
+
* - `'auto'` — default, element and children receive events
|
|
319
|
+
* - `'none'` — element and children are invisible to events (pass through)
|
|
320
|
+
* - `'box-none'` — element ignores events but children can receive them
|
|
321
|
+
* - `'box-only'` — element receives events but children cannot
|
|
322
|
+
*/
|
|
323
|
+
readonly pointerEvents?: PointerEventsMode;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Opacity of the element (0 = fully transparent, 1 = fully opaque).
|
|
327
|
+
*
|
|
328
|
+
* When set explicitly, overrides the automatic `0.5` opacity applied by `disabled`.
|
|
329
|
+
*/
|
|
330
|
+
readonly opacity?: number;
|
|
331
|
+
|
|
251
332
|
// ── Appearance ──
|
|
252
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Color theme for this Frame's visual rendering (background, border, text).
|
|
336
|
+
*
|
|
337
|
+
* Selects which of the 6 themes to use from the resolved tokens.
|
|
338
|
+
* Does not affect scheme selection — use `scheme` for that.
|
|
339
|
+
*
|
|
340
|
+
* @default 'primary'
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```tsx
|
|
344
|
+
* <Frame theme="error" appearance="tinted">
|
|
345
|
+
* <Text>Error banner</Text>
|
|
346
|
+
* </Frame>
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
readonly theme?: ThemeName;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Appearance variant within the selected theme.
|
|
353
|
+
*
|
|
354
|
+
* Controls the visual emphasis of the Frame's chrome (background, border):
|
|
355
|
+
* - `'main'` — default surface (passive contrast)
|
|
356
|
+
* - `'emphasis'` — prominent, filled surface (active contrast)
|
|
357
|
+
* - `'tinted'` — subtle tinted surface
|
|
358
|
+
* - `'strong'` — bold, high-contrast variant
|
|
359
|
+
*
|
|
360
|
+
* @default 'main'
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```tsx
|
|
364
|
+
* <Frame theme="primary" appearance="emphasis">
|
|
365
|
+
* <Text>CTA section</Text>
|
|
366
|
+
* </Frame>
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
readonly appearance?: AppearanceName;
|
|
370
|
+
|
|
253
371
|
/**
|
|
254
372
|
* Border radius.
|
|
255
373
|
*
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { Text, type TextStyle } from 'react-native';
|
|
3
|
-
import {
|
|
4
|
-
import { useTokens } from '../../tokens/useTokens';
|
|
3
|
+
import { useTokens, useFrameContext } from 'newtone-api';
|
|
5
4
|
import type { IconProps } from './Icon.types';
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -18,8 +17,8 @@ import type { IconProps } from './Icon.types';
|
|
|
18
17
|
* ```
|
|
19
18
|
*/
|
|
20
19
|
export function Icon({
|
|
21
|
-
name,
|
|
22
|
-
size,
|
|
20
|
+
name = 'add',
|
|
21
|
+
size = 24,
|
|
23
22
|
opticalSize,
|
|
24
23
|
fill = 0,
|
|
25
24
|
color,
|
|
@@ -33,6 +32,9 @@ export function Icon({
|
|
|
33
32
|
}: IconProps) {
|
|
34
33
|
// Inherit tokens from nearest parent Frame via FrameContext.
|
|
35
34
|
const tokens = useTokens();
|
|
35
|
+
const frameCtx = useFrameContext();
|
|
36
|
+
const resolvedTheme = frameCtx?.theme ?? 'primary';
|
|
37
|
+
const resolvedAppearance = frameCtx?.appearance ?? 'main';
|
|
36
38
|
|
|
37
39
|
// Build the icon's style from the theme tokens and props.
|
|
38
40
|
// Wrapped in useMemo so it only recalculates when the inputs change,
|
|
@@ -54,8 +56,8 @@ export function Icon({
|
|
|
54
56
|
// Use explicit opticalSize if provided, otherwise auto-calculate from fontSize.
|
|
55
57
|
const opsz = opticalSize ?? getOpticalSize(fontSize);
|
|
56
58
|
|
|
57
|
-
// Use the provided color, or fall back to the theme
|
|
58
|
-
const iconColor = color ??
|
|
59
|
+
// Use the provided color, or fall back to the inherited theme/appearance text color.
|
|
60
|
+
const iconColor = color ?? tokens.colors[resolvedTheme][resolvedAppearance].fontPrimary;
|
|
59
61
|
|
|
60
62
|
// Build the font family name from the theme's icon variant setting.
|
|
61
63
|
// Example: variant 'rounded' → 'Material Symbols Rounded'
|
|
@@ -81,7 +83,7 @@ export function Icon({
|
|
|
81
83
|
fontVariationSettings, // web-only: controls the variable font axes listed above
|
|
82
84
|
...style,
|
|
83
85
|
} as TextStyle; // Cast needed because web-only properties aren't in RN's type definitions
|
|
84
|
-
}, [tokens, size, opticalSize, fill, color, style]);
|
|
86
|
+
}, [tokens, size, opticalSize, fill, color, style, resolvedTheme, resolvedAppearance]);
|
|
85
87
|
|
|
86
88
|
// Material Symbols renders icons as text ligatures — the icon name (like "home")
|
|
87
89
|
// is passed as text content, and the font renders it as the icon glyph.
|
|
@@ -23,9 +23,9 @@ export interface IconProps {
|
|
|
23
23
|
* @example `'home'`, `'settings'`, `'check'`, `'expand_more'`, `'delete'`, `'add'`, `'search'`
|
|
24
24
|
* @see {@link https://fonts.google.com/icons Browse all icons}
|
|
25
25
|
*/
|
|
26
|
-
readonly name
|
|
26
|
+
readonly name?: string;
|
|
27
27
|
|
|
28
|
-
/** Font size in pixels. @default
|
|
28
|
+
/** Font size in pixels. @default 24 */
|
|
29
29
|
readonly size?: number;
|
|
30
30
|
|
|
31
31
|
/** Optical size for variable font axis. Adjusts stroke weight for readability at small sizes. @default same as size */
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React, { useContext, useMemo } from 'react';
|
|
2
2
|
import { Text as RNText } from 'react-native';
|
|
3
3
|
import type { TextStyle } from 'react-native';
|
|
4
|
-
import { useTokens } from '
|
|
4
|
+
import { useTokens, useFrameContext } from 'newtone-api';
|
|
5
|
+
import type { ThemeName, AppearanceName } from 'newtone-api';
|
|
5
6
|
import { TextScopeContext, resolveTextColor } from './Text';
|
|
6
7
|
import type { TextSpanProps, TextWeight } from './Text.types';
|
|
7
8
|
|
|
@@ -11,18 +12,21 @@ import type { TextSpanProps, TextWeight } from './Text.types';
|
|
|
11
12
|
* Only inline formatting properties (color, weight, italic, underline, highlight) are exposed.
|
|
12
13
|
*/
|
|
13
14
|
export function TextSpan({ children, color, weight, italic, underline, highlight, style }: TextSpanProps) {
|
|
14
|
-
const tokens = useTokens(
|
|
15
|
+
const tokens = useTokens();
|
|
15
16
|
const scopeCtx = useContext(TextScopeContext);
|
|
17
|
+
const frameCtx = useFrameContext();
|
|
18
|
+
const resolvedTheme: ThemeName = frameCtx?.theme ?? 'primary';
|
|
19
|
+
const resolvedAppearance: AppearanceName = frameCtx?.appearance ?? 'main';
|
|
16
20
|
|
|
17
21
|
const spanStyle = useMemo<TextStyle>(() => {
|
|
18
22
|
const s: TextStyle = {};
|
|
19
|
-
if (color) s.color = resolveTextColor(color, tokens);
|
|
23
|
+
if (color) s.color = resolveTextColor(color, tokens, resolvedTheme, resolvedAppearance);
|
|
20
24
|
if (weight && scopeCtx) s.fontWeight = String(scopeCtx.weights[weight]) as TextStyle['fontWeight'];
|
|
21
25
|
if (italic) s.fontStyle = 'italic';
|
|
22
26
|
if (underline) s.textDecorationLine = 'underline';
|
|
23
|
-
if (highlight) s.backgroundColor = resolveTextColor(highlight, tokens);
|
|
27
|
+
if (highlight) s.backgroundColor = resolveTextColor(highlight, tokens, resolvedTheme, resolvedAppearance);
|
|
24
28
|
return s;
|
|
25
|
-
}, [tokens, scopeCtx, color, weight, italic, underline, highlight]);
|
|
29
|
+
}, [tokens, scopeCtx, color, weight, italic, underline, highlight, resolvedTheme, resolvedAppearance]);
|
|
26
30
|
|
|
27
31
|
return React.createElement(
|
|
28
32
|
RNText,
|