@parallelworks/ui 0.19.0 → 0.19.1
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/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
- package/dist/ai/adapter/mock/index.js +2 -80
- package/dist/ai/adapter/mock/mockAdapter.js +81 -0
- package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
- package/dist/ai/adapter/openai/errors.js +37 -0
- package/dist/ai/adapter/openai/index.js +5 -333
- package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
- package/dist/ai/adapter/openai/responses.js +108 -0
- package/dist/ai/adapter/openai/sse.js +112 -0
- package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
- package/dist/ai/agent/classifier.js +12 -0
- package/dist/ai/agent/diff.js +223 -0
- package/dist/ai/agent/diffHighlight.js +101 -0
- package/dist/ai/agent/permissions.js +29 -0
- package/dist/ai/agent/toolfmt.js +383 -0
- package/dist/ai/agent/transcript.js +127 -0
- package/dist/ai/components/AllocationSelector.js +56 -0
- package/dist/ai/components/AttachmentManager.js +144 -0
- package/dist/ai/components/AttachmentUpload.js +179 -0
- package/dist/ai/components/BlockedGroupBanner.js +29 -0
- package/dist/ai/components/BranchNavigator.js +57 -0
- package/dist/ai/components/ChatEmptyState.js +171 -0
- package/dist/ai/components/ChatInput.js +265 -0
- package/dist/ai/components/ChatLayout.js +15 -0
- package/dist/ai/components/ChatMessage.js +338 -0
- package/dist/ai/components/ChatMessageList.js +301 -0
- package/dist/ai/components/ChatSidebar.js +345 -0
- package/dist/ai/components/ChatThread.js +198 -0
- package/dist/ai/components/ComposerChrome.js +50 -0
- package/dist/ai/components/ComposerFrame.js +33 -0
- package/dist/ai/components/DragOverlay.js +20 -0
- package/dist/ai/components/ModelSelector.js +343 -0
- package/dist/ai/components/ShareDialog.js +260 -0
- package/dist/ai/components/SlashMenu.js +91 -0
- package/dist/ai/components/agent/ActivityLine.js +151 -0
- package/dist/ai/components/agent/AgentMessageParts.js +721 -0
- package/dist/ai/components/agent/PermissionPicker.js +38 -0
- package/dist/ai/components/attachmentKeys.js +10 -0
- package/dist/ai/core/ChatProvider.js +848 -0
- package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
- package/dist/ai/core/chatReducer.js +223 -0
- package/dist/ai/core/config.js +45 -0
- package/dist/ai/core/events.js +4 -0
- package/dist/ai/core/exportConversation.js +42 -0
- package/dist/ai/core/greeting.js +38 -0
- package/dist/ai/core/parts.js +84 -0
- package/dist/ai/core/useDragDrop.js +36 -0
- package/dist/ai/core/useKeyboardShortcuts.js +77 -0
- package/dist/ai/core/useSSEStream.js +98 -0
- package/dist/ai/index.js +43 -6644
- package/dist/ai/strings.js +175 -0
- package/dist/ai/ui/Avatar.js +35 -0
- package/dist/ai/ui/Dropdown.js +110 -0
- package/dist/ai/ui/Markdown.js +79 -0
- package/dist/ai/ui/Notice.js +77 -0
- package/dist/ai/ui/codeBreaks.js +36 -0
- package/dist/ai/ui/prose.js +13 -0
- package/dist/ai/ui/sidebar.js +148 -0
- package/dist/ai/utils.js +23 -0
- package/dist/components/AddMenu.js +46 -0
- package/dist/components/Avatar.js +46 -0
- package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
- package/dist/components/Breadcrumbs.js +83 -0
- package/dist/components/Button.js +83 -0
- package/dist/components/Callout.js +23 -0
- package/dist/components/Card.js +31 -0
- package/dist/components/CollapsiblePanel.js +77 -0
- package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
- package/dist/components/CopyToClipboard.js +81 -0
- package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
- package/dist/components/DescriptionList.js +42 -0
- package/dist/components/Dropdown.js +349 -0
- package/dist/components/EmptyState.js +27 -0
- package/dist/components/Filter.js +32 -0
- package/dist/components/FilterPill.js +13 -0
- package/dist/components/IconButton.js +34 -0
- package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
- package/dist/components/Input.js +88 -0
- package/dist/components/LetterBadge.js +13 -0
- package/dist/components/Listbox.js +123 -0
- package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
- package/dist/components/Markdown.js +15 -0
- package/dist/components/MultiSelect.js +171 -0
- package/dist/components/Overview.js +39 -0
- package/dist/components/PageHeader.js +194 -0
- package/dist/components/Pagination.js +35 -0
- package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +1 -1
- package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
- package/dist/components/SectionHeader.js +11 -0
- package/dist/components/SettingModeOption.js +30 -0
- package/dist/components/SettingRow.js +35 -0
- package/dist/components/SettingsCard.js +31 -0
- package/dist/components/SettingsGroup.js +17 -0
- package/dist/components/Sort.js +42 -0
- package/dist/components/StatusBadge.js +63 -0
- package/dist/components/SwitchToggle.js +59 -0
- package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
- package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
- package/dist/components/Toggle.js +20 -0
- package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
- package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
- package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
- package/dist/components/ghostButton.js +7 -0
- package/dist/components/inputClasses.js +4 -0
- package/dist/components/keys.js +27 -0
- package/dist/components/relativeTime.js +32 -0
- package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
- package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
- package/dist/editor/Editor.js +13 -0
- package/dist/editor/EditorField.js +53 -0
- package/dist/editor/FormCodePanel.js +173 -0
- package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +4 -2
- package/dist/editor/index.js +6 -1
- package/dist/editor/themes.js +91 -0
- package/dist/editor/workers.js +29 -0
- package/dist/editor/yaml.js +15 -0
- package/dist/file-explorer/FileExplorer.js +1402 -0
- package/dist/file-explorer/FileExplorerContext.js +370 -0
- package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
- package/dist/file-explorer/FilePreview/Inline.js +45 -0
- package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
- package/dist/file-explorer/FilePreview/Viewer.js +526 -0
- package/dist/file-explorer/FilePreview/index.js +266 -0
- package/dist/file-explorer/FilePreview/parse.js +63 -0
- package/dist/file-explorer/FilePreview/previewCache.js +98 -0
- package/dist/file-explorer/FilePreview/previewType.js +151 -0
- package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
- package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
- package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
- package/dist/file-explorer/FileRow.js +165 -0
- package/dist/file-explorer/FileRowsWindow.js +92 -0
- package/dist/file-explorer/FileTable.js +172 -0
- package/dist/file-explorer/FileTableHeaders.js +49 -0
- package/dist/file-explorer/LoadMoreRow.js +46 -0
- package/dist/file-explorer/TreeView.js +376 -0
- package/dist/file-explorer/helpers.js +537 -0
- package/dist/file-explorer/index.js +7 -5671
- package/dist/file-explorer/lib/batch.js +39 -0
- package/dist/file-explorer/lib/errors.js +9 -0
- package/dist/file-explorer/lib/paging.js +124 -0
- package/dist/file-explorer/lib/utils.js +322 -0
- package/dist/file-explorer/toasts.js +400 -0
- package/dist/file-explorer/treeRows.js +73 -0
- package/dist/file-explorer/useNearEnd.js +27 -0
- package/dist/form/FieldWrapper.js +54 -0
- package/dist/form/Fields/BooleanField.js +51 -0
- package/dist/form/Fields/CheckboxGroupField.js +72 -0
- package/dist/form/Fields/ColorField.js +33 -0
- package/dist/form/Fields/DropdownField.js +49 -0
- package/dist/form/Fields/DurationField.js +130 -0
- package/dist/form/Fields/LabelField.js +19 -0
- package/dist/form/Fields/MultiDropdownField.js +40 -0
- package/dist/form/Fields/NumberField.js +51 -0
- package/dist/form/Fields/ObjectField.js +54 -0
- package/dist/form/Fields/RadioField.js +49 -0
- package/dist/form/Fields/RangeField.js +58 -0
- package/dist/form/Fields/ResourceOptionIcon.js +21 -0
- package/dist/form/Fields/StepField.js +6 -0
- package/dist/form/Fields/StringField.js +37 -0
- package/dist/form/Fields/TextAreaField.js +31 -0
- package/dist/form/Fields/durationValidity.js +11 -0
- package/dist/form/Form.js +643 -0
- package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
- package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
- package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
- package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
- package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
- package/dist/form/Wizard/WizardContainer.js +138 -0
- package/dist/form/Wizard/WizardNavigation.js +92 -0
- package/dist/form/Wizard/WizardStepContent.js +35 -0
- package/dist/form/Wizard/WizardStepIndicator.js +108 -0
- package/dist/form/Wizard/useWizardState.js +118 -0
- package/dist/form/Wizard/utils.js +34 -0
- package/dist/form/fieldContext.js +26 -0
- package/dist/form/fieldRegistry.js +50 -0
- package/dist/form/index.js +17 -2321
- package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
- package/dist/form/useParsedOpts.js +62 -0
- package/dist/form/usePrevious.js +11 -0
- package/dist/form/utils/checkShowIfObject.js +14 -0
- package/dist/form/utils/duration.js +69 -0
- package/dist/form/utils/getParentValue.js +23 -0
- package/dist/form/utils/getPlaceholder.js +9 -0
- package/dist/form/utils/getValueUsingPath.js +23 -0
- package/dist/form/utils/secondaryField.js +22 -0
- package/dist/graph/AnnotationBanner.js +141 -0
- package/dist/graph/Collapse.js +41 -0
- package/dist/graph/DependencyGraph.js +1398 -0
- package/dist/graph/JobSummary.js +104 -0
- package/dist/graph/MatrixGroup.js +107 -0
- package/dist/graph/Reveal.js +57 -0
- package/dist/graph/TreeView.js +711 -0
- package/dist/graph/index.js +1 -2519
- package/dist/graph/types.js +6 -0
- package/dist/index.js +46 -599
- package/dist/list/ActionToolbar.js +184 -0
- package/dist/list/HoverCard.js +73 -0
- package/dist/list/ListPage.js +145 -0
- package/dist/list/ListPager.js +59 -0
- package/dist/list/ListTable.js +163 -0
- package/dist/list/ListViewControls.js +372 -0
- package/dist/list/RowContextMenu.js +350 -0
- package/dist/list/UserHoverCard.js +117 -0
- package/dist/list/index.js +11 -2
- package/dist/list/listSearch.js +137 -0
- package/dist/list/listView.js +210 -0
- package/dist/list/textEntry.js +10 -0
- package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
- package/dist/logviewer/index.js +2 -1
- package/dist/logviewer/segments.js +80 -0
- package/package.json +1 -1
- package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
- package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
- package/dist/chunks/editor-Dk1rbV75.js +0 -361
- package/dist/chunks/list-CJm875m7.js +0 -1418
- /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
|
@@ -1,692 +0,0 @@
|
|
|
1
|
-
import { i as useNotify, l as useSlots, n as useLink, u as useStrings } from "./Provider-CDYurraE.js";
|
|
2
|
-
import { AddIcon, CheckIcon, ChevronRightIcon, ClipboardIcon, CopyIcon, EditIcon, IdCardIcon, KeyIcon, LinkIcon, MailIcon, MoreIcon, UserIcon } from "../icons.js";
|
|
3
|
-
import { n as TOOLTIP_ID, o as keyedByContent } from "./Tooltip-K5HJr4_p.js";
|
|
4
|
-
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
|
5
|
-
import cx from "classnames";
|
|
6
|
-
import React, { Fragment, createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
7
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { createPortal } from "react-dom";
|
|
9
|
-
//#region src/components/AddMenu.tsx
|
|
10
|
-
var addMenuItemClasses = "flex w-full items-center gap-2 px-3 py-1.5 text-[13px] text-(--theme-app) data-[focus]:bg-(--theme-muted-panel-bg) cursor-pointer";
|
|
11
|
-
function itemButtonProps(item) {
|
|
12
|
-
if (!item.disabled) return { onClick: item.onSelect };
|
|
13
|
-
return {
|
|
14
|
-
"aria-disabled": true,
|
|
15
|
-
...item.hint ? {
|
|
16
|
-
"aria-label": `${item.label}. ${item.hint}`,
|
|
17
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
18
|
-
"data-tooltip-content": item.hint
|
|
19
|
-
} : {}
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function AddMenu({ items, label, buttonClassName, zClassName = "z-50", children }) {
|
|
23
|
-
const Link = useLink();
|
|
24
|
-
return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuButton, {
|
|
25
|
-
"aria-label": label,
|
|
26
|
-
title: label,
|
|
27
|
-
className: buttonClassName,
|
|
28
|
-
children
|
|
29
|
-
}), /* @__PURE__ */ jsx(MenuItems, {
|
|
30
|
-
anchor: "bottom start",
|
|
31
|
-
className: cx("mt-1 min-w-52 rounded-lg border border-(--theme-border) bg-(--theme-app-bg) py-1 shadow-lg focus:outline-none", zClassName),
|
|
32
|
-
children: items.map((item) => /* @__PURE__ */ jsxs(Fragment, { children: [item.separatorAbove && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-(--theme-border)" }), /* @__PURE__ */ jsx(MenuItem, {
|
|
33
|
-
disabled: item.disabled ?? false,
|
|
34
|
-
children: item.to && !item.disabled ? /* @__PURE__ */ jsxs(Link, {
|
|
35
|
-
to: item.to,
|
|
36
|
-
className: addMenuItemClasses,
|
|
37
|
-
children: [item.icon, item.label]
|
|
38
|
-
}) : /* @__PURE__ */ jsxs("button", {
|
|
39
|
-
type: "button",
|
|
40
|
-
...itemButtonProps(item),
|
|
41
|
-
className: cx(addMenuItemClasses, item.disabled && "opacity-50 cursor-not-allowed"),
|
|
42
|
-
children: [item.icon, item.label]
|
|
43
|
-
})
|
|
44
|
-
})] }, item.label))
|
|
45
|
-
})] });
|
|
46
|
-
}
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/components/Avatar.tsx
|
|
49
|
-
var SIZE_CLASSES = {
|
|
50
|
-
sm: "w-6 h-6 text-xs",
|
|
51
|
-
md: "w-8 h-8 text-sm",
|
|
52
|
-
lg: "w-10 h-10 text-base",
|
|
53
|
-
xl: "w-12 h-12 text-lg",
|
|
54
|
-
"2xl": "w-16 h-16 text-xl"
|
|
55
|
-
};
|
|
56
|
-
var STATUS_CLASSES = {
|
|
57
|
-
online: "bg-green-500",
|
|
58
|
-
offline: "bg-(--theme-muted-text-color)",
|
|
59
|
-
busy: "bg-red-500",
|
|
60
|
-
away: "bg-yellow-500"
|
|
61
|
-
};
|
|
62
|
-
/** Up to two initials: the first and last word of a name split on spaces and dots. */
|
|
63
|
-
function avatarInitials(name) {
|
|
64
|
-
const parts = (name ?? "").split(/[\s.]+/).filter(Boolean);
|
|
65
|
-
if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
66
|
-
return parts[0]?.[0]?.toUpperCase() || "?";
|
|
67
|
-
}
|
|
68
|
-
function Avatar({ src, name, size = "md", status, className }) {
|
|
69
|
-
const strings = useStrings();
|
|
70
|
-
const [erroredUrl, setErroredUrl] = useState(null);
|
|
71
|
-
const showImage = !!src && erroredUrl !== src;
|
|
72
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
73
|
-
className: cx("relative inline-flex", className),
|
|
74
|
-
children: [showImage ? /* @__PURE__ */ jsx("img", {
|
|
75
|
-
src,
|
|
76
|
-
alt: name || strings.common.userAvatar,
|
|
77
|
-
onError: () => setErroredUrl(src),
|
|
78
|
-
className: cx("rounded-full object-cover", SIZE_CLASSES[size])
|
|
79
|
-
}) : /* @__PURE__ */ jsx("div", {
|
|
80
|
-
className: cx("rounded-full flex items-center justify-center font-medium", "bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] text-white", SIZE_CLASSES[size]),
|
|
81
|
-
children: avatarInitials(name)
|
|
82
|
-
}), status && /* @__PURE__ */ jsx("span", {
|
|
83
|
-
"data-testid": "online-indicator",
|
|
84
|
-
className: cx("absolute bottom-0 right-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "sm" ? "w-1.5 h-1.5" : "w-2.5 h-2.5")
|
|
85
|
-
})]
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/components/Breadcrumbs.tsx
|
|
90
|
-
var BreadcrumbContext = createContext({
|
|
91
|
-
breadcrumbs: [],
|
|
92
|
-
setBreadcrumbs: () => {},
|
|
93
|
-
rightsideBreadcrumb: null,
|
|
94
|
-
setRightsideBreadcrumb: () => {},
|
|
95
|
-
hidden: false,
|
|
96
|
-
setHidden: () => {},
|
|
97
|
-
titleActionSlot: null,
|
|
98
|
-
setTitleActionSlot: () => {},
|
|
99
|
-
rightActionSlot: null,
|
|
100
|
-
setRightActionSlot: () => {},
|
|
101
|
-
claimedPath: { current: null }
|
|
102
|
-
});
|
|
103
|
-
var useBreadcrumb = () => useContext(BreadcrumbContext);
|
|
104
|
-
function BreadcrumbProvider({ children }) {
|
|
105
|
-
const [breadcrumbs, setBreadcrumbs] = React.useState([]);
|
|
106
|
-
const [rightsideBreadcrumb, setRightsideBreadcrumb] = React.useState(null);
|
|
107
|
-
const [hidden, setHidden] = React.useState(false);
|
|
108
|
-
const [titleActionSlot, setTitleActionSlot] = React.useState(null);
|
|
109
|
-
const [rightActionSlot, setRightActionSlot] = React.useState(null);
|
|
110
|
-
const claimedPath = React.useRef(null);
|
|
111
|
-
return /* @__PURE__ */ jsx(BreadcrumbContext.Provider, {
|
|
112
|
-
value: {
|
|
113
|
-
breadcrumbs,
|
|
114
|
-
setBreadcrumbs,
|
|
115
|
-
rightsideBreadcrumb,
|
|
116
|
-
setRightsideBreadcrumb,
|
|
117
|
-
hidden,
|
|
118
|
-
setHidden,
|
|
119
|
-
titleActionSlot,
|
|
120
|
-
setTitleActionSlot,
|
|
121
|
-
rightActionSlot,
|
|
122
|
-
setRightActionSlot,
|
|
123
|
-
claimedPath
|
|
124
|
-
},
|
|
125
|
-
children
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
function useSetBreadcrumbs(getBreadcrumbs) {
|
|
129
|
-
const { setBreadcrumbs, claimedPath } = useBreadcrumb();
|
|
130
|
-
useLayoutEffect(() => {
|
|
131
|
-
claimedPath.current = window.location.pathname;
|
|
132
|
-
setBreadcrumbs(typeof getBreadcrumbs === "function" ? getBreadcrumbs() : getBreadcrumbs);
|
|
133
|
-
}, [
|
|
134
|
-
getBreadcrumbs,
|
|
135
|
-
setBreadcrumbs,
|
|
136
|
-
claimedPath
|
|
137
|
-
]);
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* For layout routes that derive breadcrumbs from the URL: applies them only
|
|
141
|
-
* while no page under the layout has set its own for the current path.
|
|
142
|
-
* Without this, a layout re-running its effect (for example when the
|
|
143
|
-
* organization's display name loads) overwrote the page's breadcrumbs.
|
|
144
|
-
*/
|
|
145
|
-
function useSetDefaultBreadcrumbs(getBreadcrumbs) {
|
|
146
|
-
const { setBreadcrumbs, claimedPath } = useBreadcrumb();
|
|
147
|
-
useLayoutEffect(() => {
|
|
148
|
-
if (claimedPath.current === window.location.pathname) return;
|
|
149
|
-
setBreadcrumbs(typeof getBreadcrumbs === "function" ? getBreadcrumbs() : getBreadcrumbs);
|
|
150
|
-
}, [
|
|
151
|
-
getBreadcrumbs,
|
|
152
|
-
setBreadcrumbs,
|
|
153
|
-
claimedPath
|
|
154
|
-
]);
|
|
155
|
-
}
|
|
156
|
-
var EMPTY_BREADCRUMBS = [];
|
|
157
|
-
/** For pages that render their own header instead of the breadcrumb strip. */
|
|
158
|
-
function useClearBreadcrumbs() {
|
|
159
|
-
useSetBreadcrumbs(EMPTY_BREADCRUMBS);
|
|
160
|
-
}
|
|
161
|
-
function useHideBreadcrumbs(hidden) {
|
|
162
|
-
const { setHidden } = useBreadcrumb();
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
setHidden(hidden);
|
|
165
|
-
return () => setHidden(false);
|
|
166
|
-
}, [hidden, setHidden]);
|
|
167
|
-
}
|
|
168
|
-
//#endregion
|
|
169
|
-
//#region src/list/RowContextMenu.tsx
|
|
170
|
-
/** Converts a single row action to a menu item: a `to` makes it a link, otherwise an action. */
|
|
171
|
-
function toRowMenuItem(action) {
|
|
172
|
-
if (action.to) return {
|
|
173
|
-
kind: "link",
|
|
174
|
-
label: action.label,
|
|
175
|
-
icon: action.icon,
|
|
176
|
-
to: action.to,
|
|
177
|
-
destructive: action.destructive
|
|
178
|
-
};
|
|
179
|
-
return {
|
|
180
|
-
kind: "action",
|
|
181
|
-
label: action.label,
|
|
182
|
-
icon: action.icon,
|
|
183
|
-
onSelect: action.onSelect ?? (() => {}),
|
|
184
|
-
disabled: action.disabled,
|
|
185
|
-
destructive: action.destructive,
|
|
186
|
-
tooltip: action.tooltip
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
/** Bridges a toolbar action (icon component, `onClick`/`href`) onto the shared
|
|
190
|
-
* `RowAction` shape. Typed structurally so any toolbar action shape matching
|
|
191
|
-
* these fields is assignable. */
|
|
192
|
-
function toolbarActionToRowAction(action) {
|
|
193
|
-
const Icon = action.icon;
|
|
194
|
-
return {
|
|
195
|
-
key: action.key,
|
|
196
|
-
label: action.label,
|
|
197
|
-
icon: /* @__PURE__ */ jsx(Icon, {}),
|
|
198
|
-
onSelect: action.onClick,
|
|
199
|
-
to: action.href,
|
|
200
|
-
disabled: action.disabled,
|
|
201
|
-
destructive: action.key === "delete" || action.key === "destroy",
|
|
202
|
-
tooltip: action.disabledTooltip
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
/** Assembles a row's context menu in the shared order: leading link(s) → middle
|
|
206
|
-
* actions → extra items → Copy submenu → trailing (destructive) actions last. */
|
|
207
|
-
function assembleRowMenu({ lead = [], actions, exclude, order, trailing = ["delete"], extra = [], copy }) {
|
|
208
|
-
const trailingSet = new Set(trailing);
|
|
209
|
-
const excludeSet = new Set(exclude);
|
|
210
|
-
let middle = actions.filter((a) => !trailingSet.has(a.key) && !excludeSet.has(a.key));
|
|
211
|
-
if (order) {
|
|
212
|
-
const byKey = new Map(middle.map((a) => [a.key, a]));
|
|
213
|
-
middle = order.map((key) => byKey.get(key)).filter((a) => a !== void 0);
|
|
214
|
-
}
|
|
215
|
-
const trailingItems = trailing.map((key) => actions.find((a) => a.key === key)).filter((a) => a !== void 0);
|
|
216
|
-
return [
|
|
217
|
-
...lead,
|
|
218
|
-
...middle.map(toRowMenuItem),
|
|
219
|
-
...extra,
|
|
220
|
-
...copy ? [copy] : [],
|
|
221
|
-
...trailingItems.map(toRowMenuItem)
|
|
222
|
-
];
|
|
223
|
-
}
|
|
224
|
-
function useRowMenu(zClassName = "z-50") {
|
|
225
|
-
const [menu, setMenu] = useState(null);
|
|
226
|
-
const onCloseRef = useRef(void 0);
|
|
227
|
-
const openMenu = useCallback((x, y, items, onClose) => {
|
|
228
|
-
if (items.length > 0) {
|
|
229
|
-
onCloseRef.current?.();
|
|
230
|
-
onCloseRef.current = onClose;
|
|
231
|
-
setMenu({
|
|
232
|
-
x,
|
|
233
|
-
y,
|
|
234
|
-
items
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}, []);
|
|
238
|
-
const close = useCallback(() => {
|
|
239
|
-
onCloseRef.current?.();
|
|
240
|
-
onCloseRef.current = void 0;
|
|
241
|
-
setMenu(null);
|
|
242
|
-
}, []);
|
|
243
|
-
return {
|
|
244
|
-
openMenu,
|
|
245
|
-
contextMenu: /* @__PURE__ */ jsx(RowContextMenu, {
|
|
246
|
-
state: menu,
|
|
247
|
-
onClose: close,
|
|
248
|
-
zClassName
|
|
249
|
-
})
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
/** The full-screen menu overlay drops CSS :hover on the triggering row; wrap openMenu here to substitute a JS-driven `active` highlight. */
|
|
253
|
-
function useRowMenuActive(openMenu) {
|
|
254
|
-
const [active, setActive] = useState(false);
|
|
255
|
-
return {
|
|
256
|
-
active,
|
|
257
|
-
openMenu: useCallback((x, y, items) => {
|
|
258
|
-
setActive(true);
|
|
259
|
-
openMenu(x, y, items, () => setActive(false));
|
|
260
|
-
}, [openMenu])
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function rowContextMenuProps(openMenu, items) {
|
|
264
|
-
return { onContextMenu: (e) => {
|
|
265
|
-
e.preventDefault();
|
|
266
|
-
if (items.length > 0) e.stopPropagation();
|
|
267
|
-
openMenu(e.clientX, e.clientY, items);
|
|
268
|
-
} };
|
|
269
|
-
}
|
|
270
|
-
function RowContextMenu({ state, onClose, zClassName }) {
|
|
271
|
-
const ref = useRef(null);
|
|
272
|
-
const [pos, setPos] = useState(null);
|
|
273
|
-
useLayoutEffect(() => {
|
|
274
|
-
if (!state || !ref.current) {
|
|
275
|
-
setPos(null);
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
const { width, height } = ref.current.getBoundingClientRect();
|
|
279
|
-
const pad = 8;
|
|
280
|
-
const top = height > window.innerHeight - pad - state.y && state.y - height - pad >= 0 ? state.y - height : Math.min(state.y, window.innerHeight - height - pad);
|
|
281
|
-
setPos({
|
|
282
|
-
left: Math.max(pad, Math.min(state.x, window.innerWidth - width - pad)),
|
|
283
|
-
top: Math.max(pad, top)
|
|
284
|
-
});
|
|
285
|
-
}, [state]);
|
|
286
|
-
useEffect(() => {
|
|
287
|
-
if (!state) return;
|
|
288
|
-
const close = () => onClose();
|
|
289
|
-
const onKey = (e) => {
|
|
290
|
-
if (e.key === "Escape") onClose();
|
|
291
|
-
};
|
|
292
|
-
window.addEventListener("scroll", close, true);
|
|
293
|
-
window.addEventListener("resize", close);
|
|
294
|
-
window.addEventListener("keydown", onKey);
|
|
295
|
-
return () => {
|
|
296
|
-
window.removeEventListener("scroll", close, true);
|
|
297
|
-
window.removeEventListener("resize", close);
|
|
298
|
-
window.removeEventListener("keydown", onKey);
|
|
299
|
-
};
|
|
300
|
-
}, [state, onClose]);
|
|
301
|
-
if (!state) return null;
|
|
302
|
-
const side = (pos?.left ?? state.x) > window.innerWidth * .6 ? "left" : "right";
|
|
303
|
-
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
304
|
-
role: "none",
|
|
305
|
-
className: cx("fixed inset-0", zClassName),
|
|
306
|
-
onClick: (e) => {
|
|
307
|
-
if (e.target === e.currentTarget) onClose();
|
|
308
|
-
},
|
|
309
|
-
onContextMenu: (e) => {
|
|
310
|
-
e.preventDefault();
|
|
311
|
-
if (ref.current?.contains(e.target)) {
|
|
312
|
-
onClose();
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
const { clientX, clientY } = e;
|
|
316
|
-
const overlay = e.currentTarget;
|
|
317
|
-
overlay.style.pointerEvents = "none";
|
|
318
|
-
const under = document.elementFromPoint(clientX, clientY);
|
|
319
|
-
overlay.style.pointerEvents = "";
|
|
320
|
-
onClose();
|
|
321
|
-
under?.dispatchEvent(new MouseEvent("contextmenu", {
|
|
322
|
-
bubbles: true,
|
|
323
|
-
cancelable: true,
|
|
324
|
-
clientX,
|
|
325
|
-
clientY
|
|
326
|
-
}));
|
|
327
|
-
},
|
|
328
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
329
|
-
ref,
|
|
330
|
-
role: "menu",
|
|
331
|
-
className: "absolute min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg backdrop-blur-xl",
|
|
332
|
-
style: {
|
|
333
|
-
left: pos?.left ?? state.x,
|
|
334
|
-
top: pos?.top ?? state.y,
|
|
335
|
-
visibility: pos ? "visible" : "hidden"
|
|
336
|
-
},
|
|
337
|
-
children: /* @__PURE__ */ jsx(MenuItemList, {
|
|
338
|
-
items: state.items,
|
|
339
|
-
onClose,
|
|
340
|
-
side
|
|
341
|
-
})
|
|
342
|
-
})
|
|
343
|
-
}), document.body);
|
|
344
|
-
}
|
|
345
|
-
var MENU_ITEM_CLASSES = "flex w-full items-center gap-2.5 px-3 py-1.5 text-left text-[13px] hover:bg-(--theme-muted-panel-bg) transition-colors cursor-pointer [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0";
|
|
346
|
-
function MenuItemList({ items, onClose, side }) {
|
|
347
|
-
return keyedByContent(items, (it) => it.kind === "divider" ? "divider" : it.label).map(({ key, item }) => item.kind === "divider" ? /* @__PURE__ */ jsx("div", {
|
|
348
|
-
"aria-hidden": "true",
|
|
349
|
-
className: "my-1 h-px bg-(--theme-border)"
|
|
350
|
-
}, key) : /* @__PURE__ */ jsx(MenuRow, {
|
|
351
|
-
item,
|
|
352
|
-
onClose,
|
|
353
|
-
side
|
|
354
|
-
}, key));
|
|
355
|
-
}
|
|
356
|
-
function MenuRow({ item, onClose, side }) {
|
|
357
|
-
const Link = useLink();
|
|
358
|
-
const notify = useNotify();
|
|
359
|
-
const { list: t } = useStrings();
|
|
360
|
-
const [openSub, setOpenSub] = useState(false);
|
|
361
|
-
const closeTimer = useRef(void 0);
|
|
362
|
-
if (item.kind === "submenu") {
|
|
363
|
-
const open = () => {
|
|
364
|
-
clearTimeout(closeTimer.current);
|
|
365
|
-
setOpenSub(true);
|
|
366
|
-
};
|
|
367
|
-
const close = () => {
|
|
368
|
-
closeTimer.current = setTimeout(() => setOpenSub(false), 160);
|
|
369
|
-
};
|
|
370
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
371
|
-
className: "relative",
|
|
372
|
-
role: "none",
|
|
373
|
-
onMouseEnter: open,
|
|
374
|
-
onMouseLeave: close,
|
|
375
|
-
onFocus: open,
|
|
376
|
-
onBlur: close,
|
|
377
|
-
children: [/* @__PURE__ */ jsxs("button", {
|
|
378
|
-
type: "button",
|
|
379
|
-
"aria-expanded": openSub,
|
|
380
|
-
"aria-haspopup": "menu",
|
|
381
|
-
onClick: open,
|
|
382
|
-
className: cx(MENU_ITEM_CLASSES, "justify-between text-(--theme-app)"),
|
|
383
|
-
children: [/* @__PURE__ */ jsxs("span", {
|
|
384
|
-
className: "flex items-center gap-2.5",
|
|
385
|
-
children: [item.icon, item.label]
|
|
386
|
-
}), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 shrink-0 opacity-60" })]
|
|
387
|
-
}), openSub && /* @__PURE__ */ jsx("div", {
|
|
388
|
-
className: cx("absolute -top-1 z-10 min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg", side === "left" ? "right-full" : "left-full"),
|
|
389
|
-
children: /* @__PURE__ */ jsx(MenuItemList, {
|
|
390
|
-
items: item.items,
|
|
391
|
-
onClose,
|
|
392
|
-
side
|
|
393
|
-
})
|
|
394
|
-
})]
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
if (item.kind === "link") {
|
|
398
|
-
const className = cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)");
|
|
399
|
-
if (item.reloadDocument) return /* @__PURE__ */ jsxs("a", {
|
|
400
|
-
href: item.to,
|
|
401
|
-
onClick: onClose,
|
|
402
|
-
className,
|
|
403
|
-
children: [item.icon, item.label]
|
|
404
|
-
});
|
|
405
|
-
return /* @__PURE__ */ jsxs(Link, {
|
|
406
|
-
to: item.to,
|
|
407
|
-
onClick: onClose,
|
|
408
|
-
className,
|
|
409
|
-
children: [item.icon, item.label]
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
413
|
-
type: "button",
|
|
414
|
-
disabled: item.disabled && !item.tooltip,
|
|
415
|
-
"aria-disabled": item.disabled,
|
|
416
|
-
...item.disabled && item.tooltip ? {
|
|
417
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
418
|
-
"data-tooltip-content": item.tooltip
|
|
419
|
-
} : {},
|
|
420
|
-
onClick: () => {
|
|
421
|
-
if (item.disabled) return;
|
|
422
|
-
if (item.copy) {
|
|
423
|
-
const { text, label } = item.copy;
|
|
424
|
-
navigator.clipboard?.writeText(text).then(() => notify.success(t.copied(label)), () => notify.error(t.couldntCopy(label)));
|
|
425
|
-
}
|
|
426
|
-
item.onSelect?.();
|
|
427
|
-
onClose();
|
|
428
|
-
},
|
|
429
|
-
className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)", item.disabled && "opacity-40 cursor-not-allowed hover:bg-transparent"),
|
|
430
|
-
children: [
|
|
431
|
-
item.icon,
|
|
432
|
-
item.label,
|
|
433
|
-
item.selected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto opacity-80" })
|
|
434
|
-
]
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
/** Returns a builder for the Copy submenu, labeled from the provider's strings. */
|
|
438
|
-
function useCopySubmenu() {
|
|
439
|
-
const { list: t } = useStrings();
|
|
440
|
-
return useCallback(({ name, nameLabel, email, username, uid, id, url, extra }) => {
|
|
441
|
-
const items = [
|
|
442
|
-
{
|
|
443
|
-
label: nameLabel ?? t.labelName,
|
|
444
|
-
value: name,
|
|
445
|
-
icon: /* @__PURE__ */ jsx(CopyIcon, {})
|
|
446
|
-
},
|
|
447
|
-
{
|
|
448
|
-
label: t.labelEmail,
|
|
449
|
-
value: email,
|
|
450
|
-
icon: /* @__PURE__ */ jsx(MailIcon, {})
|
|
451
|
-
},
|
|
452
|
-
{
|
|
453
|
-
label: t.labelUsername,
|
|
454
|
-
value: username,
|
|
455
|
-
icon: /* @__PURE__ */ jsx(UserIcon, {})
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
label: t.labelUid,
|
|
459
|
-
value: uid === null || uid === void 0 ? null : String(uid),
|
|
460
|
-
icon: /* @__PURE__ */ jsx(KeyIcon, {})
|
|
461
|
-
},
|
|
462
|
-
{
|
|
463
|
-
label: t.labelId,
|
|
464
|
-
value: id,
|
|
465
|
-
icon: /* @__PURE__ */ jsx(IdCardIcon, {})
|
|
466
|
-
},
|
|
467
|
-
{
|
|
468
|
-
label: t.labelUrl,
|
|
469
|
-
value: url,
|
|
470
|
-
icon: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
471
|
-
},
|
|
472
|
-
...(extra ?? []).map((e) => ({
|
|
473
|
-
label: e.label,
|
|
474
|
-
value: e.value,
|
|
475
|
-
icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
|
|
476
|
-
}))
|
|
477
|
-
].filter((f) => f.value).map((f) => ({
|
|
478
|
-
kind: "action",
|
|
479
|
-
label: t.copy(f.label),
|
|
480
|
-
icon: f.icon,
|
|
481
|
-
copy: {
|
|
482
|
-
text: f.value,
|
|
483
|
-
label: f.label
|
|
484
|
-
}
|
|
485
|
-
}));
|
|
486
|
-
return {
|
|
487
|
-
kind: "submenu",
|
|
488
|
-
label: t.copyMenu,
|
|
489
|
-
icon: /* @__PURE__ */ jsx(ClipboardIcon, {}),
|
|
490
|
-
items
|
|
491
|
-
};
|
|
492
|
-
}, [t]);
|
|
493
|
-
}
|
|
494
|
-
/** Stays visible while active (menu open) so it doesn't vanish behind the overlay. */
|
|
495
|
-
function MoreButton({ onOpen, active, className }) {
|
|
496
|
-
const { list: t } = useStrings();
|
|
497
|
-
return /* @__PURE__ */ jsx("button", {
|
|
498
|
-
type: "button",
|
|
499
|
-
"aria-label": t.moreActions,
|
|
500
|
-
onClick: (e) => {
|
|
501
|
-
e.stopPropagation();
|
|
502
|
-
const r = e.currentTarget.getBoundingClientRect();
|
|
503
|
-
onOpen(r.right, r.bottom);
|
|
504
|
-
},
|
|
505
|
-
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) focus-visible:opacity-100", active ? "opacity-100" : "opacity-0 group-hover:opacity-100", className),
|
|
506
|
-
children: /* @__PURE__ */ jsx(MoreIcon, { className: "h-4 w-4" })
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
//#endregion
|
|
510
|
-
//#region src/components/PageHeader.tsx
|
|
511
|
-
var headerActionButtonClasses = "flex items-center justify-center w-6 h-6 rounded-md shrink-0 cursor-pointer text-(--theme-muted-text-color) hover:text-(--theme-app) hover:bg-(--theme-muted-panel-bg) transition-colors";
|
|
512
|
-
var headerAddButtonClasses = "inline-flex h-[26px] shrink-0 items-center gap-1.5 rounded-md border border-(--theme-border) px-2 text-xs font-medium cursor-pointer text-(--theme-muted-text-color) hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) transition-colors";
|
|
513
|
-
/** With menu, the plus opens a chooser; otherwise navigates to or calls the
|
|
514
|
-
* single action. `word` is the visible verb; `label` stays the full action for
|
|
515
|
-
* the tooltip and screen readers. */
|
|
516
|
-
function HeaderAddButton({ to, onClick, label, word = "add", menu, disabled = false, disabledHint }) {
|
|
517
|
-
const { common } = useStrings();
|
|
518
|
-
const Link = useLink();
|
|
519
|
-
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AddIcon, { className: "w-3 h-3" }), /* @__PURE__ */ jsx("span", { children: word === "create" ? common.create : common.add })] });
|
|
520
|
-
if (menu) return /* @__PURE__ */ jsx(AddMenu, {
|
|
521
|
-
items: menu,
|
|
522
|
-
label,
|
|
523
|
-
buttonClassName: headerAddButtonClasses,
|
|
524
|
-
children: content
|
|
525
|
-
});
|
|
526
|
-
if (to) return /* @__PURE__ */ jsx(Link, {
|
|
527
|
-
to,
|
|
528
|
-
"aria-label": label,
|
|
529
|
-
title: label,
|
|
530
|
-
className: headerAddButtonClasses,
|
|
531
|
-
children: content
|
|
532
|
-
});
|
|
533
|
-
const hint = disabled ? disabledHint : void 0;
|
|
534
|
-
return /* @__PURE__ */ jsx("button", {
|
|
535
|
-
type: "button",
|
|
536
|
-
onClick: disabled ? void 0 : onClick,
|
|
537
|
-
"aria-label": hint ? `${label}. ${hint}` : label,
|
|
538
|
-
"aria-disabled": disabled || void 0,
|
|
539
|
-
...hint ? {
|
|
540
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
541
|
-
"data-tooltip-content": hint
|
|
542
|
-
} : { title: label },
|
|
543
|
-
className: cx(headerAddButtonClasses, "aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:hover:bg-transparent aria-disabled:hover:text-(--theme-muted-text-color)"),
|
|
544
|
-
children: content
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
function HeaderActionMenu({ items, label = "Actions" }) {
|
|
548
|
-
if (items.length === 0) return null;
|
|
549
|
-
return /* @__PURE__ */ jsx(AddMenu, {
|
|
550
|
-
items,
|
|
551
|
-
label,
|
|
552
|
-
buttonClassName: headerActionButtonClasses,
|
|
553
|
-
children: /* @__PURE__ */ jsx(MoreIcon, { className: "w-3.5 h-3.5" })
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
/** The header "…" trigger for a RowMenuItem menu — same rendering (submenus,
|
|
557
|
-
* destructive styling) as the list pages' right-click context menus. */
|
|
558
|
-
function HeaderRowMenu({ items, label = "Actions" }) {
|
|
559
|
-
const { openMenu, contextMenu } = useRowMenu();
|
|
560
|
-
if (items.length === 0) return null;
|
|
561
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
562
|
-
type: "button",
|
|
563
|
-
"aria-label": label,
|
|
564
|
-
title: label,
|
|
565
|
-
className: headerActionButtonClasses,
|
|
566
|
-
onClick: (e) => {
|
|
567
|
-
const r = e.currentTarget.getBoundingClientRect();
|
|
568
|
-
openMenu(r.left, r.bottom + 4, items);
|
|
569
|
-
},
|
|
570
|
-
children: /* @__PURE__ */ jsx(MoreIcon, { className: "w-3.5 h-3.5" })
|
|
571
|
-
}), contextMenu] });
|
|
572
|
-
}
|
|
573
|
-
function HeaderEditButton({ to, onClick, label = "Edit", disabled, tooltip }) {
|
|
574
|
-
const Link = useLink();
|
|
575
|
-
const tooltipProps = tooltip ? {
|
|
576
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
577
|
-
"data-tooltip-content": tooltip
|
|
578
|
-
} : {};
|
|
579
|
-
if (to && !disabled) return /* @__PURE__ */ jsx(Link, {
|
|
580
|
-
to,
|
|
581
|
-
"aria-label": label,
|
|
582
|
-
...tooltip ? {} : { title: label },
|
|
583
|
-
className: headerActionButtonClasses,
|
|
584
|
-
...tooltipProps,
|
|
585
|
-
children: /* @__PURE__ */ jsx(EditIcon, { className: "w-3 h-3" })
|
|
586
|
-
});
|
|
587
|
-
return /* @__PURE__ */ jsx("button", {
|
|
588
|
-
type: "button",
|
|
589
|
-
onClick,
|
|
590
|
-
disabled,
|
|
591
|
-
"aria-label": label,
|
|
592
|
-
title: tooltip ? void 0 : label,
|
|
593
|
-
className: cx(headerActionButtonClasses, disabled && "opacity-50 cursor-not-allowed hover:bg-transparent"),
|
|
594
|
-
...tooltipProps,
|
|
595
|
-
children: /* @__PURE__ */ jsx(EditIcon, { className: "w-3 h-3" })
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
/** Renders nothing when the modern breadcrumb strip isn't mounted (classic chrome or self-headered pages). */
|
|
599
|
-
function BreadcrumbsTitleAction({ children }) {
|
|
600
|
-
const { titleActionSlot } = useBreadcrumb();
|
|
601
|
-
if (!titleActionSlot) return null;
|
|
602
|
-
return createPortal(children, titleActionSlot);
|
|
603
|
-
}
|
|
604
|
-
function BreadcrumbsRightAction({ children }) {
|
|
605
|
-
const { rightActionSlot } = useBreadcrumb();
|
|
606
|
-
if (!rightActionSlot) return null;
|
|
607
|
-
return createPortal(children, rightActionSlot);
|
|
608
|
-
}
|
|
609
|
-
var breadcrumbsActionClasses = "flex items-center gap-1 link text-xs whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed";
|
|
610
|
-
function BreadcrumbsActionButton({ icon: Icon, label, ariaLabel, to, onClick, disabled, tooltip }) {
|
|
611
|
-
const Link = useLink();
|
|
612
|
-
const tip = tooltip ? {
|
|
613
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
614
|
-
"data-tooltip-content": tooltip
|
|
615
|
-
} : {};
|
|
616
|
-
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }), label] });
|
|
617
|
-
if (to && !disabled) return /* @__PURE__ */ jsx(Link, {
|
|
618
|
-
to,
|
|
619
|
-
className: breadcrumbsActionClasses,
|
|
620
|
-
...ariaLabel ? { "aria-label": ariaLabel } : {},
|
|
621
|
-
...tip,
|
|
622
|
-
children: content
|
|
623
|
-
});
|
|
624
|
-
return /* @__PURE__ */ jsx("button", {
|
|
625
|
-
type: "button",
|
|
626
|
-
onClick,
|
|
627
|
-
disabled,
|
|
628
|
-
className: breadcrumbsActionClasses,
|
|
629
|
-
...ariaLabel ? { "aria-label": ariaLabel } : {},
|
|
630
|
-
...tip,
|
|
631
|
-
children: content
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
function PageHeader({ breadcrumbs, title, titleAction, actions, toolbar, className, sticky = true, stickyTopClassName = "top-0" }) {
|
|
635
|
-
const { setHidden } = useBreadcrumb();
|
|
636
|
-
const Link = useLink();
|
|
637
|
-
const { breadcrumbPin, navToggle } = useSlots();
|
|
638
|
-
useLayoutEffect(() => {
|
|
639
|
-
setHidden(true);
|
|
640
|
-
return () => setHidden(false);
|
|
641
|
-
}, [setHidden]);
|
|
642
|
-
const crumbs = [...breadcrumbs ?? []];
|
|
643
|
-
const lastLabel = crumbs[crumbs.length - 1]?.label;
|
|
644
|
-
if (title !== null && title !== void 0 && title !== lastLabel) crumbs.push({ label: title });
|
|
645
|
-
const crumbRow = crumbs.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
646
|
-
className: "flex items-center gap-1.5 min-w-0",
|
|
647
|
-
children: [
|
|
648
|
-
/* @__PURE__ */ jsx("nav", {
|
|
649
|
-
"aria-label": "Breadcrumb",
|
|
650
|
-
className: "flex items-center gap-2 min-w-0 text-[13px]",
|
|
651
|
-
children: keyedByContent(crumbs, (c) => c.href ?? (typeof c.label === "string" ? c.label : "crumb")).map(({ key, item: crumb }, idx) => {
|
|
652
|
-
if (idx === crumbs.length - 1) return /* @__PURE__ */ jsx("h1", {
|
|
653
|
-
className: "m-0 text-[13px] font-medium leading-none text-(--theme-app) truncate",
|
|
654
|
-
children: crumb.label
|
|
655
|
-
}, key);
|
|
656
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [crumb.href ? /* @__PURE__ */ jsx(Link, {
|
|
657
|
-
to: crumb.href,
|
|
658
|
-
className: "text-(--theme-muted-text-color) hover:text-(--theme-app) transition-colors cursor-pointer whitespace-nowrap",
|
|
659
|
-
children: crumb.label
|
|
660
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
661
|
-
className: "text-(--theme-muted-text-color) whitespace-nowrap",
|
|
662
|
-
children: crumb.label
|
|
663
|
-
}), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3 h-3 opacity-60 shrink-0 text-(--theme-muted-text-color)" })] }, key);
|
|
664
|
-
})
|
|
665
|
-
}),
|
|
666
|
-
titleAction,
|
|
667
|
-
breadcrumbPin?.({ crumbs })
|
|
668
|
-
]
|
|
669
|
-
});
|
|
670
|
-
const actionCluster = actions && /* @__PURE__ */ jsx("div", {
|
|
671
|
-
className: "flex items-center gap-1.5 shrink-0",
|
|
672
|
-
children: actions
|
|
673
|
-
});
|
|
674
|
-
const toggle = navToggle?.();
|
|
675
|
-
const hasLeading = !!crumbRow || !!toggle;
|
|
676
|
-
const leading = hasLeading ? /* @__PURE__ */ jsxs("div", {
|
|
677
|
-
className: "flex items-center gap-2 min-w-0",
|
|
678
|
-
children: [toggle, crumbRow]
|
|
679
|
-
}) : /* @__PURE__ */ jsx("div", {});
|
|
680
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
681
|
-
className: cx(sticky && cx("sticky z-20", stickyTopClassName), "w-full bg-(--theme-app-bg)", className),
|
|
682
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
683
|
-
className: cx("flex items-center justify-between gap-6 px-4 h-11", hasLeading && "border-b border-(--theme-border)"),
|
|
684
|
-
children: [leading, actionCluster]
|
|
685
|
-
}), toolbar && /* @__PURE__ */ jsx("div", {
|
|
686
|
-
className: "px-4",
|
|
687
|
-
children: toolbar
|
|
688
|
-
})]
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
//#endregion
|
|
692
|
-
export { useSetDefaultBreadcrumbs as C, AddMenu as E, useSetBreadcrumbs as S, avatarInitials as T, useRowMenuActive as _, HeaderAddButton as a, useClearBreadcrumbs as b, PageHeader as c, assembleRowMenu as d, rowContextMenuProps as f, useRowMenu as g, useCopySubmenu as h, HeaderActionMenu as i, headerActionButtonClasses as l, toolbarActionToRowAction as m, BreadcrumbsRightAction as n, HeaderEditButton as o, toRowMenuItem as p, BreadcrumbsTitleAction as r, HeaderRowMenu as s, BreadcrumbsActionButton as t, MoreButton as u, BreadcrumbProvider as v, Avatar as w, useHideBreadcrumbs as x, useBreadcrumb as y };
|