@parallelworks/ui 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/chunks/BareModal-DBa84JZO.js +80 -0
  2. package/dist/chunks/{CodePreviewEditor-CSPRILMp.js → CodePreviewEditor-CBtYRZi6.js} +2 -1
  3. package/dist/chunks/CreateModal-6zZZHxCI.js +595 -0
  4. package/dist/chunks/Loader-BXoXTZGc.js +47 -0
  5. package/dist/chunks/{Monaco-CC4ak1JG.js → Monaco-CvFXoW3r.js} +11 -5
  6. package/dist/chunks/{Provider-DvVvScTQ.js → Provider-jQCAN3NN.js} +73 -2
  7. package/dist/chunks/{SwitchToggle-2uRw8ZeJ.js → SwitchToggle-D0ud8cd5.js} +36 -29
  8. package/dist/chunks/{Table-C5z6qWjM.js → Table-ByziK93x.js} +1 -1
  9. package/dist/chunks/{editor-D55tumuZ.js → editor-CEXg6C8X.js} +5 -41
  10. package/dist/chunks/list-CvDWt0TC.js +1259 -0
  11. package/dist/chunks/useCssIsDark-DHr05dG2.js +38 -0
  12. package/dist/components/AddMenu.d.ts +17 -0
  13. package/dist/components/BareModal.d.ts +17 -0
  14. package/dist/components/Button.d.ts +18 -0
  15. package/dist/components/Card.d.ts +19 -0
  16. package/dist/components/ConfirmModal.d.ts +17 -0
  17. package/dist/components/CreateModal.d.ts +92 -0
  18. package/dist/components/Filter.d.ts +15 -0
  19. package/dist/components/FilterPill.d.ts +7 -0
  20. package/dist/components/IconButton.d.ts +17 -0
  21. package/dist/components/Input.d.ts +14 -0
  22. package/dist/components/LetterBadge.d.ts +6 -0
  23. package/dist/components/Loader.d.ts +2 -1
  24. package/dist/components/Pagination.d.ts +15 -0
  25. package/dist/components/Provider.d.ts +39 -12
  26. package/dist/components/SettingModeOption.d.ts +13 -0
  27. package/dist/components/SettingRow.d.ts +18 -0
  28. package/dist/components/SettingsCard.d.ts +24 -0
  29. package/dist/components/SettingsGroup.d.ts +8 -0
  30. package/dist/components/Sort.d.ts +9 -0
  31. package/dist/components/Toggle.d.ts +6 -0
  32. package/dist/components/dropdownUtils.d.ts +10 -0
  33. package/dist/components/ghostButton.d.ts +4 -0
  34. package/dist/components/inputClasses.d.ts +1 -0
  35. package/dist/editor/index.d.ts +0 -1
  36. package/dist/editor/index.js +2 -2
  37. package/dist/file-explorer/index.js +27 -28
  38. package/dist/form/index.js +4 -4
  39. package/dist/index.d.ts +21 -1
  40. package/dist/index.js +433 -8
  41. package/dist/list/HoverCard.d.ts +22 -0
  42. package/dist/list/ListPager.d.ts +7 -0
  43. package/dist/list/ListViewControls.d.ts +12 -0
  44. package/dist/list/index.d.ts +6 -0
  45. package/dist/list/index.js +2 -2
  46. package/dist/list/listSearch.d.ts +27 -0
  47. package/dist/list/listView.d.ts +129 -0
  48. package/dist/list/textEntry.d.ts +2 -0
  49. package/dist/logviewer/index.js +1 -1
  50. package/dist/styles/theme.css +21 -0
  51. package/dist/styles.css +1 -1
  52. package/dist/workflow/index.js +8 -8
  53. package/package.json +2 -6
  54. package/dist/chunks/Loader-DQiZ75fa.js +0 -25
  55. package/dist/chunks/Markdown-C5Re2ezs.js +0 -101
  56. package/dist/chunks/Modal-sOUEwebV.js +0 -121
  57. package/dist/chunks/list-7PyDF1tz.js +0 -465
  58. package/dist/components/Modal.d.ts +0 -26
  59. /package/dist/{editor → components}/useCssIsDark.d.ts +0 -0
@@ -0,0 +1,80 @@
1
+ import cx from "classnames";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useRef } from "react";
4
+ import { createPortal } from "react-dom";
5
+ //#region src/components/BareModal.tsx
6
+ /** Omit when the content supplies its own panel styling. */
7
+ var modalPanelClasses = "rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-2xl";
8
+ var FOCUSABLE = "a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])";
9
+ function BareModal({ open, onClose, ariaLabel, className, onPanelKeyDown, onPanelMouseDown, align = "top", preventClose = false, children }) {
10
+ const panelRef = useRef(null);
11
+ useEffect(() => {
12
+ if (!open || preventClose) return;
13
+ const onKeyDown = (e) => {
14
+ if (e.key === "Escape") onClose();
15
+ };
16
+ document.addEventListener("keydown", onKeyDown);
17
+ return () => document.removeEventListener("keydown", onKeyDown);
18
+ }, [
19
+ open,
20
+ onClose,
21
+ preventClose
22
+ ]);
23
+ useEffect(() => {
24
+ if (!open) return;
25
+ const previouslyFocused = document.activeElement;
26
+ const previousOverflow = document.body.style.overflow;
27
+ document.body.style.overflow = "hidden";
28
+ return () => {
29
+ document.body.style.overflow = previousOverflow;
30
+ previouslyFocused?.focus?.();
31
+ };
32
+ }, [open]);
33
+ const trapFocus = useCallback((e) => {
34
+ const panel = panelRef.current;
35
+ if (e.key !== "Tab" || !panel || !panel.contains(document.activeElement)) {
36
+ onPanelKeyDown?.(e);
37
+ return;
38
+ }
39
+ const focusable = panel.querySelectorAll(FOCUSABLE);
40
+ if (focusable.length === 0) {
41
+ e.preventDefault();
42
+ onPanelKeyDown?.(e);
43
+ return;
44
+ }
45
+ const first = focusable[0];
46
+ const last = focusable[focusable.length - 1];
47
+ if (!first || !last) {
48
+ onPanelKeyDown?.(e);
49
+ return;
50
+ }
51
+ if (e.shiftKey && document.activeElement === first) {
52
+ e.preventDefault();
53
+ last.focus();
54
+ } else if (!e.shiftKey && document.activeElement === last) {
55
+ e.preventDefault();
56
+ first.focus();
57
+ }
58
+ onPanelKeyDown?.(e);
59
+ }, [onPanelKeyDown]);
60
+ if (!open) return null;
61
+ return createPortal(/* @__PURE__ */ jsx("div", {
62
+ "data-testid": "modal-backdrop",
63
+ className: cx("fixed inset-0 z-[9990] flex justify-center px-4 pb-8", align === "center" ? "items-center" : "items-start pt-[14vh]"),
64
+ style: { backgroundColor: "rgba(0, 0, 0, 0.4)" },
65
+ onClick: preventClose ? void 0 : onClose,
66
+ children: /* @__PURE__ */ jsx("div", {
67
+ ref: panelRef,
68
+ role: "dialog",
69
+ "aria-modal": "true",
70
+ "aria-label": ariaLabel,
71
+ className,
72
+ onClick: (e) => e.stopPropagation(),
73
+ onKeyDown: trapFocus,
74
+ onMouseDown: onPanelMouseDown,
75
+ children
76
+ })
77
+ }), document.body);
78
+ }
79
+ //#endregion
80
+ export { modalPanelClasses as n, BareModal as t };
@@ -1,4 +1,5 @@
1
- import { i as getThemeName, n as setupMonacoWorkers, r as defineEditorThemes, t as useCssIsDark } from "./editor-D55tumuZ.js";
1
+ import { t as useCssIsDark } from "./useCssIsDark-DHr05dG2.js";
2
+ import { n as defineEditorThemes, r as getThemeName, t as setupMonacoWorkers } from "./editor-CEXg6C8X.js";
2
3
  import { jsx } from "react/jsx-runtime";
3
4
  import { useEffect, useRef } from "react";
4
5
  import * as monaco from "monaco-editor";
@@ -0,0 +1,595 @@
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-jQCAN3NN.js";
3
+ import { n as TOOLTIP_ID } from "./Tooltip-WgbiC_nd.js";
4
+ import { n as modalPanelClasses, t as BareModal } from "./BareModal-DBa84JZO.js";
5
+ import cx from "classnames";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { Fragment as Fragment$1, Suspense, lazy, useCallback, useEffect, useRef, useState } from "react";
8
+ import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
9
+ //#region src/components/Callout.tsx
10
+ function CalloutIcon({ type }) {
11
+ if (type === "warning" || type === "error") return /* @__PURE__ */ jsx(AlertIcon, { className: "h-6 w-6 mr-4 text-lg" });
12
+ else return /* @__PURE__ */ jsx(InfoIcon, { className: "h-6 w-6 mr-4 text-lg" });
13
+ }
14
+ function Callout({ type, className = "", children }) {
15
+ return /* @__PURE__ */ jsx("div", {
16
+ className: cx(className, type === "warning" && "bg-orange-100 border-orange-500 text-orange-700", type === "error" && "bg-red-100 border-red-500 text-red-700", type === "info" && "bg-blue-100 border-blue-500 text-blue-700", "border-t-4 rounded-b px-4 py-3 shadow-md my-4"),
17
+ role: "alert",
18
+ children: /* @__PURE__ */ jsxs("div", {
19
+ className: "flex",
20
+ children: [/* @__PURE__ */ jsx("div", {
21
+ className: "py-1",
22
+ children: /* @__PURE__ */ jsx(CalloutIcon, { type })
23
+ }), /* @__PURE__ */ jsx("div", { children })]
24
+ })
25
+ });
26
+ }
27
+ //#endregion
28
+ //#region src/components/CopyToClipboard.tsx
29
+ function CopyToClipboard({ as = "div", text, className, children, showIcon = true }) {
30
+ const notify = useNotify();
31
+ const handleCopy = async () => {
32
+ try {
33
+ await navigator.clipboard.writeText(text);
34
+ notify.info("Copied to clipboard");
35
+ } catch {
36
+ notify.error("Failed to copy to clipboard");
37
+ }
38
+ };
39
+ return /* @__PURE__ */ jsxs(as, {
40
+ className,
41
+ onClick: handleCopy,
42
+ ...as === "button" ? { type: "button" } : {},
43
+ children: [showIcon && /* @__PURE__ */ jsx(ClipboardIcon, {}), children]
44
+ });
45
+ }
46
+ function CopyCodeBlock({ textToCopy, children, secret = false, isRevealed = false, onRevealToggle }) {
47
+ const notify = useNotify();
48
+ const [copied, setCopied] = useState(false);
49
+ const handleCopy = async () => {
50
+ if (copied) return;
51
+ try {
52
+ await navigator.clipboard.writeText(textToCopy);
53
+ setCopied(true);
54
+ notify.info("Copied to clipboard");
55
+ setTimeout(() => setCopied(false), 2e3);
56
+ } catch {
57
+ notify.error("Failed to copy to clipboard");
58
+ }
59
+ };
60
+ return /* @__PURE__ */ jsxs("div", {
61
+ className: "group relative",
62
+ onClick: handleCopy,
63
+ children: [/* @__PURE__ */ jsx("pre", {
64
+ className: `p-4 theme-hover border rounded-lg text-left font-mono text-sm overflow-x-auto ${secret ? "pr-24" : "pr-12"}`,
65
+ children
66
+ }), /* @__PURE__ */ jsxs("div", {
67
+ className: "absolute top-0 right-0 bottom-0 flex items-center gap-1 pl-8 pr-2 bg-gradient-to-l from-[var(--color-panel)] from-70% to-transparent rounded-r-lg",
68
+ children: [secret && /* @__PURE__ */ jsx("button", {
69
+ type: "button",
70
+ onClick: (e) => {
71
+ e.stopPropagation();
72
+ onRevealToggle?.();
73
+ },
74
+ className: "p-2 rounded-md opacity-0 group-hover:opacity-100 transition-all duration-150",
75
+ "aria-label": isRevealed ? "Hide secret" : "Reveal secret",
76
+ title: isRevealed ? "Hide secret" : "Reveal secret",
77
+ children: isRevealed ? /* @__PURE__ */ jsx(HiddenFalseIcon, {}) : /* @__PURE__ */ jsx(HiddenTrueIcon, {})
78
+ }), /* @__PURE__ */ jsx("button", {
79
+ type: "button",
80
+ onClick: (e) => {
81
+ e.stopPropagation();
82
+ handleCopy();
83
+ },
84
+ className: "p-2 rounded-md opacity-0 group-hover:opacity-100 transition-all duration-150",
85
+ "aria-label": copied ? "Copied" : "Copy to clipboard",
86
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-green-400" }) : /* @__PURE__ */ jsx(CopyIcon, {})
87
+ })]
88
+ })]
89
+ });
90
+ }
91
+ //#endregion
92
+ //#region src/components/Markdown.tsx
93
+ var MarkdownImpl = lazy(() => import("./MarkdownImpl-Bq4QhrtA.js"));
94
+ function Markdown(props) {
95
+ return /* @__PURE__ */ jsx(Suspense, {
96
+ fallback: /* @__PURE__ */ jsx("div", {
97
+ className: "markdown whitespace-pre-wrap text-start w-full",
98
+ children: props.children
99
+ }),
100
+ children: /* @__PURE__ */ jsx(MarkdownImpl, { ...props })
101
+ });
102
+ }
103
+ //#endregion
104
+ //#region src/components/ghostButton.ts
105
+ var ghostButtonClasses = "inline-flex cursor-pointer items-center gap-1.5 h-8 px-3 rounded-md text-sm text-(--theme-muted-text-color) hover:text-(--theme-app) hover:bg-(--theme-muted-panel-bg) transition-colors";
106
+ var primaryButtonClasses = "inline-flex cursor-pointer items-center gap-1.5 h-7 px-2.5 rounded-md text-[12.5px] font-medium bg-(--theme-element) text-(--theme-element-text) hover:opacity-90 transition-opacity";
107
+ /** Filled destructive button for confirming irreversible actions in ds modals. */
108
+ var dangerButtonClasses = "inline-flex cursor-pointer items-center gap-1.5 h-7 px-2.5 rounded-md text-[12.5px] font-medium bg-red-600 text-white hover:bg-red-700 transition-colors";
109
+ //#endregion
110
+ //#region src/components/ConfirmModal.tsx
111
+ function ConfirmModal({ open, onClose, title, description, children, confirmLabel, onConfirm, confirmDisabled = false, destructive = false, align = "top", cancelLabel, closeOnConfirm = true }) {
112
+ const strings = useStrings();
113
+ const [pending, setPending] = useState(false);
114
+ const firedRef = useRef(false);
115
+ useEffect(() => {
116
+ if (open) firedRef.current = false;
117
+ }, [open]);
118
+ const onCloseRef = useRef(onClose);
119
+ onCloseRef.current = onClose;
120
+ const runConfirm = useCallback(async () => {
121
+ if (firedRef.current) return;
122
+ firedRef.current = true;
123
+ setPending(true);
124
+ try {
125
+ await onConfirm();
126
+ if (closeOnConfirm) onCloseRef.current();
127
+ else firedRef.current = false;
128
+ } finally {
129
+ setPending(false);
130
+ }
131
+ }, [onConfirm, closeOnConfirm]);
132
+ return /* @__PURE__ */ jsxs(BareModal, {
133
+ open,
134
+ onClose,
135
+ ariaLabel: title,
136
+ align,
137
+ preventClose: pending,
138
+ className: cx(modalPanelClasses, "w-[480px] max-w-full"),
139
+ children: [/* @__PURE__ */ jsxs("div", {
140
+ className: "px-5 pt-5",
141
+ children: [
142
+ /* @__PURE__ */ jsx("h2", {
143
+ className: "text-lg font-semibold text-(--theme-app)",
144
+ children: title
145
+ }),
146
+ description !== null && description !== void 0 && /* @__PURE__ */ jsx("p", {
147
+ className: "mt-1.5 text-sm text-(--theme-muted-text-color)",
148
+ children: description
149
+ }),
150
+ children !== null && children !== void 0 && /* @__PURE__ */ jsx("div", {
151
+ className: "mt-4",
152
+ children
153
+ })
154
+ ]
155
+ }), /* @__PURE__ */ jsxs("div", {
156
+ className: "mt-5 flex items-center justify-end gap-2 border-t border-(--theme-border) px-5 py-3",
157
+ children: [/* @__PURE__ */ jsx("button", {
158
+ type: "button",
159
+ onClick: onClose,
160
+ disabled: pending,
161
+ className: cx(ghostButtonClasses, pending && "cursor-wait"),
162
+ children: cancelLabel ?? strings.modal.cancel
163
+ }), /* @__PURE__ */ jsx("button", {
164
+ type: "button",
165
+ onClick: runConfirm,
166
+ disabled: confirmDisabled || pending,
167
+ className: cx(destructive ? dangerButtonClasses : primaryButtonClasses, "disabled:cursor-not-allowed disabled:opacity-50", pending && "cursor-wait"),
168
+ children: confirmLabel
169
+ })]
170
+ })]
171
+ });
172
+ }
173
+ //#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
+ //#region src/components/CreateModal.tsx
201
+ /** Small info icon that surfaces field help via the global tooltip. */
202
+ function FieldHelp({ tooltip }) {
203
+ if (!tooltip) return null;
204
+ return /* @__PURE__ */ jsx("span", {
205
+ "data-tooltip-id": TOOLTIP_ID,
206
+ "data-tooltip-content": tooltip,
207
+ className: "inline-flex cursor-help text-(--theme-muted-text-color)",
208
+ children: /* @__PURE__ */ jsx(TooltipIcon, { className: "w-3 h-3" })
209
+ });
210
+ }
211
+ /** Anchors the tooltip on a non-focusable span so it opens on hover but not when focus returns to the button after its menu/toggle closes (which would leave it stuck). */
212
+ function PillTooltip({ content, className, children }) {
213
+ return /* @__PURE__ */ jsx("span", {
214
+ ...content ? {
215
+ "data-tooltip-id": TOOLTIP_ID,
216
+ "data-tooltip-content": content
217
+ } : {},
218
+ className: cx("inline-flex items-center gap-1.5", className),
219
+ children
220
+ });
221
+ }
222
+ /** Submits on Enter in the name field or ⌘/Ctrl+Enter from anywhere in the panel. */
223
+ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, namePlaceholder, hideName = false, initialName, showDescription = true, descriptionPlaceholder, submitLabel, submittingLabel, validateName, sanitizeName, nameHint, children, properties, advanced, submitDisabled = false, hideSubmit = false, nameOptional = false, onNameChange, dirty = false, showFavorite = false, onSubmit }) {
224
+ const t = useStrings().modal;
225
+ const submitText = submitLabel ?? t.create;
226
+ const submittingText = submittingLabel ?? t.creating;
227
+ const descriptionText = descriptionPlaceholder ?? t.addDescription;
228
+ const [name, setName] = useState("");
229
+ const [description, setDescription] = useState("");
230
+ const [submitting, setSubmitting] = useState(false);
231
+ const [advancedOpen, setAdvancedOpen] = useState(false);
232
+ const [favorite, setFavorite] = useState(false);
233
+ const [nameFlash, setNameFlash] = useState(false);
234
+ const [nameTouched, setNameTouched] = useState(false);
235
+ const [interacted, setInteracted] = useState(false);
236
+ const nameRef = useRef(null);
237
+ useEffect(() => {
238
+ if (open) {
239
+ setName(initialName ?? "");
240
+ setDescription("");
241
+ setSubmitting(false);
242
+ setAdvancedOpen(false);
243
+ setFavorite(false);
244
+ setNameTouched(false);
245
+ setInteracted(false);
246
+ requestAnimationFrame(() => nameRef.current?.focus());
247
+ }
248
+ }, [open, initialName]);
249
+ const nameError = name.trim() ? validateName?.(name.trim()) ?? null : null;
250
+ const hint = !nameError && name.trim() ? nameHint?.(name.trim()) : null;
251
+ const canSubmit = (hideName || nameOptional || name.trim().length > 0) && !nameError && !submitting && !submitDisabled;
252
+ const isDirty = !submitting && (interacted || name !== (initialName ?? "") || description !== "" || favorite || dirty);
253
+ const nameMissing = !hideName && !nameOptional && (!name.trim() || !!nameError) && (nameTouched || description !== "" || favorite || dirty);
254
+ const flashName = () => {
255
+ setNameTouched(true);
256
+ nameRef.current?.focus();
257
+ setNameFlash(false);
258
+ requestAnimationFrame(() => setNameFlash(true));
259
+ };
260
+ const handleSubmit = async () => {
261
+ if (!canSubmit) {
262
+ if (!hideName && !submitting && (!name.trim() || nameError)) flashName();
263
+ return;
264
+ }
265
+ setSubmitting(true);
266
+ let close = false;
267
+ try {
268
+ close = await onSubmit(name.trim(), description.trim(), favorite);
269
+ } finally {
270
+ if (!close) setSubmitting(false);
271
+ }
272
+ if (close) onClose();
273
+ };
274
+ return /* @__PURE__ */ jsxs(BareModal, {
275
+ open,
276
+ onClose,
277
+ ariaLabel: `${submitText}: ${typeLabel}`,
278
+ className: cx(modalPanelClasses, "w-[560px] max-w-full flex flex-col max-h-full"),
279
+ preventClose: isDirty,
280
+ onPanelKeyDown: (e) => {
281
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleSubmit();
282
+ },
283
+ onPanelMouseDown: (e) => {
284
+ if (e.target instanceof Element && !e.target.closest("input, textarea, button, a, select, label")) e.preventDefault();
285
+ },
286
+ children: [/* @__PURE__ */ jsxs("div", {
287
+ className: "flex-1 min-h-0 overflow-y-auto overscroll-contain",
288
+ onChangeCapture: () => setInteracted(true),
289
+ children: [
290
+ /* @__PURE__ */ jsxs("div", {
291
+ className: "px-4 pt-4",
292
+ children: [
293
+ typeMenu && typeMenu.length > 0 ? /* @__PURE__ */ jsxs(AddMenu, {
294
+ items: typeMenu,
295
+ label: typeLabel,
296
+ zClassName: "z-[9999]",
297
+ buttonClassName: "inline-flex items-center gap-1.5 px-1.5 py-1 rounded-md bg-(--theme-muted-panel-bg) text-xs font-medium text-(--theme-muted-text-color) transition-colors hover:text-(--theme-app)",
298
+ children: [
299
+ typeIcon,
300
+ typeLabel,
301
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "w-3 h-3 opacity-60" })
302
+ ]
303
+ }) : /* @__PURE__ */ jsxs("div", {
304
+ className: "inline-flex items-center gap-1.5 px-1.5 py-1 rounded-md bg-(--theme-muted-panel-bg) text-xs font-medium text-(--theme-muted-text-color)",
305
+ children: [typeIcon, typeLabel]
306
+ }),
307
+ hideName ? /* @__PURE__ */ jsx("div", { className: "mt-3" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
308
+ /* @__PURE__ */ jsx("input", {
309
+ ref: nameRef,
310
+ type: "text",
311
+ autoComplete: "off",
312
+ "data-1p-ignore": true,
313
+ value: name,
314
+ onChange: (e) => {
315
+ const next = sanitizeName ? sanitizeName(e.target.value) : e.target.value;
316
+ setName(next);
317
+ onNameChange?.(next);
318
+ },
319
+ onBlur: (e) => {
320
+ if (!e.target.value.trim()) setNameTouched(true);
321
+ },
322
+ onKeyDown: (e) => {
323
+ if (e.key === "Enter" && !e.nativeEvent.isComposing && !e.metaKey && !e.ctrlKey) {
324
+ e.preventDefault();
325
+ e.stopPropagation();
326
+ handleSubmit();
327
+ }
328
+ },
329
+ placeholder: namePlaceholder,
330
+ "aria-label": namePlaceholder,
331
+ onAnimationEnd: () => setNameFlash(false),
332
+ className: cx("mt-2 -mb-1 -mx-1.5 w-[calc(100%+0.75rem)] rounded-md border-0 px-1.5 py-1 bg-transparent shadow-none text-lg font-medium text-(--theme-app) placeholder:text-(--theme-muted-text-color) focus:outline-none", nameFlash && "animate-field-flash", nameMissing ? "ring-1 ring-(--theme-error)" : "focus:ring-0")
333
+ }),
334
+ nameError && /* @__PURE__ */ jsx("p", {
335
+ className: "mt-1 text-xs text-(--theme-error)",
336
+ children: nameError
337
+ }),
338
+ hint && /* @__PURE__ */ jsx("p", {
339
+ className: "mt-1 text-xs text-(--theme-muted-text-color)",
340
+ children: hint
341
+ }),
342
+ showDescription ? /* @__PURE__ */ jsx("textarea", {
343
+ autoComplete: "off",
344
+ "data-1p-ignore": true,
345
+ value: description,
346
+ onChange: (e) => setDescription(e.target.value),
347
+ placeholder: descriptionText,
348
+ "aria-label": descriptionText,
349
+ rows: 3,
350
+ className: "mt-1.5 w-full border-0 p-0 bg-transparent shadow-none resize-none text-sm text-(--theme-app) placeholder:text-(--theme-muted-text-color) focus:outline-none focus:ring-0"
351
+ }) : /* @__PURE__ */ jsx("div", { className: "mt-3" })
352
+ ] }),
353
+ children
354
+ ]
355
+ }),
356
+ properties && /* @__PURE__ */ jsx("div", {
357
+ className: "flex flex-wrap items-center gap-1.5 px-4 pt-1 pb-3",
358
+ children: properties
359
+ }),
360
+ advanced && /* @__PURE__ */ jsxs("div", {
361
+ className: "px-4 pb-3",
362
+ children: [/* @__PURE__ */ jsxs("button", {
363
+ type: "button",
364
+ onClick: () => setAdvancedOpen((o) => !o),
365
+ className: "inline-flex items-center gap-1 text-xs font-medium text-(--theme-muted-text-color) hover:text-(--theme-app) transition-colors",
366
+ children: [/* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("w-3 h-3 transition-transform", advancedOpen && "rotate-90") }), t.advanced]
367
+ }), advancedOpen && /* @__PURE__ */ jsx("div", {
368
+ className: "mt-2",
369
+ children: advanced
370
+ })]
371
+ })
372
+ ]
373
+ }), /* @__PURE__ */ jsxs("div", {
374
+ className: "shrink-0 flex items-center justify-between gap-2 px-4 py-3",
375
+ children: [showFavorite ? /* @__PURE__ */ jsx("button", {
376
+ type: "button",
377
+ role: "switch",
378
+ "aria-checked": favorite,
379
+ "aria-label": t.favorite,
380
+ onClick: () => setFavorite((f) => !f),
381
+ className: cx("inline-flex h-8 rounded-md text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-(--theme-focus-ring)", favorite ? "text-(--theme-favorite) bg-(--theme-favorite-muted)" : "text-(--theme-muted-text-color) hover:text-(--theme-app) hover:bg-(--theme-muted-panel-bg)"),
382
+ children: /* @__PURE__ */ jsxs(PillTooltip, {
383
+ content: favorite ? t.favoriteHintOn : t.favoriteHintOff,
384
+ className: "px-2.5",
385
+ children: [favorite ? /* @__PURE__ */ jsx(FavoriteIcon, { className: "w-4 h-4 scale-110 transition-transform" }) : /* @__PURE__ */ jsx(FavoriteOutlineIcon, { className: "w-4 h-4 transition-transform" }), favorite ? t.favorited : t.favorite]
386
+ })
387
+ }) : /* @__PURE__ */ jsx("span", {}), /* @__PURE__ */ jsxs("div", {
388
+ className: "flex items-center gap-2",
389
+ children: [/* @__PURE__ */ jsx("button", {
390
+ type: "button",
391
+ onClick: onClose,
392
+ className: ghostButtonClasses,
393
+ children: hideSubmit ? t.close : t.cancel
394
+ }), !hideSubmit && /* @__PURE__ */ jsx("button", {
395
+ type: "button",
396
+ onClick: handleSubmit,
397
+ "aria-disabled": !canSubmit,
398
+ className: `inline-flex cursor-pointer items-center gap-1.5 h-7 px-2.5 rounded-md text-[12.5px] font-medium bg-(--theme-element) text-(--theme-element-text) hover:opacity-90 transition-opacity aria-disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:hover:opacity-50`,
399
+ children: submitting ? submittingText : submitText
400
+ })]
401
+ })]
402
+ })]
403
+ });
404
+ }
405
+ var fieldInputClasses = "w-full h-8 px-2.5 rounded-md border border-(--theme-border) bg-(--theme-input-bg) shadow-none text-sm text-(--theme-app) placeholder:text-(--theme-muted-text-color) transition-colors focus:outline-none focus:ring-0 focus:border-(--theme-element)";
406
+ var fieldLabelClasses = "block mb-1 text-xs font-medium text-(--theme-muted-text-color)";
407
+ /** Labeled single-line input row for the dialog's extra fields. */
408
+ function CreateModalField({ label, tooltip, ...props }) {
409
+ return /* @__PURE__ */ jsxs("label", {
410
+ className: "block mb-3",
411
+ children: [/* @__PURE__ */ jsxs("span", {
412
+ className: cx(fieldLabelClasses, "flex items-center gap-1"),
413
+ children: [label, /* @__PURE__ */ jsx(FieldHelp, { tooltip })]
414
+ }), /* @__PURE__ */ jsx("input", {
415
+ type: "text",
416
+ autoComplete: "off",
417
+ "data-1p-ignore": true,
418
+ ...props,
419
+ className: fieldInputClasses
420
+ })]
421
+ });
422
+ }
423
+ /** Labeled multi-line field for credential blobs (JSON keys, PEM keys). */
424
+ function CreateModalTextarea({ label, tooltip, rows = 4, ...props }) {
425
+ return /* @__PURE__ */ jsxs("label", {
426
+ className: "block mb-3",
427
+ children: [/* @__PURE__ */ jsxs("span", {
428
+ className: cx(fieldLabelClasses, "flex items-center gap-1"),
429
+ children: [label, /* @__PURE__ */ jsx(FieldHelp, { tooltip })]
430
+ }), /* @__PURE__ */ jsx("textarea", {
431
+ autoComplete: "off",
432
+ "data-1p-ignore": true,
433
+ rows,
434
+ ...props,
435
+ className: cx(fieldInputClasses, "h-auto py-2 font-mono text-xs leading-relaxed resize-y")
436
+ })]
437
+ });
438
+ }
439
+ /** Labeled input row with typeahead suggestions; free-form values allowed. */
440
+ function CreateModalAutocompleteField({ label, tooltip, value, onChange, options, placeholder }) {
441
+ const query = value.trim().toLowerCase();
442
+ const filtered = query ? options.filter((option) => option.toLowerCase().includes(query)) : options;
443
+ return /* @__PURE__ */ jsxs("div", {
444
+ className: "mb-3",
445
+ children: [/* @__PURE__ */ jsxs("span", {
446
+ className: cx(fieldLabelClasses, "flex items-center gap-1"),
447
+ children: [label, /* @__PURE__ */ jsx(FieldHelp, { tooltip })]
448
+ }), /* @__PURE__ */ jsxs(Combobox, {
449
+ value,
450
+ onChange: (next) => onChange(next ?? ""),
451
+ immediate: true,
452
+ children: [/* @__PURE__ */ jsx(ComboboxInput, {
453
+ autoComplete: "off",
454
+ "data-1p-ignore": true,
455
+ "aria-label": label,
456
+ placeholder,
457
+ displayValue: (current) => current ?? "",
458
+ onChange: (e) => onChange(e.target.value),
459
+ className: fieldInputClasses
460
+ }), filtered.length > 0 && /* @__PURE__ */ jsx(ComboboxOptions, {
461
+ anchor: "bottom start",
462
+ className: "z-[9999] mt-1 w-(--input-width) [--anchor-max-height:14rem] overflow-auto rounded-lg border border-(--theme-border) bg-(--theme-app-bg) py-1 shadow-lg focus:outline-none",
463
+ children: filtered.map((option) => /* @__PURE__ */ jsx(ComboboxOption, {
464
+ value: option,
465
+ className: "px-3 py-1.5 text-[13px] text-(--theme-app) data-[focus]:bg-(--theme-muted-panel-bg) cursor-pointer",
466
+ children: option
467
+ }, option))
468
+ })]
469
+ })]
470
+ });
471
+ }
472
+ /** Compact property pill with an on/off switch. */
473
+ function CreateModalSwitch({ label, checked, onChange, tooltip }) {
474
+ return /* @__PURE__ */ jsx("button", {
475
+ type: "button",
476
+ role: "switch",
477
+ "aria-checked": checked,
478
+ onClick: () => onChange(!checked),
479
+ className: cx("inline-flex h-7 rounded-md border border-(--theme-border) text-xs font-medium transition-colors hover:bg-(--theme-muted-panel-bg)", checked ? "text-(--theme-app)" : "text-(--theme-muted-text-color)"),
480
+ children: /* @__PURE__ */ jsxs(PillTooltip, {
481
+ content: tooltip,
482
+ className: "px-2",
483
+ children: [/* @__PURE__ */ jsx("span", {
484
+ className: cx("relative inline-flex h-3.5 w-6 shrink-0 rounded-full transition-colors", checked ? "bg-(--theme-element)" : "bg-(--theme-border)"),
485
+ children: /* @__PURE__ */ jsx("span", { className: cx("absolute top-0.5 left-0.5 h-2.5 w-2.5 rounded-full bg-white shadow-sm transition-transform", checked && "translate-x-2.5") })
486
+ }), label]
487
+ })
488
+ });
489
+ }
490
+ function buildOptionNodes(options, query, onChange) {
491
+ const normalize = (s) => s.toLowerCase().replace(/-/g, "");
492
+ const q = normalize(query.trim());
493
+ const filtered = q ? options.filter((o) => normalize(o.label).includes(q)) : options;
494
+ const nodes = [];
495
+ let lastGroup;
496
+ for (const option of filtered) {
497
+ if (option.group && option.group !== lastGroup) {
498
+ lastGroup = option.group;
499
+ nodes.push(/* @__PURE__ */ jsx("div", {
500
+ className: "px-3 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-wide text-(--theme-muted-text-color)",
501
+ children: option.group
502
+ }, `group-${option.group}`));
503
+ }
504
+ nodes.push(/* @__PURE__ */ jsx(MenuItem, { children: /* @__PURE__ */ jsxs("button", {
505
+ type: "button",
506
+ onClick: () => onChange(option.value),
507
+ className: "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",
508
+ children: [option.icon, option.label]
509
+ }) }, option.value));
510
+ }
511
+ return nodes;
512
+ }
513
+ function CreateModalSelectPanel({ open, options, label, onChange }) {
514
+ const t = useStrings().modal;
515
+ const [query, setQuery] = useState("");
516
+ const inputRef = useRef(null);
517
+ const showFilter = options.length > 8;
518
+ useEffect(() => {
519
+ if (!open) {
520
+ setQuery("");
521
+ return;
522
+ }
523
+ if (!showFilter) return;
524
+ const raf = requestAnimationFrame(() => inputRef.current?.focus());
525
+ return () => cancelAnimationFrame(raf);
526
+ }, [open, showFilter]);
527
+ const rendered = buildOptionNodes(options, query, onChange);
528
+ return /* @__PURE__ */ jsxs(MenuItems, {
529
+ anchor: "bottom start",
530
+ className: "z-[9999] mt-1 min-w-44 [--anchor-max-height:16rem] overflow-auto rounded-lg border border-(--theme-border) bg-(--theme-app-bg) shadow-lg focus:outline-none",
531
+ children: [showFilter && /* @__PURE__ */ jsx("div", {
532
+ className: "sticky top-0 z-10 bg-(--theme-app-bg) px-1.5 pt-1 pb-1.5 border-b border-(--theme-border)",
533
+ children: /* @__PURE__ */ jsx("input", {
534
+ ref: inputRef,
535
+ type: "text",
536
+ autoComplete: "off",
537
+ "data-1p-ignore": true,
538
+ "aria-label": label,
539
+ placeholder: t.filter,
540
+ value: query,
541
+ onChange: (e) => setQuery(e.target.value),
542
+ onKeyDown: (e) => {
543
+ if (e.key !== "Escape") e.stopPropagation();
544
+ },
545
+ className: "w-full h-7 px-2 rounded-md border border-(--theme-border) bg-(--theme-input-bg) text-[13px] text-(--theme-app) placeholder:text-(--theme-muted-text-color) focus:outline-none focus:border-(--theme-element)"
546
+ })
547
+ }), /* @__PURE__ */ jsx("div", {
548
+ className: "py-1",
549
+ children: rendered.length === 0 ? /* @__PURE__ */ jsx("div", {
550
+ className: "px-3 py-1.5 text-[13px] text-(--theme-muted-text-color)",
551
+ children: t.noOptions
552
+ }) : rendered
553
+ })]
554
+ });
555
+ }
556
+ /** Compact property pill with a dropdown of options. Options may carry leading
557
+ * icons and group headers (e.g. Clusters vs Kubernetes). */
558
+ function CreateModalSelect({ label, icon, value, options, onChange, disabled = false, disabledHint, tooltip }) {
559
+ const selected = options.find((o) => o.value === value);
560
+ const pillContent = /* @__PURE__ */ jsxs(Fragment, { children: [
561
+ selected?.icon ?? icon,
562
+ selected ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
563
+ className: "font-normal text-(--theme-muted-text-color)",
564
+ children: label
565
+ }), selected.label] }) : label,
566
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "w-3 h-3 opacity-60" })
567
+ ] });
568
+ if (disabled) return /* @__PURE__ */ jsx("button", {
569
+ type: "button",
570
+ "aria-disabled": "true",
571
+ "aria-label": label,
572
+ className: cx("inline-flex h-7 rounded-md border border-(--theme-border) text-xs font-medium", "opacity-50 cursor-not-allowed text-(--theme-muted-text-color)"),
573
+ children: /* @__PURE__ */ jsx(PillTooltip, {
574
+ content: disabledHint ?? tooltip,
575
+ className: "px-2",
576
+ children: pillContent
577
+ })
578
+ });
579
+ return /* @__PURE__ */ jsx(Menu, { children: ({ open }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuButton, {
580
+ "aria-label": label,
581
+ className: cx("inline-flex h-7 rounded-md border border-(--theme-border) text-xs font-medium transition-colors hover:bg-(--theme-muted-panel-bg)", selected ? "text-(--theme-app)" : "text-(--theme-muted-text-color)"),
582
+ children: /* @__PURE__ */ jsx(PillTooltip, {
583
+ content: tooltip,
584
+ className: "px-2",
585
+ children: pillContent
586
+ })
587
+ }), /* @__PURE__ */ jsx(CreateModalSelectPanel, {
588
+ open,
589
+ options,
590
+ label,
591
+ onChange
592
+ })] }) });
593
+ }
594
+ //#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 };