@parallelworks/ui 0.50.0 → 0.52.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 +204 -18
- package/dist/ai/agent/toolStrings.d.ts +2 -0
- package/dist/ai/agent/toolStrings.js +20 -18
- package/dist/ai/ai.css +12 -0
- package/dist/ai/components/AllocationSelector.js +5 -1
- package/dist/ai/components/AttachmentManager.js +51 -42
- package/dist/ai/components/AttachmentUpload.d.ts +4 -2
- package/dist/ai/components/AttachmentUpload.js +9 -9
- package/dist/ai/components/BlockedGroupBanner.js +8 -14
- package/dist/ai/components/BranchNavigator.js +11 -12
- package/dist/ai/components/ChatEmptyState.js +12 -19
- package/dist/ai/components/ChatInput.d.ts +4 -3
- package/dist/ai/components/ChatInput.js +27 -13
- package/dist/ai/components/ChatMessage.js +45 -121
- package/dist/ai/components/ChatMessageList.d.ts +5 -2
- package/dist/ai/components/ChatMessageList.js +89 -51
- package/dist/ai/components/ChatSidebar.js +11 -7
- package/dist/ai/components/ChatThread.js +1 -13
- package/dist/ai/components/DragOverlay.js +3 -3
- package/dist/ai/components/MessageAttachments.d.ts +10 -0
- package/dist/ai/components/MessageAttachments.js +78 -0
- package/dist/ai/components/ModelSelector.js +4 -4
- package/dist/ai/components/PastedText.js +2 -2
- package/dist/ai/components/ProviderIssueBanner.js +19 -23
- package/dist/ai/components/ShareDialog.js +2 -2
- package/dist/ai/components/agent/ActivityLine.d.ts +0 -2
- package/dist/ai/components/agent/ActivityLine.js +8 -51
- package/dist/ai/components/agent/AgentMessageParts.js +117 -56
- package/dist/ai/core/ChatProvider.d.ts +16 -5
- package/dist/ai/core/ChatProvider.js +41 -8
- package/dist/ai/core/config.js +4 -3
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +3 -3
- package/dist/ai/strings.d.ts +29 -3
- package/dist/ai/strings.js +81 -26
- package/dist/ai/types.d.ts +4 -0
- package/dist/ai/ui/Notice.d.ts +2 -2
- package/dist/ai/ui/Notice.js +29 -62
- package/dist/ai/ui/sidebar.d.ts +5 -3
- package/dist/ai/ui/sidebar.js +21 -9
- package/dist/components/ActionMenu.d.ts +1 -0
- package/dist/components/ActionMenu.js +6 -1
- package/dist/components/AppLink.d.ts +26 -0
- package/dist/components/AppLink.js +51 -0
- package/dist/components/Avatar.d.ts +2 -1
- package/dist/components/Avatar.js +4 -2
- package/dist/components/Button.d.ts +15 -5
- package/dist/components/Button.js +47 -40
- package/dist/components/Callout.d.ts +31 -7
- package/dist/components/Callout.js +51 -24
- package/dist/components/Card.d.ts +11 -6
- package/dist/components/Card.js +14 -8
- package/dist/components/Checkbox.js +2 -1
- package/dist/components/ColorInput.js +5 -3
- package/dist/components/Combobox.js +49 -19
- package/dist/components/ConfirmModal.d.ts +19 -8
- package/dist/components/ConfirmModal.js +31 -53
- package/dist/components/CopyButton.d.ts +38 -0
- package/dist/components/CopyButton.js +68 -0
- package/dist/components/CreateModal.js +118 -111
- package/dist/components/DatePicker.js +12 -8
- package/dist/components/DescriptionList.d.ts +51 -17
- package/dist/components/DescriptionList.js +117 -31
- package/dist/components/Disclosure.js +1 -1
- package/dist/components/Drawer.js +10 -16
- package/dist/components/Field.d.ts +15 -5
- package/dist/components/Field.js +41 -9
- package/dist/components/IconButton.d.ts +14 -5
- package/dist/components/IconButton.js +25 -14
- package/dist/components/InfoTip.d.ts +4 -1
- package/dist/components/InfoTip.js +2 -1
- package/dist/components/Input.d.ts +14 -8
- package/dist/components/Input.js +46 -31
- package/dist/components/Loader.js +1 -1
- package/dist/components/MenuEntries.d.ts +43 -12
- package/dist/components/MenuEntries.js +34 -19
- package/dist/components/Meter.js +5 -4
- package/dist/components/Modal.d.ts +28 -4
- package/dist/components/Modal.js +37 -14
- package/dist/components/Overview.d.ts +20 -12
- package/dist/components/Overview.js +14 -9
- package/dist/components/PageHeader.d.ts +47 -65
- package/dist/components/PageHeader.js +275 -153
- package/dist/components/PageHeaderAction.d.ts +67 -0
- package/dist/components/PageHeaderAction.js +107 -0
- package/dist/components/Pagination.js +6 -16
- package/dist/components/Popover.js +3 -2
- package/dist/components/Provider.d.ts +79 -19
- package/dist/components/Provider.js +140 -130
- package/dist/components/Radio.js +2 -1
- package/dist/components/RefreshButton.js +7 -8
- package/dist/components/RequiredMark.js +1 -1
- package/dist/components/RunStatusIcon.js +2 -2
- package/dist/components/Section.js +1 -1
- package/dist/components/Select.d.ts +4 -9
- package/dist/components/Select.js +24 -11
- package/dist/components/SettingModeOption.d.ts +1 -1
- package/dist/components/SettingModeOption.js +7 -1
- package/dist/components/SettingsCard.d.ts +5 -3
- package/dist/components/SettingsCard.js +27 -20
- package/dist/components/Slider.js +1 -1
- package/dist/components/StatusBadge.js +2 -2
- package/dist/components/StatusIcons.js +2 -2
- package/dist/components/Switch.js +5 -4
- package/dist/components/Table.d.ts +30 -20
- package/dist/components/Table.js +50 -73
- package/dist/components/Tabs.d.ts +3 -7
- package/dist/components/Tabs.js +6 -10
- package/dist/components/ThemeEditor.js +24 -14
- package/dist/components/Toast.d.ts +11 -3
- package/dist/components/Toast.js +47 -22
- package/dist/components/buttonClasses.js +2 -2
- package/dist/components/comboboxItems.d.ts +4 -0
- package/dist/components/comboboxItems.js +6 -1
- package/dist/components/dismiss.d.ts +12 -0
- package/dist/components/dismiss.js +19 -0
- package/dist/components/fieldBox.d.ts +4 -0
- package/dist/components/fieldBox.js +7 -3
- package/dist/components/floating.d.ts +3 -3
- package/dist/components/floating.js +1 -1
- package/dist/components/markdownCodeBreaks.js +3 -4
- package/dist/components/pageHeaderStore.d.ts +41 -0
- package/dist/components/pageHeaderStore.js +67 -0
- package/dist/components/pathBreaks.d.ts +8 -0
- package/dist/components/pathBreaks.js +28 -0
- package/dist/components/segmented.js +1 -1
- package/dist/components/shortcutKey.d.ts +2 -1
- package/dist/components/shortcutKey.js +19 -2
- package/dist/components/splitter.js +1 -1
- package/dist/components/tone.d.ts +5 -2
- package/dist/components/tone.js +15 -6
- package/dist/components/useCssIsDark.js +40 -18
- package/dist/components/useTheme.js +9 -10
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +14 -0
- package/dist/editor/Editor.d.ts +3 -2
- package/dist/editor/Editor.js +11 -2
- package/dist/editor/EditorField.d.ts +2 -1
- package/dist/editor/EditorField.js +11 -29
- package/dist/editor/FormCodePanel.d.ts +7 -3
- package/dist/editor/FormCodePanel.js +14 -7
- package/dist/editor/Monaco.d.ts +14 -5
- package/dist/editor/Monaco.js +163 -112
- package/dist/editor/index.d.ts +5 -5
- package/dist/editor/index.js +3 -3
- package/dist/editor/themes.d.ts +8 -5
- package/dist/editor/themes.js +58 -30
- package/dist/editor/yaml.d.ts +6 -2
- package/dist/editor/yaml.js +11 -2
- package/dist/file-explorer/FileExplorer.js +143 -124
- package/dist/file-explorer/FileExplorerContext.js +1 -1
- package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
- package/dist/file-explorer/FilePreview/Viewer.js +2 -2
- package/dist/file-explorer/FilePreview/index.js +4 -4
- package/dist/file-explorer/FileRow.js +1 -1
- package/dist/file-explorer/FileRowsWindow.js +34 -3
- package/dist/file-explorer/FileTable.js +3 -1
- package/dist/file-explorer/TreeView.js +37 -14
- package/dist/file-explorer/helpers.d.ts +2 -1
- package/dist/file-explorer/helpers.js +21 -20
- package/dist/file-explorer/toasts.js +27 -19
- package/dist/file-explorer/treeRows.d.ts +6 -0
- package/dist/file-explorer/treeRows.js +19 -1
- package/dist/file-explorer/useNearEnd.js +3 -6
- package/dist/form/Fields/CheckboxGroupField.js +12 -5
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Fields/LabelField.js +1 -1
- package/dist/form/Fields/ObjectField.d.ts +1 -1
- package/dist/form/Fields/ObjectField.js +3 -2
- package/dist/form/Fields/StringField.js +16 -29
- package/dist/form/Fields/TextAreaField.js +3 -4
- package/dist/form/Form.js +3 -8
- package/dist/form/Wizard/WizardNavigation.js +1 -4
- package/dist/form/Wizard/WizardStepIndicator.js +1 -1
- package/dist/form/Wizard/utils.js +1 -1
- package/dist/form/fieldFrame.d.ts +1 -1
- package/dist/form/fieldFrame.js +2 -2
- package/dist/form/types/fieldComponentTypes.d.ts +2 -1
- package/dist/graph/AnnotationBanner.d.ts +1 -2
- package/dist/graph/AnnotationBanner.js +30 -32
- package/dist/graph/Connectors.js +4 -1
- package/dist/graph/DependencyGraph.js +2 -2
- package/dist/graph/GraphEditor.js +12 -10
- package/dist/graph/GraphEditorDialogs.js +2 -2
- package/dist/graph/GraphNode.js +7 -4
- package/dist/graph/InputDialog.js +1 -1
- package/dist/graph/InputsEditor.js +14 -11
- package/dist/graph/MatrixGroup.js +9 -3
- package/dist/graph/ProblemsButton.js +2 -2
- package/dist/graph/Reveal.js +18 -10
- package/dist/graph/ShortcutsButton.d.ts +11 -2
- package/dist/graph/ShortcutsButton.js +15 -4
- package/dist/graph/TreeView.js +35 -18
- package/dist/graph/WorkflowSettingsDialog.js +1 -1
- package/dist/graph/editorChrome.js +1 -1
- package/dist/graph/editorFields.js +1 -1
- package/dist/graph/editorRows.js +16 -10
- package/dist/graph/editorStrings.d.ts +7 -0
- package/dist/graph/editorStrings.js +8 -1
- package/dist/graph/fieldProblems.js +1 -1
- package/dist/graph/inputRefs.js +1 -1
- package/dist/graph/settingsViews.js +11 -18
- package/dist/graph/stepWith.js +2 -2
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +4 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +16 -16
- package/dist/list/ActionToolbar.d.ts +44 -8
- package/dist/list/ActionToolbar.js +301 -102
- package/dist/list/ListPage.d.ts +15 -23
- package/dist/list/ListPage.js +46 -45
- package/dist/list/ListTable.d.ts +32 -7
- package/dist/list/ListTable.js +48 -12
- package/dist/list/ListViewControls.js +2 -2
- package/dist/list/UserHoverCard.js +7 -15
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +2 -2
- package/dist/list/listSearch.js +12 -10
- package/dist/list/listView.d.ts +10 -1
- package/dist/list/listView.js +15 -1
- package/dist/list/rowMenu.d.ts +2 -2
- package/dist/logviewer/LogViewer.d.ts +4 -2
- package/dist/logviewer/LogViewer.js +88 -70
- package/dist/logviewer/logviewer.css +3 -2
- package/dist/reducedMotion.d.ts +5 -0
- package/dist/reducedMotion.js +20 -0
- package/dist/safeUrl.d.ts +1 -1
- package/dist/safeUrl.js +4 -2
- package/dist/styles/theme.css +24 -10
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +1 -1
- package/dist/theme/derive.js +46 -21
- package/dist/theme/fit.js +10 -4
- package/package.json +1 -1
- package/dist/components/Breadcrumbs.d.ts +0 -37
- package/dist/components/Breadcrumbs.js +0 -90
- package/dist/components/CopyToClipboard.d.ts +0 -17
- package/dist/components/CopyToClipboard.js +0 -66
- package/dist/components/Sort.d.ts +0 -9
- package/dist/components/Sort.js +0 -42
|
@@ -2,12 +2,12 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { useStrings } from "./Provider.js";
|
|
3
3
|
import { useCopy } from "./useCopy.js";
|
|
4
4
|
import { Button } from "./Button.js";
|
|
5
|
+
import { fieldBox } from "./fieldBox.js";
|
|
5
6
|
import { parseColor, toHex } from "../theme/color.js";
|
|
6
7
|
import { CODE_STYLES, DEFAULT_THEME, THEME_PRESETS, modeOf, parseTheme, schemeFor, serializeTheme } from "../theme/model.js";
|
|
7
8
|
import { deriveTheme, generateTheme } from "../theme/derive.js";
|
|
8
9
|
import { prefersWideGamut } from "../theme/index.js";
|
|
9
10
|
import { Field } from "./Field.js";
|
|
10
|
-
import { fieldBox } from "./fieldBox.js";
|
|
11
11
|
import { Textarea } from "./Input.js";
|
|
12
12
|
import { ColorInput } from "./ColorInput.js";
|
|
13
13
|
import { Disclosure } from "./Disclosure.js";
|
|
@@ -32,7 +32,8 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
|
|
|
32
32
|
setOwnMode(next);
|
|
33
33
|
onModeChange?.(next);
|
|
34
34
|
};
|
|
35
|
-
const scheme = schemeFor(value, editing);
|
|
35
|
+
const scheme = useMemo(() => schemeFor(value, editing), [value, editing]);
|
|
36
|
+
const serialized = useMemo(() => serializeTheme(value), [value]);
|
|
36
37
|
const seed = scheme.interface;
|
|
37
38
|
const update = (next) => onChange({
|
|
38
39
|
...value,
|
|
@@ -76,7 +77,7 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
|
|
|
76
77
|
children: THEME_PRESETS.map((preset) => {
|
|
77
78
|
const native = preset.theme[editing] ? editing : preset.theme.light ? "light" : "dark";
|
|
78
79
|
const own = schemeFor(preset.theme, native).interface;
|
|
79
|
-
const current =
|
|
80
|
+
const current = presetKey(preset.theme) === serialized;
|
|
80
81
|
return /* @__PURE__ */ jsxs(Button, {
|
|
81
82
|
size: "sm",
|
|
82
83
|
variant: current ? "primary" : "secondary",
|
|
@@ -201,12 +202,21 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
|
|
|
201
202
|
})]
|
|
202
203
|
});
|
|
203
204
|
}
|
|
205
|
+
var presetKeys = /* @__PURE__ */ new WeakMap();
|
|
206
|
+
var presetKey = (theme) => {
|
|
207
|
+
let key = presetKeys.get(theme);
|
|
208
|
+
if (key === void 0) {
|
|
209
|
+
key = serializeTheme(theme);
|
|
210
|
+
presetKeys.set(theme, key);
|
|
211
|
+
}
|
|
212
|
+
return key;
|
|
213
|
+
};
|
|
204
214
|
function Swatch({ colors }) {
|
|
205
215
|
return /* @__PURE__ */ jsx("span", {
|
|
206
216
|
"aria-hidden": "true",
|
|
207
217
|
className: "flex -space-x-1",
|
|
208
218
|
children: colors.map((c, i) => /* @__PURE__ */ jsx("span", {
|
|
209
|
-
className: "size-3 rounded-full border border-
|
|
219
|
+
className: "size-3 rounded-full border border-(--theme-border-strong)",
|
|
210
220
|
style: { backgroundColor: toHex(parseColor(c) ?? {
|
|
211
221
|
l: 0,
|
|
212
222
|
c: 0,
|
|
@@ -280,7 +290,7 @@ var CODE_SAMPLE = [
|
|
|
280
290
|
/** The theme on a small page: a sidebar, a panel of text, a control, statuses and code. */
|
|
281
291
|
function ThemePreview({ theme, mode }) {
|
|
282
292
|
const { theme: t } = useStrings();
|
|
283
|
-
const scheme = schemeFor(theme, mode);
|
|
293
|
+
const scheme = useMemo(() => schemeFor(theme, mode), [theme, mode]);
|
|
284
294
|
const style = useMemo(() => {
|
|
285
295
|
const generated = generateTheme(scheme, theme.code ? { code: theme.code } : {});
|
|
286
296
|
return {
|
|
@@ -294,7 +304,7 @@ function ThemePreview({ theme, mode }) {
|
|
|
294
304
|
"data-testid": "theme-preview",
|
|
295
305
|
style,
|
|
296
306
|
className: "flex min-h-80 overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-sm text-(--theme-app) shadow-(--theme-shadow)",
|
|
297
|
-
children: [/* @__PURE__ */ jsx("
|
|
307
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
298
308
|
className: "flex w-32 shrink-0 flex-col gap-0.5 bg-(--theme-sidebar-bg) p-2",
|
|
299
309
|
children: t.previewNav.map((item, i) => /* @__PURE__ */ jsx("span", {
|
|
300
310
|
className: cx("rounded-md px-2 py-1.5", i === 1 ? "bg-(--theme-sidebar-active-bg) font-medium text-(--theme-sidebar-active-text)" : "text-(--theme-sidebar-text)"),
|
|
@@ -306,7 +316,7 @@ function ThemePreview({ theme, mode }) {
|
|
|
306
316
|
/* @__PURE__ */ jsxs("div", {
|
|
307
317
|
className: "flex flex-col gap-2 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) p-3 shadow-(--theme-shadow-sm)",
|
|
308
318
|
children: [
|
|
309
|
-
/* @__PURE__ */ jsx("
|
|
319
|
+
/* @__PURE__ */ jsx("p", {
|
|
310
320
|
className: "font-semibold",
|
|
311
321
|
children: t.previewHeading
|
|
312
322
|
}),
|
|
@@ -318,13 +328,13 @@ function ThemePreview({ theme, mode }) {
|
|
|
318
328
|
/* @__PURE__ */ jsxs("div", {
|
|
319
329
|
className: "flex flex-wrap items-center gap-2",
|
|
320
330
|
children: [
|
|
321
|
-
/* @__PURE__ */
|
|
322
|
-
className: "rounded-full bg-(--theme-success-muted) px-2 py-0.5 text-xs text-(--theme-success)",
|
|
323
|
-
children: t.previewPassed
|
|
331
|
+
/* @__PURE__ */ jsxs("span", {
|
|
332
|
+
className: "inline-flex items-center gap-1.5 rounded-full bg-(--theme-success-muted) px-2 py-0.5 text-xs text-(--theme-success-text)",
|
|
333
|
+
children: [/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-(--theme-success)" }), t.previewPassed]
|
|
324
334
|
}),
|
|
325
|
-
/* @__PURE__ */
|
|
326
|
-
className: "rounded-full bg-(--theme-error-muted) px-2 py-0.5 text-xs text-(--theme-error)",
|
|
327
|
-
children: t.previewFailed
|
|
335
|
+
/* @__PURE__ */ jsxs("span", {
|
|
336
|
+
className: "inline-flex items-center gap-1.5 rounded-full bg-(--theme-error-muted) px-2 py-0.5 text-xs text-(--theme-error-text)",
|
|
337
|
+
children: [/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-(--theme-error)" }), t.previewFailed]
|
|
328
338
|
}),
|
|
329
339
|
/* @__PURE__ */ jsx("span", {
|
|
330
340
|
className: "text-(--theme-link) underline underline-offset-2",
|
|
@@ -337,7 +347,7 @@ function ThemePreview({ theme, mode }) {
|
|
|
337
347
|
/* @__PURE__ */ jsxs("div", {
|
|
338
348
|
className: "flex items-center gap-2",
|
|
339
349
|
children: [/* @__PURE__ */ jsx("span", {
|
|
340
|
-
className: cx(fieldBox({ size: "sm" }), "flex-1 cursor-default text-(--theme-placeholder) border-(--theme-border-strong)"),
|
|
350
|
+
className: cx(fieldBox({ size: "sm" }), "flex flex-1 cursor-default items-center text-(--theme-placeholder) border-(--theme-border-strong)"),
|
|
341
351
|
children: t.previewSearch
|
|
342
352
|
}), /* @__PURE__ */ jsx("span", {
|
|
343
353
|
className: "rounded-md bg-(--theme-accent) px-3 py-1.5 text-xs font-medium text-(--theme-accent-text)",
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import { type LinkTarget } from './AppLink.js';
|
|
2
3
|
export type ToastTone = 'info' | 'success' | 'warning' | 'error';
|
|
3
|
-
|
|
4
|
+
/** Runs `onClick`, or with `href` is a link, such as to what the toast reports
|
|
5
|
+
* on; either way the toast then closes. */
|
|
6
|
+
export type ToastAction = {
|
|
4
7
|
label: ReactNode;
|
|
5
|
-
/** Runs, then the toast closes. */
|
|
6
8
|
onClick: () => void;
|
|
7
|
-
|
|
9
|
+
href?: undefined;
|
|
10
|
+
} | ({
|
|
11
|
+
label: ReactNode;
|
|
12
|
+
onClick?: undefined;
|
|
13
|
+
} & LinkTarget & {
|
|
14
|
+
href: string;
|
|
15
|
+
});
|
|
8
16
|
export interface ToastOptions {
|
|
9
17
|
/** Shows the toast in place of an open one with this id, rather than stacking another. */
|
|
10
18
|
id?: string | undefined;
|
package/dist/components/Toast.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { CloseIcon, ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from "../icons.js";
|
|
3
2
|
import { buttonClasses } from "./buttonClasses.js";
|
|
3
|
+
import { CloseIcon, ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from "../icons.js";
|
|
4
4
|
import { Loader } from "./Loader.js";
|
|
5
|
-
import {
|
|
5
|
+
import { toneIcon } from "./tone.js";
|
|
6
6
|
import { useStrings } from "./Provider.js";
|
|
7
|
+
import { AppLink } from "./AppLink.js";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { useEffect, useId, useSyncExternalStore } from "react";
|
|
9
10
|
import { Toast } from "@base-ui/react/toast";
|
|
10
11
|
//#region src/components/Toast.tsx
|
|
12
|
+
function actionFields(action) {
|
|
13
|
+
if (action.href === void 0) return {
|
|
14
|
+
actionProps: {
|
|
15
|
+
children: action.label,
|
|
16
|
+
onClick: action.onClick
|
|
17
|
+
},
|
|
18
|
+
link: void 0
|
|
19
|
+
};
|
|
20
|
+
const { onClick: _, ...link } = action;
|
|
21
|
+
return {
|
|
22
|
+
actionProps: void 0,
|
|
23
|
+
link
|
|
24
|
+
};
|
|
25
|
+
}
|
|
11
26
|
var manager = Toast.createToastManager();
|
|
12
27
|
var TIMEOUT = {
|
|
13
28
|
info: 5e3,
|
|
@@ -18,21 +33,19 @@ var TIMEOUT = {
|
|
|
18
33
|
};
|
|
19
34
|
/** Everything a toast shows, from its kind's defaults and the options that override them. */
|
|
20
35
|
function toastOptions(kind, message, options) {
|
|
21
|
-
const
|
|
36
|
+
const action = options.action && actionFields(options.action);
|
|
22
37
|
return {
|
|
23
38
|
type: kind,
|
|
24
39
|
title: options.title,
|
|
25
40
|
description: message,
|
|
26
41
|
timeout: options.timeout === false ? 0 : options.timeout ?? TIMEOUT[kind],
|
|
27
42
|
priority: kind === "error" ? "high" : "low",
|
|
28
|
-
actionProps: action
|
|
29
|
-
children: action.label,
|
|
30
|
-
onClick: action.onClick
|
|
31
|
-
},
|
|
43
|
+
actionProps: action?.actionProps,
|
|
32
44
|
data: {
|
|
33
45
|
kind,
|
|
34
46
|
icon: options.icon ?? true,
|
|
35
|
-
dismissible: options.dismissible ?? kind !== "loading"
|
|
47
|
+
dismissible: options.dismissible ?? kind !== "loading",
|
|
48
|
+
link: action?.link
|
|
36
49
|
}
|
|
37
50
|
};
|
|
38
51
|
}
|
|
@@ -59,18 +72,17 @@ var toast = {
|
|
|
59
72
|
icon: true,
|
|
60
73
|
dismissible: true
|
|
61
74
|
};
|
|
75
|
+
const action = options.action && actionFields(options.action);
|
|
62
76
|
return {
|
|
63
77
|
...message === void 0 ? {} : { description: message },
|
|
64
78
|
..."title" in options ? { title: options.title } : {},
|
|
65
79
|
...options.timeout === void 0 ? {} : { timeout: options.timeout === false ? 0 : options.timeout },
|
|
66
|
-
...
|
|
67
|
-
children: options.action.label,
|
|
68
|
-
onClick: options.action.onClick
|
|
69
|
-
} },
|
|
80
|
+
...action ? { actionProps: action.actionProps } : {},
|
|
70
81
|
data: {
|
|
71
82
|
kind: data.kind,
|
|
72
83
|
icon: options.icon ?? data.icon,
|
|
73
|
-
dismissible: options.dismissible ?? data.dismissible
|
|
84
|
+
dismissible: options.dismissible ?? data.dismissible,
|
|
85
|
+
link: action ? action.link : data.link
|
|
74
86
|
}
|
|
75
87
|
};
|
|
76
88
|
});
|
|
@@ -149,18 +161,22 @@ function ToneIcon({ tone }) {
|
|
|
149
161
|
const Icon = ICONS[tone];
|
|
150
162
|
return /* @__PURE__ */ jsx(Icon, {
|
|
151
163
|
"aria-hidden": "true",
|
|
152
|
-
className: cx("mt-0.5 size-4 shrink-0",
|
|
164
|
+
className: cx("mt-0.5 size-4 shrink-0", toneIcon[tone])
|
|
153
165
|
});
|
|
154
166
|
}
|
|
167
|
+
var actionClasses = buttonClasses({
|
|
168
|
+
variant: "outline",
|
|
169
|
+
size: "xs"
|
|
170
|
+
});
|
|
155
171
|
function ToastList() {
|
|
156
172
|
const { toasts } = Toast.useToastManager();
|
|
157
173
|
const { common } = useStrings();
|
|
158
174
|
return toasts.map((item) => {
|
|
159
|
-
const { kind = "info", icon = true, dismissible = true } = item.data ?? {};
|
|
175
|
+
const { kind = "info", icon = true, dismissible = true, link } = item.data ?? {};
|
|
160
176
|
return /* @__PURE__ */ jsx(Toast.Root, {
|
|
161
177
|
toast: item,
|
|
162
178
|
swipeDirection: ["up", "right"],
|
|
163
|
-
className: cx("[--gap:0.5rem] [--peek:0.5rem] [--scale:calc(max(0,1-(var(--toast-index)*0.05)))] [--height:var(--toast-frontmost-height,var(--toast-height))]", "[--offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--gap)+var(--toast-swipe-movement-y))]", "absolute inset-x-0 top-0 z-[calc(100-var(--toast-index))] h-(--height) origin-top select-none", "[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+var(--toast-index)*var(--peek)+(1-var(--scale))*var(--height)))_scale(var(--scale))]", "data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]", "data-starting-style:[transform:translateY(-150%)] data-ending-style:opacity-0 data-limited:opacity-0", "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(-150%)]", "data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]", "data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]", "rounded-lg border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-(--theme-shadow-lg) outline-
|
|
179
|
+
className: cx("[--gap:0.5rem] [--peek:0.5rem] [--scale:calc(max(0,1-(var(--toast-index)*0.05)))] [--height:var(--toast-frontmost-height,var(--toast-height))]", "[--offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--gap)+var(--toast-swipe-movement-y))]", "absolute inset-x-0 top-0 z-[calc(100-var(--toast-index))] h-(--height) origin-top select-none", "[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+var(--toast-index)*var(--peek)+(1-var(--scale))*var(--height)))_scale(var(--scale))]", "data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]", "data-starting-style:[transform:translateY(-150%)] data-ending-style:opacity-0 data-limited:opacity-0", "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(-150%)]", "data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]", "data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]", "rounded-lg border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-(--theme-shadow-lg) outline-hidden focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-(--theme-focus)", "[transition:transform_0.4s_cubic-bezier(0.22,1,0.36,1),opacity_0.4s,height_0.15s] motion-reduce:transition-none", "after:absolute after:inset-x-0 after:top-full after:h-[calc(var(--gap)+1px)] after:content-['']"),
|
|
164
180
|
children: /* @__PURE__ */ jsxs(Toast.Content, {
|
|
165
181
|
className: "flex items-start gap-3 overflow-hidden p-3 transition-opacity duration-200 data-behind:opacity-0 data-expanded:opacity-100",
|
|
166
182
|
children: [
|
|
@@ -184,15 +200,24 @@ function ToastList() {
|
|
|
184
200
|
}),
|
|
185
201
|
item.actionProps && /* @__PURE__ */ jsx(Toast.Action, {
|
|
186
202
|
onClick: () => manager.close(item.id),
|
|
187
|
-
className:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
203
|
+
className: actionClasses
|
|
204
|
+
}),
|
|
205
|
+
link && /* @__PURE__ */ jsx(AppLink, {
|
|
206
|
+
href: link.href,
|
|
207
|
+
reloadDocument: link.reloadDocument,
|
|
208
|
+
target: link.target,
|
|
209
|
+
onClick: () => manager.close(item.id),
|
|
210
|
+
className: actionClasses,
|
|
211
|
+
children: link.label
|
|
191
212
|
}),
|
|
192
213
|
dismissible && /* @__PURE__ */ jsx(Toast.Close, {
|
|
193
214
|
"aria-label": common.close,
|
|
194
|
-
className:
|
|
195
|
-
|
|
215
|
+
className: cx(buttonClasses({
|
|
216
|
+
variant: "ghost",
|
|
217
|
+
size: "sm",
|
|
218
|
+
iconOnly: true
|
|
219
|
+
}), "-m-1.5"),
|
|
220
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
196
221
|
})
|
|
197
222
|
]
|
|
198
223
|
})
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
//#region src/components/buttonClasses.ts
|
|
3
|
-
var base = "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium no-underline transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-
|
|
3
|
+
var base = "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium no-underline transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
|
|
4
4
|
var variants = {
|
|
5
5
|
primary: "bg-(--theme-accent) text-(--theme-accent-text) hover:not-disabled:not-aria-disabled:bg-(--theme-accent-hover)",
|
|
6
6
|
secondary: "border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) hover:not-disabled:not-aria-disabled:bg-(--theme-hover)",
|
|
7
7
|
outline: "border border-(--theme-border) text-(--theme-muted-text-color) hover:not-disabled:not-aria-disabled:bg-(--theme-muted-panel-bg) hover:not-disabled:not-aria-disabled:text-(--theme-app) aria-pressed:border-(--theme-link) aria-pressed:text-(--theme-app) data-selected:border-(--theme-link) data-selected:text-(--theme-app) data-popup-open:bg-(--theme-muted-panel-bg) data-popup-open:text-(--theme-app)",
|
|
8
8
|
ghost: "text-(--theme-muted-text-color) hover:not-disabled:not-aria-disabled:bg-(--theme-muted-panel-bg) hover:not-disabled:not-aria-disabled:text-(--theme-app) aria-pressed:bg-(--theme-muted-panel-bg) aria-pressed:text-(--theme-link) data-selected:bg-(--theme-muted-panel-bg) data-selected:text-(--theme-link) data-popup-open:bg-(--theme-muted-panel-bg) data-popup-open:text-(--theme-app)",
|
|
9
|
-
danger: "bg-(--theme-error) text-white hover:not-disabled:not-aria-disabled:bg-(--theme-error)/90"
|
|
9
|
+
danger: "bg-(--theme-error-solid) text-white hover:not-disabled:not-aria-disabled:bg-(--theme-error-solid)/90"
|
|
10
10
|
};
|
|
11
11
|
var sizes = {
|
|
12
12
|
xs: "h-6 px-2 text-xs [&_svg]:size-3",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
/** An option's row in a Select's or a Combobox's list, so both lists look alike: the icon, the
|
|
3
|
+
* label over its description, and the check at the end. */
|
|
4
|
+
export declare const pickerItemClassName: string;
|
|
5
|
+
/** An option of a Select or a Combobox. */
|
|
2
6
|
export interface ComboboxItem<Value = string> {
|
|
3
7
|
value: Value;
|
|
4
8
|
label: string;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { panelItemClassName } from "./floating.js";
|
|
1
3
|
//#region src/components/comboboxItems.ts
|
|
4
|
+
/** An option's row in a Select's or a Combobox's list, so both lists look alike: the icon, the
|
|
5
|
+
* label over its description, and the check at the end. */
|
|
6
|
+
var pickerItemClassName = cx(panelItemClassName, "data-selected:font-medium");
|
|
2
7
|
function isComboboxGroup(item) {
|
|
3
8
|
return typeof item === "object" && "items" in item;
|
|
4
9
|
}
|
|
@@ -7,4 +12,4 @@ function comboboxLeaves(items) {
|
|
|
7
12
|
return items.flatMap((item) => isComboboxGroup(item) ? item.items : [item]);
|
|
8
13
|
}
|
|
9
14
|
//#endregion
|
|
10
|
-
export { comboboxLeaves, isComboboxGroup };
|
|
15
|
+
export { comboboxLeaves, isComboboxGroup, pickerItemClassName };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface CloseDetails {
|
|
2
|
+
reason: string;
|
|
3
|
+
event: Event;
|
|
4
|
+
cancel: () => void;
|
|
5
|
+
}
|
|
6
|
+
/** The `onOpenChange` of a modal or drawer that the host opens and closes:
|
|
7
|
+
* Escape and a press outside close it unless it's not `dismissible`, and a
|
|
8
|
+
* press on a toast never does, since the toast sits above the backdrop. */
|
|
9
|
+
export declare function closeHandler(dismissible: boolean, onClose: () => void): (next: boolean, details: CloseDetails) => void;
|
|
10
|
+
/** The row of a dialog's actions along its bottom edge, ruled off from its body. */
|
|
11
|
+
export declare const dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-5 py-3";
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { pressedToast } from "./Toast.js";
|
|
2
|
+
//#region src/components/dismiss.ts
|
|
3
|
+
/** The `onOpenChange` of a modal or drawer that the host opens and closes:
|
|
4
|
+
* Escape and a press outside close it unless it's not `dismissible`, and a
|
|
5
|
+
* press on a toast never does, since the toast sits above the backdrop. */
|
|
6
|
+
function closeHandler(dismissible, onClose) {
|
|
7
|
+
return (next, details) => {
|
|
8
|
+
if (next) return;
|
|
9
|
+
if (!dismissible && details.reason === "escape-key" || details.reason === "outside-press" && pressedToast(details.event)) {
|
|
10
|
+
details.cancel();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
onClose();
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** The row of a dialog's actions along its bottom edge, ruled off from its body. */
|
|
17
|
+
var dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-5 py-3";
|
|
18
|
+
//#endregion
|
|
19
|
+
export { closeHandler, dialogFooterClassName };
|
|
@@ -9,6 +9,10 @@ export interface FieldBoxOptions {
|
|
|
9
9
|
* buttons beside it: focus, invalid and disabled then follow what is inside. */
|
|
10
10
|
within?: boolean | undefined;
|
|
11
11
|
}
|
|
12
|
+
/** The keyboard focus ring of a control that isn't a box, such as a checkbox, switch or slider
|
|
13
|
+
* thumb: an outline in the theme's focus color, which is solved for 3:1 on every surface a
|
|
14
|
+
* control sits on, so it shows on a checked control as well as an empty one. */
|
|
15
|
+
export declare const focusOutline = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)";
|
|
12
16
|
/** The box every input-like control draws: text inputs, textareas, and the triggers of
|
|
13
17
|
* pickers. Invalid follows `aria-invalid`, disabled follows `disabled` or `data-disabled`. */
|
|
14
18
|
export declare function fieldBox({ size, multiline, padded, within, }?: FieldBoxOptions): string;
|
|
@@ -16,9 +16,13 @@ var sizes = {
|
|
|
16
16
|
text: "text-sm"
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
/** The keyboard focus ring of a control that isn't a box, such as a checkbox, switch or slider
|
|
20
|
+
* thumb: an outline in the theme's focus color, which is solved for 3:1 on every surface a
|
|
21
|
+
* control sits on, so it shows on a checked control as well as an empty one. */
|
|
22
|
+
var focusOutline = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)";
|
|
19
23
|
var base = "w-full min-w-0 rounded-md border border-(--theme-border) bg-(--theme-input-bg) text-(--theme-app) outline-none transition-colors placeholder:text-(--theme-placeholder)";
|
|
20
|
-
var own = cx("focus-visible:border-(--theme-
|
|
21
|
-
var inside = cx("has-[:focus-visible]:border-(--theme-
|
|
24
|
+
var own = cx("focus-visible:border-(--theme-focus) focus-visible:ring-1 focus-visible:ring-(--theme-focus)", "aria-invalid:border-(--theme-error) aria-invalid:focus-visible:ring-(--theme-error)", "disabled:cursor-not-allowed disabled:bg-(--theme-input-disabled-bg) disabled:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
|
|
25
|
+
var inside = cx("has-[:focus-visible]:border-(--theme-focus) has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-(--theme-focus)", "has-[[aria-invalid=true]]:border-(--theme-error) has-[[aria-invalid=true]:focus-visible]:ring-(--theme-error)", "has-[input:disabled]:cursor-not-allowed has-[input:disabled]:bg-(--theme-input-disabled-bg) has-[input:disabled]:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
|
|
22
26
|
/** The box every input-like control draws: text inputs, textareas, and the triggers of
|
|
23
27
|
* pickers. Invalid follows `aria-invalid`, disabled follows `disabled` or `data-disabled`. */
|
|
24
28
|
function fieldBox({ size = "md", multiline = false, padded = true, within = false } = {}) {
|
|
@@ -26,4 +30,4 @@ function fieldBox({ size = "md", multiline = false, padded = true, within = fals
|
|
|
26
30
|
return cx(base, box.text, multiline ? box.minHeight : box.height, padded && box.px, padded && multiline && box.py, within ? inside : own);
|
|
27
31
|
}
|
|
28
32
|
//#endregion
|
|
29
|
-
export { fieldBox };
|
|
33
|
+
export { fieldBox, focusOutline };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/** Above dialogs and sticky chrome; hidden while its anchor is scrolled out of view. */
|
|
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
|
-
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";
|
|
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
5
|
/** A row in a panel. */
|
|
6
6
|
export declare const panelItemClassName = "flex w-full cursor-pointer select-none items-center gap-2 px-3 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
7
|
/** A tooltip's or infotip's small inverted surface. */
|
|
8
|
-
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";
|
|
8
|
+
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
9
|
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";
|
|
10
10
|
/** A hover card's surface; the card sets its own width and padding. */
|
|
11
|
-
export declare const cardClassName = "overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) 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";
|
|
11
|
+
export declare const cardClassName = "overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) 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";
|
|
12
12
|
/** Where a popup opens: under an element, such as the button that opened it, or
|
|
13
13
|
* at a pointer event's point, which then moves with the element it landed on. */
|
|
14
14
|
export type FloatingAnchor = Element | {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/components/floating.ts
|
|
2
2
|
/** Above dialogs and sticky chrome; hidden while its anchor is scrolled out of view. */
|
|
3
3
|
var positionerClassName = "z-(--layer-popover) outline-none data-anchor-hidden:invisible";
|
|
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";
|
|
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
7
|
/** A row in a panel. */
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
+
import { pathPieces } from "./pathBreaks.js";
|
|
1
2
|
//#region src/components/markdownCodeBreaks.ts
|
|
2
|
-
var BREAK_AFTER = /(?<=[/])/;
|
|
3
3
|
function withBreaks(text) {
|
|
4
|
-
const pieces = text.split(BREAK_AFTER);
|
|
5
4
|
const out = [];
|
|
6
|
-
|
|
5
|
+
pathPieces(text).forEach((piece, i) => {
|
|
7
6
|
if (i > 0) out.push({
|
|
8
7
|
type: "element",
|
|
9
8
|
tagName: "wbr",
|
|
10
9
|
properties: {},
|
|
11
10
|
children: []
|
|
12
11
|
});
|
|
13
|
-
|
|
12
|
+
out.push({
|
|
14
13
|
type: "text",
|
|
15
14
|
value: piece
|
|
16
15
|
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** One step of the trail to the current page. */
|
|
2
|
+
export interface Breadcrumb {
|
|
3
|
+
/** Empty while the name is still loading: the bar shows a placeholder. */
|
|
4
|
+
label: string;
|
|
5
|
+
href?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export type PageHeaderRegion = 'titleActions' | 'actions' | 'toolbar';
|
|
8
|
+
/** The nodes a declaration portals its regions into. They are created with the
|
|
9
|
+
* declaration, before any bar exists, so its content renders on the first pass
|
|
10
|
+
* and keeps its state when the bar unmounts or moves. */
|
|
11
|
+
export type RegionNodes = Readonly<Record<PageHeaderRegion, HTMLElement>>;
|
|
12
|
+
export interface Declaration {
|
|
13
|
+
breadcrumbs: readonly Breadcrumb[] | undefined;
|
|
14
|
+
hidden: boolean;
|
|
15
|
+
nodes: RegionNodes | null;
|
|
16
|
+
fills: Readonly<Record<PageHeaderRegion, boolean>>;
|
|
17
|
+
}
|
|
18
|
+
export interface PageHeaderSnapshot {
|
|
19
|
+
breadcrumbs: readonly Breadcrumb[];
|
|
20
|
+
hidden: boolean;
|
|
21
|
+
titleActions: readonly HTMLElement[];
|
|
22
|
+
actions: readonly HTMLElement[];
|
|
23
|
+
toolbar: readonly HTMLElement[];
|
|
24
|
+
}
|
|
25
|
+
export declare function sameCrumbs(a: readonly Breadcrumb[] | undefined, b: readonly Breadcrumb[] | undefined): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Holds what each mounted PageHeader declares, keyed by its render order. The
|
|
28
|
+
* bar reads one merged snapshot through useSyncExternalStore, so a page
|
|
29
|
+
* changing its header re-renders the bar alone, never the app under the
|
|
30
|
+
* provider.
|
|
31
|
+
*/
|
|
32
|
+
export declare class PageHeaderStore {
|
|
33
|
+
private declarations;
|
|
34
|
+
private listeners;
|
|
35
|
+
private snapshot;
|
|
36
|
+
subscribe: (listener: () => void) => (() => void);
|
|
37
|
+
getSnapshot: () => PageHeaderSnapshot;
|
|
38
|
+
set(order: number, declaration: Declaration): void;
|
|
39
|
+
delete(order: number): void;
|
|
40
|
+
private publish;
|
|
41
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region src/components/pageHeaderStore.ts
|
|
2
|
+
var NO_NODES = [];
|
|
3
|
+
var NO_CRUMBS = [];
|
|
4
|
+
var EMPTY = {
|
|
5
|
+
breadcrumbs: NO_CRUMBS,
|
|
6
|
+
hidden: false,
|
|
7
|
+
titleActions: NO_NODES,
|
|
8
|
+
actions: NO_NODES,
|
|
9
|
+
toolbar: NO_NODES
|
|
10
|
+
};
|
|
11
|
+
function sameCrumbs(a, b) {
|
|
12
|
+
if (a === b) return true;
|
|
13
|
+
if (!a || !b || a.length !== b.length) return false;
|
|
14
|
+
return a.every((crumb, i) => crumb.label === b[i]?.label && crumb.href === b[i]?.href);
|
|
15
|
+
}
|
|
16
|
+
function sameDeclaration(a, b) {
|
|
17
|
+
return sameCrumbs(a.breadcrumbs, b.breadcrumbs) && a.hidden === b.hidden && a.nodes === b.nodes && a.fills.titleActions === b.fills.titleActions && a.fills.actions === b.fills.actions && a.fills.toolbar === b.fills.toolbar;
|
|
18
|
+
}
|
|
19
|
+
function sameNodes(a, b) {
|
|
20
|
+
return a.length === b.length && a.every((node, i) => node === b[i]);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Holds what each mounted PageHeader declares, keyed by its render order. The
|
|
24
|
+
* bar reads one merged snapshot through useSyncExternalStore, so a page
|
|
25
|
+
* changing its header re-renders the bar alone, never the app under the
|
|
26
|
+
* provider.
|
|
27
|
+
*/
|
|
28
|
+
var PageHeaderStore = class {
|
|
29
|
+
declarations = /* @__PURE__ */ new Map();
|
|
30
|
+
listeners = /* @__PURE__ */ new Set();
|
|
31
|
+
snapshot = EMPTY;
|
|
32
|
+
subscribe = (listener) => {
|
|
33
|
+
this.listeners.add(listener);
|
|
34
|
+
return () => {
|
|
35
|
+
this.listeners.delete(listener);
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
getSnapshot = () => this.snapshot;
|
|
39
|
+
set(order, declaration) {
|
|
40
|
+
const prev = this.declarations.get(order);
|
|
41
|
+
if (prev && sameDeclaration(prev, declaration)) return;
|
|
42
|
+
this.declarations.set(order, declaration);
|
|
43
|
+
this.publish();
|
|
44
|
+
}
|
|
45
|
+
delete(order) {
|
|
46
|
+
if (this.declarations.delete(order)) this.publish();
|
|
47
|
+
}
|
|
48
|
+
publish() {
|
|
49
|
+
const ordered = [...this.declarations.entries()].sort(([a], [b]) => a - b).map(([, declaration]) => declaration);
|
|
50
|
+
const regionNodes = (region, prev) => {
|
|
51
|
+
const next = ordered.flatMap((d) => d.nodes && d.fills[region] ? [d.nodes[region]] : []);
|
|
52
|
+
return sameNodes(next, prev) ? prev : next;
|
|
53
|
+
};
|
|
54
|
+
const trail = ordered.findLast((d) => d.breadcrumbs !== void 0)?.breadcrumbs ?? NO_CRUMBS;
|
|
55
|
+
const prev = this.snapshot;
|
|
56
|
+
this.snapshot = {
|
|
57
|
+
breadcrumbs: sameCrumbs(trail, prev.breadcrumbs) ? prev.breadcrumbs : trail,
|
|
58
|
+
hidden: ordered.some((d) => d.hidden),
|
|
59
|
+
titleActions: regionNodes("titleActions", prev.titleActions),
|
|
60
|
+
actions: regionNodes("actions", prev.actions),
|
|
61
|
+
toolbar: regionNodes("toolbar", prev.toolbar)
|
|
62
|
+
};
|
|
63
|
+
for (const listener of this.listeners) listener();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
//#endregion
|
|
67
|
+
export { PageHeaderStore, sameCrumbs };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** The pieces of `text` with a break allowed after each, split after each path
|
|
3
|
+
* separator; one piece when it holds none. */
|
|
4
|
+
export declare function pathPieces(text: string): string[];
|
|
5
|
+
/** `node` with a place to wrap after each path separator in its text: a string,
|
|
6
|
+
* or an element, such as a link, whose child is one. Deeper content is left as
|
|
7
|
+
* it is. */
|
|
8
|
+
export declare function withPathBreaks(node: ReactNode): ReactNode;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Children, Fragment as Fragment$1, cloneElement, isValidElement } from "react";
|
|
3
|
+
//#region src/components/pathBreaks.tsx
|
|
4
|
+
var SEPARATOR = /(?<=[/\\])(?![/\\])/;
|
|
5
|
+
/** The pieces of `text` with a break allowed after each, split after each path
|
|
6
|
+
* separator; one piece when it holds none. */
|
|
7
|
+
function pathPieces(text) {
|
|
8
|
+
return text.split(SEPARATOR).filter((piece) => piece !== "");
|
|
9
|
+
}
|
|
10
|
+
function breakText(text) {
|
|
11
|
+
const pieces = pathPieces(text);
|
|
12
|
+
if (pieces.length < 2) return text;
|
|
13
|
+
return pieces.map((piece, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [piece, i < pieces.length - 1 && /* @__PURE__ */ jsx("wbr", {})] }, i));
|
|
14
|
+
}
|
|
15
|
+
/** `node` with a place to wrap after each path separator in its text: a string,
|
|
16
|
+
* or an element, such as a link, whose child is one. Deeper content is left as
|
|
17
|
+
* it is. */
|
|
18
|
+
function withPathBreaks(node) {
|
|
19
|
+
if (typeof node === "string") return breakText(node);
|
|
20
|
+
if (isValidElement(node)) {
|
|
21
|
+
const inner = node.props.children;
|
|
22
|
+
return typeof inner === "string" ? cloneElement(node, void 0, breakText(inner)) : node;
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(node)) return Children.map(node, (child) => typeof child === "string" ? breakText(child) : child);
|
|
25
|
+
return node;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { pathPieces, withPathBreaks };
|
|
@@ -5,7 +5,7 @@ function segmentGroupClassName({ fill, iconOnly }) {
|
|
|
5
5
|
return cx("gap-0.5", iconOnly ? "flex flex-col items-center" : cx("rounded-lg theme-muted-panel p-0.5", fill ? "grid auto-cols-fr grid-flow-col" : "inline-flex"));
|
|
6
6
|
}
|
|
7
7
|
function segmentClassName(current, { fill, iconOnly }) {
|
|
8
|
-
return cx("relative flex min-w-0 cursor-pointer items-center justify-center rounded-md font-medium transition-colors duration-150
|
|
8
|
+
return cx("relative flex min-w-0 cursor-pointer items-center justify-center rounded-md font-medium transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) data-disabled:cursor-not-allowed data-disabled:opacity-50", current ? "bg-(--theme-panel-bg) theme-text shadow-sm ring-1 ring-(--theme-border)" : "theme-muted-text hover:theme-text hover:bg-(--theme-hover)", iconOnly ? "h-8 w-8" : cx("h-7 gap-1.5 text-[13px]", fill ? "px-1.5" : "px-2.5"));
|
|
9
9
|
}
|
|
10
10
|
function SegmentContent({ label, icon, badge, iconOnly }) {
|
|
11
11
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/** Guards page shortcuts from firing inside
|
|
1
|
+
/** Guards page shortcuts from firing inside text fields, editors, dialogs, and
|
|
2
|
+
* widgets with typeahead such as menus, lists and trees. */
|
|
2
3
|
export declare function isTextEntryContext(target: EventTarget | null): boolean;
|
|
3
4
|
/** Calls `onPress` on a single key, such as F to filter, unless the key goes to a text field. */
|
|
4
5
|
export declare function useShortcutKey(key: string | undefined, onPress: () => void): void;
|