@sincpro/mobile-ui 3.2.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/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/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/index.d.ts +8 -0
- package/dist/Display/index.js +6 -0
- package/dist/utils/document.d.ts +18 -0
- package/dist/utils/document.js +46 -0
- package/package.json +4 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DocumentRenderer } from "./document-renderer.js";
|
|
2
|
+
import type { DocumentSource } from "../utils/document.js";
|
|
3
|
+
export interface DocumentPreviewProps {
|
|
4
|
+
source: DocumentSource;
|
|
5
|
+
title?: string;
|
|
6
|
+
height?: number;
|
|
7
|
+
fit?: "top" | "contain";
|
|
8
|
+
onPress?: () => void;
|
|
9
|
+
renderer?: DocumentRenderer;
|
|
10
|
+
className?: string;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function DocumentPreview({ source, title, height, fit, onPress, renderer, className, testID, }: DocumentPreviewProps): import("react").JSX.Element;
|
|
14
|
+
export default DocumentPreview;
|
|
15
|
+
export { DocumentPreview };
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import ExpoImage from "./Display.ExpoImage.js";
|
|
3
|
+
import Icon from "./Display.Icon.js";
|
|
4
|
+
import { documentHeading, documentMeta, DocumentStatus, useDocumentPages } from "./document-pages.js";
|
|
5
|
+
import Skeleton from "../Feedback/Feedback.Skeleton.js";
|
|
6
|
+
import Pressable from "../primitives/Pressable.js";
|
|
7
|
+
import { useTheme } from "../theme/index.js";
|
|
8
|
+
import { cn } from "../theme/tw.js";
|
|
9
|
+
import { Typography } from "../Typography/index.js";
|
|
10
|
+
import { useWindowDimensions, View } from "react-native";
|
|
11
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
12
|
+
const MAX_THUMBNAIL_WIDTH = 1080;
|
|
13
|
+
function Notice(t0) {
|
|
14
|
+
const $ = _c(8);
|
|
15
|
+
const {
|
|
16
|
+
icon,
|
|
17
|
+
label,
|
|
18
|
+
color
|
|
19
|
+
} = t0;
|
|
20
|
+
let t1;
|
|
21
|
+
if ($[0] !== color || $[1] !== icon) {
|
|
22
|
+
t1 = _jsx(Icon, {
|
|
23
|
+
color: color,
|
|
24
|
+
name: icon,
|
|
25
|
+
size: 28
|
|
26
|
+
});
|
|
27
|
+
$[0] = color;
|
|
28
|
+
$[1] = icon;
|
|
29
|
+
$[2] = t1;
|
|
30
|
+
} else {
|
|
31
|
+
t1 = $[2];
|
|
32
|
+
}
|
|
33
|
+
let t2;
|
|
34
|
+
if ($[3] !== label) {
|
|
35
|
+
t2 = _jsx(Typography.Text, {
|
|
36
|
+
align: "center",
|
|
37
|
+
className: "text-text-secondary",
|
|
38
|
+
variant: "bodySmall",
|
|
39
|
+
children: label
|
|
40
|
+
});
|
|
41
|
+
$[3] = label;
|
|
42
|
+
$[4] = t2;
|
|
43
|
+
} else {
|
|
44
|
+
t2 = $[4];
|
|
45
|
+
}
|
|
46
|
+
let t3;
|
|
47
|
+
if ($[5] !== t1 || $[6] !== t2) {
|
|
48
|
+
t3 = _jsxs(View, {
|
|
49
|
+
className: "flex-1 items-center justify-center gap-2 px-4",
|
|
50
|
+
children: [t1, t2]
|
|
51
|
+
});
|
|
52
|
+
$[5] = t1;
|
|
53
|
+
$[6] = t2;
|
|
54
|
+
$[7] = t3;
|
|
55
|
+
} else {
|
|
56
|
+
t3 = $[7];
|
|
57
|
+
}
|
|
58
|
+
return t3;
|
|
59
|
+
}
|
|
60
|
+
function DocumentPreview(t0) {
|
|
61
|
+
const $ = _c(68);
|
|
62
|
+
const {
|
|
63
|
+
source,
|
|
64
|
+
title,
|
|
65
|
+
height: t1,
|
|
66
|
+
fit: t2,
|
|
67
|
+
onPress,
|
|
68
|
+
renderer,
|
|
69
|
+
className,
|
|
70
|
+
testID
|
|
71
|
+
} = t0;
|
|
72
|
+
const height = t1 === undefined ? 180 : t1;
|
|
73
|
+
const fit = t2 === undefined ? "top" : t2;
|
|
74
|
+
const theme = useTheme();
|
|
75
|
+
const {
|
|
76
|
+
width,
|
|
77
|
+
scale
|
|
78
|
+
} = useWindowDimensions();
|
|
79
|
+
let t3;
|
|
80
|
+
if ($[0] !== scale || $[1] !== width) {
|
|
81
|
+
t3 = Math.round(width * scale);
|
|
82
|
+
$[0] = scale;
|
|
83
|
+
$[1] = width;
|
|
84
|
+
$[2] = t3;
|
|
85
|
+
} else {
|
|
86
|
+
t3 = $[2];
|
|
87
|
+
}
|
|
88
|
+
const document = useDocumentPages(source, Math.min(MAX_THUMBNAIL_WIDTH, t3), true, renderer);
|
|
89
|
+
const page = document.pages[0];
|
|
90
|
+
const failed = document.status === DocumentStatus.ERROR;
|
|
91
|
+
let t4;
|
|
92
|
+
if ($[3] !== document || $[4] !== title) {
|
|
93
|
+
t4 = title ?? documentHeading(document);
|
|
94
|
+
$[3] = document;
|
|
95
|
+
$[4] = title;
|
|
96
|
+
$[5] = t4;
|
|
97
|
+
} else {
|
|
98
|
+
t4 = $[5];
|
|
99
|
+
}
|
|
100
|
+
const heading = t4;
|
|
101
|
+
let t5;
|
|
102
|
+
if ($[6] !== document.isImage || $[7] !== document.label || $[8] !== document.pageCount) {
|
|
103
|
+
t5 = documentMeta(document.label, document.isImage, document.pageCount);
|
|
104
|
+
$[6] = document.isImage;
|
|
105
|
+
$[7] = document.label;
|
|
106
|
+
$[8] = document.pageCount;
|
|
107
|
+
$[9] = t5;
|
|
108
|
+
} else {
|
|
109
|
+
t5 = $[9];
|
|
110
|
+
}
|
|
111
|
+
const meta = t5;
|
|
112
|
+
const handlePress = failed ? document.retry : onPress;
|
|
113
|
+
let t6;
|
|
114
|
+
if ($[10] !== height || $[11] !== theme.bg.muted) {
|
|
115
|
+
t6 = {
|
|
116
|
+
height,
|
|
117
|
+
backgroundColor: theme.bg.muted
|
|
118
|
+
};
|
|
119
|
+
$[10] = height;
|
|
120
|
+
$[11] = theme.bg.muted;
|
|
121
|
+
$[12] = t6;
|
|
122
|
+
} else {
|
|
123
|
+
t6 = $[12];
|
|
124
|
+
}
|
|
125
|
+
let t7;
|
|
126
|
+
if ($[13] !== document.attempt || $[14] !== document.reportPageError || $[15] !== document.status || $[16] !== fit || $[17] !== page) {
|
|
127
|
+
t7 = document.status === DocumentStatus.READY && page ? _jsx(ExpoImage, {
|
|
128
|
+
contentFit: fit === "top" ? "cover" : "contain",
|
|
129
|
+
contentPosition: "top",
|
|
130
|
+
onError: document.reportPageError,
|
|
131
|
+
source: {
|
|
132
|
+
uri: page.uri
|
|
133
|
+
},
|
|
134
|
+
style: {
|
|
135
|
+
flex: 1,
|
|
136
|
+
width: "100%",
|
|
137
|
+
borderTopLeftRadius: 6,
|
|
138
|
+
borderTopRightRadius: 6
|
|
139
|
+
}
|
|
140
|
+
}, document.attempt) : null;
|
|
141
|
+
$[13] = document.attempt;
|
|
142
|
+
$[14] = document.reportPageError;
|
|
143
|
+
$[15] = document.status;
|
|
144
|
+
$[16] = fit;
|
|
145
|
+
$[17] = page;
|
|
146
|
+
$[18] = t7;
|
|
147
|
+
} else {
|
|
148
|
+
t7 = $[18];
|
|
149
|
+
}
|
|
150
|
+
let t8;
|
|
151
|
+
if ($[19] !== document.status) {
|
|
152
|
+
t8 = document.status === DocumentStatus.LOADING ? _jsx(Skeleton, {
|
|
153
|
+
height: "100%",
|
|
154
|
+
radius: 6,
|
|
155
|
+
width: "100%"
|
|
156
|
+
}) : null;
|
|
157
|
+
$[19] = document.status;
|
|
158
|
+
$[20] = t8;
|
|
159
|
+
} else {
|
|
160
|
+
t8 = $[20];
|
|
161
|
+
}
|
|
162
|
+
let t9;
|
|
163
|
+
if ($[21] !== failed || $[22] !== theme.danger) {
|
|
164
|
+
t9 = failed ? _jsx(Notice, {
|
|
165
|
+
color: theme.danger,
|
|
166
|
+
icon: "error",
|
|
167
|
+
label: "No se pudo generar la vista previa. Toca para reintentar."
|
|
168
|
+
}) : null;
|
|
169
|
+
$[21] = failed;
|
|
170
|
+
$[22] = theme.danger;
|
|
171
|
+
$[23] = t9;
|
|
172
|
+
} else {
|
|
173
|
+
t9 = $[23];
|
|
174
|
+
}
|
|
175
|
+
let t10;
|
|
176
|
+
if ($[24] !== document.status || $[25] !== theme.icon.tertiary) {
|
|
177
|
+
t10 = document.status === DocumentStatus.UNSUPPORTED ? _jsx(Notice, {
|
|
178
|
+
color: theme.icon.tertiary,
|
|
179
|
+
icon: "document",
|
|
180
|
+
label: "Vista previa no disponible"
|
|
181
|
+
}) : null;
|
|
182
|
+
$[24] = document.status;
|
|
183
|
+
$[25] = theme.icon.tertiary;
|
|
184
|
+
$[26] = t10;
|
|
185
|
+
} else {
|
|
186
|
+
t10 = $[26];
|
|
187
|
+
}
|
|
188
|
+
let t11;
|
|
189
|
+
if ($[27] !== t10 || $[28] !== t6 || $[29] !== t7 || $[30] !== t8 || $[31] !== t9) {
|
|
190
|
+
t11 = _jsxs(View, {
|
|
191
|
+
className: "px-3 pt-3",
|
|
192
|
+
style: t6,
|
|
193
|
+
children: [t7, t8, t9, t10]
|
|
194
|
+
});
|
|
195
|
+
$[27] = t10;
|
|
196
|
+
$[28] = t6;
|
|
197
|
+
$[29] = t7;
|
|
198
|
+
$[30] = t8;
|
|
199
|
+
$[31] = t9;
|
|
200
|
+
$[32] = t11;
|
|
201
|
+
} else {
|
|
202
|
+
t11 = $[32];
|
|
203
|
+
}
|
|
204
|
+
const t12 = document.isImage ? "image" : "document";
|
|
205
|
+
let t13;
|
|
206
|
+
if ($[33] !== t12 || $[34] !== theme.icon.secondary) {
|
|
207
|
+
t13 = _jsx(Icon, {
|
|
208
|
+
color: theme.icon.secondary,
|
|
209
|
+
name: t12,
|
|
210
|
+
size: 20
|
|
211
|
+
});
|
|
212
|
+
$[33] = t12;
|
|
213
|
+
$[34] = theme.icon.secondary;
|
|
214
|
+
$[35] = t13;
|
|
215
|
+
} else {
|
|
216
|
+
t13 = $[35];
|
|
217
|
+
}
|
|
218
|
+
let t14;
|
|
219
|
+
if ($[36] !== heading) {
|
|
220
|
+
t14 = _jsx(Typography.Text, {
|
|
221
|
+
className: "text-text-primary",
|
|
222
|
+
numberOfLines: 1,
|
|
223
|
+
semibold: true,
|
|
224
|
+
children: heading
|
|
225
|
+
});
|
|
226
|
+
$[36] = heading;
|
|
227
|
+
$[37] = t14;
|
|
228
|
+
} else {
|
|
229
|
+
t14 = $[37];
|
|
230
|
+
}
|
|
231
|
+
let t15;
|
|
232
|
+
if ($[38] !== meta) {
|
|
233
|
+
t15 = _jsx(Typography.Text, {
|
|
234
|
+
className: "text-text-secondary",
|
|
235
|
+
variant: "caption",
|
|
236
|
+
children: meta
|
|
237
|
+
});
|
|
238
|
+
$[38] = meta;
|
|
239
|
+
$[39] = t15;
|
|
240
|
+
} else {
|
|
241
|
+
t15 = $[39];
|
|
242
|
+
}
|
|
243
|
+
let t16;
|
|
244
|
+
if ($[40] !== t14 || $[41] !== t15) {
|
|
245
|
+
t16 = _jsxs(View, {
|
|
246
|
+
className: "flex-1",
|
|
247
|
+
children: [t14, t15]
|
|
248
|
+
});
|
|
249
|
+
$[40] = t14;
|
|
250
|
+
$[41] = t15;
|
|
251
|
+
$[42] = t16;
|
|
252
|
+
} else {
|
|
253
|
+
t16 = $[42];
|
|
254
|
+
}
|
|
255
|
+
let t17;
|
|
256
|
+
if ($[43] !== failed || $[44] !== onPress || $[45] !== theme.icon.tertiary) {
|
|
257
|
+
t17 = onPress && !failed ? _jsx(Icon, {
|
|
258
|
+
color: theme.icon.tertiary,
|
|
259
|
+
name: "next",
|
|
260
|
+
size: 18
|
|
261
|
+
}) : null;
|
|
262
|
+
$[43] = failed;
|
|
263
|
+
$[44] = onPress;
|
|
264
|
+
$[45] = theme.icon.tertiary;
|
|
265
|
+
$[46] = t17;
|
|
266
|
+
} else {
|
|
267
|
+
t17 = $[46];
|
|
268
|
+
}
|
|
269
|
+
let t18;
|
|
270
|
+
if ($[47] !== t13 || $[48] !== t16 || $[49] !== t17) {
|
|
271
|
+
t18 = _jsxs(View, {
|
|
272
|
+
className: "flex-row items-center gap-3 px-3 py-2.5",
|
|
273
|
+
children: [t13, t16, t17]
|
|
274
|
+
});
|
|
275
|
+
$[47] = t13;
|
|
276
|
+
$[48] = t16;
|
|
277
|
+
$[49] = t17;
|
|
278
|
+
$[50] = t18;
|
|
279
|
+
} else {
|
|
280
|
+
t18 = $[50];
|
|
281
|
+
}
|
|
282
|
+
let t19;
|
|
283
|
+
if ($[51] !== t11 || $[52] !== t18) {
|
|
284
|
+
t19 = _jsxs(_Fragment, {
|
|
285
|
+
children: [t11, t18]
|
|
286
|
+
});
|
|
287
|
+
$[51] = t11;
|
|
288
|
+
$[52] = t18;
|
|
289
|
+
$[53] = t19;
|
|
290
|
+
} else {
|
|
291
|
+
t19 = $[53];
|
|
292
|
+
}
|
|
293
|
+
const body = t19;
|
|
294
|
+
let t20;
|
|
295
|
+
if ($[54] !== className) {
|
|
296
|
+
t20 = cn("overflow-hidden rounded-xl border border-border-light bg-bg-card", className);
|
|
297
|
+
$[54] = className;
|
|
298
|
+
$[55] = t20;
|
|
299
|
+
} else {
|
|
300
|
+
t20 = $[55];
|
|
301
|
+
}
|
|
302
|
+
const surface = t20;
|
|
303
|
+
const label = `Vista previa de ${heading}, ${meta}`;
|
|
304
|
+
if (!handlePress) {
|
|
305
|
+
let t21;
|
|
306
|
+
if ($[56] !== body || $[57] !== label || $[58] !== surface || $[59] !== testID) {
|
|
307
|
+
t21 = _jsx(View, {
|
|
308
|
+
accessibilityLabel: label,
|
|
309
|
+
accessibilityRole: "image",
|
|
310
|
+
accessible: true,
|
|
311
|
+
className: surface,
|
|
312
|
+
testID: testID,
|
|
313
|
+
children: body
|
|
314
|
+
});
|
|
315
|
+
$[56] = body;
|
|
316
|
+
$[57] = label;
|
|
317
|
+
$[58] = surface;
|
|
318
|
+
$[59] = testID;
|
|
319
|
+
$[60] = t21;
|
|
320
|
+
} else {
|
|
321
|
+
t21 = $[60];
|
|
322
|
+
}
|
|
323
|
+
return t21;
|
|
324
|
+
}
|
|
325
|
+
const t21 = failed ? "Reintenta generar la vista previa" : "Abre el documento";
|
|
326
|
+
let t22;
|
|
327
|
+
if ($[61] !== body || $[62] !== handlePress || $[63] !== label || $[64] !== surface || $[65] !== t21 || $[66] !== testID) {
|
|
328
|
+
t22 = _jsx(Pressable, {
|
|
329
|
+
accessibilityHint: t21,
|
|
330
|
+
accessibilityLabel: label,
|
|
331
|
+
className: surface,
|
|
332
|
+
onPress: handlePress,
|
|
333
|
+
testID: testID,
|
|
334
|
+
children: body
|
|
335
|
+
});
|
|
336
|
+
$[61] = body;
|
|
337
|
+
$[62] = handlePress;
|
|
338
|
+
$[63] = label;
|
|
339
|
+
$[64] = surface;
|
|
340
|
+
$[65] = t21;
|
|
341
|
+
$[66] = testID;
|
|
342
|
+
$[67] = t22;
|
|
343
|
+
} else {
|
|
344
|
+
t22 = $[67];
|
|
345
|
+
}
|
|
346
|
+
return t22;
|
|
347
|
+
}
|
|
348
|
+
export default DocumentPreview;
|
|
349
|
+
export { DocumentPreview };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DocumentRenderer } from "./document-renderer.js";
|
|
2
|
+
import type { DocumentSource } from "../utils/document.js";
|
|
3
|
+
import { type ReactNode } from "react";
|
|
4
|
+
export interface DocumentViewerProps {
|
|
5
|
+
visible: boolean;
|
|
6
|
+
source: DocumentSource | null;
|
|
7
|
+
title?: string;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
actions?: ReactNode;
|
|
10
|
+
renderer?: DocumentRenderer;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function DocumentViewer({ visible, source, title, onClose, actions, renderer, testID, }: DocumentViewerProps): import("react").JSX.Element;
|
|
14
|
+
export default DocumentViewer;
|
|
15
|
+
export { DocumentViewer };
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import ExpoImage from "./Display.ExpoImage.js";
|
|
3
|
+
import { documentHeading, documentMeta, DocumentStatus, useDocumentPages } from "./document-pages.js";
|
|
4
|
+
import State from "../Feedback/Feedback.State.js";
|
|
5
|
+
import { AppBar } from "../Navigation/Navigation.AppBar.js";
|
|
6
|
+
import { useTheme, useThemeVars } from "../theme/index.js";
|
|
7
|
+
import { Typography } from "../Typography/index.js";
|
|
8
|
+
import { useReducedMotion } from "../utils/useReducedMotion.js";
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
import { Modal, ScrollView, useWindowDimensions, View } from "react-native";
|
|
11
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
13
|
+
const MAX_RENDER_WIDTH = 2048;
|
|
14
|
+
const ZOOM_SCALE = 2;
|
|
15
|
+
const GUTTER = 12;
|
|
16
|
+
const A4_RATIO = 1 / Math.SQRT2;
|
|
17
|
+
function ViewerPage(t0) {
|
|
18
|
+
const $ = _c(26);
|
|
19
|
+
const {
|
|
20
|
+
page,
|
|
21
|
+
width,
|
|
22
|
+
number,
|
|
23
|
+
pageCount,
|
|
24
|
+
label,
|
|
25
|
+
onError
|
|
26
|
+
} = t0;
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
const [loadedRatio, setLoadedRatio] = useState(null);
|
|
29
|
+
const ratio = page.width && page.height ? page.width / page.height : loadedRatio ?? A4_RATIO;
|
|
30
|
+
let t1;
|
|
31
|
+
if ($[0] !== width) {
|
|
32
|
+
t1 = {
|
|
33
|
+
width,
|
|
34
|
+
gap: 6
|
|
35
|
+
};
|
|
36
|
+
$[0] = width;
|
|
37
|
+
$[1] = t1;
|
|
38
|
+
} else {
|
|
39
|
+
t1 = $[1];
|
|
40
|
+
}
|
|
41
|
+
let t2;
|
|
42
|
+
if ($[2] !== ratio || $[3] !== theme.border.light || $[4] !== theme.shadow.sm || $[5] !== width) {
|
|
43
|
+
t2 = {
|
|
44
|
+
width,
|
|
45
|
+
aspectRatio: ratio,
|
|
46
|
+
borderColor: theme.border.light,
|
|
47
|
+
borderWidth: 1,
|
|
48
|
+
...theme.shadow.sm
|
|
49
|
+
};
|
|
50
|
+
$[2] = ratio;
|
|
51
|
+
$[3] = theme.border.light;
|
|
52
|
+
$[4] = theme.shadow.sm;
|
|
53
|
+
$[5] = width;
|
|
54
|
+
$[6] = t2;
|
|
55
|
+
} else {
|
|
56
|
+
t2 = $[6];
|
|
57
|
+
}
|
|
58
|
+
const t3 = pageCount > 1 ? `${label}, página ${number} de ${pageCount}` : label;
|
|
59
|
+
let t4;
|
|
60
|
+
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
61
|
+
t4 = event => {
|
|
62
|
+
if (event.source.height > 0) {
|
|
63
|
+
setLoadedRatio(event.source.width / event.source.height);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
$[7] = t4;
|
|
67
|
+
} else {
|
|
68
|
+
t4 = $[7];
|
|
69
|
+
}
|
|
70
|
+
let t5;
|
|
71
|
+
if ($[8] !== page.uri) {
|
|
72
|
+
t5 = {
|
|
73
|
+
uri: page.uri
|
|
74
|
+
};
|
|
75
|
+
$[8] = page.uri;
|
|
76
|
+
$[9] = t5;
|
|
77
|
+
} else {
|
|
78
|
+
t5 = $[9];
|
|
79
|
+
}
|
|
80
|
+
let t6;
|
|
81
|
+
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
|
|
82
|
+
t6 = {
|
|
83
|
+
width: "100%",
|
|
84
|
+
height: "100%"
|
|
85
|
+
};
|
|
86
|
+
$[10] = t6;
|
|
87
|
+
} else {
|
|
88
|
+
t6 = $[10];
|
|
89
|
+
}
|
|
90
|
+
let t7;
|
|
91
|
+
if ($[11] !== onError || $[12] !== t3 || $[13] !== t5) {
|
|
92
|
+
t7 = _jsx(ExpoImage, {
|
|
93
|
+
accessibilityLabel: t3,
|
|
94
|
+
accessible: true,
|
|
95
|
+
contentFit: "contain",
|
|
96
|
+
onError: onError,
|
|
97
|
+
onLoad: t4,
|
|
98
|
+
source: t5,
|
|
99
|
+
style: t6
|
|
100
|
+
});
|
|
101
|
+
$[11] = onError;
|
|
102
|
+
$[12] = t3;
|
|
103
|
+
$[13] = t5;
|
|
104
|
+
$[14] = t7;
|
|
105
|
+
} else {
|
|
106
|
+
t7 = $[14];
|
|
107
|
+
}
|
|
108
|
+
let t8;
|
|
109
|
+
if ($[15] !== t2 || $[16] !== t7) {
|
|
110
|
+
t8 = _jsx(View, {
|
|
111
|
+
style: t2,
|
|
112
|
+
children: t7
|
|
113
|
+
});
|
|
114
|
+
$[15] = t2;
|
|
115
|
+
$[16] = t7;
|
|
116
|
+
$[17] = t8;
|
|
117
|
+
} else {
|
|
118
|
+
t8 = $[17];
|
|
119
|
+
}
|
|
120
|
+
let t9;
|
|
121
|
+
if ($[18] !== number || $[19] !== pageCount || $[20] !== theme.text) {
|
|
122
|
+
t9 = pageCount > 1 ? _jsxs(Typography.Text, {
|
|
123
|
+
align: "center",
|
|
124
|
+
style: {
|
|
125
|
+
color: theme.text.secondary
|
|
126
|
+
},
|
|
127
|
+
variant: "caption",
|
|
128
|
+
children: ["P\xE1gina ", number, " de ", pageCount]
|
|
129
|
+
}) : null;
|
|
130
|
+
$[18] = number;
|
|
131
|
+
$[19] = pageCount;
|
|
132
|
+
$[20] = theme.text;
|
|
133
|
+
$[21] = t9;
|
|
134
|
+
} else {
|
|
135
|
+
t9 = $[21];
|
|
136
|
+
}
|
|
137
|
+
let t10;
|
|
138
|
+
if ($[22] !== t1 || $[23] !== t8 || $[24] !== t9) {
|
|
139
|
+
t10 = _jsxs(View, {
|
|
140
|
+
style: t1,
|
|
141
|
+
children: [t8, t9]
|
|
142
|
+
});
|
|
143
|
+
$[22] = t1;
|
|
144
|
+
$[23] = t8;
|
|
145
|
+
$[24] = t9;
|
|
146
|
+
$[25] = t10;
|
|
147
|
+
} else {
|
|
148
|
+
t10 = $[25];
|
|
149
|
+
}
|
|
150
|
+
return t10;
|
|
151
|
+
}
|
|
152
|
+
function ViewerContent(t0) {
|
|
153
|
+
const $ = _c(55);
|
|
154
|
+
const {
|
|
155
|
+
source,
|
|
156
|
+
title,
|
|
157
|
+
onClose,
|
|
158
|
+
actions,
|
|
159
|
+
renderer
|
|
160
|
+
} = t0;
|
|
161
|
+
const theme = useTheme();
|
|
162
|
+
const insets = useSafeAreaInsets();
|
|
163
|
+
const {
|
|
164
|
+
width,
|
|
165
|
+
scale
|
|
166
|
+
} = useWindowDimensions();
|
|
167
|
+
const [zoomed, setZoomed] = useState(false);
|
|
168
|
+
let t1;
|
|
169
|
+
if ($[0] !== scale || $[1] !== width) {
|
|
170
|
+
t1 = Math.round(width * scale * ZOOM_SCALE);
|
|
171
|
+
$[0] = scale;
|
|
172
|
+
$[1] = width;
|
|
173
|
+
$[2] = t1;
|
|
174
|
+
} else {
|
|
175
|
+
t1 = $[2];
|
|
176
|
+
}
|
|
177
|
+
const document = useDocumentPages(source, Math.min(MAX_RENDER_WIDTH, t1), false, renderer);
|
|
178
|
+
const ready = document.status === DocumentStatus.READY;
|
|
179
|
+
let t2;
|
|
180
|
+
if ($[3] !== document || $[4] !== title) {
|
|
181
|
+
t2 = title ?? documentHeading(document);
|
|
182
|
+
$[3] = document;
|
|
183
|
+
$[4] = title;
|
|
184
|
+
$[5] = t2;
|
|
185
|
+
} else {
|
|
186
|
+
t2 = $[5];
|
|
187
|
+
}
|
|
188
|
+
const heading = t2;
|
|
189
|
+
const fitWidth = width - insets.left - insets.right - GUTTER * 2;
|
|
190
|
+
const pageWidth = zoomed ? fitWidth * ZOOM_SCALE : fitWidth;
|
|
191
|
+
let t3;
|
|
192
|
+
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
|
193
|
+
t3 = {
|
|
194
|
+
gap: GUTTER * 2
|
|
195
|
+
};
|
|
196
|
+
$[6] = t3;
|
|
197
|
+
} else {
|
|
198
|
+
t3 = $[6];
|
|
199
|
+
}
|
|
200
|
+
let t4;
|
|
201
|
+
if ($[7] !== document.attempt || $[8] !== document.pageCount || $[9] !== document.pages || $[10] !== document.reportPageError || $[11] !== heading || $[12] !== pageWidth) {
|
|
202
|
+
let t5;
|
|
203
|
+
if ($[14] !== document.attempt || $[15] !== document.pageCount || $[16] !== document.reportPageError || $[17] !== heading || $[18] !== pageWidth) {
|
|
204
|
+
t5 = (page, index) => _jsx(ViewerPage, {
|
|
205
|
+
label: heading,
|
|
206
|
+
number: index + 1,
|
|
207
|
+
onError: document.reportPageError,
|
|
208
|
+
page: page,
|
|
209
|
+
pageCount: document.pageCount,
|
|
210
|
+
width: pageWidth
|
|
211
|
+
}, `${document.attempt}:${index}`);
|
|
212
|
+
$[14] = document.attempt;
|
|
213
|
+
$[15] = document.pageCount;
|
|
214
|
+
$[16] = document.reportPageError;
|
|
215
|
+
$[17] = heading;
|
|
216
|
+
$[18] = pageWidth;
|
|
217
|
+
$[19] = t5;
|
|
218
|
+
} else {
|
|
219
|
+
t5 = $[19];
|
|
220
|
+
}
|
|
221
|
+
t4 = document.pages.map(t5);
|
|
222
|
+
$[7] = document.attempt;
|
|
223
|
+
$[8] = document.pageCount;
|
|
224
|
+
$[9] = document.pages;
|
|
225
|
+
$[10] = document.reportPageError;
|
|
226
|
+
$[11] = heading;
|
|
227
|
+
$[12] = pageWidth;
|
|
228
|
+
$[13] = t4;
|
|
229
|
+
} else {
|
|
230
|
+
t4 = $[13];
|
|
231
|
+
}
|
|
232
|
+
let t5;
|
|
233
|
+
if ($[20] !== t4) {
|
|
234
|
+
t5 = _jsx(View, {
|
|
235
|
+
style: t3,
|
|
236
|
+
children: t4
|
|
237
|
+
});
|
|
238
|
+
$[20] = t4;
|
|
239
|
+
$[21] = t5;
|
|
240
|
+
} else {
|
|
241
|
+
t5 = $[21];
|
|
242
|
+
}
|
|
243
|
+
const pages = t5;
|
|
244
|
+
let t6;
|
|
245
|
+
if ($[22] !== theme.bg.muted) {
|
|
246
|
+
t6 = {
|
|
247
|
+
flex: 1,
|
|
248
|
+
backgroundColor: theme.bg.muted
|
|
249
|
+
};
|
|
250
|
+
$[22] = theme.bg.muted;
|
|
251
|
+
$[23] = t6;
|
|
252
|
+
} else {
|
|
253
|
+
t6 = $[23];
|
|
254
|
+
}
|
|
255
|
+
let t7;
|
|
256
|
+
if ($[24] !== ready || $[25] !== zoomed) {
|
|
257
|
+
t7 = ready ? _jsx(AppBar.Action, {
|
|
258
|
+
accessibilityLabel: zoomed ? "Ajustar al ancho" : "Ampliar",
|
|
259
|
+
label: zoomed ? "Ajustar" : "Ampliar",
|
|
260
|
+
onPress: () => setZoomed(_temp)
|
|
261
|
+
}) : null;
|
|
262
|
+
$[24] = ready;
|
|
263
|
+
$[25] = zoomed;
|
|
264
|
+
$[26] = t7;
|
|
265
|
+
} else {
|
|
266
|
+
t7 = $[26];
|
|
267
|
+
}
|
|
268
|
+
let t8;
|
|
269
|
+
if ($[27] !== actions || $[28] !== t7) {
|
|
270
|
+
t8 = _jsxs(_Fragment, {
|
|
271
|
+
children: [t7, actions]
|
|
272
|
+
});
|
|
273
|
+
$[27] = actions;
|
|
274
|
+
$[28] = t7;
|
|
275
|
+
$[29] = t8;
|
|
276
|
+
} else {
|
|
277
|
+
t8 = $[29];
|
|
278
|
+
}
|
|
279
|
+
let t9;
|
|
280
|
+
if ($[30] !== onClose) {
|
|
281
|
+
t9 = _jsx(AppBar.Action, {
|
|
282
|
+
accessibilityLabel: "Cerrar",
|
|
283
|
+
icon: "close",
|
|
284
|
+
onPress: onClose
|
|
285
|
+
});
|
|
286
|
+
$[30] = onClose;
|
|
287
|
+
$[31] = t9;
|
|
288
|
+
} else {
|
|
289
|
+
t9 = $[31];
|
|
290
|
+
}
|
|
291
|
+
let t10;
|
|
292
|
+
if ($[32] !== document.isImage || $[33] !== document.label || $[34] !== document.pageCount) {
|
|
293
|
+
t10 = documentMeta(document.label, document.isImage, document.pageCount);
|
|
294
|
+
$[32] = document.isImage;
|
|
295
|
+
$[33] = document.label;
|
|
296
|
+
$[34] = document.pageCount;
|
|
297
|
+
$[35] = t10;
|
|
298
|
+
} else {
|
|
299
|
+
t10 = $[35];
|
|
300
|
+
}
|
|
301
|
+
let t11;
|
|
302
|
+
if ($[36] !== heading || $[37] !== t10 || $[38] !== t8 || $[39] !== t9) {
|
|
303
|
+
t11 = _jsx(AppBar, {
|
|
304
|
+
actions: t8,
|
|
305
|
+
leading: t9,
|
|
306
|
+
subtitle: t10,
|
|
307
|
+
title: heading
|
|
308
|
+
});
|
|
309
|
+
$[36] = heading;
|
|
310
|
+
$[37] = t10;
|
|
311
|
+
$[38] = t8;
|
|
312
|
+
$[39] = t9;
|
|
313
|
+
$[40] = t11;
|
|
314
|
+
} else {
|
|
315
|
+
t11 = $[40];
|
|
316
|
+
}
|
|
317
|
+
let t12;
|
|
318
|
+
if ($[41] !== document.label || $[42] !== document.retry || $[43] !== document.status || $[44] !== insets.bottom || $[45] !== insets.left || $[46] !== insets.right || $[47] !== pages || $[48] !== ready || $[49] !== zoomed) {
|
|
319
|
+
t12 = ready ? _jsx(ScrollView, {
|
|
320
|
+
contentContainerStyle: {
|
|
321
|
+
paddingTop: GUTTER,
|
|
322
|
+
paddingLeft: insets.left + GUTTER,
|
|
323
|
+
paddingRight: insets.right + GUTTER,
|
|
324
|
+
paddingBottom: insets.bottom + GUTTER * 2
|
|
325
|
+
},
|
|
326
|
+
children: zoomed ? _jsx(ScrollView, {
|
|
327
|
+
horizontal: true,
|
|
328
|
+
children: pages
|
|
329
|
+
}) : pages
|
|
330
|
+
}) : _jsxs(View, {
|
|
331
|
+
style: {
|
|
332
|
+
flex: 1,
|
|
333
|
+
paddingBottom: insets.bottom
|
|
334
|
+
},
|
|
335
|
+
children: [document.status === DocumentStatus.LOADING ? _jsx(State, {
|
|
336
|
+
kind: "loading",
|
|
337
|
+
message: "Generando vista previa\u2026"
|
|
338
|
+
}) : null, document.status === DocumentStatus.ERROR ? _jsx(State, {
|
|
339
|
+
kind: "error",
|
|
340
|
+
message: "No se pudo generar la vista previa del documento.",
|
|
341
|
+
onRetry: document.retry
|
|
342
|
+
}) : null, document.status === DocumentStatus.UNSUPPORTED ? _jsx(State, {
|
|
343
|
+
description: `Esta app no tiene un visor configurado para ${document.label}.`,
|
|
344
|
+
icon: "document",
|
|
345
|
+
kind: "empty",
|
|
346
|
+
title: "Vista previa no disponible"
|
|
347
|
+
}) : null]
|
|
348
|
+
});
|
|
349
|
+
$[41] = document.label;
|
|
350
|
+
$[42] = document.retry;
|
|
351
|
+
$[43] = document.status;
|
|
352
|
+
$[44] = insets.bottom;
|
|
353
|
+
$[45] = insets.left;
|
|
354
|
+
$[46] = insets.right;
|
|
355
|
+
$[47] = pages;
|
|
356
|
+
$[48] = ready;
|
|
357
|
+
$[49] = zoomed;
|
|
358
|
+
$[50] = t12;
|
|
359
|
+
} else {
|
|
360
|
+
t12 = $[50];
|
|
361
|
+
}
|
|
362
|
+
let t13;
|
|
363
|
+
if ($[51] !== t11 || $[52] !== t12 || $[53] !== t6) {
|
|
364
|
+
t13 = _jsxs(View, {
|
|
365
|
+
style: t6,
|
|
366
|
+
children: [t11, t12]
|
|
367
|
+
});
|
|
368
|
+
$[51] = t11;
|
|
369
|
+
$[52] = t12;
|
|
370
|
+
$[53] = t6;
|
|
371
|
+
$[54] = t13;
|
|
372
|
+
} else {
|
|
373
|
+
t13 = $[54];
|
|
374
|
+
}
|
|
375
|
+
return t13;
|
|
376
|
+
}
|
|
377
|
+
function _temp(previous) {
|
|
378
|
+
return !previous;
|
|
379
|
+
}
|
|
380
|
+
function DocumentViewer(t0) {
|
|
381
|
+
const $ = _c(18);
|
|
382
|
+
const {
|
|
383
|
+
visible,
|
|
384
|
+
source,
|
|
385
|
+
title,
|
|
386
|
+
onClose,
|
|
387
|
+
actions,
|
|
388
|
+
renderer,
|
|
389
|
+
testID
|
|
390
|
+
} = t0;
|
|
391
|
+
const reducedMotion = useReducedMotion();
|
|
392
|
+
const themeVars = useThemeVars();
|
|
393
|
+
const t1 = reducedMotion ? "none" : "slide";
|
|
394
|
+
const t2 = visible && source !== null;
|
|
395
|
+
let t3;
|
|
396
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
397
|
+
t3 = {
|
|
398
|
+
flex: 1
|
|
399
|
+
};
|
|
400
|
+
$[0] = t3;
|
|
401
|
+
} else {
|
|
402
|
+
t3 = $[0];
|
|
403
|
+
}
|
|
404
|
+
let t4;
|
|
405
|
+
if ($[1] !== themeVars) {
|
|
406
|
+
t4 = [t3, themeVars];
|
|
407
|
+
$[1] = themeVars;
|
|
408
|
+
$[2] = t4;
|
|
409
|
+
} else {
|
|
410
|
+
t4 = $[2];
|
|
411
|
+
}
|
|
412
|
+
let t5;
|
|
413
|
+
if ($[3] !== actions || $[4] !== onClose || $[5] !== renderer || $[6] !== source || $[7] !== title) {
|
|
414
|
+
t5 = source ? _jsx(ViewerContent, {
|
|
415
|
+
actions: actions,
|
|
416
|
+
onClose: onClose,
|
|
417
|
+
renderer: renderer,
|
|
418
|
+
source: source,
|
|
419
|
+
title: title
|
|
420
|
+
}) : null;
|
|
421
|
+
$[3] = actions;
|
|
422
|
+
$[4] = onClose;
|
|
423
|
+
$[5] = renderer;
|
|
424
|
+
$[6] = source;
|
|
425
|
+
$[7] = title;
|
|
426
|
+
$[8] = t5;
|
|
427
|
+
} else {
|
|
428
|
+
t5 = $[8];
|
|
429
|
+
}
|
|
430
|
+
let t6;
|
|
431
|
+
if ($[9] !== t4 || $[10] !== t5 || $[11] !== testID) {
|
|
432
|
+
t6 = _jsx(View, {
|
|
433
|
+
style: t4,
|
|
434
|
+
testID: testID,
|
|
435
|
+
children: t5
|
|
436
|
+
});
|
|
437
|
+
$[9] = t4;
|
|
438
|
+
$[10] = t5;
|
|
439
|
+
$[11] = testID;
|
|
440
|
+
$[12] = t6;
|
|
441
|
+
} else {
|
|
442
|
+
t6 = $[12];
|
|
443
|
+
}
|
|
444
|
+
let t7;
|
|
445
|
+
if ($[13] !== onClose || $[14] !== t1 || $[15] !== t2 || $[16] !== t6) {
|
|
446
|
+
t7 = _jsx(Modal, {
|
|
447
|
+
animationType: t1,
|
|
448
|
+
navigationBarTranslucent: true,
|
|
449
|
+
onRequestClose: onClose,
|
|
450
|
+
statusBarTranslucent: true,
|
|
451
|
+
visible: t2,
|
|
452
|
+
children: t6
|
|
453
|
+
});
|
|
454
|
+
$[13] = onClose;
|
|
455
|
+
$[14] = t1;
|
|
456
|
+
$[15] = t2;
|
|
457
|
+
$[16] = t6;
|
|
458
|
+
$[17] = t7;
|
|
459
|
+
} else {
|
|
460
|
+
t7 = $[17];
|
|
461
|
+
}
|
|
462
|
+
return t7;
|
|
463
|
+
}
|
|
464
|
+
export default DocumentViewer;
|
|
465
|
+
export { DocumentViewer };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type DocumentRenderer } from "./document-renderer.js";
|
|
2
|
+
import { type DocumentPage, type DocumentSource } from "../utils/document.js";
|
|
3
|
+
export declare enum DocumentStatus {
|
|
4
|
+
LOADING = "loading",
|
|
5
|
+
READY = "ready",
|
|
6
|
+
UNSUPPORTED = "unsupported",
|
|
7
|
+
ERROR = "error"
|
|
8
|
+
}
|
|
9
|
+
export interface DocumentPagesState {
|
|
10
|
+
label: string;
|
|
11
|
+
isImage: boolean;
|
|
12
|
+
status: DocumentStatus;
|
|
13
|
+
pageCount: number;
|
|
14
|
+
pages: DocumentPage[];
|
|
15
|
+
attempt: number;
|
|
16
|
+
retry: () => void;
|
|
17
|
+
reportPageError: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function documentMeta(label: string, isImage: boolean, pageCount: number): string;
|
|
20
|
+
export declare function documentHeading(state: DocumentPagesState): string;
|
|
21
|
+
export declare function useDocumentPages(source: DocumentSource, maxWidth: number, firstPageOnly: boolean, override?: DocumentRenderer): DocumentPagesState;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import { documentRenderer } from "./document-renderer.js";
|
|
3
|
+
import { documentImageUri, documentMimeType, isImageMimeType, mimeTypeLabel } from "../utils/document.js";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
export let DocumentStatus = /*#__PURE__*/function (DocumentStatus) {
|
|
6
|
+
DocumentStatus["LOADING"] = "loading";
|
|
7
|
+
DocumentStatus["READY"] = "ready";
|
|
8
|
+
DocumentStatus["UNSUPPORTED"] = "unsupported";
|
|
9
|
+
DocumentStatus["ERROR"] = "error";
|
|
10
|
+
return DocumentStatus;
|
|
11
|
+
}({});
|
|
12
|
+
export function documentMeta(label, isImage, pageCount) {
|
|
13
|
+
if (isImage || pageCount === 0) return label;
|
|
14
|
+
return `${label} · ${pageCount} ${pageCount === 1 ? "página" : "páginas"}`;
|
|
15
|
+
}
|
|
16
|
+
export function documentHeading(state) {
|
|
17
|
+
return state.isImage ? state.label : `Documento ${state.label}`;
|
|
18
|
+
}
|
|
19
|
+
export function useDocumentPages(source, maxWidth, firstPageOnly, override) {
|
|
20
|
+
const $ = _c(45);
|
|
21
|
+
let isImage;
|
|
22
|
+
let renderer;
|
|
23
|
+
let t0;
|
|
24
|
+
if ($[0] !== override || $[1] !== source) {
|
|
25
|
+
const detected = documentMimeType(source);
|
|
26
|
+
renderer = override ?? documentRenderer(detected);
|
|
27
|
+
isImage = !renderer && isImageMimeType(detected);
|
|
28
|
+
t0 = renderer?.label ?? mimeTypeLabel(detected);
|
|
29
|
+
$[0] = override;
|
|
30
|
+
$[1] = source;
|
|
31
|
+
$[2] = isImage;
|
|
32
|
+
$[3] = renderer;
|
|
33
|
+
$[4] = t0;
|
|
34
|
+
} else {
|
|
35
|
+
isImage = $[2];
|
|
36
|
+
renderer = $[3];
|
|
37
|
+
t0 = $[4];
|
|
38
|
+
}
|
|
39
|
+
const label = t0;
|
|
40
|
+
const isUri = "uri" in source;
|
|
41
|
+
const value = isUri ? source.uri : source.base64;
|
|
42
|
+
const {
|
|
43
|
+
mimeType
|
|
44
|
+
} = source;
|
|
45
|
+
const [attempt, setAttempt] = useState(0);
|
|
46
|
+
const [rendered, setRendered] = useState(null);
|
|
47
|
+
const [pageFailure, setPageFailure] = useState(null);
|
|
48
|
+
let t1;
|
|
49
|
+
let t2;
|
|
50
|
+
if ($[5] !== attempt || $[6] !== firstPageOnly || $[7] !== isUri || $[8] !== maxWidth || $[9] !== mimeType || $[10] !== renderer || $[11] !== value) {
|
|
51
|
+
t1 = () => {
|
|
52
|
+
if (!renderer) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const target = isUri ? {
|
|
57
|
+
uri: value,
|
|
58
|
+
mimeType
|
|
59
|
+
} : {
|
|
60
|
+
base64: value,
|
|
61
|
+
mimeType
|
|
62
|
+
};
|
|
63
|
+
const request = {
|
|
64
|
+
renderer,
|
|
65
|
+
value,
|
|
66
|
+
isUri,
|
|
67
|
+
mimeType,
|
|
68
|
+
maxWidth,
|
|
69
|
+
firstPageOnly,
|
|
70
|
+
attempt
|
|
71
|
+
};
|
|
72
|
+
renderer.render(target, {
|
|
73
|
+
maxWidth,
|
|
74
|
+
firstPageOnly,
|
|
75
|
+
signal: controller.signal
|
|
76
|
+
}).then(result => {
|
|
77
|
+
if (!controller.signal.aborted) {
|
|
78
|
+
setRendered({
|
|
79
|
+
...request,
|
|
80
|
+
failed: false,
|
|
81
|
+
...result
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}, error => {
|
|
85
|
+
if (controller.signal.aborted) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
console.error(`[Document] ${renderer.label} preview failed`, error);
|
|
89
|
+
setRendered({
|
|
90
|
+
...request,
|
|
91
|
+
failed: true,
|
|
92
|
+
pageCount: 0,
|
|
93
|
+
pages: []
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
return () => controller.abort();
|
|
97
|
+
};
|
|
98
|
+
t2 = [renderer, isUri, value, mimeType, maxWidth, firstPageOnly, attempt];
|
|
99
|
+
$[5] = attempt;
|
|
100
|
+
$[6] = firstPageOnly;
|
|
101
|
+
$[7] = isUri;
|
|
102
|
+
$[8] = maxWidth;
|
|
103
|
+
$[9] = mimeType;
|
|
104
|
+
$[10] = renderer;
|
|
105
|
+
$[11] = value;
|
|
106
|
+
$[12] = t1;
|
|
107
|
+
$[13] = t2;
|
|
108
|
+
} else {
|
|
109
|
+
t1 = $[12];
|
|
110
|
+
t2 = $[13];
|
|
111
|
+
}
|
|
112
|
+
useEffect(t1, t2);
|
|
113
|
+
let t3;
|
|
114
|
+
if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
|
|
115
|
+
t3 = () => setAttempt(_temp);
|
|
116
|
+
$[14] = t3;
|
|
117
|
+
} else {
|
|
118
|
+
t3 = $[14];
|
|
119
|
+
}
|
|
120
|
+
let t4;
|
|
121
|
+
if ($[15] !== attempt || $[16] !== value) {
|
|
122
|
+
t4 = () => setPageFailure({
|
|
123
|
+
value,
|
|
124
|
+
attempt
|
|
125
|
+
});
|
|
126
|
+
$[15] = attempt;
|
|
127
|
+
$[16] = value;
|
|
128
|
+
$[17] = t4;
|
|
129
|
+
} else {
|
|
130
|
+
t4 = $[17];
|
|
131
|
+
}
|
|
132
|
+
let t5;
|
|
133
|
+
if ($[18] !== attempt || $[19] !== isImage || $[20] !== label || $[21] !== t4) {
|
|
134
|
+
t5 = {
|
|
135
|
+
label,
|
|
136
|
+
isImage,
|
|
137
|
+
attempt,
|
|
138
|
+
retry: t3,
|
|
139
|
+
reportPageError: t4
|
|
140
|
+
};
|
|
141
|
+
$[18] = attempt;
|
|
142
|
+
$[19] = isImage;
|
|
143
|
+
$[20] = label;
|
|
144
|
+
$[21] = t4;
|
|
145
|
+
$[22] = t5;
|
|
146
|
+
} else {
|
|
147
|
+
t5 = $[22];
|
|
148
|
+
}
|
|
149
|
+
const base = t5;
|
|
150
|
+
let t6;
|
|
151
|
+
if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
|
|
152
|
+
t6 = [];
|
|
153
|
+
$[23] = t6;
|
|
154
|
+
} else {
|
|
155
|
+
t6 = $[23];
|
|
156
|
+
}
|
|
157
|
+
let t7;
|
|
158
|
+
if ($[24] !== base) {
|
|
159
|
+
t7 = {
|
|
160
|
+
...base,
|
|
161
|
+
pageCount: 0,
|
|
162
|
+
pages: t6
|
|
163
|
+
};
|
|
164
|
+
$[24] = base;
|
|
165
|
+
$[25] = t7;
|
|
166
|
+
} else {
|
|
167
|
+
t7 = $[25];
|
|
168
|
+
}
|
|
169
|
+
const empty = t7;
|
|
170
|
+
const pageFailed = pageFailure?.value === value && pageFailure.attempt === attempt;
|
|
171
|
+
if (pageFailed) {
|
|
172
|
+
let t8;
|
|
173
|
+
if ($[26] !== empty) {
|
|
174
|
+
t8 = {
|
|
175
|
+
...empty,
|
|
176
|
+
status: DocumentStatus.ERROR
|
|
177
|
+
};
|
|
178
|
+
$[26] = empty;
|
|
179
|
+
$[27] = t8;
|
|
180
|
+
} else {
|
|
181
|
+
t8 = $[27];
|
|
182
|
+
}
|
|
183
|
+
return t8;
|
|
184
|
+
}
|
|
185
|
+
if (isImage) {
|
|
186
|
+
let t8;
|
|
187
|
+
if ($[28] !== source) {
|
|
188
|
+
t8 = documentImageUri(source);
|
|
189
|
+
$[28] = source;
|
|
190
|
+
$[29] = t8;
|
|
191
|
+
} else {
|
|
192
|
+
t8 = $[29];
|
|
193
|
+
}
|
|
194
|
+
let t9;
|
|
195
|
+
if ($[30] !== t8) {
|
|
196
|
+
t9 = [{
|
|
197
|
+
uri: t8
|
|
198
|
+
}];
|
|
199
|
+
$[30] = t8;
|
|
200
|
+
$[31] = t9;
|
|
201
|
+
} else {
|
|
202
|
+
t9 = $[31];
|
|
203
|
+
}
|
|
204
|
+
let t10;
|
|
205
|
+
if ($[32] !== base || $[33] !== t9) {
|
|
206
|
+
t10 = {
|
|
207
|
+
...base,
|
|
208
|
+
status: DocumentStatus.READY,
|
|
209
|
+
pageCount: 1,
|
|
210
|
+
pages: t9
|
|
211
|
+
};
|
|
212
|
+
$[32] = base;
|
|
213
|
+
$[33] = t9;
|
|
214
|
+
$[34] = t10;
|
|
215
|
+
} else {
|
|
216
|
+
t10 = $[34];
|
|
217
|
+
}
|
|
218
|
+
return t10;
|
|
219
|
+
}
|
|
220
|
+
if (!renderer) {
|
|
221
|
+
let t8;
|
|
222
|
+
if ($[35] !== empty) {
|
|
223
|
+
t8 = {
|
|
224
|
+
...empty,
|
|
225
|
+
status: DocumentStatus.UNSUPPORTED
|
|
226
|
+
};
|
|
227
|
+
$[35] = empty;
|
|
228
|
+
$[36] = t8;
|
|
229
|
+
} else {
|
|
230
|
+
t8 = $[36];
|
|
231
|
+
}
|
|
232
|
+
return t8;
|
|
233
|
+
}
|
|
234
|
+
const current = rendered?.renderer === renderer && rendered.value === value && rendered.isUri === isUri && rendered.mimeType === mimeType && rendered.maxWidth === maxWidth && rendered.firstPageOnly === firstPageOnly && rendered.attempt === attempt ? rendered : null;
|
|
235
|
+
if (!current) {
|
|
236
|
+
let t8;
|
|
237
|
+
if ($[37] !== empty) {
|
|
238
|
+
t8 = {
|
|
239
|
+
...empty,
|
|
240
|
+
status: DocumentStatus.LOADING
|
|
241
|
+
};
|
|
242
|
+
$[37] = empty;
|
|
243
|
+
$[38] = t8;
|
|
244
|
+
} else {
|
|
245
|
+
t8 = $[38];
|
|
246
|
+
}
|
|
247
|
+
return t8;
|
|
248
|
+
}
|
|
249
|
+
if (current.failed) {
|
|
250
|
+
let t8;
|
|
251
|
+
if ($[39] !== empty) {
|
|
252
|
+
t8 = {
|
|
253
|
+
...empty,
|
|
254
|
+
status: DocumentStatus.ERROR
|
|
255
|
+
};
|
|
256
|
+
$[39] = empty;
|
|
257
|
+
$[40] = t8;
|
|
258
|
+
} else {
|
|
259
|
+
t8 = $[40];
|
|
260
|
+
}
|
|
261
|
+
return t8;
|
|
262
|
+
}
|
|
263
|
+
let t8;
|
|
264
|
+
if ($[41] !== base || $[42] !== current.pageCount || $[43] !== current.pages) {
|
|
265
|
+
t8 = {
|
|
266
|
+
...base,
|
|
267
|
+
status: DocumentStatus.READY,
|
|
268
|
+
pageCount: current.pageCount,
|
|
269
|
+
pages: current.pages
|
|
270
|
+
};
|
|
271
|
+
$[41] = base;
|
|
272
|
+
$[42] = current.pageCount;
|
|
273
|
+
$[43] = current.pages;
|
|
274
|
+
$[44] = t8;
|
|
275
|
+
} else {
|
|
276
|
+
t8 = $[44];
|
|
277
|
+
}
|
|
278
|
+
return t8;
|
|
279
|
+
}
|
|
280
|
+
function _temp(previous) {
|
|
281
|
+
return previous + 1;
|
|
282
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DocumentPage, DocumentSource } from "../utils/document.js";
|
|
2
|
+
/**
|
|
3
|
+
* The design system shows pages; turning a document into pages is the app's job. Register
|
|
4
|
+
* one renderer per MIME type at startup (`"image/*"` matches every image):
|
|
5
|
+
*
|
|
6
|
+
* registerDocumentRenderers({
|
|
7
|
+
* "application/pdf": { label: "PDF", render: renderPdfPages },
|
|
8
|
+
* "text/html": { label: "HTML", render: renderHtmlPages },
|
|
9
|
+
* });
|
|
10
|
+
*
|
|
11
|
+
* A component can override it with its `renderer` prop; keep that object stable (module
|
|
12
|
+
* scope), since a new one starts a new render. Images without a renderer load natively;
|
|
13
|
+
* any other type without one shows that the preview is unavailable.
|
|
14
|
+
*/
|
|
15
|
+
export interface DocumentRenderRequest {
|
|
16
|
+
maxWidth: number;
|
|
17
|
+
firstPageOnly: boolean;
|
|
18
|
+
signal: AbortSignal;
|
|
19
|
+
}
|
|
20
|
+
export interface DocumentRenderResult {
|
|
21
|
+
pageCount: number;
|
|
22
|
+
pages: DocumentPage[];
|
|
23
|
+
}
|
|
24
|
+
export interface DocumentRenderer {
|
|
25
|
+
label: string;
|
|
26
|
+
render: (source: DocumentSource, request: DocumentRenderRequest) => Promise<DocumentRenderResult>;
|
|
27
|
+
}
|
|
28
|
+
export declare function registerDocumentRenderers(entries: Record<string, DocumentRenderer | null>): void;
|
|
29
|
+
export declare function resetDocumentRenderers(): void;
|
|
30
|
+
export declare function documentRenderer(mimeType: string | undefined): DocumentRenderer | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The design system shows pages; turning a document into pages is the app's job. Register
|
|
3
|
+
* one renderer per MIME type at startup (`"image/*"` matches every image):
|
|
4
|
+
*
|
|
5
|
+
* registerDocumentRenderers({
|
|
6
|
+
* "application/pdf": { label: "PDF", render: renderPdfPages },
|
|
7
|
+
* "text/html": { label: "HTML", render: renderHtmlPages },
|
|
8
|
+
* });
|
|
9
|
+
*
|
|
10
|
+
* A component can override it with its `renderer` prop; keep that object stable (module
|
|
11
|
+
* scope), since a new one starts a new render. Images without a renderer load natively;
|
|
12
|
+
* any other type without one shows that the preview is unavailable.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const renderers = new Map();
|
|
16
|
+
export function registerDocumentRenderers(entries) {
|
|
17
|
+
for (const [mimeType, renderer] of Object.entries(entries)) {
|
|
18
|
+
if (renderer) renderers.set(mimeType.toLowerCase(), renderer);else renderers.delete(mimeType.toLowerCase());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function resetDocumentRenderers() {
|
|
22
|
+
renderers.clear();
|
|
23
|
+
}
|
|
24
|
+
export function documentRenderer(mimeType) {
|
|
25
|
+
if (!mimeType) return undefined;
|
|
26
|
+
const type = mimeType.toLowerCase();
|
|
27
|
+
return renderers.get(type) ?? renderers.get(`${type.split("/")[0]}/*`);
|
|
28
|
+
}
|
package/dist/Display/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import CountRecords from "./Display.CountRecords.js";
|
|
|
8
8
|
import DataTable from "./Display.DataTable.js";
|
|
9
9
|
import Date from "./Display.Date.js";
|
|
10
10
|
import Divider from "./Display.Divider.js";
|
|
11
|
+
import DocumentPreview from "./Display.DocumentPreview.js";
|
|
12
|
+
import DocumentViewer from "./Display.DocumentViewer.js";
|
|
11
13
|
import ExpoImage from "./Display.ExpoImage.js";
|
|
12
14
|
import GradientSurface from "./Display.GradientSurface.js";
|
|
13
15
|
import IconBadge from "./Display.IconBadge.js";
|
|
@@ -70,6 +72,8 @@ export declare const Display: {
|
|
|
70
72
|
Tag: typeof Tag;
|
|
71
73
|
Image: typeof DisplayImage;
|
|
72
74
|
ExpoImage: typeof ExpoImage;
|
|
75
|
+
DocumentPreview: typeof DocumentPreview;
|
|
76
|
+
DocumentViewer: typeof DocumentViewer;
|
|
73
77
|
MediaCard: typeof MediaCard;
|
|
74
78
|
MediaEmbed: typeof MediaEmbed;
|
|
75
79
|
Story: typeof Story;
|
|
@@ -109,13 +113,17 @@ export { type BadgeProps, BadgeVariants };
|
|
|
109
113
|
export type { AmountSummaryRootProps, AmountSummaryRowProps, AmountSummaryTotalProps, } from "./Display.AmountSummary.js";
|
|
110
114
|
export type { CarouselControlsProps, CarouselProps, } from "./Display.Carousel.js";
|
|
111
115
|
export type { CircleButtonProps } from "./Display.CircleButton.js";
|
|
116
|
+
export type { DocumentPreviewProps } from "./Display.DocumentPreview.js";
|
|
117
|
+
export type { DocumentViewerProps } from "./Display.DocumentViewer.js";
|
|
112
118
|
export type { IconProps } from "./Display.Icon.js";
|
|
113
119
|
export type { ListGroupProps } from "./Display.ListGroup.js";
|
|
114
120
|
export type { ListItemProps } from "./Display.ListItem.js";
|
|
115
121
|
export type { MenuCardProps } from "./Display.MenuCard.js";
|
|
116
122
|
export type { MenuGridItem } from "./Display.MenuGrid.js";
|
|
117
123
|
export { defineStatuses, resolveStatus, type StatusBadgeProps, type StatusDefinition, type StatusMap, type StatusTone, } from "./Display.StatusBadge.js";
|
|
124
|
+
export { type DocumentRenderer, type DocumentRenderRequest, type DocumentRenderResult, registerDocumentRenderers, resetDocumentRenderers, } from "./document-renderer.js";
|
|
118
125
|
export { ICON_FONT_FAMILY, ICON_FONTS } from "./icon-font.js";
|
|
119
126
|
export { type BuiltInIconName, ICON_NAMES, type IconName, } from "./icon-map.js";
|
|
120
127
|
export { type CustomIconRegistry, type CustomIconRenderer, registerIcons, } from "./icon-registry.js";
|
|
128
|
+
export { documentBase64, documentMimeType, type DocumentPage, type DocumentSource, } from "../utils/document.js";
|
|
121
129
|
export default Display;
|
package/dist/Display/index.js
CHANGED
|
@@ -12,6 +12,8 @@ import CountRecords from "./Display.CountRecords.js";
|
|
|
12
12
|
import DataTable from "./Display.DataTable.js";
|
|
13
13
|
import Date from "./Display.Date.js";
|
|
14
14
|
import Divider from "./Display.Divider.js";
|
|
15
|
+
import DocumentPreview from "./Display.DocumentPreview.js";
|
|
16
|
+
import DocumentViewer from "./Display.DocumentViewer.js";
|
|
15
17
|
import ExpoImage from "./Display.ExpoImage.js";
|
|
16
18
|
import GradientSurface from "./Display.GradientSurface.js";
|
|
17
19
|
import Icon from "./Display.Icon.js";
|
|
@@ -58,6 +60,8 @@ export const Display = {
|
|
|
58
60
|
Tag,
|
|
59
61
|
Image: DisplayImage,
|
|
60
62
|
ExpoImage,
|
|
63
|
+
DocumentPreview,
|
|
64
|
+
DocumentViewer,
|
|
61
65
|
MediaCard,
|
|
62
66
|
MediaEmbed,
|
|
63
67
|
Story,
|
|
@@ -95,7 +99,9 @@ export const Display = {
|
|
|
95
99
|
};
|
|
96
100
|
export { BadgeVariants };
|
|
97
101
|
export { defineStatuses, resolveStatus } from "./Display.StatusBadge.js";
|
|
102
|
+
export { registerDocumentRenderers, resetDocumentRenderers } from "./document-renderer.js";
|
|
98
103
|
export { ICON_FONT_FAMILY, ICON_FONTS } from "./icon-font.js";
|
|
99
104
|
export { ICON_NAMES } from "./icon-map.js";
|
|
100
105
|
export { registerIcons } from "./icon-registry.js";
|
|
106
|
+
export { documentBase64, documentMimeType } from "../utils/document.js";
|
|
101
107
|
export default Display;
|
|
@@ -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",
|