@btndprojects/loam-ui-native 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/dist/accordion/index.js +5 -3
- package/dist/adaptive/index.js +6 -2
- package/dist/alert/index.js +5 -2
- package/dist/analyzer/index.js +9 -6
- package/dist/announcement/index.js +8 -5
- package/dist/audio-player/index.js +5 -3
- package/dist/avatar/index.js +5 -2
- package/dist/avatar-group/index.js +7 -3
- package/dist/badge/index.js +7 -4
- package/dist/banner/index.js +5 -2
- package/dist/board/index.js +11 -6
- package/dist/button/index.js +6 -3
- package/dist/camera-permission/index.js +15 -12
- package/dist/capture-result/index.js +19 -16
- package/dist/card/index.js +6 -3
- package/dist/card-form/index.js +12 -8
- package/dist/carousel/index.js +4 -2
- package/dist/chart/index.js +8 -5
- package/dist/charts/index.js +8 -6
- package/dist/chat/index.js +16 -0
- package/dist/checkbox/index.js +6 -4
- package/dist/checklist/index.js +11 -8
- package/dist/checkout/index.js +16 -11
- package/dist/chip/index.js +7 -4
- package/dist/{chunk-XNUVB5OL.js → chunk-2OLKPG4E.js} +92 -28
- package/dist/{chunk-RUZHTGKB.js → chunk-2PKYGLQ6.js} +71 -40
- package/dist/{chunk-UC2WGUP3.js → chunk-2SWKL3AJ.js} +91 -252
- package/dist/{chunk-AI4DWZCD.js → chunk-2SY63FCH.js} +63 -16
- package/dist/{chunk-F5XNPWS7.js → chunk-2TXERVVA.js} +92 -35
- package/dist/chunk-36EC2T6P.js +581 -0
- package/dist/chunk-3DUWIYV5.js +437 -0
- package/dist/{chunk-RGQWWKLA.js → chunk-3QMEOFW5.js} +275 -71
- package/dist/chunk-3WEZCGHX.js +265 -0
- package/dist/chunk-46MMSDGL.js +194 -0
- package/dist/{chunk-7O2FMUPT.js → chunk-4IZXHVFJ.js} +297 -92
- package/dist/{chunk-LAECSR4H.js → chunk-5LAAAXFP.js} +14 -8
- package/dist/{chunk-2A5NIQAK.js → chunk-5RENVKBQ.js} +134 -46
- package/dist/{chunk-2ZZ7TDJ4.js → chunk-5UTRIXQ6.js} +37 -31
- package/dist/{chunk-LOE5YNN3.js → chunk-5VFZRGVD.js} +37 -10
- package/dist/{chunk-52X2VYTD.js → chunk-67IZZ2MJ.js} +115 -60
- package/dist/{chunk-UYG5L34B.js → chunk-6YAQBXB3.js} +10 -4
- package/dist/{chunk-BTTFCMKG.js → chunk-74FLKD24.js} +94 -23
- package/dist/{chunk-ITTYJZWX.js → chunk-7BUIKDD6.js} +73 -18
- package/dist/{chunk-FOKG57CR.js → chunk-7OVVSVEZ.js} +273 -109
- package/dist/chunk-AEB7KCHQ.js +287 -0
- package/dist/chunk-APCWFOZW.js +28 -0
- package/dist/chunk-AWKQIE5I.js +139 -0
- package/dist/{chunk-VCDBXW5H.js → chunk-B7N4ASYE.js} +86 -42
- package/dist/{chunk-IVNRBPGC.js → chunk-C4GTDLRC.js} +104 -20
- package/dist/{chunk-4ZAHCY44.js → chunk-C6APNDVA.js} +12 -5
- package/dist/{chunk-4SZYY6AN.js → chunk-CMTVNF3D.js} +18 -13
- package/dist/{chunk-WVKKJA6U.js → chunk-CPTOADB2.js} +151 -96
- package/dist/chunk-D5N5QWI7.js +1325 -0
- package/dist/{chunk-IIQTAY3J.js → chunk-DN7MNQIP.js} +113 -29
- package/dist/{chunk-47FWHGUN.js → chunk-DVGBZ3TX.js} +84 -23
- package/dist/chunk-DW3L54DQ.js +305 -0
- package/dist/{chunk-3ARE4TES.js → chunk-E2E3I5W2.js} +69 -18
- package/dist/{chunk-DHWADYZX.js → chunk-EDCBJV7J.js} +41 -28
- package/dist/{chunk-WSW6ZFAQ.js → chunk-ENP3BMZU.js} +4 -4
- package/dist/{chunk-OOPPQH27.js → chunk-EVOIGUBI.js} +43 -19
- package/dist/{chunk-VEAYTRPX.js → chunk-EY4DD67D.js} +165 -97
- package/dist/{chunk-223Q2T2Q.js → chunk-F3H33DQX.js} +132 -61
- package/dist/{chunk-CYRBHQQZ.js → chunk-F5B3UINI.js} +68 -35
- package/dist/{chunk-6X6PQ443.js → chunk-FAJI7BSC.js} +20 -9
- package/dist/{chunk-MOUJOP55.js → chunk-FUMHAAF3.js} +96 -29
- package/dist/{chunk-6HT2LP62.js → chunk-FV6HMP7W.js} +192 -73
- package/dist/{chunk-S7F6XLTK.js → chunk-FYWNRX4F.js} +76 -47
- package/dist/{chunk-YG3ZJHGU.js → chunk-FZGAAOKS.js} +30 -8
- package/dist/{chunk-YDGVJETP.js → chunk-G3AFC24V.js} +1 -1
- package/dist/{chunk-EJBDRVIH.js → chunk-G6UESEVN.js} +15 -8
- package/dist/chunk-GDKVKNR2.js +339 -0
- package/dist/chunk-GEIGMWNF.js +10 -0
- package/dist/{chunk-JUAMLEHX.js → chunk-H7DWSL4O.js} +24 -12
- package/dist/chunk-HJFFOOJ4.js +1 -0
- package/dist/{chunk-RW6ZL2FQ.js → chunk-HJLPZA4X.js} +106 -21
- package/dist/chunk-HYEOQWT7.js +647 -0
- package/dist/chunk-I2KLQ2HA.js +19 -0
- package/dist/{chunk-CJ5EOYZE.js → chunk-I4FHVKEC.js} +11 -5
- package/dist/{chunk-JNH2TYIN.js → chunk-IDM7JJMO.js} +19 -5
- package/dist/{chunk-O4AEHWII.js → chunk-IPUNJMAQ.js} +141 -49
- package/dist/{chunk-J7Q7VCVC.js → chunk-IT6FUXXG.js} +13 -6
- package/dist/{chunk-QJJ6MADV.js → chunk-IVKMZ7BB.js} +80 -28
- package/dist/{chunk-Z7H7VSFZ.js → chunk-IXKWIFWZ.js} +17 -6
- package/dist/chunk-J64KGCGX.js +55 -0
- package/dist/chunk-JBMLWFSJ.js +270 -0
- package/dist/{chunk-4BXMXBJO.js → chunk-JJLPBRVZ.js} +22 -11
- package/dist/chunk-JLC6PM5S.js +406 -0
- package/dist/chunk-JUYWSSKW.js +335 -0
- package/dist/{chunk-7CFF4HXS.js → chunk-JV5YOTOB.js} +49 -11
- package/dist/{chunk-LZLHELAG.js → chunk-KFJGFLMW.js} +29 -8
- package/dist/{chunk-O7AE6DAF.js → chunk-KQZ3GLHR.js} +18 -8
- package/dist/{chunk-N32RGOA5.js → chunk-LKFC4CS7.js} +80 -24
- package/dist/{chunk-YC6WORFL.js → chunk-LMPHCVJJ.js} +82 -50
- package/dist/{chunk-3WPW4KUN.js → chunk-LQP4KEXZ.js} +45 -13
- package/dist/{chunk-TKQYWZ5V.js → chunk-LUMVGO2K.js} +47 -31
- package/dist/{chunk-AWJOCGFZ.js → chunk-M656FYNH.js} +25 -13
- package/dist/{chunk-35OFI3JG.js → chunk-MKSNFG7H.js} +73 -20
- package/dist/{chunk-4GBOGOTV.js → chunk-NBEF4EPJ.js} +16 -6
- package/dist/chunk-NNCOFLNE.js +24 -0
- package/dist/{chunk-4YQOR7JM.js → chunk-NTQ2F3AU.js} +73 -20
- package/dist/{chunk-QCDXZBC5.js → chunk-O5V4TG3V.js} +126 -44
- package/dist/{chunk-U7TFM2JA.js → chunk-OJQUBQWA.js} +3 -3
- package/dist/{chunk-VQHPQEUH.js → chunk-OWAMM2DK.js} +13 -6
- package/dist/chunk-PID3NJB7.js +405 -0
- package/dist/{chunk-66SG2H23.js → chunk-PMMTGBBS.js} +27 -17
- package/dist/{chunk-RIBDXGUG.js → chunk-PNF3NKB5.js} +49 -16
- package/dist/{chunk-JXJB2X6M.js → chunk-Q6NKEPRE.js} +81 -32
- package/dist/chunk-QDZGFXQD.js +176 -0
- package/dist/{chunk-SYNOJOQO.js → chunk-QEYFDRHR.js} +60 -26
- package/dist/{chunk-VBOXAEPI.js → chunk-QHAITQIF.js} +97 -22
- package/dist/{chunk-VXDZFJGP.js → chunk-QHTVYA65.js} +230 -76
- package/dist/{chunk-TUTI5HOZ.js → chunk-QIKT7LIB.js} +14 -8
- package/dist/{chunk-3ENTMPQY.js → chunk-QP3KMOVF.js} +82 -42
- package/dist/{chunk-GNNJ4GCC.js → chunk-QPWDDJJ4.js} +62 -148
- package/dist/{chunk-QWCMU5B2.js → chunk-QRUMA22E.js} +205 -80
- package/dist/{chunk-ZVFE5QGU.js → chunk-QYPE5JX3.js} +50 -10
- package/dist/{chunk-PUPM2YGF.js → chunk-ROCUG24E.js} +76 -36
- package/dist/{chunk-NQYBUO3K.js → chunk-RU3ZPNL6.js} +333 -142
- package/dist/{chunk-TOXAGRDQ.js → chunk-RXSCIO6W.js} +14 -5
- package/dist/{chunk-FIF2M24N.js → chunk-SATMR6SG.js} +631 -203
- package/dist/{chunk-4YIP3CWS.js → chunk-SHHY5OMK.js} +7 -5
- package/dist/chunk-SKWO3SZF.js +2284 -0
- package/dist/{chunk-YF4NSSMT.js → chunk-SWS5JQIF.js} +41 -13
- package/dist/{chunk-CUMUNPXY.js → chunk-T5LTPKX6.js} +15 -7
- package/dist/{chunk-H6NIOQHK.js → chunk-TDMG26JI.js} +26 -6
- package/dist/{chunk-UWFLYMAR.js → chunk-TLCIR6RG.js} +267 -126
- package/dist/{chunk-SBMNWWBV.js → chunk-TN2ZNJUI.js} +47 -9
- package/dist/{chunk-5YNTNN5A.js → chunk-TQVAIKFD.js} +106 -41
- package/dist/chunk-TRGFFU6A.js +1456 -0
- package/dist/{chunk-2GK6PHGE.js → chunk-TY4MTKQJ.js} +100 -22
- package/dist/{chunk-AZRX6SAC.js → chunk-U23FYWME.js} +15 -7
- package/dist/{chunk-PZXZJBMP.js → chunk-U5NLHYV6.js} +26 -12
- package/dist/chunk-UQEN55EY.js +1 -0
- package/dist/chunk-UQGBTPXH.js +218 -0
- package/dist/chunk-UXGIW7OK.js +116 -0
- package/dist/{chunk-PJXUJYS6.js → chunk-UYGDJWMN.js} +55 -30
- package/dist/{chunk-QDYDBCFP.js → chunk-V2OEB75Z.js} +50 -51
- package/dist/{chunk-LSS54GLJ.js → chunk-VAOAKWUK.js} +34 -13
- package/dist/{chunk-DM5QUKKO.js → chunk-VDPK5CY4.js} +18 -6
- package/dist/chunk-W23G6JLF.js +37 -0
- package/dist/{chunk-CDRZHT42.js → chunk-W63AJTM7.js} +276 -12
- package/dist/{chunk-XXXEFXY5.js → chunk-W74TXYFB.js} +13 -5
- package/dist/{chunk-LRJNDEIA.js → chunk-WRDSPUE7.js} +144 -29
- package/dist/{chunk-C2NTXVWM.js → chunk-XBZGDDMR.js} +11 -4
- package/dist/{chunk-BV3B2HYZ.js → chunk-XIDTBCBA.js} +189 -131
- package/dist/{chunk-DSJBXLUG.js → chunk-XN4KG3P4.js} +348 -153
- package/dist/chunk-XQXMLMH3.js +211 -0
- package/dist/{chunk-HPPW424V.js → chunk-XTORZWRF.js} +19 -8
- package/dist/{chunk-P23EQNRQ.js → chunk-YAAHPATV.js} +181 -30
- package/dist/{chunk-KMI5ML5I.js → chunk-YXOAPXMU.js} +57 -18
- package/dist/{chunk-RJQOOHT2.js → chunk-ZECZOOSB.js} +59 -28
- package/dist/{chunk-QKXCPTFS.js → chunk-ZLTO5VQI.js} +121 -31
- package/dist/{chunk-BEDBFJND.js → chunk-ZVATDZOM.js} +16 -18
- package/dist/coachmark/index.js +6 -3
- package/dist/code-block/index.js +5 -3
- package/dist/color-field/index.js +6 -4
- package/dist/commerce/index.js +19 -16
- package/dist/connectivity/index.js +5 -2
- package/dist/context-menu/index.js +5 -3
- package/dist/copy-button/index.js +4 -2
- package/dist/data-grid/index.js +21 -16
- package/dist/date-range-picker/index.js +11 -8
- package/dist/description-list/index.js +3 -1
- package/dist/dialog/index.js +4 -2
- package/dist/empty-state/index.js +4 -2
- package/dist/error-summary/index.js +4 -2
- package/dist/fab/index.js +5 -2
- package/dist/file-manager/index.js +28 -0
- package/dist/file-upload/index.js +10 -7
- package/dist/filter-bar/index.js +9 -6
- package/dist/flow-run/index.js +15 -12
- package/dist/form/index.js +5 -3
- package/dist/gallery/index.js +5 -2
- package/dist/hold-to-confirm/index.js +4 -2
- package/dist/index.d.ts +9557 -2985
- package/dist/index.js +355 -122
- package/dist/infinite-list/index.js +4 -2
- package/dist/inline-edit/index.js +6 -4
- package/dist/input/index.js +5 -3
- package/dist/interactions/index.js +2 -1
- package/dist/invoice/index.js +13 -9
- package/dist/kbd/index.js +5 -1
- package/dist/keyboard/index.js +4 -2
- package/dist/list-row/index.js +6 -4
- package/dist/log-viewer/index.js +4 -2
- package/dist/map-view/index.js +5 -3
- package/dist/markdown/index.js +9 -6
- package/dist/metric/index.js +7 -4
- package/dist/money/index.js +9 -3
- package/dist/nav-drawer/index.js +4 -2
- package/dist/nav-header/index.js +9 -0
- package/dist/navigation/index.js +5 -2
- package/dist/notification-center/index.js +12 -10
- package/dist/number-roll/index.js +5 -2
- package/dist/one-handed/index.js +5 -3
- package/dist/os-surfaces/index.js +6 -3
- package/dist/otp/index.js +7 -4
- package/dist/page-header/index.js +1 -0
- package/dist/pagination/index.js +6 -0
- package/dist/payment-method/index.js +14 -10
- package/dist/payment-status/index.js +17 -14
- package/dist/permission/index.js +5 -2
- package/dist/picker/index.js +11 -6
- package/dist/progress/index.js +6 -3
- package/dist/pull-to-refresh/index.js +4 -2
- package/dist/radio-group/index.js +6 -4
- package/dist/rating/index.js +5 -2
- package/dist/receivables/index.js +21 -16
- package/dist/refund/index.js +18 -14
- package/dist/save-status/index.js +5 -3
- package/dist/scroll-area/index.js +3 -1
- package/dist/search-field/index.js +8 -0
- package/dist/segmented-control/index.js +4 -3
- package/dist/sheet/index.js +5 -3
- package/dist/skeleton/index.js +3 -1
- package/dist/slider/index.js +4 -2
- package/dist/sortable/index.js +7 -0
- package/dist/spinner/index.js +3 -1
- package/dist/split-button/index.js +9 -6
- package/dist/spotlight/index.js +3 -1
- package/dist/stage-timeline/index.js +5 -3
- package/dist/status-dot/index.js +4 -2
- package/dist/stepper/index.js +7 -4
- package/dist/streaming-text/index.js +3 -2
- package/dist/survey/index.js +18 -15
- package/dist/switch/index.js +5 -3
- package/dist/system-state/index.js +7 -4
- package/dist/tab-bar/index.js +5 -2
- package/dist/tabs/index.js +4 -2
- package/dist/tags-input/index.js +10 -0
- package/dist/textarea/index.js +6 -4
- package/dist/thinking/index.js +3 -1
- package/dist/time-field/index.js +12 -0
- package/dist/time-range-control/index.js +22 -0
- package/dist/timeline/index.js +4 -2
- package/dist/toast/index.js +4 -2
- package/dist/toolbar/index.js +4 -2
- package/dist/tour/index.js +12 -9
- package/dist/truncation-notice/index.js +5 -2
- package/dist/update-notice/index.js +12 -9
- package/dist/video-player/index.js +5 -2
- package/dist/viewfinder/index.js +6 -4
- package/dist/widget/index.js +7 -4
- package/dist/wizard/index.js +7 -4
- package/package.json +13 -12
- package/dist/chunk-6N33LFQA.js +0 -35
- package/dist/chunk-GDKZTW34.js +0 -395
- package/dist/chunk-GL7B2DOW.js +0 -134
- package/dist/chunk-NKB7BZYK.js +0 -167
- package/dist/chunk-OETCUXQP.js +0 -134
- package/dist/chunk-OPXFZ4Y5.js +0 -204
- package/dist/chunk-Q72LJOVE.js +0 -169
- package/dist/chunk-RNGLIHFA.js +0 -191
- package/dist/chunk-RQ3HASCC.js +0 -6
- package/dist/chunk-RSOJT5YW.js +0 -124
- package/dist/chunk-TKVFVF5D.js +0 -95
- package/dist/chunk-XOSCY2CW.js +0 -242
- package/dist/header/index.js +0 -5
- package/dist/search-bar/index.js +0 -5
- /package/dist/{chunk-3ECPOSKO.js → chunk-3UG6JUCV.js} +0 -0
- /package/dist/{chunk-JRLTGLN4.js → chunk-5WWRTEPS.js} +0 -0
- /package/dist/{chunk-RTIKSY6A.js → chunk-5Z5ZYMOJ.js} +0 -0
|
@@ -0,0 +1,1456 @@
|
|
|
1
|
+
import { NavHeader, NavHeaderAction } from './chunk-NTQ2F3AU.js';
|
|
2
|
+
import { ListRow } from './chunk-C4GTDLRC.js';
|
|
3
|
+
import { ContextMenu } from './chunk-U5NLHYV6.js';
|
|
4
|
+
import { EmptyState } from './chunk-KFJGFLMW.js';
|
|
5
|
+
import { SegmentedControl } from './chunk-TQVAIKFD.js';
|
|
6
|
+
import { Sheet } from './chunk-QYPE5JX3.js';
|
|
7
|
+
import { DescriptionList } from './chunk-QIKT7LIB.js';
|
|
8
|
+
import { Skeleton } from './chunk-PNF3NKB5.js';
|
|
9
|
+
import { TextField } from './chunk-7BUIKDD6.js';
|
|
10
|
+
import { Dialog, DialogFooter } from './chunk-GDKVKNR2.js';
|
|
11
|
+
import { Button } from './chunk-E2E3I5W2.js';
|
|
12
|
+
import { haptics } from './chunk-NY2U3PBI.js';
|
|
13
|
+
import { useLabels, useLoamLocale } from './chunk-APCWFOZW.js';
|
|
14
|
+
import { Icon } from './chunk-UXGIW7OK.js';
|
|
15
|
+
import { __export, __reExport } from './chunk-I2KLQ2HA.js';
|
|
16
|
+
import * as React5 from 'react';
|
|
17
|
+
import { View, Image, Text, ScrollView, FlatList, Pressable } from 'react-native';
|
|
18
|
+
import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
|
|
19
|
+
import * as loam_file_manager_core_star from '@btndprojects/loam-file-manager-core';
|
|
20
|
+
import { resolveFileManagerLabels, fileCategory, FILE_CATEGORY_ICON, DEFAULT_FILE_SORT, childrenOf, formatFileSize, indexEntries, pathTo, summarize, applyPending, isPlaceholderId, sortEntries, searchEntries, recentFiles, flattenRows, validateFileName, uniqueFileName, moveRefusal, placeholderId, topLevelIds } from '@btndprojects/loam-file-manager-core';
|
|
21
|
+
import { TIMING } from '@btndprojects/loam-tokens';
|
|
22
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
23
|
+
|
|
24
|
+
// src/file-manager/file-manager-labels.ts
|
|
25
|
+
var file_manager_labels_exports = {};
|
|
26
|
+
__export(file_manager_labels_exports, {
|
|
27
|
+
useFileManagerLabels: () => useFileManagerLabels
|
|
28
|
+
});
|
|
29
|
+
__reExport(file_manager_labels_exports, loam_file_manager_core_star);
|
|
30
|
+
var NO_DEFAULTS = {};
|
|
31
|
+
function useFileManagerLabels(own) {
|
|
32
|
+
const provided = useLabels("fileManager", NO_DEFAULTS);
|
|
33
|
+
return React5.useMemo(
|
|
34
|
+
() => resolveFileManagerLabels({
|
|
35
|
+
...provided,
|
|
36
|
+
...own,
|
|
37
|
+
sortKey: { ...provided.sortKey, ...own?.sortKey },
|
|
38
|
+
category: { ...provided.category, ...own?.category },
|
|
39
|
+
nameError: { ...provided.nameError, ...own?.nameError }
|
|
40
|
+
}),
|
|
41
|
+
[provided, own]
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function useDelayedLoading(loading, delay = TIMING.loadingFloor) {
|
|
45
|
+
const [visible, setVisible] = React5.useState(false);
|
|
46
|
+
const shownAt = React5.useRef(0);
|
|
47
|
+
React5.useEffect(() => {
|
|
48
|
+
if (loading) {
|
|
49
|
+
if (visible) return;
|
|
50
|
+
const t2 = setTimeout(() => {
|
|
51
|
+
shownAt.current = Date.now();
|
|
52
|
+
setVisible(true);
|
|
53
|
+
}, delay);
|
|
54
|
+
return () => clearTimeout(t2);
|
|
55
|
+
}
|
|
56
|
+
if (!visible) return;
|
|
57
|
+
const remaining = Math.max(0, delay - (Date.now() - shownAt.current));
|
|
58
|
+
const t = setTimeout(() => setVisible(false), remaining);
|
|
59
|
+
return () => clearTimeout(t);
|
|
60
|
+
}, [loading, visible, delay]);
|
|
61
|
+
return visible;
|
|
62
|
+
}
|
|
63
|
+
function FileIcon({ entry, size = "md" }) {
|
|
64
|
+
const theme = useLoamTheme("file-manager");
|
|
65
|
+
const { styles } = useStyles(sheet, { size });
|
|
66
|
+
const [broken, setBroken] = React5.useState(false);
|
|
67
|
+
const [loaded, setLoaded] = React5.useState(false);
|
|
68
|
+
const thumb = entry.thumbnailUrl;
|
|
69
|
+
React5.useEffect(() => {
|
|
70
|
+
setBroken(false);
|
|
71
|
+
setLoaded(false);
|
|
72
|
+
}, [thumb]);
|
|
73
|
+
const category = fileCategory(entry);
|
|
74
|
+
const showThumb = Boolean(thumb) && !broken && (size === "lg" || size === "xl");
|
|
75
|
+
const glyph = { sm: theme.icon.sm, md: theme.icon.md, lg: theme.space.s6, xl: theme.space.s7 }[size];
|
|
76
|
+
const large = size === "lg" || size === "xl";
|
|
77
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles.frame, showThumb && styles.thumbFrame], accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: [
|
|
78
|
+
!showThumb || !loaded ? /* @__PURE__ */ jsx(
|
|
79
|
+
Icon,
|
|
80
|
+
{
|
|
81
|
+
name: FILE_CATEGORY_ICON[category],
|
|
82
|
+
size: glyph,
|
|
83
|
+
strokeWidth: large ? 1.25 : 1.5,
|
|
84
|
+
color: category === "folder" ? theme.color.accentStrong : theme.color.text3
|
|
85
|
+
}
|
|
86
|
+
) : null,
|
|
87
|
+
showThumb ? /* @__PURE__ */ jsx(
|
|
88
|
+
Image,
|
|
89
|
+
{
|
|
90
|
+
source: { uri: thumb },
|
|
91
|
+
resizeMode: "cover",
|
|
92
|
+
onLoad: () => setLoaded(true),
|
|
93
|
+
onError: () => setBroken(true),
|
|
94
|
+
style: [styles.thumb, { opacity: loaded ? 1 : 0 }]
|
|
95
|
+
}
|
|
96
|
+
) : null
|
|
97
|
+
] });
|
|
98
|
+
}
|
|
99
|
+
var sheet = createStyleSheet((theme) => ({
|
|
100
|
+
frame: {
|
|
101
|
+
alignItems: "center",
|
|
102
|
+
justifyContent: "center",
|
|
103
|
+
overflow: "hidden",
|
|
104
|
+
variants: {
|
|
105
|
+
size: {
|
|
106
|
+
sm: { width: theme.icon.sm, height: theme.icon.sm },
|
|
107
|
+
md: { width: theme.icon.md, height: theme.icon.md },
|
|
108
|
+
lg: { width: theme.space[48], height: theme.space[48], borderRadius: theme.radius.sm },
|
|
109
|
+
xl: { width: theme.space[64], height: theme.space[64], borderRadius: theme.radius.md }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
thumbFrame: {
|
|
114
|
+
backgroundColor: theme.color.surface3,
|
|
115
|
+
borderWidth: theme.borderWidth.hair,
|
|
116
|
+
borderColor: theme.color.border
|
|
117
|
+
},
|
|
118
|
+
thumb: {
|
|
119
|
+
position: "absolute",
|
|
120
|
+
top: 0,
|
|
121
|
+
left: 0,
|
|
122
|
+
right: 0,
|
|
123
|
+
bottom: 0
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
function ChoiceRow({
|
|
127
|
+
icon,
|
|
128
|
+
label,
|
|
129
|
+
detail,
|
|
130
|
+
selected,
|
|
131
|
+
disabled,
|
|
132
|
+
indent = 0,
|
|
133
|
+
onPress
|
|
134
|
+
}) {
|
|
135
|
+
const theme = useLoamTheme("file-manager");
|
|
136
|
+
const { styles } = useStyles(sheet2);
|
|
137
|
+
return /* @__PURE__ */ jsxs(
|
|
138
|
+
Pressable,
|
|
139
|
+
{
|
|
140
|
+
accessibilityRole: "button",
|
|
141
|
+
accessibilityState: { selected: Boolean(selected), disabled: Boolean(disabled) },
|
|
142
|
+
accessibilityLabel: detail ? `${label}, ${detail}` : label,
|
|
143
|
+
disabled,
|
|
144
|
+
onPress,
|
|
145
|
+
style: ({ pressed }) => [
|
|
146
|
+
styles.choice,
|
|
147
|
+
{ paddingStart: theme.space.s4 + indent * theme.space.s5 },
|
|
148
|
+
pressed && styles.choicePressed,
|
|
149
|
+
disabled && styles.choiceDisabled
|
|
150
|
+
],
|
|
151
|
+
children: [
|
|
152
|
+
icon ? /* @__PURE__ */ jsx(Icon, { name: icon, size: theme.icon.md, color: selected ? theme.color.accentStrong : theme.color.text2 }) : null,
|
|
153
|
+
/* @__PURE__ */ jsx(Text, { style: [styles.choiceLabel, selected && styles.choiceLabelSelected], numberOfLines: 1, children: label }),
|
|
154
|
+
detail ? /* @__PURE__ */ jsx(Text, { style: styles.choiceDetail, children: detail }) : null,
|
|
155
|
+
selected ? /* @__PURE__ */ jsx(Icon, { name: "check", size: theme.icon.md, color: theme.color.accentStrong }) : null
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function GroupLabel({ children }) {
|
|
161
|
+
const { styles } = useStyles(sheet2);
|
|
162
|
+
return /* @__PURE__ */ jsx(Text, { style: styles.groupLabel, accessibilityRole: "header", children });
|
|
163
|
+
}
|
|
164
|
+
var SORT_KEYS = ["name", "modified", "size", "type"];
|
|
165
|
+
function FileOptionsSheet({
|
|
166
|
+
open,
|
|
167
|
+
onClose,
|
|
168
|
+
view,
|
|
169
|
+
onViewChange,
|
|
170
|
+
sort,
|
|
171
|
+
onSortChange,
|
|
172
|
+
onNewFolder,
|
|
173
|
+
labels,
|
|
174
|
+
safeAreaBottom,
|
|
175
|
+
motion
|
|
176
|
+
}) {
|
|
177
|
+
const { styles } = useStyles(sheet2);
|
|
178
|
+
return /* @__PURE__ */ jsxs(Sheet, { open, onClose, title: labels.view, closeLabel: labels.close, safeAreaBottom, motion, children: [
|
|
179
|
+
/* @__PURE__ */ jsx(View, { style: styles.segment, children: /* @__PURE__ */ jsx(
|
|
180
|
+
SegmentedControl,
|
|
181
|
+
{
|
|
182
|
+
accessibilityLabel: labels.view,
|
|
183
|
+
items: [
|
|
184
|
+
{ value: "grid", label: labels.viewGrid, icon: "grid" },
|
|
185
|
+
{ value: "list", label: labels.viewList, icon: "list-ul" }
|
|
186
|
+
],
|
|
187
|
+
value: view,
|
|
188
|
+
onValueChange: (v) => onViewChange(v),
|
|
189
|
+
motion
|
|
190
|
+
}
|
|
191
|
+
) }),
|
|
192
|
+
/* @__PURE__ */ jsx(GroupLabel, { children: labels.sort }),
|
|
193
|
+
SORT_KEYS.map((key) => {
|
|
194
|
+
const chosen = sort.key === key;
|
|
195
|
+
return /* @__PURE__ */ jsx(
|
|
196
|
+
ChoiceRow,
|
|
197
|
+
{
|
|
198
|
+
icon: chosen ? sort.direction === "asc" ? "arrow-up" : "arrow-down" : void 0,
|
|
199
|
+
label: labels.sortKey[key],
|
|
200
|
+
detail: chosen ? sort.direction === "asc" ? labels.ascending : labels.descending : void 0,
|
|
201
|
+
selected: chosen,
|
|
202
|
+
onPress: () => {
|
|
203
|
+
haptics.selection();
|
|
204
|
+
onSortChange(
|
|
205
|
+
chosen ? { key, direction: sort.direction === "asc" ? "desc" : "asc" } : { key, direction: key === "modified" || key === "size" ? "desc" : DEFAULT_FILE_SORT.direction }
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
key
|
|
210
|
+
);
|
|
211
|
+
}),
|
|
212
|
+
onNewFolder ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
213
|
+
/* @__PURE__ */ jsx(View, { style: styles.rule }),
|
|
214
|
+
/* @__PURE__ */ jsx(
|
|
215
|
+
ChoiceRow,
|
|
216
|
+
{
|
|
217
|
+
icon: "folder-plus",
|
|
218
|
+
label: labels.newFolder,
|
|
219
|
+
onPress: () => {
|
|
220
|
+
onClose();
|
|
221
|
+
onNewFolder();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] }) : null
|
|
226
|
+
] });
|
|
227
|
+
}
|
|
228
|
+
function FileLocations({ location, onLocationChange, folders, recents, favorites, labels }) {
|
|
229
|
+
const at = (l) => l.kind === location.kind && (l.kind !== "folder" || location.kind === "folder" && location.id === l.id);
|
|
230
|
+
return (
|
|
231
|
+
// A labelled group, not a list: its children are headings and choice rows,
|
|
232
|
+
// and a `list` that owns no `listitem` is an invalid ARIA tree on the web.
|
|
233
|
+
/* @__PURE__ */ jsxs(View, { role: "group", accessibilityLabel: labels.locations, children: [
|
|
234
|
+
/* @__PURE__ */ jsx(GroupLabel, { children: labels.locations }),
|
|
235
|
+
/* @__PURE__ */ jsx(ChoiceRow, { icon: "folder", label: labels.root, selected: at({ kind: "folder", id: null }), onPress: () => onLocationChange({ kind: "folder", id: null }) }),
|
|
236
|
+
recents ? /* @__PURE__ */ jsx(ChoiceRow, { icon: "clock", label: labels.recent, selected: at({ kind: "recent" }), onPress: () => onLocationChange({ kind: "recent" }) }) : null,
|
|
237
|
+
favorites ? /* @__PURE__ */ jsx(ChoiceRow, { icon: "star", label: labels.favorites, selected: at({ kind: "favorites" }), onPress: () => onLocationChange({ kind: "favorites" }) }) : null,
|
|
238
|
+
folders.length > 0 ? /* @__PURE__ */ jsx(GroupLabel, { children: labels.folders }) : null,
|
|
239
|
+
folders.map((f) => /* @__PURE__ */ jsx(ChoiceRow, { icon: "folder", label: f.name, selected: at({ kind: "folder", id: f.id }), onPress: () => onLocationChange({ kind: "folder", id: f.id }) }, f.id))
|
|
240
|
+
] })
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
function entryMeta(entry, items, labels, locale) {
|
|
244
|
+
if (entry.type === "folder") return labels.items(childrenOf(items, entry.id).length);
|
|
245
|
+
return [labels.category[fileCategory(entry)], entry.size !== void 0 ? formatFileSize(entry.size, locale) : ""].filter(Boolean).join(" \xB7 ");
|
|
246
|
+
}
|
|
247
|
+
function formatDate(value, locale) {
|
|
248
|
+
if (value === void 0) return "";
|
|
249
|
+
const d = new Date(value);
|
|
250
|
+
return Number.isNaN(d.getTime()) ? "" : d.toLocaleString(locale, { dateStyle: "medium", timeStyle: "short" });
|
|
251
|
+
}
|
|
252
|
+
function FileInfoSheet({ entry, items, onClose, labels, locale, safeAreaBottom, motion }) {
|
|
253
|
+
const { styles } = useStyles(sheet2);
|
|
254
|
+
const last = React5.useRef(entry);
|
|
255
|
+
if (entry) last.current = entry;
|
|
256
|
+
const shown = last.current;
|
|
257
|
+
const rows = React5.useMemo(() => {
|
|
258
|
+
if (!shown) return [];
|
|
259
|
+
const index = indexEntries(items);
|
|
260
|
+
const where = [labels.root, ...pathTo(index, shown.parentId).map((e) => e.name)].join(" \u203A ");
|
|
261
|
+
const out = [{ term: labels.kind, description: labels.category[fileCategory(shown)] }];
|
|
262
|
+
if (shown.type === "folder") {
|
|
263
|
+
const s = summarize(childrenOf(items, shown.id));
|
|
264
|
+
out.push({ term: labels.contains, description: labels.items(s.files + s.folders) });
|
|
265
|
+
} else if (shown.size !== void 0) {
|
|
266
|
+
out.push({ term: labels.size, description: formatFileSize(shown.size, locale) });
|
|
267
|
+
}
|
|
268
|
+
out.push({ term: labels.location, description: where });
|
|
269
|
+
const date = formatDate(shown.modifiedAt, locale);
|
|
270
|
+
if (date) out.push({ term: labels.modified, description: date });
|
|
271
|
+
if (shown.tags?.length) out.push({ term: labels.tags, description: shown.tags.join(", ") });
|
|
272
|
+
return out;
|
|
273
|
+
}, [shown, items, labels, locale]);
|
|
274
|
+
return /* @__PURE__ */ jsxs(Sheet, { open: entry !== null, onClose, title: labels.getInfo, closeLabel: labels.close, safeAreaBottom, motion, children: [
|
|
275
|
+
shown ? /* @__PURE__ */ jsxs(View, { style: styles.infoHead, children: [
|
|
276
|
+
/* @__PURE__ */ jsx(FileIcon, { entry: shown, size: "lg" }),
|
|
277
|
+
/* @__PURE__ */ jsxs(View, { style: styles.infoTitle, children: [
|
|
278
|
+
/* @__PURE__ */ jsx(Text, { style: styles.infoName, numberOfLines: 2, children: shown.name }),
|
|
279
|
+
/* @__PURE__ */ jsx(Text, { style: styles.infoMeta, numberOfLines: 1, children: entryMeta(shown, items, labels, locale) })
|
|
280
|
+
] })
|
|
281
|
+
] }) : null,
|
|
282
|
+
/* @__PURE__ */ jsx(View, { style: styles.infoBody, children: /* @__PURE__ */ jsx(DescriptionList, { items: rows }) })
|
|
283
|
+
] });
|
|
284
|
+
}
|
|
285
|
+
function FilePreviewSheet({
|
|
286
|
+
entry,
|
|
287
|
+
files,
|
|
288
|
+
onEntryChange,
|
|
289
|
+
onClose,
|
|
290
|
+
items,
|
|
291
|
+
renderPreview,
|
|
292
|
+
labels,
|
|
293
|
+
locale,
|
|
294
|
+
safeAreaBottom,
|
|
295
|
+
motion
|
|
296
|
+
}) {
|
|
297
|
+
const { styles } = useStyles(sheet2);
|
|
298
|
+
const last = React5.useRef(entry);
|
|
299
|
+
if (entry) last.current = entry;
|
|
300
|
+
const shown = last.current;
|
|
301
|
+
const [failed, setFailed] = React5.useState(false);
|
|
302
|
+
React5.useEffect(() => setFailed(false), [shown?.id]);
|
|
303
|
+
const at = shown ? files.findIndex((f) => f.id === shown.id) : -1;
|
|
304
|
+
const step = (by) => {
|
|
305
|
+
const next = files[at + by];
|
|
306
|
+
if (next) {
|
|
307
|
+
haptics.selection();
|
|
308
|
+
onEntryChange(next);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
const src = shown?.url ?? shown?.thumbnailUrl;
|
|
312
|
+
const custom = shown ? renderPreview?.(shown) : void 0;
|
|
313
|
+
const isImage = shown ? fileCategory(shown) === "image" && Boolean(src) && !failed : false;
|
|
314
|
+
return /* @__PURE__ */ jsx(
|
|
315
|
+
Sheet,
|
|
316
|
+
{
|
|
317
|
+
open: entry !== null,
|
|
318
|
+
onClose,
|
|
319
|
+
title: shown?.name,
|
|
320
|
+
closeLabel: labels.close,
|
|
321
|
+
detents: ["full"],
|
|
322
|
+
initialDetent: "full",
|
|
323
|
+
safeAreaBottom,
|
|
324
|
+
motion,
|
|
325
|
+
footer: files.length > 1 ? /* @__PURE__ */ jsxs(View, { style: styles.stepper, children: [
|
|
326
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", leadingIcon: "chevron-left", disabled: at <= 0, onPress: () => step(-1), accessibilityLabel: labels.previous, children: labels.previous }),
|
|
327
|
+
/* @__PURE__ */ jsx(Text, { style: styles.stepperCount, children: at >= 0 ? `${at + 1} / ${files.length}` : "" }),
|
|
328
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", trailingIcon: "chevron-right", disabled: at < 0 || at >= files.length - 1, onPress: () => step(1), accessibilityLabel: labels.next, children: labels.next })
|
|
329
|
+
] }) : void 0,
|
|
330
|
+
children: shown ? custom !== void 0 ? /* @__PURE__ */ jsx(View, { style: styles.previewBody, children: custom }) : isImage ? /* @__PURE__ */ jsx(View, { style: styles.previewImageWrap, children: /* @__PURE__ */ jsx(
|
|
331
|
+
Image,
|
|
332
|
+
{
|
|
333
|
+
source: { uri: src },
|
|
334
|
+
resizeMode: "contain",
|
|
335
|
+
onError: () => setFailed(true),
|
|
336
|
+
style: styles.previewImage,
|
|
337
|
+
accessibilityLabel: shown.name
|
|
338
|
+
}
|
|
339
|
+
) }) : /* @__PURE__ */ jsxs(View, { style: styles.previewEmpty, children: [
|
|
340
|
+
/* @__PURE__ */ jsx(FileIcon, { entry: shown, size: "xl" }),
|
|
341
|
+
/* @__PURE__ */ jsx(Text, { style: styles.previewTitle, children: failed ? labels.previewFailed : labels.previewUnavailable }),
|
|
342
|
+
/* @__PURE__ */ jsx(Text, { style: styles.previewMeta, children: entryMeta(shown, items, labels, locale) })
|
|
343
|
+
] }) : null
|
|
344
|
+
}
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
function FileMoveSheet({ entries, items, onMove, onClose, labels, locale, safeAreaBottom, motion }) {
|
|
348
|
+
const last = React5.useRef(entries);
|
|
349
|
+
if (entries.length > 0) last.current = entries;
|
|
350
|
+
const moving = last.current;
|
|
351
|
+
const [target, setTarget] = React5.useState(void 0);
|
|
352
|
+
React5.useEffect(() => {
|
|
353
|
+
if (entries.length > 0) setTarget(void 0);
|
|
354
|
+
}, [entries]);
|
|
355
|
+
const index = React5.useMemo(() => indexEntries(items), [items]);
|
|
356
|
+
const ids = React5.useMemo(() => moving.map((e) => e.id), [moving]);
|
|
357
|
+
const tree = React5.useMemo(() => {
|
|
358
|
+
const out = [];
|
|
359
|
+
const walk = (parentId, depth) => {
|
|
360
|
+
for (const f of sortEntries(childrenOf(items, parentId), DEFAULT_FILE_SORT, locale)) {
|
|
361
|
+
if (f.type !== "folder") continue;
|
|
362
|
+
out.push({ entry: f, depth });
|
|
363
|
+
walk(f.id, depth + 1);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
walk(null, 1);
|
|
367
|
+
return out;
|
|
368
|
+
}, [items, locale]);
|
|
369
|
+
const allowed = (id) => moveRefusal(index, ids, id) === null;
|
|
370
|
+
return /* @__PURE__ */ jsx(
|
|
371
|
+
Sheet,
|
|
372
|
+
{
|
|
373
|
+
open: entries.length > 0,
|
|
374
|
+
onClose,
|
|
375
|
+
title: labels.chooseFolder,
|
|
376
|
+
closeLabel: labels.close,
|
|
377
|
+
detents: ["half", "full"],
|
|
378
|
+
initialDetent: "full",
|
|
379
|
+
safeAreaBottom,
|
|
380
|
+
motion,
|
|
381
|
+
footer: /* @__PURE__ */ jsx(
|
|
382
|
+
Button,
|
|
383
|
+
{
|
|
384
|
+
variant: "primary",
|
|
385
|
+
fullWidth: true,
|
|
386
|
+
disabled: target === void 0,
|
|
387
|
+
onPress: () => {
|
|
388
|
+
if (target !== void 0) onMove(target);
|
|
389
|
+
},
|
|
390
|
+
children: labels.moveHere
|
|
391
|
+
}
|
|
392
|
+
),
|
|
393
|
+
children: /* @__PURE__ */ jsxs(ScrollView, { children: [
|
|
394
|
+
/* @__PURE__ */ jsx(ChoiceRow, { icon: "folder", label: labels.root, selected: target === null, disabled: !allowed(null), onPress: () => setTarget(null) }),
|
|
395
|
+
tree.map(({ entry, depth }) => /* @__PURE__ */ jsx(
|
|
396
|
+
ChoiceRow,
|
|
397
|
+
{
|
|
398
|
+
icon: "folder",
|
|
399
|
+
indent: depth,
|
|
400
|
+
label: entry.name,
|
|
401
|
+
selected: target === entry.id,
|
|
402
|
+
disabled: !allowed(entry.id),
|
|
403
|
+
onPress: () => setTarget(entry.id)
|
|
404
|
+
},
|
|
405
|
+
entry.id
|
|
406
|
+
))
|
|
407
|
+
] })
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
function FileNameDialog({ open, title, initialName, confirmLabel, validate, onSubmit, onClose, labels, motion }) {
|
|
412
|
+
const [name, setName] = React5.useState(initialName);
|
|
413
|
+
const [touched, setTouched] = React5.useState(false);
|
|
414
|
+
React5.useEffect(() => {
|
|
415
|
+
if (open) {
|
|
416
|
+
setName(initialName);
|
|
417
|
+
setTouched(false);
|
|
418
|
+
}
|
|
419
|
+
}, [open, initialName]);
|
|
420
|
+
const error = validate(name);
|
|
421
|
+
const submit = () => {
|
|
422
|
+
setTouched(true);
|
|
423
|
+
if (error) {
|
|
424
|
+
haptics.notify("error");
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
onSubmit(name.trim());
|
|
428
|
+
};
|
|
429
|
+
const dot = initialName.lastIndexOf(".");
|
|
430
|
+
const stemEnd = dot > 0 ? dot : initialName.length;
|
|
431
|
+
return /* @__PURE__ */ jsxs(Dialog, { open, onClose, title, motion, children: [
|
|
432
|
+
/* @__PURE__ */ jsx(
|
|
433
|
+
TextField,
|
|
434
|
+
{
|
|
435
|
+
label: labels.nameLabel,
|
|
436
|
+
value: name,
|
|
437
|
+
onChangeText: (t) => {
|
|
438
|
+
setName(t);
|
|
439
|
+
setTouched(true);
|
|
440
|
+
},
|
|
441
|
+
autoFocus: true,
|
|
442
|
+
selectTextOnFocus: false,
|
|
443
|
+
selection: touched ? void 0 : { start: 0, end: stemEnd },
|
|
444
|
+
autoCapitalize: "none",
|
|
445
|
+
autoCorrect: false,
|
|
446
|
+
returnKeyType: "done",
|
|
447
|
+
onSubmitEditing: submit,
|
|
448
|
+
error: touched && error ? labels.nameError[error] : void 0
|
|
449
|
+
}
|
|
450
|
+
),
|
|
451
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
452
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onPress: onClose, children: labels.cancel }),
|
|
453
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onPress: submit, children: confirmLabel })
|
|
454
|
+
] })
|
|
455
|
+
] });
|
|
456
|
+
}
|
|
457
|
+
function FileDeleteDialog({ entries, onConfirm, onClose, labels, motion }) {
|
|
458
|
+
const last = React5.useRef(entries);
|
|
459
|
+
if (entries) last.current = entries;
|
|
460
|
+
const list = last.current ?? [];
|
|
461
|
+
const first = list[0];
|
|
462
|
+
return /* @__PURE__ */ jsx(
|
|
463
|
+
Dialog,
|
|
464
|
+
{
|
|
465
|
+
open: entries !== null,
|
|
466
|
+
onClose,
|
|
467
|
+
title: labels.deleteTitle(list.length, first?.name ?? ""),
|
|
468
|
+
description: labels.deleteDescription,
|
|
469
|
+
motion,
|
|
470
|
+
children: /* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
471
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onPress: onClose, children: labels.keep }),
|
|
472
|
+
/* @__PURE__ */ jsx(Button, { variant: "danger", onPress: onConfirm, children: labels.deleteConfirm(list.length) })
|
|
473
|
+
] })
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
var sheet2 = createStyleSheet((theme) => ({
|
|
478
|
+
choice: {
|
|
479
|
+
flexDirection: "row",
|
|
480
|
+
alignItems: "center",
|
|
481
|
+
gap: theme.space.s3,
|
|
482
|
+
minHeight: theme.ctl.lg,
|
|
483
|
+
paddingEnd: theme.space.s4,
|
|
484
|
+
paddingVertical: theme.space.s2,
|
|
485
|
+
borderRadius: theme.radius.md
|
|
486
|
+
},
|
|
487
|
+
choicePressed: { backgroundColor: theme.color.surface2 },
|
|
488
|
+
choiceDisabled: { opacity: theme.state.disabledOpacity },
|
|
489
|
+
choiceLabel: {
|
|
490
|
+
flex: 1,
|
|
491
|
+
minWidth: 0,
|
|
492
|
+
fontFamily: theme.font.sans,
|
|
493
|
+
fontSize: theme.type.body.fontSize,
|
|
494
|
+
lineHeight: theme.type.body.lineHeight,
|
|
495
|
+
color: theme.color.text
|
|
496
|
+
},
|
|
497
|
+
choiceLabelSelected: { color: theme.color.accentStrong, fontWeight: theme.type.headline.fontWeight },
|
|
498
|
+
choiceDetail: {
|
|
499
|
+
fontFamily: theme.font.sans,
|
|
500
|
+
fontSize: theme.type.footnote.fontSize,
|
|
501
|
+
color: theme.color.text3
|
|
502
|
+
},
|
|
503
|
+
groupLabel: {
|
|
504
|
+
fontFamily: theme.font.sans,
|
|
505
|
+
fontSize: theme.type.footnote.fontSize,
|
|
506
|
+
fontWeight: theme.type.headline.fontWeight,
|
|
507
|
+
color: theme.color.text3,
|
|
508
|
+
paddingHorizontal: theme.space.s4,
|
|
509
|
+
paddingTop: theme.space.s4,
|
|
510
|
+
paddingBottom: theme.space.s2
|
|
511
|
+
},
|
|
512
|
+
segment: { paddingHorizontal: theme.space.s4, paddingTop: theme.space.s2 },
|
|
513
|
+
rule: {
|
|
514
|
+
height: theme.borderWidth.hair,
|
|
515
|
+
backgroundColor: theme.color.border,
|
|
516
|
+
marginHorizontal: theme.space.s4,
|
|
517
|
+
marginVertical: theme.space.s2
|
|
518
|
+
},
|
|
519
|
+
infoHead: {
|
|
520
|
+
flexDirection: "row",
|
|
521
|
+
alignItems: "center",
|
|
522
|
+
gap: theme.space.s3,
|
|
523
|
+
paddingHorizontal: theme.space.s4,
|
|
524
|
+
paddingBottom: theme.space.s3
|
|
525
|
+
},
|
|
526
|
+
infoTitle: { flex: 1, minWidth: 0, gap: theme.space.s1 },
|
|
527
|
+
infoName: {
|
|
528
|
+
fontFamily: theme.font.sans,
|
|
529
|
+
fontSize: theme.type.headline.fontSize,
|
|
530
|
+
fontWeight: theme.type.headline.fontWeight,
|
|
531
|
+
lineHeight: theme.type.headline.lineHeight,
|
|
532
|
+
color: theme.color.text
|
|
533
|
+
},
|
|
534
|
+
infoMeta: {
|
|
535
|
+
fontFamily: theme.font.sans,
|
|
536
|
+
fontSize: theme.type.subheadline.fontSize,
|
|
537
|
+
color: theme.color.text2
|
|
538
|
+
},
|
|
539
|
+
infoBody: { paddingHorizontal: theme.space.s4 },
|
|
540
|
+
stepper: {
|
|
541
|
+
flexDirection: "row",
|
|
542
|
+
alignItems: "center",
|
|
543
|
+
justifyContent: "space-between",
|
|
544
|
+
gap: theme.space.s2
|
|
545
|
+
},
|
|
546
|
+
stepperCount: {
|
|
547
|
+
fontFamily: theme.font.sans,
|
|
548
|
+
fontSize: theme.type.footnote.fontSize,
|
|
549
|
+
color: theme.color.text3,
|
|
550
|
+
fontVariant: ["tabular-nums"]
|
|
551
|
+
},
|
|
552
|
+
previewBody: { flex: 1, paddingHorizontal: theme.space.s4 },
|
|
553
|
+
previewImageWrap: { flex: 1, minHeight: theme.space[256], paddingHorizontal: theme.space.s4 },
|
|
554
|
+
previewImage: { flex: 1, width: "100%", borderRadius: theme.radius.md },
|
|
555
|
+
previewEmpty: {
|
|
556
|
+
flex: 1,
|
|
557
|
+
alignItems: "center",
|
|
558
|
+
justifyContent: "center",
|
|
559
|
+
gap: theme.space.s3,
|
|
560
|
+
paddingVertical: theme.space.s8,
|
|
561
|
+
paddingHorizontal: theme.space.s5
|
|
562
|
+
},
|
|
563
|
+
previewTitle: {
|
|
564
|
+
fontFamily: theme.font.sans,
|
|
565
|
+
fontSize: theme.type.headline.fontSize,
|
|
566
|
+
fontWeight: theme.type.headline.fontWeight,
|
|
567
|
+
color: theme.color.text,
|
|
568
|
+
textAlign: "center"
|
|
569
|
+
},
|
|
570
|
+
previewMeta: {
|
|
571
|
+
fontFamily: theme.font.sans,
|
|
572
|
+
fontSize: theme.type.subheadline.fontSize,
|
|
573
|
+
color: theme.color.text2,
|
|
574
|
+
textAlign: "center"
|
|
575
|
+
}
|
|
576
|
+
}));
|
|
577
|
+
var SIDEBAR_MIN_WIDTH = 768;
|
|
578
|
+
function useControllable(value, initial, onChange) {
|
|
579
|
+
const [inner, setInner] = React5.useState(initial);
|
|
580
|
+
const current = value !== void 0 ? value : inner;
|
|
581
|
+
const set = React5.useCallback(
|
|
582
|
+
(next) => {
|
|
583
|
+
if (value === void 0) setInner(next);
|
|
584
|
+
onChange?.(next);
|
|
585
|
+
},
|
|
586
|
+
[value, onChange]
|
|
587
|
+
);
|
|
588
|
+
return [current, set];
|
|
589
|
+
}
|
|
590
|
+
var seq = 0;
|
|
591
|
+
var nextKey = () => `fm${++seq}`;
|
|
592
|
+
function FileManager({
|
|
593
|
+
items,
|
|
594
|
+
folderId: folderIdProp,
|
|
595
|
+
defaultFolderId = null,
|
|
596
|
+
onFolderChange,
|
|
597
|
+
view: viewProp,
|
|
598
|
+
defaultView = "list",
|
|
599
|
+
onViewChange,
|
|
600
|
+
sort: sortProp,
|
|
601
|
+
defaultSort = DEFAULT_FILE_SORT,
|
|
602
|
+
onSortChange,
|
|
603
|
+
onCreateFolder,
|
|
604
|
+
onRename,
|
|
605
|
+
onDelete,
|
|
606
|
+
confirmDelete = false,
|
|
607
|
+
onMove,
|
|
608
|
+
onOpenFile,
|
|
609
|
+
onShare,
|
|
610
|
+
onFavoriteChange,
|
|
611
|
+
renderPreview,
|
|
612
|
+
onNotify,
|
|
613
|
+
loading = false,
|
|
614
|
+
error = false,
|
|
615
|
+
onRetry,
|
|
616
|
+
recents = true,
|
|
617
|
+
nested = true,
|
|
618
|
+
defaultExpanded,
|
|
619
|
+
sidebar = "auto",
|
|
620
|
+
density = "comfortable",
|
|
621
|
+
platform,
|
|
622
|
+
safeAreaBottom = 0,
|
|
623
|
+
motion,
|
|
624
|
+
locale: localeProp,
|
|
625
|
+
labels: labelsProp
|
|
626
|
+
}) {
|
|
627
|
+
const theme = useLoamTheme("file-manager");
|
|
628
|
+
const { styles } = useStyles(sheet3);
|
|
629
|
+
const labels = useFileManagerLabels(labelsProp);
|
|
630
|
+
const providerLocale = useLoamLocale();
|
|
631
|
+
const locale = localeProp ?? providerLocale;
|
|
632
|
+
const [folderId, setFolderId] = useControllable(
|
|
633
|
+
folderIdProp,
|
|
634
|
+
defaultFolderId,
|
|
635
|
+
onFolderChange
|
|
636
|
+
);
|
|
637
|
+
const [view, setView] = useControllable(viewProp, defaultView, onViewChange);
|
|
638
|
+
const [sort, setSort] = useControllable(sortProp, defaultSort, onSortChange);
|
|
639
|
+
const [special, setSpecial] = React5.useState(null);
|
|
640
|
+
const [query, setQuery] = React5.useState("");
|
|
641
|
+
const [selecting, setSelecting] = React5.useState(false);
|
|
642
|
+
const [selection, setSelection] = React5.useState([]);
|
|
643
|
+
const [expanded, setExpanded] = React5.useState(
|
|
644
|
+
() => new Set(defaultExpanded)
|
|
645
|
+
);
|
|
646
|
+
const [pending, setPending] = React5.useState([]);
|
|
647
|
+
const [width, setWidth] = React5.useState(0);
|
|
648
|
+
const [optionsOpen, setOptionsOpen] = React5.useState(false);
|
|
649
|
+
const [locationsOpen, setLocationsOpen] = React5.useState(false);
|
|
650
|
+
const [info, setInfo] = React5.useState(null);
|
|
651
|
+
const [preview, setPreview] = React5.useState(null);
|
|
652
|
+
const [moving, setMoving] = React5.useState([]);
|
|
653
|
+
const [naming, setNaming] = React5.useState(null);
|
|
654
|
+
const [deleting, setDeleting] = React5.useState(null);
|
|
655
|
+
const { entries: drawn, pendingIds } = React5.useMemo(
|
|
656
|
+
() => applyPending(items, pending),
|
|
657
|
+
[items, pending]
|
|
658
|
+
);
|
|
659
|
+
const index = React5.useMemo(() => indexEntries(drawn), [drawn]);
|
|
660
|
+
const favoritesOn = Boolean(onFavoriteChange) || drawn.some((e) => e.favorite);
|
|
661
|
+
React5.useEffect(() => {
|
|
662
|
+
if (folderId !== null && !index.has(folderId) && !isPlaceholderId(folderId)) setFolderId(null);
|
|
663
|
+
}, [folderId, index, setFolderId]);
|
|
664
|
+
const location = special ? { kind: special } : { kind: "folder", id: folderId };
|
|
665
|
+
const folder = folderId !== null ? index.get(folderId) ?? null : null;
|
|
666
|
+
const crumbs = React5.useMemo(() => pathTo(index, folderId), [index, folderId]);
|
|
667
|
+
const parent = crumbs.length > 1 ? crumbs[crumbs.length - 2] : null;
|
|
668
|
+
const searching = query.trim().length > 0;
|
|
669
|
+
const listed = React5.useMemo(() => {
|
|
670
|
+
if (searching)
|
|
671
|
+
return sortEntries(searchEntries(drawn, query, special ? null : folderId), sort, locale);
|
|
672
|
+
if (special === "recent") return recentFiles(drawn);
|
|
673
|
+
if (special === "favorites")
|
|
674
|
+
return sortEntries(
|
|
675
|
+
drawn.filter((e) => e.favorite),
|
|
676
|
+
sort,
|
|
677
|
+
locale
|
|
678
|
+
);
|
|
679
|
+
return sortEntries(childrenOf(drawn, folderId), sort, locale);
|
|
680
|
+
}, [drawn, query, searching, special, folderId, sort, locale]);
|
|
681
|
+
const rows = React5.useMemo(
|
|
682
|
+
() => nested && view === "list" && !searching && special === null ? flattenRows(listed, expanded, (f) => sortEntries(childrenOf(drawn, f.id), sort, locale)) : listed.map((entry) => ({ kind: "entry", entry, depth: 0 })),
|
|
683
|
+
[nested, view, searching, special, listed, expanded, drawn, sort, locale]
|
|
684
|
+
);
|
|
685
|
+
const files = React5.useMemo(() => listed.filter((e) => e.type === "file"), [listed]);
|
|
686
|
+
const selectedEntries = React5.useMemo(
|
|
687
|
+
() => selection.map((id) => index.get(id)).filter((e) => e !== void 0),
|
|
688
|
+
[selection, index]
|
|
689
|
+
);
|
|
690
|
+
const wide = sidebar === true || sidebar === "auto" && width >= SIDEBAR_MIN_WIDTH;
|
|
691
|
+
const showSkeleton = useDelayedLoading(loading && drawn.length === 0);
|
|
692
|
+
const notify = (title2, result) => {
|
|
693
|
+
if (typeof result === "function") {
|
|
694
|
+
const undo = result;
|
|
695
|
+
onNotify?.({ title: title2, tone: "good", undoable: true, undo: () => void undo() });
|
|
696
|
+
} else onNotify?.({ title: title2, tone: "good" });
|
|
697
|
+
};
|
|
698
|
+
const run = async (action, op, success, optimistic) => {
|
|
699
|
+
const key = optimistic ? nextKey() : null;
|
|
700
|
+
if (key && optimistic) setPending((list) => [...list, { key, op: optimistic }]);
|
|
701
|
+
try {
|
|
702
|
+
notify(success, await op());
|
|
703
|
+
return true;
|
|
704
|
+
} catch {
|
|
705
|
+
haptics.notify("error");
|
|
706
|
+
onNotify?.({ title: labels.failed(action), tone: "danger" });
|
|
707
|
+
return false;
|
|
708
|
+
} finally {
|
|
709
|
+
if (key) setPending((list) => list.filter((p) => p.key !== key));
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
const folderName = (id) => id === null ? labels.root : index.get(id)?.name ?? labels.root;
|
|
713
|
+
const topLevel = (entries) => topLevelIds(
|
|
714
|
+
index,
|
|
715
|
+
entries.map((e) => e.id)
|
|
716
|
+
).map((id) => index.get(id)).filter((e) => e !== void 0);
|
|
717
|
+
const remove = (entries) => {
|
|
718
|
+
if (!onDelete || entries.length === 0) return;
|
|
719
|
+
const list = topLevel(entries);
|
|
720
|
+
setSelection((s) => s.filter((id) => !list.some((e) => e.id === id)));
|
|
721
|
+
haptics.notify("warning");
|
|
722
|
+
void run(labels.delete, () => onDelete(list), labels.deleted(list.length), {
|
|
723
|
+
kind: "delete",
|
|
724
|
+
ids: list.map((e) => e.id)
|
|
725
|
+
});
|
|
726
|
+
};
|
|
727
|
+
const askDelete = (entries) => confirmDelete ? setDeleting([...entries]) : remove(entries);
|
|
728
|
+
const move = (entries, targetId) => {
|
|
729
|
+
if (!onMove) return;
|
|
730
|
+
const ids = entries.map((e) => e.id);
|
|
731
|
+
const refusal = moveRefusal(index, ids, targetId);
|
|
732
|
+
if (refusal === "into-itself") onNotify?.({ title: labels.cannotMoveIntoItself, tone: "warn" });
|
|
733
|
+
if (refusal) return;
|
|
734
|
+
const list = topLevel(entries);
|
|
735
|
+
void run(
|
|
736
|
+
labels.moveTo,
|
|
737
|
+
() => onMove(list, targetId),
|
|
738
|
+
labels.moved(list.length, folderName(targetId)),
|
|
739
|
+
{
|
|
740
|
+
kind: "move",
|
|
741
|
+
ids: list.map((e) => e.id),
|
|
742
|
+
targetId
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
};
|
|
746
|
+
const favorite = (entry) => {
|
|
747
|
+
if (!onFavoriteChange) return;
|
|
748
|
+
const next = !entry.favorite;
|
|
749
|
+
haptics.selection();
|
|
750
|
+
void run(
|
|
751
|
+
next ? labels.favorite : labels.unfavorite,
|
|
752
|
+
() => onFavoriteChange(entry, next),
|
|
753
|
+
next ? labels.favorite : labels.unfavorite,
|
|
754
|
+
{
|
|
755
|
+
kind: "favorite",
|
|
756
|
+
id: entry.id,
|
|
757
|
+
favorite: next
|
|
758
|
+
}
|
|
759
|
+
);
|
|
760
|
+
};
|
|
761
|
+
const submitName = (name) => {
|
|
762
|
+
const target = naming?.entry ?? null;
|
|
763
|
+
setNaming(null);
|
|
764
|
+
if (target) {
|
|
765
|
+
if (!onRename || name === target.name) return;
|
|
766
|
+
void run(labels.rename, () => onRename(target, name), labels.renamed(name), {
|
|
767
|
+
kind: "rename",
|
|
768
|
+
id: target.id,
|
|
769
|
+
name
|
|
770
|
+
});
|
|
771
|
+
} else if (onCreateFolder) {
|
|
772
|
+
const at = special ? null : folderId;
|
|
773
|
+
const draft = {
|
|
774
|
+
id: placeholderId(nextKey()),
|
|
775
|
+
name,
|
|
776
|
+
type: "folder",
|
|
777
|
+
parentId: at,
|
|
778
|
+
modifiedAt: Date.now()
|
|
779
|
+
};
|
|
780
|
+
void run(labels.newFolder, () => onCreateFolder(at, name), labels.created(name), {
|
|
781
|
+
kind: "add",
|
|
782
|
+
entries: [draft]
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
const go = (l) => {
|
|
787
|
+
setLocationsOpen(false);
|
|
788
|
+
setQuery("");
|
|
789
|
+
setSelection([]);
|
|
790
|
+
if (l.kind === "folder") {
|
|
791
|
+
setSpecial(null);
|
|
792
|
+
setFolderId(l.id);
|
|
793
|
+
} else setSpecial(l.kind);
|
|
794
|
+
};
|
|
795
|
+
const toggleSelected = (id) => {
|
|
796
|
+
haptics.selection();
|
|
797
|
+
setSelection((s) => s.includes(id) ? s.filter((x) => x !== id) : [...s, id]);
|
|
798
|
+
};
|
|
799
|
+
const endSelecting = () => {
|
|
800
|
+
setSelecting(false);
|
|
801
|
+
setSelection([]);
|
|
802
|
+
};
|
|
803
|
+
const open = (entry) => {
|
|
804
|
+
if (pendingIds.has(entry.id) && isPlaceholderId(entry.id)) return;
|
|
805
|
+
if (selecting) return toggleSelected(entry.id);
|
|
806
|
+
if (entry.type === "folder") return go({ kind: "folder", id: entry.id });
|
|
807
|
+
if (onOpenFile) return onOpenFile(entry);
|
|
808
|
+
setPreview(entry);
|
|
809
|
+
};
|
|
810
|
+
const toggleExpanded = (id) => {
|
|
811
|
+
haptics.selection();
|
|
812
|
+
setExpanded((s) => {
|
|
813
|
+
const next = new Set(s);
|
|
814
|
+
if (next.has(id)) next.delete(id);
|
|
815
|
+
else next.add(id);
|
|
816
|
+
return next;
|
|
817
|
+
});
|
|
818
|
+
};
|
|
819
|
+
const menuFor = (entry) => {
|
|
820
|
+
const busy = pendingIds.has(entry.id);
|
|
821
|
+
const out = [];
|
|
822
|
+
out.push({
|
|
823
|
+
key: "open",
|
|
824
|
+
label: labels.open,
|
|
825
|
+
icon: entry.type === "folder" ? "folder-open" : "external-link",
|
|
826
|
+
onSelect: () => open(entry)
|
|
827
|
+
});
|
|
828
|
+
if (entry.type === "file")
|
|
829
|
+
out.push({
|
|
830
|
+
key: "preview",
|
|
831
|
+
label: labels.preview,
|
|
832
|
+
icon: "eye",
|
|
833
|
+
onSelect: () => setPreview(entry)
|
|
834
|
+
});
|
|
835
|
+
if (entry.type === "folder" && nested && view === "list" && !searching && special === null) {
|
|
836
|
+
const isOpen = expanded.has(entry.id);
|
|
837
|
+
out.push({
|
|
838
|
+
key: "disclose",
|
|
839
|
+
label: isOpen ? labels.collapseFolder(entry.name) : labels.expandFolder(entry.name),
|
|
840
|
+
icon: isOpen ? "chevron-up" : "chevron-down",
|
|
841
|
+
onSelect: () => toggleExpanded(entry.id)
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
out.push({ key: "info", label: labels.getInfo, icon: "info", onSelect: () => setInfo(entry) });
|
|
845
|
+
if (busy) return out;
|
|
846
|
+
if (onRename && !entry.locked)
|
|
847
|
+
out.push({
|
|
848
|
+
key: "rename",
|
|
849
|
+
label: labels.rename,
|
|
850
|
+
icon: "rename",
|
|
851
|
+
onSelect: () => setNaming({ entry })
|
|
852
|
+
});
|
|
853
|
+
if (onMove && !entry.locked)
|
|
854
|
+
out.push({
|
|
855
|
+
key: "move",
|
|
856
|
+
label: labels.moveTo,
|
|
857
|
+
icon: "folder-input",
|
|
858
|
+
onSelect: () => setMoving([entry])
|
|
859
|
+
});
|
|
860
|
+
if (onFavoriteChange)
|
|
861
|
+
out.push({
|
|
862
|
+
key: "favorite",
|
|
863
|
+
label: entry.favorite ? labels.unfavorite : labels.favorite,
|
|
864
|
+
icon: "star",
|
|
865
|
+
onSelect: () => favorite(entry)
|
|
866
|
+
});
|
|
867
|
+
if (onShare && entry.type === "file")
|
|
868
|
+
out.push({
|
|
869
|
+
key: "share",
|
|
870
|
+
label: labels.download,
|
|
871
|
+
icon: "upload",
|
|
872
|
+
onSelect: () => onShare([entry])
|
|
873
|
+
});
|
|
874
|
+
if (onDelete && !entry.locked)
|
|
875
|
+
out.push({
|
|
876
|
+
key: "delete",
|
|
877
|
+
label: labels.delete,
|
|
878
|
+
icon: "trash",
|
|
879
|
+
destructive: true,
|
|
880
|
+
onSelect: () => askDelete([entry])
|
|
881
|
+
});
|
|
882
|
+
return out;
|
|
883
|
+
};
|
|
884
|
+
const swipesFor = (entry) => {
|
|
885
|
+
if (selecting || pendingIds.has(entry.id) || entry.locked) return void 0;
|
|
886
|
+
const star = onFavoriteChange ? {
|
|
887
|
+
key: "favorite",
|
|
888
|
+
label: entry.favorite ? labels.swipeUnfavorite : labels.swipeFavorite,
|
|
889
|
+
icon: "star",
|
|
890
|
+
fullSwipe: true,
|
|
891
|
+
onAction: () => favorite(entry)
|
|
892
|
+
} : null;
|
|
893
|
+
const relocate = onMove ? {
|
|
894
|
+
key: "move",
|
|
895
|
+
label: labels.moveTo,
|
|
896
|
+
icon: "folder-input",
|
|
897
|
+
onAction: () => setMoving([entry])
|
|
898
|
+
} : null;
|
|
899
|
+
const trash = onDelete ? {
|
|
900
|
+
key: "delete",
|
|
901
|
+
label: labels.delete,
|
|
902
|
+
icon: "trash",
|
|
903
|
+
destructive: true,
|
|
904
|
+
fullSwipe: !confirmDelete,
|
|
905
|
+
collapses: !confirmDelete,
|
|
906
|
+
onAction: () => askDelete([entry])
|
|
907
|
+
} : null;
|
|
908
|
+
if (!star && !relocate && !trash) return void 0;
|
|
909
|
+
const trailing = relocate && trash ? [relocate, trash] : relocate ? [relocate] : trash ? [trash] : [];
|
|
910
|
+
return { leading: star ? [star] : [], trailing };
|
|
911
|
+
};
|
|
912
|
+
const pad = theme.space.s4;
|
|
913
|
+
const gap = theme.space.s3;
|
|
914
|
+
const tileMin = theme.space[104] ?? theme.space[100];
|
|
915
|
+
const mainWidth = wide ? width - SIDEBAR_WIDTH(theme) : width;
|
|
916
|
+
const columns = Math.max(3, Math.floor((mainWidth - 2 * pad + gap) / (tileMin + gap)));
|
|
917
|
+
const tileWidth = mainWidth > 0 ? (mainWidth - 2 * pad - gap * (columns - 1)) / columns : tileMin;
|
|
918
|
+
const renderRow = ({ item: row }) => {
|
|
919
|
+
if (row.kind !== "entry") {
|
|
920
|
+
return /* @__PURE__ */ jsx(
|
|
921
|
+
View,
|
|
922
|
+
{
|
|
923
|
+
style: [
|
|
924
|
+
styles.standIn,
|
|
925
|
+
{ paddingStart: pad + indentOf(row.depth, theme) + DISCLOSURE(theme) }
|
|
926
|
+
],
|
|
927
|
+
children: row.kind === "loading" ? /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: theme.space[120] }) : /* @__PURE__ */ jsx(Text, { style: [styles.standInText, row.kind === "error" && styles.standInError], children: row.kind === "error" ? labels.loadFailed : labels.nestedEmpty })
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
const { entry, depth } = row;
|
|
932
|
+
const busy = pendingIds.has(entry.id);
|
|
933
|
+
const isOpen = expanded.has(entry.id);
|
|
934
|
+
const treeable = nested && view === "list" && !searching && special === null;
|
|
935
|
+
const meta = entryMeta(entry, drawn, labels, locale);
|
|
936
|
+
const where = searching || special ? folderName(entry.parentId) : null;
|
|
937
|
+
return /* @__PURE__ */ jsx(View, { style: busy && styles.busy, children: /* @__PURE__ */ jsx(
|
|
938
|
+
ListRow,
|
|
939
|
+
{
|
|
940
|
+
title: entry.name,
|
|
941
|
+
subtitle: where ? `${where} \xB7 ${meta}` : meta,
|
|
942
|
+
density,
|
|
943
|
+
divider: true,
|
|
944
|
+
leading: /* @__PURE__ */ jsxs(View, { style: [styles.lead, { paddingStart: indentOf(depth, theme) }], children: [
|
|
945
|
+
treeable ? entry.type === "folder" ? (
|
|
946
|
+
// No button role: the row is the button, and the disclosure is
|
|
947
|
+
// reachable to assistive tech through the row's actions.
|
|
948
|
+
/* @__PURE__ */ jsx(
|
|
949
|
+
Pressable,
|
|
950
|
+
{
|
|
951
|
+
accessibilityLabel: isOpen ? labels.collapseFolder(entry.name) : labels.expandFolder(entry.name),
|
|
952
|
+
accessibilityState: { expanded: isOpen },
|
|
953
|
+
hitSlop: theme.space.s3,
|
|
954
|
+
onPress: () => toggleExpanded(entry.id),
|
|
955
|
+
style: styles.disclosure,
|
|
956
|
+
children: /* @__PURE__ */ jsx(View, { style: isOpen && styles.disclosureOpen, children: /* @__PURE__ */ jsx(
|
|
957
|
+
Icon,
|
|
958
|
+
{
|
|
959
|
+
name: "chevron-right",
|
|
960
|
+
size: theme.icon.sm,
|
|
961
|
+
color: theme.color.text3,
|
|
962
|
+
strokeWidth: 2
|
|
963
|
+
}
|
|
964
|
+
) })
|
|
965
|
+
}
|
|
966
|
+
)
|
|
967
|
+
) : /* @__PURE__ */ jsx(View, { style: styles.disclosure }) : null,
|
|
968
|
+
/* @__PURE__ */ jsx(FileIcon, { entry, size: density === "compact" ? "md" : "lg" })
|
|
969
|
+
] }),
|
|
970
|
+
trailing: entry.favorite ? /* @__PURE__ */ jsx(Icon, { name: "star", size: theme.icon.sm, color: theme.color.text3 }) : entry.type === "folder" && !selecting && !treeable ? /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: theme.icon.sm, color: theme.color.text3 }) : void 0,
|
|
971
|
+
selectable: selecting,
|
|
972
|
+
selected: selection.includes(entry.id),
|
|
973
|
+
onSelectedChange: () => toggleSelected(entry.id),
|
|
974
|
+
onPress: () => open(entry),
|
|
975
|
+
swipeActions: swipesFor(entry),
|
|
976
|
+
menuItems: selecting ? void 0 : menuFor(entry),
|
|
977
|
+
motion
|
|
978
|
+
}
|
|
979
|
+
) });
|
|
980
|
+
};
|
|
981
|
+
const renderTile = ({ item: entry }) => {
|
|
982
|
+
const busy = pendingIds.has(entry.id);
|
|
983
|
+
const chosen = selection.includes(entry.id);
|
|
984
|
+
const body = /* @__PURE__ */ jsxs(View, { style: [styles.tile, { width: tileWidth }, busy && styles.busy], children: [
|
|
985
|
+
/* @__PURE__ */ jsxs(View, { style: [styles.tileArt, chosen && styles.tileArtChosen], children: [
|
|
986
|
+
/* @__PURE__ */ jsx(FileIcon, { entry, size: "xl" }),
|
|
987
|
+
selecting ? /* @__PURE__ */ jsx(View, { style: [styles.check, chosen && styles.checkOn], children: chosen ? /* @__PURE__ */ jsx(
|
|
988
|
+
Icon,
|
|
989
|
+
{
|
|
990
|
+
name: "check",
|
|
991
|
+
size: theme.icon.xs,
|
|
992
|
+
color: theme.color.surface,
|
|
993
|
+
strokeWidth: 2.5
|
|
994
|
+
}
|
|
995
|
+
) : null }) : null
|
|
996
|
+
] }),
|
|
997
|
+
/* @__PURE__ */ jsx(Text, { style: styles.tileName, numberOfLines: 2, children: entry.name }),
|
|
998
|
+
/* @__PURE__ */ jsx(Text, { style: styles.tileMeta, numberOfLines: 1, children: entryMeta(entry, drawn, labels, locale) })
|
|
999
|
+
] });
|
|
1000
|
+
if (selecting) {
|
|
1001
|
+
return /* @__PURE__ */ jsx(
|
|
1002
|
+
Pressable,
|
|
1003
|
+
{
|
|
1004
|
+
accessibilityRole: "checkbox",
|
|
1005
|
+
accessibilityLabel: entry.name,
|
|
1006
|
+
accessibilityState: { checked: chosen },
|
|
1007
|
+
onPress: () => toggleSelected(entry.id),
|
|
1008
|
+
children: body
|
|
1009
|
+
}
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
return /* @__PURE__ */ jsx(
|
|
1013
|
+
ContextMenu,
|
|
1014
|
+
{
|
|
1015
|
+
items: menuFor(entry),
|
|
1016
|
+
onPress: () => open(entry),
|
|
1017
|
+
platform,
|
|
1018
|
+
accessibilityLabel: entry.name,
|
|
1019
|
+
radius: theme.radius.md,
|
|
1020
|
+
motion,
|
|
1021
|
+
children: body
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
};
|
|
1025
|
+
const title = searching ? labels.searchResults(special ? labels.root : folderName(folderId)) : special === "recent" ? labels.recent : special === "favorites" ? labels.favorites : folder?.name ?? labels.root;
|
|
1026
|
+
const canBack = special === null && folderId !== null;
|
|
1027
|
+
const hasLocations = recents || favoritesOn || childrenOf(drawn, null).some((e) => e.type === "folder");
|
|
1028
|
+
const empty = (() => {
|
|
1029
|
+
if (error)
|
|
1030
|
+
return /* @__PURE__ */ jsx(
|
|
1031
|
+
EmptyState,
|
|
1032
|
+
{
|
|
1033
|
+
variant: "error",
|
|
1034
|
+
title: labels.loadFailed,
|
|
1035
|
+
actionLabel: onRetry ? labels.retry : void 0,
|
|
1036
|
+
onAction: onRetry
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
if (showSkeleton) return /* @__PURE__ */ jsx(SkeletonRows, { view, columns, tileWidth, label: labels.loading });
|
|
1040
|
+
if (loading) return null;
|
|
1041
|
+
if (searching)
|
|
1042
|
+
return /* @__PURE__ */ jsx(
|
|
1043
|
+
EmptyState,
|
|
1044
|
+
{
|
|
1045
|
+
variant: "no-results",
|
|
1046
|
+
title: labels.noResultsTitle(query.trim()),
|
|
1047
|
+
description: labels.noResultsDescription,
|
|
1048
|
+
actionLabel: labels.clearSearch,
|
|
1049
|
+
onAction: () => setQuery("")
|
|
1050
|
+
}
|
|
1051
|
+
);
|
|
1052
|
+
if (special === "recent") return /* @__PURE__ */ jsx(EmptyState, { icon: "clock", title: labels.noRecent });
|
|
1053
|
+
return /* @__PURE__ */ jsx(
|
|
1054
|
+
EmptyState,
|
|
1055
|
+
{
|
|
1056
|
+
icon: "folder-open",
|
|
1057
|
+
title: labels.emptyFolderTitle,
|
|
1058
|
+
actionLabel: onCreateFolder && special === null ? labels.newFolder : void 0,
|
|
1059
|
+
onAction: () => setNaming({ entry: null })
|
|
1060
|
+
}
|
|
1061
|
+
);
|
|
1062
|
+
})();
|
|
1063
|
+
const locationsList = /* @__PURE__ */ jsx(
|
|
1064
|
+
FileLocations,
|
|
1065
|
+
{
|
|
1066
|
+
location,
|
|
1067
|
+
onLocationChange: go,
|
|
1068
|
+
folders: sortEntries(
|
|
1069
|
+
childrenOf(drawn, null).filter((e) => e.type === "folder"),
|
|
1070
|
+
DEFAULT_FILE_SORT,
|
|
1071
|
+
locale
|
|
1072
|
+
),
|
|
1073
|
+
recents,
|
|
1074
|
+
favorites: favoritesOn,
|
|
1075
|
+
labels
|
|
1076
|
+
}
|
|
1077
|
+
);
|
|
1078
|
+
return /* @__PURE__ */ jsxs(
|
|
1079
|
+
View,
|
|
1080
|
+
{
|
|
1081
|
+
style: styles.root,
|
|
1082
|
+
onLayout: (e) => setWidth(e.nativeEvent.layout.width),
|
|
1083
|
+
children: [
|
|
1084
|
+
wide ? /* @__PURE__ */ jsx(View, { style: styles.side, children: locationsList }) : null,
|
|
1085
|
+
/* @__PURE__ */ jsxs(View, { style: styles.main, children: [
|
|
1086
|
+
/* @__PURE__ */ jsx(
|
|
1087
|
+
NavHeader,
|
|
1088
|
+
{
|
|
1089
|
+
title: selecting ? labels.selected(selection.length) : title,
|
|
1090
|
+
large: !selecting,
|
|
1091
|
+
leading: !selecting && canBack ? "chevron-left" : void 0,
|
|
1092
|
+
leadingLabel: canBack ? parent?.name ?? labels.root : void 0,
|
|
1093
|
+
onLeadingPress: () => go({ kind: "folder", id: folder?.parentId ?? null }),
|
|
1094
|
+
leadingSlot: !selecting && !canBack && !wide && hasLocations ? /* @__PURE__ */ jsx(
|
|
1095
|
+
NavHeaderAction,
|
|
1096
|
+
{
|
|
1097
|
+
icon: "menu",
|
|
1098
|
+
accessibilityLabel: labels.locations,
|
|
1099
|
+
onPress: () => setLocationsOpen(true)
|
|
1100
|
+
}
|
|
1101
|
+
) : void 0,
|
|
1102
|
+
search: !selecting,
|
|
1103
|
+
searchPlaceholder: labels.searchPlaceholder,
|
|
1104
|
+
searchValue: query,
|
|
1105
|
+
onSearchChangeText: setQuery,
|
|
1106
|
+
onSearchCancel: () => setQuery(""),
|
|
1107
|
+
trailing: /* @__PURE__ */ jsxs(View, { style: styles.headerActions, children: [
|
|
1108
|
+
selecting ? null : /* @__PURE__ */ jsx(
|
|
1109
|
+
NavHeaderAction,
|
|
1110
|
+
{
|
|
1111
|
+
icon: "sliders",
|
|
1112
|
+
accessibilityLabel: labels.view,
|
|
1113
|
+
onPress: () => setOptionsOpen(true)
|
|
1114
|
+
}
|
|
1115
|
+
),
|
|
1116
|
+
listed.length > 0 || selecting ? /* @__PURE__ */ jsx(
|
|
1117
|
+
Button,
|
|
1118
|
+
{
|
|
1119
|
+
variant: "ghost",
|
|
1120
|
+
size: "sm",
|
|
1121
|
+
onPress: () => selecting ? endSelecting() : setSelecting(true),
|
|
1122
|
+
children: selecting ? labels.done : labels.select
|
|
1123
|
+
}
|
|
1124
|
+
) : null
|
|
1125
|
+
] })
|
|
1126
|
+
}
|
|
1127
|
+
),
|
|
1128
|
+
listed.length === 0 || error ? /* @__PURE__ */ jsx(View, { style: styles.empty, children: empty }) : view === "grid" ? /* @__PURE__ */ jsx(
|
|
1129
|
+
FlatList,
|
|
1130
|
+
{
|
|
1131
|
+
data: listed,
|
|
1132
|
+
keyExtractor: (e) => e.id,
|
|
1133
|
+
numColumns: columns,
|
|
1134
|
+
renderItem: renderTile,
|
|
1135
|
+
columnWrapperStyle: { gap },
|
|
1136
|
+
contentContainerStyle: [
|
|
1137
|
+
styles.gridContent,
|
|
1138
|
+
{ paddingBottom: theme.space.s6 + safeAreaBottom }
|
|
1139
|
+
],
|
|
1140
|
+
initialNumToRender: columns * 6,
|
|
1141
|
+
windowSize: 7
|
|
1142
|
+
},
|
|
1143
|
+
`grid-${columns}`
|
|
1144
|
+
) : /* @__PURE__ */ jsx(
|
|
1145
|
+
FlatList,
|
|
1146
|
+
{
|
|
1147
|
+
data: rows,
|
|
1148
|
+
keyExtractor: (r) => r.kind === "entry" ? r.entry.id : `${r.kind}:${r.parent.id}`,
|
|
1149
|
+
renderItem: renderRow,
|
|
1150
|
+
contentContainerStyle: { paddingBottom: theme.space.s6 + safeAreaBottom },
|
|
1151
|
+
initialNumToRender: 16,
|
|
1152
|
+
windowSize: 9
|
|
1153
|
+
},
|
|
1154
|
+
"list"
|
|
1155
|
+
),
|
|
1156
|
+
selecting ? /* @__PURE__ */ jsxs(View, { style: [styles.bar, { paddingBottom: theme.space.s2 + safeAreaBottom }], children: [
|
|
1157
|
+
/* @__PURE__ */ jsx(
|
|
1158
|
+
Button,
|
|
1159
|
+
{
|
|
1160
|
+
variant: "ghost",
|
|
1161
|
+
leadingIcon: "folder-input",
|
|
1162
|
+
disabled: !onMove || selectedEntries.length === 0,
|
|
1163
|
+
onPress: () => setMoving(selectedEntries),
|
|
1164
|
+
children: labels.moveTo
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
onShare ? /* @__PURE__ */ jsx(
|
|
1168
|
+
Button,
|
|
1169
|
+
{
|
|
1170
|
+
variant: "ghost",
|
|
1171
|
+
leadingIcon: "upload",
|
|
1172
|
+
disabled: !selectedEntries.some((e) => e.type === "file"),
|
|
1173
|
+
onPress: () => onShare(selectedEntries.filter((e) => e.type === "file")),
|
|
1174
|
+
children: labels.download
|
|
1175
|
+
}
|
|
1176
|
+
) : null,
|
|
1177
|
+
/* @__PURE__ */ jsx(
|
|
1178
|
+
Button,
|
|
1179
|
+
{
|
|
1180
|
+
variant: "ghost",
|
|
1181
|
+
leadingIcon: "trash",
|
|
1182
|
+
disabled: !onDelete || selectedEntries.length === 0,
|
|
1183
|
+
onPress: () => {
|
|
1184
|
+
askDelete(selectedEntries);
|
|
1185
|
+
if (!confirmDelete) setSelecting(false);
|
|
1186
|
+
},
|
|
1187
|
+
accessibilityLabel: labels.delete,
|
|
1188
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles.danger, children: labels.delete })
|
|
1189
|
+
}
|
|
1190
|
+
)
|
|
1191
|
+
] }) : null
|
|
1192
|
+
] }),
|
|
1193
|
+
/* @__PURE__ */ jsx(
|
|
1194
|
+
FileOptionsSheet,
|
|
1195
|
+
{
|
|
1196
|
+
open: optionsOpen,
|
|
1197
|
+
onClose: () => setOptionsOpen(false),
|
|
1198
|
+
view,
|
|
1199
|
+
onViewChange: setView,
|
|
1200
|
+
sort,
|
|
1201
|
+
onSortChange: setSort,
|
|
1202
|
+
onNewFolder: onCreateFolder && special === null ? () => setNaming({ entry: null }) : void 0,
|
|
1203
|
+
labels,
|
|
1204
|
+
safeAreaBottom,
|
|
1205
|
+
motion
|
|
1206
|
+
}
|
|
1207
|
+
),
|
|
1208
|
+
!wide ? /* @__PURE__ */ jsx(
|
|
1209
|
+
SheetLocations,
|
|
1210
|
+
{
|
|
1211
|
+
open: locationsOpen,
|
|
1212
|
+
onClose: () => setLocationsOpen(false),
|
|
1213
|
+
labels,
|
|
1214
|
+
safeAreaBottom,
|
|
1215
|
+
motion,
|
|
1216
|
+
children: locationsList
|
|
1217
|
+
}
|
|
1218
|
+
) : null,
|
|
1219
|
+
/* @__PURE__ */ jsx(
|
|
1220
|
+
FileInfoSheet,
|
|
1221
|
+
{
|
|
1222
|
+
entry: info,
|
|
1223
|
+
items: drawn,
|
|
1224
|
+
onClose: () => setInfo(null),
|
|
1225
|
+
labels,
|
|
1226
|
+
locale,
|
|
1227
|
+
safeAreaBottom,
|
|
1228
|
+
motion
|
|
1229
|
+
}
|
|
1230
|
+
),
|
|
1231
|
+
/* @__PURE__ */ jsx(
|
|
1232
|
+
FilePreviewSheet,
|
|
1233
|
+
{
|
|
1234
|
+
entry: preview,
|
|
1235
|
+
files,
|
|
1236
|
+
onEntryChange: setPreview,
|
|
1237
|
+
onClose: () => setPreview(null),
|
|
1238
|
+
items: drawn,
|
|
1239
|
+
renderPreview,
|
|
1240
|
+
labels,
|
|
1241
|
+
locale,
|
|
1242
|
+
safeAreaBottom,
|
|
1243
|
+
motion
|
|
1244
|
+
}
|
|
1245
|
+
),
|
|
1246
|
+
/* @__PURE__ */ jsx(
|
|
1247
|
+
FileMoveSheet,
|
|
1248
|
+
{
|
|
1249
|
+
entries: moving,
|
|
1250
|
+
items: drawn,
|
|
1251
|
+
onClose: () => setMoving([]),
|
|
1252
|
+
onMove: (target) => {
|
|
1253
|
+
const list = moving;
|
|
1254
|
+
setMoving([]);
|
|
1255
|
+
endSelecting();
|
|
1256
|
+
move(list, target);
|
|
1257
|
+
},
|
|
1258
|
+
labels,
|
|
1259
|
+
locale,
|
|
1260
|
+
safeAreaBottom,
|
|
1261
|
+
motion
|
|
1262
|
+
}
|
|
1263
|
+
),
|
|
1264
|
+
/* @__PURE__ */ jsx(
|
|
1265
|
+
FileNameDialog,
|
|
1266
|
+
{
|
|
1267
|
+
open: naming !== null,
|
|
1268
|
+
title: naming?.entry ? labels.rename : labels.newFolder,
|
|
1269
|
+
initialName: naming?.entry ? naming.entry.name : uniqueFileName(labels.untitledFolder, childrenOf(drawn, folderId)),
|
|
1270
|
+
confirmLabel: naming?.entry ? labels.save : labels.create,
|
|
1271
|
+
validate: (name) => validateFileName(
|
|
1272
|
+
name,
|
|
1273
|
+
childrenOf(drawn, naming?.entry?.parentId ?? folderId),
|
|
1274
|
+
naming?.entry?.id
|
|
1275
|
+
),
|
|
1276
|
+
onSubmit: submitName,
|
|
1277
|
+
onClose: () => setNaming(null),
|
|
1278
|
+
labels,
|
|
1279
|
+
motion
|
|
1280
|
+
}
|
|
1281
|
+
),
|
|
1282
|
+
/* @__PURE__ */ jsx(
|
|
1283
|
+
FileDeleteDialog,
|
|
1284
|
+
{
|
|
1285
|
+
entries: deleting,
|
|
1286
|
+
onClose: () => setDeleting(null),
|
|
1287
|
+
onConfirm: () => {
|
|
1288
|
+
const list = deleting ?? [];
|
|
1289
|
+
setDeleting(null);
|
|
1290
|
+
endSelecting();
|
|
1291
|
+
remove(list);
|
|
1292
|
+
},
|
|
1293
|
+
labels,
|
|
1294
|
+
motion
|
|
1295
|
+
}
|
|
1296
|
+
)
|
|
1297
|
+
]
|
|
1298
|
+
}
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
function SheetLocations({
|
|
1302
|
+
open,
|
|
1303
|
+
onClose,
|
|
1304
|
+
labels,
|
|
1305
|
+
safeAreaBottom,
|
|
1306
|
+
motion,
|
|
1307
|
+
children
|
|
1308
|
+
}) {
|
|
1309
|
+
return /* @__PURE__ */ jsx(
|
|
1310
|
+
Sheet,
|
|
1311
|
+
{
|
|
1312
|
+
open,
|
|
1313
|
+
onClose,
|
|
1314
|
+
title: labels.locations,
|
|
1315
|
+
closeLabel: labels.close,
|
|
1316
|
+
safeAreaBottom,
|
|
1317
|
+
motion,
|
|
1318
|
+
children
|
|
1319
|
+
}
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
function SkeletonRows({
|
|
1323
|
+
view,
|
|
1324
|
+
columns,
|
|
1325
|
+
tileWidth,
|
|
1326
|
+
label
|
|
1327
|
+
}) {
|
|
1328
|
+
const theme = useLoamTheme("file-manager");
|
|
1329
|
+
const { styles } = useStyles(sheet3);
|
|
1330
|
+
if (view === "grid") {
|
|
1331
|
+
return /* @__PURE__ */ jsx(View, { style: [styles.gridContent, styles.skeletonGrid], accessibilityLabel: label, children: Array.from({ length: columns * 2 }, (_, i) => /* @__PURE__ */ jsxs(View, { style: [styles.tile, { width: tileWidth }], children: [
|
|
1332
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", width: theme.space[64], height: theme.space[64], radius: "md" }),
|
|
1333
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "text", width: tileWidth * 0.7 })
|
|
1334
|
+
] }, i)) });
|
|
1335
|
+
}
|
|
1336
|
+
return /* @__PURE__ */ jsx(View, { accessibilityLabel: label, children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ jsxs(View, { style: styles.skeletonRow, children: [
|
|
1337
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "rect", width: theme.space[48], height: theme.space[48], radius: "sm" }),
|
|
1338
|
+
/* @__PURE__ */ jsxs(View, { style: styles.skeletonText, children: [
|
|
1339
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "text", width: theme.space[160] * (i % 3 === 0 ? 1 : 0.75) }),
|
|
1340
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "text", width: theme.space[100] })
|
|
1341
|
+
] })
|
|
1342
|
+
] }, i)) });
|
|
1343
|
+
}
|
|
1344
|
+
var SIDEBAR_WIDTH = (theme) => theme.space[256];
|
|
1345
|
+
var DISCLOSURE = (theme) => theme.space.s5;
|
|
1346
|
+
var indentOf = (depth, theme) => depth * theme.space[20];
|
|
1347
|
+
var sheet3 = createStyleSheet((theme) => ({
|
|
1348
|
+
root: { flex: 1, flexDirection: "row", backgroundColor: theme.color.bg },
|
|
1349
|
+
side: {
|
|
1350
|
+
width: SIDEBAR_WIDTH(theme),
|
|
1351
|
+
borderEndWidth: theme.borderWidth.hair,
|
|
1352
|
+
borderEndColor: theme.color.border,
|
|
1353
|
+
backgroundColor: theme.color.surface,
|
|
1354
|
+
paddingHorizontal: theme.space.s2,
|
|
1355
|
+
paddingTop: theme.space.s4
|
|
1356
|
+
},
|
|
1357
|
+
main: { flex: 1, minWidth: 0 },
|
|
1358
|
+
headerActions: { flexDirection: "row", alignItems: "center", gap: theme.space.s1 },
|
|
1359
|
+
empty: { flex: 1, justifyContent: "center" },
|
|
1360
|
+
lead: { flexDirection: "row", alignItems: "center", gap: theme.space.s1 },
|
|
1361
|
+
disclosure: {
|
|
1362
|
+
width: DISCLOSURE(theme),
|
|
1363
|
+
height: DISCLOSURE(theme),
|
|
1364
|
+
alignItems: "center",
|
|
1365
|
+
justifyContent: "center"
|
|
1366
|
+
},
|
|
1367
|
+
disclosureOpen: { transform: [{ rotate: "90deg" }] },
|
|
1368
|
+
busy: { opacity: theme.state.disabledOpacity },
|
|
1369
|
+
standIn: {
|
|
1370
|
+
minHeight: theme.ctl.lg,
|
|
1371
|
+
justifyContent: "center",
|
|
1372
|
+
paddingEnd: theme.space.s4
|
|
1373
|
+
},
|
|
1374
|
+
standInText: {
|
|
1375
|
+
fontFamily: theme.font.sans,
|
|
1376
|
+
fontSize: theme.type.footnote.fontSize,
|
|
1377
|
+
fontStyle: "italic",
|
|
1378
|
+
color: theme.color.text3
|
|
1379
|
+
},
|
|
1380
|
+
standInError: { color: theme.color.dangerOnSoft, fontStyle: "normal" },
|
|
1381
|
+
gridContent: {
|
|
1382
|
+
paddingHorizontal: theme.space.s4,
|
|
1383
|
+
paddingTop: theme.space.s2,
|
|
1384
|
+
gap: theme.space.s5
|
|
1385
|
+
},
|
|
1386
|
+
skeletonGrid: { flexDirection: "row", flexWrap: "wrap", columnGap: theme.space.s3 },
|
|
1387
|
+
tile: { alignItems: "center", gap: theme.space.s1, paddingVertical: theme.space.s1 },
|
|
1388
|
+
tileArt: {
|
|
1389
|
+
width: theme.space[76],
|
|
1390
|
+
height: theme.space[76],
|
|
1391
|
+
alignItems: "center",
|
|
1392
|
+
justifyContent: "center",
|
|
1393
|
+
borderRadius: theme.radius.lg,
|
|
1394
|
+
marginBottom: theme.space.s1
|
|
1395
|
+
},
|
|
1396
|
+
tileArtChosen: {
|
|
1397
|
+
backgroundColor: theme.color.accentSoft,
|
|
1398
|
+
borderWidth: theme.borderWidth.base,
|
|
1399
|
+
// The measured accent: a selection edge is a graphical object held to 3:1.
|
|
1400
|
+
borderColor: theme.focus.ringColor
|
|
1401
|
+
},
|
|
1402
|
+
tileName: {
|
|
1403
|
+
fontFamily: theme.font.sans,
|
|
1404
|
+
fontSize: theme.type.footnote.fontSize,
|
|
1405
|
+
lineHeight: theme.type.footnote.lineHeight,
|
|
1406
|
+
fontWeight: theme.type.headline.fontWeight,
|
|
1407
|
+
color: theme.color.text,
|
|
1408
|
+
textAlign: "center"
|
|
1409
|
+
},
|
|
1410
|
+
tileMeta: {
|
|
1411
|
+
fontFamily: theme.font.sans,
|
|
1412
|
+
fontSize: theme.type.caption1.fontSize,
|
|
1413
|
+
lineHeight: theme.type.caption1.lineHeight,
|
|
1414
|
+
color: theme.color.text3,
|
|
1415
|
+
textAlign: "center"
|
|
1416
|
+
},
|
|
1417
|
+
check: {
|
|
1418
|
+
position: "absolute",
|
|
1419
|
+
bottom: theme.space.s1,
|
|
1420
|
+
end: theme.space.s1,
|
|
1421
|
+
width: theme.space.s5,
|
|
1422
|
+
height: theme.space.s5,
|
|
1423
|
+
borderRadius: theme.radius.full,
|
|
1424
|
+
borderWidth: theme.borderWidth.base,
|
|
1425
|
+
borderColor: theme.color.borderStrong,
|
|
1426
|
+
backgroundColor: theme.color.surface,
|
|
1427
|
+
alignItems: "center",
|
|
1428
|
+
justifyContent: "center"
|
|
1429
|
+
},
|
|
1430
|
+
checkOn: { backgroundColor: theme.color.accent, borderColor: theme.color.accent },
|
|
1431
|
+
bar: {
|
|
1432
|
+
flexDirection: "row",
|
|
1433
|
+
justifyContent: "space-around",
|
|
1434
|
+
alignItems: "center",
|
|
1435
|
+
paddingTop: theme.space.s2,
|
|
1436
|
+
paddingHorizontal: theme.space.s2,
|
|
1437
|
+
borderTopWidth: theme.borderWidth.hair,
|
|
1438
|
+
borderTopColor: theme.color.border,
|
|
1439
|
+
backgroundColor: theme.color.surface
|
|
1440
|
+
},
|
|
1441
|
+
danger: {
|
|
1442
|
+
color: theme.color.dangerOnSoft,
|
|
1443
|
+
fontFamily: theme.font.sans,
|
|
1444
|
+
fontWeight: theme.type.headline.fontWeight
|
|
1445
|
+
},
|
|
1446
|
+
skeletonRow: {
|
|
1447
|
+
flexDirection: "row",
|
|
1448
|
+
alignItems: "center",
|
|
1449
|
+
gap: theme.space.s3,
|
|
1450
|
+
paddingHorizontal: theme.space.s4,
|
|
1451
|
+
minHeight: theme.layout.listRowH
|
|
1452
|
+
},
|
|
1453
|
+
skeletonText: { gap: theme.space.s2 }
|
|
1454
|
+
}));
|
|
1455
|
+
|
|
1456
|
+
export { FileDeleteDialog, FileIcon, FileInfoSheet, FileLocations, FileManager, FileMoveSheet, FileNameDialog, FileOptionsSheet, FilePreviewSheet, entryMeta, file_manager_labels_exports, useDelayedLoading, useFileManagerLabels };
|