@parallelworks/ui 0.80.0 → 0.82.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/README.md +7 -1
- package/dist/ai/adapter/types.d.ts +1 -0
- package/dist/ai/ai.css +3 -92
- package/dist/ai/components/agent/AgentMessageParts.js +1 -0
- package/dist/ai/core/ChatProvider.js +10 -5
- package/dist/ai/strings.d.ts +3 -0
- package/dist/ai/strings.js +2 -0
- package/dist/ai/types.d.ts +5 -0
- package/dist/components/Avatar.d.ts +5 -3
- package/dist/components/Avatar.js +6 -2
- package/dist/components/Card.d.ts +16 -1
- package/dist/components/Card.js +13 -2
- package/dist/components/CodeBlock.d.ts +40 -0
- package/dist/components/CodeBlock.js +159 -0
- package/dist/components/CopyButton.d.ts +11 -4
- package/dist/components/CopyButton.js +86 -11
- package/dist/components/CreateModal.d.ts +3 -1
- package/dist/components/CreateModal.js +31 -11
- package/dist/components/DescriptionList.js +1 -1
- package/dist/components/Drawer.js +1 -1
- package/dist/components/Input.d.ts +5 -0
- package/dist/components/Input.js +4 -3
- package/dist/components/Listbox.d.ts +12 -3
- package/dist/components/Listbox.js +38 -15
- package/dist/components/MarkdownImpl.js +89 -2
- package/dist/components/MenuEntries.d.ts +3 -0
- package/dist/components/MenuEntries.js +19 -6
- package/dist/components/Modal.d.ts +1 -1
- package/dist/components/Modal.js +6 -5
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +11 -5
- package/dist/components/Provider.d.ts +3 -0
- package/dist/components/Provider.js +1 -0
- package/dist/components/Select.js +1 -1
- package/dist/components/SettingsCard.d.ts +7 -2
- package/dist/components/SettingsCard.js +42 -7
- package/dist/components/ToggleGroup.d.ts +3 -1
- package/dist/components/ToggleGroup.js +2 -2
- package/dist/components/Tooltip.js +35 -2
- package/dist/components/codeHighlight.d.ts +9 -0
- package/dist/components/codeHighlight.js +29 -0
- package/dist/components/pageHeaderStore.d.ts +4 -0
- package/dist/components/pageHeaderStore.js +5 -2
- package/dist/file-explorer/FileExplorer.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/list/ListFilterBar.js +6 -5
- package/dist/list/filterModel.d.ts +4 -0
- package/dist/list/filterModel.js +7 -1
- package/dist/styles/theme.css +1 -0
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +1 -1
- package/dist/theme/derive.js +3 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { CheckIcon, CopyIcon, EyeIcon, EyeOffIcon } from "../icons.js";
|
|
|
4
4
|
import { useStrings } from "./Provider.js";
|
|
5
5
|
import { useCopy } from "./useCopy.js";
|
|
6
6
|
import { IconButton } from "./IconButton.js";
|
|
7
|
-
import { useState } from "react";
|
|
7
|
+
import { useEffectEvent, useLayoutEffect, useRef, useState } from "react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/components/CopyButton.tsx
|
|
10
10
|
/** The one copy control: a button that copies its text, turns into a check for a
|
|
@@ -40,12 +40,60 @@ function CopyButton({ text, label, quiet = false, showLabel = false, variant = s
|
|
|
40
40
|
onClick
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
|
+
var NO_ENDS = {
|
|
44
|
+
start: false,
|
|
45
|
+
end: false
|
|
46
|
+
};
|
|
47
|
+
function useHiddenEnds(active) {
|
|
48
|
+
const ref = useRef(null);
|
|
49
|
+
const [ends, setEnds] = useState(NO_ENDS);
|
|
50
|
+
const measureNow = () => {
|
|
51
|
+
const el = ref.current;
|
|
52
|
+
if (!el || !active) {
|
|
53
|
+
setEnds(NO_ENDS);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const scrolled = Math.abs(el.scrollLeft);
|
|
57
|
+
const start = scrolled > 1;
|
|
58
|
+
const end = scrolled + el.clientWidth < el.scrollWidth - 1;
|
|
59
|
+
setEnds((was) => was.start === start && was.end === end ? was : {
|
|
60
|
+
start,
|
|
61
|
+
end
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
const measure = useEffectEvent(measureNow);
|
|
65
|
+
useLayoutEffect(() => {
|
|
66
|
+
measure();
|
|
67
|
+
});
|
|
68
|
+
useLayoutEffect(() => {
|
|
69
|
+
const el = ref.current;
|
|
70
|
+
if (!el || !active || typeof ResizeObserver === "undefined") return;
|
|
71
|
+
const observer = new ResizeObserver(() => measure());
|
|
72
|
+
observer.observe(el);
|
|
73
|
+
return () => observer.disconnect();
|
|
74
|
+
}, [active]);
|
|
75
|
+
return {
|
|
76
|
+
ref,
|
|
77
|
+
ends,
|
|
78
|
+
onScroll: measureNow
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
var FADE = "1.25rem";
|
|
82
|
+
function fadeMask({ start, end }) {
|
|
83
|
+
if (!start && !end) return;
|
|
84
|
+
const image = `linear-gradient(to var(--fade-end, right), ${start ? `transparent, #000 ${FADE}` : "#000"}, ${end ? `#000 calc(100% - ${FADE}), transparent` : "#000"})`;
|
|
85
|
+
return {
|
|
86
|
+
maskImage: image,
|
|
87
|
+
WebkitMaskImage: image
|
|
88
|
+
};
|
|
89
|
+
}
|
|
43
90
|
var MASK = "•".repeat(24);
|
|
44
91
|
/** A block of code, such as a command to run, with a button that copies it. The
|
|
45
92
|
* buttons show while the pointer is over the block or focus is in it, and always
|
|
46
|
-
* where there is no hover to reveal them. With `
|
|
47
|
-
* such as a
|
|
48
|
-
|
|
93
|
+
* where there is no hover to reveal them. With `inline` it is a compact value in the line
|
|
94
|
+
* instead, such as a token shown once, its buttons always beside it. With `secret` it
|
|
95
|
+
* masks the value until the eye shows it, and copies it either way. */
|
|
96
|
+
function CopyCodeBlock({ text, label, children, secret = false, revealed: revealedProp, defaultRevealed = false, onRevealedChange, inline = false, wrap = false, className }) {
|
|
49
97
|
const { common: t } = useStrings();
|
|
50
98
|
const [ownRevealed, setOwnRevealed] = useState(defaultRevealed);
|
|
51
99
|
const revealed = revealedProp ?? ownRevealed;
|
|
@@ -63,6 +111,39 @@ function CopyCodeBlock({ text, label, children, secret = false, revealed: reveal
|
|
|
63
111
|
className: "sr-only",
|
|
64
112
|
children: t.hiddenValue
|
|
65
113
|
})] });
|
|
114
|
+
const scroller = useHiddenEnds(inline && !wrap);
|
|
115
|
+
const overflows = scroller.ends.start || scroller.ends.end;
|
|
116
|
+
const revealButton = secret && /* @__PURE__ */ jsx(IconButton, {
|
|
117
|
+
label: t.showValue,
|
|
118
|
+
icon: revealed ? /* @__PURE__ */ jsx(EyeIcon, {}) : /* @__PURE__ */ jsx(EyeOffIcon, {}),
|
|
119
|
+
pressed: revealed,
|
|
120
|
+
onClick: () => setRevealed(!revealed),
|
|
121
|
+
size: inline ? "xs" : "sm",
|
|
122
|
+
className: inline ? void 0 : cx("bg-(--theme-muted-panel-bg)", reveal)
|
|
123
|
+
});
|
|
124
|
+
if (inline) return /* @__PURE__ */ jsxs("span", {
|
|
125
|
+
className: cx("inline-flex max-w-full items-start gap-1 rounded-md border border-current/15 bg-(--theme-panel-bg)/70 py-px ps-2 pe-px align-middle", "has-[code:focus-visible]:outline-2 has-[code:focus-visible]:outline-offset-1 has-[code:focus-visible]:outline-(--theme-focus)", className),
|
|
126
|
+
children: [/* @__PURE__ */ jsx("code", {
|
|
127
|
+
ref: scroller.ref,
|
|
128
|
+
onScroll: scroller.onScroll,
|
|
129
|
+
...overflows ? {
|
|
130
|
+
tabIndex: 0,
|
|
131
|
+
role: "region",
|
|
132
|
+
"aria-label": label ?? t.codeOf("")
|
|
133
|
+
} : {},
|
|
134
|
+
style: fadeMask(scroller.ends),
|
|
135
|
+
className: cx("min-w-0 py-[3px] font-mono text-[0.8125rem] leading-[18px] text-(--theme-app)", "outline-none", "rtl:[--fade-end:left]", wrap ? "break-all whitespace-pre-wrap" : "overflow-x-auto whitespace-nowrap [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"),
|
|
136
|
+
children: shown
|
|
137
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
138
|
+
className: "flex shrink-0 items-center",
|
|
139
|
+
children: [/* @__PURE__ */ jsx(CopyButton, {
|
|
140
|
+
text,
|
|
141
|
+
label,
|
|
142
|
+
size: "xs",
|
|
143
|
+
quiet: true
|
|
144
|
+
}), revealButton]
|
|
145
|
+
})]
|
|
146
|
+
});
|
|
66
147
|
return /* @__PURE__ */ jsxs("div", {
|
|
67
148
|
className: cx("group/code relative", className),
|
|
68
149
|
children: [/* @__PURE__ */ jsx("pre", {
|
|
@@ -70,13 +151,7 @@ function CopyCodeBlock({ text, label, children, secret = false, revealed: reveal
|
|
|
70
151
|
children: shown
|
|
71
152
|
}), /* @__PURE__ */ jsxs("div", {
|
|
72
153
|
className: "absolute top-2 right-2 flex items-center gap-1",
|
|
73
|
-
children: [
|
|
74
|
-
label: t.showValue,
|
|
75
|
-
icon: revealed ? /* @__PURE__ */ jsx(EyeIcon, {}) : /* @__PURE__ */ jsx(EyeOffIcon, {}),
|
|
76
|
-
pressed: revealed,
|
|
77
|
-
onClick: () => setRevealed(!revealed),
|
|
78
|
-
className: cx("bg-(--theme-muted-panel-bg)", reveal)
|
|
79
|
-
}), /* @__PURE__ */ jsx(CopyButton, {
|
|
154
|
+
children: [revealButton, /* @__PURE__ */ jsx(CopyButton, {
|
|
80
155
|
text,
|
|
81
156
|
label,
|
|
82
157
|
className: cx("bg-(--theme-muted-panel-bg)", reveal)
|
|
@@ -40,7 +40,9 @@ interface CreateModalProps {
|
|
|
40
40
|
dirty?: boolean;
|
|
41
41
|
/** Show a favorite toggle in the footer. */
|
|
42
42
|
showFavorite?: boolean;
|
|
43
|
-
/** Muted text at the footer's start, such as which keys submit
|
|
43
|
+
/** Muted text at the footer's start, such as which keys submit, written with `Kbd` so each
|
|
44
|
+
* reader sees their own keyboard's modifier. Hidden on a touch screen, where keys mean
|
|
45
|
+
* nothing. `error` takes its place. */
|
|
44
46
|
footerHint?: ReactNode;
|
|
45
47
|
/** Why the last submit failed, at the footer's start, read out as it appears. */
|
|
46
48
|
error?: ReactNode;
|
|
@@ -6,12 +6,13 @@ import { useStrings } from "./Provider.js";
|
|
|
6
6
|
import { ActionMenu } from "./ActionMenu.js";
|
|
7
7
|
import { Button } from "./Button.js";
|
|
8
8
|
import { ErrorText } from "./Field.js";
|
|
9
|
+
import { useAutosize } from "./Input.js";
|
|
9
10
|
import { comboboxLeaves } from "./comboboxItems.js";
|
|
10
11
|
import { Combobox } from "./Combobox.js";
|
|
11
12
|
import { Modal } from "./Modal.js";
|
|
12
13
|
import { Disclosure } from "./Disclosure.js";
|
|
13
14
|
import { Switch } from "./Switch.js";
|
|
14
|
-
import { useId, useRef, useState } from "react";
|
|
15
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
15
16
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
17
|
import { Toggle } from "@base-ui/react/toggle";
|
|
17
18
|
//#region src/components/CreateModal.tsx
|
|
@@ -30,6 +31,7 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
30
31
|
const [nameTouched, setNameTouched] = useState(false);
|
|
31
32
|
const [interacted, setInteracted] = useState(false);
|
|
32
33
|
const nameRef = useRef(null);
|
|
34
|
+
const { element: nameSizer, resize: resizeName } = useAutosize(open && !hideName, name);
|
|
33
35
|
const nameMessageId = useId();
|
|
34
36
|
const session = open ? initialName ?? "" : null;
|
|
35
37
|
const [shownSession, setShownSession] = useState(session);
|
|
@@ -48,7 +50,17 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
48
50
|
const hint = !nameError && name.trim() ? nameHint?.(name.trim()) : null;
|
|
49
51
|
const canSubmit = (hideName || nameOptional || name.trim().length > 0) && !nameError && !submitting && !submitDisabled;
|
|
50
52
|
const isDirty = !submitting && (interacted || name !== (initialName ?? "") || description !== "" || favorite || dirty);
|
|
51
|
-
const nameMissing = !hideName && !nameOptional && (!name.trim() || !!nameError) &&
|
|
53
|
+
const nameMissing = !hideName && !nameOptional && (!name.trim() || !!nameError) && nameTouched;
|
|
54
|
+
const focusInside = useRef(false);
|
|
55
|
+
const leaveCheck = useRef(void 0);
|
|
56
|
+
useEffect(() => () => clearTimeout(leaveCheck.current), []);
|
|
57
|
+
const checkLeft = () => {
|
|
58
|
+
focusInside.current = false;
|
|
59
|
+
clearTimeout(leaveCheck.current);
|
|
60
|
+
leaveCheck.current = setTimeout(() => {
|
|
61
|
+
if (!focusInside.current && document.hasFocus() && !nameRef.current?.value.trim()) setNameTouched(true);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
52
64
|
const flashName = () => {
|
|
53
65
|
setNameTouched(true);
|
|
54
66
|
nameRef.current?.focus();
|
|
@@ -78,15 +90,18 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
78
90
|
size,
|
|
79
91
|
dismissible: !isDirty,
|
|
80
92
|
initialFocus: () => nameRef.current ?? true,
|
|
93
|
+
onFocus: () => {
|
|
94
|
+
focusInside.current = true;
|
|
95
|
+
},
|
|
81
96
|
onKeyDown: (e) => {
|
|
82
97
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleSubmit(true);
|
|
83
98
|
},
|
|
84
99
|
onMouseDown: (e) => {
|
|
85
|
-
if (e.target instanceof Element && !e.target.closest("input, textarea, button, a, select, label, code, pre, .select-all")) e.preventDefault();
|
|
100
|
+
if (e.target instanceof Element && !e.target.closest("input, textarea, button, a, select, label, code, pre, .select-all, [contenteditable]:not([contenteditable=\"false\"])")) e.preventDefault();
|
|
86
101
|
},
|
|
87
102
|
footer: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
88
103
|
(showFavorite || footerHint || error) && /* @__PURE__ */ jsxs("div", {
|
|
89
|
-
className: "me-auto flex min-w-0 items-center gap-3",
|
|
104
|
+
className: cx("me-auto flex min-w-0 items-center gap-3", !showFavorite && !error && "pointer-coarse:hidden"),
|
|
90
105
|
children: [showFavorite && /* @__PURE__ */ jsx(Tooltip, {
|
|
91
106
|
content: favorite ? t.favoriteHintOn : t.favoriteHintOff,
|
|
92
107
|
children: /* @__PURE__ */ jsxs(Toggle, {
|
|
@@ -100,7 +115,7 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
100
115
|
children: [favorite ? /* @__PURE__ */ jsx(FavoriteIcon, { className: "text-(--theme-favorite)" }) : /* @__PURE__ */ jsx(FavoriteOutlineIcon, {}), favorite ? t.favorited : t.favorite]
|
|
101
116
|
})
|
|
102
117
|
}), error ? /* @__PURE__ */ jsx(ErrorText, { children: error }) : footerHint && /* @__PURE__ */ jsx("p", {
|
|
103
|
-
className: "m-0 min-w-0 text-xs text-(--theme-muted-text-color)",
|
|
118
|
+
className: "m-0 min-w-0 text-xs text-(--theme-muted-text-color) pointer-coarse:hidden",
|
|
104
119
|
children: footerHint
|
|
105
120
|
})]
|
|
106
121
|
}),
|
|
@@ -141,19 +156,24 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
141
156
|
children: [typeIcon, typeLabel]
|
|
142
157
|
}),
|
|
143
158
|
hideName ? /* @__PURE__ */ jsx("div", { className: "mt-3" }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
144
|
-
/* @__PURE__ */ jsx("
|
|
145
|
-
ref:
|
|
146
|
-
|
|
159
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
160
|
+
ref: (element) => {
|
|
161
|
+
nameRef.current = element;
|
|
162
|
+
nameSizer.current = element;
|
|
163
|
+
},
|
|
164
|
+
rows: 1,
|
|
147
165
|
autoComplete: "off",
|
|
148
166
|
"data-1p-ignore": true,
|
|
149
167
|
value: name,
|
|
150
168
|
onChange: (e) => {
|
|
151
|
-
const
|
|
169
|
+
const joined = e.target.value.replace(/\s*\n+\s*/g, " ");
|
|
170
|
+
const next = sanitizeName ? sanitizeName(joined) : joined;
|
|
152
171
|
setName(next);
|
|
153
172
|
onNameChange?.(next);
|
|
173
|
+
resizeName?.();
|
|
154
174
|
},
|
|
155
175
|
onBlur: (e) => {
|
|
156
|
-
if (!e.target.value.trim())
|
|
176
|
+
if (!e.target.value.trim()) checkLeft();
|
|
157
177
|
},
|
|
158
178
|
onKeyDown: (e) => {
|
|
159
179
|
if (e.key === "Enter" && !e.nativeEvent.isComposing && !e.metaKey && !e.ctrlKey) {
|
|
@@ -168,7 +188,7 @@ function CreateModal({ open, onClose, typeIcon, typeLabel, typeMenu, typeMenuSea
|
|
|
168
188
|
"aria-invalid": nameMissing || !!nameError,
|
|
169
189
|
"aria-describedby": nameError || hint ? nameMessageId : void 0,
|
|
170
190
|
onAnimationEnd: () => setNameFlash(false),
|
|
171
|
-
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-placeholder) focus:outline-none", nameFlash && "animate-field-flash", nameMissing ? "ring-1 ring-(--theme-error)" : "focus:ring-0")
|
|
191
|
+
className: cx("mt-2 -mb-1 -mx-1.5 block w-[calc(100%+0.75rem)] resize-none overflow-hidden rounded-md border-0 px-1.5 py-1 bg-transparent shadow-none text-lg leading-snug font-medium text-(--theme-app) [field-sizing:content] placeholder:text-(--theme-placeholder) focus:outline-none", nameFlash && "animate-field-flash", nameMissing ? "ring-1 ring-(--theme-error)" : "focus:ring-0")
|
|
172
192
|
}),
|
|
173
193
|
nameError && /* @__PURE__ */ jsx("p", {
|
|
174
194
|
id: nameMessageId,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { Tooltip } from "./Tooltip.js";
|
|
3
3
|
import { useStrings } from "./Provider.js";
|
|
4
|
-
import { InfoTip } from "./InfoTip.js";
|
|
5
4
|
import { CopyButton } from "./CopyButton.js";
|
|
5
|
+
import { InfoTip } from "./InfoTip.js";
|
|
6
6
|
import { withPathBreaks } from "./pathBreaks.js";
|
|
7
7
|
import { createContext, useContext, useId, useRef } from "react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -47,7 +47,7 @@ function Drawer$1({ open, onClose, title, description, onBack, backLabel, footer
|
|
|
47
47
|
container: contained ? container : portal.container,
|
|
48
48
|
keepMounted,
|
|
49
49
|
className: contained ? "contents" : portal.className,
|
|
50
|
-
children: [modal !== false && /* @__PURE__ */ jsx(Drawer.Backdrop, { className: cx(area, "z-(--layer-drawer) bg-
|
|
50
|
+
children: [modal !== false && /* @__PURE__ */ jsx(Drawer.Backdrop, { className: cx(area, "z-(--layer-drawer) bg-(--theme-backdrop) opacity-[calc(1-var(--drawer-swipe-progress))] transition-opacity duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-swiping:duration-0 motion-reduce:transition-none") }), /* @__PURE__ */ jsx(Drawer.Viewport, {
|
|
51
51
|
ref: viewport,
|
|
52
52
|
className: cx(area, "pointer-events-none z-(--layer-drawer) flex", side === "right" ? "justify-end pl-[max(var(--app-inset-start,0px),2.5rem)]" : "justify-start pl-(--app-inset-start,0px) pr-10"),
|
|
53
53
|
children: /* @__PURE__ */ jsxs(Drawer.Popup, {
|
|
@@ -46,6 +46,11 @@ export declare function framed({ label, hint, help, actions, description, error,
|
|
|
46
46
|
/** A single-line text field. `type="password"` adds a button that shows what was typed. Placed in
|
|
47
47
|
* a Field, it takes the Field's label, description and invalid state. */
|
|
48
48
|
export declare function Input({ label, hint, help, description, error, className, mono, size, type, ref, ...props }: InputProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
49
|
+
/** Sets a textarea's height to its text's while the browser can't, from its value. */
|
|
50
|
+
export declare function useAutosize(enabled: boolean, value: unknown): {
|
|
51
|
+
element: import("react").RefObject<HTMLTextAreaElement | null>;
|
|
52
|
+
resize: (() => void) | undefined;
|
|
53
|
+
};
|
|
49
54
|
/** A multi-line text field that grows by hand, or with its text with `autosize`. Placed in a
|
|
50
55
|
* Field, it takes the Field's label, description and invalid state. */
|
|
51
56
|
export declare function Textarea({ label, hint, help, description, error, className, mono, size, ref, autosize, bare, secret, style, ...props }: TextareaProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
package/dist/components/Input.js
CHANGED
|
@@ -168,7 +168,7 @@ function TitleInput({ value, onCommit, autoSelect = false, size = "xl", readOnly
|
|
|
168
168
|
setShown(value);
|
|
169
169
|
if (!editing.current) setDraft(value);
|
|
170
170
|
}
|
|
171
|
-
const { resize } = useAutosize(true, draft);
|
|
171
|
+
const { element: sizer, resize } = useAutosize(true, draft);
|
|
172
172
|
useEffect(() => {
|
|
173
173
|
if (autoSelect && element.current) {
|
|
174
174
|
element.current.focus();
|
|
@@ -177,9 +177,10 @@ function TitleInput({ value, onCommit, autoSelect = false, size = "xl", readOnly
|
|
|
177
177
|
}, []);
|
|
178
178
|
const setRef = useCallback((el) => {
|
|
179
179
|
element.current = el;
|
|
180
|
+
sizer.current = el;
|
|
180
181
|
if (typeof ref === "function") ref(el);
|
|
181
182
|
else if (ref) ref.current = el;
|
|
182
|
-
}, [ref]);
|
|
183
|
+
}, [ref, sizer]);
|
|
183
184
|
return /* @__PURE__ */ jsx("textarea", {
|
|
184
185
|
...props,
|
|
185
186
|
ref: setRef,
|
|
@@ -218,4 +219,4 @@ function TitleInput({ value, onCommit, autoSelect = false, size = "xl", readOnly
|
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
221
|
//#endregion
|
|
221
|
-
export { Input$1 as Input, Textarea, TitleInput, framed };
|
|
222
|
+
export { Input$1 as Input, Textarea, TitleInput, framed, useAutosize };
|
|
@@ -6,7 +6,9 @@ export interface ListboxNavigationOptions<T> {
|
|
|
6
6
|
onChoose: (item: T, index: number) => void;
|
|
7
7
|
/** Called on Escape, such as to close the list until the text changes. */
|
|
8
8
|
onDismiss?: (() => void) | undefined;
|
|
9
|
-
/** False while the list isn't shown: the keys are then the host's own.
|
|
9
|
+
/** False while the list isn't shown: the keys are then the host's own. A list that hides
|
|
10
|
+
* itself while empty passes false then too, or Escape dismisses what isn't there. Default
|
|
11
|
+
* true. */
|
|
10
12
|
open?: boolean | undefined;
|
|
11
13
|
/** Past the end comes the start, and before the start the end. Default true. */
|
|
12
14
|
loop?: boolean | undefined;
|
|
@@ -91,10 +93,17 @@ export interface ListboxOptionProps {
|
|
|
91
93
|
inline?: boolean | undefined;
|
|
92
94
|
/** Short muted text at the row's end, such as a key. */
|
|
93
95
|
hint?: ReactNode;
|
|
96
|
+
/** In a list of choices that stay chosen, such as the labels on an issue: true shows the
|
|
97
|
+
* check at the row's end and tells assistive technology, false leaves it unchecked. Leave
|
|
98
|
+
* it out for a list that only acts. */
|
|
99
|
+
checked?: boolean | undefined;
|
|
100
|
+
/** The option opens more choices, such as a submenu or a next step: a chevron ends the row. */
|
|
101
|
+
submenu?: boolean | undefined;
|
|
94
102
|
className?: string | undefined;
|
|
95
103
|
}
|
|
96
|
-
/** One option of a ListboxPanel: an icon, its label and description, and
|
|
97
|
-
|
|
104
|
+
/** One option of a ListboxPanel: an icon, its label and description, and at its end a hint, a
|
|
105
|
+
* check while it is chosen and a chevron when it opens more. */
|
|
106
|
+
export declare function ListboxOption({ option, icon, label, description, inline, hint, checked, submenu, className, }: ListboxOptionProps): import("react").JSX.Element;
|
|
98
107
|
/** Options under a heading in a ListboxPanel. */
|
|
99
108
|
export declare function ListboxGroup({ label, children }: {
|
|
100
109
|
label: ReactNode;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
+
import { CheckIcon, ChevronRightIcon } from "../icons.js";
|
|
2
3
|
import { panelClassName, panelItemClassName } from "./floating.js";
|
|
3
4
|
import { Popover } from "./Popover.js";
|
|
4
5
|
import "./comboboxItems.js";
|
|
5
|
-
import { useEffect, useId, useState } from "react";
|
|
6
|
+
import { Children, useEffect, useId, useState } from "react";
|
|
6
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
//#region src/components/Listbox.tsx
|
|
8
9
|
/** The parts a highlighted list needs while focus stays on the box the reader types in, such
|
|
@@ -44,7 +45,14 @@ function useListboxNavigation({ items, onChoose, onDismiss, open = true, loop =
|
|
|
44
45
|
/** Handles a key the list owns, and says whether it did; leave the rest to the host. */
|
|
45
46
|
const handleKey = (event) => {
|
|
46
47
|
const composing = "nativeEvent" in event ? event.nativeEvent.isComposing : event.isComposing;
|
|
47
|
-
if (!
|
|
48
|
+
if (!open || composing) return false;
|
|
49
|
+
if (event.key === "Escape") {
|
|
50
|
+
if (!onDismiss) return false;
|
|
51
|
+
onDismiss();
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (!shownOpen) return false;
|
|
48
56
|
const ctrlOnly = event.ctrlKey && !event.metaKey && !event.altKey;
|
|
49
57
|
switch (true) {
|
|
50
58
|
case event.key === "ArrowDown" || ctrlOnly && event.key === "n":
|
|
@@ -59,10 +67,6 @@ function useListboxNavigation({ items, onChoose, onDismiss, open = true, loop =
|
|
|
59
67
|
case homeEnd && event.key === "End":
|
|
60
68
|
setActive(step(count, -1));
|
|
61
69
|
break;
|
|
62
|
-
case event.key === "Escape":
|
|
63
|
-
if (!onDismiss) return false;
|
|
64
|
-
onDismiss();
|
|
65
|
-
break;
|
|
66
70
|
case event.key === "Enter" || chooseKeys.includes(event.key):
|
|
67
71
|
if (event.shiftKey || event.altKey || event.metaKey || event.ctrlKey) return false;
|
|
68
72
|
choose(shown);
|
|
@@ -110,7 +114,7 @@ function useListboxNavigation({ items, onChoose, onDismiss, open = true, loop =
|
|
|
110
114
|
}
|
|
111
115
|
/** The panel of a highlighted list that the reader drives from a box that keeps focus. */
|
|
112
116
|
function ListboxPanel({ listProps, "aria-label": label, footer, empty, at, onDismiss, className, children }) {
|
|
113
|
-
const hasOptions =
|
|
117
|
+
const hasOptions = Children.toArray(children).length > 0;
|
|
114
118
|
const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
115
119
|
id: listProps.id,
|
|
116
120
|
role: "listbox",
|
|
@@ -143,11 +147,17 @@ function ListboxPanel({ listProps, "aria-label": label, footer, empty, at, onDis
|
|
|
143
147
|
children: body
|
|
144
148
|
});
|
|
145
149
|
}
|
|
146
|
-
/** One option of a ListboxPanel: an icon, its label and description, and
|
|
147
|
-
|
|
150
|
+
/** One option of a ListboxPanel: an icon, its label and description, and at its end a hint, a
|
|
151
|
+
* check while it is chosen and a chevron when it opens more. */
|
|
152
|
+
function ListboxOption({ option, icon, label, description, inline = false, hint, checked, submenu = false, className }) {
|
|
153
|
+
const checkable = checked !== void 0;
|
|
148
154
|
return /* @__PURE__ */ jsxs("div", {
|
|
149
155
|
...option,
|
|
150
|
-
|
|
156
|
+
role: "option",
|
|
157
|
+
tabIndex: -1,
|
|
158
|
+
"aria-checked": checked,
|
|
159
|
+
"data-checked": checked || void 0,
|
|
160
|
+
className: cx(panelItemClassName, inline && "items-baseline", checked && "font-medium", className),
|
|
151
161
|
children: [
|
|
152
162
|
icon && /* @__PURE__ */ jsx("span", {
|
|
153
163
|
className: "flex shrink-0 items-center self-center",
|
|
@@ -163,12 +173,25 @@ function ListboxOption({ option, icon, label, description, inline = false, hint,
|
|
|
163
173
|
children: description
|
|
164
174
|
})]
|
|
165
175
|
}),
|
|
166
|
-
hint && /* @__PURE__ */
|
|
176
|
+
(hint || checkable || submenu) && /* @__PURE__ */ jsxs("span", {
|
|
167
177
|
className: "ml-auto flex h-[1lh] shrink-0 items-center gap-2 self-start pl-2",
|
|
168
|
-
children:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
children: [
|
|
179
|
+
hint && /* @__PURE__ */ jsx("span", {
|
|
180
|
+
className: "text-xs tabular-nums text-(--theme-muted-text-color)",
|
|
181
|
+
children: hint
|
|
182
|
+
}),
|
|
183
|
+
checkable && (checked || hint) && /* @__PURE__ */ jsx("span", {
|
|
184
|
+
className: cx("flex items-center", hint && "w-3.5"),
|
|
185
|
+
children: checked && /* @__PURE__ */ jsx(CheckIcon, {
|
|
186
|
+
"aria-hidden": "true",
|
|
187
|
+
className: "size-3.5"
|
|
188
|
+
})
|
|
189
|
+
}),
|
|
190
|
+
submenu && /* @__PURE__ */ jsx(ChevronRightIcon, {
|
|
191
|
+
"aria-hidden": "true",
|
|
192
|
+
className: "size-3 opacity-60"
|
|
193
|
+
})
|
|
194
|
+
]
|
|
172
195
|
})
|
|
173
196
|
]
|
|
174
197
|
});
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
+
import { CodeBlock } from "./CodeBlock.js";
|
|
2
3
|
import { ExternalLink } from "./ExternalLink.js";
|
|
3
4
|
import { readIsDark } from "./useCssIsDark.js";
|
|
4
5
|
import { CODE_THEMES } from "./codeTheme.js";
|
|
5
6
|
import { rehypeHttpsImagesOnly } from "./httpsImages.js";
|
|
6
7
|
import { rehypeCodeBreaks } from "./markdownCodeBreaks.js";
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
8
|
+
import { useEffect, useMemo, useState } from "react";
|
|
8
9
|
import { jsx } from "react/jsx-runtime";
|
|
9
10
|
import { code } from "@streamdown/code";
|
|
10
11
|
import { math } from "@streamdown/math";
|
|
11
12
|
import "katex/dist/katex.min.css";
|
|
12
|
-
import { Streamdown, defaultRehypePlugins } from "streamdown";
|
|
13
|
+
import { Streamdown, defaultComponents, defaultRehypePlugins, useIsCodeFenceIncomplete } from "streamdown";
|
|
13
14
|
//#region src/components/MarkdownImpl.tsx
|
|
14
15
|
var basePlugins = {
|
|
15
16
|
code,
|
|
@@ -35,6 +36,81 @@ function loadMermaid() {
|
|
|
35
36
|
}
|
|
36
37
|
var rehypePlugins = [...Object.values(defaultRehypePlugins), rehypeCodeBreaks];
|
|
37
38
|
var httpsImagesRehypePlugins = [...Object.entries(defaultRehypePlugins).flatMap(([name, plugin]) => name === "harden" ? [rehypeHttpsImagesOnly, plugin] : [plugin]), rehypeCodeBreaks];
|
|
39
|
+
function codeControls(controls) {
|
|
40
|
+
if (controls === false) return {
|
|
41
|
+
copy: false,
|
|
42
|
+
download: null
|
|
43
|
+
};
|
|
44
|
+
const code = controls === void 0 || controls === true ? true : controls.code;
|
|
45
|
+
if (code === false) return {
|
|
46
|
+
copy: false,
|
|
47
|
+
download: null
|
|
48
|
+
};
|
|
49
|
+
if (code === void 0 || code === true) return {
|
|
50
|
+
copy: true,
|
|
51
|
+
download: "file"
|
|
52
|
+
};
|
|
53
|
+
const { download } = code;
|
|
54
|
+
return {
|
|
55
|
+
copy: code.copy !== false,
|
|
56
|
+
download: download === false ? null : typeof download === "object" ? download.filename : "file"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var EXTENSIONS = {
|
|
60
|
+
javascript: "js",
|
|
61
|
+
typescript: "ts",
|
|
62
|
+
python: "py",
|
|
63
|
+
ruby: "rb",
|
|
64
|
+
rust: "rs",
|
|
65
|
+
golang: "go",
|
|
66
|
+
bash: "sh",
|
|
67
|
+
shell: "sh",
|
|
68
|
+
shellscript: "sh",
|
|
69
|
+
zsh: "sh",
|
|
70
|
+
console: "sh",
|
|
71
|
+
markdown: "md",
|
|
72
|
+
text: "txt",
|
|
73
|
+
plaintext: "txt",
|
|
74
|
+
csharp: "cs",
|
|
75
|
+
kotlin: "kt",
|
|
76
|
+
powershell: "ps1",
|
|
77
|
+
dockerfile: "Dockerfile"
|
|
78
|
+
};
|
|
79
|
+
function extensionFor(language) {
|
|
80
|
+
const lang = language.toLowerCase();
|
|
81
|
+
return EXTENSIONS[lang] ?? (/^[a-z0-9+]{1,10}$/.test(lang) ? lang : "txt");
|
|
82
|
+
}
|
|
83
|
+
var LANGUAGE = /language-([^\s]+)/;
|
|
84
|
+
var START_LINE = /startLine=(\d+)/;
|
|
85
|
+
var NO_LINE_NUMBERS = /\bnoLineNumbers\b/;
|
|
86
|
+
var DefaultCode = defaultComponents.code;
|
|
87
|
+
function textOf(children) {
|
|
88
|
+
if (typeof children === "string") return children;
|
|
89
|
+
if (Array.isArray(children)) return children.map(textOf).join("");
|
|
90
|
+
if (children && typeof children === "object" && "props" in children) return textOf(children.props.children);
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
function makeCode(controls, diagrams) {
|
|
94
|
+
return function MarkdownCode(props) {
|
|
95
|
+
const incomplete = useIsCodeFenceIncomplete();
|
|
96
|
+
const language = props.className?.match(LANGUAGE)?.[1] ?? "";
|
|
97
|
+
if (!("data-block" in props) || diagrams && language === "mermaid") return /* @__PURE__ */ jsx(DefaultCode, { ...props });
|
|
98
|
+
const meta = props.node?.properties?.["metastring"];
|
|
99
|
+
const metastring = typeof meta === "string" ? meta : "";
|
|
100
|
+
const start = Number.parseInt(metastring.match(START_LINE)?.[1] ?? "", 10);
|
|
101
|
+
return /* @__PURE__ */ jsx(CodeBlock, {
|
|
102
|
+
className: "my-3.5",
|
|
103
|
+
code: textOf(props.children),
|
|
104
|
+
language,
|
|
105
|
+
copy: controls.copy,
|
|
106
|
+
filename: controls.download === null ? void 0 : `${controls.download}.${extensionFor(language)}`,
|
|
107
|
+
lineNumbers: NO_LINE_NUMBERS.test(metastring) ? false : void 0,
|
|
108
|
+
startLine: start >= 1 ? start : 1,
|
|
109
|
+
maxHeight: 400,
|
|
110
|
+
streaming: incomplete
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
}
|
|
38
114
|
function MarkdownImpl({ children, isStreaming, controls, components, httpsImagesOnly, compact }) {
|
|
39
115
|
const needsMermaid = !!children && children.includes("```mermaid");
|
|
40
116
|
const [, setMermaidReady] = useState(() => !!pluginsWithMermaid);
|
|
@@ -49,6 +125,16 @@ function MarkdownImpl({ children, isStreaming, controls, components, httpsImages
|
|
|
49
125
|
};
|
|
50
126
|
}, [needsMermaid]);
|
|
51
127
|
const plugins = needsMermaid && pluginsWithMermaid ? pluginsWithMermaid : basePlugins;
|
|
128
|
+
const { copy, download } = codeControls(controls);
|
|
129
|
+
const diagrams = plugins === pluginsWithMermaid;
|
|
130
|
+
const code = useMemo(() => makeCode({
|
|
131
|
+
copy,
|
|
132
|
+
download
|
|
133
|
+
}, diagrams), [
|
|
134
|
+
copy,
|
|
135
|
+
download,
|
|
136
|
+
diagrams
|
|
137
|
+
]);
|
|
52
138
|
return /* @__PURE__ */ jsx("div", {
|
|
53
139
|
className: cx("markdown whitespace-normal text-start w-full", compact && "markdown-compact"),
|
|
54
140
|
children: /* @__PURE__ */ jsx(Streamdown, {
|
|
@@ -63,6 +149,7 @@ function MarkdownImpl({ children, isStreaming, controls, components, httpsImages
|
|
|
63
149
|
rehypePlugins: httpsImagesOnly ? httpsImagesRehypePlugins : rehypePlugins,
|
|
64
150
|
shikiTheme: CODE_THEMES,
|
|
65
151
|
components: {
|
|
152
|
+
code,
|
|
66
153
|
a: ({ node, ...props }) => /* @__PURE__ */ jsx(ExternalLink, {
|
|
67
154
|
...props,
|
|
68
155
|
className: cx("link wrap-break-word", props.className)
|
|
@@ -9,6 +9,9 @@ interface MenuActionBase {
|
|
|
9
9
|
/** The key that does the same from the page, such as `S` or `⌘K`, in plain text at the
|
|
10
10
|
* row's end. The menu doesn't bind it; the host does. */
|
|
11
11
|
shortcut?: string | undefined;
|
|
12
|
+
/** Muted text at the row's end that tells rows apart, such as a team's key `CORE`. It is
|
|
13
|
+
* read with the label, and a menu's search matches it. For a key to press, use `shortcut`. */
|
|
14
|
+
hint?: string | undefined;
|
|
12
15
|
/** A small mark at the row's end, such as a dot for something unseen. It is hidden from
|
|
13
16
|
* screen readers, so say what it means in `label`. */
|
|
14
17
|
badge?: ReactNode;
|
|
@@ -121,7 +121,7 @@ function SearchedEntries({ entries, search, query }) {
|
|
|
121
121
|
const matches = useQueryMatch();
|
|
122
122
|
if (!search) return /* @__PURE__ */ jsx(EntryRows, { entries });
|
|
123
123
|
const needle = query.trim();
|
|
124
|
-
const shown = needle ? searchMatches(entries, (a) => matches(needle, a.label, a.description, a.keywords), (submenu) => matches(needle, submenu.label, submenu.keywords)) : entries;
|
|
124
|
+
const shown = needle ? searchMatches(entries, (a) => matches(needle, a.label, a.description, a.keywords, a.hint), (submenu) => matches(needle, submenu.label, submenu.keywords)) : entries;
|
|
125
125
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
126
126
|
/* @__PURE__ */ jsx("div", {
|
|
127
127
|
className: "sticky top-0 z-[1] bg-(--theme-app-bg) px-1 pt-0.5 pb-1",
|
|
@@ -183,6 +183,7 @@ function RowEnd({ children, className }) {
|
|
|
183
183
|
children
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
|
+
var hintClassName = "ps-3 text-xs text-(--theme-muted-text-color) in-data-[size=sm]:text-[11px]";
|
|
186
187
|
var shortcutClassName = "ps-3 text-xs text-(--theme-muted-text-color) tabular-nums in-data-[size=sm]:text-[11px]";
|
|
187
188
|
/** A row's icon, label, second line and end details, laid out alike in every kind of row. */
|
|
188
189
|
function RowContent({ icon, label, description, end }) {
|
|
@@ -290,11 +291,19 @@ function ActionRow({ action }) {
|
|
|
290
291
|
const runAction = useRunAction();
|
|
291
292
|
const className = cx(action.description && "items-start", action.destructive && destructiveClassName, action.current && "font-medium");
|
|
292
293
|
const keyshortcuts = ariaKeyShortcut(action.shortcut);
|
|
294
|
+
const heard = action.hint && /* @__PURE__ */ jsxs("span", {
|
|
295
|
+
className: "sr-only",
|
|
296
|
+
children: [". ", action.hint]
|
|
297
|
+
});
|
|
293
298
|
const end = (trailing) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
294
299
|
action.badge !== void 0 && action.badge !== null && action.badge !== false && /* @__PURE__ */ jsx(RowEnd, {
|
|
295
300
|
className: "ps-2",
|
|
296
301
|
children: action.badge
|
|
297
302
|
}),
|
|
303
|
+
action.hint && /* @__PURE__ */ jsx(RowEnd, {
|
|
304
|
+
className: hintClassName,
|
|
305
|
+
children: action.hint
|
|
306
|
+
}),
|
|
298
307
|
action.shortcut && /* @__PURE__ */ jsx(RowEnd, {
|
|
299
308
|
className: shortcutClassName,
|
|
300
309
|
children: action.shortcut
|
|
@@ -314,7 +323,7 @@ function ActionRow({ action }) {
|
|
|
314
323
|
className,
|
|
315
324
|
children: /* @__PURE__ */ jsx(RowContent, {
|
|
316
325
|
icon: action.icon,
|
|
317
|
-
label: action.label,
|
|
326
|
+
label: /* @__PURE__ */ jsxs(Fragment$1, { children: [action.label, heard] }),
|
|
318
327
|
description: action.description,
|
|
319
328
|
end: end(action.current ? /* @__PURE__ */ jsx(RowEnd, {
|
|
320
329
|
className: "ps-2",
|
|
@@ -330,10 +339,14 @@ function ActionRow({ action }) {
|
|
|
330
339
|
const reason = action.disabled ? action.disabledReason : void 0;
|
|
331
340
|
const content = (trailing) => /* @__PURE__ */ jsx(RowContent, {
|
|
332
341
|
icon: action.icon,
|
|
333
|
-
label: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
342
|
+
label: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
343
|
+
action.label,
|
|
344
|
+
heard,
|
|
345
|
+
reason && /* @__PURE__ */ jsxs("span", {
|
|
346
|
+
className: "sr-only",
|
|
347
|
+
children: [". ", reason]
|
|
348
|
+
})
|
|
349
|
+
] }),
|
|
337
350
|
description: action.description,
|
|
338
351
|
end: end(trailing)
|
|
339
352
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Dialog } from '@base-ui/react/dialog';
|
|
2
2
|
import { type FormEvent, type ReactNode } from 'react';
|
|
3
3
|
/** The panel a modal draws by default; pass `panel={false}` to paint your own. */
|
|
4
|
-
export declare const modalPanelClassName = "rounded-xl border border-(--theme-border) bg-(--theme-
|
|
4
|
+
export declare const modalPanelClassName = "rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) shadow-2xl";
|
|
5
5
|
/** Names the modal for assistive technology; renders an `<h2>`. */
|
|
6
6
|
export declare const ModalTitle: import("react").ForwardRefExoticComponent<Omit<import("@base-ui/react").DialogTitleProps, "ref"> & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
7
7
|
/** Describes the modal for assistive technology; renders a `<p>`. */
|