@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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { useLink, useStrings } from "../components/Provider.js";
|
|
2
|
+
import { MenuIcon } from "../icons.js";
|
|
3
|
+
import { TOOLTIP_ID } from "../components/Tooltip.js";
|
|
4
|
+
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
|
5
|
+
import cx from "classnames";
|
|
6
|
+
import { Fragment, createContext, useContext, useLayoutEffect, useRef, useState } from "react";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/list/ActionToolbar.tsx
|
|
9
|
+
var OverflowMenuContext = createContext(false);
|
|
10
|
+
/** Omits data-tooltip-content when absent — react-tooltip treats an explicit undefined as an empty tooltip anchor. */
|
|
11
|
+
function tipProps(content, place) {
|
|
12
|
+
return {
|
|
13
|
+
"data-tooltip-id": TOOLTIP_ID,
|
|
14
|
+
"data-tooltip-place": place,
|
|
15
|
+
...content !== void 0 && { "data-tooltip-content": content }
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function ToolbarItemView({ item }) {
|
|
19
|
+
if ("element" in item) return /* @__PURE__ */ jsx(Fragment$1, { children: item.element });
|
|
20
|
+
return /* @__PURE__ */ jsx(ToolbarButton, { action: item });
|
|
21
|
+
}
|
|
22
|
+
function ToolbarButton({ action }) {
|
|
23
|
+
const inOverflowMenu = useContext(OverflowMenuContext);
|
|
24
|
+
const Link = useLink();
|
|
25
|
+
if (inOverflowMenu) return /* @__PURE__ */ jsx(OverflowRow, { item: action });
|
|
26
|
+
const className = cx("inline-flex items-center gap-x-0.5 h-9 px-2 rounded-md text-[13.5px] uppercase font-semibold transition-colors whitespace-nowrap", "bg-(--theme-element) text-(--theme-element-text)", action.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-(--theme-element-hover)");
|
|
27
|
+
const tooltipProps = tipProps(action.disabled ? action.disabledTooltip : action.enabledTooltip, "bottom");
|
|
28
|
+
const Icon = action.icon;
|
|
29
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
30
|
+
className: "h-6 flex items-center",
|
|
31
|
+
children: /* @__PURE__ */ jsx(Icon, { className: cx("w-auto", action.iconClassName) })
|
|
32
|
+
}), action.label] });
|
|
33
|
+
if (action.href && !action.disabled) return /* @__PURE__ */ jsx(Link, {
|
|
34
|
+
to: action.href,
|
|
35
|
+
className,
|
|
36
|
+
...tooltipProps,
|
|
37
|
+
children: content
|
|
38
|
+
});
|
|
39
|
+
if (action.disabled) return /* @__PURE__ */ jsx("span", {
|
|
40
|
+
className: "inline-flex",
|
|
41
|
+
...tooltipProps,
|
|
42
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
43
|
+
type: "button",
|
|
44
|
+
disabled: true,
|
|
45
|
+
className,
|
|
46
|
+
children: content
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
return /* @__PURE__ */ jsx("button", {
|
|
50
|
+
type: "button",
|
|
51
|
+
onClick: action.onClick,
|
|
52
|
+
className,
|
|
53
|
+
...tooltipProps,
|
|
54
|
+
children: content
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** A single overflowed item rendered as a full-width row inside the `…` menu. */
|
|
58
|
+
function OverflowRow({ item }) {
|
|
59
|
+
const Link = useLink();
|
|
60
|
+
const Icon = item.icon;
|
|
61
|
+
const className = cx("flex w-full items-center gap-x-1 px-4 py-2 text-[13px] uppercase font-semibold link hover:theme-hover", item.disabled && "opacity-50 cursor-not-allowed");
|
|
62
|
+
const tooltipProps = tipProps(item.disabled ? item.disabledTooltip : item.enabledTooltip, "left");
|
|
63
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
64
|
+
className: "w-5 h-6 flex items-center",
|
|
65
|
+
children: /* @__PURE__ */ jsx(Icon, { className: cx(item.iconClassName) })
|
|
66
|
+
}), item.label] });
|
|
67
|
+
if (item.href && !item.disabled) return /* @__PURE__ */ jsx(MenuItem, {
|
|
68
|
+
as: Link,
|
|
69
|
+
to: item.href,
|
|
70
|
+
className,
|
|
71
|
+
...tooltipProps,
|
|
72
|
+
children: content
|
|
73
|
+
});
|
|
74
|
+
return /* @__PURE__ */ jsx(MenuItem, {
|
|
75
|
+
as: "button",
|
|
76
|
+
type: "button",
|
|
77
|
+
onClick: item.onClick,
|
|
78
|
+
disabled: item.disabled ?? false,
|
|
79
|
+
className,
|
|
80
|
+
...tooltipProps,
|
|
81
|
+
children: content
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function OverflowMenu({ items }) {
|
|
85
|
+
const { list: t } = useStrings();
|
|
86
|
+
return /* @__PURE__ */ jsxs(Menu, {
|
|
87
|
+
as: "div",
|
|
88
|
+
className: "relative inline-block text-left",
|
|
89
|
+
children: [/* @__PURE__ */ jsx(MenuButton, {
|
|
90
|
+
"aria-label": t.moreActions,
|
|
91
|
+
className: "inline-flex items-center justify-center h-9 w-9 rounded-md border theme-border link hover:theme-hover transition-colors",
|
|
92
|
+
"data-tooltip-id": TOOLTIP_ID,
|
|
93
|
+
"data-tooltip-content": t.moreActions,
|
|
94
|
+
"data-testid": "action-toolbar-menu-button",
|
|
95
|
+
children: /* @__PURE__ */ jsx(MenuIcon, {})
|
|
96
|
+
}), /* @__PURE__ */ jsx(MenuItems, {
|
|
97
|
+
unmount: false,
|
|
98
|
+
anchor: {
|
|
99
|
+
to: "bottom end",
|
|
100
|
+
gap: 4
|
|
101
|
+
},
|
|
102
|
+
className: "z-50 min-w-56 rounded-md border theme-border bg-(--theme-app-bg) shadow-lg py-1 focus:outline-none",
|
|
103
|
+
children: /* @__PURE__ */ jsx(OverflowMenuContext.Provider, {
|
|
104
|
+
value: true,
|
|
105
|
+
children: items.map((item) => "element" in item ? /* @__PURE__ */ jsx(Fragment, { children: item.element }, item.key) : /* @__PURE__ */ jsx(OverflowRow, { item }, item.key))
|
|
106
|
+
})
|
|
107
|
+
})]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
var MENU_BUTTON_WIDTH = 44;
|
|
111
|
+
var ITEM_GAP = 4;
|
|
112
|
+
function fitCount(widths, available, gap, menuWidth) {
|
|
113
|
+
if (widths.length === 0) return 0;
|
|
114
|
+
if (widths.reduce((sum, w) => sum + w, 0) + gap * (widths.length - 1) <= available) return widths.length;
|
|
115
|
+
let used = menuWidth;
|
|
116
|
+
let count = 0;
|
|
117
|
+
for (const w of widths) {
|
|
118
|
+
if (used + gap + w > available) break;
|
|
119
|
+
used += gap + w;
|
|
120
|
+
count++;
|
|
121
|
+
}
|
|
122
|
+
return count;
|
|
123
|
+
}
|
|
124
|
+
/** Measures in a layout effect (before paint) so the inline/overflow split never flashes. */
|
|
125
|
+
function CollapsibleRight({ items }) {
|
|
126
|
+
const wrapRef = useRef(null);
|
|
127
|
+
const itemRefs = useRef({});
|
|
128
|
+
const widthCache = useRef({});
|
|
129
|
+
const [available, setAvailable] = useState(Number.POSITIVE_INFINITY);
|
|
130
|
+
const [count, setCount] = useState(items.length);
|
|
131
|
+
useLayoutEffect(() => {
|
|
132
|
+
const el = wrapRef.current;
|
|
133
|
+
if (!el) return;
|
|
134
|
+
const update = () => setAvailable(el.clientWidth);
|
|
135
|
+
update();
|
|
136
|
+
const observer = new ResizeObserver(update);
|
|
137
|
+
observer.observe(el);
|
|
138
|
+
return () => observer.disconnect();
|
|
139
|
+
}, []);
|
|
140
|
+
useLayoutEffect(() => {
|
|
141
|
+
for (const key in itemRefs.current) {
|
|
142
|
+
const el = itemRefs.current[key];
|
|
143
|
+
if (el) widthCache.current[key] = el.offsetWidth;
|
|
144
|
+
}
|
|
145
|
+
const next = fitCount(items.map((item) => widthCache.current[item.key] ?? 0), available, ITEM_GAP, MENU_BUTTON_WIDTH);
|
|
146
|
+
setCount((prev) => prev === next ? prev : next);
|
|
147
|
+
});
|
|
148
|
+
const visible = items.slice(0, count);
|
|
149
|
+
const overflow = items.slice(count);
|
|
150
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
151
|
+
ref: wrapRef,
|
|
152
|
+
className: "flex-1 min-w-0 flex items-center justify-end gap-1",
|
|
153
|
+
children: [visible.map((item) => /* @__PURE__ */ jsx("span", {
|
|
154
|
+
ref: (el) => {
|
|
155
|
+
itemRefs.current[item.key] = el;
|
|
156
|
+
},
|
|
157
|
+
className: "inline-flex shrink-0",
|
|
158
|
+
children: /* @__PURE__ */ jsx(ToolbarItemView, { item })
|
|
159
|
+
}, item.key)), overflow.length > 0 && /* @__PURE__ */ jsx(OverflowMenu, { items: overflow })]
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** Pins a detail-page toolbar just below the sticky breadcrumb strip (top-10 matches the strip's 40px height). */
|
|
163
|
+
var stickyToolbarClasses = "sticky top-10 z-10 bg-(--theme-app-bg)";
|
|
164
|
+
/** Pins a detail-page tabs row under the pinned toolbar (top-22 = 40px strip + 48px toolbar block). */
|
|
165
|
+
var stickyTabsClasses = "sticky top-22 z-10 bg-(--theme-app-bg)";
|
|
166
|
+
/** Pins a detail-page tabs row directly under the breadcrumb strip when the page has no pinned toolbar (top-10 = the strip's height). */
|
|
167
|
+
var stickyTabsUnderHeaderClasses = "sticky top-10 z-10 bg-(--theme-app-bg)";
|
|
168
|
+
/** Action groups left, secondary actions right (collapsing into a `…` menu). */
|
|
169
|
+
function ActionToolbar({ groups, right = [], sticky = false }) {
|
|
170
|
+
const visibleGroups = groups.map((group) => group.filter((a) => !a.hidden)).filter((group) => group.length > 0);
|
|
171
|
+
const visibleRight = right.filter((a) => !a.hidden);
|
|
172
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
173
|
+
className: cx("flex items-center gap-2.5", sticky && cx("sticky top-10 z-10 bg-(--theme-app-bg)", "py-1.5")),
|
|
174
|
+
children: [visibleGroups.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
175
|
+
className: "flex items-center gap-2.5 shrink-0",
|
|
176
|
+
children: visibleGroups.map((group, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-(--theme-border)" }), /* @__PURE__ */ jsx("div", {
|
|
177
|
+
className: "flex items-center gap-1",
|
|
178
|
+
children: group.map((item) => /* @__PURE__ */ jsx(ToolbarItemView, { item }, item.key))
|
|
179
|
+
})] }, group[0]?.key ?? i))
|
|
180
|
+
}), visibleRight.length > 0 && /* @__PURE__ */ jsx(CollapsibleRight, { items: visibleRight })]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
export { ActionToolbar, ToolbarButton, stickyTabsClasses, stickyTabsUnderHeaderClasses, stickyToolbarClasses };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import cx from "classnames";
|
|
2
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
//#region src/list/HoverCard.tsx
|
|
6
|
+
function useHoverCard() {
|
|
7
|
+
const triggerRef = useRef(null);
|
|
8
|
+
const [coords, setCoords] = useState(null);
|
|
9
|
+
const openTimer = useRef(void 0);
|
|
10
|
+
const closeTimer = useRef(void 0);
|
|
11
|
+
useEffect(() => () => {
|
|
12
|
+
clearTimeout(openTimer.current);
|
|
13
|
+
clearTimeout(closeTimer.current);
|
|
14
|
+
}, []);
|
|
15
|
+
const scheduleOpen = () => {
|
|
16
|
+
clearTimeout(closeTimer.current);
|
|
17
|
+
openTimer.current = setTimeout(() => {
|
|
18
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
19
|
+
if (rect) setCoords({
|
|
20
|
+
x: rect.left,
|
|
21
|
+
y: rect.bottom
|
|
22
|
+
});
|
|
23
|
+
}, 350);
|
|
24
|
+
};
|
|
25
|
+
const scheduleClose = () => {
|
|
26
|
+
clearTimeout(openTimer.current);
|
|
27
|
+
closeTimer.current = setTimeout(() => setCoords(null), 150);
|
|
28
|
+
};
|
|
29
|
+
const keepOpen = () => clearTimeout(closeTimer.current);
|
|
30
|
+
return {
|
|
31
|
+
triggerRef,
|
|
32
|
+
coords,
|
|
33
|
+
scheduleOpen,
|
|
34
|
+
scheduleClose,
|
|
35
|
+
keepOpen
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function HoverCardSurface({ x, y, widthClassName, padded = true, relayoutKey, onKeepOpen, onLeave, children }) {
|
|
39
|
+
const ref = useRef(null);
|
|
40
|
+
const [pos, setPos] = useState(null);
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
if (!ref.current) return;
|
|
43
|
+
const { width, height } = ref.current.getBoundingClientRect();
|
|
44
|
+
const pad = 8;
|
|
45
|
+
const left = Math.max(pad, Math.min(x, window.innerWidth - width - pad));
|
|
46
|
+
const top = y + 8 + height + pad > window.innerHeight ? Math.max(pad, y - 8 - height) : y + 8;
|
|
47
|
+
setPos({
|
|
48
|
+
left,
|
|
49
|
+
top
|
|
50
|
+
});
|
|
51
|
+
}, [
|
|
52
|
+
x,
|
|
53
|
+
y,
|
|
54
|
+
relayoutKey
|
|
55
|
+
]);
|
|
56
|
+
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
57
|
+
ref,
|
|
58
|
+
role: "none",
|
|
59
|
+
onMouseEnter: onKeepOpen,
|
|
60
|
+
onMouseLeave: onLeave,
|
|
61
|
+
onFocus: onKeepOpen,
|
|
62
|
+
onBlur: onLeave,
|
|
63
|
+
className: cx("fixed z-[9999] overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) shadow-xl backdrop-blur-xl", padded && "p-3", widthClassName),
|
|
64
|
+
style: {
|
|
65
|
+
left: pos?.left ?? x,
|
|
66
|
+
top: pos?.top ?? y + 8,
|
|
67
|
+
visibility: pos ? "visible" : "hidden"
|
|
68
|
+
},
|
|
69
|
+
children
|
|
70
|
+
}), document.querySelector(".ds-root") ?? document.body);
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { HoverCardSurface, useHoverCard };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { useNavigation } from "../components/Provider.js";
|
|
2
|
+
import "../components/Tooltip.js";
|
|
3
|
+
import { MoreButton, rowContextMenuProps, useRowMenuActive } from "./RowContextMenu.js";
|
|
4
|
+
import { PageHeader } from "../components/PageHeader.js";
|
|
5
|
+
import { Table } from "../components/Table.js";
|
|
6
|
+
import { ListActionsHeader } from "./ListTable.js";
|
|
7
|
+
import cx from "classnames";
|
|
8
|
+
import { Children, cloneElement, createContext, isValidElement, useContext, useMemo } from "react";
|
|
9
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/list/ListPage.tsx
|
|
11
|
+
/** Negative offsets (admin/org) cancel the shell's pt-4 so rows don't peek through the gap above the pinned header. */
|
|
12
|
+
var SECTION_STICKY_TOP = {
|
|
13
|
+
main: "top-0",
|
|
14
|
+
kubernetes: "top-0",
|
|
15
|
+
admin: "-top-4",
|
|
16
|
+
org: "-top-4"
|
|
17
|
+
};
|
|
18
|
+
/** Whether the shell adds pt-4 padding that the edge-to-edge list must cancel with a negative margin. */
|
|
19
|
+
var SECTION_SHELL_PADDED = {
|
|
20
|
+
main: false,
|
|
21
|
+
kubernetes: false,
|
|
22
|
+
admin: true,
|
|
23
|
+
org: true
|
|
24
|
+
};
|
|
25
|
+
/** Defaults mean rows outside a ListView fully show actions (no view = show everything). */
|
|
26
|
+
var RowActionsContext = createContext({
|
|
27
|
+
show: true,
|
|
28
|
+
always: false,
|
|
29
|
+
columnClasses: []
|
|
30
|
+
});
|
|
31
|
+
function useRowActions(view) {
|
|
32
|
+
return useMemo(() => ({
|
|
33
|
+
show: view?.showActions ?? true,
|
|
34
|
+
always: view?.alwaysShowActions ?? false,
|
|
35
|
+
columnClasses: view?.columnClasses ?? []
|
|
36
|
+
}), [
|
|
37
|
+
view?.showActions,
|
|
38
|
+
view?.alwaysShowActions,
|
|
39
|
+
view?.columnClasses
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
function ListRowActionsProvider({ view, children }) {
|
|
43
|
+
const rowActions = useRowActions(view);
|
|
44
|
+
return /* @__PURE__ */ jsx(RowActionsContext.Provider, {
|
|
45
|
+
value: rowActions,
|
|
46
|
+
children
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function ListPage({ section = "main", shellPadded, embedded = false, breadcrumbs, title, titleAction, actions, toolbar, view, children }) {
|
|
50
|
+
const cancelShellPadding = shellPadded ?? SECTION_SHELL_PADDED[section];
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
52
|
+
className: cx("flex h-full min-h-0 flex-col", cancelShellPadding && "-m-4"),
|
|
53
|
+
children: [embedded ? toolbar && /* @__PURE__ */ jsx("div", {
|
|
54
|
+
className: "px-4 py-1.5",
|
|
55
|
+
children: toolbar
|
|
56
|
+
}) : /* @__PURE__ */ jsx(PageHeader, {
|
|
57
|
+
stickyTopClassName: SECTION_STICKY_TOP[section],
|
|
58
|
+
breadcrumbs,
|
|
59
|
+
title,
|
|
60
|
+
titleAction,
|
|
61
|
+
actions,
|
|
62
|
+
toolbar
|
|
63
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
64
|
+
className: "relative @container min-h-0 flex-1 overflow-auto",
|
|
65
|
+
children: /* @__PURE__ */ jsx(ListRowActionsProvider, {
|
|
66
|
+
view,
|
|
67
|
+
children
|
|
68
|
+
})
|
|
69
|
+
})]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
|
|
73
|
+
const { active: menuActive, openMenu: openRowMenu } = useRowMenuActive(openMenu);
|
|
74
|
+
const { show: showActions, always: alwaysShowActions, columnClasses } = useContext(RowActionsContext);
|
|
75
|
+
const styledCells = Children.toArray(children).map((child, i) => {
|
|
76
|
+
const cls = columnClasses[i];
|
|
77
|
+
if (!cls || !isValidElement(child)) return child;
|
|
78
|
+
const el = child;
|
|
79
|
+
return cloneElement(el, { className: cx(el.props.className, cls) });
|
|
80
|
+
});
|
|
81
|
+
const handleRowClick = (e) => {
|
|
82
|
+
if (e.target.closest("a,button,input,label")) return;
|
|
83
|
+
if (selectionActive && onRowSelect) {
|
|
84
|
+
onRowSelect(e);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (href) goTo(href);
|
|
88
|
+
else onActivate?.();
|
|
89
|
+
};
|
|
90
|
+
const pinnedLabels = new Set((pinnedActions ?? []).map((a) => a.label));
|
|
91
|
+
const hasOverflowItems = items.some((item) => item.kind !== "divider" && (item.kind === "submenu" || !pinnedLabels.has(item.label)));
|
|
92
|
+
return /* @__PURE__ */ jsxs("tr", {
|
|
93
|
+
className: cx("group", selected ? "bg-blue-500/5" : menuActive ? "theme-hover" : "hover:theme-hover", (href || onActivate || selectionActive) && "cursor-pointer", className),
|
|
94
|
+
onClick: handleRowClick,
|
|
95
|
+
...rowContextMenuProps(openRowMenu, items),
|
|
96
|
+
children: [
|
|
97
|
+
leading,
|
|
98
|
+
styledCells,
|
|
99
|
+
showActions && /* @__PURE__ */ jsx(Table.Item, {
|
|
100
|
+
className: "relative py-2.5",
|
|
101
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
102
|
+
className: "absolute inset-y-0 right-0 flex items-center gap-0.5 pr-4",
|
|
103
|
+
children: [pinnedActions && pinnedActions.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
104
|
+
className: "hidden items-center gap-0.5 @[44rem]:flex",
|
|
105
|
+
children: pinnedActions.map((action) => /* @__PURE__ */ jsx("button", {
|
|
106
|
+
type: "button",
|
|
107
|
+
"aria-label": action.label,
|
|
108
|
+
"data-tooltip-id": "global-tooltip",
|
|
109
|
+
"data-tooltip-content": action.disabled && action.tooltip ? action.tooltip : action.label,
|
|
110
|
+
"data-tooltip-place": "bottom",
|
|
111
|
+
"aria-disabled": action.disabled,
|
|
112
|
+
onClick: (e) => {
|
|
113
|
+
e.stopPropagation();
|
|
114
|
+
if (action.disabled) return;
|
|
115
|
+
action.onSelect();
|
|
116
|
+
},
|
|
117
|
+
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) aria-disabled:cursor-not-allowed aria-disabled:opacity-20 aria-disabled:hover:bg-transparent aria-disabled:hover:text-(--theme-muted-text-color) [&>svg]:h-4 [&>svg]:w-4", alwaysShowActions || menuActive ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100"),
|
|
118
|
+
children: action.icon
|
|
119
|
+
}, action.key))
|
|
120
|
+
}), /* @__PURE__ */ jsx(MoreButton, {
|
|
121
|
+
active: menuActive || alwaysShowActions,
|
|
122
|
+
onOpen: (x, y) => openRowMenu(x, y, items),
|
|
123
|
+
className: hasOverflowItems ? void 0 : "@[44rem]:hidden"
|
|
124
|
+
})]
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** Name column min-width is by role, not position, so a leading checkbox doesn't shift it. */
|
|
131
|
+
function ListColumns({ view }) {
|
|
132
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [view.visibleColumns.map((col, i) => /* @__PURE__ */ jsx(Table.Header, {
|
|
133
|
+
caps: false,
|
|
134
|
+
className: cx(col.headerClassName, view.columnClasses[i]),
|
|
135
|
+
style: col.alwaysVisible ? { minWidth: 200 } : void 0,
|
|
136
|
+
children: col.label
|
|
137
|
+
}, col.key)), /* @__PURE__ */ jsx(ListActionsHeader, { view })] });
|
|
138
|
+
}
|
|
139
|
+
ListColumns.isTableHeader = true;
|
|
140
|
+
/** Stable `goTo` for whole-row navigation (`rowNavProps`, `ListRow`). */
|
|
141
|
+
function useListNavigate() {
|
|
142
|
+
return useNavigation().goTo;
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useStrings } from "../components/Provider.js";
|
|
2
|
+
import { ChevronLeftIcon, ChevronRightIcon } from "../icons.js";
|
|
3
|
+
import { listControlButtonClasses } from "./ListViewControls.js";
|
|
4
|
+
import cx from "classnames";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/list/ListPager.tsx
|
|
7
|
+
/** Page sizes offered by the pager's per-page select; first entry is the default. */
|
|
8
|
+
var LIST_PAGE_SIZES = [
|
|
9
|
+
50,
|
|
10
|
+
100,
|
|
11
|
+
200
|
|
12
|
+
];
|
|
13
|
+
/** Footer pager bar for paginated new-nav lists: "{start}–{end} of {total}" with prev/next. Renders nothing for a single page. */
|
|
14
|
+
function ListPager({ page, pageSize, total, onPageChange, pageSizes = LIST_PAGE_SIZES, onPageSizeChange, hasNext }) {
|
|
15
|
+
const t = useStrings().list;
|
|
16
|
+
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
17
|
+
const start = page * pageSize + 1;
|
|
18
|
+
const end = Math.min(total, (page + 1) * pageSize);
|
|
19
|
+
const smallest = Math.min(...pageSizes);
|
|
20
|
+
const showSizeSelect = !!onPageSizeChange && (total > smallest || pageSize > smallest);
|
|
21
|
+
if (pageCount <= 1 && !showSizeSelect) return null;
|
|
22
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
23
|
+
className: "flex items-center justify-between px-2.5 h-10 shrink-0 border-t theme-border",
|
|
24
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
25
|
+
className: "flex items-center gap-3 text-xs text-(--theme-muted-text-color)",
|
|
26
|
+
children: [/* @__PURE__ */ jsx("span", { children: t.pager(start, end, total) }), showSizeSelect && /* @__PURE__ */ jsxs("label", {
|
|
27
|
+
className: "flex items-center gap-1",
|
|
28
|
+
children: [t.perPage, /* @__PURE__ */ jsx("select", {
|
|
29
|
+
value: pageSize,
|
|
30
|
+
onChange: (e) => onPageSizeChange(Number(e.target.value)),
|
|
31
|
+
className: "theme-input rounded px-1.5 py-0.5 text-xs",
|
|
32
|
+
children: pageSizes.map((size) => /* @__PURE__ */ jsx("option", {
|
|
33
|
+
value: size,
|
|
34
|
+
children: size
|
|
35
|
+
}, size))
|
|
36
|
+
})]
|
|
37
|
+
})]
|
|
38
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
39
|
+
className: "flex items-center gap-1",
|
|
40
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
41
|
+
type: "button",
|
|
42
|
+
"aria-label": t.paginationPrevious,
|
|
43
|
+
disabled: page === 0,
|
|
44
|
+
onClick: () => onPageChange(page - 1),
|
|
45
|
+
className: cx(listControlButtonClasses, "disabled:opacity-40 disabled:pointer-events-none"),
|
|
46
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "w-3.5 h-3.5" })
|
|
47
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
48
|
+
type: "button",
|
|
49
|
+
"aria-label": t.paginationNext,
|
|
50
|
+
disabled: hasNext === void 0 ? page >= pageCount - 1 : !hasNext,
|
|
51
|
+
onClick: () => onPageChange(page + 1),
|
|
52
|
+
className: cx(listControlButtonClasses, "disabled:opacity-40 disabled:pointer-events-none"),
|
|
53
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3.5 h-3.5" })
|
|
54
|
+
})]
|
|
55
|
+
})]
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { LIST_PAGE_SIZES, ListPager };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { useLink, useStrings } from "../components/Provider.js";
|
|
2
|
+
import { ErrorIcon } from "../icons.js";
|
|
3
|
+
import { positionKeys } from "../components/keys.js";
|
|
4
|
+
import { Table } from "../components/Table.js";
|
|
5
|
+
import cx from "classnames";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/list/ListTable.tsx
|
|
8
|
+
var NAME_TEXT = "font-medium text-[13px] leading-tight text-(--theme-app) truncate";
|
|
9
|
+
var SUBTITLE_TEXT = "text-xs leading-tight text-(--theme-muted-text-color) truncate";
|
|
10
|
+
/** table-auto + horizontal scroll; the name column has a min-width floor so it can't be crushed. */
|
|
11
|
+
var listTableProps = {
|
|
12
|
+
borderless: true,
|
|
13
|
+
panel: false,
|
|
14
|
+
rounded: false,
|
|
15
|
+
theadClassName: "text-(--theme-muted-text-color)",
|
|
16
|
+
tbodyClassName: "divide-y border-b border-(--theme-border) divide-(--theme-border)",
|
|
17
|
+
className: "table-auto w-full [&_td:first-child]:pl-4 [&_th:first-child]:pl-4 [&_td:last-child]:pr-4 [&_th:last-child]:pr-4"
|
|
18
|
+
};
|
|
19
|
+
/** Widths come only from the header row, so a windowed body cannot shift the
|
|
20
|
+
* columns as different content scrolls into view. */
|
|
21
|
+
var listTableFixedProps = {
|
|
22
|
+
...listTableProps,
|
|
23
|
+
className: listTableProps.className.replace("table-auto", "table-fixed")
|
|
24
|
+
};
|
|
25
|
+
function NameCell({ icon, name, subtitle, href, badge, title }) {
|
|
26
|
+
const Link = useLink();
|
|
27
|
+
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [icon, /* @__PURE__ */ jsxs("div", {
|
|
28
|
+
className: "min-w-0",
|
|
29
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
30
|
+
className: "flex min-w-0 items-center gap-1.5",
|
|
31
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
32
|
+
className: cx(NAME_TEXT, href && "group-hover/namecell:text-(--theme-link)"),
|
|
33
|
+
title,
|
|
34
|
+
children: name
|
|
35
|
+
}), badge]
|
|
36
|
+
}), subtitle && /* @__PURE__ */ jsx("div", {
|
|
37
|
+
className: SUBTITLE_TEXT,
|
|
38
|
+
children: subtitle
|
|
39
|
+
})]
|
|
40
|
+
})] });
|
|
41
|
+
return /* @__PURE__ */ jsx(Table.Item, {
|
|
42
|
+
className: "py-2.5",
|
|
43
|
+
children: href ? /* @__PURE__ */ jsx(Link, {
|
|
44
|
+
to: href,
|
|
45
|
+
className: "group/namecell flex items-center gap-2.5 min-w-0 cursor-pointer",
|
|
46
|
+
children: inner
|
|
47
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
48
|
+
className: "flex items-center gap-2.5 min-w-0",
|
|
49
|
+
children: inner
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function GroupRow({ label, count, colSpan }) {
|
|
54
|
+
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", {
|
|
55
|
+
colSpan,
|
|
56
|
+
className: "bg-(--theme-muted-panel-bg) py-1.5 text-xs font-medium",
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", {
|
|
59
|
+
className: "text-(--theme-app)",
|
|
60
|
+
children: label
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ jsx("span", {
|
|
63
|
+
className: "mx-1.5 opacity-50",
|
|
64
|
+
children: "·"
|
|
65
|
+
}),
|
|
66
|
+
/* @__PURE__ */ jsx("span", {
|
|
67
|
+
className: "text-(--theme-muted-text-color)",
|
|
68
|
+
children: count
|
|
69
|
+
})
|
|
70
|
+
]
|
|
71
|
+
}) });
|
|
72
|
+
}
|
|
73
|
+
function ListError({ error, noun = "data" }) {
|
|
74
|
+
const { list: t } = useStrings();
|
|
75
|
+
const message = error && typeof error === "object" && "message" in error ? String(error.message) : void 0;
|
|
76
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
77
|
+
className: "flex flex-col items-center justify-center gap-3 py-20 text-center",
|
|
78
|
+
children: [/* @__PURE__ */ jsx(ErrorIcon, { className: "h-10 w-10 text-red-400 opacity-80" }), /* @__PURE__ */ jsxs("div", {
|
|
79
|
+
className: "space-y-1",
|
|
80
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
81
|
+
className: "text-sm font-medium text-(--theme-app)",
|
|
82
|
+
children: t.couldNotLoad(noun)
|
|
83
|
+
}), message && /* @__PURE__ */ jsx("p", {
|
|
84
|
+
className: "max-w-md text-xs text-(--theme-muted-text-color)",
|
|
85
|
+
children: message
|
|
86
|
+
})]
|
|
87
|
+
})]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function ListSkeleton({ rows = 6 }) {
|
|
91
|
+
const { loading } = useStrings();
|
|
92
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
93
|
+
role: "status",
|
|
94
|
+
"aria-label": loading,
|
|
95
|
+
className: "divide-y border-b border-(--theme-border) divide-(--theme-border)",
|
|
96
|
+
children: [positionKeys(rows, "skeleton").map((key) => /* @__PURE__ */ jsxs("div", {
|
|
97
|
+
"aria-hidden": "true",
|
|
98
|
+
className: "flex items-center gap-3 px-4 py-2.5 animate-pulse",
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ jsx("div", { className: "h-5 w-5 rounded bg-(--theme-muted-panel-bg)" }),
|
|
101
|
+
/* @__PURE__ */ jsxs("div", {
|
|
102
|
+
className: "space-y-1.5",
|
|
103
|
+
children: [/* @__PURE__ */ jsx("div", { className: "h-3 w-40 rounded bg-(--theme-muted-panel-bg)" }), /* @__PURE__ */ jsx("div", { className: "h-2.5 w-24 rounded bg-(--theme-muted-panel-bg)" })]
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ jsx("div", { className: "ml-auto h-3 w-20 rounded bg-(--theme-muted-panel-bg)" })
|
|
106
|
+
]
|
|
107
|
+
}, key)), /* @__PURE__ */ jsx("span", {
|
|
108
|
+
className: "sr-only",
|
|
109
|
+
children: loading
|
|
110
|
+
})]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Prevents the name column from being crushed under table-auto layout during horizontal overflow. */
|
|
114
|
+
var NAME_MIN_WIDTH_PX = 200;
|
|
115
|
+
/** Trailing cell geometry: icon-button size + gap + padding, sized to fit exactly its pinned buttons. */
|
|
116
|
+
var ACTION_BUTTON_PX = 24;
|
|
117
|
+
var ACTION_GAP_PX = 2;
|
|
118
|
+
var ACTIONS_CELL_PAD_PX = 28;
|
|
119
|
+
/** Width the trailing actions column reserves for `count` always-visible
|
|
120
|
+
* buttons plus the hover `⋯` trigger. */
|
|
121
|
+
function actionsColumnWidth(count) {
|
|
122
|
+
const buttons = count + 1;
|
|
123
|
+
return buttons * ACTION_BUTTON_PX + (buttons - 1) * ACTION_GAP_PX + ACTIONS_CELL_PAD_PX;
|
|
124
|
+
}
|
|
125
|
+
/** Shared leading selection checkbox for multi-select rows: stops the row-click
|
|
126
|
+
* and suppresses shift-click text selection. Wrap in <Table.Item> for `leading`. */
|
|
127
|
+
function RowSelectCheckbox({ checked, label, onToggle }) {
|
|
128
|
+
return /* @__PURE__ */ jsx("input", {
|
|
129
|
+
type: "checkbox",
|
|
130
|
+
"aria-label": label,
|
|
131
|
+
checked,
|
|
132
|
+
onChange: () => {},
|
|
133
|
+
onClick: (e) => {
|
|
134
|
+
e.stopPropagation();
|
|
135
|
+
onToggle(e);
|
|
136
|
+
},
|
|
137
|
+
onMouseDown: (e) => {
|
|
138
|
+
if (e.shiftKey) e.preventDefault();
|
|
139
|
+
},
|
|
140
|
+
className: "h-4 w-4 shrink-0 rounded border-(--theme-border) text-blue-500 focus:ring-blue-500 focus:ring-offset-0 cursor-pointer"
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/** Sizes to fit pinned buttons + ⋯; below ~44rem only ⋯ remains. Pass a view's
|
|
144
|
+
* chrome (structurally: showActions + actionsWidth) or actionCount. */
|
|
145
|
+
function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
146
|
+
if (view && !view.showActions) return null;
|
|
147
|
+
const width = view ? view.actionsWidth : actionsColumnWidth(actionCount);
|
|
148
|
+
return /* @__PURE__ */ jsx(Table.Header, {
|
|
149
|
+
caps: false,
|
|
150
|
+
style: {
|
|
151
|
+
width,
|
|
152
|
+
minWidth: width
|
|
153
|
+
},
|
|
154
|
+
className: cx("relative py-2 text-right @max-[43rem]:w-[52px]! @max-[43rem]:min-w-[52px]!", className),
|
|
155
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
156
|
+
className: "sr-only",
|
|
157
|
+
children: "Actions"
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
ListActionsHeader.isTableHeader = true;
|
|
162
|
+
//#endregion
|
|
163
|
+
export { GroupRow, ListActionsHeader, ListError, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps };
|