@decoda-ui/mobile 0.1.0

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.
@@ -0,0 +1,12 @@
1
+ export type ButtonTone = 'primary' | 'secondary' | 'ghost' | 'destructive';
2
+ export type ButtonSize = 'small' | 'medium' | 'large';
3
+ export interface ButtonProps {
4
+ label: string;
5
+ onPress: () => void;
6
+ tone?: ButtonTone;
7
+ size?: ButtonSize;
8
+ disabled?: boolean;
9
+ loading?: boolean;
10
+ }
11
+ /** Complete native action; label, busy state and touch target stay in sync. */
12
+ export declare function Button({ label, onPress, tone, size, disabled, loading }: ButtonProps): import("react").JSX.Element;
package/dist/Button.js ADDED
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ActivityIndicator } from 'react-native';
3
+ import { useTheme } from '@tamagui/core';
4
+ import { cifraLightColors } from '@decoda-ui/tokens';
5
+ import { ButtonFrame, ButtonLabel } from './primitives.js';
6
+ /** Complete native action; label, busy state and touch target stay in sync. */
7
+ export function Button({ label, onPress, tone = 'primary', size = 'medium', disabled = false, loading = false }) {
8
+ const theme = useTheme();
9
+ const unavailable = disabled || loading;
10
+ const activityColor = tone === 'primary'
11
+ ? theme.primaryForeground?.val ?? cifraLightColors.primaryForeground
12
+ : theme.foreground?.val ?? cifraLightColors.foreground;
13
+ return (_jsxs(ButtonFrame, { tone: tone, size: size, onPress: onPress, disabled: unavailable, accessibilityRole: "button", accessibilityLabel: label, accessibilityState: { disabled: unavailable, busy: loading }, flexDirection: "row", gap: "$sm", children: [loading && _jsx(ActivityIndicator, { size: "small", color: activityColor }), _jsx(ButtonLabel, { tone: tone, children: loading ? 'Procesando…' : label })] }));
14
+ }
@@ -0,0 +1,10 @@
1
+ export interface ShareBarProps {
2
+ label: string;
3
+ /** A share of the whole, from 0 to 1. Out-of-range values are clamped. */
4
+ share: number;
5
+ /** Optional second share, shown as a narrow marker. */
6
+ tick?: number | null;
7
+ covered?: boolean;
8
+ }
9
+ /** Cifra's thin annual progress track, available to screen readers. */
10
+ export declare function ShareBar({ label, share, tick, covered }: ShareBarProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { View } from 'react-native';
3
+ import { useTheme } from '@tamagui/core';
4
+ import { cifraLightColors, sharePercent } from '@decoda-ui/tokens';
5
+ /** Cifra's thin annual progress track, available to screen readers. */
6
+ export function ShareBar({ label, share, tick, covered = false }) {
7
+ const theme = useTheme();
8
+ const percent = sharePercent(share);
9
+ const tickPercent = tick == null ? null : sharePercent(tick);
10
+ return (_jsxs(View, { accessibilityRole: "progressbar", accessibilityLabel: label, accessibilityValue: { min: 0, max: 100, now: Math.round(percent) }, style: { height: 8, borderRadius: 999, backgroundColor: theme.muted?.val ?? cifraLightColors.muted }, children: [_jsx(View, { style: {
11
+ width: `${percent}%`, height: 8, borderRadius: 999,
12
+ backgroundColor: covered ? theme.success?.val ?? cifraLightColors.success : theme.warning?.val ?? cifraLightColors.warning
13
+ } }), tickPercent != null && _jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
14
+ position: 'absolute', left: `${tickPercent}%`, top: -4, width: 2, height: 16,
15
+ backgroundColor: theme.foreground?.val ?? cifraLightColors.foreground,
16
+ transform: [{ translateX: -1 }], borderRadius: 1
17
+ } })] }));
18
+ }
@@ -0,0 +1,298 @@
1
+ import { type ColorRoles, type ThemeOverrides } from '@decoda-ui/tokens';
2
+ export interface DecodaConfigOptions {
3
+ light?: ThemeOverrides;
4
+ /** Tamagui themes can swap colors; foundational scales are shared across modes. */
5
+ dark?: {
6
+ color?: Partial<ColorRoles>;
7
+ };
8
+ }
9
+ /** A fresh config per app allows branding without changing the library. */
10
+ export declare function createDecodaConfig(options?: DecodaConfigOptions): import("@tamagui/core").TamaguiInternalConfig<{
11
+ color: {};
12
+ space: {
13
+ true: import("@tamagui/core").Variable<number>;
14
+ none: import("@tamagui/core").Variable<number>;
15
+ xxs: import("@tamagui/core").Variable<number>;
16
+ xs: import("@tamagui/core").Variable<number>;
17
+ sm: import("@tamagui/core").Variable<number>;
18
+ md: import("@tamagui/core").Variable<number>;
19
+ lg: import("@tamagui/core").Variable<number>;
20
+ xl: import("@tamagui/core").Variable<number>;
21
+ "2xl": import("@tamagui/core").Variable<number>;
22
+ "3xl": import("@tamagui/core").Variable<number>;
23
+ "4xl": import("@tamagui/core").Variable<number>;
24
+ "5xl": import("@tamagui/core").Variable<number>;
25
+ "6xl": import("@tamagui/core").Variable<number>;
26
+ };
27
+ size: {
28
+ true: import("@tamagui/core").Variable<number>;
29
+ sm: import("@tamagui/core").Variable<number>;
30
+ md: import("@tamagui/core").Variable<number>;
31
+ touch: import("@tamagui/core").Variable<number>;
32
+ lg: import("@tamagui/core").Variable<number>;
33
+ xl: import("@tamagui/core").Variable<number>;
34
+ };
35
+ radius: {
36
+ true: import("@tamagui/core").Variable<number>;
37
+ none: import("@tamagui/core").Variable<number>;
38
+ xs: import("@tamagui/core").Variable<number>;
39
+ sm: import("@tamagui/core").Variable<number>;
40
+ md: import("@tamagui/core").Variable<number>;
41
+ lg: import("@tamagui/core").Variable<number>;
42
+ xl: import("@tamagui/core").Variable<number>;
43
+ "2xl": import("@tamagui/core").Variable<number>;
44
+ pill: import("@tamagui/core").Variable<number>;
45
+ };
46
+ zIndex: {
47
+ base: import("@tamagui/core").Variable<number>;
48
+ floating: import("@tamagui/core").Variable<number>;
49
+ modal: import("@tamagui/core").Variable<number>;
50
+ };
51
+ } & Omit<{
52
+ size: {
53
+ true: import("@tamagui/core").Variable<number>;
54
+ sm: import("@tamagui/core").Variable<number>;
55
+ md: import("@tamagui/core").Variable<number>;
56
+ touch: import("@tamagui/core").Variable<number>;
57
+ lg: import("@tamagui/core").Variable<number>;
58
+ xl: import("@tamagui/core").Variable<number>;
59
+ };
60
+ space: {
61
+ true: import("@tamagui/core").Variable<number>;
62
+ none: import("@tamagui/core").Variable<number>;
63
+ xxs: import("@tamagui/core").Variable<number>;
64
+ xs: import("@tamagui/core").Variable<number>;
65
+ sm: import("@tamagui/core").Variable<number>;
66
+ md: import("@tamagui/core").Variable<number>;
67
+ lg: import("@tamagui/core").Variable<number>;
68
+ xl: import("@tamagui/core").Variable<number>;
69
+ "2xl": import("@tamagui/core").Variable<number>;
70
+ "3xl": import("@tamagui/core").Variable<number>;
71
+ "4xl": import("@tamagui/core").Variable<number>;
72
+ "5xl": import("@tamagui/core").Variable<number>;
73
+ "6xl": import("@tamagui/core").Variable<number>;
74
+ };
75
+ radius: {
76
+ true: import("@tamagui/core").Variable<number>;
77
+ none: import("@tamagui/core").Variable<number>;
78
+ xs: import("@tamagui/core").Variable<number>;
79
+ sm: import("@tamagui/core").Variable<number>;
80
+ md: import("@tamagui/core").Variable<number>;
81
+ lg: import("@tamagui/core").Variable<number>;
82
+ xl: import("@tamagui/core").Variable<number>;
83
+ "2xl": import("@tamagui/core").Variable<number>;
84
+ pill: import("@tamagui/core").Variable<number>;
85
+ };
86
+ zIndex: {
87
+ base: import("@tamagui/core").Variable<number>;
88
+ floating: import("@tamagui/core").Variable<number>;
89
+ modal: import("@tamagui/core").Variable<number>;
90
+ };
91
+ }, "zIndex" | "space" | "color" | "size" | "radius">, {
92
+ light: ColorRoles;
93
+ dark: ColorRoles;
94
+ }, {}, {
95
+ sm: {
96
+ minWidth: number;
97
+ };
98
+ md: {
99
+ minWidth: number;
100
+ };
101
+ lg: {
102
+ minWidth: number;
103
+ };
104
+ }, {}, {
105
+ body: {
106
+ family: string;
107
+ size: {
108
+ caption: number;
109
+ body: number;
110
+ title: number;
111
+ display: number;
112
+ };
113
+ lineHeight: {
114
+ caption: number;
115
+ body: number;
116
+ title: number;
117
+ display: number;
118
+ };
119
+ weight: {
120
+ regular: string;
121
+ medium: string;
122
+ bold: string;
123
+ };
124
+ face: {
125
+ 400: {
126
+ normal: string;
127
+ };
128
+ 500: {
129
+ normal: string;
130
+ };
131
+ 700: {
132
+ normal: string;
133
+ };
134
+ };
135
+ };
136
+ mono: {
137
+ family: string;
138
+ size: {
139
+ body: number;
140
+ title: number;
141
+ };
142
+ lineHeight: {
143
+ body: number;
144
+ title: number;
145
+ };
146
+ weight: {
147
+ regular: string;
148
+ medium: string;
149
+ };
150
+ };
151
+ }, {
152
+ defaultFont: string;
153
+ }, "default">;
154
+ export declare const decodaConfig: import("@tamagui/core").TamaguiInternalConfig<{
155
+ color: {};
156
+ space: {
157
+ true: import("@tamagui/core").Variable<number>;
158
+ none: import("@tamagui/core").Variable<number>;
159
+ xxs: import("@tamagui/core").Variable<number>;
160
+ xs: import("@tamagui/core").Variable<number>;
161
+ sm: import("@tamagui/core").Variable<number>;
162
+ md: import("@tamagui/core").Variable<number>;
163
+ lg: import("@tamagui/core").Variable<number>;
164
+ xl: import("@tamagui/core").Variable<number>;
165
+ "2xl": import("@tamagui/core").Variable<number>;
166
+ "3xl": import("@tamagui/core").Variable<number>;
167
+ "4xl": import("@tamagui/core").Variable<number>;
168
+ "5xl": import("@tamagui/core").Variable<number>;
169
+ "6xl": import("@tamagui/core").Variable<number>;
170
+ };
171
+ size: {
172
+ true: import("@tamagui/core").Variable<number>;
173
+ sm: import("@tamagui/core").Variable<number>;
174
+ md: import("@tamagui/core").Variable<number>;
175
+ touch: import("@tamagui/core").Variable<number>;
176
+ lg: import("@tamagui/core").Variable<number>;
177
+ xl: import("@tamagui/core").Variable<number>;
178
+ };
179
+ radius: {
180
+ true: import("@tamagui/core").Variable<number>;
181
+ none: import("@tamagui/core").Variable<number>;
182
+ xs: import("@tamagui/core").Variable<number>;
183
+ sm: import("@tamagui/core").Variable<number>;
184
+ md: import("@tamagui/core").Variable<number>;
185
+ lg: import("@tamagui/core").Variable<number>;
186
+ xl: import("@tamagui/core").Variable<number>;
187
+ "2xl": import("@tamagui/core").Variable<number>;
188
+ pill: import("@tamagui/core").Variable<number>;
189
+ };
190
+ zIndex: {
191
+ base: import("@tamagui/core").Variable<number>;
192
+ floating: import("@tamagui/core").Variable<number>;
193
+ modal: import("@tamagui/core").Variable<number>;
194
+ };
195
+ } & Omit<{
196
+ size: {
197
+ true: import("@tamagui/core").Variable<number>;
198
+ sm: import("@tamagui/core").Variable<number>;
199
+ md: import("@tamagui/core").Variable<number>;
200
+ touch: import("@tamagui/core").Variable<number>;
201
+ lg: import("@tamagui/core").Variable<number>;
202
+ xl: import("@tamagui/core").Variable<number>;
203
+ };
204
+ space: {
205
+ true: import("@tamagui/core").Variable<number>;
206
+ none: import("@tamagui/core").Variable<number>;
207
+ xxs: import("@tamagui/core").Variable<number>;
208
+ xs: import("@tamagui/core").Variable<number>;
209
+ sm: import("@tamagui/core").Variable<number>;
210
+ md: import("@tamagui/core").Variable<number>;
211
+ lg: import("@tamagui/core").Variable<number>;
212
+ xl: import("@tamagui/core").Variable<number>;
213
+ "2xl": import("@tamagui/core").Variable<number>;
214
+ "3xl": import("@tamagui/core").Variable<number>;
215
+ "4xl": import("@tamagui/core").Variable<number>;
216
+ "5xl": import("@tamagui/core").Variable<number>;
217
+ "6xl": import("@tamagui/core").Variable<number>;
218
+ };
219
+ radius: {
220
+ true: import("@tamagui/core").Variable<number>;
221
+ none: import("@tamagui/core").Variable<number>;
222
+ xs: import("@tamagui/core").Variable<number>;
223
+ sm: import("@tamagui/core").Variable<number>;
224
+ md: import("@tamagui/core").Variable<number>;
225
+ lg: import("@tamagui/core").Variable<number>;
226
+ xl: import("@tamagui/core").Variable<number>;
227
+ "2xl": import("@tamagui/core").Variable<number>;
228
+ pill: import("@tamagui/core").Variable<number>;
229
+ };
230
+ zIndex: {
231
+ base: import("@tamagui/core").Variable<number>;
232
+ floating: import("@tamagui/core").Variable<number>;
233
+ modal: import("@tamagui/core").Variable<number>;
234
+ };
235
+ }, "zIndex" | "space" | "color" | "size" | "radius">, {
236
+ light: ColorRoles;
237
+ dark: ColorRoles;
238
+ }, {}, {
239
+ sm: {
240
+ minWidth: number;
241
+ };
242
+ md: {
243
+ minWidth: number;
244
+ };
245
+ lg: {
246
+ minWidth: number;
247
+ };
248
+ }, {}, {
249
+ body: {
250
+ family: string;
251
+ size: {
252
+ caption: number;
253
+ body: number;
254
+ title: number;
255
+ display: number;
256
+ };
257
+ lineHeight: {
258
+ caption: number;
259
+ body: number;
260
+ title: number;
261
+ display: number;
262
+ };
263
+ weight: {
264
+ regular: string;
265
+ medium: string;
266
+ bold: string;
267
+ };
268
+ face: {
269
+ 400: {
270
+ normal: string;
271
+ };
272
+ 500: {
273
+ normal: string;
274
+ };
275
+ 700: {
276
+ normal: string;
277
+ };
278
+ };
279
+ };
280
+ mono: {
281
+ family: string;
282
+ size: {
283
+ body: number;
284
+ title: number;
285
+ };
286
+ lineHeight: {
287
+ body: number;
288
+ title: number;
289
+ };
290
+ weight: {
291
+ regular: string;
292
+ medium: string;
293
+ };
294
+ };
295
+ }, {
296
+ defaultFont: string;
297
+ }, "default">;
298
+ export type DecodaConfig = typeof decodaConfig;
package/dist/config.js ADDED
@@ -0,0 +1,47 @@
1
+ import { createFont, createTamagui, createTokens } from '@tamagui/core';
2
+ import { cifraDarkColors, cifraLightColors, createTheme } from '@decoda-ui/tokens';
3
+ /** A fresh config per app allows branding without changing the library. */
4
+ export function createDecodaConfig(options = {}) {
5
+ const light = createTheme(cifraLightColors, options.light);
6
+ const dark = createTheme(cifraDarkColors, options.dark);
7
+ return createTamagui({
8
+ themes: {
9
+ light: light.color,
10
+ dark: dark.color
11
+ },
12
+ tokens: createTokens({
13
+ size: { ...light.controlSize, true: light.controlSize.touch },
14
+ space: { ...light.space, true: light.space.lg },
15
+ radius: { ...light.radius, true: light.radius.md },
16
+ zIndex: { base: 0, floating: 10, modal: 100 }
17
+ }),
18
+ fonts: {
19
+ body: createFont({
20
+ family: light.fontFamily.body,
21
+ size: { caption: 12, body: 14, title: 20, display: 32 },
22
+ lineHeight: { caption: 17, body: 21, title: 28, display: 40 },
23
+ weight: { regular: '400', medium: '500', bold: '700' },
24
+ face: {
25
+ 400: { normal: light.fontFamily.body },
26
+ 500: { normal: `${light.fontFamily.body}-Medium` },
27
+ 700: { normal: `${light.fontFamily.body}-Bold` }
28
+ }
29
+ }),
30
+ mono: createFont({
31
+ family: light.fontFamily.mono,
32
+ size: { body: 14, title: 20 },
33
+ lineHeight: { body: 21, title: 28 },
34
+ weight: { regular: '400', medium: '500' }
35
+ })
36
+ },
37
+ media: {
38
+ sm: { minWidth: 640 },
39
+ md: { minWidth: 768 },
40
+ lg: { minWidth: 1024 }
41
+ },
42
+ settings: {
43
+ defaultFont: '$body'
44
+ }
45
+ });
46
+ }
47
+ export const decodaConfig = createDecodaConfig();
@@ -0,0 +1,7 @@
1
+ export { createDecodaConfig, decodaConfig } from './config.js';
2
+ export type { DecodaConfig, DecodaConfigOptions } from './config.js';
3
+ export { Surface, BodyText, ButtonFrame, ButtonLabel } from './primitives.js';
4
+ export { Button } from './Button.js';
5
+ export type { ButtonProps, ButtonSize, ButtonTone } from './Button.js';
6
+ export { ShareBar } from './ShareBar.js';
7
+ export type { ShareBarProps } from './ShareBar.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createDecodaConfig, decodaConfig } from './config.js';
2
+ export { Surface, BodyText, ButtonFrame, ButtonLabel } from './primitives.js';
3
+ export { Button } from './Button.js';
4
+ export { ShareBar } from './ShareBar.js';
@@ -0,0 +1,9 @@
1
+ export declare const Surface: import("@tamagui/core").TamaguiComponent<import("@tamagui/core").TamaDefer, import("@tamagui/core").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/core").StackStyleBase, {}, import("@tamagui/core").StaticConfigPublic>;
2
+ export declare const BodyText: import("@tamagui/core").TamaguiComponent<import("@tamagui/core").TamaDefer, import("@tamagui/core").TamaguiTextElement, import("@tamagui/core").RNTamaguiTextNonStyleProps, import("@tamagui/core").TextStylePropsBase, {}, import("@tamagui/core").StaticConfigPublic>;
3
+ export declare const ButtonFrame: import("@tamagui/core").TamaguiComponent<import("@tamagui/core").TamaDefer, import("@tamagui/core").TamaguiElement, import("@tamagui/core").RNTamaguiViewNonStyleProps, import("@tamagui/core").StackStyleBase, {
4
+ size?: "small" | "medium" | "large" | undefined;
5
+ tone?: "primary" | "secondary" | "ghost" | "destructive" | undefined;
6
+ }, import("@tamagui/core").StaticConfigPublic>;
7
+ export declare const ButtonLabel: import("@tamagui/core").TamaguiComponent<import("@tamagui/core").TamaDefer, import("@tamagui/core").TamaguiTextElement, import("@tamagui/core").RNTamaguiTextNonStyleProps, import("@tamagui/core").TextStylePropsBase, {
8
+ tone?: "primary" | "secondary" | "ghost" | "destructive" | undefined;
9
+ }, import("@tamagui/core").StaticConfigPublic>;
@@ -0,0 +1,59 @@
1
+ import { styled, Text, View } from '@tamagui/core';
2
+ export const Surface = styled(View, {
3
+ name: 'DuiSurface',
4
+ backgroundColor: '$card',
5
+ borderColor: '$border',
6
+ borderWidth: 1,
7
+ borderRadius: '$xl',
8
+ padding: '$xl'
9
+ });
10
+ export const BodyText = styled(Text, {
11
+ name: 'DuiBodyText',
12
+ color: '$foreground',
13
+ fontFamily: '$body',
14
+ fontSize: '$body'
15
+ });
16
+ export const ButtonFrame = styled(View, {
17
+ name: 'DuiButton',
18
+ alignItems: 'center',
19
+ justifyContent: 'center',
20
+ minHeight: '$touch',
21
+ paddingHorizontal: '$lg',
22
+ borderRadius: '$md',
23
+ borderWidth: 1,
24
+ borderColor: 'transparent',
25
+ backgroundColor: '$primary',
26
+ pressStyle: { opacity: 0.9, scale: 0.98 },
27
+ focusVisibleStyle: { borderColor: '$ring', borderWidth: 2 },
28
+ disabledStyle: { opacity: 0.5 },
29
+ variants: {
30
+ tone: {
31
+ primary: { backgroundColor: '$primary' },
32
+ secondary: { backgroundColor: '$secondary', borderColor: '$secondaryBorder' },
33
+ ghost: { backgroundColor: 'transparent' },
34
+ destructive: { backgroundColor: '$destructiveSurface', borderColor: '$destructiveBorder' }
35
+ },
36
+ size: {
37
+ small: { minHeight: '$touch', paddingHorizontal: 24 },
38
+ medium: { minHeight: '$lg', paddingHorizontal: 34 },
39
+ large: { minHeight: '$xl', paddingHorizontal: 40 }
40
+ }
41
+ },
42
+ defaultVariants: { tone: 'primary', size: 'medium' }
43
+ });
44
+ export const ButtonLabel = styled(Text, {
45
+ name: 'DuiButtonLabel',
46
+ color: '$primaryForeground',
47
+ fontFamily: '$body',
48
+ fontSize: '$body',
49
+ fontWeight: '700',
50
+ variants: {
51
+ tone: {
52
+ primary: { color: '$primaryForeground' },
53
+ secondary: { color: '$secondaryForeground' },
54
+ ghost: { color: '$mutedForeground' },
55
+ destructive: { color: '$destructive' }
56
+ }
57
+ },
58
+ defaultVariants: { tone: 'primary' }
59
+ });
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@decoda-ui/mobile",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./config": {
15
+ "types": "./dist/config.d.ts",
16
+ "import": "./dist/config.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "dependencies": {
23
+ "@decoda-ui/tokens": "0.1.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@tamagui/core": ">=1",
27
+ "react": ">=18",
28
+ "react-native": ">=0.72"
29
+ },
30
+ "devDependencies": {
31
+ "@tamagui/core": "latest",
32
+ "@types/react": "latest",
33
+ "react": "latest",
34
+ "react-native": "latest"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.build.json",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit"
39
+ }
40
+ }