@j2-health/design-system 0.6.4 → 0.6.6
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/_virtual/_rolldown/runtime.cjs +1 -2
- package/dist/index.cjs +12 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -3
- package/dist/index2.js +8 -3
- package/dist/src/AppConfigProvider.cjs +1 -2
- package/dist/src/AppConfigProvider.js +1 -2
- package/dist/src/appTheme.cjs +8 -2
- package/dist/src/appTheme.cjs.map +1 -1
- package/dist/src/appTheme.js +8 -2
- package/dist/src/appTheme.js.map +1 -1
- package/dist/src/components/alert/Alert.cjs +1 -2
- package/dist/src/components/alert/Alert.js +1 -2
- package/dist/src/components/alert/Alert.module.css.cjs +1 -2
- package/dist/src/components/alert/Alert.module.css.js +1 -2
- package/dist/src/components/barchart/BarChart.cjs +1 -2
- package/dist/src/components/barchart/BarChart.js +1 -2
- package/dist/src/components/barchart/chart.module.css.cjs +1 -2
- package/dist/src/components/barchart/chart.module.css.js +1 -2
- package/dist/src/components/bareButton/BareButton.cjs +1 -2
- package/dist/src/components/bareButton/BareButton.js +1 -2
- package/dist/src/components/breadcrumb/Breadcrumb.cjs +1 -2
- package/dist/src/components/breadcrumb/Breadcrumb.js +1 -2
- package/dist/src/components/bulkActionBar/BulkActionBar.cjs +1 -2
- package/dist/src/components/bulkActionBar/BulkActionBar.js +1 -2
- package/dist/src/components/button/Button.cjs +1 -2
- package/dist/src/components/button/Button.js +1 -2
- package/dist/src/components/callout/Callout.cjs +35 -0
- package/dist/src/components/callout/Callout.cjs.map +1 -0
- package/dist/src/components/callout/Callout.d.ts +18 -0
- package/dist/src/components/callout/Callout.js +33 -0
- package/dist/src/components/callout/Callout.js.map +1 -0
- package/dist/src/components/callout/index.d.ts +1 -0
- package/dist/src/components/card/Card.cjs +1 -2
- package/dist/src/components/card/Card.js +1 -2
- package/dist/src/components/changeChip/ChangeChip.cjs +1 -2
- package/dist/src/components/changeChip/ChangeChip.js +1 -2
- package/dist/src/components/checkbox/Checkbox.cjs +1 -2
- package/dist/src/components/checkbox/Checkbox.js +1 -2
- package/dist/src/components/checkboxTree/CheckboxTree.cjs +1 -2
- package/dist/src/components/checkboxTree/CheckboxTree.js +1 -2
- package/dist/src/components/checkboxTree/TreeNode.cjs +1 -2
- package/dist/src/components/checkboxTree/TreeNode.js +1 -2
- package/dist/src/components/checkboxTree/utils.cjs +1 -2
- package/dist/src/components/checkboxTree/utils.js +1 -2
- package/dist/src/components/collapse/Collapse.cjs +1 -2
- package/dist/src/components/collapse/Collapse.js +1 -2
- package/dist/src/components/collapse/Collapse.module.css.cjs +1 -2
- package/dist/src/components/collapse/Collapse.module.css.js +1 -2
- package/dist/src/components/drawer/Drawer.cjs +1 -2
- package/dist/src/components/drawer/Drawer.js +1 -2
- package/dist/src/components/dropdown/Dropdown.cjs +1 -2
- package/dist/src/components/dropdown/Dropdown.js +1 -2
- package/dist/src/components/emptyState/EmptyState.cjs +1 -2
- package/dist/src/components/emptyState/EmptyState.js +1 -2
- package/dist/src/components/fileDropzone/FileDropzone.cjs +296 -0
- package/dist/src/components/fileDropzone/FileDropzone.cjs.map +1 -0
- package/dist/src/components/fileDropzone/FileDropzone.d.ts +68 -0
- package/dist/src/components/fileDropzone/FileDropzone.js +293 -0
- package/dist/src/components/fileDropzone/FileDropzone.js.map +1 -0
- package/dist/src/components/fileDropzone/index.d.ts +1 -0
- package/dist/src/components/filterform/FilterGroup.cjs +1 -2
- package/dist/src/components/filterform/FilterGroup.js +1 -2
- package/dist/src/components/filterform/FilterInput.cjs +1 -2
- package/dist/src/components/filterform/FilterInput.js +1 -2
- package/dist/src/components/filterform/FiltersForm.cjs +1 -2
- package/dist/src/components/filterform/FiltersForm.js +1 -2
- package/dist/src/components/filterform/FiltersForm.module.css.cjs +1 -2
- package/dist/src/components/filterform/FiltersForm.module.css.js +1 -2
- package/dist/src/components/filterform/filterHelpers.cjs +1 -2
- package/dist/src/components/filterform/filterHelpers.js +1 -2
- package/dist/src/components/filterform/useFilterField.cjs +1 -2
- package/dist/src/components/filterform/useFilterField.js +1 -2
- package/dist/src/components/filterform/useFiltersForm.cjs +1 -2
- package/dist/src/components/filterform/useFiltersForm.js +1 -2
- package/dist/src/components/form/Form.cjs +1 -2
- package/dist/src/components/form/Form.js +1 -2
- package/dist/src/components/form/FormItem.cjs +1 -2
- package/dist/src/components/form/FormItem.js +1 -2
- package/dist/src/components/form/FormItemFieldContext.cjs +1 -2
- package/dist/src/components/form/FormItemFieldContext.cjs.map +1 -1
- package/dist/src/components/form/FormItemFieldContext.js +1 -2
- package/dist/src/components/form/FormikField.cjs +1 -2
- package/dist/src/components/form/FormikField.js +1 -2
- package/dist/src/components/input/AntdInput.cjs +1 -2
- package/dist/src/components/input/AntdInput.d.ts +1 -1
- package/dist/src/components/input/AntdInput.js +1 -2
- package/dist/src/components/input/AntdSearchInput.cjs +1 -2
- package/dist/src/components/input/AntdSearchInput.d.ts +1 -1
- package/dist/src/components/input/AntdSearchInput.js +1 -2
- package/dist/src/components/input/AntdTextArea.cjs +15 -0
- package/dist/src/components/input/AntdTextArea.cjs.map +1 -0
- package/dist/src/components/input/AntdTextArea.d.ts +347 -0
- package/dist/src/components/input/AntdTextArea.js +15 -0
- package/dist/src/components/input/AntdTextArea.js.map +1 -0
- package/dist/src/components/input/Input.cjs +1 -2
- package/dist/src/components/input/Input.js +1 -2
- package/dist/src/components/input/index.d.ts +1 -0
- package/dist/src/components/inputnumber/InputNumber.cjs +1 -2
- package/dist/src/components/inputnumber/InputNumber.js +1 -2
- package/dist/src/components/inputnumber/InputNumber.module.css.cjs +1 -2
- package/dist/src/components/inputnumber/InputNumber.module.css.js +1 -2
- package/dist/src/components/legacyNavMenu/LegacyNavMenu.cjs +1 -2
- package/dist/src/components/legacyNavMenu/LegacyNavMenu.js +1 -2
- package/dist/src/components/legacyNavMenu/LegacyNavMenu.module.css.cjs +1 -2
- package/dist/src/components/legacyNavMenu/LegacyNavMenu.module.css.js +1 -2
- package/dist/src/components/legacyNavMenu/UserProfile.cjs +1 -2
- package/dist/src/components/legacyNavMenu/UserProfile.js +1 -2
- package/dist/src/components/legacyNavMenu/UserProfile.module.css.cjs +1 -2
- package/dist/src/components/legacyNavMenu/UserProfile.module.css.js +1 -2
- package/dist/src/components/listRow/ListRow.cjs +1 -2
- package/dist/src/components/listRow/ListRow.js +1 -2
- package/dist/src/components/listpopover/ListPopover.cjs +1 -2
- package/dist/src/components/listpopover/ListPopover.js +1 -2
- package/dist/src/components/listpopover/ListPopover.module.css.cjs +1 -2
- package/dist/src/components/listpopover/ListPopover.module.css.js +1 -2
- package/dist/src/components/manageColumns/ManageColumnsItem.cjs +1 -2
- package/dist/src/components/manageColumns/ManageColumnsItem.js +1 -2
- package/dist/src/components/manageColumns/ManageColumnsPanel.cjs +1 -2
- package/dist/src/components/manageColumns/ManageColumnsPanel.js +1 -2
- package/dist/src/components/manageColumns/SelectAll.cjs +1 -2
- package/dist/src/components/manageColumns/SelectAll.js +1 -2
- package/dist/src/components/menu/Menu.cjs +1 -2
- package/dist/src/components/menu/Menu.js +1 -2
- package/dist/src/components/menu/Menu.module.css.cjs +1 -2
- package/dist/src/components/menu/Menu.module.css.js +1 -2
- package/dist/src/components/message/Message.module.css.cjs +1 -2
- package/dist/src/components/message/Message.module.css.js +1 -2
- package/dist/src/components/message/useMessage.cjs +1 -2
- package/dist/src/components/message/useMessage.js +1 -2
- package/dist/src/components/modal/Modal.cjs +1 -2
- package/dist/src/components/modal/Modal.js +1 -2
- package/dist/src/components/navMenu/NavMenu.cjs +1 -2
- package/dist/src/components/navMenu/NavMenu.js +1 -2
- package/dist/src/components/navMenu/NavMenu.module.css.cjs +1 -2
- package/dist/src/components/navMenu/NavMenu.module.css.js +1 -2
- package/dist/src/components/notification/Notification.module.css.cjs +1 -2
- package/dist/src/components/notification/Notification.module.css.js +1 -2
- package/dist/src/components/notification/useNotification.cjs +1 -2
- package/dist/src/components/notification/useNotification.js +1 -2
- package/dist/src/components/notificationModal/NotifcationModal.module.css.cjs +1 -2
- package/dist/src/components/notificationModal/NotifcationModal.module.css.js +1 -2
- package/dist/src/components/notificationModal/NotificationModal.cjs +1 -2
- package/dist/src/components/notificationModal/NotificationModal.js +1 -2
- package/dist/src/components/pagination/Pagination.cjs +1 -2
- package/dist/src/components/pagination/Pagination.js +1 -2
- package/dist/src/components/pagination/Pagination.module.css.cjs +1 -2
- package/dist/src/components/pagination/Pagination.module.css.js +1 -2
- package/dist/src/components/popover/Popover.cjs +1 -2
- package/dist/src/components/popover/Popover.js +1 -2
- package/dist/src/components/popover/Popover.module.css.cjs +1 -2
- package/dist/src/components/popover/Popover.module.css.js +1 -2
- package/dist/src/components/progress/Progress.cjs +1 -2
- package/dist/src/components/progress/Progress.js +1 -2
- package/dist/src/components/radio/Radio.cjs +1 -2
- package/dist/src/components/radio/Radio.js +1 -2
- package/dist/src/components/radioCardGroup/RadioCardGroup.cjs +78 -0
- package/dist/src/components/radioCardGroup/RadioCardGroup.cjs.map +1 -0
- package/dist/src/components/radioCardGroup/RadioCardGroup.d.ts +26 -0
- package/dist/src/components/radioCardGroup/RadioCardGroup.js +76 -0
- package/dist/src/components/radioCardGroup/RadioCardGroup.js.map +1 -0
- package/dist/src/components/radioCardGroup/index.d.ts +1 -0
- package/dist/src/components/rate/Rate.cjs +1 -2
- package/dist/src/components/rate/Rate.js +1 -2
- package/dist/src/components/select/AntdSelect.cjs +1 -2
- package/dist/src/components/select/AntdSelect.js +1 -2
- package/dist/src/components/select/Select.cjs +1 -2
- package/dist/src/components/select/Select.js +1 -2
- package/dist/src/components/select/SummarizedSelect.cjs +1 -2
- package/dist/src/components/select/SummarizedSelect.js +1 -2
- package/dist/src/components/select/SummarizedSelect.module.css.cjs +1 -2
- package/dist/src/components/select/SummarizedSelect.module.css.js +1 -2
- package/dist/src/components/skeleton/Skeleton.cjs +1 -2
- package/dist/src/components/skeleton/Skeleton.js +1 -2
- package/dist/src/components/slider/Slider.cjs +21 -0
- package/dist/src/components/slider/Slider.cjs.map +1 -0
- package/dist/src/components/slider/Slider.d.ts +7 -0
- package/dist/src/components/slider/Slider.js +19 -0
- package/dist/src/components/slider/Slider.js.map +1 -0
- package/dist/src/components/slider/index.d.ts +1 -0
- package/dist/src/components/spinner/Spinner.cjs +1 -2
- package/dist/src/components/spinner/Spinner.js +1 -2
- package/dist/src/components/statusPill/StatusPill.cjs +1 -2
- package/dist/src/components/statusPill/StatusPill.js +1 -2
- package/dist/src/components/statusPill/StatusPill.module.css.cjs +1 -2
- package/dist/src/components/statusPill/StatusPill.module.css.js +1 -2
- package/dist/src/components/stepDrawer/StepDrawer.cjs +1 -2
- package/dist/src/components/stepDrawer/StepDrawer.js +1 -2
- package/dist/src/components/steps/Steps.cjs +1 -2
- package/dist/src/components/steps/Steps.js +1 -2
- package/dist/src/components/steps/useSteps.cjs +1 -2
- package/dist/src/components/steps/useSteps.js +1 -2
- package/dist/src/components/swatch/Swatch.cjs +1 -2
- package/dist/src/components/swatch/Swatch.js +1 -2
- package/dist/src/components/swatchStrip/SwatchStrip.cjs +1 -2
- package/dist/src/components/swatchStrip/SwatchStrip.js +1 -2
- package/dist/src/components/switch/Switch.cjs +1 -2
- package/dist/src/components/switch/Switch.js +1 -2
- package/dist/src/components/table/Table.cjs +2 -3
- package/dist/src/components/table/Table.js +2 -3
- package/dist/src/components/table/Table.module.css.cjs +1 -2
- package/dist/src/components/table/Table.module.css.js +1 -2
- package/dist/src/components/tabs/Tabs.cjs +1 -2
- package/dist/src/components/tabs/Tabs.js +1 -2
- package/dist/src/components/tabs/Tabs.module.css.cjs +1 -2
- package/dist/src/components/tabs/Tabs.module.css.js +1 -2
- package/dist/src/components/tag/Tag.cjs +1 -2
- package/dist/src/components/tag/Tag.js +1 -2
- package/dist/src/components/thresholdBar/ThresholdBar.cjs +1 -2
- package/dist/src/components/thresholdBar/ThresholdBar.js +1 -2
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.cjs +1 -2
- package/dist/src/components/thresholdBar/ThresholdBar.module.css.js +1 -2
- package/dist/src/components/tooltip/Tooltip.cjs +1 -2
- package/dist/src/components/tooltip/Tooltip.js +1 -2
- package/dist/src/components/vennDiagram/VennDiagram.cjs +1 -2
- package/dist/src/components/vennDiagram/VennDiagram.js +1 -2
- package/dist/src/svgs/ProgressCircle.svg.cjs +1 -2
- package/dist/src/svgs/ProgressCircle.svg.js +1 -2
- package/dist/src/svgs/j2-logo-menu-collapse.svg.cjs +1 -2
- package/dist/src/svgs/j2-logo-menu-collapse.svg.js +1 -2
- package/dist/src/svgs/j2-logo-menu.svg.cjs +1 -2
- package/dist/src/svgs/j2-logo-menu.svg.js +1 -2
- package/dist/src/svgs/menu-sidebar-collapse.svg.cjs +1 -2
- package/dist/src/svgs/menu-sidebar-collapse.svg.js +1 -2
- package/dist/src/svgs/menu-sidebar-expand.svg.cjs +1 -2
- package/dist/src/svgs/menu-sidebar-expand.svg.js +1 -2
- package/dist/src/utils/useRender.cjs +1 -2
- package/dist/src/utils/useRender.js +1 -2
- package/dist/style.css +78 -78
- package/dist/tailwind.cjs +1 -2
- package/dist/tailwind.js +1 -2
- package/package.json +13 -13
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
const require_runtime = require("../../../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_Button = require("../button/Button.cjs");
|
|
3
|
+
const require_Modal = require("../modal/Modal.cjs");
|
|
4
|
+
const require_Spinner = require("../spinner/Spinner.cjs");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
let _phosphor_icons_react = require("@phosphor-icons/react");
|
|
7
|
+
_phosphor_icons_react = require_runtime.__toESM(_phosphor_icons_react, 1);
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
let classnames = require("classnames");
|
|
10
|
+
classnames = require_runtime.__toESM(classnames, 1);
|
|
11
|
+
// src/components/fileDropzone/FileDropzone.tsx
|
|
12
|
+
function ViewIssuesButton({ onClick }) {
|
|
13
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Button.Button, {
|
|
14
|
+
type: "link",
|
|
15
|
+
size: "small",
|
|
16
|
+
className: "h-auto p-0 text-sm font-medium",
|
|
17
|
+
onClick: (event) => {
|
|
18
|
+
event.stopPropagation();
|
|
19
|
+
onClick?.();
|
|
20
|
+
},
|
|
21
|
+
children: "View & Fix Issues"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A file upload: an optional label, a full-width Download Template bar, and a
|
|
26
|
+
* dashed dropzone that shows the prompt, a spinner while the file is checked,
|
|
27
|
+
* or the uploaded file with a Replace link. Error and warning banners tuck
|
|
28
|
+
* under the dropzone. Click, keyboard or drag and drop all upload; with
|
|
29
|
+
* `replaceConfirm` set, replacing an existing file asks first.
|
|
30
|
+
*
|
|
31
|
+
* Presentational: the caller checks the file and passes the result back as
|
|
32
|
+
* `status` and the counts.
|
|
33
|
+
*/
|
|
34
|
+
function FileDropzone({ status, fileName, label, accept = ".csv", errorRowCount, warningRowCount, missingHeaders, templateUrl, onDownloadTemplate, uploadDisabled = false, onFileSelected, onViewIssues, errorMessage, replaceConfirm, hasExistingUpload = false, successExtra, handleRef, className }) {
|
|
35
|
+
const fileInputRef = (0, react.useRef)(null);
|
|
36
|
+
const [isDragOver, setIsDragOver] = (0, react.useState)(false);
|
|
37
|
+
const [dragError, setDragError] = (0, react.useState)(null);
|
|
38
|
+
const [confirmOpen, setConfirmOpen] = (0, react.useState)(false);
|
|
39
|
+
const pendingDropRef = (0, react.useRef)(null);
|
|
40
|
+
const isUploading = status === "validating";
|
|
41
|
+
const hasHeaderError = status === "header-error";
|
|
42
|
+
const hasRowErrors = status === "success-with-errors";
|
|
43
|
+
const hasRowWarnings = status === "success-with-warnings";
|
|
44
|
+
const isUploaded = status === "success" || hasRowErrors || hasRowWarnings;
|
|
45
|
+
const disabled = uploadDisabled || isUploading;
|
|
46
|
+
const acceptLabel = accept.replace(/^\./, "").toUpperCase();
|
|
47
|
+
const needsReplaceConfirm = Boolean(replaceConfirm) && (isUploaded || hasExistingUpload);
|
|
48
|
+
const handleFile = (0, react.useCallback)((file) => {
|
|
49
|
+
if (!file) return;
|
|
50
|
+
setDragError(null);
|
|
51
|
+
onFileSelected(file);
|
|
52
|
+
}, [onFileSelected]);
|
|
53
|
+
const handleFileChange = (event) => {
|
|
54
|
+
handleFile(event.target.files?.[0] ?? null);
|
|
55
|
+
event.target.value = "";
|
|
56
|
+
};
|
|
57
|
+
const openPicker = () => fileInputRef.current?.click();
|
|
58
|
+
const requestUpload = () => {
|
|
59
|
+
if (disabled) return;
|
|
60
|
+
if (needsReplaceConfirm) {
|
|
61
|
+
pendingDropRef.current = null;
|
|
62
|
+
setConfirmOpen(true);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
openPicker();
|
|
66
|
+
};
|
|
67
|
+
(0, react.useImperativeHandle)(handleRef, () => ({ requestUpload }));
|
|
68
|
+
const confirmReplace = () => {
|
|
69
|
+
setConfirmOpen(false);
|
|
70
|
+
const droppedFile = pendingDropRef.current;
|
|
71
|
+
pendingDropRef.current = null;
|
|
72
|
+
if (droppedFile) handleFile(droppedFile);
|
|
73
|
+
else openPicker();
|
|
74
|
+
};
|
|
75
|
+
const cancelReplace = () => {
|
|
76
|
+
pendingDropRef.current = null;
|
|
77
|
+
setConfirmOpen(false);
|
|
78
|
+
};
|
|
79
|
+
const handleDragOver = (event) => {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
event.stopPropagation();
|
|
82
|
+
if (!disabled) setIsDragOver(true);
|
|
83
|
+
};
|
|
84
|
+
const handleDragLeave = (event) => {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
event.stopPropagation();
|
|
87
|
+
setIsDragOver(false);
|
|
88
|
+
};
|
|
89
|
+
const handleDrop = (event) => {
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
event.stopPropagation();
|
|
92
|
+
setIsDragOver(false);
|
|
93
|
+
if (disabled) return;
|
|
94
|
+
const file = event.dataTransfer.files?.[0] ?? null;
|
|
95
|
+
if (!file) return;
|
|
96
|
+
if (!file.name.toLowerCase().endsWith(accept.toLowerCase())) {
|
|
97
|
+
setDragError(`Only ${acceptLabel} files are supported`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setDragError(null);
|
|
101
|
+
if (needsReplaceConfirm) {
|
|
102
|
+
pendingDropRef.current = file;
|
|
103
|
+
setConfirmOpen(true);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
handleFile(file);
|
|
107
|
+
};
|
|
108
|
+
const templateClass = (0, classnames.default)("mt-2 flex w-full items-center justify-center gap-2 rounded-j2 border-0 bg-j2-gray-3 px-4 py-1.5 text-sm text-j2-primary no-underline transition-colors", uploadDisabled ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:bg-j2-gray-4");
|
|
109
|
+
const templateBar = onDownloadTemplate || !templateUrl || uploadDisabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
110
|
+
type: "button",
|
|
111
|
+
disabled: uploadDisabled || !onDownloadTemplate,
|
|
112
|
+
onClick: onDownloadTemplate,
|
|
113
|
+
className: templateClass,
|
|
114
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.DownloadSimpleIcon, {
|
|
115
|
+
size: 16,
|
|
116
|
+
weight: "regular"
|
|
117
|
+
}), "Download Template"]
|
|
118
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
119
|
+
href: templateUrl,
|
|
120
|
+
download: true,
|
|
121
|
+
className: templateClass,
|
|
122
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.DownloadSimpleIcon, {
|
|
123
|
+
size: 16,
|
|
124
|
+
weight: "regular"
|
|
125
|
+
}), "Download Template"]
|
|
126
|
+
});
|
|
127
|
+
const renderContent = () => {
|
|
128
|
+
if (isUploading) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
129
|
+
className: "flex flex-col items-center gap-2 py-4",
|
|
130
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Spinner.Spinner, { size: 32 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
131
|
+
className: "m-0 text-sm text-j2-text-secondary",
|
|
132
|
+
children: "Checking file..."
|
|
133
|
+
})]
|
|
134
|
+
});
|
|
135
|
+
if (fileName && isUploaded) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
136
|
+
className: "flex flex-col items-center gap-4 py-8",
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.CheckCircleIcon, {
|
|
139
|
+
size: 32,
|
|
140
|
+
weight: "regular",
|
|
141
|
+
className: "text-j2-green-9"
|
|
142
|
+
}),
|
|
143
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
144
|
+
className: "flex flex-col items-center gap-1",
|
|
145
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
146
|
+
className: "m-0 text-base font-normal text-j2-text",
|
|
147
|
+
children: "File Uploaded"
|
|
148
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
149
|
+
className: "inline-flex items-center gap-1 rounded-j2-sm border border-solid border-j2-border px-2 py-1 text-xs text-j2-text",
|
|
150
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.FileCsvIcon, {
|
|
151
|
+
size: 14,
|
|
152
|
+
weight: "regular"
|
|
153
|
+
}), fileName.replace(new RegExp(`\\${accept}$`, "i"), "")]
|
|
154
|
+
})]
|
|
155
|
+
}),
|
|
156
|
+
successExtra && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
157
|
+
className: "flex w-full cursor-default justify-center",
|
|
158
|
+
onClick: (event) => event.stopPropagation(),
|
|
159
|
+
children: successExtra
|
|
160
|
+
}),
|
|
161
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
162
|
+
type: "button",
|
|
163
|
+
disabled,
|
|
164
|
+
onClick: (event) => {
|
|
165
|
+
event.stopPropagation();
|
|
166
|
+
requestUpload();
|
|
167
|
+
},
|
|
168
|
+
className: (0, classnames.default)("border-none bg-transparent p-0 text-sm font-medium", disabled ? "cursor-not-allowed text-j2-text-tertiary" : "cursor-pointer text-j2-blue-10 hover:underline"),
|
|
169
|
+
children: "Replace"
|
|
170
|
+
})
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
174
|
+
className: "flex flex-col items-center gap-4 py-8",
|
|
175
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_phosphor_icons_react.UploadSimpleIcon, {
|
|
176
|
+
size: 32,
|
|
177
|
+
weight: "regular",
|
|
178
|
+
className: "text-j2-blue-9"
|
|
179
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
180
|
+
className: "flex flex-col items-center gap-1",
|
|
181
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
182
|
+
className: "m-0 text-base font-normal text-j2-text",
|
|
183
|
+
children: ["Upload ", acceptLabel]
|
|
184
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
185
|
+
className: "m-0 text-sm text-j2-text-secondary",
|
|
186
|
+
children: "Structure your file according to the provided template"
|
|
187
|
+
})]
|
|
188
|
+
})]
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
192
|
+
className,
|
|
193
|
+
children: [
|
|
194
|
+
label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
195
|
+
className: "mb-1 block text-sm font-semibold",
|
|
196
|
+
children: label
|
|
197
|
+
}),
|
|
198
|
+
templateBar,
|
|
199
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
200
|
+
ref: fileInputRef,
|
|
201
|
+
type: "file",
|
|
202
|
+
accept,
|
|
203
|
+
onChange: handleFileChange,
|
|
204
|
+
className: "hidden",
|
|
205
|
+
"data-testid": "file-dropzone-input"
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
208
|
+
role: "button",
|
|
209
|
+
tabIndex: 0,
|
|
210
|
+
"aria-disabled": disabled,
|
|
211
|
+
"aria-label": `Upload ${acceptLabel} file`,
|
|
212
|
+
onClick: disabled ? void 0 : requestUpload,
|
|
213
|
+
onKeyDown: (event) => {
|
|
214
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
215
|
+
event.preventDefault();
|
|
216
|
+
if (!disabled) requestUpload();
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
onDragOver: handleDragOver,
|
|
220
|
+
onDragLeave: handleDragLeave,
|
|
221
|
+
onDrop: handleDrop,
|
|
222
|
+
className: (0, classnames.default)("mt-2 rounded-j2-lg border-2 border-dashed transition-colors", isDragOver ? "border-j2-blue-7 bg-j2-blue-2" : (0, classnames.default)("border-j2-gray-6 bg-j2-gray-1", !disabled && "hover:border-j2-gray-8"), disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"),
|
|
223
|
+
children: renderContent()
|
|
224
|
+
}),
|
|
225
|
+
hasHeaderError && (missingHeaders?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
226
|
+
className: "mx-4 flex items-start justify-between gap-3 rounded-b-xl border-x border-b border-solid border-j2-error bg-j2-red-2 px-3 py-2 text-sm",
|
|
227
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
228
|
+
className: "font-medium text-j2-primary",
|
|
229
|
+
children: [
|
|
230
|
+
"Missing required",
|
|
231
|
+
" ",
|
|
232
|
+
missingHeaders.length === 1 ? "column" : "columns",
|
|
233
|
+
":",
|
|
234
|
+
" ",
|
|
235
|
+
missingHeaders.map((header) => `"${header}"`).join(", ")
|
|
236
|
+
]
|
|
237
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
238
|
+
className: "m-0 text-xs text-j2-text-secondary",
|
|
239
|
+
children: [
|
|
240
|
+
"Header names are case-sensitive. Add the missing",
|
|
241
|
+
" ",
|
|
242
|
+
missingHeaders.length === 1 ? "column" : "columns",
|
|
243
|
+
" and re-upload."
|
|
244
|
+
]
|
|
245
|
+
})] })
|
|
246
|
+
}),
|
|
247
|
+
hasRowErrors && (errorRowCount ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
248
|
+
className: "mx-4 flex items-center justify-between rounded-b-xl border-x border-b border-solid border-j2-error bg-j2-red-2 px-3 py-2 text-sm",
|
|
249
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
250
|
+
className: "font-medium text-j2-primary",
|
|
251
|
+
children: [
|
|
252
|
+
errorRowCount.toLocaleString(),
|
|
253
|
+
" ",
|
|
254
|
+
errorRowCount === 1 ? "row" : "rows",
|
|
255
|
+
" will not be ingested"
|
|
256
|
+
]
|
|
257
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewIssuesButton, { onClick: onViewIssues })]
|
|
258
|
+
}),
|
|
259
|
+
hasRowWarnings && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
260
|
+
className: "mx-4 flex items-center justify-between rounded-b-xl border-x border-b border-solid border-j2-warning bg-j2-warning-bg px-3 py-2 text-sm",
|
|
261
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
262
|
+
className: "font-medium text-j2-primary",
|
|
263
|
+
children: (warningRowCount ?? 0) > 0 ? `${warningRowCount.toLocaleString()} ${warningRowCount === 1 ? "row has" : "rows have"} warnings` : "This file has warnings"
|
|
264
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewIssuesButton, { onClick: onViewIssues })]
|
|
265
|
+
}),
|
|
266
|
+
(dragError || errorMessage) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
267
|
+
className: "m-0 mt-1 text-xs text-j2-error",
|
|
268
|
+
children: dragError || errorMessage
|
|
269
|
+
}),
|
|
270
|
+
replaceConfirm && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Modal.Modal, {
|
|
271
|
+
open: confirmOpen,
|
|
272
|
+
width: 460,
|
|
273
|
+
title: "Replace this file?",
|
|
274
|
+
onCancel: cancelReplace,
|
|
275
|
+
footer: null,
|
|
276
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
277
|
+
className: "text-sm text-j2-text",
|
|
278
|
+
children: replaceConfirm
|
|
279
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
280
|
+
className: "mt-6 flex justify-end gap-2",
|
|
281
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Button.Button, {
|
|
282
|
+
onClick: cancelReplace,
|
|
283
|
+
children: "Cancel"
|
|
284
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Button.Button, {
|
|
285
|
+
type: "primary",
|
|
286
|
+
onClick: confirmReplace,
|
|
287
|
+
children: "Replace"
|
|
288
|
+
})]
|
|
289
|
+
})]
|
|
290
|
+
})
|
|
291
|
+
]
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
exports.FileDropzone = FileDropzone;
|
|
295
|
+
|
|
296
|
+
//# sourceMappingURL=FileDropzone.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileDropzone.cjs","names":["Button","useRef","useState","useCallback","cx","DownloadSimpleIcon","Spinner","CheckCircleIcon","FileCsvIcon","UploadSimpleIcon","Modal"],"sources":["../../../../src/components/fileDropzone/FileDropzone.tsx"],"sourcesContent":["import {\n useCallback,\n useImperativeHandle,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n} from 'react'\nimport cx from 'classnames'\nimport {\n CheckCircleIcon,\n DownloadSimpleIcon,\n FileCsvIcon,\n UploadSimpleIcon,\n} from '@phosphor-icons/react'\n\nimport { Button } from '../button'\nimport { Modal } from '../modal'\nimport { Spinner } from '../spinner'\n\nexport type FileDropzoneStatus =\n | 'idle'\n /** The file is being checked; the dropzone shows a spinner. */\n | 'validating'\n /** A file-level failure: the dropzone returns to its idle prompt and the\n * caller shows the details (usually in a results dialog). */\n | 'file-error'\n /** Required columns are missing; `missingHeaders` names them. */\n | 'header-error'\n | 'success'\n /** Uploaded, with rows that will not be ingested (`errorRowCount`). */\n | 'success-with-errors'\n /** Uploaded, with rows to review (`warningRowCount`). */\n | 'success-with-warnings'\n\n/** Lets a caller start an upload from outside the dropzone, such as a results\n * dialog's Re-upload. It goes through the same replace confirm as a click. */\nexport type FileDropzoneHandle = { requestUpload: () => void }\n\nexport type FileDropzoneProps = {\n status: FileDropzoneStatus\n /** Shown in a chip once a file is uploaded. */\n fileName?: string | null\n /** Bold label above the Download Template bar. Omit when the caller renders\n * its own section header. */\n label?: ReactNode\n /** Accepted file extension, for the picker and the drag-and-drop guard. */\n accept?: string\n errorRowCount?: number\n warningRowCount?: number\n missingHeaders?: string[]\n /** Static template URL for an `<a download>`. */\n templateUrl?: string\n /** Generates the template at runtime; takes precedence over `templateUrl`. */\n onDownloadTemplate?: () => void\n /** Greys out the template bar and the dropzone, e.g. until a choice the\n * upload depends on has been made. */\n uploadDisabled?: boolean\n onFileSelected: (file: File) => void\n /** Opens the caller's results dialog from an error or warning banner. */\n onViewIssues?: () => void\n /** A request that failed before the file was checked, shown under the\n * dropzone. */\n errorMessage?: ReactNode\n /** Body of a blocking \"Replace this file?\" confirm. When set and a file\n * already exists, every attempt to upload (click, Replace, keyboard or a\n * drop) asks first. When omitted, uploads proceed with no confirm. */\n replaceConfirm?: ReactNode\n /** True when a stored upload would be replaced even though the dropzone\n * looks idle. Defaults to the visible uploaded state. */\n hasExistingUpload?: boolean\n /** Read-only content in the uploaded state, between the file name and the\n * Replace link (a summary of what the file holds). Clicks inside it do not\n * start a replace. */\n successExtra?: ReactNode\n handleRef?: Ref<FileDropzoneHandle>\n className?: string\n}\n\nfunction ViewIssuesButton({ onClick }: { onClick?: () => void }) {\n return (\n <Button\n type=\"link\"\n size=\"small\"\n className=\"h-auto p-0 text-sm font-medium\"\n onClick={(event) => {\n event.stopPropagation()\n onClick?.()\n }}\n >\n View & Fix Issues\n </Button>\n )\n}\n\n/**\n * A file upload: an optional label, a full-width Download Template bar, and a\n * dashed dropzone that shows the prompt, a spinner while the file is checked,\n * or the uploaded file with a Replace link. Error and warning banners tuck\n * under the dropzone. Click, keyboard or drag and drop all upload; with\n * `replaceConfirm` set, replacing an existing file asks first.\n *\n * Presentational: the caller checks the file and passes the result back as\n * `status` and the counts.\n */\nexport function FileDropzone({\n status,\n fileName,\n label,\n accept = '.csv',\n errorRowCount,\n warningRowCount,\n missingHeaders,\n templateUrl,\n onDownloadTemplate,\n uploadDisabled = false,\n onFileSelected,\n onViewIssues,\n errorMessage,\n replaceConfirm,\n hasExistingUpload = false,\n successExtra,\n handleRef,\n className,\n}: FileDropzoneProps) {\n const fileInputRef = useRef<HTMLInputElement>(null)\n const [isDragOver, setIsDragOver] = useState(false)\n const [dragError, setDragError] = useState<string | null>(null)\n const [confirmOpen, setConfirmOpen] = useState(false)\n // A file dropped onto an uploaded dropzone waits here until the confirm\n // resolves; a picker request leaves it null.\n const pendingDropRef = useRef<File | null>(null)\n\n const isUploading = status === 'validating'\n const hasHeaderError = status === 'header-error'\n const hasRowErrors = status === 'success-with-errors'\n const hasRowWarnings = status === 'success-with-warnings'\n const isUploaded = status === 'success' || hasRowErrors || hasRowWarnings\n\n const disabled = uploadDisabled || isUploading\n const acceptLabel = accept.replace(/^\\./, '').toUpperCase()\n // The first upload overwrites nothing, so only a replace asks first.\n const needsReplaceConfirm =\n Boolean(replaceConfirm) && (isUploaded || hasExistingUpload)\n\n const handleFile = useCallback(\n (file: File | null) => {\n if (!file) return\n setDragError(null)\n onFileSelected(file)\n },\n [onFileSelected]\n )\n\n const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n handleFile(event.target.files?.[0] ?? null)\n event.target.value = ''\n }\n\n const openPicker = () => fileInputRef.current?.click()\n\n // Every upload attempt routes through here, so a replace always confirms.\n const requestUpload = () => {\n if (disabled) return\n if (needsReplaceConfirm) {\n pendingDropRef.current = null\n setConfirmOpen(true)\n return\n }\n openPicker()\n }\n\n useImperativeHandle(handleRef, () => ({ requestUpload }))\n\n const confirmReplace = () => {\n setConfirmOpen(false)\n const droppedFile = pendingDropRef.current\n pendingDropRef.current = null\n if (droppedFile) handleFile(droppedFile)\n else openPicker()\n }\n\n const cancelReplace = () => {\n pendingDropRef.current = null\n setConfirmOpen(false)\n }\n\n // Drag events are always cancelled, even while disabled: otherwise the\n // browser's own drop opens the file in place of the page.\n const handleDragOver = (event: React.DragEvent) => {\n event.preventDefault()\n event.stopPropagation()\n if (!disabled) setIsDragOver(true)\n }\n\n const handleDragLeave = (event: React.DragEvent) => {\n event.preventDefault()\n event.stopPropagation()\n setIsDragOver(false)\n }\n\n const handleDrop = (event: React.DragEvent) => {\n event.preventDefault()\n event.stopPropagation()\n setIsDragOver(false)\n if (disabled) return\n const file = event.dataTransfer.files?.[0] ?? null\n if (!file) return\n if (!file.name.toLowerCase().endsWith(accept.toLowerCase())) {\n setDragError(`Only ${acceptLabel} files are supported`)\n return\n }\n setDragError(null)\n // Dropping onto an existing upload is still a replace: confirm first.\n if (needsReplaceConfirm) {\n pendingDropRef.current = file\n setConfirmOpen(true)\n return\n }\n handleFile(file)\n }\n\n const templateClass = cx(\n 'mt-2 flex w-full items-center justify-center gap-2 rounded-j2 border-0 bg-j2-gray-3 px-4 py-1.5 text-sm text-j2-primary no-underline transition-colors',\n uploadDisabled\n ? 'cursor-not-allowed opacity-60'\n : 'cursor-pointer hover:bg-j2-gray-4'\n )\n\n // While disabled, the URL form renders as the disabled button too, so the\n // template can't be downloaded before the upload is available.\n const templateBar =\n onDownloadTemplate || !templateUrl || uploadDisabled ? (\n <button\n type=\"button\"\n disabled={uploadDisabled || !onDownloadTemplate}\n onClick={onDownloadTemplate}\n className={templateClass}\n >\n <DownloadSimpleIcon size={16} weight=\"regular\" />\n Download Template\n </button>\n ) : (\n <a href={templateUrl} download className={templateClass}>\n <DownloadSimpleIcon size={16} weight=\"regular\" />\n Download Template\n </a>\n )\n\n const renderContent = () => {\n if (isUploading) {\n return (\n <div className=\"flex flex-col items-center gap-2 py-4\">\n <Spinner size={32} />\n <p className=\"m-0 text-sm text-j2-text-secondary\">Checking file...</p>\n </div>\n )\n }\n\n if (fileName && isUploaded) {\n return (\n <div className=\"flex flex-col items-center gap-4 py-8\">\n <CheckCircleIcon\n size={32}\n weight=\"regular\"\n className=\"text-j2-green-9\"\n />\n <div className=\"flex flex-col items-center gap-1\">\n <p className=\"m-0 text-base font-normal text-j2-text\">\n File Uploaded\n </p>\n <span className=\"inline-flex items-center gap-1 rounded-j2-sm border border-solid border-j2-border px-2 py-1 text-xs text-j2-text\">\n <FileCsvIcon size={14} weight=\"regular\" />\n {fileName.replace(new RegExp(`\\\\${accept}$`, 'i'), '')}\n </span>\n </div>\n {successExtra && (\n // Read-only content, not part of the click-to-replace target.\n <div\n className=\"flex w-full cursor-default justify-center\"\n onClick={(event) => event.stopPropagation()}\n >\n {successExtra}\n </div>\n )}\n <button\n type=\"button\"\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation()\n requestUpload()\n }}\n className={cx(\n 'border-none bg-transparent p-0 text-sm font-medium',\n disabled\n ? 'cursor-not-allowed text-j2-text-tertiary'\n : 'cursor-pointer text-j2-blue-10 hover:underline'\n )}\n >\n Replace\n </button>\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col items-center gap-4 py-8\">\n <UploadSimpleIcon\n size={32}\n weight=\"regular\"\n className=\"text-j2-blue-9\"\n />\n <div className=\"flex flex-col items-center gap-1\">\n <p className=\"m-0 text-base font-normal text-j2-text\">\n Upload {acceptLabel}\n </p>\n <p className=\"m-0 text-sm text-j2-text-secondary\">\n Structure your file according to the provided template\n </p>\n </div>\n </div>\n )\n }\n\n return (\n <div className={className}>\n {label && (\n <label className=\"mb-1 block text-sm font-semibold\">{label}</label>\n )}\n\n {templateBar}\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n onChange={handleFileChange}\n className=\"hidden\"\n data-testid=\"file-dropzone-input\"\n />\n\n <div\n role=\"button\"\n tabIndex={0}\n aria-disabled={disabled}\n aria-label={`Upload ${acceptLabel} file`}\n onClick={disabled ? undefined : requestUpload}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n if (!disabled) requestUpload()\n }\n }}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n className={cx(\n 'mt-2 rounded-j2-lg border-2 border-dashed transition-colors',\n isDragOver\n ? 'border-j2-blue-7 bg-j2-blue-2'\n : cx(\n 'border-j2-gray-6 bg-j2-gray-1',\n !disabled && 'hover:border-j2-gray-8'\n ),\n disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'\n )}\n >\n {renderContent()}\n </div>\n\n {hasHeaderError && (missingHeaders?.length ?? 0) > 0 && (\n <div className=\"mx-4 flex items-start justify-between gap-3 rounded-b-xl border-x border-b border-solid border-j2-error bg-j2-red-2 px-3 py-2 text-sm\">\n <div>\n <span className=\"font-medium text-j2-primary\">\n Missing required{' '}\n {missingHeaders!.length === 1 ? 'column' : 'columns'}:{' '}\n {missingHeaders!.map((header) => `\"${header}\"`).join(', ')}\n </span>\n <p className=\"m-0 text-xs text-j2-text-secondary\">\n Header names are case-sensitive. Add the missing{' '}\n {missingHeaders!.length === 1 ? 'column' : 'columns'} and\n re-upload.\n </p>\n </div>\n </div>\n )}\n\n {hasRowErrors && (errorRowCount ?? 0) > 0 && (\n <div className=\"mx-4 flex items-center justify-between rounded-b-xl border-x border-b border-solid border-j2-error bg-j2-red-2 px-3 py-2 text-sm\">\n <span className=\"font-medium text-j2-primary\">\n {errorRowCount!.toLocaleString()}{' '}\n {errorRowCount === 1 ? 'row' : 'rows'} will not be ingested\n </span>\n <ViewIssuesButton onClick={onViewIssues} />\n </div>\n )}\n\n {hasRowWarnings && (\n <div className=\"mx-4 flex items-center justify-between rounded-b-xl border-x border-b border-solid border-j2-warning bg-j2-warning-bg px-3 py-2 text-sm\">\n <span className=\"font-medium text-j2-primary\">\n {(warningRowCount ?? 0) > 0\n ? `${warningRowCount!.toLocaleString()} ${\n warningRowCount === 1 ? 'row has' : 'rows have'\n } warnings`\n : 'This file has warnings'}\n </span>\n <ViewIssuesButton onClick={onViewIssues} />\n </div>\n )}\n\n {(dragError || errorMessage) && (\n <p className=\"m-0 mt-1 text-xs text-j2-error\">\n {dragError || errorMessage}\n </p>\n )}\n\n {replaceConfirm && (\n <Modal\n open={confirmOpen}\n width={460}\n title=\"Replace this file?\"\n onCancel={cancelReplace}\n footer={null}\n >\n <div className=\"text-sm text-j2-text\">{replaceConfirm}</div>\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button onClick={cancelReplace}>Cancel</Button>\n <Button type=\"primary\" onClick={confirmReplace}>\n Replace\n </Button>\n </div>\n </Modal>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;AA+EA,SAAS,iBAAiB,EAAE,WAAqC;CAC/D,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,QAAD;EACE,MAAK;EACL,MAAK;EACL,WAAU;EACV,UAAU,UAAU;GAClB,MAAM,gBAAgB;GACtB,UAAU;EACZ;EACD,UAAA;CAEO,CAAA;AAEZ;;;;;;;;;;;AAYA,SAAgB,aAAa,EAC3B,QACA,UACA,OACA,SAAS,QACT,eACA,iBACA,gBACA,aACA,oBACA,iBAAiB,OACjB,gBACA,cACA,cACA,gBACA,oBAAoB,OACpB,cACA,WACA,aACoB;CACpB,MAAM,gBAAA,GAAeC,MAAAA,OAAAA,CAAyB,IAAI;CAClD,MAAM,CAAC,YAAY,kBAAA,GAAiBC,MAAAA,SAAAA,CAAS,KAAK;CAClD,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAwB,IAAI;CAC9D,MAAM,CAAC,aAAa,mBAAA,GAAkBA,MAAAA,SAAAA,CAAS,KAAK;CAGpD,MAAM,kBAAA,GAAiBD,MAAAA,OAAAA,CAAoB,IAAI;CAE/C,MAAM,cAAc,WAAW;CAC/B,MAAM,iBAAiB,WAAW;CAClC,MAAM,eAAe,WAAW;CAChC,MAAM,iBAAiB,WAAW;CAClC,MAAM,aAAa,WAAW,aAAa,gBAAgB;CAE3D,MAAM,WAAW,kBAAkB;CACnC,MAAM,cAAc,OAAO,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY;CAE1D,MAAM,sBACJ,QAAQ,cAAc,MAAM,cAAc;CAE5C,MAAM,cAAA,GAAaE,MAAAA,YAAAA,EAChB,SAAsB;EACrB,IAAI,CAAC,MAAM;EACX,aAAa,IAAI;EACjB,eAAe,IAAI;CACrB,GACA,CAAC,cAAc,CACjB;CAEA,MAAM,oBAAoB,UAA+C;EACvE,WAAW,MAAM,OAAO,QAAQ,MAAM,IAAI;EAC1C,MAAM,OAAO,QAAQ;CACvB;CAEA,MAAM,mBAAmB,aAAa,SAAS,MAAM;CAGrD,MAAM,sBAAsB;EAC1B,IAAI,UAAU;EACd,IAAI,qBAAqB;GACvB,eAAe,UAAU;GACzB,eAAe,IAAI;GACnB;EACF;EACA,WAAW;CACb;CAEA,CAAA,GAAA,MAAA,oBAAA,CAAoB,kBAAkB,EAAE,cAAc,EAAE;CAExD,MAAM,uBAAuB;EAC3B,eAAe,KAAK;EACpB,MAAM,cAAc,eAAe;EACnC,eAAe,UAAU;EACzB,IAAI,aAAa,WAAW,WAAW;OAClC,WAAW;CAClB;CAEA,MAAM,sBAAsB;EAC1B,eAAe,UAAU;EACzB,eAAe,KAAK;CACtB;CAIA,MAAM,kBAAkB,UAA2B;EACjD,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,IAAI,CAAC,UAAU,cAAc,IAAI;CACnC;CAEA,MAAM,mBAAmB,UAA2B;EAClD,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,cAAc,KAAK;CACrB;CAEA,MAAM,cAAc,UAA2B;EAC7C,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,cAAc,KAAK;EACnB,IAAI,UAAU;EACd,MAAM,OAAO,MAAM,aAAa,QAAQ,MAAM;EAC9C,IAAI,CAAC,MAAM;EACX,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,SAAS,OAAO,YAAY,CAAC,GAAG;GAC3D,aAAa,QAAQ,YAAY,qBAAqB;GACtD;EACF;EACA,aAAa,IAAI;EAEjB,IAAI,qBAAqB;GACvB,eAAe,UAAU;GACzB,eAAe,IAAI;GACnB;EACF;EACA,WAAW,IAAI;CACjB;CAEA,MAAM,iBAAA,GAAgBC,WAAAA,QAAAA,CACpB,0JACA,iBACI,kCACA,mCACN;CAIA,MAAM,cACJ,sBAAsB,CAAC,eAAe,iBACpC,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;EACE,MAAK;EACL,UAAU,kBAAkB,CAAC;EAC7B,SAAS;EACT,WAAW;EAJb,UAAA,CAME,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,oBAAD;GAAoB,MAAM;GAAI,QAAO;EAAW,CAAA,GAAC,mBAE3C;CAER,CAAA,IAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;EAAG,MAAM;EAAa,UAAA;EAAS,WAAW;EAA1C,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,sBAAAA,oBAAD;GAAoB,MAAM;GAAI,QAAO;EAAW,CAAA,GAAC,mBAEhD;;CAGP,MAAM,sBAAsB;EAC1B,IAAI,aACF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,gBAAAA,SAAD,EAAS,MAAM,GAAK,CAAA,GACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IAAG,WAAU;IAAqC,UAAA;GAAmB,CAAA,CAClE;;EAIT,IAAI,YAAY,YACd,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,iBAAD;KACE,MAAM;KACN,QAAO;KACP,WAAU;IACX,CAAA;IACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAU;MAAyC,UAAA;KAEnD,CAAA,GACH,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,aAAD;OAAa,MAAM;OAAI,QAAO;MAAW,CAAA,GACxC,SAAS,QAAQ,IAAI,OAAO,KAAK,OAAO,IAAI,GAAG,GAAG,EAAE,CACjD;KACH,CAAA,CAAA;;IACJ,gBAEC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACE,WAAU;KACV,UAAU,UAAU,MAAM,gBAAgB;KAEzC,UAAA;IACE,CAAA;IAEP,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;KACE,MAAK;KACK;KACV,UAAU,UAAU;MAClB,MAAM,gBAAgB;MACtB,cAAc;KAChB;KACA,YAAA,GAAWJ,WAAAA,QAAAA,CACT,sDACA,WACI,6CACA,gDACN;KACD,UAAA;IAEO,CAAA;GACL;;EAIT,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACK,sBAAAA,kBAAD;IACE,MAAM;IACN,QAAO;IACP,WAAU;GACX,CAAA,GACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;KAAG,WAAU;KAAb,UAAA,CAAsD,WAC5C,WACP;IACH,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;KAAG,WAAU;KAAqC,UAAA;IAE/C,CAAA,CACA;GACF,CAAA,CAAA;;CAET;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAgB;EAAhB,UAAA;GACG,SACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;IAAO,WAAU;IAAoC,UAAA;GAAa,CAAA;GAGnE;GAED,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;IACE,KAAK;IACL,MAAK;IACG;IACR,UAAU;IACV,WAAU;IACV,eAAY;GACb,CAAA;GAED,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IACE,MAAK;IACL,UAAU;IACV,iBAAe;IACf,cAAY,UAAU,YAAY;IAClC,SAAS,WAAW,KAAA,IAAY;IAChC,YAAY,UAAU;KACpB,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;MAC9C,MAAM,eAAe;MACrB,IAAI,CAAC,UAAU,cAAc;KAC/B;IACF;IACA,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,YAAA,GAAWL,WAAAA,QAAAA,CACT,+DACA,aACI,mCAAA,GACAA,WAAAA,QAAAA,CACE,iCACA,CAAC,YAAY,wBACf,GACJ,WAAW,kCAAkC,gBAC/C;IAEC,UAAA,cAAc;GACZ,CAAA;GAEJ,mBAAmB,gBAAgB,UAAU,KAAK,KACjD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;IACb,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MAA8C;MAC3B;MAChB,eAAgB,WAAW,IAAI,WAAW;MAAU;MAAE;MACtD,eAAgB,KAAK,WAAW,IAAI,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI;KACrD;IACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;KAAG,WAAU;KAAb,UAAA;MAAkD;MACC;MAChD,eAAgB,WAAW,IAAI,WAAW;MAAU;KAEpD;IACA,CAAA,CAAA,EAAA,CAAA;GACF,CAAA;GAGN,iBAAiB,iBAAiB,KAAK,KACtC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACG,cAAe,eAAe;MAAG;MACjC,kBAAkB,IAAI,QAAQ;MAAO;KAClC;IACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,SAAS,aAAe,CAAA,CACvC;;GAGN,kBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;KACZ,WAAA,mBAAmB,KAAK,IACtB,GAAG,gBAAiB,eAAe,EAAE,GACnC,oBAAoB,IAAI,YAAY,YACrC,aACD;IACA,CAAA,GACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,kBAAD,EAAkB,SAAS,aAAe,CAAA,CACvC;;IAGL,aAAa,iBACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IAAG,WAAU;IACV,UAAA,aAAa;GACb,CAAA;GAGJ,kBACC,iBAAA,GAAA,kBAAA,KAAA,CAACM,cAAAA,OAAD;IACE,MAAM;IACN,OAAO;IACP,OAAM;IACN,UAAU;IACV,QAAQ;IALV,UAAA,CAOE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;KAAwB,UAAA;IAAoB,CAAA,GAC3D,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACV,eAAAA,QAAD;MAAQ,SAAS;MAAe,UAAA;KAAc,CAAA,GAC9C,iBAAA,GAAA,kBAAA,IAAA,CAACA,eAAAA,QAAD;MAAQ,MAAK;MAAU,SAAS;MAAgB,UAAA;KAExC,CAAA,CACL;IACA,CAAA,CAAA;;EAEN;;AAET"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ReactNode, Ref } from 'react';
|
|
2
|
+
export type FileDropzoneStatus = 'idle'
|
|
3
|
+
/** The file is being checked; the dropzone shows a spinner. */
|
|
4
|
+
| 'validating'
|
|
5
|
+
/** A file-level failure: the dropzone returns to its idle prompt and the
|
|
6
|
+
* caller shows the details (usually in a results dialog). */
|
|
7
|
+
| 'file-error'
|
|
8
|
+
/** Required columns are missing; `missingHeaders` names them. */
|
|
9
|
+
| 'header-error' | 'success'
|
|
10
|
+
/** Uploaded, with rows that will not be ingested (`errorRowCount`). */
|
|
11
|
+
| 'success-with-errors'
|
|
12
|
+
/** Uploaded, with rows to review (`warningRowCount`). */
|
|
13
|
+
| 'success-with-warnings';
|
|
14
|
+
/** Lets a caller start an upload from outside the dropzone, such as a results
|
|
15
|
+
* dialog's Re-upload. It goes through the same replace confirm as a click. */
|
|
16
|
+
export type FileDropzoneHandle = {
|
|
17
|
+
requestUpload: () => void;
|
|
18
|
+
};
|
|
19
|
+
export type FileDropzoneProps = {
|
|
20
|
+
status: FileDropzoneStatus;
|
|
21
|
+
/** Shown in a chip once a file is uploaded. */
|
|
22
|
+
fileName?: string | null;
|
|
23
|
+
/** Bold label above the Download Template bar. Omit when the caller renders
|
|
24
|
+
* its own section header. */
|
|
25
|
+
label?: ReactNode;
|
|
26
|
+
/** Accepted file extension, for the picker and the drag-and-drop guard. */
|
|
27
|
+
accept?: string;
|
|
28
|
+
errorRowCount?: number;
|
|
29
|
+
warningRowCount?: number;
|
|
30
|
+
missingHeaders?: string[];
|
|
31
|
+
/** Static template URL for an `<a download>`. */
|
|
32
|
+
templateUrl?: string;
|
|
33
|
+
/** Generates the template at runtime; takes precedence over `templateUrl`. */
|
|
34
|
+
onDownloadTemplate?: () => void;
|
|
35
|
+
/** Greys out the template bar and the dropzone, e.g. until a choice the
|
|
36
|
+
* upload depends on has been made. */
|
|
37
|
+
uploadDisabled?: boolean;
|
|
38
|
+
onFileSelected: (file: File) => void;
|
|
39
|
+
/** Opens the caller's results dialog from an error or warning banner. */
|
|
40
|
+
onViewIssues?: () => void;
|
|
41
|
+
/** A request that failed before the file was checked, shown under the
|
|
42
|
+
* dropzone. */
|
|
43
|
+
errorMessage?: ReactNode;
|
|
44
|
+
/** Body of a blocking "Replace this file?" confirm. When set and a file
|
|
45
|
+
* already exists, every attempt to upload (click, Replace, keyboard or a
|
|
46
|
+
* drop) asks first. When omitted, uploads proceed with no confirm. */
|
|
47
|
+
replaceConfirm?: ReactNode;
|
|
48
|
+
/** True when a stored upload would be replaced even though the dropzone
|
|
49
|
+
* looks idle. Defaults to the visible uploaded state. */
|
|
50
|
+
hasExistingUpload?: boolean;
|
|
51
|
+
/** Read-only content in the uploaded state, between the file name and the
|
|
52
|
+
* Replace link (a summary of what the file holds). Clicks inside it do not
|
|
53
|
+
* start a replace. */
|
|
54
|
+
successExtra?: ReactNode;
|
|
55
|
+
handleRef?: Ref<FileDropzoneHandle>;
|
|
56
|
+
className?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* A file upload: an optional label, a full-width Download Template bar, and a
|
|
60
|
+
* dashed dropzone that shows the prompt, a spinner while the file is checked,
|
|
61
|
+
* or the uploaded file with a Replace link. Error and warning banners tuck
|
|
62
|
+
* under the dropzone. Click, keyboard or drag and drop all upload; with
|
|
63
|
+
* `replaceConfirm` set, replacing an existing file asks first.
|
|
64
|
+
*
|
|
65
|
+
* Presentational: the caller checks the file and passes the result back as
|
|
66
|
+
* `status` and the counts.
|
|
67
|
+
*/
|
|
68
|
+
export declare function FileDropzone({ status, fileName, label, accept, errorRowCount, warningRowCount, missingHeaders, templateUrl, onDownloadTemplate, uploadDisabled, onFileSelected, onViewIssues, errorMessage, replaceConfirm, hasExistingUpload, successExtra, handleRef, className, }: FileDropzoneProps): import('react').JSX.Element;
|