@parallelworks/ui 0.5.1 → 0.5.3

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.
@@ -1,5 +1,5 @@
1
1
  import { t as useCssIsDark } from "./useCssIsDark-DHr05dG2.js";
2
- import { n as defineEditorThemes, r as getThemeName, t as setupMonacoWorkers } from "./editor-DbDUZn8w.js";
2
+ import { n as defineEditorThemes, r as getThemeName, t as setupMonacoWorkers } from "./editor-4ZuZruLz.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { useEffect, useRef } from "react";
5
5
  import * as monaco from "monaco-editor";
@@ -1,10 +1,11 @@
1
1
  import { AlertIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ClipboardIcon, CopyIcon, FavoriteIcon, FavoriteOutlineIcon, HiddenFalseIcon, HiddenTrueIcon, InfoIcon, TooltipIcon } from "../icons.js";
2
- import { c as useStrings, i as useNotify, n as useLink } from "./Provider-wC9G01Ou.js";
2
+ import { c as useStrings, i as useNotify } from "./Provider-BIL5347a.js";
3
3
  import { n as TOOLTIP_ID } from "./Tooltip-WgbiC_nd.js";
4
4
  import { n as modalPanelClasses, t as BareModal } from "./BareModal-DBa84JZO.js";
5
+ import { S as AddMenu } from "./PageHeader-CSo3LVId.js";
5
6
  import cx from "classnames";
6
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import { Fragment as Fragment$1, Suspense, lazy, useCallback, useEffect, useRef, useState } from "react";
8
+ import { Suspense, lazy, useCallback, useEffect, useRef, useState } from "react";
8
9
  import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
9
10
  //#region src/components/Callout.tsx
10
11
  function CalloutIcon({ type }) {
@@ -171,32 +172,6 @@ function ConfirmModal({ open, onClose, title, description, children, confirmLabe
171
172
  });
172
173
  }
173
174
  //#endregion
174
- //#region src/components/AddMenu.tsx
175
- 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";
176
- function AddMenu({ items, label, buttonClassName, zClassName = "z-50", children }) {
177
- const Link = useLink();
178
- return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuButton, {
179
- "aria-label": label,
180
- title: label,
181
- className: buttonClassName,
182
- children
183
- }), /* @__PURE__ */ jsx(MenuItems, {
184
- anchor: "bottom start",
185
- 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),
186
- children: items.map((item) => /* @__PURE__ */ jsxs(Fragment$1, { children: [item.separatorAbove && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-(--theme-border)" }), /* @__PURE__ */ jsx(MenuItem, { children: item.to && !item.disabled ? /* @__PURE__ */ jsxs(Link, {
187
- to: item.to,
188
- className: addMenuItemClasses,
189
- children: [item.icon, item.label]
190
- }) : /* @__PURE__ */ jsxs("button", {
191
- type: "button",
192
- onClick: item.onSelect,
193
- disabled: item.disabled,
194
- className: cx(addMenuItemClasses, item.disabled && "opacity-50 cursor-not-allowed"),
195
- children: [item.icon, item.label]
196
- }) })] }, item.label))
197
- })] });
198
- }
199
- //#endregion
200
175
  //#region src/components/CreateModal.tsx
201
176
  /** Small info icon that surfaces field help via the global tooltip. */
202
177
  function FieldHelp({ tooltip }) {
@@ -592,4 +567,4 @@ function CreateModalSelect({ label, icon, value, options, onChange, disabled = f
592
567
  })] }) });
593
568
  }
594
569
  //#endregion
595
- export { CreateModalSwitch as a, ConfirmModal as c, primaryButtonClasses as d, Markdown as f, Callout as h, CreateModalSelect as i, dangerButtonClasses as l, CopyToClipboard as m, CreateModalAutocompleteField as n, CreateModalTextarea as o, CopyCodeBlock as p, CreateModalField as r, AddMenu as s, CreateModal as t, ghostButtonClasses as u };
570
+ export { CreateModalSwitch as a, dangerButtonClasses as c, Markdown as d, CopyCodeBlock as f, CreateModalSelect as i, ghostButtonClasses as l, Callout as m, CreateModalAutocompleteField as n, CreateModalTextarea as o, CopyToClipboard as p, CreateModalField as r, ConfirmModal as s, CreateModal as t, primaryButtonClasses as u };
@@ -1,6 +1,6 @@
1
- import { l as useWorkflowJsonResolver } from "./Provider-wC9G01Ou.js";
1
+ import { l as useWorkflowJsonResolver } from "./Provider-BIL5347a.js";
2
2
  import { t as useCssIsDark } from "./useCssIsDark-DHr05dG2.js";
3
- import { n as defineEditorThemes, r as getThemeName, t as setupMonacoWorkers } from "./editor-DbDUZn8w.js";
3
+ import { n as defineEditorThemes, r as getThemeName, t as setupMonacoWorkers } from "./editor-4ZuZruLz.js";
4
4
  import cx from "classnames";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { useEffect, useRef } from "react";
@@ -0,0 +1,571 @@
1
+ import { AddIcon, CheckIcon, ChevronRightIcon, ClipboardIcon, CopyIcon, EditIcon, IdCardIcon, KeyIcon, LinkIcon, MailIcon, MoreIcon, UserIcon } from "../icons.js";
2
+ import { c as useStrings, i as useNotify, n as useLink, s as useSlots } from "./Provider-BIL5347a.js";
3
+ import { n as TOOLTIP_ID } from "./Tooltip-WgbiC_nd.js";
4
+ import cx from "classnames";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import React, { Fragment as Fragment$1, createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
7
+ import { createPortal } from "react-dom";
8
+ import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
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 AddMenu({ items, label, buttonClassName, zClassName = "z-50", children }) {
12
+ const Link = useLink();
13
+ return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuButton, {
14
+ "aria-label": label,
15
+ title: label,
16
+ className: buttonClassName,
17
+ children
18
+ }), /* @__PURE__ */ jsx(MenuItems, {
19
+ anchor: "bottom start",
20
+ 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),
21
+ children: items.map((item) => /* @__PURE__ */ jsxs(Fragment$1, { children: [item.separatorAbove && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-(--theme-border)" }), /* @__PURE__ */ jsx(MenuItem, { children: item.to && !item.disabled ? /* @__PURE__ */ jsxs(Link, {
22
+ to: item.to,
23
+ className: addMenuItemClasses,
24
+ children: [item.icon, item.label]
25
+ }) : /* @__PURE__ */ jsxs("button", {
26
+ type: "button",
27
+ onClick: item.onSelect,
28
+ disabled: item.disabled,
29
+ className: cx(addMenuItemClasses, item.disabled && "opacity-50 cursor-not-allowed"),
30
+ children: [item.icon, item.label]
31
+ }) })] }, item.label))
32
+ })] });
33
+ }
34
+ //#endregion
35
+ //#region src/components/Breadcrumbs.tsx
36
+ var BreadcrumbContext = createContext({
37
+ breadcrumbs: [],
38
+ setBreadcrumbs: () => {},
39
+ rightsideBreadcrumb: null,
40
+ setRightsideBreadcrumb: () => {},
41
+ hidden: false,
42
+ setHidden: () => {},
43
+ titleActionSlot: null,
44
+ setTitleActionSlot: () => {},
45
+ rightActionSlot: null,
46
+ setRightActionSlot: () => {}
47
+ });
48
+ var useBreadcrumb = () => useContext(BreadcrumbContext);
49
+ function BreadcrumbProvider({ children }) {
50
+ const [breadcrumbs, setBreadcrumbs] = React.useState([]);
51
+ const [rightsideBreadcrumb, setRightsideBreadcrumb] = React.useState(null);
52
+ const [hidden, setHidden] = React.useState(false);
53
+ const [titleActionSlot, setTitleActionSlot] = React.useState(null);
54
+ const [rightActionSlot, setRightActionSlot] = React.useState(null);
55
+ return /* @__PURE__ */ jsx(BreadcrumbContext.Provider, {
56
+ value: {
57
+ breadcrumbs,
58
+ setBreadcrumbs,
59
+ rightsideBreadcrumb,
60
+ setRightsideBreadcrumb,
61
+ hidden,
62
+ setHidden,
63
+ titleActionSlot,
64
+ setTitleActionSlot,
65
+ rightActionSlot,
66
+ setRightActionSlot
67
+ },
68
+ children
69
+ });
70
+ }
71
+ function useSetBreadcrumbs(getBreadcrumbs) {
72
+ const { setBreadcrumbs } = useBreadcrumb();
73
+ useLayoutEffect(() => {
74
+ setBreadcrumbs(typeof getBreadcrumbs === "function" ? getBreadcrumbs() : getBreadcrumbs);
75
+ }, [getBreadcrumbs, setBreadcrumbs]);
76
+ }
77
+ var EMPTY_BREADCRUMBS = [];
78
+ /** For pages that render their own header instead of the breadcrumb strip. */
79
+ function useClearBreadcrumbs() {
80
+ useSetBreadcrumbs(EMPTY_BREADCRUMBS);
81
+ }
82
+ function useHideBreadcrumbs(hidden) {
83
+ const { setHidden } = useBreadcrumb();
84
+ useEffect(() => {
85
+ setHidden(hidden);
86
+ return () => setHidden(false);
87
+ }, [hidden, setHidden]);
88
+ }
89
+ //#endregion
90
+ //#region src/list/RowContextMenu.tsx
91
+ /** Converts a single row action to a menu item: a `to` makes it a link, otherwise an action. */
92
+ function toRowMenuItem(action) {
93
+ if (action.to) return {
94
+ kind: "link",
95
+ label: action.label,
96
+ icon: action.icon,
97
+ to: action.to,
98
+ destructive: action.destructive
99
+ };
100
+ return {
101
+ kind: "action",
102
+ label: action.label,
103
+ icon: action.icon,
104
+ onSelect: action.onSelect ?? (() => {}),
105
+ disabled: action.disabled,
106
+ destructive: action.destructive
107
+ };
108
+ }
109
+ /** Bridges a toolbar action (icon component, `onClick`/`href`) onto the shared
110
+ * `RowAction` shape. Typed structurally so any toolbar action shape matching
111
+ * these fields is assignable. */
112
+ function toolbarActionToRowAction(action) {
113
+ const Icon = action.icon;
114
+ return {
115
+ key: action.key,
116
+ label: action.label,
117
+ icon: /* @__PURE__ */ jsx(Icon, {}),
118
+ onSelect: action.onClick,
119
+ to: action.href,
120
+ disabled: action.disabled,
121
+ destructive: action.key === "delete" || action.key === "destroy"
122
+ };
123
+ }
124
+ /** Assembles a row's context menu in the shared order: leading link(s) → middle
125
+ * actions → extra items → Copy submenu → trailing (destructive) actions last. */
126
+ function assembleRowMenu({ lead = [], actions, exclude, order, trailing = ["delete"], extra = [], copy }) {
127
+ const trailingSet = new Set(trailing);
128
+ const excludeSet = new Set(exclude);
129
+ let middle = actions.filter((a) => !trailingSet.has(a.key) && !excludeSet.has(a.key));
130
+ if (order) {
131
+ const byKey = new Map(middle.map((a) => [a.key, a]));
132
+ middle = order.map((key) => byKey.get(key)).filter((a) => a !== void 0);
133
+ }
134
+ const trailingItems = trailing.map((key) => actions.find((a) => a.key === key)).filter((a) => a !== void 0);
135
+ return [
136
+ ...lead,
137
+ ...middle.map(toRowMenuItem),
138
+ ...extra,
139
+ ...copy ? [copy] : [],
140
+ ...trailingItems.map(toRowMenuItem)
141
+ ];
142
+ }
143
+ function useRowMenu() {
144
+ const [menu, setMenu] = useState(null);
145
+ const onCloseRef = useRef(void 0);
146
+ return {
147
+ openMenu: useCallback((x, y, items, onClose) => {
148
+ if (items.length > 0) {
149
+ onCloseRef.current?.();
150
+ onCloseRef.current = onClose;
151
+ setMenu({
152
+ x,
153
+ y,
154
+ items
155
+ });
156
+ }
157
+ }, []),
158
+ contextMenu: /* @__PURE__ */ jsx(RowContextMenu, {
159
+ state: menu,
160
+ onClose: useCallback(() => {
161
+ onCloseRef.current?.();
162
+ onCloseRef.current = void 0;
163
+ setMenu(null);
164
+ }, [])
165
+ })
166
+ };
167
+ }
168
+ /** The full-screen menu overlay drops CSS :hover on the triggering row; wrap openMenu here to substitute a JS-driven `active` highlight. */
169
+ function useRowMenuActive(openMenu) {
170
+ const [active, setActive] = useState(false);
171
+ return {
172
+ active,
173
+ openMenu: useCallback((x, y, items) => {
174
+ setActive(true);
175
+ openMenu(x, y, items, () => setActive(false));
176
+ }, [openMenu])
177
+ };
178
+ }
179
+ function rowContextMenuProps(openMenu, items) {
180
+ return { onContextMenu: (e) => {
181
+ e.preventDefault();
182
+ if (items.length > 0) e.stopPropagation();
183
+ openMenu(e.clientX, e.clientY, items);
184
+ } };
185
+ }
186
+ function RowContextMenu({ state, onClose }) {
187
+ const ref = useRef(null);
188
+ const [pos, setPos] = useState(null);
189
+ useLayoutEffect(() => {
190
+ if (!state || !ref.current) {
191
+ setPos(null);
192
+ return;
193
+ }
194
+ const { width, height } = ref.current.getBoundingClientRect();
195
+ const pad = 8;
196
+ const top = height > window.innerHeight - pad - state.y && state.y - height - pad >= 0 ? state.y - height : Math.min(state.y, window.innerHeight - height - pad);
197
+ setPos({
198
+ left: Math.max(pad, Math.min(state.x, window.innerWidth - width - pad)),
199
+ top: Math.max(pad, top)
200
+ });
201
+ }, [state]);
202
+ useEffect(() => {
203
+ if (!state) return;
204
+ const close = () => onClose();
205
+ const onKey = (e) => {
206
+ if (e.key === "Escape") onClose();
207
+ };
208
+ window.addEventListener("scroll", close, true);
209
+ window.addEventListener("resize", close);
210
+ window.addEventListener("keydown", onKey);
211
+ return () => {
212
+ window.removeEventListener("scroll", close, true);
213
+ window.removeEventListener("resize", close);
214
+ window.removeEventListener("keydown", onKey);
215
+ };
216
+ }, [state, onClose]);
217
+ if (!state) return null;
218
+ const side = (pos?.left ?? state.x) > window.innerWidth * .6 ? "left" : "right";
219
+ return createPortal(/* @__PURE__ */ jsx("div", {
220
+ className: "fixed inset-0 z-50",
221
+ onClick: onClose,
222
+ onContextMenu: (e) => {
223
+ e.preventDefault();
224
+ if (ref.current?.contains(e.target)) {
225
+ onClose();
226
+ return;
227
+ }
228
+ const { clientX, clientY } = e;
229
+ const overlay = e.currentTarget;
230
+ overlay.style.pointerEvents = "none";
231
+ const under = document.elementFromPoint(clientX, clientY);
232
+ overlay.style.pointerEvents = "";
233
+ onClose();
234
+ under?.dispatchEvent(new MouseEvent("contextmenu", {
235
+ bubbles: true,
236
+ cancelable: true,
237
+ clientX,
238
+ clientY
239
+ }));
240
+ },
241
+ children: /* @__PURE__ */ jsx("div", {
242
+ ref,
243
+ role: "menu",
244
+ className: "absolute min-w-44 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) py-1 shadow-lg backdrop-blur-xl",
245
+ style: {
246
+ left: pos?.left ?? state.x,
247
+ top: pos?.top ?? state.y,
248
+ visibility: pos ? "visible" : "hidden"
249
+ },
250
+ onClick: (e) => e.stopPropagation(),
251
+ children: /* @__PURE__ */ jsx(MenuItemList, {
252
+ items: state.items,
253
+ onClose,
254
+ side
255
+ })
256
+ })
257
+ }), document.body);
258
+ }
259
+ 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";
260
+ function MenuItemList({ items, onClose, side }) {
261
+ return items.map((item, i) => item.kind === "divider" ? /* @__PURE__ */ jsx("div", {
262
+ "aria-hidden": "true",
263
+ className: "my-1 h-px bg-(--theme-border)"
264
+ }, `divider-${i}`) : /* @__PURE__ */ jsx(MenuRow, {
265
+ item,
266
+ onClose,
267
+ side
268
+ }, `${item.label}-${i}`));
269
+ }
270
+ function MenuRow({ item, onClose, side }) {
271
+ const Link = useLink();
272
+ const notify = useNotify();
273
+ const { list: t } = useStrings();
274
+ const [openSub, setOpenSub] = useState(false);
275
+ const closeTimer = useRef(void 0);
276
+ if (item.kind === "submenu") {
277
+ const open = () => {
278
+ clearTimeout(closeTimer.current);
279
+ setOpenSub(true);
280
+ };
281
+ const close = () => {
282
+ closeTimer.current = setTimeout(() => setOpenSub(false), 160);
283
+ };
284
+ return /* @__PURE__ */ jsxs("div", {
285
+ className: "relative",
286
+ onMouseEnter: open,
287
+ onMouseLeave: close,
288
+ children: [/* @__PURE__ */ jsxs("div", {
289
+ className: cx(MENU_ITEM_CLASSES, "justify-between text-(--theme-app)"),
290
+ children: [/* @__PURE__ */ jsxs("span", {
291
+ className: "flex items-center gap-2.5",
292
+ children: [item.icon, item.label]
293
+ }), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3 w-3 shrink-0 opacity-60" })]
294
+ }), openSub && /* @__PURE__ */ jsx("div", {
295
+ 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"),
296
+ children: /* @__PURE__ */ jsx(MenuItemList, {
297
+ items: item.items,
298
+ onClose,
299
+ side
300
+ })
301
+ })]
302
+ });
303
+ }
304
+ if (item.kind === "link") return /* @__PURE__ */ jsxs(Link, {
305
+ to: item.to,
306
+ onClick: onClose,
307
+ className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)"),
308
+ children: [item.icon, item.label]
309
+ });
310
+ return /* @__PURE__ */ jsxs("button", {
311
+ type: "button",
312
+ disabled: item.disabled,
313
+ onClick: () => {
314
+ if (item.copy) {
315
+ const { text, label } = item.copy;
316
+ navigator.clipboard?.writeText(text).then(() => notify.success(t.copied(label)), () => notify.error(t.couldntCopy(label)));
317
+ }
318
+ item.onSelect?.();
319
+ onClose();
320
+ },
321
+ className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)", item.disabled && "opacity-40 cursor-not-allowed hover:bg-transparent"),
322
+ children: [
323
+ item.icon,
324
+ item.label,
325
+ item.selected && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto opacity-80" })
326
+ ]
327
+ });
328
+ }
329
+ /** Builds the Copy submenu entries for whichever fields a row has, in stable
330
+ * order. The menu itself performs the copy and notifies; `t` is an optional
331
+ * host translator for the field labels (falls back to the provider defaults'
332
+ * English). */
333
+ function copySubmenu({ name, nameLabel, email, username, uid, id, url, extra, t }) {
334
+ const items = [
335
+ {
336
+ label: nameLabel ?? (t ? t("rowContextMenu.labelName") : "name"),
337
+ value: name,
338
+ icon: /* @__PURE__ */ jsx(CopyIcon, {})
339
+ },
340
+ {
341
+ label: t ? t("rowContextMenu.labelEmail") : "email",
342
+ value: email,
343
+ icon: /* @__PURE__ */ jsx(MailIcon, {})
344
+ },
345
+ {
346
+ label: t ? t("rowContextMenu.labelUsername") : "username",
347
+ value: username,
348
+ icon: /* @__PURE__ */ jsx(UserIcon, {})
349
+ },
350
+ {
351
+ label: t ? t("rowContextMenu.labelUid") : "UID",
352
+ value: uid === null || uid === void 0 ? null : String(uid),
353
+ icon: /* @__PURE__ */ jsx(KeyIcon, {})
354
+ },
355
+ {
356
+ label: t ? t("rowContextMenu.labelId") : "ID",
357
+ value: id,
358
+ icon: /* @__PURE__ */ jsx(IdCardIcon, {})
359
+ },
360
+ {
361
+ label: t ? t("rowContextMenu.labelUrl") : "URL",
362
+ value: url,
363
+ icon: /* @__PURE__ */ jsx(LinkIcon, {})
364
+ },
365
+ ...(extra ?? []).map((e) => ({
366
+ label: e.label,
367
+ value: e.value,
368
+ icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
369
+ }))
370
+ ].filter((f) => f.value).map((f) => ({
371
+ kind: "action",
372
+ label: t ? t("rowContextMenu.copy", { label: f.label }) : `Copy ${f.label}`,
373
+ icon: f.icon,
374
+ copy: {
375
+ text: f.value,
376
+ label: f.label
377
+ }
378
+ }));
379
+ return {
380
+ kind: "submenu",
381
+ label: t ? t("common.copy") : "Copy",
382
+ icon: /* @__PURE__ */ jsx(ClipboardIcon, {}),
383
+ items
384
+ };
385
+ }
386
+ /** Stays visible while active (menu open) so it doesn't vanish behind the overlay. */
387
+ function MoreButton({ onOpen, active, className }) {
388
+ const { list: t } = useStrings();
389
+ return /* @__PURE__ */ jsx("button", {
390
+ type: "button",
391
+ "aria-label": t.moreActions,
392
+ onClick: (e) => {
393
+ e.stopPropagation();
394
+ const r = e.currentTarget.getBoundingClientRect();
395
+ onOpen(r.right, r.bottom);
396
+ },
397
+ 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),
398
+ children: /* @__PURE__ */ jsx(MoreIcon, { className: "h-4 w-4" })
399
+ });
400
+ }
401
+ //#endregion
402
+ //#region src/components/PageHeader.tsx
403
+ 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";
404
+ 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";
405
+ /** With menu, the plus opens a chooser; otherwise navigates to or calls the
406
+ * single action. `word` is the visible verb; `label` stays the full action for
407
+ * the tooltip and screen readers. */
408
+ function HeaderAddButton({ to, onClick, label, word = "add", menu }) {
409
+ const { common } = useStrings();
410
+ const Link = useLink();
411
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AddIcon, { className: "w-3 h-3" }), /* @__PURE__ */ jsx("span", { children: word === "create" ? common.create : common.add })] });
412
+ if (menu) return /* @__PURE__ */ jsx(AddMenu, {
413
+ items: menu,
414
+ label,
415
+ buttonClassName: headerAddButtonClasses,
416
+ children: content
417
+ });
418
+ if (to) return /* @__PURE__ */ jsx(Link, {
419
+ to,
420
+ "aria-label": label,
421
+ title: label,
422
+ className: headerAddButtonClasses,
423
+ children: content
424
+ });
425
+ return /* @__PURE__ */ jsx("button", {
426
+ type: "button",
427
+ onClick,
428
+ "aria-label": label,
429
+ title: label,
430
+ className: headerAddButtonClasses,
431
+ children: content
432
+ });
433
+ }
434
+ function HeaderActionMenu({ items, label = "Actions" }) {
435
+ if (items.length === 0) return null;
436
+ return /* @__PURE__ */ jsx(AddMenu, {
437
+ items,
438
+ label,
439
+ buttonClassName: headerActionButtonClasses,
440
+ children: /* @__PURE__ */ jsx(MoreIcon, { className: "w-3.5 h-3.5" })
441
+ });
442
+ }
443
+ /** The header "…" trigger for a RowMenuItem menu — same rendering (submenus,
444
+ * destructive styling) as the list pages' right-click context menus. */
445
+ function HeaderRowMenu({ items, label = "Actions" }) {
446
+ const { openMenu, contextMenu } = useRowMenu();
447
+ if (items.length === 0) return null;
448
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
449
+ type: "button",
450
+ "aria-label": label,
451
+ title: label,
452
+ className: headerActionButtonClasses,
453
+ onClick: (e) => {
454
+ const r = e.currentTarget.getBoundingClientRect();
455
+ openMenu(r.left, r.bottom + 4, items);
456
+ },
457
+ children: /* @__PURE__ */ jsx(MoreIcon, { className: "w-3.5 h-3.5" })
458
+ }), contextMenu] });
459
+ }
460
+ function HeaderEditButton({ to, onClick, label = "Edit", disabled, tooltip }) {
461
+ const Link = useLink();
462
+ const tooltipProps = tooltip ? {
463
+ "data-tooltip-id": TOOLTIP_ID,
464
+ "data-tooltip-content": tooltip
465
+ } : {};
466
+ if (to && !disabled) return /* @__PURE__ */ jsx(Link, {
467
+ to,
468
+ "aria-label": label,
469
+ ...tooltip ? {} : { title: label },
470
+ className: headerActionButtonClasses,
471
+ ...tooltipProps,
472
+ children: /* @__PURE__ */ jsx(EditIcon, { className: "w-3 h-3" })
473
+ });
474
+ return /* @__PURE__ */ jsx("button", {
475
+ type: "button",
476
+ onClick,
477
+ disabled,
478
+ "aria-label": label,
479
+ title: tooltip ? void 0 : label,
480
+ className: cx(headerActionButtonClasses, disabled && "opacity-50 cursor-not-allowed hover:bg-transparent"),
481
+ ...tooltipProps,
482
+ children: /* @__PURE__ */ jsx(EditIcon, { className: "w-3 h-3" })
483
+ });
484
+ }
485
+ /** Renders nothing when the modern breadcrumb strip isn't mounted (classic chrome or self-headered pages). */
486
+ function BreadcrumbsTitleAction({ children }) {
487
+ const { titleActionSlot } = useBreadcrumb();
488
+ if (!titleActionSlot) return null;
489
+ return createPortal(children, titleActionSlot);
490
+ }
491
+ function BreadcrumbsRightAction({ children }) {
492
+ const { rightActionSlot } = useBreadcrumb();
493
+ if (!rightActionSlot) return null;
494
+ return createPortal(children, rightActionSlot);
495
+ }
496
+ var breadcrumbsActionClasses = "flex items-center gap-1 link text-xs whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed";
497
+ function BreadcrumbsActionButton({ icon: Icon, label, to, onClick, disabled, tooltip }) {
498
+ const Link = useLink();
499
+ const tip = tooltip ? {
500
+ "data-tooltip-id": TOOLTIP_ID,
501
+ "data-tooltip-content": tooltip
502
+ } : {};
503
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }), label] });
504
+ if (to && !disabled) return /* @__PURE__ */ jsx(Link, {
505
+ to,
506
+ className: breadcrumbsActionClasses,
507
+ ...tip,
508
+ children: content
509
+ });
510
+ return /* @__PURE__ */ jsx("button", {
511
+ type: "button",
512
+ onClick,
513
+ disabled,
514
+ className: breadcrumbsActionClasses,
515
+ ...tip,
516
+ children: content
517
+ });
518
+ }
519
+ function PageHeader({ breadcrumbs, title, titleAction, actions, toolbar, className, sticky = true, stickyTopClassName = "top-0" }) {
520
+ const { setHidden } = useBreadcrumb();
521
+ const Link = useLink();
522
+ const { breadcrumbPin } = useSlots();
523
+ useLayoutEffect(() => {
524
+ setHidden(true);
525
+ return () => setHidden(false);
526
+ }, [setHidden]);
527
+ const crumbs = [...breadcrumbs ?? []];
528
+ const lastLabel = crumbs[crumbs.length - 1]?.label;
529
+ if (title !== null && title !== void 0 && title !== lastLabel) crumbs.push({ label: title });
530
+ const crumbRow = crumbs.length > 0 && /* @__PURE__ */ jsxs("div", {
531
+ className: "flex items-center gap-1.5 min-w-0",
532
+ children: [
533
+ /* @__PURE__ */ jsx("nav", {
534
+ "aria-label": "Breadcrumb",
535
+ className: "flex items-center gap-2 min-w-0 text-[13px]",
536
+ children: crumbs.map((crumb, idx) => {
537
+ if (idx === crumbs.length - 1) return /* @__PURE__ */ jsx("h1", {
538
+ className: "m-0 text-[13px] font-medium leading-none text-(--theme-app) truncate",
539
+ children: crumb.label
540
+ }, `${crumb.label}-${idx}`);
541
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [crumb.href ? /* @__PURE__ */ jsx(Link, {
542
+ to: crumb.href,
543
+ className: "text-(--theme-muted-text-color) hover:text-(--theme-app) transition-colors cursor-pointer whitespace-nowrap",
544
+ children: crumb.label
545
+ }) : /* @__PURE__ */ jsx("span", {
546
+ className: "text-(--theme-muted-text-color) whitespace-nowrap",
547
+ children: crumb.label
548
+ }), /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3 h-3 opacity-60 shrink-0 text-(--theme-muted-text-color)" })] }, `${crumb.label}-${idx}`);
549
+ })
550
+ }),
551
+ titleAction,
552
+ breadcrumbPin?.({ crumbs })
553
+ ]
554
+ });
555
+ const actionCluster = actions && /* @__PURE__ */ jsx("div", {
556
+ className: "flex items-center gap-1.5 shrink-0",
557
+ children: actions
558
+ });
559
+ return /* @__PURE__ */ jsxs("div", {
560
+ className: cx(sticky && cx("sticky z-20", stickyTopClassName), "w-full bg-(--theme-app-bg)", className),
561
+ children: [/* @__PURE__ */ jsxs("div", {
562
+ className: cx("flex items-center justify-between gap-6 px-4 h-11", crumbRow && "border-b border-(--theme-border)"),
563
+ children: [crumbRow || /* @__PURE__ */ jsx("div", {}), actionCluster]
564
+ }), toolbar && /* @__PURE__ */ jsx("div", {
565
+ className: "px-4",
566
+ children: toolbar
567
+ })]
568
+ });
569
+ }
570
+ //#endregion
571
+ export { AddMenu as S, BreadcrumbProvider as _, HeaderAddButton as a, useHideBreadcrumbs as b, PageHeader as c, copySubmenu as d, rowContextMenuProps as f, useRowMenuActive as g, useRowMenu as h, HeaderActionMenu as i, MoreButton as l, toolbarActionToRowAction as m, BreadcrumbsRightAction as n, HeaderEditButton as o, toRowMenuItem as p, BreadcrumbsTitleAction as r, HeaderRowMenu as s, BreadcrumbsActionButton as t, assembleRowMenu as u, useBreadcrumb as v, useSetBreadcrumbs as x, useClearBreadcrumbs as y };
@@ -365,6 +365,7 @@ var DEFAULTS = {
365
365
  }
366
366
  },
367
367
  navigation: {
368
+ goTo: (to) => window.location.assign(to),
368
369
  toWorkflow: () => {},
369
370
  toMarketItem: () => {},
370
371
  openExternal: (href) => window.open(href, "_blank")
@@ -1,5 +1,5 @@
1
1
  import { AngleDownIcon, AngleRightIcon, CaretDownIcon } from "../icons.js";
2
- import { c as useStrings } from "./Provider-wC9G01Ou.js";
2
+ import { c as useStrings } from "./Provider-BIL5347a.js";
3
3
  import { n as TOOLTIP_ID } from "./Tooltip-WgbiC_nd.js";
4
4
  import cx from "classnames";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -156,6 +156,11 @@ function ActiveWatcher({ active, onChange }) {
156
156
  function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", portalEl }) {
157
157
  const DEBOUNCE_MS = 500;
158
158
  const [query, setQuery] = useState("");
159
+ const [selectedIconWidth, setSelectedIconWidth] = useState(0);
160
+ const selectedIconRef = useCallback((node) => {
161
+ setSelectedIconWidth(node?.offsetWidth ?? 0);
162
+ }, []);
163
+ const selectedIcon = query === "" ? value?.icon : void 0;
159
164
  const [referenceElement, setReferenceElement] = useState(null);
160
165
  const [popperElement, setPopperElement] = useState(null);
161
166
  const [boundaryEl, setBoundaryEl] = useState(null);
@@ -313,6 +318,11 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
313
318
  active: activeOption,
314
319
  onChange: onActiveChange
315
320
  }),
321
+ selectedIcon && /* @__PURE__ */ jsx("span", {
322
+ ref: selectedIconRef,
323
+ className: "pointer-events-none absolute inset-y-0 left-3 z-10 flex items-center",
324
+ children: selectedIcon
325
+ }, value.label),
316
326
  /* @__PURE__ */ jsx(ComboboxInput, {
317
327
  id,
318
328
  "aria-label": ariaLabel || void 0,
@@ -322,6 +332,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
322
332
  onClick: () => {
323
333
  if (!open) buttonRef.current?.click();
324
334
  },
335
+ style: selectedIcon && selectedIconWidth > 0 ? { paddingLeft: selectedIconWidth + 18 } : void 0,
325
336
  className: cx("placeholder:text-xs bg-(--theme-input-bg) border-(--theme-border) text-(--theme-app) focus:border-(--theme-element) focus:outline-none focus:ring-1 focus:ring-(--theme-element) w-full h-full text-ellipsis pr-8", "disabled:bg-(--theme-input-disabled-bg) disabled:text-(--theme-input-disabled-text) disabled:cursor-not-allowed", textBoxClassName),
326
337
  autoComplete: "off",
327
338
  onChange: (event) => onQueryChange(event.target.value),