@apliteni/apliteni-ui 0.132.0 → 0.133.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/guidelines/file-drop.md +9 -7
- package/package.json +1 -1
- package/react/dist/index.css +40 -0
- package/react/dist/index.d.ts +10 -1
- package/react/dist/index.js +231 -190
- package/src/components/index.js +4 -2
- package/src/styles/card.css +4 -0
- package/src/styles/file-drop.css +39 -0
- package/src/styles/layout.css +6 -4
package/guidelines/file-drop.md
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
**Rule:** At rest, a file drop is one row: the button that opens the picker and the accepted types beside it.
|
|
8
8
|
|
|
9
|
-
**Why:** A tall box holds the page's best space
|
|
9
|
+
**Why:** A tall box holds the page's best space for a file that arrives once a month.
|
|
10
10
|
|
|
11
11
|
**Do:** Put an Upload button and “PDF or CSV, up to 10 MB” on one line above the list they feed.
|
|
12
12
|
|
|
13
13
|
**Don't:** Draw a tall dashed box with a glyph, an invitation and a button stacked inside it.
|
|
14
14
|
|
|
15
|
-
**Except:** A page
|
|
15
|
+
**Except:** A page that exists to receive one file may use the field-sized picker, which has its own label. An empty page may show a dashed drop area until the first file arrives. See #458 for this exception.
|
|
16
16
|
|
|
17
17
|
## Paint the target only while a file is over it
|
|
18
18
|
|
|
@@ -26,15 +26,17 @@
|
|
|
26
26
|
|
|
27
27
|
**Don't:** Cover the whole window when one panel accepts the file.
|
|
28
28
|
|
|
29
|
+
**Except:** A page that takes files anywhere may cover the whole page, slightly transparent and blurred over a table. See #458 for this exception.
|
|
30
|
+
|
|
29
31
|
## Keep the file in the row it arrived in
|
|
30
32
|
|
|
31
33
|
<!-- rule: in-the-row -->
|
|
32
34
|
|
|
33
35
|
**Rule:** After the drop, the file's name, size and progress take the place the button was in, with remove on the name's line.
|
|
34
36
|
|
|
35
|
-
**Why:** A row that changes in place keeps the page still
|
|
37
|
+
**Why:** A row that changes in place keeps the page still during the upload.
|
|
36
38
|
|
|
37
|
-
**Do:**
|
|
39
|
+
**Do:** Put remove at the end of the name's line, the size under it, and the progress track below both.
|
|
38
40
|
|
|
39
41
|
**Don't:** Push the list down with a progress card, or open a dialog over the page.
|
|
40
42
|
|
|
@@ -44,7 +46,7 @@
|
|
|
44
46
|
|
|
45
47
|
**Rule:** A refused file keeps its place, says what it did wrong under its name, and offers Retry beside Remove.
|
|
46
48
|
|
|
47
|
-
**Why:** A row that drops the file sends the reader back to choosing one.
|
|
49
|
+
**Why:** A row that drops the file sends the reader back to choosing one.
|
|
48
50
|
|
|
49
51
|
**Do:** Keep the name on its line and say “Larger than 10 MB” under it, with Retry.
|
|
50
52
|
|
|
@@ -80,8 +82,8 @@
|
|
|
80
82
|
|
|
81
83
|
**Rule:** Use a row where the file joins a list on the page, a region when one panel owns the file, and a dialog only when the upload needs answers of its own.
|
|
82
84
|
|
|
83
|
-
**Why:** A dialog that asks nothing is one more thing to dismiss.
|
|
85
|
+
**Why:** A dialog that asks nothing is one more thing to dismiss. A drawing would show one container, not the choice.
|
|
84
86
|
|
|
85
|
-
**Do:** Take a statement into the row under the statements it joins
|
|
87
|
+
**Do:** Take a statement into the row under the statements it joins.
|
|
86
88
|
|
|
87
89
|
**Don't:** Open a dialog for one file that the row behind it could have taken.
|
package/package.json
CHANGED
package/react/dist/index.css
CHANGED
|
@@ -847,6 +847,43 @@
|
|
|
847
847
|
.ui-drop.is-disabled .ui-drop__name {
|
|
848
848
|
color: var(--disabled-ink);
|
|
849
849
|
}
|
|
850
|
+
.ui-drop--area {
|
|
851
|
+
border: 1px dashed var(--border-strong);
|
|
852
|
+
border-radius: var(--radius-lg);
|
|
853
|
+
padding: var(--space-4);
|
|
854
|
+
}
|
|
855
|
+
.ui-drop--area.is-dragging {
|
|
856
|
+
border-color: var(--accent);
|
|
857
|
+
}
|
|
858
|
+
@media (max-width: 560px) {
|
|
859
|
+
.ui-drop--area {
|
|
860
|
+
padding: var(--space-3);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
.ui-drop--page {
|
|
864
|
+
position: fixed;
|
|
865
|
+
inset: calc(var(--ui-app-band, 0px) + var(--ui-app-top, 0px) + var(--space-4)) var(--space-4) var(--space-4);
|
|
866
|
+
z-index: var(--z-overlay);
|
|
867
|
+
display: flex;
|
|
868
|
+
align-items: center;
|
|
869
|
+
justify-content: center;
|
|
870
|
+
pointer-events: none;
|
|
871
|
+
background: var(--bg);
|
|
872
|
+
}
|
|
873
|
+
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
|
|
874
|
+
.ui-drop--page {
|
|
875
|
+
background: color-mix(in srgb, var(--bg) 80%, transparent);
|
|
876
|
+
-webkit-backdrop-filter: blur(var(--space-2));
|
|
877
|
+
backdrop-filter: blur(var(--space-2));
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
881
|
+
.ui-drop--page {
|
|
882
|
+
background: var(--bg);
|
|
883
|
+
-webkit-backdrop-filter: none;
|
|
884
|
+
backdrop-filter: none;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
850
887
|
|
|
851
888
|
/* src/Toast.css */
|
|
852
889
|
.rx-toast-stack {
|
|
@@ -907,6 +944,9 @@
|
|
|
907
944
|
gap: var(--space-1);
|
|
908
945
|
padding-inline: var(--space-2);
|
|
909
946
|
}
|
|
947
|
+
.ui-react-app .ui-app__bar:not(:has(> .ui-app__menu:first-child)) {
|
|
948
|
+
padding-inline-start: var(--space-4);
|
|
949
|
+
}
|
|
910
950
|
.ui-react-app .ui-app__bar-gap {
|
|
911
951
|
display: none;
|
|
912
952
|
}
|
package/react/dist/index.d.ts
CHANGED
|
@@ -759,6 +759,12 @@ type FileDropProps = {
|
|
|
759
759
|
label?: string;
|
|
760
760
|
/** The accepted types and the size limit, stated once beside the button. */
|
|
761
761
|
note?: string;
|
|
762
|
+
/** Makes the drop an empty page's area: a dashed box around a first-run block with this title,
|
|
763
|
+
* the note and the button. The block stands in for the row and `children`, and the page
|
|
764
|
+
* leaves the area when the first file arrives, so it never shows a file in hand. */
|
|
765
|
+
title?: string;
|
|
766
|
+
/** Lets the picker take several files. */
|
|
767
|
+
multiple?: boolean;
|
|
762
768
|
/** Filters the system picker only; the consumer still validates the file. */
|
|
763
769
|
accept?: string;
|
|
764
770
|
/** The words on the drop target. */
|
|
@@ -771,14 +777,17 @@ type FileDropProps = {
|
|
|
771
777
|
/** Drives the target from a parent that owns the drag region. */
|
|
772
778
|
dragging?: boolean;
|
|
773
779
|
disabled?: boolean;
|
|
780
|
+
/** The first file chosen or dropped. */
|
|
774
781
|
onFile?: (file: File) => void;
|
|
782
|
+
/** Every file chosen or dropped, together. A consumer may pass both props. */
|
|
783
|
+
onFiles?: (files: File[]) => void;
|
|
775
784
|
onRemove?: () => void;
|
|
776
785
|
onRetry?: () => void;
|
|
777
786
|
/** What the region accepts the file for; the target covers it while dragging. */
|
|
778
787
|
children?: ReactNode;
|
|
779
788
|
className?: string;
|
|
780
789
|
};
|
|
781
|
-
declare function FileDrop({ label, note, accept, dropLabel, removeLabel, retryLabel, file, dragging, disabled, onFile, onRemove, onRetry, children, className, }: FileDropProps): react.JSX.Element;
|
|
790
|
+
declare function FileDrop({ label, note, title, multiple, accept, dropLabel, removeLabel, retryLabel, file, dragging, disabled, onFile, onFiles, onRemove, onRetry, children, className, }: FileDropProps): react.JSX.Element;
|
|
782
791
|
|
|
783
792
|
type SearchFieldProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'aria-label'> & {
|
|
784
793
|
/** The control's name. A toolbar search box shows no label, so this is the
|
package/react/dist/index.js
CHANGED
|
@@ -219,8 +219,7 @@ var Button = forwardRef3(function Button2({
|
|
|
219
219
|
// src/primitives/Badge.tsx
|
|
220
220
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
221
221
|
function Badge({ variant = "neutral", children }) {
|
|
222
|
-
|
|
223
|
-
return /* @__PURE__ */ jsx5("span", { className: cls, children });
|
|
222
|
+
return /* @__PURE__ */ jsx5("span", { className: `ui-badge ui-badge--${variant}`, children });
|
|
224
223
|
}
|
|
225
224
|
|
|
226
225
|
// src/primitives/Avatar.tsx
|
|
@@ -3313,7 +3312,31 @@ function FileField({ label, hint, error, required, disabled, onFileChange, class
|
|
|
3313
3312
|
|
|
3314
3313
|
// src/FileDrop.tsx
|
|
3315
3314
|
import { useRef as useRef17, useState as useState12 } from "react";
|
|
3316
|
-
|
|
3315
|
+
|
|
3316
|
+
// src/EmptyState.tsx
|
|
3317
|
+
import { icon as kitIcon2, illo } from "@apliteni/apliteni-ui";
|
|
3318
|
+
import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3319
|
+
var cases = {
|
|
3320
|
+
"first-run": { title: "Nothing needs you yet", sub: "New items will appear here when they need your attention.", icon: "check" },
|
|
3321
|
+
"no-matches": { title: "No results in this view", sub: "Try another search or clear your filters.", icon: "search" },
|
|
3322
|
+
"not-found": { title: "We can't find that page", sub: "Check the address or return to the home page.", icon: "folder" },
|
|
3323
|
+
"not-yet-built": { title: "This ships later", sub: "This screen is not available yet. Check back later.", icon: "clock" }
|
|
3324
|
+
};
|
|
3325
|
+
function EmptyState({ variant = "first-run", title, sub, icon: icon8, art, actions }) {
|
|
3326
|
+
const preset = cases[variant];
|
|
3327
|
+
const heading = title ?? preset.title;
|
|
3328
|
+
const guidance = sub ?? preset.sub;
|
|
3329
|
+
const glyph = icon8 ?? preset.icon;
|
|
3330
|
+
return /* @__PURE__ */ jsxs26("div", { className: "ui-empty", children: [
|
|
3331
|
+
art ? typeof art === "string" ? /* @__PURE__ */ jsx31("div", { className: "ui-empty__art", dangerouslySetInnerHTML: { __html: /<svg/.test(art) ? art : illo(art) } }) : /* @__PURE__ */ jsx31("div", { className: "ui-empty__art", "aria-hidden": "true", children: art }) : glyph ? /* @__PURE__ */ jsx31("div", { className: "ui-empty__icon", dangerouslySetInnerHTML: { __html: kitIcon2(glyph) } }) : null,
|
|
3332
|
+
heading && /* @__PURE__ */ jsx31("div", { className: "ui-empty__title", children: heading }),
|
|
3333
|
+
guidance && /* @__PURE__ */ jsx31("div", { className: "ui-empty__sub", children: guidance }),
|
|
3334
|
+
actions && /* @__PURE__ */ jsx31("div", { className: "ui-empty__actions", children: actions })
|
|
3335
|
+
] });
|
|
3336
|
+
}
|
|
3337
|
+
|
|
3338
|
+
// src/FileDrop.tsx
|
|
3339
|
+
import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3317
3340
|
var MARKS = {
|
|
3318
3341
|
uploading: "clock",
|
|
3319
3342
|
done: "circleCheck",
|
|
@@ -3333,6 +3356,8 @@ var cx7 = (...a) => a.filter(Boolean).join(" ");
|
|
|
3333
3356
|
function FileDrop({
|
|
3334
3357
|
label = "Upload",
|
|
3335
3358
|
note,
|
|
3359
|
+
title,
|
|
3360
|
+
multiple,
|
|
3336
3361
|
accept,
|
|
3337
3362
|
dropLabel = "Drop to upload",
|
|
3338
3363
|
removeLabel = "Remove",
|
|
@@ -3341,6 +3366,7 @@ function FileDrop({
|
|
|
3341
3366
|
dragging,
|
|
3342
3367
|
disabled,
|
|
3343
3368
|
onFile,
|
|
3369
|
+
onFiles,
|
|
3344
3370
|
onRemove,
|
|
3345
3371
|
onRetry,
|
|
3346
3372
|
children,
|
|
@@ -3356,118 +3382,155 @@ function FileDrop({
|
|
|
3356
3382
|
const showSize = Boolean(file?.size) && status !== "error";
|
|
3357
3383
|
const showTarget = (dragging ?? over) && !disabled;
|
|
3358
3384
|
const take = (chosen) => {
|
|
3359
|
-
if (chosen
|
|
3385
|
+
if (!chosen.length || disabled) return;
|
|
3386
|
+
onFile?.(chosen[0]);
|
|
3387
|
+
onFiles?.(chosen);
|
|
3388
|
+
};
|
|
3389
|
+
const pick = () => {
|
|
3390
|
+
if (!disabled) input.current?.click();
|
|
3391
|
+
};
|
|
3392
|
+
const picker = /* @__PURE__ */ jsx32(
|
|
3393
|
+
"input",
|
|
3394
|
+
{
|
|
3395
|
+
ref: input,
|
|
3396
|
+
type: "file",
|
|
3397
|
+
accept,
|
|
3398
|
+
multiple,
|
|
3399
|
+
disabled,
|
|
3400
|
+
hidden: true,
|
|
3401
|
+
tabIndex: -1,
|
|
3402
|
+
onClick: (event) => event.stopPropagation(),
|
|
3403
|
+
onChange: (event) => {
|
|
3404
|
+
take(Array.from(event.currentTarget.files ?? []));
|
|
3405
|
+
event.currentTarget.value = "";
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
);
|
|
3409
|
+
const drag = {
|
|
3410
|
+
onDragOver: (event) => {
|
|
3411
|
+
if (disabled || !carriesFiles(event)) return;
|
|
3412
|
+
event.preventDefault();
|
|
3413
|
+
setOver(true);
|
|
3414
|
+
},
|
|
3415
|
+
onDragLeave: (event) => {
|
|
3416
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setOver(false);
|
|
3417
|
+
},
|
|
3418
|
+
onDrop: (event) => {
|
|
3419
|
+
if (disabled || !carriesFiles(event)) return;
|
|
3420
|
+
event.preventDefault();
|
|
3421
|
+
setOver(false);
|
|
3422
|
+
take(Array.from(event.dataTransfer.files));
|
|
3423
|
+
}
|
|
3360
3424
|
};
|
|
3361
|
-
return /* @__PURE__ */
|
|
3425
|
+
if (title !== void 0) return /* @__PURE__ */ jsxs27(
|
|
3362
3426
|
"div",
|
|
3363
3427
|
{
|
|
3364
|
-
className: cx7("ui-drop", disabled && "is-disabled", className),
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
event.preventDefault();
|
|
3368
|
-
setOver(true);
|
|
3369
|
-
},
|
|
3370
|
-
onDragLeave: (event) => {
|
|
3371
|
-
if (!event.currentTarget.contains(event.relatedTarget)) setOver(false);
|
|
3372
|
-
},
|
|
3373
|
-
onDrop: (event) => {
|
|
3374
|
-
if (disabled || !carriesFiles(event)) return;
|
|
3375
|
-
event.preventDefault();
|
|
3376
|
-
setOver(false);
|
|
3377
|
-
take(event.dataTransfer.files[0]);
|
|
3378
|
-
},
|
|
3428
|
+
className: cx7("ui-drop", "ui-drop--area", showTarget && "is-dragging", disabled && "is-disabled", className),
|
|
3429
|
+
onClick: pick,
|
|
3430
|
+
...drag,
|
|
3379
3431
|
children: [
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
] }),
|
|
3388
|
-
(onRemove || status === "error" && onRetry) && /* @__PURE__ */ jsxs26("span", { className: "ui-drop__actions", children: [
|
|
3389
|
-
status === "error" && onRetry && /* @__PURE__ */ jsx31(Button, { size: "sm", icon: "refresh", onClick: onRetry, disabled, children: retryLabel }),
|
|
3390
|
-
onRemove && /* @__PURE__ */ jsx31(
|
|
3391
|
-
Button,
|
|
3392
|
-
{
|
|
3393
|
-
variant: "ghost",
|
|
3394
|
-
size: "sm",
|
|
3395
|
-
onClick: onRemove,
|
|
3396
|
-
disabled,
|
|
3397
|
-
children: removeLabel
|
|
3398
|
-
}
|
|
3399
|
-
)
|
|
3400
|
-
] })
|
|
3401
|
-
] }),
|
|
3402
|
-
(showSize || showWord) && /* @__PURE__ */ jsxs26(
|
|
3403
|
-
"div",
|
|
3404
|
-
{
|
|
3405
|
-
className: cx7("ui-drop__facts", status === "error" && "ui-drop__error"),
|
|
3406
|
-
role: status === "error" ? "alert" : void 0,
|
|
3407
|
-
children: [
|
|
3408
|
-
showSize && /* @__PURE__ */ jsx31("span", { className: "ui-drop__size", children: file.size }),
|
|
3409
|
-
showWord && /* @__PURE__ */ jsxs26("span", { className: "ui-drop__state", children: [
|
|
3410
|
-
/* @__PURE__ */ jsx31(Icon, { name: MARKS[status] }),
|
|
3411
|
-
/* @__PURE__ */ jsx31("span", { className: "ui-drop__word", title: word, children: word })
|
|
3412
|
-
] })
|
|
3413
|
-
]
|
|
3414
|
-
}
|
|
3415
|
-
),
|
|
3416
|
-
hasBar && /* @__PURE__ */ jsx31(
|
|
3417
|
-
"span",
|
|
3418
|
-
{
|
|
3419
|
-
className: "ui-drop__bar",
|
|
3420
|
-
role: "progressbar",
|
|
3421
|
-
"aria-label": `${word} ${file.name}`,
|
|
3422
|
-
"aria-valuenow": file.progress,
|
|
3423
|
-
"aria-valuemin": 0,
|
|
3424
|
-
"aria-valuemax": 100,
|
|
3425
|
-
children: /* @__PURE__ */ jsx31("span", { style: { width: `${file.progress}%` } })
|
|
3426
|
-
}
|
|
3427
|
-
)
|
|
3428
|
-
] }) : /* @__PURE__ */ jsxs26(Fragment10, { children: [
|
|
3429
|
-
/* @__PURE__ */ jsx31(
|
|
3432
|
+
/* @__PURE__ */ jsx32(
|
|
3433
|
+
EmptyState,
|
|
3434
|
+
{
|
|
3435
|
+
icon: "upload",
|
|
3436
|
+
title,
|
|
3437
|
+
sub: note ?? "",
|
|
3438
|
+
actions: /* @__PURE__ */ jsx32(
|
|
3430
3439
|
Button,
|
|
3431
3440
|
{
|
|
3441
|
+
variant: "primary",
|
|
3432
3442
|
size: "sm",
|
|
3433
3443
|
icon: "upload",
|
|
3434
3444
|
disabled,
|
|
3435
|
-
onClick: () =>
|
|
3445
|
+
onClick: (event) => {
|
|
3446
|
+
event.stopPropagation();
|
|
3447
|
+
pick();
|
|
3448
|
+
},
|
|
3436
3449
|
children: label
|
|
3437
3450
|
}
|
|
3438
|
-
)
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
"input",
|
|
3443
|
-
{
|
|
3444
|
-
ref: input,
|
|
3445
|
-
type: "file",
|
|
3446
|
-
accept,
|
|
3447
|
-
disabled,
|
|
3448
|
-
hidden: true,
|
|
3449
|
-
tabIndex: -1,
|
|
3450
|
-
onChange: (event) => {
|
|
3451
|
-
take(event.currentTarget.files?.[0]);
|
|
3452
|
-
event.currentTarget.value = "";
|
|
3453
|
-
}
|
|
3454
|
-
}
|
|
3455
|
-
)
|
|
3456
|
-
] }),
|
|
3457
|
-
showTarget && /* @__PURE__ */ jsx31("div", { className: "ui-drop__target", "aria-hidden": "true", children: dropLabel })
|
|
3451
|
+
)
|
|
3452
|
+
}
|
|
3453
|
+
),
|
|
3454
|
+
picker
|
|
3458
3455
|
]
|
|
3459
3456
|
}
|
|
3460
3457
|
);
|
|
3458
|
+
return /* @__PURE__ */ jsxs27("div", { className: cx7("ui-drop", disabled && "is-disabled", className), ...drag, children: [
|
|
3459
|
+
children,
|
|
3460
|
+
/* @__PURE__ */ jsxs27("div", { className: "ui-drop__row", children: [
|
|
3461
|
+
file ? /* @__PURE__ */ jsxs27("div", { className: cx7("ui-drop__file", status === "error" && "ui-drop__file--failed"), children: [
|
|
3462
|
+
/* @__PURE__ */ jsxs27("div", { className: "ui-drop__line", children: [
|
|
3463
|
+
/* @__PURE__ */ jsxs27("span", { className: "ui-drop__name", title: file.name, children: [
|
|
3464
|
+
/* @__PURE__ */ jsx32("span", { className: "ui-drop__stem", children: stem }),
|
|
3465
|
+
/* @__PURE__ */ jsx32("span", { className: "ui-drop__ext", children: ext })
|
|
3466
|
+
] }),
|
|
3467
|
+
(onRemove || status === "error" && onRetry) && /* @__PURE__ */ jsxs27("span", { className: "ui-drop__actions", children: [
|
|
3468
|
+
status === "error" && onRetry && /* @__PURE__ */ jsx32(Button, { size: "sm", icon: "refresh", onClick: onRetry, disabled, children: retryLabel }),
|
|
3469
|
+
onRemove && /* @__PURE__ */ jsx32(
|
|
3470
|
+
Button,
|
|
3471
|
+
{
|
|
3472
|
+
variant: "ghost",
|
|
3473
|
+
size: "sm",
|
|
3474
|
+
onClick: onRemove,
|
|
3475
|
+
disabled,
|
|
3476
|
+
children: removeLabel
|
|
3477
|
+
}
|
|
3478
|
+
)
|
|
3479
|
+
] })
|
|
3480
|
+
] }),
|
|
3481
|
+
(showSize || showWord) && /* @__PURE__ */ jsxs27(
|
|
3482
|
+
"div",
|
|
3483
|
+
{
|
|
3484
|
+
className: cx7("ui-drop__facts", status === "error" && "ui-drop__error"),
|
|
3485
|
+
role: status === "error" ? "alert" : void 0,
|
|
3486
|
+
children: [
|
|
3487
|
+
showSize && /* @__PURE__ */ jsx32("span", { className: "ui-drop__size", children: file.size }),
|
|
3488
|
+
showWord && /* @__PURE__ */ jsxs27("span", { className: "ui-drop__state", children: [
|
|
3489
|
+
/* @__PURE__ */ jsx32(Icon, { name: MARKS[status] }),
|
|
3490
|
+
/* @__PURE__ */ jsx32("span", { className: "ui-drop__word", title: word, children: word })
|
|
3491
|
+
] })
|
|
3492
|
+
]
|
|
3493
|
+
}
|
|
3494
|
+
),
|
|
3495
|
+
hasBar && /* @__PURE__ */ jsx32(
|
|
3496
|
+
"span",
|
|
3497
|
+
{
|
|
3498
|
+
className: "ui-drop__bar",
|
|
3499
|
+
role: "progressbar",
|
|
3500
|
+
"aria-label": `${word} ${file.name}`,
|
|
3501
|
+
"aria-valuenow": file.progress,
|
|
3502
|
+
"aria-valuemin": 0,
|
|
3503
|
+
"aria-valuemax": 100,
|
|
3504
|
+
children: /* @__PURE__ */ jsx32("span", { style: { width: `${file.progress}%` } })
|
|
3505
|
+
}
|
|
3506
|
+
)
|
|
3507
|
+
] }) : /* @__PURE__ */ jsxs27(Fragment10, { children: [
|
|
3508
|
+
/* @__PURE__ */ jsx32(
|
|
3509
|
+
Button,
|
|
3510
|
+
{
|
|
3511
|
+
size: "sm",
|
|
3512
|
+
icon: "upload",
|
|
3513
|
+
disabled,
|
|
3514
|
+
onClick: pick,
|
|
3515
|
+
children: label
|
|
3516
|
+
}
|
|
3517
|
+
),
|
|
3518
|
+
note && /* @__PURE__ */ jsx32("p", { className: "ui-drop__note", children: note })
|
|
3519
|
+
] }),
|
|
3520
|
+
picker
|
|
3521
|
+
] }),
|
|
3522
|
+
showTarget && /* @__PURE__ */ jsx32("div", { className: "ui-drop__target", "aria-hidden": "true", children: dropLabel })
|
|
3523
|
+
] });
|
|
3461
3524
|
}
|
|
3462
3525
|
|
|
3463
3526
|
// src/SearchField.tsx
|
|
3464
3527
|
import { forwardRef as forwardRef7 } from "react";
|
|
3465
3528
|
import { icon as icon6 } from "@apliteni/apliteni-ui";
|
|
3466
|
-
import { jsx as
|
|
3529
|
+
import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3467
3530
|
var SearchField = forwardRef7(function SearchField2({ ariaLabel, className, ...props }, ref) {
|
|
3468
|
-
return /* @__PURE__ */
|
|
3469
|
-
/* @__PURE__ */
|
|
3470
|
-
/* @__PURE__ */
|
|
3531
|
+
return /* @__PURE__ */ jsxs28("div", { className: "ui-input-group", children: [
|
|
3532
|
+
/* @__PURE__ */ jsx33("span", { className: "ui-input-group__icon", dangerouslySetInnerHTML: { __html: icon6("search") } }),
|
|
3533
|
+
/* @__PURE__ */ jsx33(
|
|
3471
3534
|
"input",
|
|
3472
3535
|
{
|
|
3473
3536
|
ref,
|
|
@@ -3483,7 +3546,7 @@ var SearchField = forwardRef7(function SearchField2({ ariaLabel, className, ...p
|
|
|
3483
3546
|
// src/Toast.tsx
|
|
3484
3547
|
import { createContext as createContext3, useCallback as useCallback6, useContext as useContext3, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef18, useState as useState13 } from "react";
|
|
3485
3548
|
import { createPortal as createPortal4 } from "react-dom";
|
|
3486
|
-
import { jsx as
|
|
3549
|
+
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3487
3550
|
var Context = createContext3(null);
|
|
3488
3551
|
var glyphs = { success: "circleCheck", danger: "circleX", warn: "circleAlert", info: "info", neutral: "bolt" };
|
|
3489
3552
|
function useToast() {
|
|
@@ -3531,7 +3594,7 @@ function Notice({ notice, remove }) {
|
|
|
3531
3594
|
remaining.current = Math.max(0, remaining.current - (Date.now() - started));
|
|
3532
3595
|
};
|
|
3533
3596
|
}, [dismiss, leaving2, paused, timed]);
|
|
3534
|
-
return /* @__PURE__ */
|
|
3597
|
+
return /* @__PURE__ */ jsxs29(
|
|
3535
3598
|
"div",
|
|
3536
3599
|
{
|
|
3537
3600
|
ref: root,
|
|
@@ -3545,12 +3608,12 @@ function Notice({ notice, remove }) {
|
|
|
3545
3608
|
if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);
|
|
3546
3609
|
},
|
|
3547
3610
|
children: [
|
|
3548
|
-
/* @__PURE__ */
|
|
3549
|
-
/* @__PURE__ */
|
|
3550
|
-
/* @__PURE__ */
|
|
3551
|
-
!notice.compact && notice.text && /* @__PURE__ */
|
|
3611
|
+
/* @__PURE__ */ jsx34("span", { className: "ui-toast__icon", children: /* @__PURE__ */ jsx34(Icon, { name: glyphs[tone] }) }),
|
|
3612
|
+
/* @__PURE__ */ jsxs29("div", { className: "ui-toast__body", children: [
|
|
3613
|
+
/* @__PURE__ */ jsx34("div", { className: "ui-toast__title", children: notice.title }),
|
|
3614
|
+
!notice.compact && notice.text && /* @__PURE__ */ jsx34("div", { className: "ui-toast__text", children: notice.text })
|
|
3552
3615
|
] }),
|
|
3553
|
-
notice.action && /* @__PURE__ */
|
|
3616
|
+
notice.action && /* @__PURE__ */ jsx34(
|
|
3554
3617
|
"button",
|
|
3555
3618
|
{
|
|
3556
3619
|
type: "button",
|
|
@@ -3565,8 +3628,8 @@ function Notice({ notice, remove }) {
|
|
|
3565
3628
|
children: notice.action.label
|
|
3566
3629
|
}
|
|
3567
3630
|
),
|
|
3568
|
-
notice.dismissible !== false && /* @__PURE__ */
|
|
3569
|
-
timed && /* @__PURE__ */
|
|
3631
|
+
notice.dismissible !== false && /* @__PURE__ */ jsx34("button", { type: "button", className: "ui-toast__close", "aria-label": "Dismiss", disabled: leaving2, onClick: dismiss, children: /* @__PURE__ */ jsx34(Icon, { name: "x" }) }),
|
|
3632
|
+
timed && /* @__PURE__ */ jsx34(
|
|
3570
3633
|
"span",
|
|
3571
3634
|
{
|
|
3572
3635
|
className: "ui-toast__timer is-running",
|
|
@@ -3608,10 +3671,10 @@ function Toast({ children }) {
|
|
|
3608
3671
|
setEntries((current) => [...current, { id, notice, remove }]);
|
|
3609
3672
|
}, []);
|
|
3610
3673
|
usePublishedReach(stack2, entries.length);
|
|
3611
|
-
return /* @__PURE__ */
|
|
3674
|
+
return /* @__PURE__ */ jsxs29(Context.Provider, { value: push, children: [
|
|
3612
3675
|
children,
|
|
3613
3676
|
typeof document !== "undefined" && createPortal4(
|
|
3614
|
-
/* @__PURE__ */
|
|
3677
|
+
/* @__PURE__ */ jsx34("div", { className: "ui-toast-stack rx-toast-stack", ref: stack2, children: entries.map((entry) => /* @__PURE__ */ jsx34(Notice, { notice: entry.notice, remove: entry.remove }, entry.id)) }),
|
|
3615
3678
|
document.body
|
|
3616
3679
|
)
|
|
3617
3680
|
] });
|
|
@@ -3624,7 +3687,7 @@ import { paletteHotkey, prism, railCollapsed } from "@apliteni/apliteni-ui";
|
|
|
3624
3687
|
// src/SidebarNav.tsx
|
|
3625
3688
|
import { forwardRef as forwardRef8, useEffect as useEffect13, useId as useId11, useState as useState14 } from "react";
|
|
3626
3689
|
import { ENTRANCE_FALLBACK_MS } from "@apliteni/apliteni-ui/motion";
|
|
3627
|
-
import { Fragment as Fragment11, jsx as
|
|
3690
|
+
import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3628
3691
|
var badgeText = (badge) => typeof badge === "object" ? badge.text : badge;
|
|
3629
3692
|
function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
|
|
3630
3693
|
const uid = useId11();
|
|
@@ -3650,15 +3713,15 @@ function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
|
|
|
3650
3713
|
item.disabled && "is-disabled",
|
|
3651
3714
|
item.danger && "is-danger"
|
|
3652
3715
|
].filter(Boolean).join(" ");
|
|
3653
|
-
const children = /* @__PURE__ */
|
|
3654
|
-
(item.leading ?? item.icon) && /* @__PURE__ */
|
|
3655
|
-
/* @__PURE__ */
|
|
3656
|
-
count != null && count !== "" && /* @__PURE__ */
|
|
3657
|
-
group && /* @__PURE__ */
|
|
3716
|
+
const children = /* @__PURE__ */ jsxs30(Fragment11, { children: [
|
|
3717
|
+
(item.leading ?? item.icon) && /* @__PURE__ */ jsx35("span", { className: "ui-nav__ic", children: item.leading ?? /* @__PURE__ */ jsx35(Icon, { name: item.icon }) }),
|
|
3718
|
+
/* @__PURE__ */ jsx35("span", { className: "ui-nav__label", children: item.label }),
|
|
3719
|
+
count != null && count !== "" && /* @__PURE__ */ jsx35("span", { className: `ui-nav__badge is-${typeof item.badge === "object" ? item.badge.tone ?? "neutral" : "neutral"}`, children: count }),
|
|
3720
|
+
group && /* @__PURE__ */ jsx35("span", { className: "ui-nav__caret", "aria-hidden": "true" })
|
|
3658
3721
|
] });
|
|
3659
3722
|
const common = { className, "aria-label": name, title: collapsed ? name : void 0, children };
|
|
3660
|
-
if (group) return /* @__PURE__ */
|
|
3661
|
-
/* @__PURE__ */
|
|
3723
|
+
if (group) return /* @__PURE__ */ jsxs30("li", { className: `ui-nav__group${open ? " is-open" : ""}`, children: [
|
|
3724
|
+
/* @__PURE__ */ jsx35(
|
|
3662
3725
|
"button",
|
|
3663
3726
|
{
|
|
3664
3727
|
...common,
|
|
@@ -3672,22 +3735,22 @@ function Row({ item, active, activeIs, collapsed, renderLink, sub }) {
|
|
|
3672
3735
|
}
|
|
3673
3736
|
}
|
|
3674
3737
|
),
|
|
3675
|
-
/* @__PURE__ */
|
|
3738
|
+
/* @__PURE__ */ jsx35("ul", { id: uid, className: `ui-nav__sub${entering ? " is-entering" : ""}`, hidden: !open, onAnimationEnd: () => setEntering(false), children: item.items.map((child) => /* @__PURE__ */ jsx35(Row, { item: child, active, activeIs, collapsed, renderLink, sub: true }, child.id)) })
|
|
3676
3739
|
] });
|
|
3677
|
-
if (item.disabled) return /* @__PURE__ */
|
|
3740
|
+
if (item.disabled) return /* @__PURE__ */ jsx35("li", { children: /* @__PURE__ */ jsx35("span", { ...common, role: "link", "aria-disabled": "true" }) });
|
|
3678
3741
|
const props = {
|
|
3679
3742
|
...common,
|
|
3680
3743
|
href: item.href ?? `#${item.id}`,
|
|
3681
3744
|
target: item.target,
|
|
3682
3745
|
"aria-current": isActive ? activeIs === "section" ? "true" : "page" : void 0
|
|
3683
3746
|
};
|
|
3684
|
-
return /* @__PURE__ */
|
|
3747
|
+
return /* @__PURE__ */ jsx35("li", { children: renderLink ? renderLink(item, props) : /* @__PURE__ */ jsx35("a", { ...props }) });
|
|
3685
3748
|
}
|
|
3686
3749
|
function Section({ section, ...props }) {
|
|
3687
3750
|
const uid = useId11();
|
|
3688
|
-
return /* @__PURE__ */
|
|
3689
|
-
section.label && /* @__PURE__ */
|
|
3690
|
-
/* @__PURE__ */
|
|
3751
|
+
return /* @__PURE__ */ jsxs30("div", { className: "ui-nav__section", children: [
|
|
3752
|
+
section.label && /* @__PURE__ */ jsx35("div", { className: "ui-nav__cap", id: uid, "aria-hidden": props.collapsed || void 0, children: section.label }),
|
|
3753
|
+
/* @__PURE__ */ jsx35("ul", { className: "ui-nav__list", "aria-labelledby": section.label ? uid : void 0, children: section.items.map((item) => /* @__PURE__ */ jsx35(Row, { item, ...props }, item.id)) })
|
|
3691
3754
|
] });
|
|
3692
3755
|
}
|
|
3693
3756
|
var SidebarNav = forwardRef8(function SidebarNav2({
|
|
@@ -3702,8 +3765,8 @@ var SidebarNav = forwardRef8(function SidebarNav2({
|
|
|
3702
3765
|
"aria-label": label = "Sidebar",
|
|
3703
3766
|
...rest
|
|
3704
3767
|
}, ref) {
|
|
3705
|
-
return /* @__PURE__ */
|
|
3706
|
-
(sections?.length ? sections : [{ items }]).map((section, index) => /* @__PURE__ */
|
|
3768
|
+
return /* @__PURE__ */ jsxs30("nav", { ...rest, ref, "aria-label": label, className: ["ui-nav", "ui-nav--side", collapsed && "is-collapsed", className].filter(Boolean).join(" "), children: [
|
|
3769
|
+
(sections?.length ? sections : [{ items }]).map((section, index) => /* @__PURE__ */ jsx35(
|
|
3707
3770
|
Section,
|
|
3708
3771
|
{
|
|
3709
3772
|
section,
|
|
@@ -3714,14 +3777,14 @@ var SidebarNav = forwardRef8(function SidebarNav2({
|
|
|
3714
3777
|
},
|
|
3715
3778
|
index
|
|
3716
3779
|
)),
|
|
3717
|
-
footer && /* @__PURE__ */
|
|
3780
|
+
footer && /* @__PURE__ */ jsx35("div", { className: "ui-nav__foot", children: footer })
|
|
3718
3781
|
] });
|
|
3719
3782
|
});
|
|
3720
3783
|
|
|
3721
3784
|
// src/ThemeToggle.tsx
|
|
3722
3785
|
import { useSyncExternalStore } from "react";
|
|
3723
3786
|
import { themeIcon } from "@apliteni/apliteni-ui";
|
|
3724
|
-
import { jsx as
|
|
3787
|
+
import { jsx as jsx36, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3725
3788
|
var STORAGE_KEY = "apliteni-strategy-theme";
|
|
3726
3789
|
var CHOICE_EVENT = "apliteni-theme-choice";
|
|
3727
3790
|
var THEME_INIT_SCRIPT = `(()=>{let t;try{t=localStorage.getItem('apliteni-strategy-theme')}catch{}document.documentElement.setAttribute('data-theme',t==='dark'||t==='light'?t:window.matchMedia?.('(prefers-color-scheme: light)').matches?'light':'dark')})()`;
|
|
@@ -3779,10 +3842,10 @@ function ThemeToggle({ labelled = false }) {
|
|
|
3779
3842
|
}
|
|
3780
3843
|
window.dispatchEvent(new Event(CHOICE_EVENT));
|
|
3781
3844
|
};
|
|
3782
|
-
const button = /* @__PURE__ */
|
|
3783
|
-
return labelled ? /* @__PURE__ */
|
|
3845
|
+
const button = /* @__PURE__ */ jsx36("button", { type: "button", className: "toggle", "aria-label": name, title: name, onClick: toggle, children: /* @__PURE__ */ jsx36("span", { className: "ic", "aria-hidden": "true", dangerouslySetInnerHTML: { __html: themeIcon(theme) } }) });
|
|
3846
|
+
return labelled ? /* @__PURE__ */ jsxs31("span", { className: "ui-theme-toggle", children: [
|
|
3784
3847
|
button,
|
|
3785
|
-
/* @__PURE__ */
|
|
3848
|
+
/* @__PURE__ */ jsxs31("span", { children: [
|
|
3786
3849
|
label,
|
|
3787
3850
|
" theme"
|
|
3788
3851
|
] })
|
|
@@ -3790,7 +3853,7 @@ function ThemeToggle({ labelled = false }) {
|
|
|
3790
3853
|
}
|
|
3791
3854
|
|
|
3792
3855
|
// src/AppShell.tsx
|
|
3793
|
-
import { Fragment as Fragment12, jsx as
|
|
3856
|
+
import { Fragment as Fragment12, jsx as jsx37, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3794
3857
|
var path = (value) => value.split(/[?#]/)[0].replace(/\/+$/, "") || "/";
|
|
3795
3858
|
function AppShell({
|
|
3796
3859
|
sections,
|
|
@@ -3855,7 +3918,7 @@ function AppShell({
|
|
|
3855
3918
|
} catch {
|
|
3856
3919
|
}
|
|
3857
3920
|
};
|
|
3858
|
-
const sidebar = (label) => /* @__PURE__ */
|
|
3921
|
+
const sidebar = (label) => /* @__PURE__ */ jsx37(
|
|
3859
3922
|
SidebarNav,
|
|
3860
3923
|
{
|
|
3861
3924
|
"aria-label": label,
|
|
@@ -3867,33 +3930,33 @@ function AppShell({
|
|
|
3867
3930
|
const linkProps = { ...props, onClick: (event) => {
|
|
3868
3931
|
if (!event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey) setMenu(false);
|
|
3869
3932
|
} };
|
|
3870
|
-
return renderLink ? renderLink(section, linkProps) : /* @__PURE__ */
|
|
3933
|
+
return renderLink ? renderLink(section, linkProps) : /* @__PURE__ */ jsx37("a", { ...linkProps });
|
|
3871
3934
|
}
|
|
3872
3935
|
}
|
|
3873
3936
|
);
|
|
3874
3937
|
const foldLabel = collapsed ? "Expand sidebar" : "Collapse sidebar";
|
|
3875
3938
|
const navigable = sections.length > 1 || Boolean(back);
|
|
3876
|
-
const lockup = /* @__PURE__ */
|
|
3877
|
-
brand ?? /* @__PURE__ */
|
|
3878
|
-
/* @__PURE__ */
|
|
3939
|
+
const lockup = /* @__PURE__ */ jsxs32("a", { className: "ui-app__brand", href: brandHref, "aria-label": word, children: [
|
|
3940
|
+
brand ?? /* @__PURE__ */ jsx37("i", { "aria-hidden": "true", className: "ui-react-app__mark", dangerouslySetInnerHTML: { __html: prism(uid, 24) } }),
|
|
3941
|
+
/* @__PURE__ */ jsx37("span", { children: word })
|
|
3879
3942
|
] });
|
|
3880
|
-
return /* @__PURE__ */
|
|
3881
|
-
navigable && /* @__PURE__ */
|
|
3882
|
-
/* @__PURE__ */
|
|
3943
|
+
return /* @__PURE__ */ jsxs32("div", { className: `ui-app ui-app--topbar ui-react-app${collapsed ? " is-collapsed" : ""}`, children: [
|
|
3944
|
+
navigable && /* @__PURE__ */ jsxs32("div", { className: "ui-app__rail", role: "region", "aria-label": "Sidebar", children: [
|
|
3945
|
+
/* @__PURE__ */ jsx37("div", { className: "ui-app__head", children: lockup }),
|
|
3883
3946
|
sidebar("Sections"),
|
|
3884
|
-
/* @__PURE__ */
|
|
3885
|
-
/* @__PURE__ */
|
|
3886
|
-
/* @__PURE__ */
|
|
3887
|
-
/* @__PURE__ */
|
|
3888
|
-
/* @__PURE__ */
|
|
3947
|
+
/* @__PURE__ */ jsx37("div", { className: "ui-app__foot", children: /* @__PURE__ */ jsx37("div", { className: "ui-app__fold-row", children: /* @__PURE__ */ jsxs32("button", { type: "button", className: "ui-nav__item ui-app__fold", "aria-expanded": !collapsed, "aria-label": foldLabel, onClick: fold, children: [
|
|
3948
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-nav__ic", children: /* @__PURE__ */ jsxs32("svg", { className: "ui-icon", viewBox: "0 0 24 24", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
3949
|
+
/* @__PURE__ */ jsx37("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
3950
|
+
/* @__PURE__ */ jsx37("path", { className: "ui-app__fold-seam", d: "M9 3v18" }),
|
|
3951
|
+
/* @__PURE__ */ jsx37("path", { className: "ui-app__fold-arrow", d: "m16 15-3-3 3-3" })
|
|
3889
3952
|
] }) }),
|
|
3890
|
-
/* @__PURE__ */
|
|
3953
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-nav__label", children: foldLabel })
|
|
3891
3954
|
] }) }) })
|
|
3892
3955
|
] }),
|
|
3893
|
-
/* @__PURE__ */
|
|
3894
|
-
/* @__PURE__ */
|
|
3895
|
-
navigable && /* @__PURE__ */
|
|
3896
|
-
/* @__PURE__ */
|
|
3956
|
+
/* @__PURE__ */ jsxs32("div", { className: "ui-app__well", children: [
|
|
3957
|
+
/* @__PURE__ */ jsxs32("header", { className: "ui-app__bar", children: [
|
|
3958
|
+
navigable && /* @__PURE__ */ jsxs32(Fragment12, { children: [
|
|
3959
|
+
/* @__PURE__ */ jsx37(
|
|
3897
3960
|
Button,
|
|
3898
3961
|
{
|
|
3899
3962
|
ref: menuButton,
|
|
@@ -3907,19 +3970,19 @@ function AppShell({
|
|
|
3907
3970
|
onClick: () => setMenu(true)
|
|
3908
3971
|
}
|
|
3909
3972
|
),
|
|
3910
|
-
/* @__PURE__ */
|
|
3973
|
+
/* @__PURE__ */ jsx37("a", { className: "ui-app__brand ui-app__brand--band", href: brandHref, "aria-label": word, children: brand ?? /* @__PURE__ */ jsx37("i", { "aria-hidden": "true", className: "ui-react-app__mark", dangerouslySetInnerHTML: { __html: prism(`${uid}-band`, 24) } }) })
|
|
3911
3974
|
] }),
|
|
3912
3975
|
!navigable && lockup,
|
|
3913
|
-
/* @__PURE__ */
|
|
3914
|
-
/* @__PURE__ */
|
|
3915
|
-
/* @__PURE__ */
|
|
3916
|
-
/* @__PURE__ */
|
|
3917
|
-
/* @__PURE__ */
|
|
3976
|
+
/* @__PURE__ */ jsxs32("button", { type: "button", className: "ui-app__search", "aria-haspopup": "dialog", onClick: () => setSearch(true), children: [
|
|
3977
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-app__search-ic", children: /* @__PURE__ */ jsx37(Icon, { name: "search" }) }),
|
|
3978
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-app__search-txt", children: searchLabel }),
|
|
3979
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-app__search-short", "aria-hidden": "true", children: searchShortLabel }),
|
|
3980
|
+
/* @__PURE__ */ jsx37("kbd", { className: "ui-cmdk__key", children: paletteHotkey() })
|
|
3918
3981
|
] }),
|
|
3919
|
-
/* @__PURE__ */
|
|
3920
|
-
bandControl && /* @__PURE__ */
|
|
3921
|
-
/* @__PURE__ */
|
|
3922
|
-
/* @__PURE__ */
|
|
3982
|
+
/* @__PURE__ */ jsx37("span", { className: "ui-app__bar-gap" }),
|
|
3983
|
+
bandControl && /* @__PURE__ */ jsx37("span", { className: "ui-react-app__band-control", children: bandControl }),
|
|
3984
|
+
/* @__PURE__ */ jsx37(ThemeToggle, {}),
|
|
3985
|
+
/* @__PURE__ */ jsx37("div", { className: "ui-app__user ui-app__user--bar", children: /* @__PURE__ */ jsx37(
|
|
3923
3986
|
Dropdown,
|
|
3924
3987
|
{
|
|
3925
3988
|
variant: "menu",
|
|
@@ -3928,48 +3991,26 @@ function AppShell({
|
|
|
3928
3991
|
ariaLabel: `Signed in as ${account.name}, ${account.email}`,
|
|
3929
3992
|
triggerClass: "ui-app__user-trigger",
|
|
3930
3993
|
panelClass: "ui-app__user-panel",
|
|
3931
|
-
triggerContent: /* @__PURE__ */
|
|
3932
|
-
header: /* @__PURE__ */
|
|
3933
|
-
/* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */
|
|
3994
|
+
triggerContent: /* @__PURE__ */ jsx37("span", { className: "ui-app__av", "aria-hidden": "true", children: /* @__PURE__ */ jsx37(Avatar, { personKey: account.email || account.name, name: account.name, size: 32 }) }),
|
|
3995
|
+
header: /* @__PURE__ */ jsxs32("div", { className: "ui-dropdown__head", children: [
|
|
3996
|
+
/* @__PURE__ */ jsx37("b", { children: account.name }),
|
|
3997
|
+
/* @__PURE__ */ jsx37("span", { children: account.email })
|
|
3935
3998
|
] }),
|
|
3936
3999
|
items: [{ label: "Sign out", icon: "logout", danger: true }],
|
|
3937
4000
|
onSelect: onSignOut
|
|
3938
4001
|
}
|
|
3939
4002
|
) })
|
|
3940
4003
|
] }),
|
|
3941
|
-
/* @__PURE__ */
|
|
3942
|
-
back && /* @__PURE__ */
|
|
3943
|
-
/* @__PURE__ */
|
|
3944
|
-
lede && /* @__PURE__ */
|
|
3945
|
-
actions && /* @__PURE__ */
|
|
3946
|
-
/* @__PURE__ */
|
|
4004
|
+
/* @__PURE__ */ jsxs32("main", { className: `ui-app__main${width === "wide" ? " ui-app__main--wide" : ""}`, children: [
|
|
4005
|
+
back && /* @__PURE__ */ jsx37(BackLink, { ...back }),
|
|
4006
|
+
/* @__PURE__ */ jsx37("h1", { children: title }),
|
|
4007
|
+
lede && /* @__PURE__ */ jsx37("p", { className: "ui-app__sub", children: lede }),
|
|
4008
|
+
actions && /* @__PURE__ */ jsx37("div", { className: "ui-react-app__actions", children: actions }),
|
|
4009
|
+
/* @__PURE__ */ jsx37("div", { className: "ui-app__body", children })
|
|
3947
4010
|
] })
|
|
3948
4011
|
] }),
|
|
3949
|
-
navigable && /* @__PURE__ */
|
|
3950
|
-
/* @__PURE__ */
|
|
3951
|
-
] });
|
|
3952
|
-
}
|
|
3953
|
-
|
|
3954
|
-
// src/EmptyState.tsx
|
|
3955
|
-
import { icon as kitIcon2, illo } from "@apliteni/apliteni-ui";
|
|
3956
|
-
import { jsx as jsx37, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3957
|
-
var cases = {
|
|
3958
|
-
"first-run": { title: "Nothing needs you yet", sub: "New items will appear here when they need your attention.", icon: "check" },
|
|
3959
|
-
"no-matches": { title: "No results in this view", sub: "Try another search or clear your filters.", icon: "search" },
|
|
3960
|
-
"not-found": { title: "We can't find that page", sub: "Check the address or return to the home page.", icon: "folder" },
|
|
3961
|
-
"not-yet-built": { title: "This ships later", sub: "This screen is not available yet. Check back later.", icon: "clock" }
|
|
3962
|
-
};
|
|
3963
|
-
function EmptyState({ variant = "first-run", title, sub, icon: icon8, art, actions }) {
|
|
3964
|
-
const preset = cases[variant];
|
|
3965
|
-
const heading = title ?? preset.title;
|
|
3966
|
-
const guidance = sub ?? preset.sub;
|
|
3967
|
-
const glyph = icon8 ?? preset.icon;
|
|
3968
|
-
return /* @__PURE__ */ jsxs32("div", { className: "ui-empty", children: [
|
|
3969
|
-
art ? typeof art === "string" ? /* @__PURE__ */ jsx37("div", { className: "ui-empty__art", dangerouslySetInnerHTML: { __html: /<svg/.test(art) ? art : illo(art) } }) : /* @__PURE__ */ jsx37("div", { className: "ui-empty__art", "aria-hidden": "true", children: art }) : glyph ? /* @__PURE__ */ jsx37("div", { className: "ui-empty__icon", dangerouslySetInnerHTML: { __html: kitIcon2(glyph) } }) : null,
|
|
3970
|
-
heading && /* @__PURE__ */ jsx37("div", { className: "ui-empty__title", children: heading }),
|
|
3971
|
-
guidance && /* @__PURE__ */ jsx37("div", { className: "ui-empty__sub", children: guidance }),
|
|
3972
|
-
actions && /* @__PURE__ */ jsx37("div", { className: "ui-empty__actions", children: actions })
|
|
4012
|
+
navigable && /* @__PURE__ */ jsx37(Drawer, { open: menu, onClose: () => setMenu(false), title: word, side: "left", size: "sm", children: /* @__PURE__ */ jsx37("div", { className: "ui-react-app__menu", children: sidebar("Menu sections") }) }),
|
|
4013
|
+
/* @__PURE__ */ jsx37(CommandPalette, { ...palette ?? { groups: [{ items: sections.map((section) => ({ id: section.href, ...section })) }] }, open: search, onClose: () => setSearch(false) })
|
|
3973
4014
|
] });
|
|
3974
4015
|
}
|
|
3975
4016
|
|
package/src/components/index.js
CHANGED
|
@@ -48,9 +48,11 @@ export function button({
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// ---- Badge / Pill --------------------------------------------------------
|
|
51
|
+
// Neutral is written out rather than left implied: a status column reading its tone off the
|
|
52
|
+
// class list found nothing on two of four rows, and the tone a chip is in is not a default
|
|
53
|
+
// the markup should have to know. The base class carries the same fill either way. #459
|
|
51
54
|
export function badge(label, variant = 'neutral') {
|
|
52
|
-
|
|
53
|
-
return `<span class="${esc(cx('ui-badge', v))}">${esc(label)}</span>`;
|
|
55
|
+
return `<span class="${esc(cx('ui-badge', `ui-badge--${variant}`))}">${esc(label)}</span>`;
|
|
54
56
|
}
|
|
55
57
|
export function pill(label, variant) {
|
|
56
58
|
return `<span class="${esc(cx('ui-pill', variant && `ui-pill--${variant}`))}">${esc(label)}</span>`;
|
package/src/styles/card.css
CHANGED
|
@@ -93,6 +93,10 @@
|
|
|
93
93
|
/* Title to description: the step, not the 5px it was. why: docs/foundations.md#spacing-and-rhythm */
|
|
94
94
|
margin: 0 0 var(--space-2);
|
|
95
95
|
}
|
|
96
|
+
/* The title of a card that supports its neighbour, such as a document beside the
|
|
97
|
+
data read from it. The size, weight and rank stay the card title's.
|
|
98
|
+
why: docs/foundations.md#text-ink */
|
|
99
|
+
.ui-card__title--muted { /* muted-ink: chrome — a supporting card ranks below its neighbour; the title is also the card's accessible name */ color: var(--muted); }
|
|
96
100
|
.ui-card__sub {
|
|
97
101
|
color: var(--text);
|
|
98
102
|
font-size: var(--text-base);
|
package/src/styles/file-drop.css
CHANGED
|
@@ -81,3 +81,42 @@
|
|
|
81
81
|
|
|
82
82
|
.ui-drop.is-disabled .ui-drop__row { /* muted-ink: state — the drop accepts nothing */ color: var(--disabled-ink); }
|
|
83
83
|
.ui-drop.is-disabled .ui-drop__name { /* muted-ink: state — the drop accepts nothing */ color: var(--disabled-ink); }
|
|
84
|
+
|
|
85
|
+
/* The empty page's drop area: the whole region is the target, drawn as a dashed
|
|
86
|
+
box around the first-run block. A file over it turns the edge to the accent,
|
|
87
|
+
the screen's one accent line, the way .ui-drop__target draws its own. */
|
|
88
|
+
.ui-drop--area { border: 1px dashed var(--border-strong); border-radius: var(--radius-lg); padding: var(--space-4); }
|
|
89
|
+
.ui-drop--area.is-dragging { border-color: var(--accent); }
|
|
90
|
+
@media (max-width: 560px) { .ui-drop--area { padding: var(--space-3); } }
|
|
91
|
+
|
|
92
|
+
/* The whole page as a target, drawn only while a file is dragged over the page. It is the
|
|
93
|
+
empty page's drop area made large: the same dashed accent edge and radius, holding the upload
|
|
94
|
+
glyph, a line that says to drop the files and the accepted types, laid over the page content below
|
|
95
|
+
the topbar. Its ground is the page ground, slightly transparent and blurred, so the table shows
|
|
96
|
+
through softly and no row stays sharp under the words. Where the engine cannot blur the backdrop,
|
|
97
|
+
or the reader asks for less transparency, the ground is solid. The layer takes no pointer events,
|
|
98
|
+
so the drop lands on what is under it. */
|
|
99
|
+
.ui-drop--page {
|
|
100
|
+
position: fixed;
|
|
101
|
+
inset: calc(var(--ui-app-band, 0px) + var(--ui-app-top, 0px) + var(--space-4)) var(--space-4) var(--space-4);
|
|
102
|
+
z-index: var(--z-overlay);
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
pointer-events: none;
|
|
107
|
+
background: var(--bg); /* code-bg: inherit — the layer holds no focus target and takes no pointer. */
|
|
108
|
+
}
|
|
109
|
+
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
|
|
110
|
+
.ui-drop--page {
|
|
111
|
+
background: color-mix(in srgb, var(--bg) 80%, transparent); /* code-bg: inherit — the layer holds no focus target and takes no pointer. */
|
|
112
|
+
-webkit-backdrop-filter: blur(var(--space-2));
|
|
113
|
+
backdrop-filter: blur(var(--space-2));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
117
|
+
.ui-drop--page {
|
|
118
|
+
background: var(--bg); /* code-bg: inherit — the layer holds no focus target and takes no pointer. */
|
|
119
|
+
-webkit-backdrop-filter: none;
|
|
120
|
+
backdrop-filter: none;
|
|
121
|
+
}
|
|
122
|
+
}
|
package/src/styles/layout.css
CHANGED
|
@@ -332,7 +332,7 @@
|
|
|
332
332
|
the three heights below are for. Level, not one continuous stroke: the rail insets
|
|
333
333
|
its own rule, and in light that half is 1.009:1 on the rail's ground.
|
|
334
334
|
why: docs/components.md#the-second-layout */
|
|
335
|
-
.ui-app { --ui-app-band: 52px; }
|
|
335
|
+
.ui-app--topbar { --ui-app-band: 52px; }
|
|
336
336
|
.ui-app__well { display: flex; flex-direction: column; min-width: 0; }
|
|
337
337
|
.ui-app__bar {
|
|
338
338
|
display: flex;
|
|
@@ -516,15 +516,17 @@
|
|
|
516
516
|
@media (max-width: 720px) {
|
|
517
517
|
/* A column, not a grid: the band sticks to the top of the shell, and a sticky grid
|
|
518
518
|
item sticks only inside its own row. */
|
|
519
|
-
.ui-app { display: flex; flex-direction: column; }
|
|
519
|
+
.ui-app { display: flex; flex-direction: column; --ui-app-band: 52px; }
|
|
520
520
|
.ui-app > .ui-app__rail { display: none; }
|
|
521
521
|
.ui-app__well { flex: 1 1 auto; }
|
|
522
522
|
.ui-app > .ui-app__main { flex: 1 1 auto; }
|
|
523
523
|
.ui-app > .ui-app__bar--phone { display: flex; }
|
|
524
524
|
.ui-btn.ui-app__menu { display: inline-flex; }
|
|
525
525
|
.ui-app__brand--band { display: flex; }
|
|
526
|
-
/* The
|
|
527
|
-
|
|
526
|
+
/* The first visible item lines up with the page. A leading menu uses the smaller
|
|
527
|
+
inset to keep its phone position in both shells. */
|
|
528
|
+
.ui-app__bar { padding-inline: var(--space-4); }
|
|
529
|
+
.ui-app__bar:has(> .ui-app__menu:first-child) { padding-inline-start: var(--space-2); }
|
|
528
530
|
/* The drawer paints itself and sits out of the flow, so its wrapper takes no height. */
|
|
529
531
|
.ui-app__drawer { display: block; }
|
|
530
532
|
/* The rail's rows are the drawer's rows: the column fills the panel, and the foot
|