@lotics/ui 5.8.0 → 5.9.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/AGENTS.md +63 -18
- package/examples/tpl_convert.tsx +11 -23
- package/examples/tpl_order.tsx +1 -1
- package/examples/tpl_ratedesk.tsx +1 -1
- package/examples/tpl_record.tsx +1 -1
- package/package.json +10 -2
- package/src/file_gallery_modal.tsx +220 -133
- package/src/file_grid.tsx +184 -0
- package/src/file_preview.web.tsx +329 -6
- package/src/file_preview_types.ts +40 -0
- package/src/file_row.tsx +114 -0
- package/src/file_rows.tsx +105 -0
- package/src/file_thumbnail.tsx +121 -79
- package/src/file_thumbnail_grid.tsx +130 -55
- package/src/icon_button.tsx +12 -1
- package/src/image_gallery.tsx +0 -4
- package/src/pdfjs_worker.d.ts +5 -0
- package/src/uploading_thumbnail.tsx +212 -0
- package/src/hover_action.tsx +0 -54
package/AGENTS.md
CHANGED
|
@@ -24,8 +24,9 @@ Pick by capability, not by name. (→ the source file for the API.)
|
|
|
24
24
|
|
|
25
25
|
- **Actions** — `Button` (labelled; `title` is MANDATORY; `color` = emphasis/risk),
|
|
26
26
|
`IconButton` (icon-ONLY — the circular affordance; an icon-only Button is a type error, so reach
|
|
27
|
-
here. `size` `lg` 40px / `md` 28px / `sm` 24px, the SAME `color` palette as Button, plus `loading
|
|
28
|
-
|
|
27
|
+
here. `size` `lg` 40px / `md` 28px / `sm` 24px, the SAME `color` palette as Button, plus `loading`
|
|
28
|
+
and `elevated` (white fill + border + shadow, for a button sitting ON imagery — a tile's remove ✕,
|
|
29
|
+
an overlay's retry); needs `accessibilityLabel`/`tooltip`), `LinkButton` (quiet ghost
|
|
29
30
|
action — Clear / Select all), `Chip` (dismissible facet chip). A button is never a raw
|
|
30
31
|
`Pressable`. For a link OUT (a URL / record / document) use `Link` — underline+blue, the
|
|
31
32
|
destination signal; the opposite of `LinkButton` (a quiet in-app action, never underlined).
|
|
@@ -74,7 +75,15 @@ Pick by capability, not by name. (→ the source file for the API.)
|
|
|
74
75
|
`Alert` (the blocking confirm).
|
|
75
76
|
- **Status / feedback** — `Badge` / `StatusBadge`, `Callout` (inline status), `EmptyState`,
|
|
76
77
|
`CompletionState`, `ActivityIndicator` / `Loading`, `Skeleton`.
|
|
77
|
-
- **Files** — `FileDropzone`, `
|
|
78
|
+
- **Files** — `FileDropzone`, `FileRows` (batteries-included file LIST: tap a row → built-in
|
|
79
|
+
full-screen gallery, ⋯ menu = Download · Open-external · Remove; the default "here are some files"
|
|
80
|
+
surface), `FileGrid` (the upload-aware grid: completed files + a live upload
|
|
81
|
+
queue in one surface — use this for any add-files screen), `FileThumbnail` / `FileThumbnailGrid`
|
|
82
|
+
(square tiles, display-only), `UploadingThumbnail` (the single in-flight tile FileGrid renders —
|
|
83
|
+
reach for it only when hand-rolling a non-grid upload layout), `FileRow` (a horizontal file/document
|
|
84
|
+
LINE — badge-or-placeholder + name + meta + a composable `trailing` slot for a status badge / action
|
|
85
|
+
/ remove; `onPress` makes the whole row a pressable door, `trailing` stays an independently-pressable
|
|
86
|
+
sibling; for checklists & readable lists), `FileBadge` (the two-tone type mark), `FilePreview` /
|
|
78
87
|
`FileGalleryModal`, `ImageGallery`; for gated CRUD compose locally with `useSelectionMode` +
|
|
79
88
|
`shareOrDownloadFiles` + `rotateImageToBlob` (see §Data entry → Attachments).
|
|
80
89
|
- **Specialized work surfaces** — `ScanField` (scan/verify), `Stepper` (a guided run / progress
|
|
@@ -199,23 +208,49 @@ marked + disabled), not a generic text menu. A composition (Badge + Button + Pop
|
|
|
199
208
|
|
|
200
209
|
### Attachments — a full add / preview / DELETE field
|
|
201
210
|
Capture with `<FileDropzone onFiles accept label hint dropLabel height>` (drag-over lights the
|
|
202
|
-
accent; click falls back to a picker); display what landed with
|
|
211
|
+
accent; click falls back to a picker); display what landed with **`<FileGrid files uploads>`** ABOVE
|
|
203
212
|
the dropzone (existing files are the content; the dropzone sinks to the bottom as the "add more"
|
|
204
|
-
affordance — only the empty state leads with it).
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
`
|
|
214
|
-
|
|
213
|
+
affordance — only the empty state leads with it). `FileGrid` is the upload-aware grid: `files` are
|
|
214
|
+
the saved/completed `DisplayFile`s, `uploads` is the LIVE add-queue (`FileUpload[]`) — it interleaves
|
|
215
|
+
both and renders each in-flight tile itself — a LABELED status overlay (uploading spinner · "Retrying"
|
|
216
|
+
· "Paused" · "Upload failed" + a retry button · "Can't upload" for a dead/empty file) — so you never
|
|
217
|
+
hand-map an upload to a `FileThumbnail`. Localize the labels with `labels.upload` (an
|
|
218
|
+
`UploadStatusLabels`; the Lotics `@lotics/ui-internal` adapter already injects vi/en). Make it CRUDable
|
|
219
|
+
by wiring its callbacks: `onFilePress`
|
|
220
|
+
→ set a `number|null` index that drives `<FileGalleryModal files activeIndex onIndexChange>` — a
|
|
221
|
+
FULL-SCREEN viewer with a toolbar (filename · counter · ⋯actions (download, optional
|
|
222
|
+
`onOpenExternal`/`onRemove`) · close-✕), prev/next, ESC, and rotate; `onDisplayRemove`/`onUploadRemove`
|
|
223
|
+
→ drop the file / cancel the upload (the grid renders a ✕ on each tile automatically); `onRetry` /
|
|
224
|
+
`onRetryAll` for failed uploads. In a sandboxed custom-code app the toolbar's "open in new tab" can't
|
|
225
|
+
pop a window — pass `onOpenExternal` wired to the SDK's `openExternal` (omit it elsewhere and the
|
|
226
|
+
action hides). PDF/Word/Excel/CSV all render INLINE here (pdf.js / `@lotics/docx` / `@lotics/xlsx`,
|
|
227
|
+
lazy) — no native `<iframe>` viewer, so they work inside the cross-origin app iframe. Keep
|
|
228
|
+
label+grid+dropzone on a `gap` (a bare `CardBody` has none). By default `FileGrid` tiles FILL the
|
|
229
|
+
container width — a uniform size (≥ `minItemWidth`, default 96) so full rows span the width and reflow
|
|
230
|
+
as it changes; a short last row keeps that size and left-aligns (no stretched tiles, no empty cells).
|
|
231
|
+
Pass `columns` for a fixed column count, or `itemSize` for exact fixed-size tiles. For a dense strip
|
|
232
|
+
in a FIXED-width container that must NOT wrap, pass `singleRow` — it fits as many tiles as the width
|
|
233
|
+
allows and collapses the rest into a clickable "+N" overflow tile (`onOverflowPress(hiddenCount)`,
|
|
234
|
+
which the host wires — e.g. open the gallery at the first hidden file). This is the responsive overflow
|
|
235
|
+
pattern (avatar stack / Finder); prefer it over a hardcoded `maxVisible`, which can't adapt to width.
|
|
236
|
+
Under the hood it composes `FileThumbnail` (the completed tile — right surface per
|
|
237
|
+
MIME: image thumbnail · a doc tile with the `FileBadge` centered + a single-line filename · media
|
|
238
|
+
card; also takes `isTemplate` to overlay a TMPL marker) and `UploadingThumbnail` (the in-flight tile);
|
|
239
|
+
reach for either directly only when hand-rolling a NON-grid layout. **When the filename must be
|
|
240
|
+
readable, use `FileRow`** — a horizontal LINE (`FileBadge` or a `placeholder` + the FULL name + a meta
|
|
241
|
+
line + a composable `trailing` slot). `onPress` makes the whole row a pressable door (open the file);
|
|
242
|
+
`trailing` (a status `Badge`, an action, a remove ✕) stays an independently-pressable sibling. For
|
|
243
|
+
attachment lists / message files / document checklists where a square tile truncates the name. Never hand-build a drop well, a file grid, the upload tiles, or a preview
|
|
244
|
+
modal. In a custom-code APP, don't hand-roll the upload+preview state either — `@lotics/app-sdk`
|
|
245
|
+
`useAttachments()` gives the chat's instant-preview lifecycle (local object-URL now, `file_id` on
|
|
246
|
+
complete); map each `AttachedFile` to a `FileUpload` (ready → `{ status: "complete", id, file: {…} }`,
|
|
247
|
+
else `{ status, id, filename, mimeType: mime_type, previewUrl: preview_url }`) and feed `FileGrid`'s
|
|
248
|
+
`uploads` — `onUploadRemove={remove}`.
|
|
215
249
|
|
|
216
250
|
**Gated file CRUD is a PATTERN, composed locally — not a sealed kit component.** When a file field must
|
|
217
|
-
GUARD deletion (operator-facing, accidental delete is a real risk),
|
|
218
|
-
|
|
251
|
+
GUARD deletion (operator-facing, accidental delete is a real risk), DON'T use `FileGrid` (its per-tile
|
|
252
|
+
✕ is exactly the stray-tap risk you're guarding against) — compose it in the app from the kit pieces;
|
|
253
|
+
don't reach for a one-size widget (the action set + layout vary per app — the host frontend's
|
|
219
254
|
`files_editor` and each app compose their own). The recipe: `FileDropzone` (add) + `FileThumbnailGrid
|
|
220
255
|
files selectedIds onFilePress` (pass `selectedIds` ONLY in select mode) + `FileGalleryModal` (view +
|
|
221
256
|
rotate + persist) + a `Dialog` confirm, all driven by **`useSelectionMode()`** — the reusable LOGIC. The
|
|
@@ -479,6 +514,16 @@ was only ever about the review surfaces' sparkles/severity glyphs, not functiona
|
|
|
479
514
|
padded container, NO `Divider`s (the gap + rounded hover separate them).
|
|
480
515
|
Right-hand columns align only if every trailing element is FIXED-width (give each trailing action
|
|
481
516
|
a fixed `width`, so amount/status columns don't jitter).
|
|
517
|
+
- **Row actions are ALWAYS-VISIBLE siblings, never hover-revealed, never nested.** A pressable row =
|
|
518
|
+
a role-less surface (the hover/press wash, via DOM `mouseenter` so it covers the whole row) + an
|
|
519
|
+
accessible "Open …" door (the body, a button) + trailing actions (⋯, remove ✕, edit) as SIBLINGS of
|
|
520
|
+
the door — a button must not contain another button, so the action is independently pressable and
|
|
521
|
+
the ✕ isn't swallowed by the row press (`FileRow` and `PressableRow` are the references). Actions
|
|
522
|
+
stay **visible** — a hover-only action is invisible to keyboard and touch users. The ONLY exception
|
|
523
|
+
is a DENSE tree/register where a persistent per-row action would clutter (e.g. the DB sidebar):
|
|
524
|
+
reveal on hover **OR focus-within**, keeping the action in the DOM + tab order and gating only its
|
|
525
|
+
opacity, so it's still keyboard-reachable. Do that locally — there is no shared hover-reveal
|
|
526
|
+
primitive (the old `HoverAction` made the keyboard-inaccessible anti-pattern easy and was removed).
|
|
482
527
|
- **Master-detail = list + workspace `Drawer` with sequencing.** Pressing a PRIMARY entity row
|
|
483
528
|
opens the record workspace in a `Drawer` with `onPrev`/`onNext`/`position` ("3/24") over the
|
|
484
529
|
visible ordering (←/→ built in). Key the drawer body by record id so per-record state resets on
|
|
@@ -619,7 +664,7 @@ command_menu · alert · peek · empty_state · completion_state · callout (Cal
|
|
|
619
664
|
CalloutText · CalloutActions) · kpi_card · kpi_strip · metric · trend_chip · sparkline ·
|
|
620
665
|
bar_chart · line_chart · pie_chart · ring_gauge · progress_bar · stacked_progress_bar · breakdown ·
|
|
621
666
|
status_grid (StatusGrid + StatusLegend) · heatmap · legend_item · remainder_meter · allocation_row ·
|
|
622
|
-
scan_field · file_dropzone · file_thumbnail · file_thumbnail_grid · file_preview ·
|
|
667
|
+
scan_field · file_dropzone · file_grid (FileGrid — the upload-aware grid: completed files + a live upload queue in one surface; FileUpload/PendingUpload types; the add-files default) · uploading_thumbnail (UploadingThumbnail — the single in-flight upload tile FileGrid renders; reach for it only when hand-rolling a non-grid upload layout) · file_thumbnail · file_thumbnail_grid · file_row · file_rows (FileRows — batteries-included file list: row press → built-in gallery + a ⋯ Download/Open-external/Remove menu; composes FileRow + ActionMenu + FileGalleryModal) · file_preview ·
|
|
623
668
|
file_gallery_modal · image_gallery · use_selection_mode · share_or_download · rotate_image · avatar · skeleton · activity_indicator · loading · divider ·
|
|
624
669
|
spacer · stack · section_card · page_header · page_content · calendar (calendar/index.ts) · gantt ·
|
|
625
670
|
comments_thread · agent_run (live streaming work feed) · agent_progress (its compact floating
|
package/examples/tpl_convert.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import { Card } from "@lotics/ui/card";
|
|
|
8
8
|
import { DetailRow } from "@lotics/ui/detail_row";
|
|
9
9
|
import { Divider } from "@lotics/ui/divider";
|
|
10
10
|
import { Drawer, DrawerFooter } from "@lotics/ui/drawer";
|
|
11
|
-
import {
|
|
11
|
+
import { FileRow } from "@lotics/ui/file_row";
|
|
12
12
|
import { FileDropzone } from "@lotics/ui/file_dropzone";
|
|
13
13
|
import { FileThumbnailGrid } from "@lotics/ui/file_thumbnail_grid";
|
|
14
14
|
import { FileGalleryModal } from "@lotics/ui/file_gallery_modal";
|
|
@@ -37,8 +37,8 @@ import { Timeline, type TimelineItem } from "@lotics/ui/timeline";
|
|
|
37
37
|
// required-document checklist with a free FILE DUMP for anything extra. The
|
|
38
38
|
// drawer's ◀▶ keys walk the manager down the queue without closing it.
|
|
39
39
|
//
|
|
40
|
-
// Reference composition — Drawer (list nav) + Stepper +
|
|
41
|
-
// + Pagination + DetailRow.
|
|
40
|
+
// Reference composition — Drawer (list nav) + Stepper + FileRow (badge + name +
|
|
41
|
+
// meta + a trailing status/action slot) + Pagination + DetailRow.
|
|
42
42
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
43
|
|
|
44
44
|
const CODES: Record<string, string> = {
|
|
@@ -141,21 +141,9 @@ function QueueRow({ app, active, onPress }: { app: Applicant; active: boolean; o
|
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}) {
|
|
148
|
-
return (
|
|
149
|
-
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
150
|
-
<FileBadge size={30} mimeType={mimeType} placeholder={placeholder} />
|
|
151
|
-
<View style={{ flex: 1 }}>
|
|
152
|
-
<Text size="sm" weight="medium">{name}</Text>
|
|
153
|
-
{meta ? <Text size="xs" color="muted">{meta}</Text> : null}
|
|
154
|
-
</View>
|
|
155
|
-
{action ?? (tone === "received" ? <Badge variant="dot" label="Received" color="emerald" /> : tone === "ready" ? <Badge variant="dot" label="Generated" color="blue" /> : null)}
|
|
156
|
-
</View>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
144
|
+
// Document status chips — the `trailing` slot content for the kit's `FileRow`.
|
|
145
|
+
const receivedBadge = <Badge variant="dot" label="Received" color="emerald" />;
|
|
146
|
+
const generatedBadge = <Badge variant="dot" label="Generated" color="blue" />;
|
|
159
147
|
|
|
160
148
|
// The extra-documents zone — the data-capture attachment field: a thumbnail grid
|
|
161
149
|
// (click to preview in the gallery, ✕ to delete) above a dropzone. Read-only once
|
|
@@ -189,7 +177,7 @@ function UploadsField({ uploads, editable, onAdd, onRemove }: {
|
|
|
189
177
|
) : uploads.length === 0 ? (
|
|
190
178
|
<Text size="sm" color="muted">No extra files.</Text>
|
|
191
179
|
) : null}
|
|
192
|
-
<FileGalleryModal files={uploads} activeIndex={active} onIndexChange={setActive}
|
|
180
|
+
<FileGalleryModal files={uploads} activeIndex={active} onIndexChange={setActive} />
|
|
193
181
|
</View>
|
|
194
182
|
);
|
|
195
183
|
}
|
|
@@ -217,7 +205,7 @@ function StageSection({ app, index, onMarkDoc, onAddUploads, onRemoveUpload }: {
|
|
|
217
205
|
if (status === "pending") {
|
|
218
206
|
body = <Text size="sm" color="muted">{`Unlocks after ${STAGES[index - 1].label.toLowerCase()}.`}</Text>;
|
|
219
207
|
} else if (index === 0) {
|
|
220
|
-
body = <FileRow name="Application fee receipt" meta={status === "done" ? `${formatMoney(app.fee)} · issued` : formatMoney(app.fee)} mimeType="application/pdf"
|
|
208
|
+
body = <FileRow name="Application fee receipt" meta={status === "done" ? `${formatMoney(app.fee)} · issued` : formatMoney(app.fee)} mimeType="application/pdf" trailing={status === "done" ? generatedBadge : undefined} />;
|
|
221
209
|
} else if (index === 1) {
|
|
222
210
|
body = (
|
|
223
211
|
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
|
|
@@ -229,7 +217,7 @@ function StageSection({ app, index, onMarkDoc, onAddUploads, onRemoveUpload }: {
|
|
|
229
217
|
body = (
|
|
230
218
|
<View style={{ gap: 10 }}>
|
|
231
219
|
{GENERATED_DOCS.map((d) => (
|
|
232
|
-
<FileRow key={d} name={d} mimeType="application/pdf" meta={status === "done" ? "generated" : "template"}
|
|
220
|
+
<FileRow key={d} name={d} mimeType="application/pdf" meta={status === "done" ? "generated" : "template"} trailing={status === "done" ? generatedBadge : undefined} />
|
|
233
221
|
))}
|
|
234
222
|
</View>
|
|
235
223
|
);
|
|
@@ -245,9 +233,9 @@ function StageSection({ app, index, onMarkDoc, onAddUploads, onRemoveUpload }: {
|
|
|
245
233
|
meta={d.received ? `${d.file} · received` : "Awaiting upload"}
|
|
246
234
|
mimeType={d.received ? "application/pdf" : undefined}
|
|
247
235
|
placeholder={!d.received}
|
|
248
|
-
|
|
236
|
+
trailing={status === "current"
|
|
249
237
|
? (d.received ? <Button title="Remove" color="muted" onPress={() => onMarkDoc(d.name, false)} /> : <Button title="Upload" color="secondary" onPress={() => onMarkDoc(d.name, true)} />)
|
|
250
|
-
: (d.received ?
|
|
238
|
+
: (d.received ? receivedBadge : undefined)}
|
|
251
239
|
/>
|
|
252
240
|
))}
|
|
253
241
|
</View>
|
package/examples/tpl_order.tsx
CHANGED
|
@@ -477,7 +477,7 @@ export function TplOrder() {
|
|
|
477
477
|
</Screen>
|
|
478
478
|
</Dialog>
|
|
479
479
|
|
|
480
|
-
<FileGalleryModal files={files} activeIndex={activeFile} onIndexChange={setActiveFile}
|
|
480
|
+
<FileGalleryModal files={files} activeIndex={activeFile} onIndexChange={setActiveFile} />
|
|
481
481
|
</ScrollView>
|
|
482
482
|
);
|
|
483
483
|
}
|
|
@@ -292,7 +292,7 @@ export function TplRatedesk() {
|
|
|
292
292
|
) : null}
|
|
293
293
|
</Dialog>
|
|
294
294
|
|
|
295
|
-
<FileGalleryModal files={files} activeIndex={activeFile} onIndexChange={setActiveFile}
|
|
295
|
+
<FileGalleryModal files={files} activeIndex={activeFile} onIndexChange={setActiveFile} />
|
|
296
296
|
</>
|
|
297
297
|
);
|
|
298
298
|
}
|
package/examples/tpl_record.tsx
CHANGED
|
@@ -295,7 +295,7 @@ export function TplRecord() {
|
|
|
295
295
|
</Card>
|
|
296
296
|
</View>
|
|
297
297
|
|
|
298
|
-
<FileGalleryModal files={docs} activeIndex={activeDoc} onIndexChange={setActiveDoc}
|
|
298
|
+
<FileGalleryModal files={docs} activeIndex={activeDoc} onIndexChange={setActiveDoc} />
|
|
299
299
|
</ScrollView>
|
|
300
300
|
);
|
|
301
301
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lotics/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./tokens": "./src/tokens.ts",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
"./file_badge": "./src/file_badge.tsx",
|
|
19
19
|
"./file_dropzone": "./src/file_dropzone.tsx",
|
|
20
20
|
"./file_thumbnail": "./src/file_thumbnail.tsx",
|
|
21
|
+
"./file_row": "./src/file_row.tsx",
|
|
22
|
+
"./file_rows": "./src/file_rows.tsx",
|
|
21
23
|
"./file_preview": {
|
|
22
24
|
"react-native": "./src/file_preview.tsx",
|
|
23
25
|
"default": "./src/file_preview.web.tsx"
|
|
@@ -29,6 +31,8 @@
|
|
|
29
31
|
"./use_image_rotation": "./src/use_image_rotation.ts",
|
|
30
32
|
"./use_selection_mode": "./src/use_selection_mode.ts",
|
|
31
33
|
"./file_thumbnail_grid": "./src/file_thumbnail_grid.tsx",
|
|
34
|
+
"./uploading_thumbnail": "./src/uploading_thumbnail.tsx",
|
|
35
|
+
"./file_grid": "./src/file_grid.tsx",
|
|
32
36
|
"./pagination": "./src/pagination.tsx",
|
|
33
37
|
"./bar_chart": "./src/bar_chart.tsx",
|
|
34
38
|
"./line_chart": "./src/line_chart.tsx",
|
|
@@ -192,7 +196,6 @@
|
|
|
192
196
|
},
|
|
193
197
|
"./use_async_fn": "./src/use_async_fn.ts",
|
|
194
198
|
"./use_form": "./src/use_form.ts",
|
|
195
|
-
"./hover_action": "./src/hover_action.tsx",
|
|
196
199
|
"./scroll_to_bottom": "./src/scroll_to_bottom.tsx",
|
|
197
200
|
"./animation_fade_in": "./src/animation_fade_in.tsx",
|
|
198
201
|
"./json_panel": "./src/json_panel.tsx",
|
|
@@ -233,6 +236,7 @@
|
|
|
233
236
|
"expo-image": ">=3.0.0",
|
|
234
237
|
"lucide-react": ">=0.460.0",
|
|
235
238
|
"lucide-react-native": ">=0.460.0",
|
|
239
|
+
"pdfjs-dist": ">=6.0.0",
|
|
236
240
|
"react": "^19.2.0",
|
|
237
241
|
"react-dom": "^19.2.0",
|
|
238
242
|
"react-native": ">=0.85.0",
|
|
@@ -246,6 +250,9 @@
|
|
|
246
250
|
"@lotics/xlsx": {
|
|
247
251
|
"optional": true
|
|
248
252
|
},
|
|
253
|
+
"pdfjs-dist": {
|
|
254
|
+
"optional": true
|
|
255
|
+
},
|
|
249
256
|
"expo-image": {
|
|
250
257
|
"optional": true
|
|
251
258
|
},
|
|
@@ -271,6 +278,7 @@
|
|
|
271
278
|
"@types/react-dom": "~19.2.2",
|
|
272
279
|
"@vitejs/plugin-react": "^4.3.4",
|
|
273
280
|
"lucide-react": "^0.562.0",
|
|
281
|
+
"pdfjs-dist": "^6.0.227",
|
|
274
282
|
"react-dom": "^19.2.0",
|
|
275
283
|
"react-native-web": "^0.21.0",
|
|
276
284
|
"vite": "^7.2.4"
|