@surflane/ui 0.1.0 → 0.2.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/README.md +8 -8
- package/dist/advanced-forms.d.ts +2 -2
- package/dist/advanced-forms.js +39 -39
- package/dist/app-shell.d.ts +1 -1
- package/dist/app-shell.js +11 -11
- package/dist/button.d.ts +5 -5
- package/dist/button.js +12 -12
- package/dist/chart.d.ts +3 -3
- package/dist/chart.js +36 -34
- package/dist/commands.d.ts +5 -5
- package/dist/commands.js +17 -17
- package/dist/content.d.ts +2 -2
- package/dist/content.js +66 -28
- package/dist/context-overlays.d.ts +3 -3
- package/dist/context-overlays.js +11 -11
- package/dist/data.d.ts +1 -1
- package/dist/data.js +18 -18
- package/dist/date-picker.d.ts +8 -8
- package/dist/date-picker.js +18 -18
- package/dist/dialog-focus.js +7 -7
- package/dist/dialog.d.ts +5 -5
- package/dist/dialog.js +16 -16
- package/dist/feedback.d.ts +5 -5
- package/dist/feedback.js +20 -20
- package/dist/file-upload.d.ts +9 -9
- package/dist/file-upload.js +64 -63
- package/dist/filter-bar.d.ts +1 -1
- package/dist/filter-bar.js +9 -9
- package/dist/form-state.d.ts +1 -1
- package/dist/form-state.js +11 -11
- package/dist/forms.d.ts +5 -5
- package/dist/forms.js +32 -32
- package/dist/foundations.d.ts +10 -10
- package/dist/foundations.js +26 -26
- package/dist/icon.d.ts +7 -7
- package/dist/icon.js +22 -22
- package/dist/index.d.ts +37 -37
- package/dist/index.js +38 -38
- package/dist/input-extensions.d.ts +3 -3
- package/dist/input-extensions.js +21 -21
- package/dist/input.d.ts +2 -2
- package/dist/input.js +7 -7
- package/dist/markdown.d.ts +2 -2
- package/dist/markdown.js +38 -38
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +19 -19
- package/dist/messages.d.ts +2 -2
- package/dist/messages.js +18 -18
- package/dist/navigation-menu.d.ts +2 -2
- package/dist/navigation-menu.js +16 -16
- package/dist/navigation.d.ts +5 -5
- package/dist/navigation.js +40 -40
- package/dist/otp-field.d.ts +1 -1
- package/dist/otp-field.js +14 -14
- package/dist/pagination.d.ts +2 -2
- package/dist/pagination.js +12 -12
- package/dist/panels.d.ts +8 -8
- package/dist/panels.js +39 -39
- package/dist/parts.d.ts +2 -2
- package/dist/parts.js +8 -8
- package/dist/popover.d.ts +3 -3
- package/dist/popover.js +6 -6
- package/dist/scroll-area.d.ts +1 -1
- package/dist/scroll-area.js +20 -20
- package/dist/select.d.ts +8 -8
- package/dist/select.js +21 -21
- package/dist/sizing.d.ts +3 -3
- package/dist/sizing.js +9 -9
- package/dist/slot.d.ts +1 -1
- package/dist/slot.js +4 -4
- package/dist/status.d.ts +4 -4
- package/dist/status.js +8 -8
- package/dist/syntax-engine.js +43 -43
- package/dist/syntax-highlighter.d.ts +2 -2
- package/dist/syntax-highlighter.js +32 -32
- package/dist/toast.d.ts +4 -4
- package/dist/toast.js +33 -33
- package/dist/tone-transition.d.ts +1 -1
- package/dist/tone-transition.js +17 -17
- package/dist/tooltip.d.ts +1 -1
- package/dist/tooltip.js +4 -4
- package/dist/tree.d.ts +4 -4
- package/dist/tree.js +60 -60
- package/package.json +2 -2
- package/src/styles.css +233 -142
package/dist/file-upload.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { Field } from
|
|
3
|
-
export type UploadState =
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Field } from './forms.js';
|
|
3
|
+
export type UploadState = 'ready' | 'uploading' | 'success' | 'error' | 'canceled';
|
|
4
4
|
export type UploadTransport = (file: File, context: {
|
|
5
5
|
signal: AbortSignal;
|
|
6
6
|
onProgress: (percent: number | null) => void;
|
|
7
7
|
}) => Promise<void>;
|
|
8
8
|
export type FileRejection = {
|
|
9
9
|
file: File;
|
|
10
|
-
reason:
|
|
10
|
+
reason: 'type' | 'size' | 'count' | 'duplicate';
|
|
11
11
|
};
|
|
12
12
|
export type FileChangeDetails = {
|
|
13
|
-
reason:
|
|
13
|
+
reason: 'select' | 'drop' | 'remove';
|
|
14
14
|
isCanceled: boolean;
|
|
15
15
|
cancel: () => void;
|
|
16
16
|
};
|
|
@@ -30,12 +30,12 @@ export type FileUploadLabels = {
|
|
|
30
30
|
reset: string;
|
|
31
31
|
progress: (file: File) => string;
|
|
32
32
|
};
|
|
33
|
-
export type FileUploadProps = Omit<React.ComponentPropsWithoutRef<typeof Field.Root>,
|
|
33
|
+
export type FileUploadProps = Omit<React.ComponentPropsWithoutRef<typeof Field.Root>, 'children' | 'name' | 'onDragEnter' | 'onDragLeave' | 'onDragOver' | 'onDrop'> & Pick<React.HTMLAttributes<HTMLDivElement>, 'onDragEnter' | 'onDragLeave' | 'onDragOver' | 'onDrop'> & {
|
|
34
34
|
label: React.ReactNode;
|
|
35
35
|
description?: React.ReactNode;
|
|
36
36
|
name?: string;
|
|
37
37
|
form?: string;
|
|
38
|
-
capture?: React.InputHTMLAttributes<HTMLInputElement>[
|
|
38
|
+
capture?: React.InputHTMLAttributes<HTMLInputElement>['capture'];
|
|
39
39
|
accept?: string;
|
|
40
40
|
multiple?: boolean;
|
|
41
41
|
required?: boolean;
|
|
@@ -47,8 +47,8 @@ export type FileUploadProps = Omit<React.ComponentPropsWithoutRef<typeof Field.R
|
|
|
47
47
|
onReject?: (rejections: FileRejection[]) => void;
|
|
48
48
|
transport?: UploadTransport;
|
|
49
49
|
getUploadError?: (error: unknown) => string;
|
|
50
|
-
labels?: Partial<Omit<FileUploadLabels,
|
|
51
|
-
status?: Partial<FileUploadLabels[
|
|
50
|
+
labels?: Partial<Omit<FileUploadLabels, 'status'>> & {
|
|
51
|
+
status?: Partial<FileUploadLabels['status']>;
|
|
52
52
|
};
|
|
53
53
|
};
|
|
54
54
|
/** Native selection/validation and a cancellable transport adapter; no network request is built in. */
|
package/dist/file-upload.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as React from
|
|
4
|
-
import { Field } from
|
|
5
|
-
import { Button } from
|
|
6
|
-
import { Progress } from
|
|
7
|
-
import { StatusBadge } from
|
|
8
|
-
import { skin } from
|
|
9
|
-
import { useResetValue, useRootRef } from
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Field } from './forms.js';
|
|
5
|
+
import { Button } from './button.js';
|
|
6
|
+
import { Progress } from './feedback.js';
|
|
7
|
+
import { StatusBadge } from './status.js';
|
|
8
|
+
import { skin } from './parts.js';
|
|
9
|
+
import { useResetValue, useRootRef } from './form-state.js';
|
|
10
10
|
const labelsDefault = {
|
|
11
|
-
choose:
|
|
12
|
-
drop:
|
|
13
|
-
upload:
|
|
14
|
-
retry:
|
|
15
|
-
cancel:
|
|
16
|
-
remove:
|
|
11
|
+
choose: 'Choose files',
|
|
12
|
+
drop: 'or drop files here',
|
|
13
|
+
upload: 'Upload',
|
|
14
|
+
retry: 'Retry',
|
|
15
|
+
cancel: 'Cancel',
|
|
16
|
+
remove: 'Remove',
|
|
17
17
|
status: {
|
|
18
|
-
ready:
|
|
19
|
-
uploading:
|
|
20
|
-
success:
|
|
21
|
-
error:
|
|
22
|
-
canceled:
|
|
18
|
+
ready: 'Ready',
|
|
19
|
+
uploading: 'Uploading',
|
|
20
|
+
success: 'Uploaded',
|
|
21
|
+
error: 'Failed',
|
|
22
|
+
canceled: 'Canceled',
|
|
23
23
|
},
|
|
24
|
-
rejection: ({ file, reason }) => `${file.name}: ${reason ===
|
|
25
|
-
changed: (count) => `${count} file${count === 1 ?
|
|
24
|
+
rejection: ({ file, reason }) => `${file.name}: ${reason === 'type' ? 'file type is not accepted' : reason === 'size' ? 'file is too large' : reason === 'count' ? 'file limit reached' : 'file is already selected'}.`,
|
|
25
|
+
changed: (count) => `${count} file${count === 1 ? '' : 's'} selected.`,
|
|
26
26
|
complete: (file) => `${file.name}: upload complete.`,
|
|
27
27
|
canceled: (file) => `${file.name}: upload canceled.`,
|
|
28
28
|
failed: (file) => `${file.name}: upload failed.`,
|
|
29
|
-
reset:
|
|
29
|
+
reset: 'Files reset.',
|
|
30
30
|
progress: (file) => `${file.name} upload progress`,
|
|
31
31
|
};
|
|
32
32
|
function signature(file) {
|
|
@@ -34,22 +34,22 @@ function signature(file) {
|
|
|
34
34
|
}
|
|
35
35
|
function accepts(file, accept) {
|
|
36
36
|
const rules = accept
|
|
37
|
-
.split(
|
|
37
|
+
.split(',')
|
|
38
38
|
.map((rule) => rule.trim().toLowerCase())
|
|
39
39
|
.filter(Boolean);
|
|
40
40
|
return (!rules.length ||
|
|
41
|
-
rules.some((rule) => rule.startsWith(
|
|
41
|
+
rules.some((rule) => rule.startsWith('.')
|
|
42
42
|
? file.name.toLowerCase().endsWith(rule)
|
|
43
|
-
: rule.endsWith(
|
|
43
|
+
: rule.endsWith('/*')
|
|
44
44
|
? file.type.toLowerCase().startsWith(rule.slice(0, -1))
|
|
45
45
|
: file.type.toLowerCase() === rule));
|
|
46
46
|
}
|
|
47
47
|
function sizeLabel(bytes) {
|
|
48
|
-
const unit = bytes >= 1024 * 1024 ?
|
|
49
|
-
return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }).format(bytes / (unit ===
|
|
48
|
+
const unit = bytes >= 1024 * 1024 ? 'MB' : bytes >= 1024 ? 'KB' : 'B';
|
|
49
|
+
return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }).format(bytes / (unit === 'MB' ? 1024 * 1024 : unit === 'KB' ? 1024 : 1))} ${unit}`;
|
|
50
50
|
}
|
|
51
51
|
/** Native selection/validation and a cancellable transport adapter; no network request is built in. */
|
|
52
|
-
export const FileUpload = React.forwardRef(function FileUpload({ label, description, name, form, accept =
|
|
52
|
+
export const FileUpload = React.forwardRef(function FileUpload({ label, description, name, form, accept = '', capture, multiple = false, required = false, maxFiles = Infinity, maxFileSize = Infinity, files: controlled, defaultFiles = [], onFilesChange, onReject, transport, getUploadError, labels: customLabels, disabled = false, className, onDragEnter, onDragLeave, onDragOver, onDrop, ...props }, forwardedRef) {
|
|
53
53
|
const labels = {
|
|
54
54
|
...labelsDefault,
|
|
55
55
|
...customLabels,
|
|
@@ -57,7 +57,7 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
57
57
|
};
|
|
58
58
|
const [root, ref] = useRootRef(forwardedRef), input = React.useRef(null);
|
|
59
59
|
const uid = React.useId(), inputId = `${uid}-input`, errorId = `${uid}-selection-errors`;
|
|
60
|
-
const [metadata, setMetadata] = React.useState(new Map()), [rejections, setRejections] = React.useState([]), [announcement, announce] = React.useState(
|
|
60
|
+
const [metadata, setMetadata] = React.useState(new Map()), [rejections, setRejections] = React.useState([]), [announcement, announce] = React.useState(''), [dragging, setDragging] = React.useState(false);
|
|
61
61
|
const notifying = React.useRef(false), lastSynced = React.useRef(null), skipNotifyFor = React.useRef(null);
|
|
62
62
|
const primaryButtons = React.useRef(new WeakMap()), removeButtons = React.useRef(new WeakMap()), focusRemove = React.useRef(null), focusPicker = React.useRef(null);
|
|
63
63
|
const requests = React.useRef(new Map()), mounted = React.useRef(false), dragDepth = React.useRef(0);
|
|
@@ -93,7 +93,7 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
93
93
|
input.current) {
|
|
94
94
|
notifying.current = true;
|
|
95
95
|
try {
|
|
96
|
-
input.current.dispatchEvent(new Event(
|
|
96
|
+
input.current.dispatchEvent(new Event('change', { bubbles: true }));
|
|
97
97
|
}
|
|
98
98
|
finally {
|
|
99
99
|
notifying.current = false;
|
|
@@ -142,11 +142,12 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
142
142
|
return;
|
|
143
143
|
requests.current.delete(file);
|
|
144
144
|
request.controller.abort();
|
|
145
|
-
update(file, { status:
|
|
145
|
+
update(file, { status: 'canceled', progress: null });
|
|
146
146
|
announce(labels.canceled(file));
|
|
147
147
|
}
|
|
148
148
|
React.useEffect(() => {
|
|
149
149
|
if (disabled) {
|
|
150
|
+
;
|
|
150
151
|
[...requests.current.keys()].forEach(cancel);
|
|
151
152
|
dragDepth.current = 0;
|
|
152
153
|
setDragging(false);
|
|
@@ -194,13 +195,13 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
194
195
|
for (const file of incoming) {
|
|
195
196
|
let rejection;
|
|
196
197
|
if (!accepts(file, accept))
|
|
197
|
-
rejection =
|
|
198
|
+
rejection = 'type';
|
|
198
199
|
else if (file.size > maxFileSize)
|
|
199
|
-
rejection =
|
|
200
|
+
rejection = 'size';
|
|
200
201
|
else if (next.some((current) => signature(current) === signature(file)))
|
|
201
|
-
rejection =
|
|
202
|
+
rejection = 'duplicate';
|
|
202
203
|
else if (next.length >= limit)
|
|
203
|
-
rejection =
|
|
204
|
+
rejection = 'count';
|
|
204
205
|
if (rejection)
|
|
205
206
|
rejected.push({ file, reason: rejection });
|
|
206
207
|
else
|
|
@@ -228,14 +229,14 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
228
229
|
requests.current.get(file) === request &&
|
|
229
230
|
!request.controller.signal.aborted &&
|
|
230
231
|
latestFiles.current.includes(file);
|
|
231
|
-
update(file, { status:
|
|
232
|
+
update(file, { status: 'uploading', progress: null });
|
|
232
233
|
try {
|
|
233
234
|
await transport(file, {
|
|
234
235
|
signal: request.controller.signal,
|
|
235
236
|
onProgress(percent) {
|
|
236
237
|
if (current())
|
|
237
238
|
update(file, {
|
|
238
|
-
status:
|
|
239
|
+
status: 'uploading',
|
|
239
240
|
progress: percent === null || !Number.isFinite(percent)
|
|
240
241
|
? null
|
|
241
242
|
: Math.max(0, Math.min(100, percent)),
|
|
@@ -246,18 +247,18 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
246
247
|
if (primaryButtons.current.get(file) ===
|
|
247
248
|
input.current?.ownerDocument.activeElement)
|
|
248
249
|
focusRemove.current = file;
|
|
249
|
-
update(file, { status:
|
|
250
|
+
update(file, { status: 'success', progress: 100 });
|
|
250
251
|
announce(labels.complete(file));
|
|
251
252
|
}
|
|
252
253
|
}
|
|
253
254
|
catch (error) {
|
|
254
255
|
if (current()) {
|
|
255
|
-
let message =
|
|
256
|
+
let message = 'Upload failed. Try again.';
|
|
256
257
|
try {
|
|
257
258
|
message = getUploadError?.(error) || message;
|
|
258
259
|
}
|
|
259
260
|
catch { }
|
|
260
|
-
update(file, { status:
|
|
261
|
+
update(file, { status: 'error', progress: null, error: message });
|
|
261
262
|
announce(labels.failed(file));
|
|
262
263
|
}
|
|
263
264
|
}
|
|
@@ -266,8 +267,8 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
266
267
|
requests.current.delete(file);
|
|
267
268
|
}
|
|
268
269
|
}
|
|
269
|
-
const hasFiles = (event) => Array.from(event.dataTransfer.types).includes(
|
|
270
|
-
return (_jsxs(Field.Root, { ...props, ref: ref, name: name, disabled: disabled, className: skin(
|
|
270
|
+
const hasFiles = (event) => Array.from(event.dataTransfer.types).includes('Files');
|
|
271
|
+
return (_jsxs(Field.Root, { ...props, ref: ref, name: name, disabled: disabled, className: skin('pui-field pui-file-upload', className), "data-dragging": dragging || undefined, children: [_jsx(Field.Label, { children: label }), description != null && description !== false && (_jsx(Field.Description, { children: description })), _jsxs("div", { className: 'pui-file-dropzone', onDragEnter: (event) => {
|
|
271
272
|
onDragEnter?.(event);
|
|
272
273
|
if (!event.defaultPrevented && hasFiles(event) && !disabled) {
|
|
273
274
|
event.preventDefault();
|
|
@@ -283,7 +284,7 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
283
284
|
onDragOver?.(event);
|
|
284
285
|
if (hasFiles(event)) {
|
|
285
286
|
event.preventDefault();
|
|
286
|
-
event.dataTransfer.dropEffect = disabled ?
|
|
287
|
+
event.dataTransfer.dropEffect = disabled ? 'none' : 'copy';
|
|
287
288
|
}
|
|
288
289
|
}, onDrop: (event) => {
|
|
289
290
|
onDrop?.(event);
|
|
@@ -291,53 +292,53 @@ export const FileUpload = React.forwardRef(function FileUpload({ label, descript
|
|
|
291
292
|
setDragging(false);
|
|
292
293
|
if (!event.defaultPrevented && hasFiles(event)) {
|
|
293
294
|
event.preventDefault();
|
|
294
|
-
select(Array.from(event.dataTransfer.files),
|
|
295
|
+
select(Array.from(event.dataTransfer.files), 'drop');
|
|
295
296
|
}
|
|
296
|
-
}, children: [_jsx(Field.Control, { ref: input, id: inputId, name: name, form: form, type:
|
|
297
|
-
if (event.key ===
|
|
297
|
+
}, children: [_jsx(Field.Control, { ref: input, id: inputId, name: name, form: form, type: 'file', accept: accept, capture: capture, multiple: multiple, required: required, disabled: disabled, className: 'pui-file-native', "aria-describedby": errorId, onKeyDown: (event) => {
|
|
298
|
+
if (event.key === 'Enter')
|
|
298
299
|
event.preventBaseUIHandler();
|
|
299
300
|
}, onChange: (event) => {
|
|
300
301
|
if (!notifying.current) {
|
|
301
302
|
event.preventBaseUIHandler();
|
|
302
|
-
select(Array.from(event.currentTarget.files ?? []),
|
|
303
|
+
select(Array.from(event.currentTarget.files ?? []), 'select');
|
|
303
304
|
}
|
|
304
|
-
} }), _jsxs("label", { htmlFor: inputId, className:
|
|
305
|
+
} }), _jsxs("label", { htmlFor: inputId, className: 'pui-button pui-file-trigger', "data-variant": 'outline', "data-disabled": disabled || undefined, children: [_jsx("svg", { width: '16', height: '16', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '1.6', "aria-hidden": 'true', children: _jsx("path", { d: 'M12 16V3m-5 5 5-5 5 5M4 16v5h16v-5' }) }), labels.choose] }), _jsx("p", { className: 'pui-file-drop-hint', children: labels.drop })] }), _jsx("div", { id: errorId, role: 'alert', className: 'pui-file-errors', children: rejections.length > 0 && (_jsx("ul", { children: rejections.map((rejection, index) => (_jsx("li", { children: labels.rejection(rejection) }, index))) })) }), _jsx(Field.Error, {}), files.length > 0 && (_jsx("ul", { className: 'pui-file-list', role: 'list', children: files.map((file) => {
|
|
305
306
|
const state = metadata.get(file) ?? {
|
|
306
|
-
status:
|
|
307
|
+
status: 'ready',
|
|
307
308
|
progress: null,
|
|
308
309
|
};
|
|
309
310
|
if (!identities.current.has(file))
|
|
310
311
|
identities.current.set(file, `${uid}-${++nextId.current}`);
|
|
311
312
|
const itemId = identities.current.get(file);
|
|
312
|
-
return (_jsxs("li", { className:
|
|
313
|
-
?
|
|
314
|
-
: state.status ===
|
|
315
|
-
?
|
|
316
|
-
: state.status ===
|
|
317
|
-
?
|
|
318
|
-
:
|
|
313
|
+
return (_jsxs("li", { className: 'pui-file-item', children: [_jsxs("div", { className: 'pui-file-info', children: [_jsx("strong", { children: file.name }), _jsx("span", { children: sizeLabel(file.size) }), _jsx(StatusBadge, { tone: state.status === 'success'
|
|
314
|
+
? 'success'
|
|
315
|
+
: state.status === 'error'
|
|
316
|
+
? 'danger'
|
|
317
|
+
: state.status === 'uploading'
|
|
318
|
+
? 'progress'
|
|
319
|
+
: 'neutral', children: labels.status[state.status] })] }), state.status === 'uploading' && (_jsx(Progress.Root, { value: state.progress, "aria-label": labels.progress(file), children: _jsx(Progress.Track, { children: _jsx(Progress.Indicator, {}) }) })), state.error && (_jsx("p", { id: `${itemId}-error`, className: 'pui-file-upload-error', children: state.error })), _jsxs("div", { className: 'pui-file-actions', children: [transport && state.status !== 'success' && (_jsx(Button, { ref: (node) => {
|
|
319
320
|
if (node)
|
|
320
321
|
primaryButtons.current.set(file, node);
|
|
321
322
|
else
|
|
322
323
|
primaryButtons.current.delete(file);
|
|
323
|
-
}, type:
|
|
324
|
-
if (state.status ===
|
|
324
|
+
}, type: 'button', size: 'sm', variant: 'outline', disabled: disabled, "aria-describedby": state.error ? `${itemId}-error` : undefined, "aria-label": `${state.status === 'uploading' ? labels.cancel : state.status === 'ready' ? labels.upload : labels.retry} ${file.name}`, onClick: () => {
|
|
325
|
+
if (state.status === 'uploading')
|
|
325
326
|
cancel(file);
|
|
326
327
|
else
|
|
327
328
|
void upload(file);
|
|
328
|
-
}, children: state.status ===
|
|
329
|
+
}, children: state.status === 'uploading'
|
|
329
330
|
? labels.cancel
|
|
330
|
-
: state.status ===
|
|
331
|
+
: state.status === 'ready'
|
|
331
332
|
? labels.upload
|
|
332
|
-
: labels.retry })), _jsx(Button, { type:
|
|
333
|
+
: labels.retry })), _jsx(Button, { type: 'button', size: 'sm', variant: 'ghost', ref: (node) => {
|
|
333
334
|
if (node)
|
|
334
335
|
removeButtons.current.set(file, node);
|
|
335
336
|
else
|
|
336
337
|
removeButtons.current.delete(file);
|
|
337
338
|
}, disabled: disabled, "aria-label": `${labels.remove} ${file.name}`, onClick: () => {
|
|
338
339
|
setRejections([]);
|
|
339
|
-
if (commit(files.filter((current) => current !== file),
|
|
340
|
+
if (commit(files.filter((current) => current !== file), 'remove'))
|
|
340
341
|
focusPicker.current = file;
|
|
341
342
|
}, children: labels.remove })] })] }, itemId));
|
|
342
|
-
}) })), _jsx("span", { className:
|
|
343
|
+
}) })), _jsx("span", { className: 'pui-visually-hidden', role: 'status', children: announcement })] }));
|
|
343
344
|
});
|
package/dist/filter-bar.d.ts
CHANGED
package/dist/filter-bar.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import * as React from
|
|
4
|
-
const cx = (base, extra) => [base, extra].filter(Boolean).join(
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
const cx = (base, extra) => [base, extra].filter(Boolean).join(' ');
|
|
5
5
|
/** Layout only: filtering, routing and async results remain controlled by the caller. */
|
|
6
6
|
const Root = React.forwardRef(function FilterBarRoot({ label, className, ...props }, ref) {
|
|
7
|
-
return (_jsx("form", { ...props, ref: ref, role:
|
|
7
|
+
return (_jsx("form", { ...props, ref: ref, role: 'search', "aria-label": label, className: cx('pui-filter-bar', className) }));
|
|
8
8
|
});
|
|
9
9
|
const Controls = React.forwardRef(function FilterBarControls({ className, ...props }, ref) {
|
|
10
|
-
return (_jsx("div", { ...props, ref: ref, className: cx(
|
|
10
|
+
return (_jsx("div", { ...props, ref: ref, className: cx('pui-filter-bar-controls', className) }));
|
|
11
11
|
});
|
|
12
|
-
const Field = React.forwardRef(function FilterBarField({ width =
|
|
13
|
-
return (_jsx("label", { ...props, ref: ref, "data-width": width, className: cx(
|
|
12
|
+
const Field = React.forwardRef(function FilterBarField({ width = 'filter', className, ...props }, ref) {
|
|
13
|
+
return (_jsx("label", { ...props, ref: ref, "data-width": width, className: cx('pui-filter-bar-field', className) }));
|
|
14
14
|
});
|
|
15
15
|
const Actions = React.forwardRef(function FilterBarActions({ className, ...props }, ref) {
|
|
16
|
-
return (_jsx("div", { ...props, ref: ref, className: cx(
|
|
16
|
+
return (_jsx("div", { ...props, ref: ref, className: cx('pui-filter-bar-actions', className) }));
|
|
17
17
|
});
|
|
18
18
|
const Summary = React.forwardRef(function FilterBarSummary({ className, ...props }, ref) {
|
|
19
|
-
return (_jsx("div", { role:
|
|
19
|
+
return (_jsx("div", { role: 'status', "aria-atomic": 'true', ...props, ref: ref, className: cx('pui-filter-bar-summary', className) }));
|
|
20
20
|
});
|
|
21
21
|
export const FilterBar = { Root, Controls, Field, Actions, Summary };
|
|
22
22
|
// Flat names for React Server Components, which cannot dot into client exports.
|
package/dist/form-state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as React from
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
/** Share the actual DOM node, including React 19 callback-ref cleanup semantics. */
|
|
3
3
|
export declare function useRootRef<Element extends HTMLElement>(forwarded: React.Ref<Element> | undefined): readonly [React.RefObject<Element | null>, (node: Element | null) => () => void];
|
|
4
4
|
/** Reset stateful primitives with their native form, without firing change callbacks. */
|
package/dist/form-state.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import * as React from
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
/** Share the actual DOM node, including React 19 callback-ref cleanup semantics. */
|
|
4
4
|
export function useRootRef(forwarded) {
|
|
5
5
|
const element = React.useRef(null);
|
|
6
6
|
const attach = React.useCallback((node) => {
|
|
7
7
|
element.current = node;
|
|
8
|
-
const cleanup = typeof forwarded ===
|
|
9
|
-
if (forwarded && typeof forwarded !==
|
|
8
|
+
const cleanup = typeof forwarded === 'function' ? forwarded(node) : undefined;
|
|
9
|
+
if (forwarded && typeof forwarded !== 'function')
|
|
10
10
|
forwarded.current = node;
|
|
11
11
|
return () => {
|
|
12
12
|
if (element.current === node)
|
|
13
13
|
element.current = null;
|
|
14
|
-
if (typeof cleanup ===
|
|
14
|
+
if (typeof cleanup === 'function')
|
|
15
15
|
cleanup();
|
|
16
|
-
else if (typeof forwarded ===
|
|
16
|
+
else if (typeof forwarded === 'function')
|
|
17
17
|
forwarded(null);
|
|
18
18
|
else if (forwarded)
|
|
19
19
|
forwarded.current = null;
|
|
@@ -30,9 +30,9 @@ export function useResetValue(controlled, initial, element, formId, afterReset)
|
|
|
30
30
|
React.useEffect(() => {
|
|
31
31
|
const node = element.current;
|
|
32
32
|
const owner = (formId ? node?.ownerDocument.getElementById(formId) : undefined) ??
|
|
33
|
-
node?.closest(
|
|
34
|
-
Array.from(node?.querySelectorAll(
|
|
35
|
-
if (!owner || owner.tagName !==
|
|
33
|
+
node?.closest('form') ??
|
|
34
|
+
Array.from(node?.querySelectorAll('input') ?? []).find((input) => input.form)?.form;
|
|
35
|
+
if (!owner || owner.tagName !== 'FORM')
|
|
36
36
|
return;
|
|
37
37
|
const pending = new Set();
|
|
38
38
|
const reset = (event) => {
|
|
@@ -49,9 +49,9 @@ export function useResetValue(controlled, initial, element, formId, afterReset)
|
|
|
49
49
|
}, 0);
|
|
50
50
|
pending.add(timer);
|
|
51
51
|
};
|
|
52
|
-
owner.addEventListener(
|
|
52
|
+
owner.addEventListener('reset', reset);
|
|
53
53
|
return () => {
|
|
54
|
-
owner.removeEventListener(
|
|
54
|
+
owner.removeEventListener('reset', reset);
|
|
55
55
|
pending.forEach(clearTimeout);
|
|
56
56
|
};
|
|
57
57
|
}, [element, formId]);
|
package/dist/forms.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { type ComponentSize } from
|
|
3
|
-
import { Form as BaseForm } from
|
|
4
|
-
import { Radio as BaseRadio } from
|
|
5
|
-
import { RadioGroup as BaseRadioGroup } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type ComponentSize } from './sizing.js';
|
|
3
|
+
import { Form as BaseForm } from '@base-ui/react/form';
|
|
4
|
+
import { Radio as BaseRadio } from '@base-ui/react/radio';
|
|
5
|
+
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';
|
|
6
6
|
declare const FieldRoot: React.ForwardRefExoticComponent<Omit<Omit<Omit<import("@base-ui/react/field").FieldRootProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref">, "size"> & {
|
|
7
7
|
size?: ComponentSize;
|
|
8
8
|
} & React.RefAttributes<HTMLDivElement>>;
|
package/dist/forms.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as React from
|
|
4
|
-
import { useComponentSize } from
|
|
5
|
-
import { Field as BaseField } from
|
|
6
|
-
import { Fieldset as BaseFieldset } from
|
|
7
|
-
import { Form as BaseForm } from
|
|
8
|
-
import { Checkbox as BaseCheckbox } from
|
|
9
|
-
import { CheckboxGroup as BaseCheckboxGroup } from
|
|
10
|
-
import { Radio as BaseRadio } from
|
|
11
|
-
import { RadioGroup as BaseRadioGroup } from
|
|
12
|
-
import { Switch as BaseSwitch } from
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { useComponentSize } from './sizing.js';
|
|
5
|
+
import { Field as BaseField } from '@base-ui/react/field';
|
|
6
|
+
import { Fieldset as BaseFieldset } from '@base-ui/react/fieldset';
|
|
7
|
+
import { Form as BaseForm } from '@base-ui/react/form';
|
|
8
|
+
import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
|
|
9
|
+
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';
|
|
10
|
+
import { Radio as BaseRadio } from '@base-ui/react/radio';
|
|
11
|
+
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';
|
|
12
|
+
import { Switch as BaseSwitch } from '@base-ui/react/switch';
|
|
13
13
|
const ChoiceResetPaint = React.createContext(0);
|
|
14
|
-
import { skin, part } from
|
|
15
|
-
const FieldRoot = part(BaseField.Root,
|
|
16
|
-
const FieldLabel = part(BaseField.Label,
|
|
17
|
-
const FieldControl = part(BaseField.Control,
|
|
18
|
-
const FieldDescription = part(BaseField.Description,
|
|
19
|
-
const FieldError = part(BaseField.Error,
|
|
20
|
-
const FieldItem = part(BaseField.Item,
|
|
14
|
+
import { skin, part } from './parts.js';
|
|
15
|
+
const FieldRoot = part(BaseField.Root, 'pui-field');
|
|
16
|
+
const FieldLabel = part(BaseField.Label, 'pui-field-label');
|
|
17
|
+
const FieldControl = part(BaseField.Control, 'pui-input');
|
|
18
|
+
const FieldDescription = part(BaseField.Description, 'pui-field-description');
|
|
19
|
+
const FieldError = part(BaseField.Error, 'pui-field-error');
|
|
20
|
+
const FieldItem = part(BaseField.Item, 'pui-field-item');
|
|
21
21
|
export const Field = {
|
|
22
22
|
...BaseField,
|
|
23
23
|
Root: FieldRoot,
|
|
@@ -29,31 +29,31 @@ export const Field = {
|
|
|
29
29
|
};
|
|
30
30
|
export const Fieldset = {
|
|
31
31
|
...BaseFieldset,
|
|
32
|
-
Root: part(BaseFieldset.Root,
|
|
33
|
-
Legend: part(BaseFieldset.Legend,
|
|
32
|
+
Root: part(BaseFieldset.Root, 'pui-fieldset'),
|
|
33
|
+
Legend: part(BaseFieldset.Legend, 'pui-fieldset-legend'),
|
|
34
34
|
};
|
|
35
35
|
export function Form({ className, ...props }) {
|
|
36
|
-
return
|
|
36
|
+
return _jsx(BaseForm, { ...props, className: skin('pui-form', className) });
|
|
37
37
|
}
|
|
38
38
|
export const Textarea = React.forwardRef(function Textarea({ className, size, ...props }, ref) {
|
|
39
39
|
const scheme = useComponentSize(size);
|
|
40
|
-
return (_jsx("textarea", { "data-ui-size": scheme, ...props, ref: ref, className: [
|
|
40
|
+
return (_jsx("textarea", { "data-ui-size": scheme, ...props, ref: ref, className: ['pui-input pui-textarea', className]
|
|
41
41
|
.filter(Boolean)
|
|
42
|
-
.join(
|
|
42
|
+
.join(' ') }));
|
|
43
43
|
});
|
|
44
|
-
import { useRootRef, useResetValue } from
|
|
44
|
+
import { useRootRef, useResetValue } from './form-state.js';
|
|
45
45
|
const CheckboxRoot = React.forwardRef(function CheckboxRoot({ checked, defaultChecked = false, onCheckedChange, className, form, ...props }, ref) {
|
|
46
46
|
React.useContext(ChoiceResetPaint);
|
|
47
47
|
const [element, attach] = useRootRef(ref);
|
|
48
48
|
const [selected, setSelected] = useResetValue(checked, defaultChecked, element, form);
|
|
49
|
-
return (_jsx(BaseCheckbox.Root, { ...props, form: form, ref: attach, checked: selected, className: skin(
|
|
49
|
+
return (_jsx(BaseCheckbox.Root, { ...props, form: form, ref: attach, checked: selected, className: skin('pui-checkbox', className), onCheckedChange: (next, event) => {
|
|
50
50
|
onCheckedChange?.(next, event);
|
|
51
51
|
if (checked === undefined && !event.isCanceled)
|
|
52
52
|
setSelected(next);
|
|
53
53
|
} }));
|
|
54
54
|
});
|
|
55
55
|
const CheckboxIndicator = React.forwardRef(function CheckboxIndicator({ className, children, ...props }, ref) {
|
|
56
|
-
return (_jsx(BaseCheckbox.Indicator, { ...props, ref: ref, className: skin(
|
|
56
|
+
return (_jsx(BaseCheckbox.Indicator, { ...props, ref: ref, className: skin('pui-checkbox-indicator', className), children: children ?? (_jsxs("svg", { width: '14', height: '14', viewBox: '0 0 20 20', fill: 'none', stroke: 'currentColor', strokeWidth: '2', "aria-hidden": 'true', children: [_jsx("path", { className: 'pui-checkbox-check', d: 'm4 10 4 4 8-8' }), _jsx("path", { className: 'pui-checkbox-mixed', d: 'M4 10h12' })] })) }));
|
|
57
57
|
});
|
|
58
58
|
export const Checkbox = {
|
|
59
59
|
...BaseCheckbox,
|
|
@@ -63,7 +63,7 @@ export const Checkbox = {
|
|
|
63
63
|
export const CheckboxGroup = React.forwardRef(function CheckboxGroup({ value, defaultValue = [], onValueChange, className, ...props }, ref) {
|
|
64
64
|
const [element, attach] = useRootRef(ref);
|
|
65
65
|
const [selected, setSelected, revision] = useResetValue(value, defaultValue, element);
|
|
66
|
-
return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseCheckboxGroup, { ...props, ref: attach, value: selected, className: skin(
|
|
66
|
+
return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseCheckboxGroup, { ...props, ref: attach, value: selected, className: skin('pui-choice-group', className), onValueChange: (next, event) => {
|
|
67
67
|
onValueChange?.(next, event);
|
|
68
68
|
if (value === undefined && !event.isCanceled)
|
|
69
69
|
setSelected(next);
|
|
@@ -72,7 +72,7 @@ export const CheckboxGroup = React.forwardRef(function CheckboxGroup({ value, de
|
|
|
72
72
|
export function RadioGroup({ value, defaultValue, onValueChange, className, form, ref, ...props }) {
|
|
73
73
|
const [element, attach] = useRootRef(ref);
|
|
74
74
|
const [selected, setSelected, revision] = useResetValue(value, defaultValue ?? null, element, form);
|
|
75
|
-
return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseRadioGroup, { ...props, form: form, ref: attach, value: selected, className: skin(
|
|
75
|
+
return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseRadioGroup, { ...props, form: form, ref: attach, value: selected, className: skin('pui-choice-group', className), onValueChange: (next, event) => {
|
|
76
76
|
onValueChange?.(next, event);
|
|
77
77
|
if (value === undefined && !event.isCanceled)
|
|
78
78
|
setSelected(next);
|
|
@@ -80,17 +80,17 @@ export function RadioGroup({ value, defaultValue, onValueChange, className, form
|
|
|
80
80
|
}
|
|
81
81
|
const RadioRoot = React.forwardRef(function RadioRoot({ className, ...props }, ref) {
|
|
82
82
|
React.useContext(ChoiceResetPaint);
|
|
83
|
-
return (_jsx(BaseRadio.Root, { ...props, ref: ref, className: skin(
|
|
83
|
+
return (_jsx(BaseRadio.Root, { ...props, ref: ref, className: skin('pui-radio', className) }));
|
|
84
84
|
});
|
|
85
85
|
export const Radio = {
|
|
86
86
|
...BaseRadio,
|
|
87
87
|
Root: RadioRoot,
|
|
88
|
-
Indicator: part(BaseRadio.Indicator,
|
|
88
|
+
Indicator: part(BaseRadio.Indicator, 'pui-radio-indicator'),
|
|
89
89
|
};
|
|
90
90
|
const SwitchRoot = React.forwardRef(function SwitchRoot({ checked, defaultChecked = false, onCheckedChange, className, form, ...props }, ref) {
|
|
91
91
|
const [element, attach] = useRootRef(ref);
|
|
92
92
|
const [selected, setSelected] = useResetValue(checked, defaultChecked, element, form);
|
|
93
|
-
return (_jsx(BaseSwitch.Root, { ...props, form: form, ref: attach, checked: selected, className: skin(
|
|
93
|
+
return (_jsx(BaseSwitch.Root, { ...props, form: form, ref: attach, checked: selected, className: skin('pui-switch', className), onCheckedChange: (next, event) => {
|
|
94
94
|
onCheckedChange?.(next, event);
|
|
95
95
|
if (checked === undefined && !event.isCanceled)
|
|
96
96
|
setSelected(next);
|
|
@@ -99,7 +99,7 @@ const SwitchRoot = React.forwardRef(function SwitchRoot({ checked, defaultChecke
|
|
|
99
99
|
export const Switch = {
|
|
100
100
|
...BaseSwitch,
|
|
101
101
|
Root: SwitchRoot,
|
|
102
|
-
Thumb: part(BaseSwitch.Thumb,
|
|
102
|
+
Thumb: part(BaseSwitch.Thumb, 'pui-switch-thumb'),
|
|
103
103
|
};
|
|
104
104
|
// Flat names for React Server Components, which cannot dot into client exports.
|
|
105
105
|
export { CheckboxIndicator, CheckboxRoot, FieldControl, FieldDescription, FieldError, FieldItem, FieldLabel, FieldRoot, RadioRoot, SwitchRoot, };
|