@parallelworks/ui 0.53.0 → 0.54.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 +55 -5
- package/dist/access/AccessDrawer.d.ts +55 -0
- package/dist/access/AccessDrawer.js +445 -0
- package/dist/access/AccessList.d.ts +58 -0
- package/dist/access/AccessList.js +382 -0
- package/dist/access/GrantView.d.ts +35 -0
- package/dist/access/GrantView.js +188 -0
- package/dist/access/GroupPicker.d.ts +35 -0
- package/dist/access/GroupPicker.js +336 -0
- package/dist/access/focus.d.ts +10 -0
- package/dist/access/focus.js +27 -0
- package/dist/access/index.d.ts +3 -0
- package/dist/access/index.js +3 -0
- package/dist/access/model.d.ts +49 -0
- package/dist/access/model.js +129 -0
- package/dist/access/strings.d.ts +122 -0
- package/dist/access/strings.js +151 -0
- package/dist/access/types.d.ts +56 -0
- package/dist/ai/components/SlashMenu.js +1 -1
- package/dist/components/Combobox.d.ts +19 -0
- package/dist/components/Combobox.js +101 -50
- package/dist/components/Drawer.d.ts +6 -1
- package/dist/components/Drawer.js +25 -16
- package/dist/components/Menu.js +4 -4
- package/dist/components/MenuEntries.js +1 -1
- package/dist/components/OptionDescription.d.ts +7 -0
- package/dist/components/OptionDescription.js +19 -0
- package/dist/components/Provider.d.ts +7 -0
- package/dist/components/Provider.js +3 -0
- package/dist/components/Select.js +13 -11
- package/dist/components/comboboxItems.d.ts +10 -0
- package/dist/components/comboboxItems.js +8 -1
- package/dist/components/floating.d.ts +5 -2
- package/dist/components/floating.js +2 -2
- package/dist/editor/themes.d.ts +5 -0
- package/dist/editor/themes.js +17 -2
- package/dist/file-explorer/FileExplorer.js +2 -1
- package/dist/file-explorer/lib/paging.d.ts +1 -0
- package/dist/file-explorer/lib/paging.js +5 -1
- package/dist/styles/theme.css +82 -62
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +5 -3
- package/dist/theme/derive.js +61 -3
- package/package.json +5 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { CloseIcon } from "../icons.js";
|
|
2
|
+
import { ArrowLeftIcon, CloseIcon } from "../icons.js";
|
|
3
3
|
import { useStrings } from "./Provider.js";
|
|
4
4
|
import { IconButton } from "./IconButton.js";
|
|
5
5
|
import { closeHandler } from "./dismiss.js";
|
|
@@ -15,7 +15,7 @@ import { Drawer } from "@base-ui/react/drawer";
|
|
|
15
15
|
* `--app-inset-top` (a top bar's height), and at its widest leaves the strip
|
|
16
16
|
* `--app-inset-start` (a start-side sidebar's width, at least 2.5rem). Set both
|
|
17
17
|
* on the document root. */
|
|
18
|
-
function Drawer$1({ open, onClose, title, description, footer, side = "right", width = 480, resizable = false, minWidth = 320, dismissible = true, modal = true, closeButton = true, contained = false, keepMounted = false, padded = true, className, children, ...popupProps }) {
|
|
18
|
+
function Drawer$1({ open, onClose, title, description, onBack, backLabel, footer, side = "right", width = 480, resizable = false, minWidth = 320, dismissible = true, modal = true, closeButton = true, contained = false, keepMounted = false, padded = true, className, children, ...popupProps }) {
|
|
19
19
|
const { common } = useStrings();
|
|
20
20
|
const container = useRef(null);
|
|
21
21
|
const viewport = useRef(null);
|
|
@@ -61,20 +61,29 @@ function Drawer$1({ open, onClose, title, description, footer, side = "right", w
|
|
|
61
61
|
children: [
|
|
62
62
|
header && /* @__PURE__ */ jsxs("div", {
|
|
63
63
|
className: "flex shrink-0 items-start gap-3 border-b border-(--theme-border) px-4 py-3",
|
|
64
|
-
children: [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
children: [
|
|
65
|
+
onBack && /* @__PURE__ */ jsx(IconButton, {
|
|
66
|
+
icon: /* @__PURE__ */ jsx(ArrowLeftIcon, {}),
|
|
67
|
+
label: backLabel ?? common.back,
|
|
68
|
+
onClick: onBack,
|
|
69
|
+
className: "-my-1 -ms-1.5"
|
|
70
|
+
}),
|
|
71
|
+
/* @__PURE__ */ jsxs("div", {
|
|
72
|
+
className: "min-w-0 flex-1",
|
|
73
|
+
children: [title !== void 0 && /* @__PURE__ */ jsx(Drawer.Title, {
|
|
74
|
+
className: "m-0 text-sm font-semibold wrap-break-word",
|
|
75
|
+
children: title
|
|
76
|
+
}), description !== void 0 && /* @__PURE__ */ jsx(Drawer.Description, {
|
|
77
|
+
className: "mt-0.5 text-xs text-(--theme-muted-text-color)",
|
|
78
|
+
children: description
|
|
79
|
+
})]
|
|
80
|
+
}),
|
|
81
|
+
closeButton && /* @__PURE__ */ jsx(Drawer.Close, { render: /* @__PURE__ */ jsx(IconButton, {
|
|
82
|
+
icon: /* @__PURE__ */ jsx(CloseIcon, {}),
|
|
83
|
+
label: common.close,
|
|
84
|
+
className: "-my-1 -me-1.5"
|
|
85
|
+
}) })
|
|
86
|
+
]
|
|
78
87
|
}),
|
|
79
88
|
/* @__PURE__ */ jsx("div", {
|
|
80
89
|
className: cx("relative flex min-h-0 flex-1 flex-col overflow-y-auto", padded && "p-4", className),
|
package/dist/components/Menu.js
CHANGED
|
@@ -16,7 +16,7 @@ function MenuPopup({ children, className, side = "bottom", align = "start", anch
|
|
|
16
16
|
sideOffset: 4,
|
|
17
17
|
className: positionerClassName,
|
|
18
18
|
children: /* @__PURE__ */ jsx(Menu.Popup, {
|
|
19
|
-
className: cx("min-w-44 max-h-(--available-height) overflow-y-auto
|
|
19
|
+
className: cx("min-w-44 max-h-(--available-height) overflow-y-auto", "p-1", panelClassName, className),
|
|
20
20
|
children
|
|
21
21
|
})
|
|
22
22
|
})
|
|
@@ -41,7 +41,7 @@ function MenuRadioItem({ className, children, ...props }) {
|
|
|
41
41
|
return /* @__PURE__ */ jsxs(Menu.RadioItem, {
|
|
42
42
|
closeOnClick: true,
|
|
43
43
|
...props,
|
|
44
|
-
className: cx(itemClassName, "pl-
|
|
44
|
+
className: cx(itemClassName, "pl-1", className),
|
|
45
45
|
children: [/* @__PURE__ */ jsx("span", {
|
|
46
46
|
className: "flex w-3.5 shrink-0 justify-center",
|
|
47
47
|
children: /* @__PURE__ */ jsx(Menu.RadioItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3" }) })
|
|
@@ -72,11 +72,11 @@ function MenuSubmenuTrigger({ className, children, ...props }) {
|
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
function MenuSeparator({ className }) {
|
|
75
|
-
return /* @__PURE__ */ jsx(Menu.Separator, { className: cx("my-1 h-px bg-(--theme-border)", className) });
|
|
75
|
+
return /* @__PURE__ */ jsx(Menu.Separator, { className: cx("-mx-1 my-1 h-px bg-(--theme-border)", className) });
|
|
76
76
|
}
|
|
77
77
|
function MenuGroupLabel({ children }) {
|
|
78
78
|
return /* @__PURE__ */ jsx(Menu.GroupLabel, {
|
|
79
|
-
className: "px-
|
|
79
|
+
className: "px-2 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-wide text-(--theme-muted-text-color)",
|
|
80
80
|
children
|
|
81
81
|
});
|
|
82
82
|
}
|
|
@@ -34,7 +34,7 @@ function MenuEntries({ entries, search, query = "" }) {
|
|
|
34
34
|
const shown = needle ? searchMatches(entries, (a) => matches(needle, a.label, a.keywords)) : entries;
|
|
35
35
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36
36
|
/* @__PURE__ */ jsx("div", {
|
|
37
|
-
className: "sticky top-0 z-[1] bg-(--theme-app-bg) px-
|
|
37
|
+
className: "sticky top-0 z-[1] bg-(--theme-app-bg) px-1 pt-0.5 pb-1",
|
|
38
38
|
children: /* @__PURE__ */ jsx(Menu.Input, {
|
|
39
39
|
"aria-label": search.placeholder,
|
|
40
40
|
placeholder: search.placeholder,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComboboxItem } from './comboboxItems.js';
|
|
2
|
+
/** An option's description under its label. An `accessibleDescription` is read in its place,
|
|
3
|
+
* so the shown one is then hidden from assistive technology rather than read twice. */
|
|
4
|
+
export declare function OptionDescription({ id, item, }: {
|
|
5
|
+
id: string;
|
|
6
|
+
item: Pick<ComboboxItem<unknown>, 'description' | 'accessibleDescription'>;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
//#region src/components/OptionDescription.tsx
|
|
3
|
+
/** An option's description under its label. An `accessibleDescription` is read in its place,
|
|
4
|
+
* so the shown one is then hidden from assistive technology rather than read twice. */
|
|
5
|
+
function OptionDescription({ id, item }) {
|
|
6
|
+
const spoken = item.accessibleDescription;
|
|
7
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [item.description && /* @__PURE__ */ jsx("span", {
|
|
8
|
+
id: spoken ? void 0 : id,
|
|
9
|
+
"aria-hidden": spoken ? true : void 0,
|
|
10
|
+
className: "text-xs leading-snug text-(--theme-muted-text-color)",
|
|
11
|
+
children: item.description
|
|
12
|
+
}), spoken && /* @__PURE__ */ jsx("span", {
|
|
13
|
+
id,
|
|
14
|
+
hidden: true,
|
|
15
|
+
children: spoken
|
|
16
|
+
})] });
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { OptionDescription };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
|
+
import type { AccessText } from '../access/strings.js';
|
|
2
3
|
import type { WorkflowAction, WorkflowEditing } from '../editing.js';
|
|
3
4
|
import type { WorkflowEngine } from '../engine.js';
|
|
4
5
|
import type { GraphEditorText, InputsEditorText } from '../graph/editorStrings.js';
|
|
@@ -14,6 +15,8 @@ export interface UIStrings {
|
|
|
14
15
|
favoriteHintOff: string;
|
|
15
16
|
};
|
|
16
17
|
common: {
|
|
18
|
+
/** Returns to the view a drawer or panel showed before. */
|
|
19
|
+
back: string;
|
|
17
20
|
cancel: string;
|
|
18
21
|
close: string;
|
|
19
22
|
save: string;
|
|
@@ -110,6 +113,8 @@ export interface UIStrings {
|
|
|
110
113
|
dropdown: {
|
|
111
114
|
select: (type: string) => string;
|
|
112
115
|
noOptionsFound: string;
|
|
116
|
+
/** While a search for options is under way. */
|
|
117
|
+
searching: string;
|
|
113
118
|
showOptions: string;
|
|
114
119
|
/** The row that adds typed text as a new value. */
|
|
115
120
|
add: (text: string) => string;
|
|
@@ -259,6 +264,8 @@ export interface UIStrings {
|
|
|
259
264
|
};
|
|
260
265
|
/** The visual editor's text a host translates; the editor fills in the rest in English. */
|
|
261
266
|
graphEditor: Partial<GraphEditorText>;
|
|
267
|
+
/** The access drawer's text, over its English defaults. */
|
|
268
|
+
access: Partial<AccessText>;
|
|
262
269
|
inputsEditor: Partial<InputsEditorText>;
|
|
263
270
|
fileExplorer: {
|
|
264
271
|
preview: {
|
|
@@ -41,6 +41,7 @@ var DEFAULTS = {
|
|
|
41
41
|
favoriteHintOff: "Favorite your item when it's created"
|
|
42
42
|
},
|
|
43
43
|
common: {
|
|
44
|
+
back: "Back",
|
|
44
45
|
cancel: "Cancel",
|
|
45
46
|
close: "Close",
|
|
46
47
|
save: "Save",
|
|
@@ -125,6 +126,7 @@ var DEFAULTS = {
|
|
|
125
126
|
dropdown: {
|
|
126
127
|
select: (type) => `Select ${type}`,
|
|
127
128
|
noOptionsFound: "No options found",
|
|
129
|
+
searching: "Searching…",
|
|
128
130
|
showOptions: "Show options",
|
|
129
131
|
add: (text) => `Add “${text}”`,
|
|
130
132
|
limitReached: (max) => `Up to ${max}`,
|
|
@@ -276,6 +278,7 @@ var DEFAULTS = {
|
|
|
276
278
|
openInNewGraph: "Open in new graph"
|
|
277
279
|
},
|
|
278
280
|
graphEditor: {},
|
|
281
|
+
access: {},
|
|
279
282
|
inputsEditor: {},
|
|
280
283
|
fileExplorer: {
|
|
281
284
|
preview: {
|
|
@@ -3,7 +3,8 @@ import { CheckIcon, ChevronDownIcon } from "../icons.js";
|
|
|
3
3
|
import { panelClassName, positionerClassName } from "./floating.js";
|
|
4
4
|
import { Tooltip } from "./Tooltip.js";
|
|
5
5
|
import { fieldBox } from "./fieldBox.js";
|
|
6
|
-
import { pickerItemClassName } from "./comboboxItems.js";
|
|
6
|
+
import { optionNaming, pickerItemClassName } from "./comboboxItems.js";
|
|
7
|
+
import { OptionDescription } from "./OptionDescription.js";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { useId } from "react";
|
|
9
10
|
import { Select } from "@base-ui/react/select";
|
|
@@ -52,12 +53,11 @@ function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "ari
|
|
|
52
53
|
children: /* @__PURE__ */ jsx(Select.Popup, {
|
|
53
54
|
className: cx("min-w-(--anchor-width) max-w-[min(20rem,var(--available-width))]", panelClassName),
|
|
54
55
|
children: /* @__PURE__ */ jsx(Select.List, {
|
|
55
|
-
className: "max-h-[min(15rem,var(--available-height))] overflow-y-auto
|
|
56
|
+
className: cx("max-h-[min(15rem,var(--available-height))] overflow-y-auto", "p-1"),
|
|
56
57
|
children: items.map((item, index) => /* @__PURE__ */ jsxs(Select.Item, {
|
|
57
58
|
value: item.value,
|
|
58
59
|
disabled: item.disabled,
|
|
59
|
-
|
|
60
|
-
"aria-describedby": item.description && `${uid}${index}description`,
|
|
60
|
+
...optionNaming(`${uid}${index}`, item),
|
|
61
61
|
onFocus: onItemHighlighted && (() => onItemHighlighted(item.value)),
|
|
62
62
|
className: pickerItemClassName,
|
|
63
63
|
children: [
|
|
@@ -67,14 +67,16 @@ function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "ari
|
|
|
67
67
|
}),
|
|
68
68
|
/* @__PURE__ */ jsxs("span", {
|
|
69
69
|
className: "flex min-w-0 flex-col",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
71
|
+
className: "flex min-w-0 items-center gap-2",
|
|
72
|
+
children: [/* @__PURE__ */ jsx(Select.ItemText, {
|
|
73
|
+
id: `${uid}${index}label`,
|
|
74
|
+
className: "truncate",
|
|
75
|
+
children: item.label
|
|
76
|
+
}), item.badge]
|
|
77
|
+
}), /* @__PURE__ */ jsx(OptionDescription, {
|
|
75
78
|
id: `${uid}${index}description`,
|
|
76
|
-
|
|
77
|
-
children: item.description
|
|
79
|
+
item
|
|
78
80
|
})]
|
|
79
81
|
}),
|
|
80
82
|
/* @__PURE__ */ jsx(Select.ItemIndicator, {
|
|
@@ -7,7 +7,12 @@ export interface ComboboxItem<Value = string> {
|
|
|
7
7
|
value: Value;
|
|
8
8
|
label: string;
|
|
9
9
|
description?: string | undefined;
|
|
10
|
+
/** Read after the label in place of `description`, for what the row shows in more than
|
|
11
|
+
* words, such as a count and a status: "24 members, synced". */
|
|
12
|
+
accessibleDescription?: string | undefined;
|
|
10
13
|
icon?: ReactNode;
|
|
14
|
+
/** Beside the label, such as a tag that marks the option out. */
|
|
15
|
+
badge?: ReactNode;
|
|
11
16
|
disabled?: boolean | undefined;
|
|
12
17
|
}
|
|
13
18
|
export interface ComboboxGroup<Value = string> {
|
|
@@ -23,6 +28,11 @@ export interface ComboboxGroup<Value = string> {
|
|
|
23
28
|
export type ComboboxLeaf<Value = string> = ComboboxItem<Value> | (Value & string);
|
|
24
29
|
/** Items, groups under headings, or both: items between groups list where they sit, without a heading. */
|
|
25
30
|
export type ComboboxItems<Value = string> = readonly (ComboboxLeaf<Value> | ComboboxGroup<Value>)[];
|
|
31
|
+
/** How an option is named and described: by its label, with its description read after it. */
|
|
32
|
+
export declare function optionNaming(id: string, item: Pick<ComboboxItem<unknown>, 'description' | 'accessibleDescription'>): {
|
|
33
|
+
'aria-labelledby': string;
|
|
34
|
+
'aria-describedby': string | undefined;
|
|
35
|
+
};
|
|
26
36
|
export declare function isComboboxGroup<Value>(item: ComboboxLeaf<Value> | ComboboxGroup<Value>): item is ComboboxGroup<Value>;
|
|
27
37
|
/** Every item, out of their groups. */
|
|
28
38
|
export declare function comboboxLeaves<Value>(items: ComboboxItems<Value>): ComboboxLeaf<Value>[];
|
|
@@ -4,6 +4,13 @@ import { panelItemClassName } from "./floating.js";
|
|
|
4
4
|
/** An option's row in a Select's or a Combobox's list, so both lists look alike: the icon, the
|
|
5
5
|
* label over its description, and the check at the end. */
|
|
6
6
|
var pickerItemClassName = cx(panelItemClassName, "data-selected:font-medium");
|
|
7
|
+
/** How an option is named and described: by its label, with its description read after it. */
|
|
8
|
+
function optionNaming(id, item) {
|
|
9
|
+
return {
|
|
10
|
+
"aria-labelledby": `${id}label`,
|
|
11
|
+
"aria-describedby": item.accessibleDescription || item.description ? `${id}description` : void 0
|
|
12
|
+
};
|
|
13
|
+
}
|
|
7
14
|
function isComboboxGroup(item) {
|
|
8
15
|
return typeof item === "object" && "items" in item;
|
|
9
16
|
}
|
|
@@ -12,4 +19,4 @@ function comboboxLeaves(items) {
|
|
|
12
19
|
return items.flatMap((item) => isComboboxGroup(item) ? item.items : [item]);
|
|
13
20
|
}
|
|
14
21
|
//#endregion
|
|
15
|
-
export { comboboxLeaves, isComboboxGroup, pickerItemClassName };
|
|
22
|
+
export { comboboxLeaves, isComboboxGroup, optionNaming, pickerItemClassName };
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
export declare const positionerClassName = "z-(--layer-popover) outline-none data-anchor-hidden:invisible";
|
|
3
3
|
/** A panel of choices: a menu, a select's list, a combobox's list. */
|
|
4
4
|
export declare const panelClassName = "rounded-lg border border-(--theme-border) bg-(--theme-app-bg) text-sm text-(--theme-app) shadow-(--theme-shadow-lg) outline-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
|
|
5
|
-
/** A
|
|
6
|
-
|
|
5
|
+
/** A panel's rows inset by the same gutter on every side, so a highlighted first or last row
|
|
6
|
+
* keeps the margin it has at its sides rather than leaving a strip against the border. */
|
|
7
|
+
export declare const panelListClassName = "p-1";
|
|
8
|
+
/** A row in a panel, inside its `panelListClassName` gutter; its text lines up with a field's. */
|
|
9
|
+
export declare const panelItemClassName = "flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-left outline-none data-highlighted:bg-(--theme-hover) data-highlighted:text-(--theme-app) data-disabled:cursor-not-allowed data-disabled:opacity-50";
|
|
7
10
|
/** A tooltip's or infotip's small inverted surface. */
|
|
8
11
|
export declare const tipClassName = "rounded-md bg-(--theme-app) px-2 py-1 text-xs text-(--theme-app-bg) shadow-(--theme-shadow) whitespace-pre-line break-words data-instant:transition-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
|
|
9
12
|
export declare const tipArrowClassName = "size-2 rotate-45 bg-(--theme-app) data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1";
|
|
@@ -4,8 +4,8 @@ var positionerClassName = "z-(--layer-popover) outline-none data-anchor-hidden:i
|
|
|
4
4
|
var enterExit = "origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
|
|
5
5
|
/** A panel of choices: a menu, a select's list, a combobox's list. */
|
|
6
6
|
var panelClassName = `rounded-lg border border-(--theme-border) bg-(--theme-app-bg) text-sm text-(--theme-app) shadow-(--theme-shadow-lg) outline-none ${enterExit}`;
|
|
7
|
-
/** A row in a panel. */
|
|
8
|
-
var panelItemClassName = "flex w-full cursor-pointer select-none items-center gap-2 px-
|
|
7
|
+
/** A row in a panel, inside its `panelListClassName` gutter; its text lines up with a field's. */
|
|
8
|
+
var panelItemClassName = "flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-left outline-none data-highlighted:bg-(--theme-hover) data-highlighted:text-(--theme-app) data-disabled:cursor-not-allowed data-disabled:opacity-50";
|
|
9
9
|
/** A tooltip's or infotip's small inverted surface. */
|
|
10
10
|
var tipClassName = `rounded-md bg-(--theme-app) px-2 py-1 text-xs text-(--theme-app-bg) shadow-(--theme-shadow) whitespace-pre-line break-words data-instant:transition-none ${enterExit}`;
|
|
11
11
|
var tipArrowClassName = "size-2 rotate-45 bg-(--theme-app) data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1";
|
package/dist/editor/themes.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type * as monaco from 'monaco-editor';
|
|
2
|
+
import { type Mode } from '../theme/index.js';
|
|
2
3
|
export declare function expandShorthandHex(color: string): string;
|
|
4
|
+
/** The arm of a `light-dark()` value for a mode, or the value itself. A token the host leaves to
|
|
5
|
+
* theme.css reads as `light-dark(light, dark)`, which CSS resolves by the color-scheme of where it
|
|
6
|
+
* is used; Monaco takes one color per theme, so each theme takes its own mode's arm. */
|
|
7
|
+
export declare function forMode(value: string, mode: Mode): string;
|
|
3
8
|
/**
|
|
4
9
|
* Defines the light and dark Monaco themes from the document's tokens. Call it again after the
|
|
5
10
|
* host applies other tokens; it returns whether anything changed.
|
package/dist/editor/themes.js
CHANGED
|
@@ -6,11 +6,26 @@ function expandShorthandHex(color) {
|
|
|
6
6
|
return /^#([0-9a-fA-F]{3,4})$/.test(color) ? "#" + color.slice(1).split("").map((c) => c + c).join("") : color;
|
|
7
7
|
}
|
|
8
8
|
var fallbacks = {};
|
|
9
|
+
/** The arm of a `light-dark()` value for a mode, or the value itself. A token the host leaves to
|
|
10
|
+
* theme.css reads as `light-dark(light, dark)`, which CSS resolves by the color-scheme of where it
|
|
11
|
+
* is used; Monaco takes one color per theme, so each theme takes its own mode's arm. */
|
|
12
|
+
function forMode(value, mode) {
|
|
13
|
+
const inner = /^light-dark\((.*)\)$/s.exec(value.trim())?.[1];
|
|
14
|
+
if (inner === void 0) return value;
|
|
15
|
+
let depth = 0;
|
|
16
|
+
for (let i = 0; i < inner.length; i++) {
|
|
17
|
+
const ch = inner[i];
|
|
18
|
+
if (ch === "(") depth++;
|
|
19
|
+
else if (ch === ")") depth--;
|
|
20
|
+
else if (ch === "," && depth === 0) return (mode === "light" ? inner.slice(0, i) : inner.slice(i + 1)).trim();
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
9
24
|
/** A token as Monaco takes it: a 6-digit hex. Monaco can't read display-p3, so
|
|
10
25
|
* a wide-gamut value is mapped back into sRGB; the default theme fills in for
|
|
11
26
|
* a host that sets no tokens. */
|
|
12
27
|
function token(style, name, mode) {
|
|
13
|
-
const color = parseColor(expandShorthandHex(style?.getPropertyValue(name)
|
|
28
|
+
const color = parseColor(expandShorthandHex(forMode(style?.getPropertyValue(name) ?? "", mode).trim()));
|
|
14
29
|
if (color) return toHex(color);
|
|
15
30
|
fallbacks[mode] ??= deriveTheme(schemeFor(DEFAULT_THEME, mode));
|
|
16
31
|
return fallbacks[mode][name];
|
|
@@ -120,4 +135,4 @@ function getThemeName(isDark) {
|
|
|
120
135
|
return `app-${isDark ? "dark" : "light"}`;
|
|
121
136
|
}
|
|
122
137
|
//#endregion
|
|
123
|
-
export { defineEditorThemes, expandShorthandHex, followThemeTokens, getThemeName };
|
|
138
|
+
export { defineEditorThemes, expandShorthandHex, followThemeTokens, forMode, getThemeName };
|
|
@@ -37,7 +37,7 @@ import { FilePreviewInline } from "./FilePreview/Inline.js";
|
|
|
37
37
|
import { UserRow } from "./FileRow.js";
|
|
38
38
|
import { FileTableHeaders } from "./FileTableHeaders.js";
|
|
39
39
|
import { FileTable } from "./FileTable.js";
|
|
40
|
-
import { advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing } from "./lib/paging.js";
|
|
40
|
+
import { advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing, retainListings } from "./lib/paging.js";
|
|
41
41
|
import { TreeView } from "./TreeView.js";
|
|
42
42
|
import { Menu } from "@base-ui/react/menu";
|
|
43
43
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -949,6 +949,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
949
949
|
const handleRefresh = async (opts) => {
|
|
950
950
|
const dirs = [...expandedPaths].map((path) => treeMap[path]).filter((node) => !!node && node.type === "directory" && !!node.storageId);
|
|
951
951
|
if (selectedNode?.type === "directory" && selectedNode.storageId && !dirs.some((dir) => dir.path === selectedNode.path)) dirs.push(selectedNode);
|
|
952
|
+
setListings((prev) => retainListings(prev, new Set(dirs.map((dir) => dir.path))));
|
|
952
953
|
if (dirs.length > 0) return { corsError: (await Promise.all(dirs.map((dir) => fetchNodeChildren(dir, {
|
|
953
954
|
replace: true,
|
|
954
955
|
silent: opts?.silent
|
|
@@ -47,6 +47,7 @@ export declare function recordListingError(listings: TListings, path: string, er
|
|
|
47
47
|
/** Keeps the cursor and pages, so a retry resumes paging instead of starting over. */
|
|
48
48
|
export declare function clearListingError(listings: TListings, path: string): TListings;
|
|
49
49
|
export declare function clearListingsUnder(listings: TListings, path: string): TListings;
|
|
50
|
+
export declare function retainListings(listings: TListings, paths: ReadonlySet<string>): TListings;
|
|
50
51
|
/** Tree paths whose children should keep arrival order, since sorting them would
|
|
51
52
|
* reshuffle rows under the user mid-scroll. */
|
|
52
53
|
export declare function incompletePaths(listings: TListings): Set<string>;
|
|
@@ -83,6 +83,10 @@ function clearListingsUnder(listings, path) {
|
|
|
83
83
|
for (const key of listings.keys()) if (key === path || key.startsWith(prefix)) next.delete(key);
|
|
84
84
|
return next;
|
|
85
85
|
}
|
|
86
|
+
function retainListings(listings, paths) {
|
|
87
|
+
if ([...listings.keys()].every((path) => paths.has(path))) return listings;
|
|
88
|
+
return new Map([...listings].filter(([path]) => paths.has(path)));
|
|
89
|
+
}
|
|
86
90
|
/** Tree paths whose children should keep arrival order, since sorting them would
|
|
87
91
|
* reshuffle rows under the user mid-scroll. */
|
|
88
92
|
function incompletePaths(listings) {
|
|
@@ -121,4 +125,4 @@ function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings,
|
|
|
121
125
|
};
|
|
122
126
|
}
|
|
123
127
|
//#endregion
|
|
124
|
-
export { LIST_PAGE_SIZE, advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing };
|
|
128
|
+
export { LIST_PAGE_SIZE, advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing, retainListings };
|
package/dist/styles/theme.css
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* The theme contract: `theme-*` utilities over the `--theme-*` tokens, which
|
|
2
2
|
* src/theme generates from a scheme of three choices (base, accent, contrast).
|
|
3
3
|
* Hosts set the tokens at runtime with applyTheme; the defaults below are the
|
|
4
|
-
* default theme's light
|
|
5
|
-
* wide-gamut screens.
|
|
4
|
+
* default theme's light and dark schemes, for standalone use and for any token
|
|
5
|
+
* a host leaves unset, with display-p3 values for wide-gamut screens. Each pairs
|
|
6
|
+
* its modes with light-dark(), so it follows the CSS color-scheme a host sets.
|
|
6
7
|
*
|
|
7
8
|
* Sidebar tokens (--theme-sidebar-*) are part of the contract but have no
|
|
8
9
|
* defaults here: hosts supply per-site fallbacks at the use sites, and a global
|
|
@@ -10,75 +11,94 @@
|
|
|
10
11
|
|
|
11
12
|
/* generated:start (src/theme/derive.test.ts checks this; UPDATE_THEME_CSS=1 rewrites it) */
|
|
12
13
|
:root {
|
|
13
|
-
--theme-app-bg: #f3f4f6;
|
|
14
|
-
--theme-panel-bg: #fcfeff;
|
|
15
|
-
--theme-panel-hover: #f2f5f9;
|
|
16
|
-
--theme-muted-panel-bg: #e7eaee;
|
|
17
|
-
--theme-hover: #e3e5e9;
|
|
18
|
-
--theme-input-bg: #fafcfe;
|
|
19
|
-
--theme-input-disabled-bg: #ebeef1;
|
|
20
|
-
--theme-app: #0a101b;
|
|
21
|
-
--theme-muted-text-color: #4e5664;
|
|
22
|
-
--theme-placeholder: #7e8796;
|
|
23
|
-
--theme-link: #06354f;
|
|
24
|
-
--theme-border: #cacdd0;
|
|
25
|
-
--theme-border-strong: #a3a6a9;
|
|
26
|
-
--theme-accent: #06354f;
|
|
27
|
-
--theme-accent-text: #ffffff;
|
|
28
|
-
--theme-accent-hover: #002841;
|
|
29
|
-
--theme-accent-subtle: #d3ebfc;
|
|
30
|
-
--theme-focus: #06354f;
|
|
31
|
-
--theme-focus-ring: rgba(6, 53, 79, 0.25);
|
|
32
|
-
--theme-success: #00973d;
|
|
33
|
-
--theme-success-text: #006226;
|
|
14
|
+
--theme-app-bg: light-dark(#f3f4f6, #111418);
|
|
15
|
+
--theme-panel-bg: light-dark(#fcfeff, #151c25);
|
|
16
|
+
--theme-panel-hover: light-dark(#f2f5f9, #1e262e);
|
|
17
|
+
--theme-muted-panel-bg: light-dark(#e7eaee, #1c242c);
|
|
18
|
+
--theme-hover: light-dark(#e3e5e9, #1f2730);
|
|
19
|
+
--theme-input-bg: light-dark(#fafcfe, #182028);
|
|
20
|
+
--theme-input-disabled-bg: light-dark(#ebeef1, #131a22);
|
|
21
|
+
--theme-app: light-dark(#0a101b, #e2eaf3);
|
|
22
|
+
--theme-muted-text-color: light-dark(#4e5664, #c1c9d2);
|
|
23
|
+
--theme-placeholder: light-dark(#7e8796, #9da5ad);
|
|
24
|
+
--theme-link: light-dark(#06354f, #8dcfff);
|
|
25
|
+
--theme-border: light-dark(#cacdd0, #30363d);
|
|
26
|
+
--theme-border-strong: light-dark(#a3a6a9, #4f565d);
|
|
27
|
+
--theme-accent: light-dark(#06354f, #5b9ccf);
|
|
28
|
+
--theme-accent-text: light-dark(#ffffff, #000000);
|
|
29
|
+
--theme-accent-hover: light-dark(#002841, #6aace0);
|
|
30
|
+
--theme-accent-subtle: light-dark(#d3ebfc, #0f2638);
|
|
31
|
+
--theme-focus: light-dark(#06354f, #5b9ccf);
|
|
32
|
+
--theme-focus-ring: light-dark(rgba(6, 53, 79, 0.25), rgba(91, 156, 207, 0.35));
|
|
33
|
+
--theme-success: light-dark(#00973d, #00bf54);
|
|
34
|
+
--theme-success-text: light-dark(#006226, #65e387);
|
|
34
35
|
--theme-success-solid: #00873c;
|
|
35
|
-
--theme-success-muted: rgba(0, 151, 61, 0.1);
|
|
36
|
-
--theme-error: #ea4841;
|
|
37
|
-
--theme-error-text: #a11a1b;
|
|
36
|
+
--theme-success-muted: light-dark(rgba(0, 151, 61, 0.1), rgba(0, 191, 84, 0.15));
|
|
37
|
+
--theme-error: light-dark(#ea4841, #ff6056);
|
|
38
|
+
--theme-error-text: light-dark(#a11a1b, #ffb8af);
|
|
38
39
|
--theme-error-solid: #db3934;
|
|
39
|
-
--theme-error-muted: rgba(234, 72, 65, 0.1);
|
|
40
|
-
--theme-warning: #bd7100;
|
|
41
|
-
--theme-warning-text: #7b4a00;
|
|
40
|
+
--theme-error-muted: light-dark(rgba(234, 72, 65, 0.1), rgba(255, 96, 86, 0.15));
|
|
41
|
+
--theme-warning: light-dark(#bd7100, #dd8900);
|
|
42
|
+
--theme-warning-text: light-dark(#7b4a00, #ffbe6a);
|
|
42
43
|
--theme-warning-solid: #a76900;
|
|
43
|
-
--theme-warning-muted: rgba(189, 113, 0, 0.1);
|
|
44
|
-
--theme-info: #0681f8;
|
|
45
|
-
--theme-info-text: #0050af;
|
|
46
|
-
--theme-info-solid: #0073e8;
|
|
47
|
-
--theme-info-muted: rgba(6, 129, 248, 0.1);
|
|
48
|
-
--theme-favorite: #e7457a;
|
|
49
|
-
--theme-favorite-text: #9e174b;
|
|
44
|
+
--theme-warning-muted: light-dark(rgba(189, 113, 0, 0.1), rgba(221, 137, 0, 0.15));
|
|
45
|
+
--theme-info: light-dark(#0681f8, #499fff);
|
|
46
|
+
--theme-info-text: light-dark(#0050af, #a6cfff);
|
|
47
|
+
--theme-info-solid: light-dark(#0073e8, #0073e9);
|
|
48
|
+
--theme-info-muted: light-dark(rgba(6, 129, 248, 0.1), rgba(73, 159, 255, 0.15));
|
|
49
|
+
--theme-favorite: light-dark(#e7457a, #fe5c8e);
|
|
50
|
+
--theme-favorite-text: light-dark(#9e174b, #ffb7c7);
|
|
50
51
|
--theme-favorite-solid: #d7366e;
|
|
51
|
-
--theme-favorite-muted: rgba(231, 69, 122, 0.1);
|
|
52
|
-
--theme-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.07);
|
|
53
|
-
--theme-shadow:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
--theme-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
--theme-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
--theme-code-
|
|
63
|
-
--theme-code-
|
|
64
|
-
--theme-code-
|
|
65
|
-
--theme-
|
|
66
|
-
--theme-
|
|
67
|
-
--theme-
|
|
68
|
-
--theme-
|
|
69
|
-
--theme-
|
|
70
|
-
--theme-
|
|
71
|
-
--theme-ansi-
|
|
72
|
-
--theme-ansi-
|
|
52
|
+
--theme-favorite-muted: light-dark(rgba(231, 69, 122, 0.1), rgba(254, 92, 142, 0.15));
|
|
53
|
+
--theme-shadow-sm: 0 1px 2px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
|
|
54
|
+
--theme-shadow:
|
|
55
|
+
0 4px 6px -1px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35)),
|
|
56
|
+
0 2px 4px -2px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
|
|
57
|
+
--theme-shadow-lg:
|
|
58
|
+
0 10px 15px -3px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35)),
|
|
59
|
+
0 4px 6px -4px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
|
|
60
|
+
--theme-shadow-xl:
|
|
61
|
+
0 25px 80px -20px light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6)),
|
|
62
|
+
0 10px 30px -10px light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4));
|
|
63
|
+
--theme-code-bg: light-dark(#e7eaee, #1c242c);
|
|
64
|
+
--theme-code-text: light-dark(#1c2330, #e1e9f2);
|
|
65
|
+
--theme-code-comment: light-dark(#555d6c, #c0c8d1);
|
|
66
|
+
--theme-code-keyword: light-dark(#36617d, #8cceff);
|
|
67
|
+
--theme-code-string: light-dark(#196a24, #8bd98d);
|
|
68
|
+
--theme-code-number: light-dark(#944500, #ffb882);
|
|
69
|
+
--theme-code-function: light-dark(#6c4b9e, #d3bcff);
|
|
70
|
+
--theme-code-type: light-dark(#006565, #31dbdb);
|
|
71
|
+
--theme-code-property: light-dark(#5a51a5, #31dbdb);
|
|
72
|
+
--theme-ansi-black: light-dark(#1c2330, #c0c8d1);
|
|
73
|
+
--theme-ansi-red: light-dark(#a3322d, #ffb5ab);
|
|
74
|
+
--theme-ansi-green: light-dark(#006a12, #7fdb83);
|
|
75
|
+
--theme-ansi-yellow: light-dark(#755800, #edc23e);
|
|
76
|
+
--theme-ansi-blue: light-dark(#0b5aae, #9ecbff);
|
|
77
|
+
--theme-ansi-magenta: light-dark(#8d3a88, #ffaafe);
|
|
78
|
+
--theme-ansi-cyan: light-dark(#00666c, #00dbe5);
|
|
79
|
+
--theme-ansi-white: light-dark(#555d6c, #e1e9f2);
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
@media (color-gamut: p3) {
|
|
76
83
|
:root {
|
|
77
|
-
--theme-success: color(display-p3 0.1559 0.5942 0.2459);
|
|
84
|
+
--theme-success: light-dark(color(display-p3 0.1559 0.5942 0.2459), #00bf54);
|
|
78
85
|
--theme-success-solid: color(display-p3 0.0738 0.5422 0.1959);
|
|
79
|
-
--theme-success-muted:
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
--theme-success-muted: light-dark(
|
|
87
|
+
color(display-p3 0.1559 0.5942 0.2459 / 0.1),
|
|
88
|
+
rgba(0, 191, 84, 0.15)
|
|
89
|
+
);
|
|
90
|
+
--theme-warning: light-dark(#bd7100, color(display-p3 0.8343 0.5429 0));
|
|
91
|
+
--theme-warning-solid: light-dark(
|
|
92
|
+
color(display-p3 0.6474 0.4089 0),
|
|
93
|
+
color(display-p3 0.6478 0.4092 0)
|
|
94
|
+
);
|
|
95
|
+
--theme-warning-muted: light-dark(
|
|
96
|
+
rgba(189, 113, 0, 0.1),
|
|
97
|
+
color(display-p3 0.8343 0.5429 0 / 0.15)
|
|
98
|
+
);
|
|
99
|
+
--theme-code-number: light-dark(#944500, color(display-p3 1 0.7209 0.5024));
|
|
100
|
+
--theme-ansi-red: light-dark(#a3322d, color(display-p3 1 0.7032 0.6565));
|
|
101
|
+
--theme-ansi-cyan: light-dark(color(display-p3 0 0.4024 0.4329), #00dbe5);
|
|
82
102
|
}
|
|
83
103
|
}
|
|
84
104
|
/* generated:end */
|