@parallelworks/ui 0.5.0 → 0.5.2
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 +0 -6
- package/dist/chunks/{CodePreviewEditor-CBtYRZi6.js → CodePreviewEditor-Uij_Npp4.js} +1 -1
- package/dist/chunks/{CreateModal-6zZZHxCI.js → CreateModal-DEvWkdFl.js} +4 -29
- package/dist/chunks/{Monaco-CvFXoW3r.js → Monaco-H1M5hQbJ.js} +2 -2
- package/dist/chunks/PageHeader-CSo3LVId.js +571 -0
- package/dist/chunks/{Provider-jQCAN3NN.js → Provider-BIL5347a.js} +5 -1
- package/dist/chunks/{SwitchToggle-D0ud8cd5.js → SwitchToggle-DiBXEP12.js} +1 -1
- package/dist/chunks/{editor-CEXg6C8X.js → editor-4ZuZruLz.js} +2 -2
- package/dist/chunks/{list-CvDWt0TC.js → list-CgzqVlao.js} +296 -302
- package/dist/components/Breadcrumbs.d.ts +28 -0
- package/dist/components/PageHeader.d.ts +69 -0
- package/dist/components/Provider.d.ts +13 -1
- package/dist/components/Table.d.ts +1 -1
- package/dist/editor/index.js +1 -1
- package/dist/file-explorer/FileExplorer.d.ts +1 -3
- package/dist/file-explorer/helpers.d.ts +1 -3
- package/dist/file-explorer/index.js +15 -22
- package/dist/form/index.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -5
- package/dist/list/ActionToolbar.d.ts +38 -0
- package/dist/list/ListPage.d.ts +63 -0
- package/dist/list/RowContextMenu.d.ts +1 -1
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +3 -2
- package/dist/logviewer/index.js +1 -1
- package/dist/styles/theme.css +2 -0
- package/dist/styles.css +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.js +9 -0
- package/dist/workflow/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,321 +1,186 @@
|
|
|
1
|
-
import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon,
|
|
2
|
-
import { c as useStrings,
|
|
1
|
+
import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, DisplayIcon, ErrorIcon, FilterIcon, MenuIcon, SearchIcon, XIcon } from "../icons.js";
|
|
2
|
+
import { c as useStrings, n as useLink, r as useNavigation } from "./Provider-BIL5347a.js";
|
|
3
3
|
import { n as TOOLTIP_ID, r as TooltipInfo } from "./Tooltip-WgbiC_nd.js";
|
|
4
|
+
import { c as PageHeader, f as rowContextMenuProps, g as useRowMenuActive, l as MoreButton } from "./PageHeader-CSo3LVId.js";
|
|
4
5
|
import { n as Table } from "./Table-ByziK93x.js";
|
|
5
6
|
import cx from "classnames";
|
|
6
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { Children, Fragment as Fragment$1, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
9
|
import { createPortal } from "react-dom";
|
|
10
|
+
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
|
9
11
|
import { useLocalStorage } from "usehooks-ts";
|
|
10
|
-
//#region src/list/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
kind: "link",
|
|
15
|
-
label: action.label,
|
|
16
|
-
icon: action.icon,
|
|
17
|
-
to: action.to,
|
|
18
|
-
destructive: action.destructive
|
|
19
|
-
};
|
|
12
|
+
//#region src/list/ActionToolbar.tsx
|
|
13
|
+
var OverflowMenuContext = createContext(false);
|
|
14
|
+
/** Omits data-tooltip-content when absent — react-tooltip treats an explicit undefined as an empty tooltip anchor. */
|
|
15
|
+
function tipProps(content, place) {
|
|
20
16
|
return {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
onSelect: action.onSelect ?? (() => {}),
|
|
25
|
-
disabled: action.disabled,
|
|
26
|
-
destructive: action.destructive
|
|
17
|
+
"data-tooltip-id": TOOLTIP_ID,
|
|
18
|
+
"data-tooltip-place": place,
|
|
19
|
+
...content !== void 0 && { "data-tooltip-content": content }
|
|
27
20
|
};
|
|
28
21
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
function ToolbarItemView({ item }) {
|
|
23
|
+
if ("element" in item) return /* @__PURE__ */ jsx(Fragment, { children: item.element });
|
|
24
|
+
return /* @__PURE__ */ jsx(ToolbarButton, { action: item });
|
|
25
|
+
}
|
|
26
|
+
function ToolbarButton({ action }) {
|
|
27
|
+
const inOverflowMenu = useContext(OverflowMenuContext);
|
|
28
|
+
const Link = useLink();
|
|
29
|
+
if (inOverflowMenu) return /* @__PURE__ */ jsx(OverflowRow, { item: action });
|
|
30
|
+
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)");
|
|
31
|
+
const tooltipProps = tipProps(action.disabled ? action.disabledTooltip : action.enabledTooltip, "bottom");
|
|
33
32
|
const Icon = action.icon;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
34
|
+
className: "h-6 flex items-center",
|
|
35
|
+
children: /* @__PURE__ */ jsx(Icon, { className: cx("w-auto", action.iconClassName) })
|
|
36
|
+
}), action.label] });
|
|
37
|
+
if (action.href && !action.disabled) return /* @__PURE__ */ jsx(Link, {
|
|
39
38
|
to: action.href,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
middle = order.map((key) => byKey.get(key)).filter((a) => a !== void 0);
|
|
53
|
-
}
|
|
54
|
-
const trailingItems = trailing.map((key) => actions.find((a) => a.key === key)).filter((a) => a !== void 0);
|
|
55
|
-
return [
|
|
56
|
-
...lead,
|
|
57
|
-
...middle.map(toRowMenuItem),
|
|
58
|
-
...extra,
|
|
59
|
-
...copy ? [copy] : [],
|
|
60
|
-
...trailingItems.map(toRowMenuItem)
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
function useRowMenu() {
|
|
64
|
-
const [menu, setMenu] = useState(null);
|
|
65
|
-
const onCloseRef = useRef(void 0);
|
|
66
|
-
return {
|
|
67
|
-
openMenu: useCallback((x, y, items, onClose) => {
|
|
68
|
-
if (items.length > 0) {
|
|
69
|
-
onCloseRef.current?.();
|
|
70
|
-
onCloseRef.current = onClose;
|
|
71
|
-
setMenu({
|
|
72
|
-
x,
|
|
73
|
-
y,
|
|
74
|
-
items
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}, []),
|
|
78
|
-
contextMenu: /* @__PURE__ */ jsx(RowContextMenu, {
|
|
79
|
-
state: menu,
|
|
80
|
-
onClose: useCallback(() => {
|
|
81
|
-
onCloseRef.current?.();
|
|
82
|
-
onCloseRef.current = void 0;
|
|
83
|
-
setMenu(null);
|
|
84
|
-
}, [])
|
|
39
|
+
className,
|
|
40
|
+
...tooltipProps,
|
|
41
|
+
children: content
|
|
42
|
+
});
|
|
43
|
+
if (action.disabled) return /* @__PURE__ */ jsx("span", {
|
|
44
|
+
className: "inline-flex",
|
|
45
|
+
...tooltipProps,
|
|
46
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
47
|
+
type: "button",
|
|
48
|
+
disabled: true,
|
|
49
|
+
className,
|
|
50
|
+
children: content
|
|
85
51
|
})
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
setActive(true);
|
|
95
|
-
openMenu(x, y, items, () => setActive(false));
|
|
96
|
-
}, [openMenu])
|
|
97
|
-
};
|
|
52
|
+
});
|
|
53
|
+
return /* @__PURE__ */ jsx("button", {
|
|
54
|
+
type: "button",
|
|
55
|
+
onClick: action.onClick,
|
|
56
|
+
className,
|
|
57
|
+
...tooltipProps,
|
|
58
|
+
children: content
|
|
59
|
+
});
|
|
98
60
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
61
|
+
/** A single overflowed item rendered as a full-width row inside the `…` menu. */
|
|
62
|
+
function OverflowRow({ item }) {
|
|
63
|
+
const Link = useLink();
|
|
64
|
+
const Icon = item.icon;
|
|
65
|
+
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");
|
|
66
|
+
const tooltipProps = tipProps(item.disabled ? item.disabledTooltip : item.enabledTooltip, "left");
|
|
67
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
68
|
+
className: "w-5 h-6 flex items-center",
|
|
69
|
+
children: /* @__PURE__ */ jsx(Icon, { className: cx(item.iconClassName) })
|
|
70
|
+
}), item.label] });
|
|
71
|
+
if (item.href && !item.disabled) return /* @__PURE__ */ jsx(MenuItem, {
|
|
72
|
+
as: Link,
|
|
73
|
+
to: item.href,
|
|
74
|
+
className,
|
|
75
|
+
...tooltipProps,
|
|
76
|
+
children: content
|
|
77
|
+
});
|
|
78
|
+
return /* @__PURE__ */ jsx(MenuItem, {
|
|
79
|
+
as: "button",
|
|
80
|
+
type: "button",
|
|
81
|
+
onClick: item.onClick,
|
|
82
|
+
disabled: item.disabled ?? false,
|
|
83
|
+
className,
|
|
84
|
+
...tooltipProps,
|
|
85
|
+
children: content
|
|
86
|
+
});
|
|
105
87
|
}
|
|
106
|
-
function
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
useEffect(() => {
|
|
123
|
-
if (!state) return;
|
|
124
|
-
const close = () => onClose();
|
|
125
|
-
const onKey = (e) => {
|
|
126
|
-
if (e.key === "Escape") onClose();
|
|
127
|
-
};
|
|
128
|
-
window.addEventListener("scroll", close, true);
|
|
129
|
-
window.addEventListener("resize", close);
|
|
130
|
-
window.addEventListener("keydown", onKey);
|
|
131
|
-
return () => {
|
|
132
|
-
window.removeEventListener("scroll", close, true);
|
|
133
|
-
window.removeEventListener("resize", close);
|
|
134
|
-
window.removeEventListener("keydown", onKey);
|
|
135
|
-
};
|
|
136
|
-
}, [state, onClose]);
|
|
137
|
-
if (!state) return null;
|
|
138
|
-
const side = (pos?.left ?? state.x) > window.innerWidth * .6 ? "left" : "right";
|
|
139
|
-
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
140
|
-
className: "fixed inset-0 z-50",
|
|
141
|
-
onClick: onClose,
|
|
142
|
-
onContextMenu: (e) => {
|
|
143
|
-
e.preventDefault();
|
|
144
|
-
if (ref.current?.contains(e.target)) {
|
|
145
|
-
onClose();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const { clientX, clientY } = e;
|
|
149
|
-
const overlay = e.currentTarget;
|
|
150
|
-
overlay.style.pointerEvents = "none";
|
|
151
|
-
const under = document.elementFromPoint(clientX, clientY);
|
|
152
|
-
overlay.style.pointerEvents = "";
|
|
153
|
-
onClose();
|
|
154
|
-
under?.dispatchEvent(new MouseEvent("contextmenu", {
|
|
155
|
-
bubbles: true,
|
|
156
|
-
cancelable: true,
|
|
157
|
-
clientX,
|
|
158
|
-
clientY
|
|
159
|
-
}));
|
|
160
|
-
},
|
|
161
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
162
|
-
ref,
|
|
163
|
-
role: "menu",
|
|
164
|
-
className: "absolute min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg backdrop-blur-xl",
|
|
165
|
-
style: {
|
|
166
|
-
left: pos?.left ?? state.x,
|
|
167
|
-
top: pos?.top ?? state.y,
|
|
168
|
-
visibility: pos ? "visible" : "hidden"
|
|
88
|
+
function OverflowMenu({ items }) {
|
|
89
|
+
const { list: t } = useStrings();
|
|
90
|
+
return /* @__PURE__ */ jsxs(Menu, {
|
|
91
|
+
as: "div",
|
|
92
|
+
className: "relative inline-block text-left",
|
|
93
|
+
children: [/* @__PURE__ */ jsx(MenuButton, {
|
|
94
|
+
className: "inline-flex items-center justify-center h-9 w-9 rounded-md border theme-border link hover:theme-hover transition-colors",
|
|
95
|
+
"data-tooltip-id": TOOLTIP_ID,
|
|
96
|
+
"data-tooltip-content": t.moreActions,
|
|
97
|
+
"data-testid": "action-toolbar-menu-button",
|
|
98
|
+
children: /* @__PURE__ */ jsx(MenuIcon, {})
|
|
99
|
+
}), /* @__PURE__ */ jsx(MenuItems, {
|
|
100
|
+
unmount: false,
|
|
101
|
+
anchor: {
|
|
102
|
+
to: "bottom end",
|
|
103
|
+
gap: 4
|
|
169
104
|
},
|
|
170
|
-
|
|
171
|
-
children: /* @__PURE__ */ jsx(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
side
|
|
105
|
+
className: "z-50 min-w-56 rounded-md border theme-border bg-(--theme-app-bg) shadow-lg py-1 focus:outline-none",
|
|
106
|
+
children: /* @__PURE__ */ jsx(OverflowMenuContext.Provider, {
|
|
107
|
+
value: true,
|
|
108
|
+
children: items.map((item) => "element" in item ? /* @__PURE__ */ jsx(Fragment$1, { children: item.element }, item.key) : /* @__PURE__ */ jsx(OverflowRow, { item }, item.key))
|
|
175
109
|
})
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
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";
|
|
180
|
-
function MenuItemList({ items, onClose, side }) {
|
|
181
|
-
return items.map((item, i) => item.kind === "divider" ? /* @__PURE__ */ jsx("div", {
|
|
182
|
-
"aria-hidden": "true",
|
|
183
|
-
className: "my-1 h-px bg-(--theme-border)"
|
|
184
|
-
}, `divider-${i}`) : /* @__PURE__ */ jsx(MenuRow, {
|
|
185
|
-
item,
|
|
186
|
-
onClose,
|
|
187
|
-
side
|
|
188
|
-
}, `${item.label}-${i}`));
|
|
110
|
+
})]
|
|
111
|
+
});
|
|
189
112
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const close = () => {
|
|
202
|
-
closeTimer.current = setTimeout(() => setOpenSub(false), 160);
|
|
203
|
-
};
|
|
204
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
205
|
-
className: "relative",
|
|
206
|
-
onMouseEnter: open,
|
|
207
|
-
onMouseLeave: close,
|
|
208
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
209
|
-
className: cx(MENU_ITEM_CLASSES, "justify-between text-(--theme-app)"),
|
|
210
|
-
children: [/* @__PURE__ */ jsxs("span", {
|
|
211
|
-
className: "flex items-center gap-2.5",
|
|
212
|
-
children: [item.icon, item.label]
|
|
213
|
-
}), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 shrink-0 opacity-60" })]
|
|
214
|
-
}), openSub && /* @__PURE__ */ jsx("div", {
|
|
215
|
-
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"),
|
|
216
|
-
children: /* @__PURE__ */ jsx(MenuItemList, {
|
|
217
|
-
items: item.items,
|
|
218
|
-
onClose,
|
|
219
|
-
side
|
|
220
|
-
})
|
|
221
|
-
})]
|
|
222
|
-
});
|
|
113
|
+
var MENU_BUTTON_WIDTH = 44;
|
|
114
|
+
var ITEM_GAP = 4;
|
|
115
|
+
function fitCount(widths, available, gap, menuWidth) {
|
|
116
|
+
if (widths.length === 0) return 0;
|
|
117
|
+
if (widths.reduce((sum, w) => sum + w, 0) + gap * (widths.length - 1) <= available) return widths.length;
|
|
118
|
+
let used = menuWidth;
|
|
119
|
+
let count = 0;
|
|
120
|
+
for (const w of widths) {
|
|
121
|
+
if (used + gap + w > available) break;
|
|
122
|
+
used += gap + w;
|
|
123
|
+
count++;
|
|
223
124
|
}
|
|
224
|
-
|
|
225
|
-
to: item.to,
|
|
226
|
-
onClick: onClose,
|
|
227
|
-
className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)"),
|
|
228
|
-
children: [item.icon, item.label]
|
|
229
|
-
});
|
|
230
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
231
|
-
type: "button",
|
|
232
|
-
disabled: item.disabled,
|
|
233
|
-
onClick: () => {
|
|
234
|
-
if (item.copy) {
|
|
235
|
-
const { text, label } = item.copy;
|
|
236
|
-
navigator.clipboard?.writeText(text).then(() => notify.success(t.copied(label)), () => notify.error(t.couldntCopy(label)));
|
|
237
|
-
}
|
|
238
|
-
item.onSelect?.();
|
|
239
|
-
onClose();
|
|
240
|
-
},
|
|
241
|
-
className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)", item.disabled && "opacity-40 cursor-not-allowed hover:bg-transparent"),
|
|
242
|
-
children: [
|
|
243
|
-
item.icon,
|
|
244
|
-
item.label,
|
|
245
|
-
item.selected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto opacity-80" })
|
|
246
|
-
]
|
|
247
|
-
});
|
|
125
|
+
return count;
|
|
248
126
|
}
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
label: t ? t("rowContextMenu.labelUid") : "UID",
|
|
272
|
-
value: uid === null || uid === void 0 ? null : String(uid),
|
|
273
|
-
icon: /* @__PURE__ */ jsx(KeyIcon, {})
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
label: t ? t("rowContextMenu.labelId") : "ID",
|
|
277
|
-
value: id,
|
|
278
|
-
icon: /* @__PURE__ */ jsx(IdCardIcon, {})
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
label: t ? t("rowContextMenu.labelUrl") : "URL",
|
|
282
|
-
value: url,
|
|
283
|
-
icon: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
284
|
-
},
|
|
285
|
-
...(extra ?? []).map((e) => ({
|
|
286
|
-
label: e.label,
|
|
287
|
-
value: e.value,
|
|
288
|
-
icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
|
|
289
|
-
}))
|
|
290
|
-
].filter((f) => f.value).map((f) => ({
|
|
291
|
-
kind: "action",
|
|
292
|
-
label: t ? t("rowContextMenu.copy", { label: f.label }) : `Copy ${f.label}`,
|
|
293
|
-
icon: f.icon,
|
|
294
|
-
copy: {
|
|
295
|
-
text: f.value,
|
|
296
|
-
label: f.label
|
|
127
|
+
/** Measures in a layout effect (before paint) so the inline/overflow split never flashes. */
|
|
128
|
+
function CollapsibleRight({ items }) {
|
|
129
|
+
const wrapRef = useRef(null);
|
|
130
|
+
const itemRefs = useRef({});
|
|
131
|
+
const widthCache = useRef({});
|
|
132
|
+
const [available, setAvailable] = useState(Number.POSITIVE_INFINITY);
|
|
133
|
+
const [count, setCount] = useState(items.length);
|
|
134
|
+
useLayoutEffect(() => {
|
|
135
|
+
const el = wrapRef.current;
|
|
136
|
+
if (!el) return;
|
|
137
|
+
const update = () => setAvailable(el.clientWidth);
|
|
138
|
+
update();
|
|
139
|
+
const observer = new ResizeObserver(update);
|
|
140
|
+
observer.observe(el);
|
|
141
|
+
return () => observer.disconnect();
|
|
142
|
+
}, []);
|
|
143
|
+
useLayoutEffect(() => {
|
|
144
|
+
for (const key in itemRefs.current) {
|
|
145
|
+
const el = itemRefs.current[key];
|
|
146
|
+
if (el) widthCache.current[key] = el.offsetWidth;
|
|
297
147
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
148
|
+
const next = fitCount(items.map((item) => widthCache.current[item.key] ?? 0), available, ITEM_GAP, MENU_BUTTON_WIDTH);
|
|
149
|
+
setCount((prev) => prev === next ? prev : next);
|
|
150
|
+
});
|
|
151
|
+
const visible = items.slice(0, count);
|
|
152
|
+
const overflow = items.slice(count);
|
|
153
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
154
|
+
ref: wrapRef,
|
|
155
|
+
className: "flex-1 min-w-0 flex items-center justify-end gap-1",
|
|
156
|
+
children: [visible.map((item) => /* @__PURE__ */ jsx("span", {
|
|
157
|
+
ref: (el) => {
|
|
158
|
+
itemRefs.current[item.key] = el;
|
|
159
|
+
},
|
|
160
|
+
className: "inline-flex shrink-0",
|
|
161
|
+
children: /* @__PURE__ */ jsx(ToolbarItemView, { item })
|
|
162
|
+
}, item.key)), overflow.length > 0 && /* @__PURE__ */ jsx(OverflowMenu, { items: overflow })]
|
|
163
|
+
});
|
|
305
164
|
}
|
|
306
|
-
/**
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
className: cx("
|
|
318
|
-
children: /* @__PURE__ */ jsx(
|
|
165
|
+
/** Pins a detail-page toolbar just below the sticky breadcrumb strip (top-10 matches the strip's 40px height). */
|
|
166
|
+
var stickyToolbarClasses = "sticky top-10 z-10 bg-(--theme-app-bg)";
|
|
167
|
+
/** Pins a detail-page tabs row under the pinned toolbar (top-22 = 40px strip + 48px toolbar block). */
|
|
168
|
+
var stickyTabsClasses = "sticky top-22 z-10 bg-(--theme-app-bg)";
|
|
169
|
+
/** Pins a detail-page tabs row directly under the breadcrumb strip when the page has no pinned toolbar (top-10 = the strip's height). */
|
|
170
|
+
var stickyTabsUnderHeaderClasses = "sticky top-10 z-10 bg-(--theme-app-bg)";
|
|
171
|
+
/** Action groups left, secondary actions right (collapsing into a `…` menu). */
|
|
172
|
+
function ActionToolbar({ groups, right = [], sticky = false }) {
|
|
173
|
+
const visibleGroups = groups.map((group) => group.filter((a) => !a.hidden)).filter((group) => group.length > 0);
|
|
174
|
+
const visibleRight = right.filter((a) => !a.hidden);
|
|
175
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
176
|
+
className: cx("flex items-center gap-2.5", sticky && cx("sticky top-10 z-10 bg-(--theme-app-bg)", "py-1.5")),
|
|
177
|
+
children: [visibleGroups.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
178
|
+
className: "flex items-center gap-2.5 shrink-0",
|
|
179
|
+
children: visibleGroups.map((group, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [i > 0 && /* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-(--theme-border)" }), /* @__PURE__ */ jsx("div", {
|
|
180
|
+
className: "flex items-center gap-1",
|
|
181
|
+
children: group.map((item) => /* @__PURE__ */ jsx(ToolbarItemView, { item }, item.key))
|
|
182
|
+
})] }, group[0]?.key ?? i))
|
|
183
|
+
}), visibleRight.length > 0 && /* @__PURE__ */ jsx(CollapsibleRight, { items: visibleRight })]
|
|
319
184
|
});
|
|
320
185
|
}
|
|
321
186
|
//#endregion
|
|
@@ -464,6 +329,135 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
|
464
329
|
}
|
|
465
330
|
ListActionsHeader.isTableHeader = true;
|
|
466
331
|
//#endregion
|
|
332
|
+
//#region src/list/ListPage.tsx
|
|
333
|
+
/** Negative offsets (admin/org) cancel the shell's pt-4 so rows don't peek through the gap above the pinned header. */
|
|
334
|
+
var SECTION_STICKY_TOP = {
|
|
335
|
+
main: "top-0",
|
|
336
|
+
kubernetes: "top-0",
|
|
337
|
+
admin: "-top-4",
|
|
338
|
+
org: "-top-4"
|
|
339
|
+
};
|
|
340
|
+
/** Whether the shell adds pt-4 padding that the edge-to-edge list must cancel with a negative margin. */
|
|
341
|
+
var SECTION_SHELL_PADDED = {
|
|
342
|
+
main: false,
|
|
343
|
+
kubernetes: false,
|
|
344
|
+
admin: true,
|
|
345
|
+
org: true
|
|
346
|
+
};
|
|
347
|
+
/** Defaults mean rows outside a ListView fully show actions (no view = show everything). */
|
|
348
|
+
var RowActionsContext = createContext({
|
|
349
|
+
show: true,
|
|
350
|
+
always: false,
|
|
351
|
+
columnClasses: []
|
|
352
|
+
});
|
|
353
|
+
function useRowActions(view) {
|
|
354
|
+
return useMemo(() => ({
|
|
355
|
+
show: view?.showActions ?? true,
|
|
356
|
+
always: view?.alwaysShowActions ?? false,
|
|
357
|
+
columnClasses: view?.columnClasses ?? []
|
|
358
|
+
}), [
|
|
359
|
+
view?.showActions,
|
|
360
|
+
view?.alwaysShowActions,
|
|
361
|
+
view?.columnClasses
|
|
362
|
+
]);
|
|
363
|
+
}
|
|
364
|
+
function ListRowActionsProvider({ view, children }) {
|
|
365
|
+
const rowActions = useRowActions(view);
|
|
366
|
+
return /* @__PURE__ */ jsx(RowActionsContext.Provider, {
|
|
367
|
+
value: rowActions,
|
|
368
|
+
children
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
function ListPage({ section = "main", shellPadded, breadcrumbs, title, titleAction, actions, toolbar, view, children }) {
|
|
372
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
373
|
+
className: cx("flex h-full min-h-0 flex-col", (shellPadded ?? SECTION_SHELL_PADDED[section]) && "-m-4"),
|
|
374
|
+
children: [/* @__PURE__ */ jsx(PageHeader, {
|
|
375
|
+
stickyTopClassName: SECTION_STICKY_TOP[section],
|
|
376
|
+
breadcrumbs,
|
|
377
|
+
title,
|
|
378
|
+
titleAction,
|
|
379
|
+
actions,
|
|
380
|
+
toolbar
|
|
381
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
382
|
+
className: "@container min-h-0 flex-1 overflow-auto",
|
|
383
|
+
children: /* @__PURE__ */ jsx(ListRowActionsProvider, {
|
|
384
|
+
view,
|
|
385
|
+
children
|
|
386
|
+
})
|
|
387
|
+
})]
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function ListRow({ href, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
|
|
391
|
+
const { active: menuActive, openMenu: openRowMenu } = useRowMenuActive(openMenu);
|
|
392
|
+
const { show: showActions, always: alwaysShowActions, columnClasses } = useContext(RowActionsContext);
|
|
393
|
+
const styledCells = Children.toArray(children).map((child, i) => {
|
|
394
|
+
const cls = columnClasses[i];
|
|
395
|
+
if (!cls || !isValidElement(child)) return child;
|
|
396
|
+
const el = child;
|
|
397
|
+
return cloneElement(el, { className: cx(el.props.className, cls) });
|
|
398
|
+
});
|
|
399
|
+
const handleRowClick = (e) => {
|
|
400
|
+
if (e.target.closest("a,button,input,label")) return;
|
|
401
|
+
if (selectionActive && onRowSelect) {
|
|
402
|
+
onRowSelect(e);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (href) goTo(href);
|
|
406
|
+
};
|
|
407
|
+
const pinnedLabels = new Set((pinnedActions ?? []).map((a) => a.label));
|
|
408
|
+
const hasOverflowItems = items.some((item) => item.kind !== "divider" && (item.kind === "submenu" || !pinnedLabels.has(item.label)));
|
|
409
|
+
return /* @__PURE__ */ jsxs("tr", {
|
|
410
|
+
className: cx("group", selected ? "bg-blue-500/5" : menuActive ? "theme-hover" : "hover:theme-hover", (href || selectionActive) && "cursor-pointer", className),
|
|
411
|
+
onClick: handleRowClick,
|
|
412
|
+
...rowContextMenuProps(openRowMenu, items),
|
|
413
|
+
children: [
|
|
414
|
+
leading,
|
|
415
|
+
styledCells,
|
|
416
|
+
showActions && /* @__PURE__ */ jsx(Table.Item, {
|
|
417
|
+
className: "relative py-2.5",
|
|
418
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
419
|
+
className: "absolute inset-y-0 right-0 flex items-center gap-0.5 pr-4",
|
|
420
|
+
children: [pinnedActions && pinnedActions.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
421
|
+
className: "hidden items-center gap-0.5 @[44rem]:flex",
|
|
422
|
+
children: pinnedActions.map((action) => /* @__PURE__ */ jsx("button", {
|
|
423
|
+
type: "button",
|
|
424
|
+
"aria-label": action.label,
|
|
425
|
+
"data-tooltip-id": "global-tooltip",
|
|
426
|
+
"data-tooltip-content": action.label,
|
|
427
|
+
"data-tooltip-place": "bottom",
|
|
428
|
+
disabled: action.disabled,
|
|
429
|
+
onClick: (e) => {
|
|
430
|
+
e.stopPropagation();
|
|
431
|
+
action.onSelect();
|
|
432
|
+
},
|
|
433
|
+
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) disabled:cursor-not-allowed disabled:opacity-20 [&>svg]:h-4 [&>svg]:w-4", alwaysShowActions || menuActive ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100"),
|
|
434
|
+
children: action.icon
|
|
435
|
+
}, action.key))
|
|
436
|
+
}), /* @__PURE__ */ jsx(MoreButton, {
|
|
437
|
+
active: menuActive || alwaysShowActions,
|
|
438
|
+
onOpen: (x, y) => openRowMenu(x, y, items),
|
|
439
|
+
className: hasOverflowItems ? void 0 : "@[44rem]:hidden"
|
|
440
|
+
})]
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
]
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/** Name column min-width is by role, not position, so a leading checkbox doesn't shift it. */
|
|
447
|
+
function ListColumns({ view }) {
|
|
448
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [view.visibleColumns.map((col, i) => /* @__PURE__ */ jsx(Table.Header, {
|
|
449
|
+
caps: false,
|
|
450
|
+
className: cx(col.headerClassName, view.columnClasses[i]),
|
|
451
|
+
style: col.alwaysVisible ? { minWidth: 200 } : void 0,
|
|
452
|
+
children: col.label
|
|
453
|
+
}, col.key)), /* @__PURE__ */ jsx(ListActionsHeader, { view })] });
|
|
454
|
+
}
|
|
455
|
+
ListColumns.isTableHeader = true;
|
|
456
|
+
/** Stable `goTo` for whole-row navigation (`rowNavProps`, `ListRow`). */
|
|
457
|
+
function useListNavigate() {
|
|
458
|
+
return useNavigation().goTo;
|
|
459
|
+
}
|
|
460
|
+
//#endregion
|
|
467
461
|
//#region src/list/listView.tsx
|
|
468
462
|
var PRIORITY_SHOW_CLASS = {
|
|
469
463
|
low: "hidden @[52rem]:table-cell",
|
|
@@ -763,7 +757,7 @@ function AnchoredPopover({ icon, label, active, shortcut, panelClassName, childr
|
|
|
763
757
|
}), document.querySelector(".ds-root") ?? document.body)] });
|
|
764
758
|
}
|
|
765
759
|
/** Small on/off switch for the Display menu's boolean options. */
|
|
766
|
-
function Switch({ checked, onChange, label }) {
|
|
760
|
+
function Switch$1({ checked, onChange, label }) {
|
|
767
761
|
return /* @__PURE__ */ jsx("button", {
|
|
768
762
|
type: "button",
|
|
769
763
|
role: "switch",
|
|
@@ -813,7 +807,7 @@ function ListDisplayMenu({ view, label }) {
|
|
|
813
807
|
children: [/* @__PURE__ */ jsx("span", {
|
|
814
808
|
className: "text-[13px] text-(--theme-app)",
|
|
815
809
|
children: t.columnHeaders
|
|
816
|
-
}), /* @__PURE__ */ jsx(Switch, {
|
|
810
|
+
}), /* @__PURE__ */ jsx(Switch$1, {
|
|
817
811
|
checked: view.showColumnHeaders,
|
|
818
812
|
onChange: view.toggleColumnHeaders,
|
|
819
813
|
label: t.showColumnHeaders
|
|
@@ -824,7 +818,7 @@ function ListDisplayMenu({ view, label }) {
|
|
|
824
818
|
children: [/* @__PURE__ */ jsx("span", {
|
|
825
819
|
className: "text-[13px] text-(--theme-app)",
|
|
826
820
|
children: t.showActions
|
|
827
|
-
}), /* @__PURE__ */ jsx(Switch, {
|
|
821
|
+
}), /* @__PURE__ */ jsx(Switch$1, {
|
|
828
822
|
checked: view.showActions,
|
|
829
823
|
onChange: view.toggleShowActions,
|
|
830
824
|
label: t.showRowActions
|
|
@@ -835,7 +829,7 @@ function ListDisplayMenu({ view, label }) {
|
|
|
835
829
|
children: [/* @__PURE__ */ jsx("span", {
|
|
836
830
|
className: "text-[13px] text-(--theme-muted-text-color)",
|
|
837
831
|
children: t.alwaysShowActions
|
|
838
|
-
}), /* @__PURE__ */ jsx(Switch, {
|
|
832
|
+
}), /* @__PURE__ */ jsx(Switch$1, {
|
|
839
833
|
checked: view.alwaysShowActions,
|
|
840
834
|
onChange: view.toggleAlwaysShowActions,
|
|
841
835
|
label: t.alwaysShowRowActions
|
|
@@ -1256,4 +1250,4 @@ function HoverCardSurface({ x, y, widthClassName, relayoutKey, onKeepOpen, onLea
|
|
|
1256
1250
|
}), document.querySelector(".ds-root") ?? document.body);
|
|
1257
1251
|
}
|
|
1258
1252
|
//#endregion
|
|
1259
|
-
export {
|
|
1253
|
+
export { ToolbarButton as A, NAME_MIN_WIDTH_PX as C, listTableFixedProps as D, actionsColumnWidth as E, stickyTabsUnderHeaderClasses as M, stickyToolbarClasses as N, listTableProps as O, ListSkeleton as S, RowSelectCheckbox as T, ListRowActionsProvider as _, ListSearchControl as a, ListActionsHeader as b, ListFilterMenu as c, DEFAULT_ORDER as d, FAVORITE_ORDER as f, ListRow as g, ListPage as h, ListCount as i, stickyTabsClasses as j, ActionToolbar as k, listControlButtonClasses as l, ListColumns as m, useHoverCard as n, useListSearch as o, useListView as p, ListPager as r, ListDisplayMenu as s, HoverCardSurface as t, isTextEntryContext as u, useListNavigate as v, NameCell as w, ListError as x, GroupRow as y };
|