@sincpro/mobile-ui 3.1.0 → 3.3.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.
- package/dist/Dialog/Dialog.EditValue.js +6 -19
- package/dist/Dialog/Dialog.Sheet.js +48 -12
- package/dist/Dialog/OverlayHost.d.ts +2 -1
- package/dist/Dialog/OverlayHost.js +36 -2
- package/dist/Dialog/SheetSurface.d.ts +19 -0
- package/dist/Dialog/SheetSurface.js +279 -225
- package/dist/Display/Display.DocumentPreview.d.ts +15 -0
- package/dist/Display/Display.DocumentPreview.js +349 -0
- package/dist/Display/Display.DocumentViewer.d.ts +15 -0
- package/dist/Display/Display.DocumentViewer.js +465 -0
- package/dist/Display/Display.SwipeableRow.js +30 -23
- package/dist/Display/document-pages.d.ts +21 -0
- package/dist/Display/document-pages.js +282 -0
- package/dist/Display/document-renderer.d.ts +30 -0
- package/dist/Display/document-renderer.js +28 -0
- package/dist/Display/icon-map.d.ts +10 -10
- package/dist/Display/icon-map.js +14 -10
- package/dist/Display/index.d.ts +8 -0
- package/dist/Display/index.js +6 -0
- package/dist/Form/Form.DatePicker.js +2 -0
- package/dist/Form/Form.Input.d.ts +1 -1
- package/dist/Form/Form.Input.js +234 -215
- package/dist/Form/Form.KeyboardToolbarHost.js +78 -37
- package/dist/Form/Form.PickerField.js +133 -156
- package/dist/Form/Form.RadioButton.d.ts +1 -0
- package/dist/Form/Form.RadioButton.js +11 -122
- package/dist/Form/Form.Select.d.ts +2 -1
- package/dist/Form/Form.Select.js +183 -286
- package/dist/Form/choice-row.d.ts +15 -0
- package/dist/Form/choice-row.js +236 -0
- package/dist/theme/active.d.ts +2 -0
- package/dist/theme/active.js +13 -0
- package/dist/theme/useTheme.d.ts +4 -0
- package/dist/theme/useTheme.js +7 -12
- package/dist/utils/document.d.ts +18 -0
- package/dist/utils/document.js +46 -0
- package/package.json +4 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import Pressable from "../primitives/Pressable.js";
|
|
3
|
+
import { tv } from "../theme/tw.js";
|
|
4
|
+
import { Typography } from "../Typography/index.js";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
7
|
+
const choice = tv({
|
|
8
|
+
slots: {
|
|
9
|
+
row: "flex-row items-center gap-3",
|
|
10
|
+
mark: "w-[18px] h-[18px] rounded-full border-2 items-center justify-center",
|
|
11
|
+
dot: "w-[9px] h-[9px] rounded-full bg-primary"
|
|
12
|
+
},
|
|
13
|
+
variants: {
|
|
14
|
+
look: {
|
|
15
|
+
// Few options, each a bordered card (RadioButton, Select).
|
|
16
|
+
card: {
|
|
17
|
+
row: "rounded-lg border px-3 bg-bg-card"
|
|
18
|
+
},
|
|
19
|
+
// Long or virtualized lists (PickerField, EditValue).
|
|
20
|
+
list: {
|
|
21
|
+
row: "border-b border-border-light py-3"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
selected: {
|
|
25
|
+
true: {
|
|
26
|
+
mark: "border-primary"
|
|
27
|
+
},
|
|
28
|
+
false: {
|
|
29
|
+
mark: "border-border-default"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
compoundVariants: [{
|
|
34
|
+
look: "card",
|
|
35
|
+
selected: true,
|
|
36
|
+
className: {
|
|
37
|
+
row: "border-primary bg-primary/10"
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
look: "card",
|
|
41
|
+
selected: false,
|
|
42
|
+
className: {
|
|
43
|
+
row: "border-border-default"
|
|
44
|
+
}
|
|
45
|
+
}],
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
look: "card",
|
|
48
|
+
selected: false
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* The single-choice row of the DS: the same radio mark, 48-point target, wrapping label and
|
|
53
|
+
* `radio` semantics on Android and iOS, whether it lists two options or two thousand.
|
|
54
|
+
*/
|
|
55
|
+
export function ChoiceRow(t0) {
|
|
56
|
+
const $ = _c(49);
|
|
57
|
+
const {
|
|
58
|
+
label,
|
|
59
|
+
description,
|
|
60
|
+
selected,
|
|
61
|
+
onPress,
|
|
62
|
+
disabled: t1,
|
|
63
|
+
look: t2,
|
|
64
|
+
testID
|
|
65
|
+
} = t0;
|
|
66
|
+
const disabled = t1 === undefined ? false : t1;
|
|
67
|
+
const look = t2 === undefined ? "card" : t2;
|
|
68
|
+
let T0;
|
|
69
|
+
let T1;
|
|
70
|
+
let t10;
|
|
71
|
+
let t11;
|
|
72
|
+
let t12;
|
|
73
|
+
let t13;
|
|
74
|
+
let t3;
|
|
75
|
+
let t4;
|
|
76
|
+
let t5;
|
|
77
|
+
let t6;
|
|
78
|
+
let t7;
|
|
79
|
+
let t8;
|
|
80
|
+
let t9;
|
|
81
|
+
if ($[0] !== disabled || $[1] !== label || $[2] !== look || $[3] !== onPress || $[4] !== selected || $[5] !== testID) {
|
|
82
|
+
const styles = choice({
|
|
83
|
+
look,
|
|
84
|
+
selected
|
|
85
|
+
});
|
|
86
|
+
T1 = Pressable;
|
|
87
|
+
t5 = label;
|
|
88
|
+
t6 = "radio";
|
|
89
|
+
if ($[19] !== disabled || $[20] !== selected) {
|
|
90
|
+
t7 = {
|
|
91
|
+
checked: selected,
|
|
92
|
+
selected,
|
|
93
|
+
disabled
|
|
94
|
+
};
|
|
95
|
+
$[19] = disabled;
|
|
96
|
+
$[20] = selected;
|
|
97
|
+
$[21] = t7;
|
|
98
|
+
} else {
|
|
99
|
+
t7 = $[21];
|
|
100
|
+
}
|
|
101
|
+
t8 = styles.row();
|
|
102
|
+
t9 = disabled;
|
|
103
|
+
t10 = 0;
|
|
104
|
+
t11 = onPress;
|
|
105
|
+
if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
|
|
106
|
+
t12 = {
|
|
107
|
+
minHeight: 48
|
|
108
|
+
};
|
|
109
|
+
$[22] = t12;
|
|
110
|
+
} else {
|
|
111
|
+
t12 = $[22];
|
|
112
|
+
}
|
|
113
|
+
t13 = testID;
|
|
114
|
+
T0 = View;
|
|
115
|
+
t3 = styles.mark();
|
|
116
|
+
t4 = selected ? _jsx(View, {
|
|
117
|
+
className: styles.dot()
|
|
118
|
+
}) : null;
|
|
119
|
+
$[0] = disabled;
|
|
120
|
+
$[1] = label;
|
|
121
|
+
$[2] = look;
|
|
122
|
+
$[3] = onPress;
|
|
123
|
+
$[4] = selected;
|
|
124
|
+
$[5] = testID;
|
|
125
|
+
$[6] = T0;
|
|
126
|
+
$[7] = T1;
|
|
127
|
+
$[8] = t10;
|
|
128
|
+
$[9] = t11;
|
|
129
|
+
$[10] = t12;
|
|
130
|
+
$[11] = t13;
|
|
131
|
+
$[12] = t3;
|
|
132
|
+
$[13] = t4;
|
|
133
|
+
$[14] = t5;
|
|
134
|
+
$[15] = t6;
|
|
135
|
+
$[16] = t7;
|
|
136
|
+
$[17] = t8;
|
|
137
|
+
$[18] = t9;
|
|
138
|
+
} else {
|
|
139
|
+
T0 = $[6];
|
|
140
|
+
T1 = $[7];
|
|
141
|
+
t10 = $[8];
|
|
142
|
+
t11 = $[9];
|
|
143
|
+
t12 = $[10];
|
|
144
|
+
t13 = $[11];
|
|
145
|
+
t3 = $[12];
|
|
146
|
+
t4 = $[13];
|
|
147
|
+
t5 = $[14];
|
|
148
|
+
t6 = $[15];
|
|
149
|
+
t7 = $[16];
|
|
150
|
+
t8 = $[17];
|
|
151
|
+
t9 = $[18];
|
|
152
|
+
}
|
|
153
|
+
let t14;
|
|
154
|
+
if ($[23] !== T0 || $[24] !== t3 || $[25] !== t4) {
|
|
155
|
+
t14 = _jsx(T0, {
|
|
156
|
+
className: t3,
|
|
157
|
+
children: t4
|
|
158
|
+
});
|
|
159
|
+
$[23] = T0;
|
|
160
|
+
$[24] = t3;
|
|
161
|
+
$[25] = t4;
|
|
162
|
+
$[26] = t14;
|
|
163
|
+
} else {
|
|
164
|
+
t14 = $[26];
|
|
165
|
+
}
|
|
166
|
+
const t15 = disabled ? "text-text-disabled" : "text-text-primary";
|
|
167
|
+
let t16;
|
|
168
|
+
if ($[27] !== label || $[28] !== selected || $[29] !== t15) {
|
|
169
|
+
t16 = _jsx(Typography.Text, {
|
|
170
|
+
className: t15,
|
|
171
|
+
semibold: selected,
|
|
172
|
+
children: label
|
|
173
|
+
});
|
|
174
|
+
$[27] = label;
|
|
175
|
+
$[28] = selected;
|
|
176
|
+
$[29] = t15;
|
|
177
|
+
$[30] = t16;
|
|
178
|
+
} else {
|
|
179
|
+
t16 = $[30];
|
|
180
|
+
}
|
|
181
|
+
let t17;
|
|
182
|
+
if ($[31] !== description) {
|
|
183
|
+
t17 = description ? _jsx(Typography.Text, {
|
|
184
|
+
className: "text-text-tertiary",
|
|
185
|
+
variant: "bodySmall",
|
|
186
|
+
children: description
|
|
187
|
+
}) : null;
|
|
188
|
+
$[31] = description;
|
|
189
|
+
$[32] = t17;
|
|
190
|
+
} else {
|
|
191
|
+
t17 = $[32];
|
|
192
|
+
}
|
|
193
|
+
let t18;
|
|
194
|
+
if ($[33] !== t16 || $[34] !== t17) {
|
|
195
|
+
t18 = _jsxs(View, {
|
|
196
|
+
className: "flex-1 py-2",
|
|
197
|
+
children: [t16, t17]
|
|
198
|
+
});
|
|
199
|
+
$[33] = t16;
|
|
200
|
+
$[34] = t17;
|
|
201
|
+
$[35] = t18;
|
|
202
|
+
} else {
|
|
203
|
+
t18 = $[35];
|
|
204
|
+
}
|
|
205
|
+
let t19;
|
|
206
|
+
if ($[36] !== T1 || $[37] !== t10 || $[38] !== t11 || $[39] !== t12 || $[40] !== t13 || $[41] !== t14 || $[42] !== t18 || $[43] !== t5 || $[44] !== t6 || $[45] !== t7 || $[46] !== t8 || $[47] !== t9) {
|
|
207
|
+
t19 = _jsxs(T1, {
|
|
208
|
+
accessibilityLabel: t5,
|
|
209
|
+
accessibilityRole: t6,
|
|
210
|
+
accessibilityState: t7,
|
|
211
|
+
className: t8,
|
|
212
|
+
disabled: t9,
|
|
213
|
+
hitSlop: t10,
|
|
214
|
+
onPress: t11,
|
|
215
|
+
style: t12,
|
|
216
|
+
testID: t13,
|
|
217
|
+
children: [t14, t18]
|
|
218
|
+
});
|
|
219
|
+
$[36] = T1;
|
|
220
|
+
$[37] = t10;
|
|
221
|
+
$[38] = t11;
|
|
222
|
+
$[39] = t12;
|
|
223
|
+
$[40] = t13;
|
|
224
|
+
$[41] = t14;
|
|
225
|
+
$[42] = t18;
|
|
226
|
+
$[43] = t5;
|
|
227
|
+
$[44] = t6;
|
|
228
|
+
$[45] = t7;
|
|
229
|
+
$[46] = t8;
|
|
230
|
+
$[47] = t9;
|
|
231
|
+
$[48] = t19;
|
|
232
|
+
} else {
|
|
233
|
+
t19 = $[48];
|
|
234
|
+
}
|
|
235
|
+
return t19;
|
|
236
|
+
}
|
package/dist/theme/active.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ThemeTokens } from "./types.js";
|
|
2
2
|
export declare function setActiveTheme(tokens: ThemeTokens): void;
|
|
3
3
|
export declare function getActiveTheme(): ThemeTokens;
|
|
4
|
+
/** The active theme as one object per change, for React readers (`useTheme`). */
|
|
5
|
+
export declare function getThemeSnapshot(): ThemeTokens;
|
|
4
6
|
export declare function subscribeTheme(listener: () => void): () => void;
|
|
5
7
|
export declare function getThemeVersion(): number;
|
package/dist/theme/active.js
CHANGED
|
@@ -3,6 +3,11 @@ import { validateTheme } from "./validate.js";
|
|
|
3
3
|
const activeTheme = {
|
|
4
4
|
...DEFAULT_THEME
|
|
5
5
|
};
|
|
6
|
+
// A new object per change: the static `theme` keeps its identity, but a component compiled
|
|
7
|
+
// with React Compiler memoizes on the object `useTheme()` returns and must see it change.
|
|
8
|
+
let snapshot = {
|
|
9
|
+
...activeTheme
|
|
10
|
+
};
|
|
6
11
|
const listeners = new Set();
|
|
7
12
|
let version = 0;
|
|
8
13
|
|
|
@@ -19,12 +24,20 @@ export function setActiveTheme(tokens) {
|
|
|
19
24
|
}
|
|
20
25
|
}
|
|
21
26
|
Object.assign(activeTheme, tokens);
|
|
27
|
+
snapshot = {
|
|
28
|
+
...activeTheme
|
|
29
|
+
};
|
|
22
30
|
version += 1;
|
|
23
31
|
listeners.forEach(listener => listener());
|
|
24
32
|
}
|
|
25
33
|
export function getActiveTheme() {
|
|
26
34
|
return activeTheme;
|
|
27
35
|
}
|
|
36
|
+
|
|
37
|
+
/** The active theme as one object per change, for React readers (`useTheme`). */
|
|
38
|
+
export function getThemeSnapshot() {
|
|
39
|
+
return snapshot;
|
|
40
|
+
}
|
|
28
41
|
export function subscribeTheme(listener) {
|
|
29
42
|
listeners.add(listener);
|
|
30
43
|
return () => {
|
package/dist/theme/useTheme.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { ThemeTokens } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The active theme, as a new object after every `setActiveTheme`. Values memoized on it
|
|
4
|
+
* (by hand or by React Compiler) recompute on a light/dark switch.
|
|
5
|
+
*/
|
|
2
6
|
export declare function useTheme(): ThemeTokens;
|
|
3
7
|
export declare const theme: ThemeTokens;
|
package/dist/theme/useTheme.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getActiveTheme, getThemeVersion, subscribeTheme } from "./active.js";
|
|
1
|
+
import { getActiveTheme, getThemeSnapshot, subscribeTheme } from "./active.js";
|
|
3
2
|
import { useSyncExternalStore } from "react";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The active theme, as a new object after every `setActiveTheme`. Values memoized on it
|
|
6
|
+
* (by hand or by React Compiler) recompute on a light/dark switch.
|
|
7
|
+
*/
|
|
4
8
|
export function useTheme() {
|
|
5
|
-
|
|
6
|
-
useSyncExternalStore(subscribeTheme, getThemeVersion, getThemeVersion);
|
|
7
|
-
let t0;
|
|
8
|
-
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
9
|
-
t0 = getActiveTheme();
|
|
10
|
-
$[0] = t0;
|
|
11
|
-
} else {
|
|
12
|
-
t0 = $[0];
|
|
13
|
-
}
|
|
14
|
-
return t0;
|
|
9
|
+
return useSyncExternalStore(subscribeTheme, getThemeSnapshot, getThemeSnapshot);
|
|
15
10
|
}
|
|
16
11
|
export const theme = getActiveTheme();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type DocumentSource = {
|
|
2
|
+
uri: string;
|
|
3
|
+
mimeType?: string;
|
|
4
|
+
} | {
|
|
5
|
+
base64: string;
|
|
6
|
+
mimeType?: string;
|
|
7
|
+
};
|
|
8
|
+
export interface DocumentPage {
|
|
9
|
+
uri: string;
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function stripDataUri(value: string): string;
|
|
14
|
+
export declare function documentMimeType(source: DocumentSource): string | undefined;
|
|
15
|
+
export declare function isImageMimeType(mimeType: string | undefined): boolean;
|
|
16
|
+
export declare function mimeTypeLabel(mimeType: string | undefined): string;
|
|
17
|
+
export declare function documentBase64(source: DocumentSource): string | undefined;
|
|
18
|
+
export declare function documentImageUri(source: DocumentSource): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const DATA_URI_PREFIX = /^data:([^;,]*)[^,]*,/;
|
|
2
|
+
const BASE64_SIGNATURES = [["JVBER", "application/pdf"], ["iVBORw0KGgo", "image/png"], ["/9j/", "image/jpeg"], ["R0lGOD", "image/gif"], ["UklGR", "image/webp"], ["PCFET0NUWVBF", "text/html"], ["PCFkb2N0eXBl", "text/html"], ["PGh0bWw", "text/html"]];
|
|
3
|
+
const FILE_EXTENSIONS = {
|
|
4
|
+
pdf: "application/pdf",
|
|
5
|
+
html: "text/html",
|
|
6
|
+
htm: "text/html"
|
|
7
|
+
};
|
|
8
|
+
const MIME_LABELS = {
|
|
9
|
+
"application/pdf": "PDF",
|
|
10
|
+
"text/html": "HTML"
|
|
11
|
+
};
|
|
12
|
+
function dataUriMimeType(value) {
|
|
13
|
+
return DATA_URI_PREFIX.exec(value)?.[1] || undefined;
|
|
14
|
+
}
|
|
15
|
+
export function stripDataUri(value) {
|
|
16
|
+
const prefix = DATA_URI_PREFIX.exec(value);
|
|
17
|
+
return prefix ? value.slice(prefix[0].length) : value;
|
|
18
|
+
}
|
|
19
|
+
export function documentMimeType(source) {
|
|
20
|
+
if (source.mimeType) return source.mimeType;
|
|
21
|
+
if ("uri" in source) {
|
|
22
|
+
const extension = /\.([a-z0-9]+)($|[?#])/i.exec(source.uri)?.[1]?.toLowerCase();
|
|
23
|
+
return dataUriMimeType(source.uri) ?? (extension ? FILE_EXTENSIONS[extension] : undefined);
|
|
24
|
+
}
|
|
25
|
+
const declared = dataUriMimeType(source.base64);
|
|
26
|
+
if (declared) return declared;
|
|
27
|
+
const payload = source.base64.trimStart();
|
|
28
|
+
return BASE64_SIGNATURES.find(([signature]) => payload.startsWith(signature))?.[1];
|
|
29
|
+
}
|
|
30
|
+
export function isImageMimeType(mimeType) {
|
|
31
|
+
return !mimeType || mimeType.toLowerCase().startsWith("image/");
|
|
32
|
+
}
|
|
33
|
+
export function mimeTypeLabel(mimeType) {
|
|
34
|
+
if (isImageMimeType(mimeType)) return "Imagen";
|
|
35
|
+
const type = mimeType.toLowerCase();
|
|
36
|
+
return MIME_LABELS[type] ?? type.split("/").pop().toUpperCase();
|
|
37
|
+
}
|
|
38
|
+
export function documentBase64(source) {
|
|
39
|
+
if ("base64" in source) return stripDataUri(source.base64).trim();
|
|
40
|
+
return source.uri.startsWith("data:") ? stripDataUri(source.uri) : undefined;
|
|
41
|
+
}
|
|
42
|
+
export function documentImageUri(source) {
|
|
43
|
+
if ("uri" in source) return source.uri;
|
|
44
|
+
if (source.base64.startsWith("data:")) return source.base64;
|
|
45
|
+
return `data:${documentMimeType(source) ?? "image/png"};base64,${source.base64.trim()}`;
|
|
46
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sincpro/mobile-ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Sincpro Mobile design system: generic, presentational React Native components (no domain logic)",
|
|
5
5
|
"main": "expo/AppEntry.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -119,8 +119,10 @@
|
|
|
119
119
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
120
120
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
121
121
|
"expo": "~58.0.23",
|
|
122
|
+
"expo-asset": "~58.0.20",
|
|
122
123
|
"expo-checkbox": "~58.0.2",
|
|
123
124
|
"expo-clipboard": "~58.0.4",
|
|
125
|
+
"expo-file-system": "~58.0.13",
|
|
124
126
|
"expo-font": "~58.0.11",
|
|
125
127
|
"expo-image": "~58.0.18",
|
|
126
128
|
"expo-linear-gradient": "~58.0.3",
|
|
@@ -139,6 +141,7 @@
|
|
|
139
141
|
"react-native-currency-input": "^1.1.1",
|
|
140
142
|
"react-native-gesture-handler": "~3.3.0",
|
|
141
143
|
"react-native-keyboard-controller": "1.22.7",
|
|
144
|
+
"react-native-pdf-thumbnail": "2.0.0",
|
|
142
145
|
"react-native-reanimated": "4.7.1",
|
|
143
146
|
"react-native-safe-area-context": "~5.11.1",
|
|
144
147
|
"react-native-sortables": "^1.10.1",
|