@pallasoft/ps-file-components 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ps-file-icon-button.js +2 -2
- package/dist/components/ps-file-picker.d.ts +2 -1
- package/dist/components/ps-file-picker.js +3 -3
- package/dist/components/ps-file-viewer-button.js +1 -1
- package/dist/components/ps-file-viewer.js +2 -2
- package/dist/components/ps-unsupported-viewer.js +1 -1
- package/dist/components/ps-upload-row.js +1 -1
- package/dist/constants/ps-file-picker-labels.d.ts +1 -0
- package/dist/constants/ps-file-picker-labels.js +1 -0
- package/dist/esm/components/ps-file-icon-button.js +2 -2
- package/dist/esm/components/ps-file-picker.js +4 -4
- package/dist/esm/components/ps-file-viewer-button.js +1 -1
- package/dist/esm/components/ps-file-viewer.js +2 -2
- package/dist/esm/components/ps-unsupported-viewer.js +1 -1
- package/dist/esm/components/ps-upload-row.js +1 -1
- package/dist/esm/constants/ps-file-picker-labels.js +1 -0
- package/package.json +2 -2
|
@@ -6,8 +6,8 @@ const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
|
6
6
|
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
7
7
|
const ps_file_icon_button_classes_1 = require("../constants/ps-file-icon-button-classes");
|
|
8
8
|
const PsFileIconButton = ({ disabled = false, download, href, iconKey, label, onClick, tone = 'neutral', }) => {
|
|
9
|
-
const className = ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring
|
|
10
|
-
const icon = (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: '
|
|
9
|
+
const className = ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring ps-control-square ps-control-compact inline-flex shrink-0 items-center justify-center rounded-ps-control text-ink/55 transition disabled:pointer-events-none disabled:opacity-40', ps_file_icon_button_classes_1.PsFileIconButtonClasses[tone]);
|
|
10
|
+
const icon = ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: iconKey }));
|
|
11
11
|
return href === undefined ? ((0, jsx_runtime_1.jsx)("button", { "aria-label": label, className: className, disabled: disabled, onClick: onClick, title: label, type: 'button', children: icon })) : ((0, jsx_runtime_1.jsx)("a", { "aria-label": label, className: className, download: download, href: href, title: label, children: icon }));
|
|
12
12
|
};
|
|
13
13
|
exports.PsFileIconButton = PsFileIconButton;
|
|
@@ -11,8 +11,9 @@ export interface PsFilePickerProps {
|
|
|
11
11
|
maxSizeBytes?: number;
|
|
12
12
|
maxSizeLabel?: string;
|
|
13
13
|
multiple?: boolean;
|
|
14
|
+
touchLabel?: string;
|
|
14
15
|
onError?: (message: string) => void;
|
|
15
16
|
onFileLoad?: (file: File) => void;
|
|
16
17
|
onFilesSelect?: (files: File[]) => void;
|
|
17
18
|
}
|
|
18
|
-
export declare const PsFilePicker: ({ accept, acceptLabel, className, disabled, dropLabel, isLoading, labels, maxSizeBytes, maxSizeLabel, multiple, onError, onFileLoad, onFilesSelect, }: PsFilePickerProps) => import("react").JSX.Element;
|
|
19
|
+
export declare const PsFilePicker: ({ accept, acceptLabel, className, disabled, dropLabel, isLoading, labels, maxSizeBytes, maxSizeLabel, multiple, onError, onFileLoad, onFilesSelect, touchLabel, }: PsFilePickerProps) => import("react").JSX.Element;
|
|
@@ -7,7 +7,7 @@ const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
|
7
7
|
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
8
8
|
const ps_file_picker_labels_1 = require("../constants/ps-file-picker-labels");
|
|
9
9
|
const ps_file_selection_service_1 = require("../services/ps-file-selection-service");
|
|
10
|
-
const PsFilePicker = ({ accept, acceptLabel, className, disabled = false, dropLabel, isLoading = false, labels, maxSizeBytes, maxSizeLabel, multiple = false, onError, onFileLoad, onFilesSelect, }) => {
|
|
10
|
+
const PsFilePicker = ({ accept, acceptLabel, className, disabled = false, dropLabel, isLoading = false, labels, maxSizeBytes, maxSizeLabel, multiple = false, onError, onFileLoad, onFilesSelect, touchLabel, }) => {
|
|
11
11
|
const [isDragging, setIsDragging] = (0, react_1.useState)(false);
|
|
12
12
|
const acceptAttr = (0, react_1.useMemo)(() => accept.join(','), [accept]);
|
|
13
13
|
const text = { ...ps_file_picker_labels_1.PsFilePickerLabels, ...labels };
|
|
@@ -40,9 +40,9 @@ const PsFilePicker = ({ accept, acceptLabel, className, disabled = false, dropLa
|
|
|
40
40
|
if (!disabled)
|
|
41
41
|
setIsDragging(isOver);
|
|
42
42
|
};
|
|
43
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-
|
|
43
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-ps-control 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) => {
|
|
44
44
|
onDrag(event, false);
|
|
45
45
|
select(event.dataTransfer.files);
|
|
46
|
-
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'pointer-events-none flex flex-col items-center gap-3 text-center', children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { className: 'h-8 w-8 text-primary', iconKey: ps_icons_1.PsIconKey.Upload }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-body-2 font-medium text-ink sm:text-body-1', children: isDragging ? text.dropActive : dropLabel }), (0, jsx_runtime_1.jsx)("p", { className: 'mt-1 text-body-3 text-ink/60 sm:text-body-2', children: text.browse }), maxSizeLabel ? (0, jsx_runtime_1.jsx)("p", { className: 'mt-3 text-body-3 text-ink/60', children: maxSizeLabel }) : null, (0, jsx_runtime_1.jsxs)("p", { className: 'text-body-3 text-ink/60', children: [text.formats, " ", acceptLabel] })] })] }), (0, jsx_runtime_1.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' })] }));
|
|
46
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'pointer-events-none flex flex-col items-center gap-3 text-center', children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { className: 'h-8 w-8 text-primary', iconKey: ps_icons_1.PsIconKey.Upload }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-body-2 font-medium text-ink sm:text-body-1', children: isDragging ? (text.dropActive) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: touchLabel === undefined ? '' : '[@media(pointer:coarse)]:hidden', children: dropLabel }), touchLabel === undefined ? null : ((0, jsx_runtime_1.jsx)("span", { className: 'hidden [@media(pointer:coarse)]:inline', children: touchLabel }))] })) }), (0, jsx_runtime_1.jsxs)("p", { className: 'mt-1 text-body-3 text-ink/60 sm:text-body-2', children: [(0, jsx_runtime_1.jsx)("span", { className: '[@media(pointer:coarse)]:hidden', children: text.browse }), (0, jsx_runtime_1.jsx)("span", { className: 'hidden [@media(pointer:coarse)]:inline', children: text.browseTouch })] }), maxSizeLabel ? (0, jsx_runtime_1.jsx)("p", { className: 'mt-3 text-body-3 text-ink/60', children: maxSizeLabel }) : null, (0, jsx_runtime_1.jsxs)("p", { className: 'text-body-3 text-ink/60', children: [text.formats, " ", acceptLabel] })] })] }), (0, jsx_runtime_1.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' })] }));
|
|
47
47
|
};
|
|
48
48
|
exports.PsFilePicker = PsFilePicker;
|
|
@@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PsFileViewerButton = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
6
|
-
const PsFileViewerButton = ({ children, className, disabled, label, onClick, tone = 'default', }) => ((0, jsx_runtime_1.jsx)("button", { "aria-label": label, className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring inline-flex
|
|
6
|
+
const PsFileViewerButton = ({ children, className, disabled, label, onClick, tone = 'default', }) => ((0, jsx_runtime_1.jsx)("button", { "aria-label": label, className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring ps-control-compact inline-flex min-w-ps-control-compact shrink-0 items-center justify-center gap-1.5 rounded-ps-control 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 }));
|
|
7
7
|
exports.PsFileViewerButton = PsFileViewerButton;
|
|
@@ -94,9 +94,9 @@ const PsFileViewer = ({ files, index, isOpen, labels, onClose, onDelete, onIndex
|
|
|
94
94
|
file.sizeBytes === undefined ? null : ps_file_size_service_1.PsFileSizeService.format(file.sizeBytes),
|
|
95
95
|
]
|
|
96
96
|
.filter((value) => value !== null)
|
|
97
|
-
.join(' · ') })] }) }), canSearch ? ((0, jsx_runtime_1.jsxs)("div", { className: 'order-last flex w-full items-center gap-1 rounded-
|
|
97
|
+
.join(' · ') })] }) }), canSearch ? ((0, jsx_runtime_1.jsxs)("div", { className: 'order-last flex w-full items-center gap-1 rounded-ps-control bg-white/10 px-3 sm:order-none sm:w-72', children: [(0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'h-4 w-4 shrink-0 text-white/60', iconKey: ps_icons_1.PsIconKey.Search }), (0, jsx_runtime_1.jsx)("input", { "aria-label": text.search, className: 'h-ps-control-compact min-w-0 flex-1 bg-transparent text-sm text-white placeholder:text-white/45 focus:outline-none', onChange: (event) => setSearch(event.target.value), onKeyDown: (event) => {
|
|
98
98
|
if (event.key === 'Enter')
|
|
99
99
|
stepMatch(event.shiftKey ? -1 : 1);
|
|
100
|
-
}, placeholder: text.search, ref: searchInput, type: 'search', value: search }), query.trim().length > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: 'shrink-0 text-xs text-white/60', children: matchCount === 0 ? text.noMatches : `${activeMatch + 1} / ${matchCount}` })) : null, (0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { disabled: matchCount === 0, label: text.previousMatch, onClick: () => stepMatch(-1), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: '
|
|
100
|
+
}, placeholder: text.search, ref: searchInput, type: 'search', value: search }), query.trim().length > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: 'shrink-0 text-xs text-white/60', children: matchCount === 0 ? text.noMatches : `${activeMatch + 1} / ${matchCount}` })) : null, (0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { disabled: matchCount === 0, label: text.previousMatch, onClick: () => stepMatch(-1), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone -rotate-90', iconKey: ps_icons_1.PsIconKey.ChevronRight }) }), (0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { disabled: matchCount === 0, label: text.nextMatch, onClick: () => stepMatch(1), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone rotate-90', iconKey: ps_icons_1.PsIconKey.ChevronRight }) })] })) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center gap-0.5', children: [canZoom ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { label: text.zoomOut, onClick: () => changeZoom(-ps_file_viewer_config_1.PsFileViewerConfig.zoomStep), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.ZoomOut }) }), (0, jsx_runtime_1.jsxs)(ps_file_viewer_button_1.PsFileViewerButton, { className: 'w-14 text-xs', label: text.zoomReset, onClick: () => setZoom(1), children: [Math.round(zoom * 100), "%"] }), (0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { label: text.zoomIn, onClick: () => changeZoom(ps_file_viewer_config_1.PsFileViewerConfig.zoomStep), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.ZoomIn }) })] })) : null, canRotate ? ((0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { label: text.rotate, onClick: () => setRotation((current) => (current + ps_file_viewer_config_1.PsFileViewerConfig.rotateStep) % 360), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.Rotate }) })) : null, (0, jsx_runtime_1.jsx)("a", { "aria-label": text.download, className: 'ps-focus-ring ps-control-square ps-control-compact inline-flex items-center justify-center rounded-ps-control text-white/80 transition hover:bg-white/15 hover:text-white', download: file.name, href: file.downloadUrl === undefined ? file.url : file.downloadUrl, title: text.download, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.Download }) }), onDelete ? ((0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { label: text.delete, onClick: () => setIsConfirming(true), tone: 'danger', children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.Trash }) })) : null, (0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { label: text.close, onClick: onClose, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.Close }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'relative flex min-h-0 flex-1', children: [files.length > 1 ? ((0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { className: 'absolute left-2 top-1/2 z-docked size-ps-control -translate-y-1/2 bg-black/40', label: text.previous, onClick: () => go(-1), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone rotate-180', iconKey: ps_icons_1.PsIconKey.ChevronRight }) })) : null, (0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-0 min-w-0 flex-1 p-3 sm:p-6', children: (0, jsx_runtime_1.jsx)(ps_file_viewer_content_1.PsFileViewerContent, { activeMatch: activeMatch, file: file, labels: text, onMatchCount: setMatchCount, pdfWorkerSrc: pdfWorkerSrc, query: canSearch ? query : '', rotation: rotation, zoom: zoom }, file.id) }), files.length > 1 ? ((0, jsx_runtime_1.jsx)(ps_file_viewer_button_1.PsFileViewerButton, { className: 'absolute right-2 top-1/2 z-docked size-ps-control -translate-y-1/2 bg-black/40', label: text.next, onClick: () => go(1), children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: ps_icons_1.PsIconKey.ChevronRight }) })) : null] }), (0, jsx_runtime_1.jsx)(ps_file_delete_confirm_1.PsFileDeleteConfirm, { fileName: file.name, isDeleting: isDeleting, isOpen: isConfirming, labels: text, onCancel: () => setIsConfirming(false), onConfirm: () => void confirmDelete() })] }) }), document.body);
|
|
101
101
|
};
|
|
102
102
|
exports.PsFileViewer = PsFileViewer;
|
|
@@ -4,5 +4,5 @@ exports.PsUnsupportedViewer = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
6
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-
|
|
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 ps-control ps-control-padding inline-flex items-center gap-2 rounded-ps-control bg-primary 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
8
|
exports.PsUnsupportedViewer = PsUnsupportedViewer;
|
|
@@ -19,6 +19,6 @@ const PsUploadRow = ({ item, labels, onCancel, onRemove, onRetry }) => {
|
|
|
19
19
|
: item.status === ps_upload_status_1.PsUploadStatus.failed && item.error
|
|
20
20
|
? item.error
|
|
21
21
|
: labels[item.status];
|
|
22
|
-
return ((0, jsx_runtime_1.jsxs)("li", { className: 'flex items-center gap-3 rounded-ps-control border border-line px-3 py-2.5', children: [(0, jsx_runtime_1.jsx)(ps_file_kind_icon_1.PsFileKindIcon, { contentType: item.file.type, name: item.file.name }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 flex-col gap-1.5', children: [(0, jsx_runtime_1.jsx)("p", { className: 'truncate text-sm font-medium text-ink', children: item.file.name }), (0, jsx_runtime_1.jsx)(ps_progress_bar_1.PsProgressBar, { label: item.file.name, tone: ps_upload_status_tones_1.PsUploadStatusTones[item.status], value: isProblem ? 1 : item.progress }), (0, jsx_runtime_1.jsxs)("p", { className: `truncate text-xs ${isProblem ? 'text-danger' : item.status === ps_upload_status_1.PsUploadStatus.done ? 'text-success' : 'text-ink/55'}`, role: item.status === ps_upload_status_1.PsUploadStatus.failed ? 'alert' : undefined, children: [size, " \u00B7 ", status] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex w-16 shrink-0 items-center justify-end gap-0.5', children: [isProblem ? ((0, jsx_runtime_1.jsx)(ps_file_icon_button_1.PsFileIconButton, { iconKey: ps_icons_1.PsIconKey.Refresh, label: `${labels.retry} ${item.file.name}`, onClick: onRetry })) : null, isActive ? ((0, jsx_runtime_1.jsx)(ps_file_icon_button_1.PsFileIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: `${labels.cancel} ${item.file.name}`, onClick: onCancel, tone: 'danger' })) : item.status === ps_upload_status_1.PsUploadStatus.done ? ((0, jsx_runtime_1.jsx)("span", { className: '
|
|
22
|
+
return ((0, jsx_runtime_1.jsxs)("li", { className: 'flex items-center gap-3 rounded-ps-control border border-line px-3 py-2.5', children: [(0, jsx_runtime_1.jsx)(ps_file_kind_icon_1.PsFileKindIcon, { contentType: item.file.type, name: item.file.name }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 flex-col gap-1.5', children: [(0, jsx_runtime_1.jsx)("p", { className: 'truncate text-sm font-medium text-ink', children: item.file.name }), (0, jsx_runtime_1.jsx)(ps_progress_bar_1.PsProgressBar, { label: item.file.name, tone: ps_upload_status_tones_1.PsUploadStatusTones[item.status], value: isProblem ? 1 : item.progress }), (0, jsx_runtime_1.jsxs)("p", { className: `truncate text-xs ${isProblem ? 'text-danger' : item.status === ps_upload_status_1.PsUploadStatus.done ? 'text-success' : 'text-ink/55'}`, role: item.status === ps_upload_status_1.PsUploadStatus.failed ? 'alert' : undefined, children: [size, " \u00B7 ", status] })] }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex w-16 shrink-0 items-center justify-end gap-0.5', children: [isProblem ? ((0, jsx_runtime_1.jsx)(ps_file_icon_button_1.PsFileIconButton, { iconKey: ps_icons_1.PsIconKey.Refresh, label: `${labels.retry} ${item.file.name}`, onClick: onRetry })) : null, isActive ? ((0, jsx_runtime_1.jsx)(ps_file_icon_button_1.PsFileIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: `${labels.cancel} ${item.file.name}`, onClick: onCancel, tone: 'danger' })) : item.status === ps_upload_status_1.PsUploadStatus.done ? ((0, jsx_runtime_1.jsx)("span", { className: 'ps-control-square ps-control-compact inline-flex items-center justify-center text-success', children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-label": labels.done, className: 'h-4 w-4', iconKey: ps_icons_1.PsIconKey.Check }) })) : ((0, jsx_runtime_1.jsx)(ps_file_icon_button_1.PsFileIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: `${labels.remove} ${item.file.name}`, onClick: onRemove }))] })] }));
|
|
23
23
|
};
|
|
24
24
|
exports.PsUploadRow = PsUploadRow;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const PsFilePickerLabels: {
|
|
2
2
|
readonly browse: "or click to browse your files";
|
|
3
|
+
readonly browseTouch: "or tap to choose from your device";
|
|
3
4
|
readonly dropActive: "Drop to upload";
|
|
4
5
|
readonly formats: "Accepted formats:";
|
|
5
6
|
readonly invalidType: "is not a supported file type.";
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PsFilePickerLabels = void 0;
|
|
4
4
|
exports.PsFilePickerLabels = {
|
|
5
5
|
browse: 'or click to browse your files',
|
|
6
|
+
browseTouch: 'or tap to choose from your device',
|
|
6
7
|
dropActive: 'Drop to upload',
|
|
7
8
|
formats: 'Accepted formats:',
|
|
8
9
|
invalidType: 'is not a supported file type.',
|
|
@@ -3,7 +3,7 @@ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
|
3
3
|
import { PsIcon } from '@pallasoft/ps-icons';
|
|
4
4
|
import { PsFileIconButtonClasses } from '../constants/ps-file-icon-button-classes';
|
|
5
5
|
export const PsFileIconButton = ({ disabled = false, download, href, iconKey, label, onClick, tone = 'neutral', }) => {
|
|
6
|
-
const className = PallasoftClassNameService.merge('ps-focus-ring
|
|
7
|
-
const icon = _jsx(PsIcon, { "aria-hidden": 'true', className: '
|
|
6
|
+
const className = PallasoftClassNameService.merge('ps-focus-ring ps-control-square ps-control-compact inline-flex shrink-0 items-center justify-center rounded-ps-control text-ink/55 transition disabled:pointer-events-none disabled:opacity-40', PsFileIconButtonClasses[tone]);
|
|
7
|
+
const icon = (_jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: iconKey }));
|
|
8
8
|
return href === undefined ? (_jsx("button", { "aria-label": label, className: className, disabled: disabled, onClick: onClick, title: label, type: 'button', children: icon })) : (_jsx("a", { "aria-label": label, className: className, download: download, href: href, title: label, children: icon }));
|
|
9
9
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState } from 'react';
|
|
3
3
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
4
4
|
import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
|
|
5
5
|
import { PsFilePickerLabels } from '../constants/ps-file-picker-labels';
|
|
6
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, }) => {
|
|
7
|
+
export const PsFilePicker = ({ accept, acceptLabel, className, disabled = false, dropLabel, isLoading = false, labels, maxSizeBytes, maxSizeLabel, multiple = false, onError, onFileLoad, onFilesSelect, touchLabel, }) => {
|
|
8
8
|
const [isDragging, setIsDragging] = useState(false);
|
|
9
9
|
const acceptAttr = useMemo(() => accept.join(','), [accept]);
|
|
10
10
|
const text = { ...PsFilePickerLabels, ...labels };
|
|
@@ -37,8 +37,8 @@ export const PsFilePicker = ({ accept, acceptLabel, className, disabled = false,
|
|
|
37
37
|
if (!disabled)
|
|
38
38
|
setIsDragging(isOver);
|
|
39
39
|
};
|
|
40
|
-
return (_jsxs("div", { className: PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-
|
|
40
|
+
return (_jsxs("div", { className: PallasoftClassNameService.merge('relative flex h-48 w-full flex-col items-center justify-center rounded-ps-control 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
41
|
onDrag(event, false);
|
|
42
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' })] }));
|
|
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) : (_jsxs(_Fragment, { children: [_jsx("span", { className: touchLabel === undefined ? '' : '[@media(pointer:coarse)]:hidden', children: dropLabel }), touchLabel === undefined ? null : (_jsx("span", { className: 'hidden [@media(pointer:coarse)]:inline', children: touchLabel }))] })) }), _jsxs("p", { className: 'mt-1 text-body-3 text-ink/60 sm:text-body-2', children: [_jsx("span", { className: '[@media(pointer:coarse)]:hidden', children: text.browse }), _jsx("span", { className: 'hidden [@media(pointer:coarse)]:inline', children: text.browseTouch })] }), 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
44
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
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
|
|
3
|
+
export const PsFileViewerButton = ({ children, className, disabled, label, onClick, tone = 'default', }) => (_jsx("button", { "aria-label": label, className: PallasoftClassNameService.merge('ps-focus-ring ps-control-compact inline-flex min-w-ps-control-compact shrink-0 items-center justify-center gap-1.5 rounded-ps-control 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 }));
|
|
@@ -91,8 +91,8 @@ export const PsFileViewer = ({ files, index, isOpen, labels, onClose, onDelete,
|
|
|
91
91
|
file.sizeBytes === undefined ? null : PsFileSizeService.format(file.sizeBytes),
|
|
92
92
|
]
|
|
93
93
|
.filter((value) => value !== null)
|
|
94
|
-
.join(' · ') })] }) }), canSearch ? (_jsxs("div", { className: 'order-last flex w-full items-center gap-1 rounded-
|
|
94
|
+
.join(' · ') })] }) }), canSearch ? (_jsxs("div", { className: 'order-last flex w-full items-center gap-1 rounded-ps-control bg-white/10 px-3 sm:order-none sm:w-72', children: [_jsx(PsIcon, { "aria-hidden": 'true', className: 'h-4 w-4 shrink-0 text-white/60', iconKey: PsIconKey.Search }), _jsx("input", { "aria-label": text.search, className: 'h-ps-control-compact min-w-0 flex-1 bg-transparent text-sm text-white placeholder:text-white/45 focus:outline-none', onChange: (event) => setSearch(event.target.value), onKeyDown: (event) => {
|
|
95
95
|
if (event.key === 'Enter')
|
|
96
96
|
stepMatch(event.shiftKey ? -1 : 1);
|
|
97
|
-
}, placeholder: text.search, ref: searchInput, type: 'search', value: search }), query.trim().length > 0 ? (_jsx("span", { className: 'shrink-0 text-xs text-white/60', children: matchCount === 0 ? text.noMatches : `${activeMatch + 1} / ${matchCount}` })) : null, _jsx(PsFileViewerButton, { disabled: matchCount === 0, label: text.previousMatch, onClick: () => stepMatch(-1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: '
|
|
97
|
+
}, placeholder: text.search, ref: searchInput, type: 'search', value: search }), query.trim().length > 0 ? (_jsx("span", { className: 'shrink-0 text-xs text-white/60', children: matchCount === 0 ? text.noMatches : `${activeMatch + 1} / ${matchCount}` })) : null, _jsx(PsFileViewerButton, { disabled: matchCount === 0, label: text.previousMatch, onClick: () => stepMatch(-1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone -rotate-90', iconKey: PsIconKey.ChevronRight }) }), _jsx(PsFileViewerButton, { disabled: matchCount === 0, label: text.nextMatch, onClick: () => stepMatch(1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone rotate-90', iconKey: PsIconKey.ChevronRight }) })] })) : null, _jsxs("div", { className: 'flex items-center gap-0.5', children: [canZoom ? (_jsxs(_Fragment, { children: [_jsx(PsFileViewerButton, { label: text.zoomOut, onClick: () => changeZoom(-PsFileViewerConfig.zoomStep), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.ZoomOut }) }), _jsxs(PsFileViewerButton, { className: 'w-14 text-xs', label: text.zoomReset, onClick: () => setZoom(1), children: [Math.round(zoom * 100), "%"] }), _jsx(PsFileViewerButton, { label: text.zoomIn, onClick: () => changeZoom(PsFileViewerConfig.zoomStep), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.ZoomIn }) })] })) : null, canRotate ? (_jsx(PsFileViewerButton, { label: text.rotate, onClick: () => setRotation((current) => (current + PsFileViewerConfig.rotateStep) % 360), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.Rotate }) })) : null, _jsx("a", { "aria-label": text.download, className: 'ps-focus-ring ps-control-square ps-control-compact inline-flex items-center justify-center rounded-ps-control text-white/80 transition hover:bg-white/15 hover:text-white', download: file.name, href: file.downloadUrl === undefined ? file.url : file.downloadUrl, title: text.download, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.Download }) }), onDelete ? (_jsx(PsFileViewerButton, { label: text.delete, onClick: () => setIsConfirming(true), tone: 'danger', children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.Trash }) })) : null, _jsx(PsFileViewerButton, { label: text.close, onClick: onClose, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.Close }) })] })] }), _jsxs("div", { className: 'relative flex min-h-0 flex-1', children: [files.length > 1 ? (_jsx(PsFileViewerButton, { className: 'absolute left-2 top-1/2 z-docked size-ps-control -translate-y-1/2 bg-black/40', label: text.previous, onClick: () => go(-1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone rotate-180', iconKey: PsIconKey.ChevronRight }) })) : null, _jsx("div", { className: 'flex min-h-0 min-w-0 flex-1 p-3 sm:p-6', children: _jsx(PsFileViewerContent, { activeMatch: activeMatch, file: file, labels: text, onMatchCount: setMatchCount, pdfWorkerSrc: pdfWorkerSrc, query: canSearch ? query : '', rotation: rotation, zoom: zoom }, file.id) }), files.length > 1 ? (_jsx(PsFileViewerButton, { className: 'absolute right-2 top-1/2 z-docked size-ps-control -translate-y-1/2 bg-black/40', label: text.next, onClick: () => go(1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-ps-control-icon-standalone', iconKey: PsIconKey.ChevronRight }) })) : null] }), _jsx(PsFileDeleteConfirm, { fileName: file.name, isDeleting: isDeleting, isOpen: isConfirming, labels: text, onCancel: () => setIsConfirming(false), onConfirm: () => void confirmDelete() })] }) }), document.body);
|
|
98
98
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
|
|
3
3
|
import { PsFileKindIcon } from './ps-file-kind-icon';
|
|
4
|
-
export const PsUnsupportedViewer = ({ file, labels }) => (_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: [_jsx(PsFileKindIcon, { className: 'h-14 w-14', contentType: file.contentType, name: file.name }), _jsx("p", { className: 'break-all font-semibold text-ink', children: file.name }), _jsx("p", { className: 'text-sm text-ink/60', children: labels.unsupported }), _jsxs("a", { className: 'ps-focus-ring inline-flex items-center gap-2 rounded-
|
|
4
|
+
export const PsUnsupportedViewer = ({ file, labels }) => (_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: [_jsx(PsFileKindIcon, { className: 'h-14 w-14', contentType: file.contentType, name: file.name }), _jsx("p", { className: 'break-all font-semibold text-ink', children: file.name }), _jsx("p", { className: 'text-sm text-ink/60', children: labels.unsupported }), _jsxs("a", { className: 'ps-focus-ring ps-control ps-control-padding inline-flex items-center gap-2 rounded-ps-control bg-primary text-sm font-semibold text-white hover:bg-primary/90', 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 }), labels.download] })] }));
|
|
@@ -16,5 +16,5 @@ export const PsUploadRow = ({ item, labels, onCancel, onRemove, onRetry }) => {
|
|
|
16
16
|
: item.status === PsUploadStatus.failed && item.error
|
|
17
17
|
? item.error
|
|
18
18
|
: labels[item.status];
|
|
19
|
-
return (_jsxs("li", { className: 'flex items-center gap-3 rounded-ps-control border border-line px-3 py-2.5', children: [_jsx(PsFileKindIcon, { contentType: item.file.type, name: item.file.name }), _jsxs("div", { className: 'flex min-w-0 flex-1 flex-col gap-1.5', children: [_jsx("p", { className: 'truncate text-sm font-medium text-ink', children: item.file.name }), _jsx(PsProgressBar, { label: item.file.name, tone: PsUploadStatusTones[item.status], value: isProblem ? 1 : item.progress }), _jsxs("p", { className: `truncate text-xs ${isProblem ? 'text-danger' : item.status === PsUploadStatus.done ? 'text-success' : 'text-ink/55'}`, role: item.status === PsUploadStatus.failed ? 'alert' : undefined, children: [size, " \u00B7 ", status] })] }), _jsxs("div", { className: 'flex w-16 shrink-0 items-center justify-end gap-0.5', children: [isProblem ? (_jsx(PsFileIconButton, { iconKey: PsIconKey.Refresh, label: `${labels.retry} ${item.file.name}`, onClick: onRetry })) : null, isActive ? (_jsx(PsFileIconButton, { iconKey: PsIconKey.Close, label: `${labels.cancel} ${item.file.name}`, onClick: onCancel, tone: 'danger' })) : item.status === PsUploadStatus.done ? (_jsx("span", { className: '
|
|
19
|
+
return (_jsxs("li", { className: 'flex items-center gap-3 rounded-ps-control border border-line px-3 py-2.5', children: [_jsx(PsFileKindIcon, { contentType: item.file.type, name: item.file.name }), _jsxs("div", { className: 'flex min-w-0 flex-1 flex-col gap-1.5', children: [_jsx("p", { className: 'truncate text-sm font-medium text-ink', children: item.file.name }), _jsx(PsProgressBar, { label: item.file.name, tone: PsUploadStatusTones[item.status], value: isProblem ? 1 : item.progress }), _jsxs("p", { className: `truncate text-xs ${isProblem ? 'text-danger' : item.status === PsUploadStatus.done ? 'text-success' : 'text-ink/55'}`, role: item.status === PsUploadStatus.failed ? 'alert' : undefined, children: [size, " \u00B7 ", status] })] }), _jsxs("div", { className: 'flex w-16 shrink-0 items-center justify-end gap-0.5', children: [isProblem ? (_jsx(PsFileIconButton, { iconKey: PsIconKey.Refresh, label: `${labels.retry} ${item.file.name}`, onClick: onRetry })) : null, isActive ? (_jsx(PsFileIconButton, { iconKey: PsIconKey.Close, label: `${labels.cancel} ${item.file.name}`, onClick: onCancel, tone: 'danger' })) : item.status === PsUploadStatus.done ? (_jsx("span", { className: 'ps-control-square ps-control-compact inline-flex items-center justify-center text-success', children: _jsx(PsIcon, { "aria-label": labels.done, className: 'h-4 w-4', iconKey: PsIconKey.Check }) })) : (_jsx(PsFileIconButton, { iconKey: PsIconKey.Close, label: `${labels.remove} ${item.file.name}`, onClick: onRemove }))] })] }));
|
|
20
20
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pallasoft/ps-file-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@pallasoft/ps-core-components": "^2.13.0",
|
|
36
|
-
"@pallasoft/ps-design-system": "^1.7.0",
|
|
37
36
|
"@pallasoft/ps-icons": "^1.6.0",
|
|
38
37
|
"@pallasoft/ps-popovers": "^1.5.2",
|
|
39
38
|
"@pallasoft/ps-utilities": "^2.9.0",
|
|
@@ -48,6 +47,7 @@
|
|
|
48
47
|
"@commitlint/config-conventional": "^20.0.0",
|
|
49
48
|
"@eslint/compat": "^2.0.0",
|
|
50
49
|
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
|
50
|
+
"@pallasoft/ps-design-system": "^1.14.0",
|
|
51
51
|
"@semantic-release/changelog": "^6.0.3",
|
|
52
52
|
"@semantic-release/commit-analyzer": "^13.0.0",
|
|
53
53
|
"@semantic-release/git": "^10.0.1",
|