@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.
- package/dist/chunks/BareModal-DBa84JZO.js +80 -0
- package/dist/chunks/{CodePreviewEditor-CSPRILMp.js → CodePreviewEditor-CBtYRZi6.js} +2 -1
- package/dist/chunks/CreateModal-6zZZHxCI.js +595 -0
- package/dist/chunks/Loader-BXoXTZGc.js +47 -0
- package/dist/chunks/{Monaco-CC4ak1JG.js → Monaco-CvFXoW3r.js} +11 -5
- package/dist/chunks/{Provider-DvVvScTQ.js → Provider-jQCAN3NN.js} +73 -2
- package/dist/chunks/{SwitchToggle-2uRw8ZeJ.js → SwitchToggle-D0ud8cd5.js} +36 -29
- package/dist/chunks/{Table-C5z6qWjM.js → Table-ByziK93x.js} +1 -1
- package/dist/chunks/{editor-D55tumuZ.js → editor-CEXg6C8X.js} +5 -41
- package/dist/chunks/list-CvDWt0TC.js +1259 -0
- package/dist/chunks/useCssIsDark-DHr05dG2.js +38 -0
- package/dist/components/AddMenu.d.ts +17 -0
- package/dist/components/BareModal.d.ts +17 -0
- package/dist/components/Button.d.ts +18 -0
- package/dist/components/Card.d.ts +19 -0
- package/dist/components/ConfirmModal.d.ts +17 -0
- package/dist/components/CreateModal.d.ts +92 -0
- package/dist/components/Filter.d.ts +15 -0
- package/dist/components/FilterPill.d.ts +7 -0
- package/dist/components/IconButton.d.ts +17 -0
- package/dist/components/Input.d.ts +14 -0
- package/dist/components/LetterBadge.d.ts +6 -0
- package/dist/components/Loader.d.ts +2 -1
- package/dist/components/Pagination.d.ts +15 -0
- package/dist/components/Provider.d.ts +39 -12
- package/dist/components/SettingModeOption.d.ts +13 -0
- package/dist/components/SettingRow.d.ts +18 -0
- package/dist/components/SettingsCard.d.ts +24 -0
- package/dist/components/SettingsGroup.d.ts +8 -0
- package/dist/components/Sort.d.ts +9 -0
- package/dist/components/Toggle.d.ts +6 -0
- package/dist/components/dropdownUtils.d.ts +10 -0
- package/dist/components/ghostButton.d.ts +4 -0
- package/dist/components/inputClasses.d.ts +1 -0
- package/dist/editor/index.d.ts +0 -1
- package/dist/editor/index.js +2 -2
- package/dist/file-explorer/index.js +27 -28
- package/dist/form/index.js +4 -4
- package/dist/index.d.ts +21 -1
- package/dist/index.js +433 -8
- package/dist/list/HoverCard.d.ts +22 -0
- package/dist/list/ListPager.d.ts +7 -0
- package/dist/list/ListViewControls.d.ts +12 -0
- package/dist/list/index.d.ts +6 -0
- package/dist/list/index.js +2 -2
- package/dist/list/listSearch.d.ts +27 -0
- package/dist/list/listView.d.ts +129 -0
- package/dist/list/textEntry.d.ts +2 -0
- package/dist/logviewer/index.js +1 -1
- package/dist/styles/theme.css +21 -0
- package/dist/styles.css +1 -1
- package/dist/workflow/index.js +8 -8
- package/package.json +2 -6
- package/dist/chunks/Loader-DQiZ75fa.js +0 -25
- package/dist/chunks/Markdown-C5Re2ezs.js +0 -101
- package/dist/chunks/Modal-sOUEwebV.js +0 -121
- package/dist/chunks/list-7PyDF1tz.js +0 -465
- package/dist/components/Modal.d.ts +0 -26
- /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 {
|
|
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 };
|