radix-native 0.0.1
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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/index.cjs +4323 -0
- package/dist/index.d.cts +861 -0
- package/dist/index.d.mts +861 -0
- package/dist/index.d.ts +861 -0
- package/dist/index.mjs +4285 -0
- package/package.json +51 -0
- package/src/components/actions/Button.tsx +337 -0
- package/src/components/actions/Checkbox.tsx +216 -0
- package/src/components/actions/CheckboxCards.tsx +257 -0
- package/src/components/actions/CheckboxGroup.tsx +249 -0
- package/src/components/actions/index.ts +4 -0
- package/src/components/layout/Box.tsx +108 -0
- package/src/components/layout/Flex.tsx +149 -0
- package/src/components/layout/Grid.tsx +224 -0
- package/src/components/layout/index.ts +9 -0
- package/src/components/playground/ThemeControls.tsx +456 -0
- package/src/components/playground/index.ts +1 -0
- package/src/components/typography/Blockquote.tsx +137 -0
- package/src/components/typography/Code.tsx +164 -0
- package/src/components/typography/Em.tsx +68 -0
- package/src/components/typography/Heading.tsx +136 -0
- package/src/components/typography/Kbd.tsx +162 -0
- package/src/components/typography/Link.tsx +173 -0
- package/src/components/typography/Quote.tsx +71 -0
- package/src/components/typography/Strong.tsx +70 -0
- package/src/components/typography/Text.tsx +140 -0
- package/src/components/typography/index.ts +9 -0
- package/src/hooks/useResolveColor.ts +24 -0
- package/src/hooks/useThemeContext.ts +11 -0
- package/src/index.ts +63 -0
- package/src/theme/Theme.tsx +12 -0
- package/src/theme/ThemeContext.ts +4 -0
- package/src/theme/ThemeImpl.tsx +54 -0
- package/src/theme/ThemeRoot.tsx +65 -0
- package/src/theme/createTheme.tsx +17 -0
- package/src/theme/resolveGrayColor.ts +38 -0
- package/src/theme/theme.types.ts +95 -0
- package/src/tokens/colors/amber.ts +28 -0
- package/src/tokens/colors/blue.ts +28 -0
- package/src/tokens/colors/bronze.ts +28 -0
- package/src/tokens/colors/brown.ts +28 -0
- package/src/tokens/colors/crimson.ts +28 -0
- package/src/tokens/colors/cyan.ts +28 -0
- package/src/tokens/colors/gold.ts +28 -0
- package/src/tokens/colors/grass.ts +28 -0
- package/src/tokens/colors/gray.ts +28 -0
- package/src/tokens/colors/green.ts +28 -0
- package/src/tokens/colors/index.ts +36 -0
- package/src/tokens/colors/indigo.ts +28 -0
- package/src/tokens/colors/iris.ts +28 -0
- package/src/tokens/colors/jade.ts +28 -0
- package/src/tokens/colors/lime.ts +28 -0
- package/src/tokens/colors/mauve.ts +28 -0
- package/src/tokens/colors/mint.ts +28 -0
- package/src/tokens/colors/olive.ts +28 -0
- package/src/tokens/colors/orange.ts +28 -0
- package/src/tokens/colors/pink.ts +28 -0
- package/src/tokens/colors/plum.ts +28 -0
- package/src/tokens/colors/purple.ts +28 -0
- package/src/tokens/colors/red.ts +28 -0
- package/src/tokens/colors/ruby.ts +28 -0
- package/src/tokens/colors/sage.ts +28 -0
- package/src/tokens/colors/sand.ts +28 -0
- package/src/tokens/colors/sky.ts +28 -0
- package/src/tokens/colors/slate.ts +28 -0
- package/src/tokens/colors/teal.ts +28 -0
- package/src/tokens/colors/tomato.ts +28 -0
- package/src/tokens/colors/types.ts +69 -0
- package/src/tokens/colors/violet.ts +28 -0
- package/src/tokens/colors/yellow.ts +28 -0
- package/src/tokens/index.ts +5 -0
- package/src/tokens/radius.ts +56 -0
- package/src/tokens/scaling.ts +10 -0
- package/src/tokens/spacing.ts +21 -0
- package/src/tokens/typography.ts +60 -0
- package/src/utils/applyScaling.ts +6 -0
- package/src/utils/classicEffect.ts +46 -0
- package/src/utils/resolveColor.ts +69 -0
- package/src/utils/resolveSpace.ts +13 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type RadiusToken = 'none' | 'small' | 'medium' | 'large' | 'full'
|
|
2
|
+
|
|
3
|
+
/** Radius level (1–6) — components choose the level that fits their visual size. */
|
|
4
|
+
export type RadiusLevel = 1 | 2 | 3 | 4 | 5 | 6
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base radius values in pixels at token='medium', scaling=1.
|
|
8
|
+
* Final radius = BASE_RADIUS[level] * RADIUS_FACTOR[token]
|
|
9
|
+
*/
|
|
10
|
+
const BASE_RADIUS: Record<RadiusLevel, number> = {
|
|
11
|
+
1: 3,
|
|
12
|
+
2: 4,
|
|
13
|
+
3: 6,
|
|
14
|
+
4: 8,
|
|
15
|
+
5: 12,
|
|
16
|
+
6: 16,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Multiplier per radius token.
|
|
21
|
+
* none=0, small=0.75, medium=1, large=1.5, full=1.5
|
|
22
|
+
*/
|
|
23
|
+
const RADIUS_FACTOR: Record<RadiusToken, number> = {
|
|
24
|
+
none: 0,
|
|
25
|
+
small: 0.75,
|
|
26
|
+
medium: 1,
|
|
27
|
+
large: 1.5,
|
|
28
|
+
full: 1.5,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Pill radius per token. Only 'full' produces a pill shape (9999); all others are 0.
|
|
33
|
+
*/
|
|
34
|
+
const RADIUS_FULL: Record<RadiusToken, number> = {
|
|
35
|
+
none: 0,
|
|
36
|
+
small: 0,
|
|
37
|
+
medium: 0,
|
|
38
|
+
large: 0,
|
|
39
|
+
full: 9999,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns the border radius in pixels for a given token and level.
|
|
44
|
+
* Each component picks the level that matches its visual size.
|
|
45
|
+
*/
|
|
46
|
+
export function getRadius(token: RadiusToken, level: RadiusLevel): number {
|
|
47
|
+
return Math.round(BASE_RADIUS[level] * RADIUS_FACTOR[token])
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns the full (pill) radius for a given token.
|
|
52
|
+
* Use this for components that should be fully rounded when token='full'.
|
|
53
|
+
*/
|
|
54
|
+
export function getFullRadius(token: RadiusToken): number {
|
|
55
|
+
return RADIUS_FULL[token]
|
|
56
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ScalingMode = '90%' | '95%' | '100%' | '105%' | '110%'
|
|
2
|
+
|
|
3
|
+
/** Multiplier applied to space, fontSize and lineHeight */
|
|
4
|
+
export const scalingMap: Record<ScalingMode, number> = {
|
|
5
|
+
'90%': 0.9,
|
|
6
|
+
'95%': 0.95,
|
|
7
|
+
'100%': 1.0,
|
|
8
|
+
'105%': 1.05,
|
|
9
|
+
'110%': 1.1,
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type SpaceToken = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Margin token — superset of SpaceToken that includes negative values.
|
|
5
|
+
* Matches Radix's marginValues which include '-1' through '-9'.
|
|
6
|
+
*/
|
|
7
|
+
export type MarginToken = -9 | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
8
|
+
|
|
9
|
+
/** Base space scale in pixels (before scaling is applied) */
|
|
10
|
+
export const space: Record<SpaceToken, number> = {
|
|
11
|
+
0: 0,
|
|
12
|
+
1: 4,
|
|
13
|
+
2: 8,
|
|
14
|
+
3: 12,
|
|
15
|
+
4: 16,
|
|
16
|
+
5: 24,
|
|
17
|
+
6: 32,
|
|
18
|
+
7: 40,
|
|
19
|
+
8: 48,
|
|
20
|
+
9: 64,
|
|
21
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type FontSizeToken = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
2
|
+
|
|
3
|
+
/** Base font size scale in pixels (before scaling is applied) */
|
|
4
|
+
export const fontSize: Record<FontSizeToken, number> = {
|
|
5
|
+
1: 12,
|
|
6
|
+
2: 14,
|
|
7
|
+
3: 16,
|
|
8
|
+
4: 18,
|
|
9
|
+
5: 20,
|
|
10
|
+
6: 24,
|
|
11
|
+
7: 28,
|
|
12
|
+
8: 35,
|
|
13
|
+
9: 60,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Base line height scale in pixels (before scaling is applied) */
|
|
17
|
+
export const lineHeight: Record<FontSizeToken, number> = {
|
|
18
|
+
1: 16,
|
|
19
|
+
2: 20,
|
|
20
|
+
3: 24,
|
|
21
|
+
4: 26,
|
|
22
|
+
5: 28,
|
|
23
|
+
6: 30,
|
|
24
|
+
7: 36,
|
|
25
|
+
8: 40,
|
|
26
|
+
9: 60,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Heading line heights in pixels (before scaling).
|
|
31
|
+
* Tighter than body line heights for sizes 2–5.
|
|
32
|
+
*/
|
|
33
|
+
export const headingLineHeight: Record<FontSizeToken, number> = {
|
|
34
|
+
1: 16,
|
|
35
|
+
2: 18,
|
|
36
|
+
3: 22,
|
|
37
|
+
4: 24,
|
|
38
|
+
5: 26,
|
|
39
|
+
6: 30,
|
|
40
|
+
7: 36,
|
|
41
|
+
8: 40,
|
|
42
|
+
9: 60,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Letter spacing as em multipliers per size token.
|
|
47
|
+
* In RN, letterSpacing is in pixels — multiply by the resolved fontSize:
|
|
48
|
+
* letterSpacing = letterSpacingEm[size] * resolvedFontSize
|
|
49
|
+
*/
|
|
50
|
+
export const letterSpacingEm: Record<FontSizeToken, number> = {
|
|
51
|
+
1: 0.0025,
|
|
52
|
+
2: 0,
|
|
53
|
+
3: 0,
|
|
54
|
+
4: -0.0025,
|
|
55
|
+
5: -0.005,
|
|
56
|
+
6: -0.00625,
|
|
57
|
+
7: -0.0075,
|
|
58
|
+
8: -0.01,
|
|
59
|
+
9: -0.025,
|
|
60
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { scalingMap, type ScalingMode } from '../tokens/scaling'
|
|
2
|
+
|
|
3
|
+
/** Applies the scaling multiplier to a base pixel value and rounds to nearest integer. */
|
|
4
|
+
export function applyScaling(value: number, scaling: ScalingMode): number {
|
|
5
|
+
return Math.round(value * scalingMap[scaling])
|
|
6
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
import type { ViewStyle } from 'react-native'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns ViewStyle that approximates the Radix "classic" 3D effect
|
|
6
|
+
* using only native RN shadow capabilities.
|
|
7
|
+
*
|
|
8
|
+
* Radix CSS uses linear-gradient overlays + inset box-shadows which
|
|
9
|
+
* are not available in RN. We approximate with an outer drop shadow
|
|
10
|
+
* and pressed state removal (simulates "pushed in").
|
|
11
|
+
*/
|
|
12
|
+
export function getClassicEffect(
|
|
13
|
+
appearance: 'light' | 'dark',
|
|
14
|
+
options?: { pressed?: boolean; disabled?: boolean },
|
|
15
|
+
): ViewStyle {
|
|
16
|
+
const isLight = appearance === 'light'
|
|
17
|
+
const pressed = options?.pressed ?? false
|
|
18
|
+
const isDisabled = options?.disabled ?? false
|
|
19
|
+
|
|
20
|
+
// Disabled: no shadow at all — keep it flat like the other disabled variants
|
|
21
|
+
if (isDisabled) return {}
|
|
22
|
+
|
|
23
|
+
// Pressed: remove shadow for "pushed in" feel
|
|
24
|
+
if (pressed) {
|
|
25
|
+
return Platform.select({
|
|
26
|
+
ios: {
|
|
27
|
+
shadowColor: 'transparent',
|
|
28
|
+
shadowOffset: { width: 0, height: 0 },
|
|
29
|
+
shadowOpacity: 0,
|
|
30
|
+
shadowRadius: 0,
|
|
31
|
+
},
|
|
32
|
+
default: { elevation: 0 },
|
|
33
|
+
})!
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Normal resting state — subtle drop shadow
|
|
37
|
+
return Platform.select({
|
|
38
|
+
ios: {
|
|
39
|
+
shadowColor: '#000',
|
|
40
|
+
shadowOffset: { width: 0, height: 1 },
|
|
41
|
+
shadowOpacity: isLight ? 0.15 : 0.3,
|
|
42
|
+
shadowRadius: 2,
|
|
43
|
+
},
|
|
44
|
+
default: { elevation: 2 },
|
|
45
|
+
})!
|
|
46
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tomato, red, ruby, crimson, pink, plum, purple, violet,
|
|
3
|
+
iris, indigo, blue, cyan, teal, jade, green, grass,
|
|
4
|
+
bronze, gold, brown, orange, amber, yellow, lime, mint, sky,
|
|
5
|
+
gray, mauve, slate, sage, olive, sand,
|
|
6
|
+
} from '../tokens/colors'
|
|
7
|
+
import type { AccentColor, GrayColor, ColorScaleWithModes } from '../tokens/colors/types'
|
|
8
|
+
import type { ThemeColor, ColorOverrides } from '../theme/theme.types'
|
|
9
|
+
|
|
10
|
+
const colorMap: Record<string, ColorScaleWithModes> = {
|
|
11
|
+
tomato, red, ruby, crimson, pink, plum, purple, violet,
|
|
12
|
+
iris, indigo, blue, cyan, teal, jade, green, grass,
|
|
13
|
+
bronze, gold, brown, orange, amber, yellow, lime, mint, sky,
|
|
14
|
+
gray, mauve, slate, sage, olive, sand,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves a ThemeColor token to a hex string.
|
|
19
|
+
*
|
|
20
|
+
* - `'accent-9'` → step 9 of the active accent color
|
|
21
|
+
* - `'accent-a9'` → alpha step a9 of the active accent color
|
|
22
|
+
* - `'accent-contrast'` → contrast color (text over step 9 background)
|
|
23
|
+
* - `'accent-surface'` → translucent tinted surface
|
|
24
|
+
* - `'gray-9'` → step 9 of the resolved gray color
|
|
25
|
+
* - `'blue-9'` → step 9 of the blue scale (exact, not aliased)
|
|
26
|
+
* - `'#ff0000'` → returned as-is (escape hatch)
|
|
27
|
+
*/
|
|
28
|
+
export function resolveColor(
|
|
29
|
+
color: ThemeColor,
|
|
30
|
+
appearance: 'light' | 'dark',
|
|
31
|
+
accentColor: AccentColor,
|
|
32
|
+
resolvedGrayColor: GrayColor,
|
|
33
|
+
colorOverrides?: ColorOverrides,
|
|
34
|
+
): string {
|
|
35
|
+
let colorName: string
|
|
36
|
+
let step: string
|
|
37
|
+
|
|
38
|
+
if (color.startsWith('accent-')) {
|
|
39
|
+
colorName = accentColor
|
|
40
|
+
step = color.slice('accent-'.length)
|
|
41
|
+
} else if (color.startsWith('gray-')) {
|
|
42
|
+
colorName = resolvedGrayColor
|
|
43
|
+
step = color.slice('gray-'.length)
|
|
44
|
+
} else {
|
|
45
|
+
// Named color: 'blue-9', 'tomato-a3', 'indigo-contrast', etc.
|
|
46
|
+
const dashIdx = color.lastIndexOf('-')
|
|
47
|
+
if (dashIdx <= 0) return color as string
|
|
48
|
+
colorName = color.slice(0, dashIdx)
|
|
49
|
+
step = color.slice(dashIdx + 1)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check overrides first (per-scale, per-mode — like CSS custom properties in Radix web)
|
|
53
|
+
if (colorOverrides) {
|
|
54
|
+
const scaleOverride = colorOverrides[colorName as keyof ColorOverrides]
|
|
55
|
+
if (scaleOverride) {
|
|
56
|
+
const modeOverride = scaleOverride[appearance]
|
|
57
|
+
if (modeOverride) {
|
|
58
|
+
const value = (modeOverride as Record<string, string>)[step]
|
|
59
|
+
if (value !== undefined) return value
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Fall back to built-in scale
|
|
65
|
+
const scale = colorMap[colorName]?.[appearance]
|
|
66
|
+
if (!scale) return color as string
|
|
67
|
+
|
|
68
|
+
return (scale as unknown as Record<string, string>)[step] ?? (color as string)
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { space, type SpaceToken, type MarginToken } from '../tokens/spacing'
|
|
2
|
+
import { scalingMap, type ScalingMode } from '../tokens/scaling'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the resolved pixel value for a SpaceToken or MarginToken with scaling applied.
|
|
6
|
+
* Negative margin tokens return a negative pixel value using the absolute space scale.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveSpace(token: MarginToken, scaling: ScalingMode): number {
|
|
9
|
+
if (token === 0) return 0
|
|
10
|
+
const sign = token < 0 ? -1 : 1
|
|
11
|
+
const abs = Math.abs(token) as SpaceToken
|
|
12
|
+
return sign * Math.round(space[abs] * scalingMap[scaling])
|
|
13
|
+
}
|