@crisp-ui-kit/crisp 0.23.4 → 0.23.5
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/cjs/components/fileupload/fileupload.js +1 -1
- package/dist/cjs/components/fileupload/fileupload.recipe.js +4 -0
- package/dist/cjs/components/toast/toast.js +2 -2
- package/dist/esm/components/fileupload/fileupload.js +1 -1
- package/dist/esm/components/fileupload/fileupload.recipe.js +4 -0
- package/dist/esm/components/toast/toast.js +2 -2
- package/dist/fileupload.css +4 -0
- package/dist/styles.css +4 -0
- package/package.json +1 -1
|
@@ -114,5 +114,5 @@ function FileUpload({ className, labels, "aria-label": ariaLabel, accept, disabl
|
|
|
114
114
|
// instead means attaching them here; without inputRef, `openFilePicker`
|
|
115
115
|
// finds no input and returns silently, so the dropzone opens nothing.
|
|
116
116
|
inputRef, dropzoneRef, } = api;
|
|
117
|
-
return ((0, jsx_runtime_1.jsxs)("div", { ...rest, className: (0, fileupload_recipe_1.fileuploadRecipe)({ className }), children: [(0, jsx_runtime_1.jsxs)("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-title", children: t.title }), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-hint", children: t.hint })] }), (0, jsx_runtime_1.jsx)("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => ((0, jsx_runtime_1.jsxs)("li", { className: "fileupload-item", "data-status": entry.status, children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && ((0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: (0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })),
|
|
117
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ...rest, className: (0, fileupload_recipe_1.fileuploadRecipe)({ className }), children: [(0, jsx_runtime_1.jsxs)("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-title", children: t.title }), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-hint", children: t.hint })] }), (0, jsx_runtime_1.jsx)("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => ((0, jsx_runtime_1.jsxs)("li", { className: "fileupload-item", "data-status": entry.status, children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && ((0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: (0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), (0, jsx_runtime_1.jsx)("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => ((0, jsx_runtime_1.jsx)("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) })] }));
|
|
118
118
|
}
|
|
@@ -92,6 +92,10 @@ const config = (0, core_1.defineRecipe)({
|
|
|
92
92
|
& .fileupload-remove:focus-visible { outline-color: ${tokens_1.contract.strokeFocusRing}; }
|
|
93
93
|
|
|
94
94
|
& .fileupload-errors { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; margin: 0; padding: 0; list-style: none; }
|
|
95
|
+
/* out of flow while empty, so the always-mounted live region costs no
|
|
96
|
+
layout: display:none would take it out of the accessibility tree, which
|
|
97
|
+
is the one thing it exists to be in */
|
|
98
|
+
& .fileupload-errors:empty { position: absolute; }
|
|
95
99
|
& .fileupload-error { color: ${tokens_1.contract.bgDanger}; font-size: ${tokens_1.contract.text.md}; line-height: 18px; }
|
|
96
100
|
`,
|
|
97
101
|
variants: {},
|
|
@@ -48,7 +48,7 @@ const ICONS = {
|
|
|
48
48
|
};
|
|
49
49
|
function ToastCard({ item, onClose, dismissLabel, }) {
|
|
50
50
|
const Icon = ICONS[item.tone ?? "info"];
|
|
51
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "toast",
|
|
51
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "toast", "data-tone": item.tone ?? "info", children: [(0, jsx_runtime_1.jsx)("span", { className: "toast-icon", children: (0, jsx_runtime_1.jsx)(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "toast-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "toast-title", children: item.title }), item.description != null && ((0, jsx_runtime_1.jsx)("div", { className: "toast-desc", children: item.description })), item.action && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "toast-action", onClick: () => {
|
|
52
52
|
item.action?.onClick();
|
|
53
53
|
onClose();
|
|
54
54
|
}, children: item.action.label }))] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "toast-close", "aria-label": dismissLabel, onClick: onClose, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 2, "aria-hidden": "true" }) })] }));
|
|
@@ -84,7 +84,7 @@ function ToastProvider({ children, duration = 4000, dismissLabel = "Dismiss", re
|
|
|
84
84
|
return () => map.forEach(clearTimeout);
|
|
85
85
|
}, []);
|
|
86
86
|
const api = React.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
|
|
87
|
-
return ((0, jsx_runtime_1.jsxs)(ToastContext.Provider, { value: api, children: [children, (0, jsx_runtime_1.jsx)("div", { className: (0, toast_recipe_1.toastRecipe)(), children: (0, jsx_runtime_1.jsx)("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, children: items.map((t) => ((0, jsx_runtime_1.jsx)(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
|
|
87
|
+
return ((0, jsx_runtime_1.jsxs)(ToastContext.Provider, { value: api, children: [children, (0, jsx_runtime_1.jsx)("div", { className: (0, toast_recipe_1.toastRecipe)(), children: (0, jsx_runtime_1.jsx)("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, "aria-live": "polite", "aria-atomic": "false", children: items.map((t) => ((0, jsx_runtime_1.jsx)(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
|
|
88
88
|
}
|
|
89
89
|
ToastProvider.displayName = "ToastProvider";
|
|
90
90
|
function useToast() {
|
|
@@ -77,5 +77,5 @@ export function FileUpload({ className, labels, "aria-label": ariaLabel, accept,
|
|
|
77
77
|
// instead means attaching them here; without inputRef, `openFilePicker`
|
|
78
78
|
// finds no input and returns silently, so the dropzone opens nothing.
|
|
79
79
|
inputRef, dropzoneRef, } = api;
|
|
80
|
-
return (_jsxs("div", { ...rest, className: fileuploadRecipe({ className }), children: [_jsxs("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [_jsx("span", { className: "fileupload-title", children: t.title }), _jsx("span", { className: "fileupload-hint", children: t.hint })] }), _jsx("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && (_jsx("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => (_jsxs("li", { className: "fileupload-item", "data-status": entry.status, children: [_jsx("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && (_jsx("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: _jsx("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), _jsx("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), _jsx("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: _jsx(X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })),
|
|
80
|
+
return (_jsxs("div", { ...rest, className: fileuploadRecipe({ className }), children: [_jsxs("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [_jsx("span", { className: "fileupload-title", children: t.title }), _jsx("span", { className: "fileupload-hint", children: t.hint })] }), _jsx("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && (_jsx("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => (_jsxs("li", { className: "fileupload-item", "data-status": entry.status, children: [_jsx("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && (_jsx("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: _jsx("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), _jsx("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), _jsx("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: _jsx(X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), _jsx("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => (_jsx("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) })] }));
|
|
81
81
|
}
|
|
@@ -89,6 +89,10 @@ const config = defineRecipe({
|
|
|
89
89
|
& .fileupload-remove:focus-visible { outline-color: ${c.strokeFocusRing}; }
|
|
90
90
|
|
|
91
91
|
& .fileupload-errors { display: flex; flex-direction: column; gap: ${c.space["0.5"]}; margin: 0; padding: 0; list-style: none; }
|
|
92
|
+
/* out of flow while empty, so the always-mounted live region costs no
|
|
93
|
+
layout: display:none would take it out of the accessibility tree, which
|
|
94
|
+
is the one thing it exists to be in */
|
|
95
|
+
& .fileupload-errors:empty { position: absolute; }
|
|
92
96
|
& .fileupload-error { color: ${c.bgDanger}; font-size: ${c.text.md}; line-height: 18px; }
|
|
93
97
|
`,
|
|
94
98
|
variants: {},
|
|
@@ -11,7 +11,7 @@ const ICONS = {
|
|
|
11
11
|
};
|
|
12
12
|
function ToastCard({ item, onClose, dismissLabel, }) {
|
|
13
13
|
const Icon = ICONS[item.tone ?? "info"];
|
|
14
|
-
return (_jsxs("div", { className: "toast",
|
|
14
|
+
return (_jsxs("div", { className: "toast", "data-tone": item.tone ?? "info", children: [_jsx("span", { className: "toast-icon", children: _jsx(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), _jsxs("div", { className: "toast-body", children: [_jsx("div", { className: "toast-title", children: item.title }), item.description != null && (_jsx("div", { className: "toast-desc", children: item.description })), item.action && (_jsx("button", { type: "button", className: "toast-action", onClick: () => {
|
|
15
15
|
item.action?.onClick();
|
|
16
16
|
onClose();
|
|
17
17
|
}, children: item.action.label }))] }), _jsx("button", { type: "button", className: "toast-close", "aria-label": dismissLabel, onClick: onClose, children: _jsx(X, { size: 15, strokeWidth: 2, "aria-hidden": "true" }) })] }));
|
|
@@ -47,7 +47,7 @@ export function ToastProvider({ children, duration = 4000, dismissLabel = "Dismi
|
|
|
47
47
|
return () => map.forEach(clearTimeout);
|
|
48
48
|
}, []);
|
|
49
49
|
const api = React.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
|
|
50
|
-
return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx("div", { className: toastRecipe(), children: _jsx("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, children: items.map((t) => (_jsx(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
|
|
50
|
+
return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx("div", { className: toastRecipe(), children: _jsx("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, "aria-live": "polite", "aria-atomic": "false", children: items.map((t) => (_jsx(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
|
|
51
51
|
}
|
|
52
52
|
ToastProvider.displayName = "ToastProvider";
|
|
53
53
|
export function useToast() {
|
package/dist/fileupload.css
CHANGED
|
@@ -72,6 +72,10 @@
|
|
|
72
72
|
& .fileupload-remove:focus-visible { outline-color: var(--stroke-focus-ring); }
|
|
73
73
|
|
|
74
74
|
& .fileupload-errors { display: flex; flex-direction: column; gap: var(--space-0-5); margin: 0; padding: 0; list-style: none; }
|
|
75
|
+
/* out of flow while empty, so the always-mounted live region costs no
|
|
76
|
+
layout: display:none would take it out of the accessibility tree, which
|
|
77
|
+
is the one thing it exists to be in */
|
|
78
|
+
& .fileupload-errors:empty { position: absolute; }
|
|
75
79
|
& .fileupload-error { color: var(--bg-danger); font-size: var(--text-md); line-height: 18px; }
|
|
76
80
|
|
|
77
81
|
}
|
package/dist/styles.css
CHANGED
|
@@ -950,6 +950,10 @@
|
|
|
950
950
|
& .fileupload-remove:focus-visible { outline-color: var(--stroke-focus-ring); }
|
|
951
951
|
|
|
952
952
|
& .fileupload-errors { display: flex; flex-direction: column; gap: var(--space-0-5); margin: 0; padding: 0; list-style: none; }
|
|
953
|
+
/* out of flow while empty, so the always-mounted live region costs no
|
|
954
|
+
layout: display:none would take it out of the accessibility tree, which
|
|
955
|
+
is the one thing it exists to be in */
|
|
956
|
+
& .fileupload-errors:empty { position: absolute; }
|
|
953
957
|
& .fileupload-error { color: var(--bg-danger); font-size: var(--text-md); line-height: 18px; }
|
|
954
958
|
|
|
955
959
|
}
|