@newtonedev/components 0.1.5 → 0.1.7
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 +3 -1
- package/dist/composites/actions/Button/Button.styles.d.ts.map +1 -1
- package/dist/index.cjs +603 -249
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +599 -251
- package/dist/index.js.map +1 -1
- package/dist/primitives/Frame/Frame.d.ts +2 -3
- package/dist/primitives/Frame/Frame.d.ts.map +1 -1
- package/dist/primitives/Frame/Frame.types.d.ts +4 -15
- package/dist/primitives/Frame/Frame.types.d.ts.map +1 -1
- package/dist/primitives/Icon/Icon.d.ts +1 -1
- package/dist/primitives/Icon/Icon.d.ts.map +1 -1
- package/dist/primitives/Icon/Icon.types.d.ts +7 -12
- package/dist/primitives/Icon/Icon.types.d.ts.map +1 -1
- package/dist/primitives/Text/Text.d.ts.map +1 -1
- package/dist/primitives/Text/Text.types.d.ts +9 -4
- 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.types.d.ts +1 -1
- package/dist/registry/icons.d.ts +7 -0
- package/dist/registry/icons.d.ts.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/types.d.ts +1 -1
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/theme/FrameContext.d.ts +7 -5
- package/dist/theme/FrameContext.d.ts.map +1 -1
- package/dist/theme/NewtoneProvider.d.ts +5 -6
- package/dist/theme/NewtoneProvider.d.ts.map +1 -1
- package/dist/theme/defaults.d.ts.map +1 -1
- package/dist/theme/types.d.ts +38 -24
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/tokens/computeTokens.d.ts +82 -7
- package/dist/tokens/computeTokens.d.ts.map +1 -1
- package/dist/tokens/types.d.ts +58 -16
- package/dist/tokens/types.d.ts.map +1 -1
- package/dist/tokens/useTokens.d.ts +2 -23
- package/dist/tokens/useTokens.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/composites/actions/Button/Button.styles.ts +53 -80
- package/src/composites/actions/Button/Button.tsx +6 -2
- package/src/composites/form-controls/Select/SelectOption.tsx +2 -2
- package/src/composites/form-controls/Toggle/Toggle.styles.ts +1 -1
- package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.ts +1 -1
- package/src/composites/range-inputs/Slider/Slider.styles.ts +2 -2
- package/src/index.ts +13 -4
- package/src/primitives/Frame/Frame.tsx +10 -18
- package/src/primitives/Frame/Frame.types.ts +5 -17
- package/src/primitives/Icon/Icon.tsx +4 -6
- package/src/primitives/Icon/Icon.types.ts +7 -14
- package/src/primitives/Text/Text.tsx +18 -8
- package/src/primitives/Text/Text.types.ts +9 -4
- package/src/primitives/Wrapper/Wrapper.tsx +1 -1
- package/src/primitives/Wrapper/Wrapper.types.ts +1 -1
- package/src/registry/icons.ts +111 -0
- package/src/registry/index.ts +3 -0
- package/src/registry/registry.ts +40 -24
- package/src/registry/types.ts +1 -1
- package/src/theme/FrameContext.tsx +7 -5
- package/src/theme/NewtoneProvider.tsx +5 -10
- package/src/theme/defaults.ts +0 -9
- package/src/theme/types.ts +53 -26
- package/src/tokens/computeTokens.ts +338 -116
- package/src/tokens/types.ts +74 -16
- package/src/tokens/useTokens.ts +16 -33
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { View, ViewStyle, GestureResponderEvent } from 'react-native';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FrameElevation } from '../../theme/types';
|
|
3
3
|
|
|
4
4
|
// ── Spacing Types ──────────────────────────────────────────────
|
|
5
5
|
|
|
@@ -115,14 +115,14 @@ export type Justification = 'start' | 'center' | 'end' | 'between' | 'around' |
|
|
|
115
115
|
* // Horizontal toolbar with consistent spacing
|
|
116
116
|
* <Frame direction="horizontal" gap="md" padding="lg" align="center">
|
|
117
117
|
* <Button onPress={() => {}}>Save</Button>
|
|
118
|
-
* <Button variant="
|
|
118
|
+
* <Button variant="tertiary" onPress={() => {}}>Cancel</Button>
|
|
119
119
|
* </Frame>
|
|
120
120
|
* ```
|
|
121
121
|
*
|
|
122
122
|
* @example
|
|
123
123
|
* ```tsx
|
|
124
|
-
* // Elevated card
|
|
125
|
-
* <Frame
|
|
124
|
+
* // Elevated card
|
|
125
|
+
* <Frame elevation={2} radius="lg" padding="xl" bordered>
|
|
126
126
|
* <Text>Elevated card content</Text>
|
|
127
127
|
* </Frame>
|
|
128
128
|
* ```
|
|
@@ -142,19 +142,7 @@ export interface FrameProps {
|
|
|
142
142
|
*/
|
|
143
143
|
readonly children: React.ReactNode;
|
|
144
144
|
|
|
145
|
-
// ──
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Theme override for this frame and all descendants.
|
|
149
|
-
* When omitted, inherits from parent Frame or NewtoneProvider.
|
|
150
|
-
*
|
|
151
|
-
* @example
|
|
152
|
-
* ```tsx
|
|
153
|
-
* <Frame theme="primary"> // Blue-ish surface
|
|
154
|
-
* <Frame theme="strong"> // High-contrast surface
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
readonly theme?: ThemeName;
|
|
145
|
+
// ── Elevation ──
|
|
158
146
|
|
|
159
147
|
/**
|
|
160
148
|
* Surface elevation: controls background lightness and shadow.
|
|
@@ -23,9 +23,7 @@ export function Icon({
|
|
|
23
23
|
opticalSize,
|
|
24
24
|
fill = 0,
|
|
25
25
|
color,
|
|
26
|
-
elevation = 1,
|
|
27
26
|
style,
|
|
28
|
-
onPress,
|
|
29
27
|
// Accessibility
|
|
30
28
|
accessibilityLabel,
|
|
31
29
|
// Testing & platform
|
|
@@ -33,8 +31,8 @@ export function Icon({
|
|
|
33
31
|
nativeID,
|
|
34
32
|
ref,
|
|
35
33
|
}: IconProps) {
|
|
36
|
-
//
|
|
37
|
-
const tokens = useTokens(
|
|
34
|
+
// Inherit tokens from nearest parent Frame via FrameContext.
|
|
35
|
+
const tokens = useTokens();
|
|
38
36
|
|
|
39
37
|
// Build the icon's style from the theme tokens and props.
|
|
40
38
|
// Wrapped in useMemo so it only recalculates when the inputs change,
|
|
@@ -69,7 +67,8 @@ export function Icon({
|
|
|
69
67
|
// wght: font weight (thinner or bolder strokes)
|
|
70
68
|
// GRAD: grade (fine-tune weight without changing overall size)
|
|
71
69
|
// opsz: optical size (adjusts detail level for the display size)
|
|
72
|
-
const
|
|
70
|
+
const fillValue = typeof fill === 'boolean' ? (fill ? 1 : 0) : fill;
|
|
71
|
+
const fontVariationSettings = `'FILL' ${fillValue}, 'wght' ${tokens.icons.weight}, 'GRAD' ${tokens.icons.grade}, 'opsz' ${opsz}`;
|
|
73
72
|
|
|
74
73
|
return {
|
|
75
74
|
fontFamily,
|
|
@@ -96,7 +95,6 @@ export function Icon({
|
|
|
96
95
|
// so assistive technology doesn't try to read the ligature text (e.g. "home").
|
|
97
96
|
importantForAccessibility={accessibilityLabel ? 'yes' : 'no-hide-descendants'}
|
|
98
97
|
style={iconStyle}
|
|
99
|
-
onPress={onPress} // When provided, makes the icon tappable
|
|
100
98
|
>
|
|
101
99
|
{name}
|
|
102
100
|
</Text>
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import type { Text as RNText, TextStyle } from 'react-native';
|
|
2
|
-
import type { ElevationLevel } from '../../theme/types';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Props for Icon — Material Symbols icon with variable font support.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Icon is a pure presentation primitive. It inherits elevation from the
|
|
7
|
+
* nearest parent Frame via FrameContext. For interactive icons, wrap in
|
|
8
|
+
* `<Button icon="..." />` instead.
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```tsx
|
|
12
12
|
* <Icon name="home" />
|
|
13
13
|
* <Icon name="settings" size={24} fill={1} />
|
|
14
14
|
* <Icon name="check" color="#00ff00" />
|
|
15
|
-
* <Icon name="delete" size={20} onPress={() => handleDelete()} />
|
|
16
15
|
* ```
|
|
17
16
|
*
|
|
18
17
|
* @see {@link https://fonts.google.com/icons Material Symbols icon reference}
|
|
@@ -35,23 +34,17 @@ export interface IconProps {
|
|
|
35
34
|
/**
|
|
36
35
|
* Fill state for the icon.
|
|
37
36
|
*
|
|
38
|
-
* - `0` — Outlined (default)
|
|
39
|
-
* - `1` — Filled (solid)
|
|
37
|
+
* - `false` / `0` — Outlined (default)
|
|
38
|
+
* - `true` / `1` — Filled (solid)
|
|
40
39
|
*/
|
|
41
|
-
readonly fill?: 0 | 1;
|
|
40
|
+
readonly fill?: boolean | 0 | 1;
|
|
42
41
|
|
|
43
42
|
/** Icon color as hex string. @default tokens.textPrimary */
|
|
44
43
|
readonly color?: string;
|
|
45
44
|
|
|
46
|
-
/**
|
|
47
|
-
readonly elevation?: ElevationLevel;
|
|
48
|
-
|
|
49
|
-
/** Additional styles applied to the icon Text element. */
|
|
45
|
+
/** Additional styles applied to the icon Text element (positioning, transforms). */
|
|
50
46
|
readonly style?: TextStyle;
|
|
51
47
|
|
|
52
|
-
/** Press handler — makes the icon tappable. */
|
|
53
|
-
readonly onPress?: () => void;
|
|
54
|
-
|
|
55
48
|
// ── Accessibility ──
|
|
56
49
|
|
|
57
50
|
/** Label read by screen readers. When omitted, the icon is treated as decorative (hidden from assistive technology). */
|
|
@@ -3,15 +3,25 @@ import { Text as RNText } from 'react-native';
|
|
|
3
3
|
import type { TextStyle } from 'react-native';
|
|
4
4
|
import { srgbToHex } from 'newtone';
|
|
5
5
|
import { useTokens } from '../../tokens/useTokens';
|
|
6
|
+
import type { UseTokensResult } from '../../tokens/useTokens';
|
|
6
7
|
import type { TextProps, TextColor } from './Text.types';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a semantic text color to a hex string from the current tokens.
|
|
11
|
+
* Neutral text colors are top-level; palette colors use nested PaletteTokens.fill.
|
|
12
|
+
*/
|
|
13
|
+
function resolveTextColor(color: TextColor, tokens: UseTokensResult): string {
|
|
14
|
+
switch (color) {
|
|
15
|
+
case 'primary': return srgbToHex(tokens.textPrimary.srgb);
|
|
16
|
+
case 'secondary': return srgbToHex(tokens.textSecondary.srgb);
|
|
17
|
+
case 'tertiary': return srgbToHex(tokens.textTertiary.srgb);
|
|
18
|
+
case 'disabled': return srgbToHex(tokens.textDisabled.srgb);
|
|
19
|
+
case 'accent': return srgbToHex(tokens.accent.fill.srgb);
|
|
20
|
+
case 'success': return srgbToHex(tokens.success.fill.srgb);
|
|
21
|
+
case 'warning': return srgbToHex(tokens.warning.fill.srgb);
|
|
22
|
+
case 'error': return srgbToHex(tokens.error.fill.srgb);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
|
|
16
26
|
/**
|
|
17
27
|
* Token-aware text primitive.
|
|
@@ -61,7 +71,7 @@ export function Text({
|
|
|
61
71
|
// Font weight is stored as a number (e.g. 400, 600) but React Native expects a string.
|
|
62
72
|
fontWeight: String(tokens.typography.weight[weight]) as TextStyle['fontWeight'],
|
|
63
73
|
// Convert the theme color from internal sRGB format to a hex string (e.g. '#1a1a1a').
|
|
64
|
-
color:
|
|
74
|
+
color: resolveTextColor(color, tokens),
|
|
65
75
|
// Line height = font size × multiplier (e.g. 16px × 1.5 = 24px line height).
|
|
66
76
|
lineHeight: fontSize * tokens.typography.lineHeight[lineHeight],
|
|
67
77
|
textAlign: align,
|
|
@@ -8,7 +8,7 @@ export type TextSize = 'xs' | 'sm' | 'base' | 'md' | 'lg' | 'xl' | 'xxl';
|
|
|
8
8
|
export type TextWeight = 'regular' | 'medium' | 'semibold' | 'bold';
|
|
9
9
|
|
|
10
10
|
/** Semantic text color tokens — resolved from the current theme's token palette. */
|
|
11
|
-
export type TextColor = 'primary' | 'secondary' | '
|
|
11
|
+
export type TextColor = 'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent' | 'success' | 'warning' | 'error';
|
|
12
12
|
|
|
13
13
|
/** Font family tokens — maps to `tokens.typography.fonts.*` font stacks. */
|
|
14
14
|
export type TextFont = 'default' | 'display' | 'mono';
|
|
@@ -58,9 +58,14 @@ export interface TextProps {
|
|
|
58
58
|
/**
|
|
59
59
|
* Semantic color token.
|
|
60
60
|
*
|
|
61
|
-
* - `'primary'` — Main text color
|
|
62
|
-
* - `'secondary'` — Subdued/muted text
|
|
63
|
-
* - `'
|
|
61
|
+
* - `'primary'` — Main text color, high contrast
|
|
62
|
+
* - `'secondary'` — Subdued/muted text (captions, labels)
|
|
63
|
+
* - `'tertiary'` — Hints, placeholders
|
|
64
|
+
* - `'disabled'` — Disabled text elements
|
|
65
|
+
* - `'accent'` — Accent palette color for links/actions
|
|
66
|
+
* - `'success'` — Success palette color for positive indicators
|
|
67
|
+
* - `'warning'` — Warning palette color for caution indicators
|
|
68
|
+
* - `'error'` — Error palette color for destructive/error indicators
|
|
64
69
|
*
|
|
65
70
|
* @default 'primary'
|
|
66
71
|
*/
|
|
@@ -18,7 +18,7 @@ import { useTokens } from '../../tokens/useTokens';
|
|
|
18
18
|
* ```tsx
|
|
19
19
|
* <Wrapper direction="horizontal" gap="md" align="center">
|
|
20
20
|
* <Button onPress={() => {}}>Save</Button>
|
|
21
|
-
* <Button variant="
|
|
21
|
+
* <Button variant="tertiary" onPress={() => {}}>Cancel</Button>
|
|
22
22
|
* </Wrapper>
|
|
23
23
|
* ```
|
|
24
24
|
*
|
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
* // Horizontal row with spacing
|
|
24
24
|
* <Wrapper direction="horizontal" gap="md" align="center">
|
|
25
25
|
* <Button onPress={() => {}}>Save</Button>
|
|
26
|
-
* <Button variant="
|
|
26
|
+
* <Button variant="tertiary" onPress={() => {}}>Cancel</Button>
|
|
27
27
|
* </Wrapper>
|
|
28
28
|
* ```
|
|
29
29
|
*
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export interface IconCatalogCategory {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly label: string;
|
|
4
|
+
readonly icons: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const ICON_CATALOG: readonly IconCatalogCategory[] = [
|
|
8
|
+
{
|
|
9
|
+
id: 'navigation',
|
|
10
|
+
label: 'Navigation',
|
|
11
|
+
icons: [
|
|
12
|
+
'home', 'menu', 'close', 'arrow_back', 'arrow_forward',
|
|
13
|
+
'arrow_upward', 'arrow_downward', 'chevron_left', 'chevron_right',
|
|
14
|
+
'expand_more', 'expand_less', 'first_page', 'last_page',
|
|
15
|
+
'more_vert', 'more_horiz', 'unfold_more', 'unfold_less',
|
|
16
|
+
'subdirectory_arrow_right',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'actions',
|
|
21
|
+
label: 'Actions',
|
|
22
|
+
icons: [
|
|
23
|
+
'search', 'settings', 'done', 'add', 'remove',
|
|
24
|
+
'delete', 'edit', 'save', 'refresh', 'undo',
|
|
25
|
+
'redo', 'download', 'upload', 'share', 'print',
|
|
26
|
+
'content_copy', 'content_paste', 'open_in_new', 'launch',
|
|
27
|
+
'drag_indicator', 'tune', 'sort', 'filter_list',
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'communication',
|
|
32
|
+
label: 'Communication',
|
|
33
|
+
icons: [
|
|
34
|
+
'mail', 'chat', 'call', 'notifications', 'forum',
|
|
35
|
+
'send', 'inbox', 'drafts', 'mark_email_read',
|
|
36
|
+
'contact_mail', 'alternate_email', 'comment',
|
|
37
|
+
'chat_bubble', 'sms', 'voicemail',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'content',
|
|
42
|
+
label: 'Content',
|
|
43
|
+
icons: [
|
|
44
|
+
'add_circle', 'remove_circle', 'check_circle', 'cancel',
|
|
45
|
+
'flag', 'bookmark', 'star', 'favorite',
|
|
46
|
+
'thumb_up', 'thumb_down', 'push_pin', 'link',
|
|
47
|
+
'link_off', 'bolt', 'label', 'inventory_2',
|
|
48
|
+
'visibility', 'visibility_off',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'media',
|
|
53
|
+
label: 'Media',
|
|
54
|
+
icons: [
|
|
55
|
+
'play_arrow', 'pause', 'stop', 'skip_next', 'skip_previous',
|
|
56
|
+
'fast_forward', 'fast_rewind', 'replay', 'shuffle',
|
|
57
|
+
'repeat', 'volume_up', 'volume_off', 'music_note',
|
|
58
|
+
'image', 'photo_camera', 'videocam', 'mic',
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'file',
|
|
63
|
+
label: 'File & Folder',
|
|
64
|
+
icons: [
|
|
65
|
+
'folder', 'folder_open', 'create_new_folder', 'description',
|
|
66
|
+
'file_copy', 'attach_file', 'cloud', 'cloud_upload',
|
|
67
|
+
'cloud_download', 'cloud_off', 'storage', 'snippet_folder',
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'social',
|
|
72
|
+
label: 'Social & People',
|
|
73
|
+
icons: [
|
|
74
|
+
'person', 'group', 'person_add', 'person_remove',
|
|
75
|
+
'people', 'face', 'sentiment_satisfied', 'sentiment_dissatisfied',
|
|
76
|
+
'public', 'workspace_premium', 'emoji_events', 'military_tech',
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'alerts',
|
|
81
|
+
label: 'Alerts & Status',
|
|
82
|
+
icons: [
|
|
83
|
+
'error', 'warning', 'info', 'help',
|
|
84
|
+
'check_circle', 'report', 'new_releases',
|
|
85
|
+
'notification_important', 'priority_high',
|
|
86
|
+
'verified', 'shield', 'security',
|
|
87
|
+
'lock', 'lock_open',
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'device',
|
|
92
|
+
label: 'Device & Hardware',
|
|
93
|
+
icons: [
|
|
94
|
+
'phone_android', 'computer', 'tablet_mac', 'watch',
|
|
95
|
+
'keyboard', 'mouse', 'headphones', 'speaker',
|
|
96
|
+
'monitor', 'devices', 'memory', 'battery_full',
|
|
97
|
+
'wifi', 'bluetooth', 'usb', 'dark_mode', 'light_mode',
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'editor',
|
|
102
|
+
label: 'Editor & Formatting',
|
|
103
|
+
icons: [
|
|
104
|
+
'format_bold', 'format_italic', 'format_underlined',
|
|
105
|
+
'format_list_bulleted', 'format_list_numbered', 'format_quote',
|
|
106
|
+
'format_align_left', 'format_align_center', 'format_align_right',
|
|
107
|
+
'title', 'text_fields', 'code', 'palette',
|
|
108
|
+
'color_lens', 'brush', 'auto_fix_high',
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
];
|
package/src/registry/index.ts
CHANGED
package/src/registry/registry.ts
CHANGED
|
@@ -20,13 +20,17 @@ export const COMPONENTS: readonly ComponentMeta[] = [
|
|
|
20
20
|
variants: [
|
|
21
21
|
{ id: 'primary-md', label: 'Primary', props: { variant: 'primary', size: 'md' } },
|
|
22
22
|
{ id: 'secondary-md', label: 'Secondary', props: { variant: 'secondary', size: 'md' } },
|
|
23
|
-
{ id: '
|
|
24
|
-
{ id: 'outline-md', label: 'Outline', props: { variant: 'outline', size: 'md' } },
|
|
23
|
+
{ id: 'tertiary-md', label: 'Tertiary', props: { variant: 'tertiary', size: 'md' } },
|
|
25
24
|
{ id: 'primary-sm', label: 'Primary Small', props: { variant: 'primary', size: 'sm' } },
|
|
26
25
|
{ id: 'primary-lg', label: 'Primary Large', props: { variant: 'primary', size: 'lg' } },
|
|
26
|
+
{ id: 'accent-primary', label: 'Accent Primary', props: { variant: 'primary', size: 'md', semantic: 'accent' } },
|
|
27
|
+
{ id: 'accent-secondary', label: 'Accent Secondary', props: { variant: 'secondary', size: 'md', semantic: 'accent' } },
|
|
28
|
+
{ id: 'success-primary', label: 'Success Primary', props: { variant: 'primary', size: 'md', semantic: 'success' } },
|
|
29
|
+
{ id: 'error-primary', label: 'Error Primary', props: { variant: 'primary', size: 'md', semantic: 'error' } },
|
|
30
|
+
{ id: 'warning-primary', label: 'Warning Primary', props: { variant: 'primary', size: 'md', semantic: 'warning' } },
|
|
27
31
|
{ id: 'icon-left', label: 'Icon Left', props: { variant: 'primary', size: 'md', icon: 'add' } },
|
|
28
32
|
{ id: 'icon-right', label: 'Icon Right', props: { variant: 'primary', size: 'md', icon: 'arrow_forward', iconPosition: 'right' } },
|
|
29
|
-
{ id: 'icon-only', label: 'Icon Only', props: { variant: '
|
|
33
|
+
{ id: 'icon-only', label: 'Icon Only', props: { variant: 'tertiary', size: 'md', icon: 'settings' } },
|
|
30
34
|
],
|
|
31
35
|
editableProps: [
|
|
32
36
|
{
|
|
@@ -36,11 +40,23 @@ export const COMPONENTS: readonly ComponentMeta[] = [
|
|
|
36
40
|
options: [
|
|
37
41
|
{ label: 'Primary', value: 'primary' },
|
|
38
42
|
{ label: 'Secondary', value: 'secondary' },
|
|
39
|
-
{ label: '
|
|
40
|
-
{ label: 'Outline', value: 'outline' },
|
|
43
|
+
{ label: 'Tertiary', value: 'tertiary' },
|
|
41
44
|
],
|
|
42
45
|
defaultValue: 'primary',
|
|
43
46
|
},
|
|
47
|
+
{
|
|
48
|
+
name: 'semantic',
|
|
49
|
+
label: 'Semantic',
|
|
50
|
+
control: 'select',
|
|
51
|
+
options: [
|
|
52
|
+
{ label: 'Neutral', value: 'neutral' },
|
|
53
|
+
{ label: 'Accent', value: 'accent' },
|
|
54
|
+
{ label: 'Success', value: 'success' },
|
|
55
|
+
{ label: 'Warning', value: 'warning' },
|
|
56
|
+
{ label: 'Error', value: 'error' },
|
|
57
|
+
],
|
|
58
|
+
defaultValue: 'neutral',
|
|
59
|
+
},
|
|
44
60
|
{
|
|
45
61
|
name: 'size',
|
|
46
62
|
label: 'Size',
|
|
@@ -403,7 +419,7 @@ export const COMPONENTS: readonly ComponentMeta[] = [
|
|
|
403
419
|
{ id: 'subheading', label: 'Subheading', props: { size: 'lg', weight: 'semibold' } },
|
|
404
420
|
{ id: 'body', label: 'Body', props: { size: 'base' } },
|
|
405
421
|
{ id: 'caption', label: 'Caption', props: { size: 'sm', color: 'secondary' } },
|
|
406
|
-
{ id: '
|
|
422
|
+
{ id: 'accent', label: 'Accent', props: { color: 'accent', weight: 'medium' } },
|
|
407
423
|
{ id: 'mono', label: 'Monospace', props: { font: 'mono', size: 'sm' } },
|
|
408
424
|
],
|
|
409
425
|
editableProps: [
|
|
@@ -441,7 +457,12 @@ export const COMPONENTS: readonly ComponentMeta[] = [
|
|
|
441
457
|
options: [
|
|
442
458
|
{ label: 'Primary', value: 'primary' },
|
|
443
459
|
{ label: 'Secondary', value: 'secondary' },
|
|
444
|
-
{ label: '
|
|
460
|
+
{ label: 'Tertiary', value: 'tertiary' },
|
|
461
|
+
{ label: 'Disabled', value: 'disabled' },
|
|
462
|
+
{ label: 'Accent', value: 'accent' },
|
|
463
|
+
{ label: 'Success', value: 'success' },
|
|
464
|
+
{ label: 'Warning', value: 'warning' },
|
|
465
|
+
{ label: 'Error', value: 'error' },
|
|
445
466
|
],
|
|
446
467
|
defaultValue: 'primary',
|
|
447
468
|
},
|
|
@@ -463,40 +484,35 @@ export const COMPONENTS: readonly ComponentMeta[] = [
|
|
|
463
484
|
name: 'Icon',
|
|
464
485
|
importName: 'Icon',
|
|
465
486
|
categoryId: 'primitives',
|
|
466
|
-
description: 'Material Symbols icon with size
|
|
487
|
+
description: 'Material Symbols icon with size and fill',
|
|
467
488
|
hasChildren: false,
|
|
468
489
|
variants: [
|
|
469
|
-
{ id: '
|
|
470
|
-
{ id: 'settings', label: 'Settings', props: { name: 'settings' } },
|
|
471
|
-
{ id: 'check', label: 'Check', props: { name: 'check' } },
|
|
472
|
-
{ id: 'add', label: 'Add', props: { name: 'add' } },
|
|
473
|
-
{ id: 'delete', label: 'Delete', props: { name: 'delete' } },
|
|
474
|
-
{ id: 'search', label: 'Search', props: { name: 'search' } },
|
|
475
|
-
{ id: 'filled', label: 'Filled Icon', props: { name: 'favorite', fill: 1 } },
|
|
476
|
-
{ id: 'large', label: 'Large Icon', props: { name: 'star', size: 32 } },
|
|
490
|
+
{ id: 'default', label: 'Default', props: { name: 'add' } },
|
|
477
491
|
],
|
|
478
492
|
editableProps: [
|
|
479
493
|
{
|
|
480
494
|
name: 'name',
|
|
481
495
|
label: 'Icon Name',
|
|
482
496
|
control: 'text',
|
|
483
|
-
defaultValue: '
|
|
497
|
+
defaultValue: 'add',
|
|
484
498
|
},
|
|
485
499
|
{
|
|
486
500
|
name: 'size',
|
|
487
501
|
label: 'Size',
|
|
488
|
-
control: '
|
|
502
|
+
control: 'discrete-slider',
|
|
503
|
+
options: [
|
|
504
|
+
{ label: '20', value: 20 },
|
|
505
|
+
{ label: '24', value: 24 },
|
|
506
|
+
{ label: '40', value: 40 },
|
|
507
|
+
{ label: '48', value: 48 },
|
|
508
|
+
],
|
|
489
509
|
defaultValue: 24,
|
|
490
510
|
},
|
|
491
511
|
{
|
|
492
512
|
name: 'fill',
|
|
493
513
|
label: 'Fill',
|
|
494
|
-
control: '
|
|
495
|
-
|
|
496
|
-
{ label: 'Outlined', value: 0 },
|
|
497
|
-
{ label: 'Filled', value: 1 },
|
|
498
|
-
],
|
|
499
|
-
defaultValue: 0,
|
|
514
|
+
control: 'toggle',
|
|
515
|
+
defaultValue: false,
|
|
500
516
|
},
|
|
501
517
|
],
|
|
502
518
|
},
|
package/src/registry/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface EditablePropOption {
|
|
|
18
18
|
export interface EditableProp {
|
|
19
19
|
readonly name: string;
|
|
20
20
|
readonly label: string;
|
|
21
|
-
readonly control: 'select' | 'text' | 'toggle' | 'number';
|
|
21
|
+
readonly control: 'select' | 'text' | 'toggle' | 'number' | 'discrete-slider';
|
|
22
22
|
readonly options?: readonly EditablePropOption[];
|
|
23
23
|
readonly defaultValue: string | number | boolean;
|
|
24
24
|
}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ElevationLevel } from './types';
|
|
3
|
+
import type { ResolvedTokens } from '../tokens/types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Context value provided by Frame to its descendants.
|
|
6
|
-
* Contains the resolved
|
|
7
|
+
* Contains the resolved elevation and pre-computed tokens.
|
|
8
|
+
* Tokens are included to avoid redundant computeTokens calls in child components.
|
|
7
9
|
*/
|
|
8
10
|
export interface FrameContextValue {
|
|
9
|
-
readonly theme: ThemeName;
|
|
10
11
|
readonly elevation: ElevationLevel;
|
|
12
|
+
readonly tokens: ResolvedTokens;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
|
-
* FrameContext - Propagates
|
|
16
|
+
* FrameContext - Propagates elevation overrides from Frame to descendants.
|
|
15
17
|
*
|
|
16
|
-
* When null, components fall back to
|
|
18
|
+
* When null, components fall back to default elevation (1).
|
|
17
19
|
* When present, useTokens() reads from this context instead.
|
|
18
20
|
*/
|
|
19
21
|
export const FrameContext = createContext<FrameContextValue | null>(null);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { createContext, useState, useMemo, useContext } from 'react';
|
|
2
|
-
import type { NewtoneThemeConfig, NewtoneThemeContext, ColorMode
|
|
2
|
+
import type { NewtoneThemeConfig, NewtoneThemeContext, ColorMode } from './types';
|
|
3
3
|
import { DEFAULT_THEME_CONFIG } from './defaults';
|
|
4
4
|
import { GoogleFontLoader } from '../fonts/GoogleFontLoader';
|
|
5
5
|
import { IconFontLoader } from '../fonts/IconFontLoader';
|
|
@@ -9,18 +9,17 @@ const ThemeContext = createContext<NewtoneThemeContext | null>(null);
|
|
|
9
9
|
export interface NewtoneProviderProps {
|
|
10
10
|
readonly config?: NewtoneThemeConfig;
|
|
11
11
|
readonly initialMode?: ColorMode;
|
|
12
|
-
readonly initialTheme?: ThemeName;
|
|
13
12
|
readonly children: React.ReactNode;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* NewtoneProvider - Provides theme context to all Newtone components
|
|
18
17
|
*
|
|
19
|
-
* Wrap your app with this provider to enable
|
|
18
|
+
* Wrap your app with this provider to enable mode switching.
|
|
20
19
|
*
|
|
21
20
|
* @example
|
|
22
21
|
* ```tsx
|
|
23
|
-
* <NewtoneProvider initialMode="light"
|
|
22
|
+
* <NewtoneProvider initialMode="light">
|
|
24
23
|
* <App />
|
|
25
24
|
* </NewtoneProvider>
|
|
26
25
|
* ```
|
|
@@ -28,21 +27,17 @@ export interface NewtoneProviderProps {
|
|
|
28
27
|
export function NewtoneProvider({
|
|
29
28
|
config = DEFAULT_THEME_CONFIG,
|
|
30
29
|
initialMode = 'light',
|
|
31
|
-
initialTheme = 'neutral',
|
|
32
30
|
children,
|
|
33
31
|
}: NewtoneProviderProps) {
|
|
34
32
|
const [mode, setMode] = useState<ColorMode>(initialMode);
|
|
35
|
-
const [theme, setTheme] = useState<ThemeName>(initialTheme);
|
|
36
33
|
|
|
37
34
|
const value = useMemo(
|
|
38
35
|
() => ({
|
|
39
36
|
config,
|
|
40
37
|
mode,
|
|
41
|
-
theme,
|
|
42
38
|
setMode,
|
|
43
|
-
setTheme,
|
|
44
39
|
}),
|
|
45
|
-
[config, mode
|
|
40
|
+
[config, mode]
|
|
46
41
|
);
|
|
47
42
|
|
|
48
43
|
return (
|
|
@@ -61,7 +56,7 @@ export function NewtoneProvider({
|
|
|
61
56
|
*
|
|
62
57
|
* @example
|
|
63
58
|
* ```tsx
|
|
64
|
-
* const { mode,
|
|
59
|
+
* const { mode, setMode } = useNewtoneTheme();
|
|
65
60
|
* ```
|
|
66
61
|
*/
|
|
67
62
|
export function useNewtoneTheme(): NewtoneThemeContext {
|
package/src/theme/defaults.ts
CHANGED
|
@@ -30,15 +30,6 @@ export const DEFAULT_THEME_CONFIG: NewtoneThemeConfig = {
|
|
|
30
30
|
{ hue: DEFAULT_ERROR_HUE, saturation: DEFAULT_ERROR_SATURATION },
|
|
31
31
|
],
|
|
32
32
|
},
|
|
33
|
-
themes: {
|
|
34
|
-
neutral: { paletteIndex: 0, lightModeNv: 0.95, darkModeNv: 0.1 },
|
|
35
|
-
primary: { paletteIndex: 1, lightModeNv: 0.95, darkModeNv: 0.1 },
|
|
36
|
-
secondary: { paletteIndex: 1, lightModeNv: 0.85, darkModeNv: 0.15 },
|
|
37
|
-
strong: { paletteIndex: 0, lightModeNv: 0.1, darkModeNv: 0.95 },
|
|
38
|
-
},
|
|
39
|
-
elevation: {
|
|
40
|
-
offsets: [-0.02, 0, 0.04], // [sunken, default, elevated]
|
|
41
|
-
},
|
|
42
33
|
spacing: {
|
|
43
34
|
'00': 0, // base * 0
|
|
44
35
|
'02': 2, // base * 0.25
|