@pallasoft/ps-file-components 1.0.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/LICENSE +32 -0
- package/README.md +10 -0
- package/dist/components/ps-file-delete-confirm.d.ts +11 -0
- package/dist/components/ps-file-delete-confirm.js +8 -0
- package/dist/components/ps-file-kind-icon.d.ts +6 -0
- package/dist/components/ps-file-kind-icon.js +10 -0
- package/dist/components/ps-file-list.d.ts +12 -0
- package/dist/components/ps-file-list.js +27 -0
- package/dist/components/ps-file-picker.d.ts +18 -0
- package/dist/components/ps-file-picker.js +48 -0
- package/dist/components/ps-file-viewer-button.d.ts +10 -0
- package/dist/components/ps-file-viewer-button.js +7 -0
- package/dist/components/ps-file-viewer-content.d.ts +2 -0
- package/dist/components/ps-file-viewer-content.js +28 -0
- package/dist/components/ps-file-viewer.d.ts +14 -0
- package/dist/components/ps-file-viewer.js +102 -0
- package/dist/components/ps-progress-bar.d.ts +7 -0
- package/dist/components/ps-progress-bar.js +15 -0
- package/dist/components/ps-upload-modal.d.ts +10 -0
- package/dist/components/ps-upload-modal.js +19 -0
- package/dist/components/ps-upload-row.d.ts +11 -0
- package/dist/components/ps-upload-row.js +28 -0
- package/dist/components/viewers/ps-highlighted-text.d.ts +6 -0
- package/dist/components/viewers/ps-highlighted-text.js +8 -0
- package/dist/components/viewers/ps-image-viewer.d.ts +2 -0
- package/dist/components/viewers/ps-image-viewer.js +33 -0
- package/dist/components/viewers/ps-media-viewer.d.ts +2 -0
- package/dist/components/viewers/ps-media-viewer.js +8 -0
- package/dist/components/viewers/ps-pdf-page.d.ts +12 -0
- package/dist/components/viewers/ps-pdf-page.js +37 -0
- package/dist/components/viewers/ps-pdf-thumbnail.d.ts +11 -0
- package/dist/components/viewers/ps-pdf-thumbnail.js +28 -0
- package/dist/components/viewers/ps-pdf-viewer.d.ts +2 -0
- package/dist/components/viewers/ps-pdf-viewer.js +100 -0
- package/dist/components/viewers/ps-text-viewer.d.ts +2 -0
- package/dist/components/viewers/ps-text-viewer.js +42 -0
- package/dist/components/viewers/ps-unsupported-viewer.d.ts +2 -0
- package/dist/components/viewers/ps-unsupported-viewer.js +8 -0
- package/dist/constants/ps-file-kind-icons.d.ts +3 -0
- package/dist/constants/ps-file-kind-icons.js +14 -0
- package/dist/constants/ps-file-kind.d.ts +10 -0
- package/dist/constants/ps-file-kind.js +12 -0
- package/dist/constants/ps-file-list-labels.d.ts +6 -0
- package/dist/constants/ps-file-list-labels.js +9 -0
- package/dist/constants/ps-file-picker-labels.d.ts +7 -0
- package/dist/constants/ps-file-picker-labels.js +10 -0
- package/dist/constants/ps-file-type-config.d.ts +7 -0
- package/dist/constants/ps-file-type-config.js +30 -0
- package/dist/constants/ps-file-viewer-config.d.ts +9 -0
- package/dist/constants/ps-file-viewer-config.js +12 -0
- package/dist/constants/ps-file-viewer-kinds.d.ts +5 -0
- package/dist/constants/ps-file-viewer-kinds.js +9 -0
- package/dist/constants/ps-file-viewer-labels.d.ts +21 -0
- package/dist/constants/ps-file-viewer-labels.js +24 -0
- package/dist/constants/ps-upload-labels.d.ts +14 -0
- package/dist/constants/ps-upload-labels.js +17 -0
- package/dist/constants/ps-upload-messages.d.ts +4 -0
- package/dist/constants/ps-upload-messages.js +7 -0
- package/dist/constants/ps-upload-queue-config.d.ts +4 -0
- package/dist/constants/ps-upload-queue-config.js +7 -0
- package/dist/constants/ps-upload-status-tones.d.ts +2 -0
- package/dist/constants/ps-upload-status-tones.js +12 -0
- package/dist/constants/ps-upload-status.d.ts +9 -0
- package/dist/constants/ps-upload-status.js +11 -0
- package/dist/esm/components/ps-file-delete-confirm.js +4 -0
- package/dist/esm/components/ps-file-kind-icon.js +6 -0
- package/dist/esm/components/ps-file-list.js +23 -0
- package/dist/esm/components/ps-file-picker.js +44 -0
- package/dist/esm/components/ps-file-viewer-button.js +3 -0
- package/dist/esm/components/ps-file-viewer-content.js +24 -0
- package/dist/esm/components/ps-file-viewer.js +98 -0
- package/dist/esm/components/ps-progress-bar.js +11 -0
- package/dist/esm/components/ps-upload-modal.js +15 -0
- package/dist/esm/components/ps-upload-row.js +24 -0
- package/dist/esm/components/viewers/ps-highlighted-text.js +4 -0
- package/dist/esm/components/viewers/ps-image-viewer.js +29 -0
- package/dist/esm/components/viewers/ps-media-viewer.js +4 -0
- package/dist/esm/components/viewers/ps-pdf-page.js +33 -0
- package/dist/esm/components/viewers/ps-pdf-thumbnail.js +24 -0
- package/dist/esm/components/viewers/ps-pdf-viewer.js +96 -0
- package/dist/esm/components/viewers/ps-text-viewer.js +38 -0
- package/dist/esm/components/viewers/ps-unsupported-viewer.js +4 -0
- package/dist/esm/constants/ps-file-kind-icons.js +11 -0
- package/dist/esm/constants/ps-file-kind.js +9 -0
- package/dist/esm/constants/ps-file-list-labels.js +6 -0
- package/dist/esm/constants/ps-file-picker-labels.js +7 -0
- package/dist/esm/constants/ps-file-type-config.js +27 -0
- package/dist/esm/constants/ps-file-viewer-config.js +9 -0
- package/dist/esm/constants/ps-file-viewer-kinds.js +6 -0
- package/dist/esm/constants/ps-file-viewer-labels.js +21 -0
- package/dist/esm/constants/ps-upload-labels.js +14 -0
- package/dist/esm/constants/ps-upload-messages.js +4 -0
- package/dist/esm/constants/ps-upload-queue-config.js +4 -0
- package/dist/esm/constants/ps-upload-status-tones.js +9 -0
- package/dist/esm/constants/ps-upload-status.js +8 -0
- package/dist/esm/hooks/use-ps-active-match-scroll.js +8 -0
- package/dist/esm/hooks/use-ps-file-text.js +21 -0
- package/dist/esm/hooks/use-ps-in-view.js +17 -0
- package/dist/esm/hooks/use-ps-upload-queue.js +67 -0
- package/dist/esm/index.js +62 -0
- package/dist/esm/models/ps-file-rejection.js +1 -0
- package/dist/esm/models/ps-file-selection-rules.js +1 -0
- package/dist/esm/models/ps-file-selection.js +1 -0
- package/dist/esm/models/ps-file-text-state.js +1 -0
- package/dist/esm/models/ps-file-viewer-content-props.js +1 -0
- package/dist/esm/models/ps-label-set.js +1 -0
- package/dist/esm/models/ps-page-size.js +1 -0
- package/dist/esm/models/ps-pdf-match.js +1 -0
- package/dist/esm/models/ps-point.js +1 -0
- package/dist/esm/models/ps-text-match.js +1 -0
- package/dist/esm/models/ps-text-segment.js +1 -0
- package/dist/esm/models/ps-upload-handler-options.js +1 -0
- package/dist/esm/models/ps-upload-item.js +1 -0
- package/dist/esm/models/ps-upload-queue-options.js +1 -0
- package/dist/esm/models/ps-upload-queue-state.js +1 -0
- package/dist/esm/models/ps-upload-summary.js +1 -0
- package/dist/esm/models/ps-viewer-file.js +1 -0
- package/dist/esm/models/ps-xhr-upload-request.js +1 -0
- package/dist/esm/models/ps-xhr-upload-response.js +1 -0
- package/dist/esm/services/ps-csv-service.js +42 -0
- package/dist/esm/services/ps-file-selection-service.js +16 -0
- package/dist/esm/services/ps-file-size-service.js +14 -0
- package/dist/esm/services/ps-file-type-service.js +38 -0
- package/dist/esm/services/ps-pdf-service.js +59 -0
- package/dist/esm/services/ps-text-search-service.js +32 -0
- package/dist/esm/services/ps-upload-queue-service.js +37 -0
- package/dist/esm/services/ps-xhr-upload-service.js +52 -0
- package/dist/hooks/use-ps-active-match-scroll.d.ts +2 -0
- package/dist/hooks/use-ps-active-match-scroll.js +12 -0
- package/dist/hooks/use-ps-file-text.d.ts +2 -0
- package/dist/hooks/use-ps-file-text.js +25 -0
- package/dist/hooks/use-ps-in-view.d.ts +2 -0
- package/dist/hooks/use-ps-in-view.js +21 -0
- package/dist/hooks/use-ps-upload-queue.d.ts +3 -0
- package/dist/hooks/use-ps-upload-queue.js +71 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +78 -0
- package/dist/models/ps-file-rejection.d.ts +4 -0
- package/dist/models/ps-file-rejection.js +2 -0
- package/dist/models/ps-file-selection-rules.d.ts +6 -0
- package/dist/models/ps-file-selection-rules.js +2 -0
- package/dist/models/ps-file-selection.d.ts +5 -0
- package/dist/models/ps-file-selection.js +2 -0
- package/dist/models/ps-file-text-state.d.ts +4 -0
- package/dist/models/ps-file-text-state.js +2 -0
- package/dist/models/ps-file-viewer-content-props.d.ts +13 -0
- package/dist/models/ps-file-viewer-content-props.js +2 -0
- package/dist/models/ps-label-set.d.ts +3 -0
- package/dist/models/ps-label-set.js +2 -0
- package/dist/models/ps-page-size.d.ts +4 -0
- package/dist/models/ps-page-size.js +2 -0
- package/dist/models/ps-pdf-match.d.ts +7 -0
- package/dist/models/ps-pdf-match.js +2 -0
- package/dist/models/ps-point.d.ts +4 -0
- package/dist/models/ps-point.js +2 -0
- package/dist/models/ps-text-match.d.ts +4 -0
- package/dist/models/ps-text-match.js +2 -0
- package/dist/models/ps-text-segment.d.ts +5 -0
- package/dist/models/ps-text-segment.js +2 -0
- package/dist/models/ps-upload-handler-options.d.ts +4 -0
- package/dist/models/ps-upload-handler-options.js +2 -0
- package/dist/models/ps-upload-item.d.ts +8 -0
- package/dist/models/ps-upload-item.js +2 -0
- package/dist/models/ps-upload-queue-options.d.ts +6 -0
- package/dist/models/ps-upload-queue-options.js +2 -0
- package/dist/models/ps-upload-queue-state.d.ts +10 -0
- package/dist/models/ps-upload-queue-state.js +2 -0
- package/dist/models/ps-upload-summary.d.ts +5 -0
- package/dist/models/ps-upload-summary.js +2 -0
- package/dist/models/ps-viewer-file.d.ts +9 -0
- package/dist/models/ps-viewer-file.js +2 -0
- package/dist/models/ps-xhr-upload-request.d.ts +8 -0
- package/dist/models/ps-xhr-upload-request.js +2 -0
- package/dist/models/ps-xhr-upload-response.d.ts +4 -0
- package/dist/models/ps-xhr-upload-response.js +2 -0
- package/dist/services/ps-csv-service.d.ts +3 -0
- package/dist/services/ps-csv-service.js +46 -0
- package/dist/services/ps-file-selection-service.d.ts +5 -0
- package/dist/services/ps-file-selection-service.js +20 -0
- package/dist/services/ps-file-size-service.d.ts +3 -0
- package/dist/services/ps-file-size-service.js +18 -0
- package/dist/services/ps-file-type-service.d.ts +6 -0
- package/dist/services/ps-file-type-service.js +42 -0
- package/dist/services/ps-pdf-service.d.ts +11 -0
- package/dist/services/ps-pdf-service.js +96 -0
- package/dist/services/ps-text-search-service.d.ts +6 -0
- package/dist/services/ps-text-search-service.js +36 -0
- package/dist/services/ps-upload-queue-service.d.ts +10 -0
- package/dist/services/ps-upload-queue-service.js +41 -0
- package/dist/services/ps-xhr-upload-service.d.ts +7 -0
- package/dist/services/ps-xhr-upload-service.js +56 -0
- package/package.json +85 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
|
2
|
+
export interface PsPdfThumbnailProps {
|
|
3
|
+
document: PDFDocumentProxy;
|
|
4
|
+
hasMatches: boolean;
|
|
5
|
+
isCurrent: boolean;
|
|
6
|
+
label: string;
|
|
7
|
+
onSelect: () => void;
|
|
8
|
+
pageNumber: number;
|
|
9
|
+
rotation: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const PsPdfThumbnail: ({ document, hasMatches, isCurrent, label, onSelect, pageNumber, rotation, }: PsPdfThumbnailProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsPdfThumbnail = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const ps_file_viewer_config_1 = require("../../constants/ps-file-viewer-config");
|
|
7
|
+
const use_ps_in_view_1 = require("../../hooks/use-ps-in-view");
|
|
8
|
+
const ps_pdf_service_1 = require("../../services/ps-pdf-service");
|
|
9
|
+
const PsPdfThumbnail = ({ document, hasMatches, isCurrent, label, onSelect, pageNumber, rotation, }) => {
|
|
10
|
+
const canvas = (0, react_1.useRef)(null);
|
|
11
|
+
const [container, isInView] = (0, use_ps_in_view_1.usePsInView)('200px');
|
|
12
|
+
(0, react_1.useEffect)(() => {
|
|
13
|
+
if (!isInView)
|
|
14
|
+
return;
|
|
15
|
+
let isCurrent = true;
|
|
16
|
+
let task = null;
|
|
17
|
+
document.getPage(pageNumber).then((page) => {
|
|
18
|
+
if (isCurrent && canvas.current)
|
|
19
|
+
task = ps_pdf_service_1.PsPdfService.render(page, canvas.current, ps_file_viewer_config_1.PsFileViewerConfig.pdfThumbnailScale, rotation);
|
|
20
|
+
});
|
|
21
|
+
return () => {
|
|
22
|
+
isCurrent = false;
|
|
23
|
+
task?.cancel();
|
|
24
|
+
};
|
|
25
|
+
}, [document, pageNumber, rotation, isInView]);
|
|
26
|
+
return ((0, jsx_runtime_1.jsxs)("button", { "aria-current": isCurrent ? 'page' : undefined, "aria-label": `${label} ${pageNumber}`, className: `ps-focus-ring relative flex flex-col items-center gap-1 rounded-md p-1.5 transition ${isCurrent ? 'bg-white/15' : 'hover:bg-white/10'}`, onClick: onSelect, ref: container, type: 'button', children: [(0, jsx_runtime_1.jsx)("canvas", { className: `block min-h-16 min-w-12 bg-white ${isCurrent ? 'ring-2 ring-primary' : ''}`, ref: canvas }), (0, jsx_runtime_1.jsx)("span", { className: 'text-[0.7rem] text-white/70', children: pageNumber }), hasMatches ? ((0, jsx_runtime_1.jsx)("span", { className: 'absolute right-1 top-1 h-2 w-2 rounded-full bg-warning' })) : null] }));
|
|
27
|
+
};
|
|
28
|
+
exports.PsPdfThumbnail = PsPdfThumbnail;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsPdfViewer = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
7
|
+
const ps_file_viewer_config_1 = require("../../constants/ps-file-viewer-config");
|
|
8
|
+
const ps_pdf_service_1 = require("../../services/ps-pdf-service");
|
|
9
|
+
const ps_pdf_page_1 = require("./ps-pdf-page");
|
|
10
|
+
const ps_pdf_thumbnail_1 = require("./ps-pdf-thumbnail");
|
|
11
|
+
const PsPdfViewer = ({ activeMatch, file, labels, onMatchCount, pdfWorkerSrc, query, rotation, zoom, }) => {
|
|
12
|
+
const [document, setDocument] = (0, react_1.useState)(null);
|
|
13
|
+
const [hasFailed, setHasFailed] = (0, react_1.useState)(false);
|
|
14
|
+
const [pageWidth, setPageWidth] = (0, react_1.useState)(0);
|
|
15
|
+
const [matches, setMatches] = (0, react_1.useState)([]);
|
|
16
|
+
const [currentPage, setCurrentPage] = (0, react_1.useState)(1);
|
|
17
|
+
const [frame, frameSize] = (0, ps_core_components_1.usePsElementSize)();
|
|
18
|
+
const scroller = (0, react_1.useRef)(null);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
let isCurrent = true;
|
|
21
|
+
let opened = null;
|
|
22
|
+
setDocument(null);
|
|
23
|
+
setHasFailed(false);
|
|
24
|
+
if (pdfWorkerSrc === undefined) {
|
|
25
|
+
setHasFailed(true);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
ps_pdf_service_1.PsPdfService.open(file.url, pdfWorkerSrc)
|
|
29
|
+
.then(async (loaded) => {
|
|
30
|
+
opened = loaded;
|
|
31
|
+
const firstPage = await loaded.getPage(1);
|
|
32
|
+
if (!isCurrent)
|
|
33
|
+
return;
|
|
34
|
+
setPageWidth(firstPage.getViewport({ rotation: firstPage.rotate + rotation, scale: 1 }).width);
|
|
35
|
+
setDocument(loaded);
|
|
36
|
+
})
|
|
37
|
+
.catch(() => {
|
|
38
|
+
if (isCurrent)
|
|
39
|
+
setHasFailed(true);
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
isCurrent = false;
|
|
43
|
+
void opened?.loadingTask.destroy();
|
|
44
|
+
};
|
|
45
|
+
}, [file.url, pdfWorkerSrc]);
|
|
46
|
+
(0, react_1.useEffect)(() => {
|
|
47
|
+
if (document === null)
|
|
48
|
+
return;
|
|
49
|
+
let isCurrent = true;
|
|
50
|
+
document.getPage(1).then((page) => {
|
|
51
|
+
if (isCurrent)
|
|
52
|
+
setPageWidth(page.getViewport({ rotation: page.rotate + rotation, scale: 1 }).width);
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
isCurrent = false;
|
|
56
|
+
};
|
|
57
|
+
}, [document, rotation]);
|
|
58
|
+
(0, react_1.useEffect)(() => {
|
|
59
|
+
if (document === null || query.trim().length === 0) {
|
|
60
|
+
setMatches([]);
|
|
61
|
+
onMatchCount(0);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let isCurrent = true;
|
|
65
|
+
ps_pdf_service_1.PsPdfService.search(document, query, rotation).then((found) => {
|
|
66
|
+
if (!isCurrent)
|
|
67
|
+
return;
|
|
68
|
+
setMatches(found);
|
|
69
|
+
onMatchCount(found.length);
|
|
70
|
+
});
|
|
71
|
+
return () => {
|
|
72
|
+
isCurrent = false;
|
|
73
|
+
};
|
|
74
|
+
}, [document, query, rotation]);
|
|
75
|
+
const active = matches.length > 0 ? matches[activeMatch % matches.length] : null;
|
|
76
|
+
const scrollToPage = (pageNumber) => {
|
|
77
|
+
const node = scroller.current?.querySelector(`[data-ps-pdf-page='${pageNumber}']`);
|
|
78
|
+
if (node instanceof HTMLElement)
|
|
79
|
+
node.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
80
|
+
setCurrentPage(pageNumber);
|
|
81
|
+
};
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
if (active !== null)
|
|
84
|
+
scrollToPage(active.pageNumber);
|
|
85
|
+
}, [active]);
|
|
86
|
+
const scale = (0, react_1.useMemo)(() => {
|
|
87
|
+
const fit = frameSize.width > 0 && pageWidth > 0
|
|
88
|
+
? (frameSize.width - 48) / pageWidth
|
|
89
|
+
: ps_file_viewer_config_1.PsFileViewerConfig.pdfBaseScale;
|
|
90
|
+
return Math.max(0.1, fit * zoom);
|
|
91
|
+
}, [frameSize.width, pageWidth, zoom]);
|
|
92
|
+
const pages = document === null ? [] : Array.from({ length: document.numPages }, (_, index) => index + 1);
|
|
93
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full w-full min-w-0', children: [document !== null && document.numPages > 1 ? ((0, jsx_runtime_1.jsx)("nav", { className: 'ps-scrollbar-hidden hidden w-24 shrink-0 flex-col items-center gap-2 overflow-y-auto border-r border-white/10 py-3 md:flex', children: pages.map((pageNumber) => ((0, jsx_runtime_1.jsx)(ps_pdf_thumbnail_1.PsPdfThumbnail, { document: document, hasMatches: matches.some((match) => match.pageNumber === pageNumber), isCurrent: pageNumber === currentPage, label: labels.page, onSelect: () => scrollToPage(pageNumber), pageNumber: pageNumber, rotation: rotation }, pageNumber))) })) : null, (0, jsx_runtime_1.jsx)("div", { className: 'min-w-0 flex-1', ref: frame, children: hasFailed ? ((0, jsx_runtime_1.jsx)("p", { className: 'flex h-full items-center justify-center text-sm text-white/70', children: labels.loadFailed })) : document === null ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex h-full items-center justify-center text-white', children: (0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { color: 'current', size: 'large' }) })) : ((0, jsx_runtime_1.jsx)("div", { className: 'flex h-full flex-col items-center gap-4 overflow-auto px-6 py-6', onScroll: (event) => {
|
|
94
|
+
const top = event.currentTarget.scrollTop + event.currentTarget.clientHeight / 3;
|
|
95
|
+
const visible = Array.from(event.currentTarget.querySelectorAll('[data-ps-pdf-page]')).find((node) => node.offsetTop + node.offsetHeight > top);
|
|
96
|
+
if (visible)
|
|
97
|
+
setCurrentPage(Number(visible.dataset.psPdfPage));
|
|
98
|
+
}, ref: scroller, children: pages.map((pageNumber) => ((0, jsx_runtime_1.jsx)(ps_pdf_page_1.PsPdfPage, { activeMatch: active, document: document, label: labels.page, matches: matches.filter((match) => match.pageNumber === pageNumber), pageNumber: pageNumber, rotation: rotation, scale: scale }, pageNumber))) })) })] }));
|
|
99
|
+
};
|
|
100
|
+
exports.PsPdfViewer = PsPdfViewer;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsTextViewer = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
7
|
+
const ps_file_kind_1 = require("../../constants/ps-file-kind");
|
|
8
|
+
const use_ps_active_match_scroll_1 = require("../../hooks/use-ps-active-match-scroll");
|
|
9
|
+
const use_ps_file_text_1 = require("../../hooks/use-ps-file-text");
|
|
10
|
+
const ps_csv_service_1 = require("../../services/ps-csv-service");
|
|
11
|
+
const ps_file_type_service_1 = require("../../services/ps-file-type-service");
|
|
12
|
+
const ps_text_search_service_1 = require("../../services/ps-text-search-service");
|
|
13
|
+
const ps_highlighted_text_1 = require("./ps-highlighted-text");
|
|
14
|
+
const PsTextViewer = ({ activeMatch, file, labels, onMatchCount, query, zoom, }) => {
|
|
15
|
+
const { hasFailed, text } = (0, use_ps_file_text_1.usePsFileText)(file.url);
|
|
16
|
+
const container = (0, react_1.useRef)(null);
|
|
17
|
+
const isCsv = ps_file_type_service_1.PsFileTypeService.kindOf(file.contentType, file.name) === ps_file_kind_1.PsFileKind.csv;
|
|
18
|
+
const rows = (0, react_1.useMemo)(() => (isCsv && text !== null ? ps_csv_service_1.PsCsvService.parse(text) : []), [isCsv, text]);
|
|
19
|
+
const cells = (0, react_1.useMemo)(() => {
|
|
20
|
+
let offset = 0;
|
|
21
|
+
return rows.map((row) => row.map((cell) => {
|
|
22
|
+
const matches = ps_text_search_service_1.PsTextSearchService.find(cell, query);
|
|
23
|
+
const segments = ps_text_search_service_1.PsTextSearchService.segments(cell, matches, offset);
|
|
24
|
+
offset += matches.length;
|
|
25
|
+
return segments;
|
|
26
|
+
}));
|
|
27
|
+
}, [rows, query]);
|
|
28
|
+
const segments = (0, react_1.useMemo)(() => isCsv || text === null
|
|
29
|
+
? []
|
|
30
|
+
: ps_text_search_service_1.PsTextSearchService.segments(text, ps_text_search_service_1.PsTextSearchService.find(text, query)), [isCsv, text, query]);
|
|
31
|
+
const count = isCsv
|
|
32
|
+
? cells.reduce((total, row) => total + row.reduce((sum, cell) => sum + cell.filter((part) => part.isMatch).length, 0), 0)
|
|
33
|
+
: segments.filter((part) => part.isMatch).length;
|
|
34
|
+
(0, react_1.useEffect)(() => onMatchCount(count), [count]);
|
|
35
|
+
(0, use_ps_active_match_scroll_1.usePsActiveMatchScroll)(container, activeMatch, query);
|
|
36
|
+
if (hasFailed)
|
|
37
|
+
return (0, jsx_runtime_1.jsx)("p", { className: 'm-auto text-sm text-white/70', children: labels.loadFailed });
|
|
38
|
+
if (text === null)
|
|
39
|
+
return (0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { className: 'm-auto', color: 'current', size: 'large' });
|
|
40
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: 'h-full w-full overflow-auto', ref: container, children: (0, jsx_runtime_1.jsx)("div", { className: 'mx-auto w-full max-w-5xl rounded-lg bg-surface p-5 text-ink shadow-2xl', style: { fontSize: `${zoom * 0.875}rem` }, children: isCsv ? ((0, jsx_runtime_1.jsx)("table", { className: 'w-full border-collapse text-left', children: (0, jsx_runtime_1.jsx)("tbody", { children: cells.map((row, rowIndex) => ((0, jsx_runtime_1.jsx)("tr", { className: rowIndex === 0 ? 'bg-primary-soft/50 font-semibold' : 'border-t border-line', children: row.map((cell, cellIndex) => ((0, jsx_runtime_1.jsx)("td", { className: 'whitespace-nowrap px-3 py-1.5 align-top', children: (0, jsx_runtime_1.jsx)(ps_highlighted_text_1.PsHighlightedText, { activeMatch: activeMatch, segments: cell }) }, cellIndex))) }, rowIndex))) }) })) : ((0, jsx_runtime_1.jsx)("pre", { className: 'whitespace-pre-wrap break-words font-mono leading-relaxed', children: (0, jsx_runtime_1.jsx)(ps_highlighted_text_1.PsHighlightedText, { activeMatch: activeMatch, segments: segments }) })) }) }));
|
|
41
|
+
};
|
|
42
|
+
exports.PsTextViewer = PsTextViewer;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsUnsupportedViewer = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
6
|
+
const ps_file_kind_icon_1 = require("../ps-file-kind-icon");
|
|
7
|
+
const PsUnsupportedViewer = ({ file, labels }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'm-auto flex max-w-sm flex-col items-center gap-4 rounded-2xl bg-surface p-8 text-center shadow-2xl', children: [(0, jsx_runtime_1.jsx)(ps_file_kind_icon_1.PsFileKindIcon, { className: 'h-14 w-14', contentType: file.contentType, name: file.name }), (0, jsx_runtime_1.jsx)("p", { className: 'break-all font-semibold text-ink', children: file.name }), (0, jsx_runtime_1.jsx)("p", { className: 'text-sm text-ink/60', children: labels.unsupported }), (0, jsx_runtime_1.jsxs)("a", { className: 'ps-focus-ring inline-flex items-center gap-2 rounded-full bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90', download: file.name, href: file.downloadUrl === undefined ? file.url : file.downloadUrl, children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'h-4 w-4', iconKey: ps_icons_1.PsIconKey.Download }), labels.download] })] }));
|
|
8
|
+
exports.PsUnsupportedViewer = PsUnsupportedViewer;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileKindIcons = void 0;
|
|
4
|
+
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
5
|
+
const ps_file_kind_1 = require("./ps-file-kind");
|
|
6
|
+
exports.PsFileKindIcons = {
|
|
7
|
+
[ps_file_kind_1.PsFileKind.audio]: ps_icons_1.PsIconKey.Audio,
|
|
8
|
+
[ps_file_kind_1.PsFileKind.csv]: ps_icons_1.PsIconKey.Sheet,
|
|
9
|
+
[ps_file_kind_1.PsFileKind.image]: ps_icons_1.PsIconKey.Image,
|
|
10
|
+
[ps_file_kind_1.PsFileKind.other]: ps_icons_1.PsIconKey.File,
|
|
11
|
+
[ps_file_kind_1.PsFileKind.pdf]: ps_icons_1.PsIconKey.Doc,
|
|
12
|
+
[ps_file_kind_1.PsFileKind.text]: ps_icons_1.PsIconKey.Text,
|
|
13
|
+
[ps_file_kind_1.PsFileKind.video]: ps_icons_1.PsIconKey.Video,
|
|
14
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const PsFileKind: {
|
|
2
|
+
readonly audio: "audio";
|
|
3
|
+
readonly csv: "csv";
|
|
4
|
+
readonly image: "image";
|
|
5
|
+
readonly other: "other";
|
|
6
|
+
readonly pdf: "pdf";
|
|
7
|
+
readonly text: "text";
|
|
8
|
+
readonly video: "video";
|
|
9
|
+
};
|
|
10
|
+
export type PsFileKind = (typeof PsFileKind)[keyof typeof PsFileKind];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileKind = void 0;
|
|
4
|
+
exports.PsFileKind = {
|
|
5
|
+
audio: 'audio',
|
|
6
|
+
csv: 'csv',
|
|
7
|
+
image: 'image',
|
|
8
|
+
other: 'other',
|
|
9
|
+
pdf: 'pdf',
|
|
10
|
+
text: 'text',
|
|
11
|
+
video: 'video',
|
|
12
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const PsFilePickerLabels: {
|
|
2
|
+
readonly browse: "or click to browse your files";
|
|
3
|
+
readonly dropActive: "Drop to upload";
|
|
4
|
+
readonly formats: "Accepted formats:";
|
|
5
|
+
readonly invalidType: "is not a supported file type.";
|
|
6
|
+
readonly tooLarge: "is too large.";
|
|
7
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFilePickerLabels = void 0;
|
|
4
|
+
exports.PsFilePickerLabels = {
|
|
5
|
+
browse: 'or click to browse your files',
|
|
6
|
+
dropActive: 'Drop to upload',
|
|
7
|
+
formats: 'Accepted formats:',
|
|
8
|
+
invalidType: 'is not a supported file type.',
|
|
9
|
+
tooLarge: 'is too large.',
|
|
10
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PsFileKind } from './ps-file-kind';
|
|
2
|
+
export declare const PsFileTypeConfig: {
|
|
3
|
+
readonly csvTypes: readonly ["text/csv", "application/csv", "application/vnd.ms-excel"];
|
|
4
|
+
readonly extensionKinds: Record<string, PsFileKind>;
|
|
5
|
+
readonly sizeUnits: readonly ["B", "KB", "MB", "GB"];
|
|
6
|
+
readonly textTypes: readonly ["application/json", "application/xml"];
|
|
7
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileTypeConfig = void 0;
|
|
4
|
+
const ps_file_kind_1 = require("./ps-file-kind");
|
|
5
|
+
exports.PsFileTypeConfig = {
|
|
6
|
+
csvTypes: ['text/csv', 'application/csv', 'application/vnd.ms-excel'],
|
|
7
|
+
extensionKinds: {
|
|
8
|
+
csv: ps_file_kind_1.PsFileKind.csv,
|
|
9
|
+
gif: ps_file_kind_1.PsFileKind.image,
|
|
10
|
+
heic: ps_file_kind_1.PsFileKind.image,
|
|
11
|
+
jpeg: ps_file_kind_1.PsFileKind.image,
|
|
12
|
+
jpg: ps_file_kind_1.PsFileKind.image,
|
|
13
|
+
json: ps_file_kind_1.PsFileKind.text,
|
|
14
|
+
log: ps_file_kind_1.PsFileKind.text,
|
|
15
|
+
md: ps_file_kind_1.PsFileKind.text,
|
|
16
|
+
mov: ps_file_kind_1.PsFileKind.video,
|
|
17
|
+
mp3: ps_file_kind_1.PsFileKind.audio,
|
|
18
|
+
mp4: ps_file_kind_1.PsFileKind.video,
|
|
19
|
+
pdf: ps_file_kind_1.PsFileKind.pdf,
|
|
20
|
+
png: ps_file_kind_1.PsFileKind.image,
|
|
21
|
+
svg: ps_file_kind_1.PsFileKind.image,
|
|
22
|
+
txt: ps_file_kind_1.PsFileKind.text,
|
|
23
|
+
wav: ps_file_kind_1.PsFileKind.audio,
|
|
24
|
+
webm: ps_file_kind_1.PsFileKind.video,
|
|
25
|
+
webp: ps_file_kind_1.PsFileKind.image,
|
|
26
|
+
xml: ps_file_kind_1.PsFileKind.text,
|
|
27
|
+
},
|
|
28
|
+
sizeUnits: ['B', 'KB', 'MB', 'GB'],
|
|
29
|
+
textTypes: ['application/json', 'application/xml'],
|
|
30
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileViewerConfig = void 0;
|
|
4
|
+
exports.PsFileViewerConfig = {
|
|
5
|
+
maxZoom: 4,
|
|
6
|
+
minZoom: 0.25,
|
|
7
|
+
pdfBaseScale: 1.4,
|
|
8
|
+
pdfThumbnailScale: 0.2,
|
|
9
|
+
rotateStep: 90,
|
|
10
|
+
searchDebounceMs: 250,
|
|
11
|
+
zoomStep: 0.25,
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileViewerKinds = void 0;
|
|
4
|
+
const ps_file_kind_1 = require("./ps-file-kind");
|
|
5
|
+
exports.PsFileViewerKinds = {
|
|
6
|
+
rotatable: [ps_file_kind_1.PsFileKind.image, ps_file_kind_1.PsFileKind.pdf],
|
|
7
|
+
searchable: [ps_file_kind_1.PsFileKind.csv, ps_file_kind_1.PsFileKind.pdf, ps_file_kind_1.PsFileKind.text],
|
|
8
|
+
zoomable: [ps_file_kind_1.PsFileKind.csv, ps_file_kind_1.PsFileKind.image, ps_file_kind_1.PsFileKind.pdf, ps_file_kind_1.PsFileKind.text],
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const PsFileViewerLabels: {
|
|
2
|
+
readonly close: "Close";
|
|
3
|
+
readonly delete: "Delete";
|
|
4
|
+
readonly deleteConfirm: "Delete file";
|
|
5
|
+
readonly deleteConfirmBody: "This file will be removed. This cannot be undone from here.";
|
|
6
|
+
readonly deleteCancel: "Keep file";
|
|
7
|
+
readonly download: "Download";
|
|
8
|
+
readonly loadFailed: "This file could not be opened.";
|
|
9
|
+
readonly next: "Next file";
|
|
10
|
+
readonly nextMatch: "Next match";
|
|
11
|
+
readonly noMatches: "No matches";
|
|
12
|
+
readonly page: "Page";
|
|
13
|
+
readonly previous: "Previous file";
|
|
14
|
+
readonly previousMatch: "Previous match";
|
|
15
|
+
readonly rotate: "Rotate";
|
|
16
|
+
readonly search: "Search in file";
|
|
17
|
+
readonly unsupported: "This file type cannot be previewed here. Download it to open it.";
|
|
18
|
+
readonly zoomIn: "Zoom in";
|
|
19
|
+
readonly zoomOut: "Zoom out";
|
|
20
|
+
readonly zoomReset: "Fit";
|
|
21
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsFileViewerLabels = void 0;
|
|
4
|
+
exports.PsFileViewerLabels = {
|
|
5
|
+
close: 'Close',
|
|
6
|
+
delete: 'Delete',
|
|
7
|
+
deleteConfirm: 'Delete file',
|
|
8
|
+
deleteConfirmBody: 'This file will be removed. This cannot be undone from here.',
|
|
9
|
+
deleteCancel: 'Keep file',
|
|
10
|
+
download: 'Download',
|
|
11
|
+
loadFailed: 'This file could not be opened.',
|
|
12
|
+
next: 'Next file',
|
|
13
|
+
nextMatch: 'Next match',
|
|
14
|
+
noMatches: 'No matches',
|
|
15
|
+
page: 'Page',
|
|
16
|
+
previous: 'Previous file',
|
|
17
|
+
previousMatch: 'Previous match',
|
|
18
|
+
rotate: 'Rotate',
|
|
19
|
+
search: 'Search in file',
|
|
20
|
+
unsupported: 'This file type cannot be previewed here. Download it to open it.',
|
|
21
|
+
zoomIn: 'Zoom in',
|
|
22
|
+
zoomOut: 'Zoom out',
|
|
23
|
+
zoomReset: 'Fit',
|
|
24
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const PsUploadLabels: {
|
|
2
|
+
readonly cancel: "Cancel";
|
|
3
|
+
readonly cancelled: "Cancelled";
|
|
4
|
+
readonly close: "Close";
|
|
5
|
+
readonly done: "Uploaded";
|
|
6
|
+
readonly failed: "Failed";
|
|
7
|
+
readonly processing: "Saving";
|
|
8
|
+
readonly remove: "Remove";
|
|
9
|
+
readonly retry: "Retry";
|
|
10
|
+
readonly title: "Uploading files";
|
|
11
|
+
readonly titleDone: "Upload finished";
|
|
12
|
+
readonly uploading: "Uploading";
|
|
13
|
+
readonly waiting: "Waiting";
|
|
14
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsUploadLabels = void 0;
|
|
4
|
+
exports.PsUploadLabels = {
|
|
5
|
+
cancel: 'Cancel',
|
|
6
|
+
cancelled: 'Cancelled',
|
|
7
|
+
close: 'Close',
|
|
8
|
+
done: 'Uploaded',
|
|
9
|
+
failed: 'Failed',
|
|
10
|
+
processing: 'Saving',
|
|
11
|
+
remove: 'Remove',
|
|
12
|
+
retry: 'Retry',
|
|
13
|
+
title: 'Uploading files',
|
|
14
|
+
titleDone: 'Upload finished',
|
|
15
|
+
uploading: 'Uploading',
|
|
16
|
+
waiting: 'Waiting',
|
|
17
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsUploadStatusTones = void 0;
|
|
4
|
+
const ps_upload_status_1 = require("./ps-upload-status");
|
|
5
|
+
exports.PsUploadStatusTones = {
|
|
6
|
+
[ps_upload_status_1.PsUploadStatus.cancelled]: 'danger',
|
|
7
|
+
[ps_upload_status_1.PsUploadStatus.done]: 'success',
|
|
8
|
+
[ps_upload_status_1.PsUploadStatus.failed]: 'danger',
|
|
9
|
+
[ps_upload_status_1.PsUploadStatus.processing]: 'primary',
|
|
10
|
+
[ps_upload_status_1.PsUploadStatus.uploading]: 'primary',
|
|
11
|
+
[ps_upload_status_1.PsUploadStatus.waiting]: 'primary',
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const PsUploadStatus: {
|
|
2
|
+
readonly cancelled: "cancelled";
|
|
3
|
+
readonly done: "done";
|
|
4
|
+
readonly failed: "failed";
|
|
5
|
+
readonly processing: "processing";
|
|
6
|
+
readonly uploading: "uploading";
|
|
7
|
+
readonly waiting: "waiting";
|
|
8
|
+
};
|
|
9
|
+
export type PsUploadStatus = (typeof PsUploadStatus)[keyof typeof PsUploadStatus];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsUploadStatus = void 0;
|
|
4
|
+
exports.PsUploadStatus = {
|
|
5
|
+
cancelled: 'cancelled',
|
|
6
|
+
done: 'done',
|
|
7
|
+
failed: 'failed',
|
|
8
|
+
processing: 'processing',
|
|
9
|
+
uploading: 'uploading',
|
|
10
|
+
waiting: 'waiting',
|
|
11
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PsButton } from '@pallasoft/ps-core-components';
|
|
3
|
+
import { PsModal } from '@pallasoft/ps-popovers';
|
|
4
|
+
export const PsFileDeleteConfirm = ({ fileName, isDeleting, isOpen, labels, onCancel, onConfirm, }) => (_jsx(PsModal, { eyebrow: fileName, isOpen: isOpen, onClose: onCancel, size: 'sm', title: labels.deleteConfirm, children: _jsxs("div", { className: 'flex flex-col gap-5', children: [_jsx("p", { className: 'text-sm text-ink/70', children: labels.deleteConfirmBody }), _jsxs("div", { className: 'flex justify-end gap-2', children: [_jsx(PsButton, { disabled: isDeleting, onClick: onCancel, type: 'button', variant: 'ghost', children: labels.deleteCancel }), _jsx(PsButton, { isLoading: isDeleting, onClick: onConfirm, type: 'button', variant: 'danger', children: labels.delete })] })] }) }));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
+
import { PsIcon } from '@pallasoft/ps-icons';
|
|
4
|
+
import { PsFileKindIcons } from '../constants/ps-file-kind-icons';
|
|
5
|
+
import { PsFileTypeService } from '../services/ps-file-type-service';
|
|
6
|
+
export const PsFileKindIcon = ({ className, contentType, name }) => (_jsx("span", { className: PallasoftClassNameService.merge('inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-ps-control bg-primary-soft/60 text-primary', className), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'h-5 w-5', iconKey: PsFileKindIcons[PsFileTypeService.kindOf(contentType, name)] }) }));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PsButton } from '@pallasoft/ps-core-components';
|
|
3
|
+
import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
|
|
4
|
+
import { PsFileKind } from '../constants/ps-file-kind';
|
|
5
|
+
import { PsFileListLabels } from '../constants/ps-file-list-labels';
|
|
6
|
+
import { PsFileSizeService } from '../services/ps-file-size-service';
|
|
7
|
+
import { PsFileTypeService } from '../services/ps-file-type-service';
|
|
8
|
+
import { PsFileKindIcon } from './ps-file-kind-icon';
|
|
9
|
+
export const PsFileList = ({ busyIds = [], files, formatDate, labels, onDelete, onOpen, }) => {
|
|
10
|
+
const text = { ...PsFileListLabels, ...labels };
|
|
11
|
+
if (files.length === 0)
|
|
12
|
+
return _jsx("p", { className: 'text-sm text-ink/60', children: text.empty });
|
|
13
|
+
return (_jsx("ul", { className: 'grid gap-2 sm:grid-cols-2', children: files.map((file, index) => {
|
|
14
|
+
const isImage = PsFileTypeService.kindOf(file.contentType, file.name) === PsFileKind.image;
|
|
15
|
+
const meta = [
|
|
16
|
+
file.sizeBytes === undefined ? null : PsFileSizeService.format(file.sizeBytes),
|
|
17
|
+
file.createdAt === undefined || formatDate === undefined
|
|
18
|
+
? null
|
|
19
|
+
: formatDate(file.createdAt),
|
|
20
|
+
].filter((value) => value !== null);
|
|
21
|
+
return (_jsxs("li", { className: 'group flex min-w-0 items-center gap-3 rounded-ps-control border border-line bg-surface p-2 transition hover:border-primary/40', children: [_jsxs("button", { "aria-label": `${text.open} ${file.name}`, className: 'ps-focus-ring flex min-w-0 flex-1 items-center gap-3 rounded-ps-control text-left', onClick: () => onOpen(index), type: 'button', children: [isImage ? (_jsx("img", { alt: '', className: 'h-12 w-12 shrink-0 rounded-ps-control border border-line object-cover', loading: 'lazy', src: file.url })) : (_jsx(PsFileKindIcon, { className: 'h-12 w-12', contentType: file.contentType, name: file.name })), _jsxs("span", { className: 'flex min-w-0 flex-col', children: [_jsx("span", { className: 'truncate text-sm font-medium text-ink group-hover:text-primary', children: file.name }), meta.length > 0 ? (_jsx("span", { className: 'truncate text-xs text-ink/55', children: meta.join(' · ') })) : null] })] }), _jsx("a", { "aria-label": `${text.download} ${file.name}`, className: 'ps-focus-ring inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-ink/55 transition hover:bg-primary-soft/60 hover:text-primary', download: file.name, href: file.downloadUrl === undefined ? file.url : file.downloadUrl, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'h-4 w-4', iconKey: PsIconKey.Download }) }), onDelete ? (_jsx(PsButton, { "aria-label": `${text.delete} ${file.name}`, className: 'h-9 w-9 shrink-0 rounded-full p-0', disabled: busyIds.includes(file.id), onClick: () => onDelete(file), size: 'compact', type: 'button', variant: 'ghost', children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'h-4 w-4', iconKey: PsIconKey.Trash }) })) : null] }, file.id));
|
|
22
|
+
}) }));
|
|
23
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
4
|
+
import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
|
|
5
|
+
import { PsFilePickerLabels } from '../constants/ps-file-picker-labels';
|
|
6
|
+
import { PsFileSelectionService } from '../services/ps-file-selection-service';
|
|
7
|
+
export const PsFilePicker = ({ accept, acceptLabel, className, disabled = false, dropLabel, isLoading = false, labels, maxSizeBytes, maxSizeLabel, multiple = false, onError, onFileLoad, onFilesSelect, }) => {
|
|
8
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
9
|
+
const acceptAttr = useMemo(() => accept.join(','), [accept]);
|
|
10
|
+
const text = { ...PsFilePickerLabels, ...labels };
|
|
11
|
+
if (isLoading)
|
|
12
|
+
return (_jsx("span", { "aria-busy": 'true', className: PallasoftClassNameService.merge('ps-skeleton block min-h-32 w-full rounded-ps-panel', className), role: 'status' }));
|
|
13
|
+
const select = (list) => {
|
|
14
|
+
if (list === null || disabled)
|
|
15
|
+
return;
|
|
16
|
+
const files = multiple ? Array.from(list) : Array.from(list).slice(0, 1);
|
|
17
|
+
const { accepted, rejected } = PsFileSelectionService.split(files, {
|
|
18
|
+
accept,
|
|
19
|
+
invalidTypeMessage: text.invalidType,
|
|
20
|
+
maxSizeBytes,
|
|
21
|
+
tooLargeMessage: maxSizeLabel ? `${text.tooLarge} ${maxSizeLabel}.` : text.tooLarge,
|
|
22
|
+
});
|
|
23
|
+
rejected.forEach((rejection) => onError?.(rejection.message));
|
|
24
|
+
if (accepted.length === 0)
|
|
25
|
+
return;
|
|
26
|
+
if (onFilesSelect)
|
|
27
|
+
onFilesSelect(accepted);
|
|
28
|
+
else
|
|
29
|
+
onFileLoad?.(accepted[0]);
|
|
30
|
+
};
|
|
31
|
+
const onChange = (event) => {
|
|
32
|
+
select(event.target.files);
|
|
33
|
+
event.target.value = '';
|
|
34
|
+
};
|
|
35
|
+
const onDrag = (event, isOver) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
if (!disabled)
|
|
38
|
+
setIsDragging(isOver);
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-lg border-2 border-dashed border-line p-4 transition-all hover:border-primary/50 hover:bg-primary/5 sm:h-64', isDragging ? 'border-primary bg-primary/10' : '', disabled ? 'pointer-events-none opacity-60' : '', className), onDragEnter: (event) => onDrag(event, true), onDragLeave: (event) => onDrag(event, false), onDragOver: (event) => onDrag(event, true), onDrop: (event) => {
|
|
41
|
+
onDrag(event, false);
|
|
42
|
+
select(event.dataTransfer.files);
|
|
43
|
+
}, children: [_jsxs("div", { className: 'pointer-events-none flex flex-col items-center gap-3 text-center', children: [_jsx(PsIcon, { className: 'h-8 w-8 text-primary', iconKey: PsIconKey.Upload }), _jsxs("div", { children: [_jsx("p", { className: 'text-body-2 font-medium text-ink sm:text-body-1', children: isDragging ? text.dropActive : dropLabel }), _jsx("p", { className: 'mt-1 text-body-3 text-ink/60 sm:text-body-2', children: text.browse }), maxSizeLabel ? _jsx("p", { className: 'mt-3 text-body-3 text-ink/60', children: maxSizeLabel }) : null, _jsxs("p", { className: 'text-body-3 text-ink/60', children: [text.formats, " ", acceptLabel] })] })] }), _jsx("input", { accept: acceptAttr, "aria-disabled": disabled, "aria-label": dropLabel, className: 'absolute inset-0 h-full w-full cursor-pointer opacity-0', disabled: disabled, multiple: multiple, onChange: onChange, type: 'file' })] }));
|
|
44
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
+
export const PsFileViewerButton = ({ children, className, disabled, label, onClick, tone = 'default', }) => (_jsx("button", { "aria-label": label, className: PallasoftClassNameService.merge('ps-focus-ring inline-flex h-9 min-w-9 shrink-0 items-center justify-center gap-1.5 rounded-full px-2 text-sm text-white/80 transition hover:bg-white/15 hover:text-white disabled:pointer-events-none disabled:opacity-40', tone === 'danger' ? 'hover:bg-danger/80' : '', className), disabled: disabled, onClick: onClick, title: label, type: 'button', children: children }));
|