@newtonedev/components 0.1.13 → 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 +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.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/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 -3
- 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 -3
- 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.map +1 -1
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts +2 -2
- package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts.map +1 -1
- package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts +2 -2
- package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts.map +1 -1
- package/dist/composites/range-inputs/Slider/Slider.styles.d.ts +2 -2
- package/dist/composites/range-inputs/Slider/Slider.styles.d.ts.map +1 -1
- package/dist/index.cjs +903 -396
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +830 -344
- 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 -4
- 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/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 +5 -3
- 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 +3 -6
- 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 +9 -1
- 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 +1 -1
- package/src/composites/actions/Button/Button.styles.ts +71 -55
- package/src/composites/actions/Button/Button.tsx +34 -13
- 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 -6
- package/src/composites/form-controls/Select/SelectOption.tsx +10 -7
- package/src/composites/form-controls/TextInput/TextInput.styles.ts +12 -8
- package/src/composites/form-controls/TextInput/TextInput.tsx +7 -4
- 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 -3
- package/src/composites/layout/AppShell/AppShell.tsx +6 -2
- package/src/composites/layout/Card/Card.styles.ts +10 -4
- package/src/composites/layout/Card/Card.tsx +4 -3
- 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 +5 -5
- package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.tsx +4 -3
- package/src/composites/range-inputs/HueSlider/HueSlider.styles.ts +7 -7
- package/src/composites/range-inputs/HueSlider/HueSlider.tsx +1 -1
- package/src/composites/range-inputs/Slider/Slider.styles.ts +9 -9
- package/src/composites/range-inputs/Slider/Slider.tsx +1 -1
- package/src/index.ts +43 -9
- package/src/primitives/Frame/Frame.styles.ts +55 -12
- package/src/primitives/Frame/Frame.tsx +138 -140
- package/src/primitives/Frame/Frame.types.ts +119 -1
- package/src/primitives/Frame/index.ts +4 -0
- package/src/primitives/Icon/Icon.tsx +9 -6
- package/src/primitives/Icon/Icon.types.ts +2 -2
- package/src/primitives/Text/Text.spans.ts +9 -5
- package/src/primitives/Text/Text.tsx +26 -15
- package/src/primitives/Text/Text.types.ts +3 -6
- package/src/primitives/Wrapper/Wrapper.styles.ts +32 -0
- package/src/primitives/Wrapper/Wrapper.tsx +22 -3
- package/src/primitives/Wrapper/Wrapper.types.ts +45 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { View, ViewStyle, GestureResponderEvent } from 'react-native';
|
|
2
|
-
import type { FrameElevation } from 'newtone-api';
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { Text, type TextStyle } from 'react-native';
|
|
3
|
-
import { useTokens } from 'newtone-api';
|
|
3
|
+
import { useTokens, useFrameContext } from 'newtone-api';
|
|
4
4
|
import type { IconProps } from './Icon.types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -17,8 +17,8 @@ import type { IconProps } from './Icon.types';
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export function Icon({
|
|
20
|
-
name,
|
|
21
|
-
size,
|
|
20
|
+
name = 'add',
|
|
21
|
+
size = 24,
|
|
22
22
|
opticalSize,
|
|
23
23
|
fill = 0,
|
|
24
24
|
color,
|
|
@@ -32,6 +32,9 @@ export function Icon({
|
|
|
32
32
|
}: IconProps) {
|
|
33
33
|
// Inherit tokens from nearest parent Frame via FrameContext.
|
|
34
34
|
const tokens = useTokens();
|
|
35
|
+
const frameCtx = useFrameContext();
|
|
36
|
+
const resolvedTheme = frameCtx?.theme ?? 'primary';
|
|
37
|
+
const resolvedAppearance = frameCtx?.appearance ?? 'main';
|
|
35
38
|
|
|
36
39
|
// Build the icon's style from the theme tokens and props.
|
|
37
40
|
// Wrapped in useMemo so it only recalculates when the inputs change,
|
|
@@ -53,8 +56,8 @@ export function Icon({
|
|
|
53
56
|
// Use explicit opticalSize if provided, otherwise auto-calculate from fontSize.
|
|
54
57
|
const opsz = opticalSize ?? getOpticalSize(fontSize);
|
|
55
58
|
|
|
56
|
-
// Use the provided color, or fall back to the theme
|
|
57
|
-
const iconColor = color ?? tokens.
|
|
59
|
+
// Use the provided color, or fall back to the inherited theme/appearance text color.
|
|
60
|
+
const iconColor = color ?? tokens.colors[resolvedTheme][resolvedAppearance].fontPrimary;
|
|
58
61
|
|
|
59
62
|
// Build the font family name from the theme's icon variant setting.
|
|
60
63
|
// Example: variant 'rounded' → 'Material Symbols Rounded'
|
|
@@ -80,7 +83,7 @@ export function Icon({
|
|
|
80
83
|
fontVariationSettings, // web-only: controls the variable font axes listed above
|
|
81
84
|
...style,
|
|
82
85
|
} as TextStyle; // Cast needed because web-only properties aren't in RN's type definitions
|
|
83
|
-
}, [tokens, size, opticalSize, fill, color, style]);
|
|
86
|
+
}, [tokens, size, opticalSize, fill, color, style, resolvedTheme, resolvedAppearance]);
|
|
84
87
|
|
|
85
88
|
// Material Symbols renders icons as text ligatures — the icon name (like "home")
|
|
86
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 'newtone-api';
|
|
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,
|
|
@@ -4,8 +4,10 @@ import type { LayoutChangeEvent, TextStyle } from 'react-native';
|
|
|
4
4
|
import { resolveResponsiveSize, estimateLineWidths, BREAKPOINT_ROLE_SCALE, scaleRoleStep, REFERENCE_LINE_HEIGHT_RATIO, buildFontFeatureSettings, SEMANTIC_WEIGHT_MAP, ROLE_DEFAULT_WEIGHTS } from '@newtonedev/fonts';
|
|
5
5
|
import { useTokens } from 'newtone-api';
|
|
6
6
|
import { useNewtoneTheme } from 'newtone-api';
|
|
7
|
+
import { useFrameContext } from 'newtone-api';
|
|
7
8
|
import type { UseTokensResult } from 'newtone-api';
|
|
8
|
-
import type {
|
|
9
|
+
import type { ThemeName, AppearanceName } from 'newtone-api';
|
|
10
|
+
import type { TextProps, TextColor, TextRole } from './Text.types';
|
|
9
11
|
import { useLocalCalibration } from 'newtone-api';
|
|
10
12
|
import { useTypographyCalibrations } from 'newtone-api';
|
|
11
13
|
import { enqueueObservation } from 'newtone-api';
|
|
@@ -21,21 +23,27 @@ export const TextScopeContext = createContext<{
|
|
|
21
23
|
readonly weights: { readonly regular: number; readonly medium: number; readonly bold: number };
|
|
22
24
|
} | null>(null);
|
|
23
25
|
|
|
26
|
+
/** Roles considered "large text" — accent uses accentLarge (lighter). */
|
|
27
|
+
const LARGE_TEXT_ROLES = new Set<TextRole>(['headline', 'title', 'heading', 'subheading']);
|
|
28
|
+
|
|
24
29
|
/**
|
|
25
30
|
* Resolve a semantic text color to a hex string from the current tokens.
|
|
26
|
-
* Neutral
|
|
31
|
+
* Neutral colors use the inherited theme/appearance from the nearest Frame.
|
|
32
|
+
* Accent uses accentLarge (large text) or accentSmall (small text) from the inherited theme/appearance.
|
|
27
33
|
*/
|
|
28
|
-
export function resolveTextColor(
|
|
29
|
-
|
|
34
|
+
export function resolveTextColor(
|
|
35
|
+
color: TextColor,
|
|
36
|
+
tokens: UseTokensResult,
|
|
37
|
+
theme: ThemeName = 'primary',
|
|
38
|
+
appearance: AppearanceName = 'main',
|
|
39
|
+
role: TextRole = 'body',
|
|
40
|
+
): string {
|
|
30
41
|
switch (color) {
|
|
31
|
-
case 'primary': return tokens.
|
|
32
|
-
case 'secondary': return tokens.
|
|
33
|
-
case 'tertiary': return tokens.
|
|
34
|
-
case 'disabled': return tokens.
|
|
35
|
-
case 'accent': return tokens.
|
|
36
|
-
case 'success': return tokens.success.fill[gamut];
|
|
37
|
-
case 'warning': return tokens.warning.fill[gamut];
|
|
38
|
-
case 'error': return tokens.error.fill[gamut];
|
|
42
|
+
case 'primary': return tokens.colors[theme][appearance].fontPrimary;
|
|
43
|
+
case 'secondary': return tokens.colors[theme][appearance].fontSecondary;
|
|
44
|
+
case 'tertiary': return tokens.colors[theme][appearance].fontTertiary;
|
|
45
|
+
case 'disabled': return tokens.colors[theme][appearance].fontDisabled;
|
|
46
|
+
case 'accent': return tokens.colors[theme][appearance][LARGE_TEXT_ROLES.has(role) ? 'accentLarge' : 'accentSmall'];
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
|
|
@@ -90,7 +98,7 @@ function TextBase({
|
|
|
90
98
|
weight: weightOverride,
|
|
91
99
|
align,
|
|
92
100
|
numberOfLines,
|
|
93
|
-
elevation
|
|
101
|
+
elevation,
|
|
94
102
|
style,
|
|
95
103
|
accessibilityRole: accessibilityRoleOverride,
|
|
96
104
|
testID,
|
|
@@ -102,6 +110,9 @@ function TextBase({
|
|
|
102
110
|
}: TextProps) {
|
|
103
111
|
const tokens = useTokens(elevation);
|
|
104
112
|
const { config, reportingEndpoint } = useNewtoneTheme();
|
|
113
|
+
const frameCtx = useFrameContext();
|
|
114
|
+
const resolvedTheme: ThemeName = frameCtx?.theme ?? 'primary';
|
|
115
|
+
const resolvedAppearance: AppearanceName = frameCtx?.appearance ?? 'main';
|
|
105
116
|
|
|
106
117
|
const size = sizeOverride ?? 'md';
|
|
107
118
|
const fontSlot = tokens.typography.fonts[scope];
|
|
@@ -195,13 +206,13 @@ function TextBase({
|
|
|
195
206
|
fontFamily: fontSlot.family,
|
|
196
207
|
fontSize: activeStep.fontSize,
|
|
197
208
|
fontWeight: String(resolvedFontWeight) as TextStyle['fontWeight'],
|
|
198
|
-
color: resolveTextColor(color, tokens),
|
|
209
|
+
color: resolveTextColor(color, tokens, resolvedTheme, resolvedAppearance, role),
|
|
199
210
|
lineHeight: correctedLineHeight,
|
|
200
211
|
textAlign: align,
|
|
201
212
|
...(vcOffset !== 0 ? { transform: [{ translateY: vcOffset }] } : {}),
|
|
202
213
|
...(featureSettings ? { fontFeatureSettings: featureSettings } as any : {}),
|
|
203
214
|
};
|
|
204
|
-
}, [tokens, fontSlot, step, resolvedStep, responsive, isAdaptive, resolvedFontWeight, color, align, config.typography.fontMetrics, centerVertically, features]);
|
|
215
|
+
}, [tokens, fontSlot, step, resolvedStep, responsive, isAdaptive, resolvedFontWeight, color, align, config.typography.fontMetrics, centerVertically, features, resolvedTheme, resolvedAppearance]);
|
|
205
216
|
|
|
206
217
|
// Auto-derive accessibility role and heading level for heading-like typography roles.
|
|
207
218
|
// react-native-web uses aria-level to render the correct <h1>/<h2>/<h3> element.
|
|
@@ -8,7 +8,7 @@ export type TextSize = 'sm' | 'md' | 'lg';
|
|
|
8
8
|
export type TextWeight = 'regular' | 'medium' | 'bold';
|
|
9
9
|
|
|
10
10
|
/** Semantic text color tokens — resolved from the current theme's token palette. */
|
|
11
|
-
export type TextColor = 'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent'
|
|
11
|
+
export type TextColor = 'primary' | 'secondary' | 'tertiary' | 'disabled' | 'accent';
|
|
12
12
|
|
|
13
13
|
/** Font scope — selects which font family slot to use. @default 'main' */
|
|
14
14
|
export type TextScope = 'main' | 'display' | 'mono' | 'currency';
|
|
@@ -66,10 +66,7 @@ export interface TextProps {
|
|
|
66
66
|
* - `'secondary'` — Subdued/muted text (captions, labels)
|
|
67
67
|
* - `'tertiary'` — Hints, placeholders
|
|
68
68
|
* - `'disabled'` — Disabled text elements
|
|
69
|
-
* - `'accent'` — Accent
|
|
70
|
-
* - `'success'` — Success palette color for positive indicators
|
|
71
|
-
* - `'warning'` — Warning palette color for caution indicators
|
|
72
|
-
* - `'error'` — Error palette color for destructive/error indicators
|
|
69
|
+
* - `'accent'` — Accent color from the inherited theme/appearance (accentLarge for large text, accentSmall for small text)
|
|
73
70
|
*
|
|
74
71
|
* @default 'primary'
|
|
75
72
|
*/
|
|
@@ -89,7 +86,7 @@ export interface TextProps {
|
|
|
89
86
|
/** Maximum number of lines before truncation with ellipsis. When omitted, text wraps freely. */
|
|
90
87
|
readonly numberOfLines?: number;
|
|
91
88
|
|
|
92
|
-
/** Elevation level for token computation.
|
|
89
|
+
/** Elevation level for token computation. When omitted, inherits from nearest parent Frame. */
|
|
93
90
|
readonly elevation?: ElevationLevel;
|
|
94
91
|
|
|
95
92
|
/** Style overrides (applied last). Supports a single style or an array of styles. */
|
|
@@ -8,6 +8,9 @@ import type {
|
|
|
8
8
|
PaddingProp,
|
|
9
9
|
GapProp,
|
|
10
10
|
SizingMode,
|
|
11
|
+
PositionType,
|
|
12
|
+
OffsetValue,
|
|
13
|
+
OverflowMode,
|
|
11
14
|
} from '../Frame/Frame.types';
|
|
12
15
|
import {
|
|
13
16
|
resolvePadding,
|
|
@@ -33,6 +36,16 @@ export interface WrapperStyleInput {
|
|
|
33
36
|
readonly maxWidth?: number;
|
|
34
37
|
readonly minHeight?: number;
|
|
35
38
|
readonly maxHeight?: number;
|
|
39
|
+
|
|
40
|
+
// Positioning
|
|
41
|
+
readonly position?: PositionType;
|
|
42
|
+
readonly top?: OffsetValue;
|
|
43
|
+
readonly right?: OffsetValue;
|
|
44
|
+
readonly bottom?: OffsetValue;
|
|
45
|
+
readonly left?: OffsetValue;
|
|
46
|
+
readonly zIndex?: number;
|
|
47
|
+
readonly overflow?: OverflowMode;
|
|
48
|
+
readonly opacity?: number;
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
/**
|
|
@@ -58,6 +71,14 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
58
71
|
maxWidth,
|
|
59
72
|
minHeight,
|
|
60
73
|
maxHeight,
|
|
74
|
+
position,
|
|
75
|
+
top,
|
|
76
|
+
right,
|
|
77
|
+
bottom,
|
|
78
|
+
left,
|
|
79
|
+
zIndex,
|
|
80
|
+
overflow,
|
|
81
|
+
opacity,
|
|
61
82
|
} = input;
|
|
62
83
|
|
|
63
84
|
// We build styles as a plain object first, then validate it through
|
|
@@ -107,6 +128,17 @@ export function getWrapperStyles(input: WrapperStyleInput): ViewStyle {
|
|
|
107
128
|
if (minHeight !== undefined) container.minHeight = minHeight;
|
|
108
129
|
if (maxHeight !== undefined) container.maxHeight = maxHeight;
|
|
109
130
|
|
|
131
|
+
// ── Positioning ──
|
|
132
|
+
// Set CSS position mode and offsets for absolute/fixed/sticky positioning.
|
|
133
|
+
if (position) container.position = position;
|
|
134
|
+
if (top !== undefined) container.top = top;
|
|
135
|
+
if (right !== undefined) container.right = right;
|
|
136
|
+
if (bottom !== undefined) container.bottom = bottom;
|
|
137
|
+
if (left !== undefined) container.left = left;
|
|
138
|
+
if (zIndex !== undefined) container.zIndex = zIndex;
|
|
139
|
+
if (overflow) container.overflow = overflow;
|
|
140
|
+
if (opacity !== undefined) container.opacity = opacity;
|
|
141
|
+
|
|
110
142
|
// Pass through StyleSheet.create() to validate and optimize the styles,
|
|
111
143
|
// then extract the single style object with `.c`.
|
|
112
144
|
return StyleSheet.create({ c: container as ViewStyle }).c;
|
|
@@ -44,6 +44,16 @@ export function Wrapper({
|
|
|
44
44
|
maxWidth,
|
|
45
45
|
minHeight,
|
|
46
46
|
maxHeight,
|
|
47
|
+
// Positioning
|
|
48
|
+
position,
|
|
49
|
+
top,
|
|
50
|
+
right,
|
|
51
|
+
bottom,
|
|
52
|
+
left,
|
|
53
|
+
zIndex,
|
|
54
|
+
overflow,
|
|
55
|
+
pointerEvents,
|
|
56
|
+
opacity,
|
|
47
57
|
style,
|
|
48
58
|
// Testing & platform
|
|
49
59
|
testID,
|
|
@@ -51,9 +61,8 @@ export function Wrapper({
|
|
|
51
61
|
ref,
|
|
52
62
|
}: WrapperProps) {
|
|
53
63
|
// Get the theme's design tokens so we can convert spacing names (like 'md')
|
|
54
|
-
// into pixel values.
|
|
55
|
-
|
|
56
|
-
const tokens = useTokens(1);
|
|
64
|
+
// into pixel values. Wrapper inherits elevation from FrameContext automatically.
|
|
65
|
+
const tokens = useTokens();
|
|
57
66
|
|
|
58
67
|
// Calculate the layout styles (direction, spacing, alignment, sizing).
|
|
59
68
|
// Wrapped in useMemo so it only recalculates when one of the props changes,
|
|
@@ -74,11 +83,20 @@ export function Wrapper({
|
|
|
74
83
|
maxWidth,
|
|
75
84
|
minHeight,
|
|
76
85
|
maxHeight,
|
|
86
|
+
position,
|
|
87
|
+
top,
|
|
88
|
+
right,
|
|
89
|
+
bottom,
|
|
90
|
+
left,
|
|
91
|
+
zIndex,
|
|
92
|
+
overflow,
|
|
93
|
+
opacity,
|
|
77
94
|
}),
|
|
78
95
|
[
|
|
79
96
|
tokens, direction, wrap, reverse,
|
|
80
97
|
align, justify, padding, gap,
|
|
81
98
|
width, height, minWidth, maxWidth, minHeight, maxHeight,
|
|
99
|
+
position, top, right, bottom, left, zIndex, overflow, opacity,
|
|
82
100
|
],
|
|
83
101
|
);
|
|
84
102
|
|
|
@@ -93,6 +111,7 @@ export function Wrapper({
|
|
|
93
111
|
ref={ref}
|
|
94
112
|
testID={testID}
|
|
95
113
|
nativeID={nativeID}
|
|
114
|
+
pointerEvents={pointerEvents}
|
|
96
115
|
// Wrapper is a layout-only container with no semantic meaning.
|
|
97
116
|
// "none" tells screen readers to skip this element and read its children directly.
|
|
98
117
|
accessibilityRole="none"
|
|
@@ -6,6 +6,10 @@ import type {
|
|
|
6
6
|
PaddingProp,
|
|
7
7
|
GapProp,
|
|
8
8
|
SizingMode,
|
|
9
|
+
PositionType,
|
|
10
|
+
OffsetValue,
|
|
11
|
+
OverflowMode,
|
|
12
|
+
PointerEventsMode,
|
|
9
13
|
} from '../Frame/Frame.types';
|
|
10
14
|
|
|
11
15
|
/**
|
|
@@ -131,6 +135,47 @@ export interface WrapperProps {
|
|
|
131
135
|
/** Maximum height in pixels. */
|
|
132
136
|
readonly maxHeight?: number;
|
|
133
137
|
|
|
138
|
+
// ── Positioning ──
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* CSS position mode.
|
|
142
|
+
*
|
|
143
|
+
* `'fixed'` and `'sticky'` are web-only (supported via react-native-web).
|
|
144
|
+
* React Native natively supports `'absolute'` and `'relative'`.
|
|
145
|
+
*/
|
|
146
|
+
readonly position?: PositionType;
|
|
147
|
+
|
|
148
|
+
/** Offset from the top edge. Accepts pixels (number) or percentage string. */
|
|
149
|
+
readonly top?: OffsetValue;
|
|
150
|
+
|
|
151
|
+
/** Offset from the right edge. Accepts pixels (number) or percentage string. */
|
|
152
|
+
readonly right?: OffsetValue;
|
|
153
|
+
|
|
154
|
+
/** Offset from the bottom edge. Accepts pixels (number) or percentage string. */
|
|
155
|
+
readonly bottom?: OffsetValue;
|
|
156
|
+
|
|
157
|
+
/** Offset from the left edge. Accepts pixels (number) or percentage string. */
|
|
158
|
+
readonly left?: OffsetValue;
|
|
159
|
+
|
|
160
|
+
/** Stacking order. Higher values render above lower values. */
|
|
161
|
+
readonly zIndex?: number;
|
|
162
|
+
|
|
163
|
+
/** Content overflow behavior. */
|
|
164
|
+
readonly overflow?: OverflowMode;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Controls whether the element can be the target of touch/pointer events.
|
|
168
|
+
*
|
|
169
|
+
* - `'auto'` — default, element and children receive events
|
|
170
|
+
* - `'none'` — element and children are invisible to events (pass through)
|
|
171
|
+
* - `'box-none'` — element ignores events but children can receive them
|
|
172
|
+
* - `'box-only'` — element receives events but children cannot
|
|
173
|
+
*/
|
|
174
|
+
readonly pointerEvents?: PointerEventsMode;
|
|
175
|
+
|
|
176
|
+
/** Opacity of the element (0 = fully transparent, 1 = fully opaque). */
|
|
177
|
+
readonly opacity?: number;
|
|
178
|
+
|
|
134
179
|
// ── Testing & Platform ──
|
|
135
180
|
|
|
136
181
|
/** Test identifier — maps to `data-testid` on web. Used by testing libraries. */
|