@parallelworks/ui 0.51.0 → 0.53.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 +197 -17
- package/dist/ai/agent/toolStrings.d.ts +2 -0
- package/dist/ai/agent/toolStrings.js +20 -18
- package/dist/ai/ai.css +17 -3
- 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 +3 -3
- 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 +114 -53
- 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 +80 -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 +22 -10
- 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 +50 -19
- 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 +25 -5
- package/dist/components/DescriptionList.js +56 -22
- package/dist/components/Disclosure.js +1 -1
- package/dist/components/Drawer.js +10 -16
- package/dist/components/Field.d.ts +16 -5
- package/dist/components/Field.js +63 -8
- package/dist/components/IconButton.d.ts +14 -5
- package/dist/components/IconButton.js +25 -14
- package/dist/components/InfoTip.d.ts +12 -1
- package/dist/components/InfoTip.js +13 -2
- 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/MarkdownImpl.d.ts +1 -0
- package/dist/components/MarkdownImpl.js +1 -0
- package/dist/components/MenuEntries.d.ts +4 -0
- package/dist/components/MenuEntries.js +11 -12
- 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.d.ts +4 -1
- package/dist/components/Popover.js +5 -3
- 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/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/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 +18 -8
- package/dist/components/Toast.d.ts +11 -3
- package/dist/components/Toast.js +45 -20
- package/dist/components/buttonClasses.js +1 -1
- 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/focus.d.ts +5 -0
- package/dist/components/focus.js +21 -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/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 +24 -5
- 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 +22 -6
- package/dist/editor/Monaco.js +177 -113
- package/dist/editor/editorModel.d.ts +1 -1
- package/dist/editor/editorModel.js +1 -1
- package/dist/editor/index.d.ts +6 -5
- package/dist/editor/index.js +5 -4
- package/dist/editor/languages.d.ts +24 -0
- package/dist/editor/languages.js +31 -0
- package/dist/editor/monacoFeatures.d.ts +7 -0
- package/dist/editor/monacoFeatures.js +19 -0
- package/dist/editor/themes.d.ts +8 -5
- package/dist/editor/themes.js +65 -32
- package/dist/editor/workers.d.ts +3 -3
- package/dist/editor/workers.js +8 -4
- package/dist/editor/yaml.d.ts +6 -2
- package/dist/editor/yaml.js +11 -2
- package/dist/editor/yamlLanguage.js +55 -38
- package/dist/file-explorer/FileExplorer.d.ts +18 -4
- package/dist/file-explorer/FileExplorer.js +204 -142
- package/dist/file-explorer/FileExplorerContext.js +1 -1
- package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
- package/dist/file-explorer/FilePreview/Viewer.js +14 -10
- package/dist/file-explorer/FilePreview/index.js +4 -4
- package/dist/file-explorer/FileRow.d.ts +6 -2
- package/dist/file-explorer/FileRow.js +35 -17
- package/dist/file-explorer/FileRowsWindow.d.ts +2 -1
- package/dist/file-explorer/FileRowsWindow.js +36 -4
- package/dist/file-explorer/FileTable.d.ts +3 -1
- package/dist/file-explorer/FileTable.js +6 -3
- package/dist/file-explorer/TreeView.d.ts +5 -1
- package/dist/file-explorer/TreeView.js +86 -39
- package/dist/file-explorer/helpers.d.ts +2 -1
- package/dist/file-explorer/helpers.js +24 -23
- package/dist/file-explorer/lib/utils.d.ts +3 -0
- package/dist/file-explorer/lib/utils.js +6 -1
- 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 +0 -3
- package/dist/form/Wizard/utils.js +2 -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 +11 -9
- package/dist/graph/GraphEditorDialogs.js +1 -1
- 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/Reveal.js +18 -10
- package/dist/graph/ShortcutsButton.d.ts +11 -2
- package/dist/graph/ShortcutsButton.js +14 -3
- package/dist/graph/TreeView.js +35 -18
- package/dist/graph/WorkflowSettingsDialog.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/inputRefs.js +1 -1
- package/dist/graph/settingsViews.js +11 -18
- package/dist/graph/stepWith.js +1 -1
- 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 +42 -6
- package/dist/list/ActionToolbar.js +298 -101
- package/dist/list/ListPage.d.ts +15 -23
- package/dist/list/ListPage.js +42 -43
- package/dist/list/ListTable.d.ts +37 -7
- package/dist/list/ListTable.js +52 -12
- package/dist/list/ListViewControls.js +1 -1
- 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/logviewer/LogViewer.d.ts +4 -2
- package/dist/logviewer/LogViewer.js +87 -69
- 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.css +1 -1
- package/package.json +5 -2
- 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
- package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +0 -6
- package/dist/file-explorer/FilePreview/CodePreviewEditor.js +0 -64
|
@@ -1,181 +1,303 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { AddIcon, ChevronRightIcon, EditIcon, MoreIcon } from "../icons.js";
|
|
3
|
-
import { keyedByContent } from "./keys.js";
|
|
4
2
|
import { buttonClasses } from "./buttonClasses.js";
|
|
3
|
+
import { ChevronRightIcon, MoreIcon } from "../icons.js";
|
|
4
|
+
import { keyedByContent } from "./keys.js";
|
|
5
5
|
import { Tooltip } from "./Tooltip.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useSlots, useStrings } from "./Provider.js";
|
|
7
|
+
import { AppLink } from "./AppLink.js";
|
|
7
8
|
import { ActionMenu } from "./ActionMenu.js";
|
|
8
|
-
import {
|
|
9
|
+
import { Skeleton } from "./Skeleton.js";
|
|
10
|
+
import { PageHeaderStore } from "./pageHeaderStore.js";
|
|
9
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import {
|
|
12
|
+
import { createContext, use, useCallback, useLayoutEffect, useState, useSyncExternalStore } from "react";
|
|
11
13
|
import { createPortal } from "react-dom";
|
|
12
14
|
//#region src/components/PageHeader.tsx
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* single action. `word` is the visible verb; `label` stays the full action for
|
|
24
|
-
* the tooltip and screen readers. */
|
|
25
|
-
function HeaderAddButton({ href, onClick, label, word = "add", menu, disabled = false, disabledHint }) {
|
|
26
|
-
const { common } = useStrings();
|
|
27
|
-
const Link = useLink();
|
|
28
|
-
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AddIcon, { className: "w-3 h-3" }), /* @__PURE__ */ jsx("span", { children: word === "create" ? common.create : common.add })] });
|
|
29
|
-
if (menu) return /* @__PURE__ */ jsx(ActionMenu, {
|
|
30
|
-
items: menu,
|
|
31
|
-
label,
|
|
32
|
-
triggerClassName: headerAddButtonClasses,
|
|
33
|
-
children: content
|
|
15
|
+
var StoreContext = createContext(null);
|
|
16
|
+
/**
|
|
17
|
+
* Holds the header the current page declares, for the `PageHeaderBar` the
|
|
18
|
+
* shell renders. Wrap the shell, above both the bar and the routes.
|
|
19
|
+
*/
|
|
20
|
+
function PageHeaderProvider({ children }) {
|
|
21
|
+
const [store] = useState(() => new PageHeaderStore());
|
|
22
|
+
return /* @__PURE__ */ jsx(StoreContext, {
|
|
23
|
+
value: store,
|
|
24
|
+
children
|
|
34
25
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
}
|
|
27
|
+
var renderOrder = 0;
|
|
28
|
+
var subscribeNever = () => () => {};
|
|
29
|
+
function createRegionNodes() {
|
|
30
|
+
if (typeof document === "undefined") return null;
|
|
31
|
+
const node = () => {
|
|
32
|
+
const el = document.createElement("div");
|
|
33
|
+
el.style.display = "contents";
|
|
34
|
+
return el;
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
titleActions: node(),
|
|
38
|
+
actions: node(),
|
|
39
|
+
toolbar: node()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Declares the page's header: its breadcrumbs, title actions, actions and
|
|
44
|
+
* toolbar. Under a `PageHeaderProvider` it renders nothing in place: the
|
|
45
|
+
* shell's `PageHeaderBar` shows it, while the actions stay in the page's React
|
|
46
|
+
* tree, with its context and state. Without a provider it renders the bar
|
|
47
|
+
* itself, for a page with no shell.
|
|
48
|
+
*
|
|
49
|
+
* Any component may render one, such as a form adding its Save button: the bar
|
|
50
|
+
* shows the actions of all of them, outermost first, and the trail of the last
|
|
51
|
+
* one rendered that has one, so a page's trail replaces its layout's.
|
|
52
|
+
*/
|
|
53
|
+
function PageHeader(props) {
|
|
54
|
+
const store = use(StoreContext);
|
|
55
|
+
if (!store) return props.hidden ? null : /* @__PURE__ */ jsx(HeaderLayout, {
|
|
56
|
+
breadcrumbs: props.breadcrumbs ?? [],
|
|
57
|
+
titleActions: props.titleActions,
|
|
58
|
+
actions: props.actions,
|
|
59
|
+
toolbar: props.toolbar
|
|
43
60
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
children: /* @__PURE__ */ jsx("button", {
|
|
48
|
-
type: "button",
|
|
49
|
-
onClick: disabled ? void 0 : onClick,
|
|
50
|
-
"aria-label": hint ? `${label}. ${hint}` : label,
|
|
51
|
-
"aria-disabled": disabled || void 0,
|
|
52
|
-
className: headerAddButtonClasses,
|
|
53
|
-
children: content
|
|
54
|
-
})
|
|
61
|
+
return /* @__PURE__ */ jsx(DeclaredHeader, {
|
|
62
|
+
store,
|
|
63
|
+
...props
|
|
55
64
|
});
|
|
56
65
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
function DeclaredHeader({ store, breadcrumbs, titleActions, actions, toolbar, hidden = false }) {
|
|
67
|
+
const [order] = useState(() => ++renderOrder);
|
|
68
|
+
const [nodes] = useState(createRegionNodes);
|
|
69
|
+
const client = useSyncExternalStore(subscribeNever, () => true, () => false);
|
|
70
|
+
const fills = {
|
|
71
|
+
titleActions: present(titleActions),
|
|
72
|
+
actions: present(actions),
|
|
73
|
+
toolbar: present(toolbar)
|
|
74
|
+
};
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
store.set(order, {
|
|
77
|
+
breadcrumbs,
|
|
78
|
+
hidden,
|
|
79
|
+
nodes,
|
|
80
|
+
fills
|
|
81
|
+
});
|
|
66
82
|
});
|
|
83
|
+
useLayoutEffect(() => () => store.delete(order), [store, order]);
|
|
84
|
+
if (!nodes || !client) return null;
|
|
85
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
86
|
+
fills.titleActions && createPortal(titleActions, nodes.titleActions),
|
|
87
|
+
fills.actions && createPortal(actions, nodes.actions),
|
|
88
|
+
fills.toolbar && createPortal(toolbar, nodes.toolbar)
|
|
89
|
+
] });
|
|
67
90
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
})
|
|
91
|
+
function present(node) {
|
|
92
|
+
return node !== void 0 && node !== null && node !== false && node !== "";
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The bar showing what the current page declares with `PageHeader`. The shell
|
|
96
|
+
* renders one, inside a `PageHeaderProvider`, wherever its chrome puts it. It
|
|
97
|
+
* renders nothing while the page declares nothing.
|
|
98
|
+
*/
|
|
99
|
+
function PageHeaderBar({ compact = false, persistent = false, className }) {
|
|
100
|
+
const store = use(StoreContext);
|
|
101
|
+
if (!store) throw new Error("PageHeaderBar needs a PageHeaderProvider above it");
|
|
102
|
+
const header = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
103
|
+
const empty = header.breadcrumbs.length === 0 && header.titleActions.length === 0 && header.actions.length === 0 && header.toolbar.length === 0;
|
|
104
|
+
if (header.hidden || empty && !persistent) return null;
|
|
105
|
+
return /* @__PURE__ */ jsx(HeaderLayout, {
|
|
106
|
+
breadcrumbs: header.breadcrumbs,
|
|
107
|
+
titleActions: header.titleActions.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.titleActions }),
|
|
108
|
+
actions: header.actions.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.actions }),
|
|
109
|
+
toolbar: header.toolbar.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.toolbar }),
|
|
110
|
+
compact,
|
|
111
|
+
className
|
|
87
112
|
});
|
|
88
113
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
114
|
+
var nodeKeys = /* @__PURE__ */ new WeakMap();
|
|
115
|
+
var nextNodeKey = 0;
|
|
116
|
+
function nodeKey(node) {
|
|
117
|
+
let key = nodeKeys.get(node);
|
|
118
|
+
if (key === void 0) {
|
|
119
|
+
key = ++nextNodeKey;
|
|
120
|
+
nodeKeys.set(node, key);
|
|
121
|
+
}
|
|
122
|
+
return key;
|
|
94
123
|
}
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
if (!rightActionSlot) return null;
|
|
98
|
-
return createPortal(children, rightActionSlot);
|
|
124
|
+
function Mounts({ nodes }) {
|
|
125
|
+
return nodes.map((node) => /* @__PURE__ */ jsx(Mount, { node }, nodeKey(node)));
|
|
99
126
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
className,
|
|
110
|
-
"aria-label": ariaLabel,
|
|
111
|
-
children: content
|
|
112
|
-
}) : /* @__PURE__ */ jsx("button", {
|
|
113
|
-
type: "button",
|
|
114
|
-
onClick,
|
|
115
|
-
disabled,
|
|
116
|
-
className,
|
|
117
|
-
"aria-label": ariaLabel,
|
|
118
|
-
children: content
|
|
119
|
-
})
|
|
127
|
+
/** Moves a declaration's region node into the bar. React owns the span and
|
|
128
|
+
* keeps it in order; the node inside is the page's. */
|
|
129
|
+
function Mount({ node }) {
|
|
130
|
+
const attach = useCallback((span) => {
|
|
131
|
+
if (span && node.parentNode !== span) span.append(node);
|
|
132
|
+
}, [node]);
|
|
133
|
+
return /* @__PURE__ */ jsx("span", {
|
|
134
|
+
ref: attach,
|
|
135
|
+
className: "contents"
|
|
120
136
|
});
|
|
121
137
|
}
|
|
122
|
-
function
|
|
123
|
-
const { setHidden } = useBreadcrumb();
|
|
124
|
-
const Link = useLink();
|
|
138
|
+
function HeaderLayout({ breadcrumbs, titleActions, actions, toolbar, compact = false, className }) {
|
|
125
139
|
const { breadcrumbPin, navToggle } = useSlots();
|
|
126
|
-
const
|
|
127
|
-
useLayoutEffect(() => {
|
|
128
|
-
setHidden(true);
|
|
129
|
-
return () => setHidden(false);
|
|
130
|
-
}, [setHidden]);
|
|
131
|
-
const crumbs = [...breadcrumbs ?? []];
|
|
132
|
-
const lastLabel = crumbs[crumbs.length - 1]?.label;
|
|
133
|
-
if (title !== null && title !== void 0 && title !== lastLabel) crumbs.push({ label: title });
|
|
134
|
-
const crumbRow = crumbs.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
135
|
-
className: "flex items-center gap-1.5 min-w-0",
|
|
136
|
-
children: [
|
|
137
|
-
/* @__PURE__ */ jsx("nav", {
|
|
138
|
-
"aria-label": common.breadcrumb,
|
|
139
|
-
className: "flex items-center gap-2 min-w-0 text-[13px]",
|
|
140
|
-
children: keyedByContent(crumbs, (c) => c.href ?? (typeof c.label === "string" ? c.label : "crumb")).map(({ key, item: crumb }, idx) => {
|
|
141
|
-
if (idx === crumbs.length - 1) return /* @__PURE__ */ jsx("h1", {
|
|
142
|
-
className: "m-0 text-[13px] font-medium leading-none text-(--theme-app) truncate",
|
|
143
|
-
children: crumb.label
|
|
144
|
-
}, key);
|
|
145
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [crumb.href ? /* @__PURE__ */ jsx(Link, {
|
|
146
|
-
href: crumb.href,
|
|
147
|
-
className: "text-(--theme-muted-text-color) hover:text-(--theme-app) transition-colors cursor-pointer whitespace-nowrap",
|
|
148
|
-
children: crumb.label
|
|
149
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
150
|
-
className: "text-(--theme-muted-text-color) whitespace-nowrap",
|
|
151
|
-
children: crumb.label
|
|
152
|
-
}), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3 h-3 opacity-60 shrink-0 text-(--theme-muted-text-color)" })] }, key);
|
|
153
|
-
})
|
|
154
|
-
}),
|
|
155
|
-
titleAction,
|
|
156
|
-
breadcrumbPin?.({ crumbs })
|
|
157
|
-
]
|
|
158
|
-
});
|
|
159
|
-
const actionCluster = actions && /* @__PURE__ */ jsx("div", {
|
|
160
|
-
className: "flex items-center gap-1.5 shrink-0",
|
|
161
|
-
children: actions
|
|
162
|
-
});
|
|
163
|
-
const toggle = navToggle?.();
|
|
164
|
-
const hasLeading = !!crumbRow || !!toggle;
|
|
165
|
-
const leading = hasLeading ? /* @__PURE__ */ jsxs("div", {
|
|
166
|
-
className: "flex items-center gap-2 min-w-0",
|
|
167
|
-
children: [toggle, crumbRow]
|
|
168
|
-
}) : /* @__PURE__ */ jsx("div", {});
|
|
140
|
+
const hasTrail = breadcrumbs.length > 0;
|
|
169
141
|
return /* @__PURE__ */ jsxs("div", {
|
|
170
|
-
className: cx(
|
|
142
|
+
className: cx("@container w-full shrink-0 bg-(--theme-app-bg)", className),
|
|
171
143
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
172
|
-
className: cx("flex items-center justify-between gap-
|
|
173
|
-
children: [
|
|
174
|
-
|
|
144
|
+
className: cx("flex items-center justify-between gap-4 border-b border-(--theme-border) px-4", compact ? "h-8" : "h-11"),
|
|
145
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
146
|
+
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
147
|
+
children: [
|
|
148
|
+
navToggle?.(),
|
|
149
|
+
hasTrail && /* @__PURE__ */ jsx(BreadcrumbTrail, { crumbs: breadcrumbs }),
|
|
150
|
+
present(titleActions) && /* @__PURE__ */ jsx("div", {
|
|
151
|
+
className: "flex shrink-0 items-center gap-0.5",
|
|
152
|
+
children: titleActions
|
|
153
|
+
}),
|
|
154
|
+
hasTrail && breadcrumbPin?.({ crumbs: breadcrumbs })
|
|
155
|
+
]
|
|
156
|
+
}), present(actions) && /* @__PURE__ */ jsx("div", {
|
|
157
|
+
className: "flex shrink-0 items-center gap-1",
|
|
158
|
+
children: actions
|
|
159
|
+
})]
|
|
160
|
+
}), present(toolbar) && /* @__PURE__ */ jsx("div", {
|
|
175
161
|
className: "px-4",
|
|
176
162
|
children: toolbar
|
|
177
163
|
})]
|
|
178
164
|
});
|
|
179
165
|
}
|
|
166
|
+
var crumbText = "block truncate text-(--theme-muted-text-color)";
|
|
167
|
+
var crumbLink = "rounded-sm transition-colors hover:text-(--theme-app) focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-link)";
|
|
168
|
+
function Separator() {
|
|
169
|
+
return /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3 shrink-0 text-(--theme-muted-text-color) opacity-60" });
|
|
170
|
+
}
|
|
171
|
+
var FOLD_WIDTH = 48;
|
|
172
|
+
var PARENT_MAX_WIDTH = 144;
|
|
173
|
+
var TITLE_MIN_WIDTH = 128;
|
|
174
|
+
/**
|
|
175
|
+
* Fits the trail to the room its row leaves it. It measures a hidden copy of
|
|
176
|
+
* the trail at its natural width against the row's width less its other items,
|
|
177
|
+
* so the answer doesn't depend on how the trail is folded at the moment.
|
|
178
|
+
*/
|
|
179
|
+
function useTrailFit(nav, natural) {
|
|
180
|
+
const [fit, setFit] = useState("all");
|
|
181
|
+
useLayoutEffect(() => {
|
|
182
|
+
const row = nav?.parentElement;
|
|
183
|
+
if (!nav || !natural || !row) return;
|
|
184
|
+
const measure = () => {
|
|
185
|
+
const gap = Number.parseFloat(getComputedStyle(row).columnGap) || 0;
|
|
186
|
+
let room = row.clientWidth;
|
|
187
|
+
for (const child of row.children) if (child !== nav) room -= child.getBoundingClientRect().width + gap;
|
|
188
|
+
if (natural.scrollWidth <= room) {
|
|
189
|
+
setFit("all");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const steps = [...natural.children];
|
|
193
|
+
const width = (el) => el?.getBoundingClientRect().width ?? 0;
|
|
194
|
+
const parent = Math.min(width(steps[steps.length - 2]), PARENT_MAX_WIDTH);
|
|
195
|
+
const title = Math.min(width(steps[steps.length - 1]), TITLE_MIN_WIDTH);
|
|
196
|
+
setFit(FOLD_WIDTH + parent + title <= room ? "parent" : "none");
|
|
197
|
+
};
|
|
198
|
+
measure();
|
|
199
|
+
const observer = new ResizeObserver(measure);
|
|
200
|
+
observer.observe(row);
|
|
201
|
+
observer.observe(natural);
|
|
202
|
+
return () => observer.disconnect();
|
|
203
|
+
}, [nav, natural]);
|
|
204
|
+
return fit;
|
|
205
|
+
}
|
|
206
|
+
function BreadcrumbTrail({ crumbs }) {
|
|
207
|
+
const { common } = useStrings();
|
|
208
|
+
const [nav, setNav] = useState(null);
|
|
209
|
+
const [natural, setNatural] = useState(null);
|
|
210
|
+
const fit = useTrailFit(nav, natural);
|
|
211
|
+
const current = crumbs[crumbs.length - 1];
|
|
212
|
+
const ancestors = crumbs.slice(0, -1);
|
|
213
|
+
const folded = fit === "none" ? ancestors : fit === "parent" ? ancestors.slice(0, -1) : [];
|
|
214
|
+
const shown = ancestors.slice(folded.length);
|
|
215
|
+
return /* @__PURE__ */ jsxs("nav", {
|
|
216
|
+
ref: setNav,
|
|
217
|
+
"aria-label": common.breadcrumb,
|
|
218
|
+
className: "relative min-w-0",
|
|
219
|
+
children: [/* @__PURE__ */ jsxs("ol", {
|
|
220
|
+
className: "m-0 flex min-w-0 list-none items-center gap-1.5 p-0 text-[13px] leading-none",
|
|
221
|
+
children: [
|
|
222
|
+
folded.length > 0 && /* @__PURE__ */ jsxs("li", {
|
|
223
|
+
className: "flex shrink-0 items-center gap-1.5",
|
|
224
|
+
children: [/* @__PURE__ */ jsx(ActionMenu, {
|
|
225
|
+
label: common.showFullPath,
|
|
226
|
+
align: "start",
|
|
227
|
+
items: folded.map((crumb) => crumb.href ? {
|
|
228
|
+
label: crumb.label,
|
|
229
|
+
href: crumb.href
|
|
230
|
+
} : {
|
|
231
|
+
label: crumb.label,
|
|
232
|
+
disabled: true,
|
|
233
|
+
onClick: () => {}
|
|
234
|
+
}),
|
|
235
|
+
triggerClassName: buttonClasses({
|
|
236
|
+
variant: "ghost",
|
|
237
|
+
size: "xs",
|
|
238
|
+
iconOnly: true
|
|
239
|
+
}),
|
|
240
|
+
children: /* @__PURE__ */ jsx(MoreIcon, {})
|
|
241
|
+
}), /* @__PURE__ */ jsx(Separator, {})]
|
|
242
|
+
}),
|
|
243
|
+
keyedByContent(shown, (c) => c.href ?? c.label).map(({ key, item: crumb }) => /* @__PURE__ */ jsxs("li", {
|
|
244
|
+
className: cx("flex items-center gap-1.5", folded.length > 0 ? "min-w-0 max-w-36 shrink-0" : "min-w-0"),
|
|
245
|
+
children: [crumb.label === "" ? /* @__PURE__ */ jsx(CrumbPlaceholder, {}) : /* @__PURE__ */ jsx(Tooltip, {
|
|
246
|
+
content: crumb.label,
|
|
247
|
+
overflowOnly: true,
|
|
248
|
+
children: crumb.href ? /* @__PURE__ */ jsx(AppLink, {
|
|
249
|
+
href: crumb.href,
|
|
250
|
+
className: cx(crumbText, crumbLink, "max-w-48"),
|
|
251
|
+
children: crumb.label
|
|
252
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
253
|
+
className: cx(crumbText, "max-w-48"),
|
|
254
|
+
children: crumb.label
|
|
255
|
+
})
|
|
256
|
+
}), /* @__PURE__ */ jsx(Separator, {})]
|
|
257
|
+
}, key)),
|
|
258
|
+
current && /* @__PURE__ */ jsx("li", {
|
|
259
|
+
className: "flex min-w-0 items-center",
|
|
260
|
+
children: current.label === "" ? /* @__PURE__ */ jsx("h1", {
|
|
261
|
+
"aria-current": "page",
|
|
262
|
+
className: "m-0",
|
|
263
|
+
children: /* @__PURE__ */ jsx(CrumbPlaceholder, {})
|
|
264
|
+
}) : /* @__PURE__ */ jsx(Tooltip, {
|
|
265
|
+
content: current.label,
|
|
266
|
+
overflowOnly: true,
|
|
267
|
+
children: /* @__PURE__ */ jsx("h1", {
|
|
268
|
+
"aria-current": "page",
|
|
269
|
+
className: "m-0 truncate text-[13px] font-medium leading-none text-(--theme-app)",
|
|
270
|
+
children: current.label
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
]
|
|
275
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
276
|
+
ref: setNatural,
|
|
277
|
+
"aria-hidden": true,
|
|
278
|
+
className: "invisible absolute top-0 left-0 flex items-center gap-1.5 whitespace-nowrap text-[13px] leading-none",
|
|
279
|
+
children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs("span", {
|
|
280
|
+
className: "flex items-center gap-1.5",
|
|
281
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
282
|
+
className: cx(i < crumbs.length - 1 && "max-w-48 truncate", i === crumbs.length - 1 && "font-medium"),
|
|
283
|
+
children: crumb.label || " ".repeat(6)
|
|
284
|
+
}), i < crumbs.length - 1 && /* @__PURE__ */ jsx(Separator, {})]
|
|
285
|
+
}, i))
|
|
286
|
+
})]
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function CrumbPlaceholder() {
|
|
290
|
+
const { common } = useStrings();
|
|
291
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
292
|
+
className: "flex items-center",
|
|
293
|
+
children: [/* @__PURE__ */ jsx(Skeleton, {
|
|
294
|
+
width: "6rem",
|
|
295
|
+
height: "0.8125rem"
|
|
296
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
297
|
+
className: "sr-only",
|
|
298
|
+
children: common.loading
|
|
299
|
+
})]
|
|
300
|
+
});
|
|
301
|
+
}
|
|
180
302
|
//#endregion
|
|
181
|
-
export {
|
|
303
|
+
export { PageHeader, PageHeaderBar, PageHeaderProvider };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { MenuEntry } from './MenuEntries.js';
|
|
3
|
+
type Target = {
|
|
4
|
+
href: string;
|
|
5
|
+
external?: boolean | undefined;
|
|
6
|
+
/** Loads the page instead of routing, for paths the host's router doesn't serve. */
|
|
7
|
+
reloadDocument?: boolean | undefined;
|
|
8
|
+
onClick?: never;
|
|
9
|
+
menu?: never;
|
|
10
|
+
} | {
|
|
11
|
+
onClick: () => void;
|
|
12
|
+
href?: never;
|
|
13
|
+
external?: never;
|
|
14
|
+
reloadDocument?: never;
|
|
15
|
+
menu?: never;
|
|
16
|
+
} | {
|
|
17
|
+
menu: MenuEntry[];
|
|
18
|
+
href?: never;
|
|
19
|
+
external?: never;
|
|
20
|
+
reloadDocument?: never;
|
|
21
|
+
onClick?: never;
|
|
22
|
+
};
|
|
23
|
+
export type PageHeaderActionProps = Target & {
|
|
24
|
+
icon: ComponentType<{
|
|
25
|
+
className?: string;
|
|
26
|
+
}>;
|
|
27
|
+
/** The visible text, or with `iconOnly` the name its tooltip shows. */
|
|
28
|
+
label: string;
|
|
29
|
+
/** A fuller name for assistive technology than the visible label, such as
|
|
30
|
+
* "Save organization flags" for "Save". */
|
|
31
|
+
ariaLabel?: string | undefined;
|
|
32
|
+
/** The icon alone, named by its tooltip, such as an edit pencil beside the title. */
|
|
33
|
+
iconOnly?: boolean | undefined;
|
|
34
|
+
disabled?: boolean | undefined;
|
|
35
|
+
disabledReason?: string | undefined;
|
|
36
|
+
/** A hint shown on hover and focus while it can be pressed. */
|
|
37
|
+
tooltip?: string | undefined;
|
|
38
|
+
/** In the error color, as a destructive menu entry is, for an action that
|
|
39
|
+
* removes or breaks something. */
|
|
40
|
+
destructive?: boolean | undefined;
|
|
41
|
+
/** A toggle's state, such as a favorite: set, it reads as pressed. Buttons only. */
|
|
42
|
+
pressed?: boolean | undefined;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* An action in the page header: a link (`href`, `external` for a new tab,
|
|
46
|
+
* `reloadDocument` for a path the router doesn't serve), a
|
|
47
|
+
* button (`onClick`) or a menu (`menu`). Labeled actions read in the link
|
|
48
|
+
* color, so the page's commands stand apart from the trail.
|
|
49
|
+
*/
|
|
50
|
+
export declare function PageHeaderAction({ icon: Icon, label, ariaLabel, iconOnly, disabled, disabledReason, tooltip, destructive, pressed, ...target }: PageHeaderActionProps): import("react").JSX.Element;
|
|
51
|
+
export type PageHeaderAddButtonProps = Target & {
|
|
52
|
+
/** The full action, such as "New cluster": the tooltip and accessible name. */
|
|
53
|
+
label: string;
|
|
54
|
+
/** The visible verb. */
|
|
55
|
+
word?: 'add' | 'create' | undefined;
|
|
56
|
+
disabled?: boolean | undefined;
|
|
57
|
+
disabledReason?: string | undefined;
|
|
58
|
+
};
|
|
59
|
+
/** The page's "+ Add" or "+ Create": with `menu`, a chooser of what to make. */
|
|
60
|
+
export declare function PageHeaderAddButton({ label, word, disabled, disabledReason, ...target }: PageHeaderAddButtonProps): import("react").JSX.Element;
|
|
61
|
+
/** The "…" menu of actions on the page's subject. Renders nothing without items. */
|
|
62
|
+
export declare function PageHeaderMenu({ items, label, }: {
|
|
63
|
+
items: MenuEntry[];
|
|
64
|
+
/** Defaults to the strings' "Actions". */
|
|
65
|
+
label?: string | undefined;
|
|
66
|
+
}): import("react").JSX.Element | null;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { buttonClasses } from "./buttonClasses.js";
|
|
3
|
+
import { AddIcon, MoreIcon } from "../icons.js";
|
|
4
|
+
import { Tooltip } from "./Tooltip.js";
|
|
5
|
+
import { useStrings } from "./Provider.js";
|
|
6
|
+
import { AppLink } from "./AppLink.js";
|
|
7
|
+
import { ActionMenu } from "./ActionMenu.js";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/components/PageHeaderAction.tsx
|
|
10
|
+
/**
|
|
11
|
+
* The one control under every header action, so links, buttons and menus share
|
|
12
|
+
* the look, the disabled behavior and the tooltip. A disabled control stays
|
|
13
|
+
* focusable (`aria-disabled`, not `disabled`), so its reason is reachable by
|
|
14
|
+
* keyboard and pointer, where a disabled button would swallow both.
|
|
15
|
+
*/
|
|
16
|
+
function HeaderControl({ name, tooltip, disabled, disabledReason, pressed, className, children, href, external, reloadDocument, onClick, menu }) {
|
|
17
|
+
const { common } = useStrings();
|
|
18
|
+
if (menu && !disabled) return /* @__PURE__ */ jsx(ActionMenu, {
|
|
19
|
+
items: menu,
|
|
20
|
+
label: name,
|
|
21
|
+
triggerClassName: className,
|
|
22
|
+
children
|
|
23
|
+
});
|
|
24
|
+
const reason = disabled ? disabledReason : void 0;
|
|
25
|
+
if (href) return /* @__PURE__ */ jsx(Tooltip, {
|
|
26
|
+
content: disabled ? disabledReason ?? tooltip : tooltip,
|
|
27
|
+
children: /* @__PURE__ */ jsx(AppLink, {
|
|
28
|
+
href,
|
|
29
|
+
reloadDocument,
|
|
30
|
+
target: external ? "_blank" : void 0,
|
|
31
|
+
disabled,
|
|
32
|
+
"aria-label": reason ? `${name}. ${reason}` : external ? `${name} ${common.opensInNewTab}` : name,
|
|
33
|
+
className,
|
|
34
|
+
children
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
38
|
+
content: disabled ? disabledReason ?? tooltip : tooltip,
|
|
39
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
40
|
+
type: "button",
|
|
41
|
+
onClick: disabled ? void 0 : onClick,
|
|
42
|
+
"aria-label": reason ? `${name}. ${reason}` : name,
|
|
43
|
+
"aria-disabled": disabled || void 0,
|
|
44
|
+
"aria-pressed": pressed,
|
|
45
|
+
className,
|
|
46
|
+
children
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* An action in the page header: a link (`href`, `external` for a new tab,
|
|
52
|
+
* `reloadDocument` for a path the router doesn't serve), a
|
|
53
|
+
* button (`onClick`) or a menu (`menu`). Labeled actions read in the link
|
|
54
|
+
* color, so the page's commands stand apart from the trail.
|
|
55
|
+
*/
|
|
56
|
+
function PageHeaderAction({ icon: Icon, label, ariaLabel, iconOnly = false, disabled = false, disabledReason, tooltip, destructive = false, pressed, ...target }) {
|
|
57
|
+
const tone = destructive ? "*:text-(--theme-error-text)" : iconOnly ? void 0 : "*:text-(--theme-link)";
|
|
58
|
+
return /* @__PURE__ */ jsxs(HeaderControl, {
|
|
59
|
+
...target,
|
|
60
|
+
name: ariaLabel ?? label,
|
|
61
|
+
tooltip: tooltip ?? label,
|
|
62
|
+
disabled,
|
|
63
|
+
disabledReason,
|
|
64
|
+
pressed,
|
|
65
|
+
className: cx(buttonClasses({
|
|
66
|
+
variant: "ghost",
|
|
67
|
+
size: "xs",
|
|
68
|
+
iconOnly
|
|
69
|
+
}), tone),
|
|
70
|
+
children: [/* @__PURE__ */ jsx(Icon, {}), !iconOnly && /* @__PURE__ */ jsx("span", {
|
|
71
|
+
className: "@max-md:sr-only",
|
|
72
|
+
children: label
|
|
73
|
+
})]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** The page's "+ Add" or "+ Create": with `menu`, a chooser of what to make. */
|
|
77
|
+
function PageHeaderAddButton({ label, word = "add", disabled = false, disabledReason, ...target }) {
|
|
78
|
+
const { common } = useStrings();
|
|
79
|
+
return /* @__PURE__ */ jsxs(HeaderControl, {
|
|
80
|
+
...target,
|
|
81
|
+
name: label,
|
|
82
|
+
tooltip: label,
|
|
83
|
+
disabled,
|
|
84
|
+
disabledReason,
|
|
85
|
+
className: buttonClasses({
|
|
86
|
+
variant: "outline",
|
|
87
|
+
size: "xs"
|
|
88
|
+
}),
|
|
89
|
+
children: [/* @__PURE__ */ jsx(AddIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
90
|
+
className: "@max-md:sr-only",
|
|
91
|
+
children: word === "create" ? common.create : common.add
|
|
92
|
+
})]
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/** The "…" menu of actions on the page's subject. Renders nothing without items. */
|
|
96
|
+
function PageHeaderMenu({ items, label }) {
|
|
97
|
+
const { common } = useStrings();
|
|
98
|
+
if (items.length === 0) return null;
|
|
99
|
+
return /* @__PURE__ */ jsx(PageHeaderAction, {
|
|
100
|
+
icon: MoreIcon,
|
|
101
|
+
iconOnly: true,
|
|
102
|
+
label: label ?? common.actions,
|
|
103
|
+
menu: items
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { PageHeaderAction, PageHeaderAddButton, PageHeaderMenu };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { ChevronLeftIcon, ChevronRightIcon } from "../icons.js";
|
|
3
|
-
import {
|
|
4
|
-
import { Tooltip } from "./Tooltip.js";
|
|
5
|
-
import { useLink, useStrings } from "./Provider.js";
|
|
3
|
+
import { useStrings } from "./Provider.js";
|
|
6
4
|
import { IconButton } from "./IconButton.js";
|
|
7
5
|
import { Select } from "./Select.js";
|
|
8
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -70,19 +68,11 @@ function Pagination({ page, pageSize, total, hasNext, onPageChange, pageHref, pa
|
|
|
70
68
|
});
|
|
71
69
|
}
|
|
72
70
|
function PageStep({ to, enabled, label, icon, onPageChange, pageHref }) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"aria-label": label,
|
|
79
|
-
className: buttonClasses({
|
|
80
|
-
variant: "outline",
|
|
81
|
-
size: "sm",
|
|
82
|
-
iconOnly: true
|
|
83
|
-
}),
|
|
84
|
-
children: icon
|
|
85
|
-
})
|
|
71
|
+
if (pageHref && enabled) return /* @__PURE__ */ jsx(IconButton, {
|
|
72
|
+
variant: "outline",
|
|
73
|
+
icon,
|
|
74
|
+
label,
|
|
75
|
+
href: pageHref(to)
|
|
86
76
|
});
|
|
87
77
|
return /* @__PURE__ */ jsx(IconButton, {
|
|
88
78
|
variant: "outline",
|