@estiva-app/ui 0.58.0 → 0.60.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/AppProvider.d.ts +47 -0
- package/dist/AppProvider.d.ts.map +1 -0
- package/dist/AppShell.d.ts +6 -2
- package/dist/AppShell.d.ts.map +1 -1
- package/dist/Avatar.d.ts +1 -1
- package/dist/Avatar.d.ts.map +1 -1
- package/dist/Chip.d.ts.map +1 -1
- package/dist/CommandPalette.d.ts.map +1 -1
- package/dist/ComposerTriggers.d.ts +13 -1
- package/dist/ComposerTriggers.d.ts.map +1 -1
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/InlineChip.d.ts.map +1 -1
- package/dist/Kbd.d.ts.map +1 -1
- package/dist/Link.d.ts +1 -1
- package/dist/Link.d.ts.map +1 -1
- package/dist/MembersDialog.d.ts +57 -0
- package/dist/MembersDialog.d.ts.map +1 -0
- package/dist/MembersPill.d.ts +22 -0
- package/dist/MembersPill.d.ts.map +1 -0
- package/dist/NavItem.d.ts +1 -1
- package/dist/NavItem.d.ts.map +1 -1
- package/dist/RailItem.d.ts +1 -1
- package/dist/RailItem.d.ts.map +1 -1
- package/dist/SearchInput.d.ts +3 -3
- package/dist/Tabs.d.ts +2 -0
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TopBar.d.ts +14 -3
- package/dist/TopBar.d.ts.map +1 -1
- package/dist/editor.js +4 -4
- package/dist/editor.js.map +2 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1332 -1143
- package/dist/index.js.map +4 -4
- package/dist/looks.d.ts +2 -0
- package/dist/looks.d.ts.map +1 -1
- package/dist/registry/{app-LDGOH6UW.js → app-X2GI4WTU.js} +2 -2
- package/dist/registry/app.d.ts.map +1 -1
- package/dist/registry/{chunk-TQ6UQER3.js → chunk-V67F474L.js} +8 -3
- package/dist/registry/chunk-V67F474L.js.map +7 -0
- package/dist/registry/cli.js +1 -1
- package/dist/registry/index.js +1 -1
- package/package.json +1 -1
- package/registry.json +234 -14
- package/skill/estiva-ui.md +2 -1
- package/src/AppProvider.mdx +69 -0
- package/src/AppProvider.stories.tsx +60 -0
- package/src/AppProvider.test.tsx +152 -0
- package/src/AppProvider.tsx +76 -0
- package/src/AppShell.mdx +4 -1
- package/src/AppShell.stories.tsx +5 -5
- package/src/AppShell.tsx +7 -3
- package/src/Avatar.tsx +7 -3
- package/src/Breadcrumb.mdx +2 -2
- package/src/Card.mdx +1 -1
- package/src/Chip.mdx +2 -2
- package/src/Chip.tsx +3 -1
- package/src/CommandPalette.tsx +2 -1
- package/src/ComposerTriggers.mdx +7 -0
- package/src/ComposerTriggers.stories.tsx +43 -4
- package/src/ComposerTriggers.test.tsx +33 -0
- package/src/ComposerTriggers.tsx +17 -5
- package/src/IconButton.mdx +2 -2
- package/src/IconButton.tsx +4 -1
- package/src/InlineChip.mdx +3 -3
- package/src/InlineChip.tsx +3 -1
- package/src/Kbd.tsx +4 -2
- package/src/Link.mdx +5 -3
- package/src/Link.tsx +4 -1
- package/src/MembersDialog.mdx +69 -0
- package/src/MembersDialog.stories.tsx +68 -0
- package/src/MembersDialog.test.tsx +69 -0
- package/src/MembersDialog.tsx +184 -0
- package/src/MembersPill.mdx +45 -0
- package/src/MembersPill.stories.tsx +38 -0
- package/src/MembersPill.tsx +35 -0
- package/src/NavItem.mdx +3 -3
- package/src/NavItem.tsx +4 -0
- package/src/NavTree.mdx +3 -2
- package/src/RailItem.mdx +3 -3
- package/src/RailItem.tsx +4 -1
- package/src/SearchInput.mdx +3 -4
- package/src/SearchInput.tsx +3 -3
- package/src/Sidebar.mdx +2 -2
- package/src/Tabs.mdx +5 -0
- package/src/Tabs.stories.tsx +15 -0
- package/src/Tabs.test.tsx +8 -0
- package/src/Tabs.tsx +12 -0
- package/src/TopBar.mdx +18 -9
- package/src/TopBar.stories.tsx +22 -4
- package/src/TopBar.test.tsx +97 -0
- package/src/TopBar.tsx +45 -4
- package/src/index.ts +3 -0
- package/src/looks.ts +3 -0
- package/src/pages.test.ts +3 -1
- package/src/registry/app.test.ts +24 -6
- package/src/registry/app.ts +21 -2
- package/src/registry/contract.test.ts +1 -1
- package/src/registry/gated.test.ts +1 -0
- package/src/registry/registry.test.ts +4 -4
- package/stories/Choosing.mdx +4 -0
- package/dist/registry/chunk-TQ6UQER3.js.map +0 -7
- /package/dist/registry/{app-LDGOH6UW.js.map → app-X2GI4WTU.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
// src/AppProvider.tsx
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
var Setup = createContext({});
|
|
5
|
+
function AppProvider({ pictureFor, navigate, children }) {
|
|
6
|
+
const value = useMemo(() => ({ pictureFor, navigate }), [pictureFor, navigate]);
|
|
7
|
+
return /* @__PURE__ */ jsx(Setup.Provider, { value, children });
|
|
8
|
+
}
|
|
9
|
+
function usePictureFor() {
|
|
10
|
+
return useContext(Setup).pictureFor;
|
|
11
|
+
}
|
|
12
|
+
function useInAppClick(href, onClick) {
|
|
13
|
+
const navigate = useContext(Setup).navigate;
|
|
14
|
+
if (!navigate || href === void 0) return onClick;
|
|
15
|
+
return (event) => {
|
|
16
|
+
onClick?.(event);
|
|
17
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
18
|
+
const link = event.currentTarget;
|
|
19
|
+
const target = link.getAttribute("target");
|
|
20
|
+
if (target && target !== "_self" || link.hasAttribute("download")) return;
|
|
21
|
+
let url;
|
|
22
|
+
try {
|
|
23
|
+
url = new URL(href, window.location.href);
|
|
24
|
+
} catch {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (url.origin !== window.location.origin) return;
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
navigate(href);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
1
33
|
// src/cn.ts
|
|
2
34
|
import { clsx } from "clsx";
|
|
3
35
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
@@ -36,7 +68,7 @@ function cn(...inputs) {
|
|
|
36
68
|
}
|
|
37
69
|
|
|
38
70
|
// src/Link.tsx
|
|
39
|
-
import { jsx } from "react/jsx-runtime";
|
|
71
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
40
72
|
var COVER_CLASSES = "after:absolute after:inset-0 after:rounded-md focus-visible:outline-none focus-visible:after:[outline-style:auto]";
|
|
41
73
|
var VARIANT_CLASSES = {
|
|
42
74
|
text: "text-info-default underline underline-offset-2 hover:opacity-80",
|
|
@@ -44,21 +76,23 @@ var VARIANT_CLASSES = {
|
|
|
44
76
|
underlined: "underline underline-offset-2 hover:text-text-primary",
|
|
45
77
|
plain: ""
|
|
46
78
|
};
|
|
47
|
-
function Link({ href, variant = "text", external = false, truncate = false, cover = false, className, children, ...props }) {
|
|
48
|
-
|
|
79
|
+
function Link({ href, variant = "text", external = false, truncate = false, cover = false, className, children, onClick, ...props }) {
|
|
80
|
+
const inApp = useInAppClick(href, onClick);
|
|
81
|
+
return /* @__PURE__ */ jsx2(
|
|
49
82
|
"a",
|
|
50
83
|
{
|
|
51
84
|
href,
|
|
52
85
|
...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
|
|
53
86
|
className: cn(VARIANT_CLASSES[variant], truncate && "truncate", cover && COVER_CLASSES, className),
|
|
54
87
|
...props,
|
|
88
|
+
onClick: inApp,
|
|
55
89
|
children
|
|
56
90
|
}
|
|
57
91
|
);
|
|
58
92
|
}
|
|
59
93
|
|
|
60
94
|
// src/Card.tsx
|
|
61
|
-
import { jsx as
|
|
95
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
62
96
|
var FILL_CLASSES = {
|
|
63
97
|
surface: "bg-bg-surface border-border-default",
|
|
64
98
|
elevated: "bg-bg-elevated border-border-default",
|
|
@@ -121,25 +155,25 @@ function Card({
|
|
|
121
155
|
const { ref, ...anchorProps } = props;
|
|
122
156
|
return (
|
|
123
157
|
// @estiva-escape(no-copied-look, no-restyled-part): a card that leads somewhere is drawn on Link's anchor (UIG-27 ruling 1), so this frame is Card's own look, not Link restyled
|
|
124
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ jsx3(Link, { href, variant: "plain", ref, className: classes, ...anchorProps, children })
|
|
125
159
|
);
|
|
126
160
|
}
|
|
127
161
|
return (
|
|
128
162
|
// @estiva-escape(no-copied-look): N6 (Katerina, 24 September: leave alone): a card that cuts its content to its corners shares four words with the palette's window by coincidence
|
|
129
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ jsx3("div", { className: classes, ...props, children })
|
|
130
164
|
);
|
|
131
165
|
}
|
|
132
166
|
|
|
133
167
|
// src/ScrollArea.tsx
|
|
134
168
|
import { ScrollArea as BaseScrollArea } from "@base-ui/react/scroll-area";
|
|
135
|
-
import { jsx as
|
|
169
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
136
170
|
var BAR = "z-10 flex touch-none select-none rounded-full opacity-0 transition-opacity delay-300 data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0";
|
|
137
171
|
var THUMB = "rounded-full bg-border-strong";
|
|
138
172
|
function ScrollArea({ orientation = "vertical", className, viewportClassName, contentClassName, viewportRef, onScroll, children }) {
|
|
139
173
|
const vertical = orientation !== "horizontal";
|
|
140
174
|
const horizontal = orientation !== "vertical";
|
|
141
175
|
return /* @__PURE__ */ jsxs(BaseScrollArea.Root, { className: cn("relative min-h-0 min-w-0", className), children: [
|
|
142
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ jsx4(
|
|
143
177
|
BaseScrollArea.Viewport,
|
|
144
178
|
{
|
|
145
179
|
ref: viewportRef,
|
|
@@ -148,35 +182,114 @@ function ScrollArea({ orientation = "vertical", className, viewportClassName, co
|
|
|
148
182
|
"h-full w-full outline-none data-[has-overflow-x]:overscroll-x-contain data-[has-overflow-y]:overscroll-y-contain",
|
|
149
183
|
viewportClassName
|
|
150
184
|
),
|
|
151
|
-
children: /* @__PURE__ */
|
|
185
|
+
children: /* @__PURE__ */ jsx4(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
|
|
152
186
|
}
|
|
153
187
|
),
|
|
154
|
-
vertical && /* @__PURE__ */
|
|
155
|
-
horizontal && /* @__PURE__ */
|
|
156
|
-
vertical && horizontal && /* @__PURE__ */
|
|
188
|
+
vertical && /* @__PURE__ */ jsx4(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5 data-[has-overflow-y]:opacity-100"), children: /* @__PURE__ */ jsx4(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
|
|
189
|
+
horizontal && /* @__PURE__ */ jsx4(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5 data-[has-overflow-x]:opacity-100"), children: /* @__PURE__ */ jsx4(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
|
|
190
|
+
vertical && horizontal && /* @__PURE__ */ jsx4(BaseScrollArea.Corner, {})
|
|
157
191
|
] });
|
|
158
192
|
}
|
|
159
193
|
|
|
160
194
|
// src/Sidebar.tsx
|
|
161
|
-
import { createContext, useContext } from "react";
|
|
162
|
-
import { jsx as
|
|
163
|
-
var SidebarOnGround =
|
|
195
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
196
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
197
|
+
var SidebarOnGround = createContext2(false);
|
|
164
198
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
165
|
-
const onGround =
|
|
166
|
-
return /* @__PURE__ */
|
|
199
|
+
const onGround = useContext2(SidebarOnGround);
|
|
200
|
+
return /* @__PURE__ */ jsx5(
|
|
167
201
|
"nav",
|
|
168
202
|
{
|
|
169
203
|
"aria-label": ariaLabel,
|
|
170
204
|
className: cn("flex w-60 shrink-0 flex-col", !onGround && "border-r border-border-default bg-bg-surface", className),
|
|
171
|
-
children: /* @__PURE__ */
|
|
205
|
+
children: /* @__PURE__ */ jsx5(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-0.5 px-2.5 py-3", children })
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/TopBar.tsx
|
|
211
|
+
import { useEffect, useRef } from "react";
|
|
212
|
+
import { Button as BaseButton } from "@base-ui/react/button";
|
|
213
|
+
|
|
214
|
+
// src/looks.ts
|
|
215
|
+
var FIELD_BOX_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong focus:border-border-focus group-hover/field:focus:border-border-focus rounded-lg";
|
|
216
|
+
var FIELD_TEXT_CLASSES = "text-text-primary placeholder:text-text-muted";
|
|
217
|
+
var FIELD_DISABLED_CLASSES = "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-field group-hover/field:disabled:border-border-field";
|
|
218
|
+
var FIELD_FOCUS_RING_CLASSES = "signal:transition-shadow signal:focus:shadow-focus-ring";
|
|
219
|
+
var FIELD_SIZE_CLASSES = {
|
|
220
|
+
default: "px-3 py-2 text-input-value",
|
|
221
|
+
small: "h-6 min-h-6 px-2 text-caption"
|
|
222
|
+
};
|
|
223
|
+
var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong rounded-lg transition-colors";
|
|
224
|
+
var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
|
|
225
|
+
var COUNT_TEXT_CLASSES = "font-mono text-caption tabular-nums text-text-muted";
|
|
226
|
+
var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
|
|
227
|
+
var MONO_CAPTION_CLASSES = "text-caption text-text-secondary signal:font-mono signal:text-small";
|
|
228
|
+
var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
|
|
229
|
+
var SIDEBAR_ROW_CLASSES = "rounded-lg transition-colors";
|
|
230
|
+
var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
|
|
231
|
+
var MUTED_CONTROL_CLASSES = "text-text-secondary hover:bg-bg-hover hover:text-text-primary";
|
|
232
|
+
var MENU_TRIGGER_CLASSES = "cursor-pointer rounded-md transition-colors hover:bg-bg-hover data-[popup-open]:bg-bg-hover";
|
|
233
|
+
var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
|
|
234
|
+
|
|
235
|
+
// src/Kbd.tsx
|
|
236
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
237
|
+
function Kbd({ children, className, tone = "default" }) {
|
|
238
|
+
return /* @__PURE__ */ jsx6(
|
|
239
|
+
"kbd",
|
|
240
|
+
{
|
|
241
|
+
className: cn(
|
|
242
|
+
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans",
|
|
243
|
+
MONO_CAPTION_CLASSES,
|
|
244
|
+
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash",
|
|
245
|
+
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
|
|
246
|
+
// Leaf sets its keys in mono, as Signal does (Katerina, 28 September): the type, not the key's shape.
|
|
247
|
+
"leaf:font-mono leaf:text-small",
|
|
248
|
+
tone === "tooltip" && "border-border-tooltip-key bg-bg-tooltip-key text-text-tooltip-key signal:bg-bg-tooltip-key ship:bg-bg-tooltip-key",
|
|
249
|
+
className
|
|
250
|
+
),
|
|
251
|
+
children
|
|
172
252
|
}
|
|
173
253
|
);
|
|
174
254
|
}
|
|
175
255
|
|
|
256
|
+
// src/shortcuts.ts
|
|
257
|
+
function isApplePlatform() {
|
|
258
|
+
if (typeof navigator === "undefined") return false;
|
|
259
|
+
return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
|
|
260
|
+
}
|
|
261
|
+
function shortcutLabel(keys, apple = isApplePlatform()) {
|
|
262
|
+
return keys.split("-").map((part, i, all) => {
|
|
263
|
+
if (i === all.length - 1) return part.length === 1 ? part.toUpperCase() : part;
|
|
264
|
+
if (part === "Mod") return apple ? "Cmd" : "Ctrl";
|
|
265
|
+
return part;
|
|
266
|
+
}).join("+");
|
|
267
|
+
}
|
|
268
|
+
|
|
176
269
|
// src/TopBar.tsx
|
|
177
|
-
import { jsx as
|
|
178
|
-
function TopBar({ variant = "solid", menu, logo, search, right, className }) {
|
|
270
|
+
import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
271
|
+
function TopBar({ variant = "solid", menu, logo, search, onSearch, searchPlaceholder = "Search\u2026", right, className }) {
|
|
179
272
|
const floating = variant === "floating";
|
|
273
|
+
const searchRef = useRef(onSearch);
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
searchRef.current = onSearch;
|
|
276
|
+
});
|
|
277
|
+
const searches = onSearch !== void 0;
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
if (!searches) return;
|
|
280
|
+
const onKey = (event) => {
|
|
281
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
282
|
+
event.preventDefault();
|
|
283
|
+
searchRef.current?.();
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
window.addEventListener("keydown", onKey);
|
|
287
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
288
|
+
}, [searches]);
|
|
289
|
+
const centre = search ?? (onSearch && /* @__PURE__ */ jsxs2(BaseButton, { type: "button", onClick: onSearch, className: cn("flex w-[290px] cursor-pointer items-center gap-2 px-3 py-2", FIELD_SHELL_CLASSES), children: [
|
|
290
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate text-left text-input-value text-text-muted", children: searchPlaceholder }),
|
|
291
|
+
/* @__PURE__ */ jsx7(Kbd, { children: shortcutLabel("Mod-K") })
|
|
292
|
+
] }));
|
|
180
293
|
return /* @__PURE__ */ jsxs2(
|
|
181
294
|
"header",
|
|
182
295
|
{
|
|
@@ -188,19 +301,19 @@ function TopBar({ variant = "solid", menu, logo, search, right, className }) {
|
|
|
188
301
|
children: [
|
|
189
302
|
(menu || logo) && /* @__PURE__ */ jsxs2("div", { className: cn("flex shrink-0 items-center gap-2", floating && "pointer-events-auto"), children: [
|
|
190
303
|
menu,
|
|
191
|
-
logo && /* @__PURE__ */
|
|
304
|
+
logo && /* @__PURE__ */ jsx7("div", { className: "flex items-center text-body-2-strong text-text-primary", children: logo })
|
|
192
305
|
] }),
|
|
193
|
-
/* @__PURE__ */
|
|
194
|
-
/* @__PURE__ */
|
|
306
|
+
/* @__PURE__ */ jsx7("div", { className: cn("flex min-w-0 flex-1 items-center justify-center", floating && "pointer-events-auto"), children: centre }),
|
|
307
|
+
/* @__PURE__ */ jsx7("div", { className: cn("flex shrink-0 items-center gap-[6px]", floating && "pointer-events-auto"), children: right })
|
|
195
308
|
]
|
|
196
309
|
}
|
|
197
310
|
);
|
|
198
311
|
}
|
|
199
312
|
|
|
200
313
|
// src/AppShell.tsx
|
|
201
|
-
import { Fragment, jsx as
|
|
202
|
-
function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav, children }) {
|
|
203
|
-
const bar = /* @__PURE__ */
|
|
314
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
315
|
+
function AppShell({ variant = "solid", menu, logo, search, onSearch, searchPlaceholder, identity, banner, nav, children }) {
|
|
316
|
+
const bar = /* @__PURE__ */ jsx8(TopBar, { variant, menu, logo, search, onSearch, searchPlaceholder, right: identity });
|
|
204
317
|
const inset = variant === "inset";
|
|
205
318
|
if (variant === "floating") {
|
|
206
319
|
return (
|
|
@@ -220,7 +333,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
220
333
|
),
|
|
221
334
|
children: [
|
|
222
335
|
banner,
|
|
223
|
-
/* @__PURE__ */
|
|
336
|
+
/* @__PURE__ */ jsx8("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
|
|
224
337
|
]
|
|
225
338
|
}
|
|
226
339
|
)
|
|
@@ -230,7 +343,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
230
343
|
}
|
|
231
344
|
const column = /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
232
345
|
banner,
|
|
233
|
-
/* @__PURE__ */
|
|
346
|
+
/* @__PURE__ */ jsx8(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex min-h-full flex-col", children: /* @__PURE__ */ jsx8("main", { className: "flex min-w-0 flex-1 flex-col", children }) })
|
|
234
347
|
] });
|
|
235
348
|
return (
|
|
236
349
|
/* `relative overflow-hidden` is the seal the floating manner already has
|
|
@@ -245,16 +358,16 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
245
358
|
/* @__PURE__ */ jsxs3("div", { className: "relative flex h-full min-h-0 flex-col overflow-hidden bg-bg-base text-text-primary", children: [
|
|
246
359
|
bar,
|
|
247
360
|
/* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1", children: [
|
|
248
|
-
/* @__PURE__ */
|
|
249
|
-
inset ? /* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ jsx8(SidebarOnGround.Provider, { value: inset, children: nav }),
|
|
362
|
+
inset ? /* @__PURE__ */ jsx8(Card, { fill: "surface", clip: true, className: "mb-4 mr-4 flex min-h-0 min-w-0 flex-1 flex-col", children: column }) : /* @__PURE__ */ jsx8("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: column })
|
|
250
363
|
] })
|
|
251
364
|
] })
|
|
252
365
|
);
|
|
253
366
|
}
|
|
254
367
|
|
|
255
368
|
// src/AttachmentCard.tsx
|
|
256
|
-
import { useEffect, useLayoutEffect, useRef as
|
|
257
|
-
import { Button as
|
|
369
|
+
import { useEffect as useEffect2, useLayoutEffect, useRef as useRef3, useState } from "react";
|
|
370
|
+
import { Button as BaseButton3 } from "@base-ui/react/button";
|
|
258
371
|
import {
|
|
259
372
|
IconAlertCircle,
|
|
260
373
|
IconAlertTriangle,
|
|
@@ -274,74 +387,32 @@ import {
|
|
|
274
387
|
} from "@tabler/icons-react";
|
|
275
388
|
|
|
276
389
|
// src/IconButton.tsx
|
|
277
|
-
import { Button as
|
|
278
|
-
|
|
279
|
-
// src/looks.ts
|
|
280
|
-
var FIELD_BOX_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong focus:border-border-focus group-hover/field:focus:border-border-focus rounded-lg";
|
|
281
|
-
var FIELD_TEXT_CLASSES = "text-text-primary placeholder:text-text-muted";
|
|
282
|
-
var FIELD_DISABLED_CLASSES = "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-field group-hover/field:disabled:border-border-field";
|
|
283
|
-
var FIELD_FOCUS_RING_CLASSES = "signal:transition-shadow signal:focus:shadow-focus-ring";
|
|
284
|
-
var FIELD_SIZE_CLASSES = {
|
|
285
|
-
default: "px-3 py-2 text-input-value",
|
|
286
|
-
small: "h-6 min-h-6 px-2 text-caption"
|
|
287
|
-
};
|
|
288
|
-
var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong rounded-lg transition-colors";
|
|
289
|
-
var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
|
|
290
|
-
var COUNT_TEXT_CLASSES = "font-mono text-caption tabular-nums text-text-muted";
|
|
291
|
-
var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
|
|
292
|
-
var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
|
|
293
|
-
var SIDEBAR_ROW_CLASSES = "rounded-lg transition-colors";
|
|
294
|
-
var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
|
|
295
|
-
var MUTED_CONTROL_CLASSES = "text-text-secondary hover:bg-bg-hover hover:text-text-primary";
|
|
296
|
-
var MENU_TRIGGER_CLASSES = "cursor-pointer rounded-md transition-colors hover:bg-bg-hover data-[popup-open]:bg-bg-hover";
|
|
297
|
-
var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
|
|
390
|
+
import { Button as BaseButton2 } from "@base-ui/react/button";
|
|
298
391
|
|
|
299
392
|
// src/formBusy.ts
|
|
300
|
-
import { createContext as
|
|
301
|
-
var FormBusyContext =
|
|
393
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
394
|
+
var FormBusyContext = createContext3(false);
|
|
302
395
|
function useFormBusy() {
|
|
303
|
-
return
|
|
396
|
+
return useContext3(FormBusyContext);
|
|
304
397
|
}
|
|
305
398
|
|
|
306
399
|
// src/Tooltip.tsx
|
|
307
400
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
308
|
-
|
|
309
|
-
// src/Kbd.tsx
|
|
310
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
311
|
-
function Kbd({ children, className, tone = "default" }) {
|
|
312
|
-
return /* @__PURE__ */ jsx7(
|
|
313
|
-
"kbd",
|
|
314
|
-
{
|
|
315
|
-
className: cn(
|
|
316
|
-
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-caption text-text-secondary",
|
|
317
|
-
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash signal:font-mono signal:text-small",
|
|
318
|
-
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
|
|
319
|
-
// Leaf sets its keys in mono, as Signal does (Katerina, 28 September): the type, not the key's shape.
|
|
320
|
-
"leaf:font-mono leaf:text-small",
|
|
321
|
-
tone === "tooltip" && "border-border-tooltip-key bg-bg-tooltip-key text-text-tooltip-key signal:bg-bg-tooltip-key ship:bg-bg-tooltip-key",
|
|
322
|
-
className
|
|
323
|
-
),
|
|
324
|
-
children
|
|
325
|
-
}
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// src/Tooltip.tsx
|
|
330
|
-
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
401
|
+
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
331
402
|
var OPEN_DELAY = 300;
|
|
332
403
|
function TooltipProvider({ delay = OPEN_DELAY, closeDelay, timeout, children }) {
|
|
333
|
-
return /* @__PURE__ */
|
|
404
|
+
return /* @__PURE__ */ jsx9(BaseTooltip.Provider, { delay, closeDelay, timeout, children });
|
|
334
405
|
}
|
|
335
406
|
function Tooltip({ label, shortcut, className, ...props }) {
|
|
336
407
|
return /* @__PURE__ */ jsxs4("div", { role: "tooltip", className: cn(FLOATING_SURFACE_CLASSES, "border-border-tooltip bg-bg-tooltip", "min-h-[30px] max-w-80 flex items-center justify-center gap-1.5 px-2 py-1", className), ...props, children: [
|
|
337
|
-
/* @__PURE__ */
|
|
338
|
-
shortcut && /* @__PURE__ */
|
|
408
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-0 text-caption text-text-tooltip break-words", children: label }),
|
|
409
|
+
shortcut && /* @__PURE__ */ jsx9(Kbd, { tone: "tooltip", children: shortcut })
|
|
339
410
|
] });
|
|
340
411
|
}
|
|
341
412
|
var GAP = 6;
|
|
342
413
|
var VIEWPORT_PAD = 8;
|
|
343
414
|
function TooltipSurface({ label, shortcut, placement }) {
|
|
344
|
-
return /* @__PURE__ */
|
|
415
|
+
return /* @__PURE__ */ jsx9(BaseTooltip.Portal, { children: /* @__PURE__ */ jsx9(
|
|
345
416
|
BaseTooltip.Positioner,
|
|
346
417
|
{
|
|
347
418
|
side: placement,
|
|
@@ -350,10 +421,10 @@ function TooltipSurface({ label, shortcut, placement }) {
|
|
|
350
421
|
collisionPadding: VIEWPORT_PAD,
|
|
351
422
|
positionMethod: "fixed",
|
|
352
423
|
className: "pointer-events-none z-[9999]",
|
|
353
|
-
children: /* @__PURE__ */
|
|
424
|
+
children: /* @__PURE__ */ jsx9(
|
|
354
425
|
BaseTooltip.Popup,
|
|
355
426
|
{
|
|
356
|
-
render: /* @__PURE__ */
|
|
427
|
+
render: /* @__PURE__ */ jsx9(Tooltip, { label, shortcut }),
|
|
357
428
|
className: cn(
|
|
358
429
|
"transition-[opacity,transform] duration-[120ms] ease-out motion-reduce:transition-none",
|
|
359
430
|
"data-[ending-style]:duration-[80ms] data-[instant]:duration-0",
|
|
@@ -369,19 +440,19 @@ function TooltipSurface({ label, shortcut, placement }) {
|
|
|
369
440
|
function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, inline = false, children }) {
|
|
370
441
|
const Wrapper = inline ? "span" : "div";
|
|
371
442
|
return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
|
|
372
|
-
/* @__PURE__ */
|
|
373
|
-
/* @__PURE__ */
|
|
443
|
+
/* @__PURE__ */ jsx9(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx9(Wrapper, { className: cn("inline-flex shrink-0", inline && "align-top", wrapperClassName) }), children }),
|
|
444
|
+
/* @__PURE__ */ jsx9(TooltipSurface, { label, shortcut, placement })
|
|
374
445
|
] });
|
|
375
446
|
}
|
|
376
447
|
function TooltipTrigger({ label, shortcut, placement = "top", children }) {
|
|
377
448
|
return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
|
|
378
|
-
/* @__PURE__ */
|
|
379
|
-
/* @__PURE__ */
|
|
449
|
+
/* @__PURE__ */ jsx9(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: children }),
|
|
450
|
+
/* @__PURE__ */ jsx9(TooltipSurface, { label, shortcut, placement })
|
|
380
451
|
] });
|
|
381
452
|
}
|
|
382
453
|
|
|
383
454
|
// src/IconButton.tsx
|
|
384
|
-
import { jsx as
|
|
455
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
385
456
|
function IconButton({
|
|
386
457
|
variant = "muted",
|
|
387
458
|
pressed,
|
|
@@ -398,6 +469,8 @@ function IconButton({
|
|
|
398
469
|
...props
|
|
399
470
|
}) {
|
|
400
471
|
const formBusy = useFormBusy();
|
|
472
|
+
const anchor = props;
|
|
473
|
+
const inApp = useInAppClick(href, anchor.onClick);
|
|
401
474
|
const unusable = disabled || !!disabledReason || formBusy;
|
|
402
475
|
const look = (off) => cn(
|
|
403
476
|
// `shrink-0` stops a flex parent squashing the button; `self-center`
|
|
@@ -432,8 +505,8 @@ function IconButton({
|
|
|
432
505
|
off && "cursor-not-allowed",
|
|
433
506
|
className
|
|
434
507
|
);
|
|
435
|
-
const button = href && !unusable ? /* @__PURE__ */
|
|
436
|
-
|
|
508
|
+
const button = href && !unusable ? /* @__PURE__ */ jsx10("a", { href, className: look(false), ...anchor, onClick: inApp, children }) : /* @__PURE__ */ jsx10(
|
|
509
|
+
BaseButton2,
|
|
437
510
|
{
|
|
438
511
|
type,
|
|
439
512
|
disabled: unusable,
|
|
@@ -446,19 +519,19 @@ function IconButton({
|
|
|
446
519
|
);
|
|
447
520
|
const label = disabledReason ?? tooltip;
|
|
448
521
|
if (label) {
|
|
449
|
-
return /* @__PURE__ */
|
|
522
|
+
return /* @__PURE__ */ jsx10(TooltipTrigger, { label, shortcut: disabledReason ? void 0 : tooltipShortcut, placement: tooltipPlacement, children: button });
|
|
450
523
|
}
|
|
451
524
|
return button;
|
|
452
525
|
}
|
|
453
526
|
|
|
454
527
|
// src/Lightbox.tsx
|
|
455
|
-
import { useRef } from "react";
|
|
528
|
+
import { useRef as useRef2 } from "react";
|
|
456
529
|
import { Dialog } from "@base-ui/react/dialog";
|
|
457
530
|
import { IconX } from "@tabler/icons-react";
|
|
458
|
-
import { jsx as
|
|
531
|
+
import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
459
532
|
function Lightbox({ src, alt, onClose, className }) {
|
|
460
|
-
const popupRef =
|
|
461
|
-
return /* @__PURE__ */
|
|
533
|
+
const popupRef = useRef2(null);
|
|
534
|
+
return /* @__PURE__ */ jsx11(
|
|
462
535
|
Dialog.Root,
|
|
463
536
|
{
|
|
464
537
|
open: true,
|
|
@@ -466,7 +539,7 @@ function Lightbox({ src, alt, onClose, className }) {
|
|
|
466
539
|
if (!open) onClose();
|
|
467
540
|
},
|
|
468
541
|
children: /* @__PURE__ */ jsxs5(Dialog.Portal, { children: [
|
|
469
|
-
/* @__PURE__ */
|
|
542
|
+
/* @__PURE__ */ jsx11(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim-strong" }),
|
|
470
543
|
/* @__PURE__ */ jsxs5(
|
|
471
544
|
Dialog.Popup,
|
|
472
545
|
{
|
|
@@ -476,7 +549,7 @@ function Lightbox({ src, alt, onClose, className }) {
|
|
|
476
549
|
className: "fixed inset-0 z-50 flex items-center justify-center p-8 outline-none",
|
|
477
550
|
onClick: onClose,
|
|
478
551
|
children: [
|
|
479
|
-
/* @__PURE__ */
|
|
552
|
+
/* @__PURE__ */ jsx11(
|
|
480
553
|
"img",
|
|
481
554
|
{
|
|
482
555
|
src,
|
|
@@ -485,12 +558,12 @@ function Lightbox({ src, alt, onClose, className }) {
|
|
|
485
558
|
className: cn("max-w-full max-h-full object-contain rounded-lg", className)
|
|
486
559
|
}
|
|
487
560
|
),
|
|
488
|
-
/* @__PURE__ */
|
|
561
|
+
/* @__PURE__ */ jsx11(
|
|
489
562
|
Dialog.Close,
|
|
490
563
|
{
|
|
491
564
|
"aria-label": "Close",
|
|
492
565
|
className: "absolute top-4 right-4 size-8 rounded-full bg-bg-tooltip border border-border-tooltip-key flex items-center justify-center text-text-tooltip-key hover:text-text-tooltip",
|
|
493
|
-
children: /* @__PURE__ */
|
|
566
|
+
children: /* @__PURE__ */ jsx11(IconX, { size: 16, stroke: 1.5 })
|
|
494
567
|
}
|
|
495
568
|
)
|
|
496
569
|
]
|
|
@@ -502,7 +575,7 @@ function Lightbox({ src, alt, onClose, className }) {
|
|
|
502
575
|
}
|
|
503
576
|
|
|
504
577
|
// src/AttachmentCard.tsx
|
|
505
|
-
import { Fragment as Fragment2, jsx as
|
|
578
|
+
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
506
579
|
var ICON_BY_EXTENSION = {
|
|
507
580
|
pdf: IconFileTypePdf,
|
|
508
581
|
doc: IconFileTypeDocx,
|
|
@@ -536,10 +609,10 @@ var NAME_CLASSES = "text-caption font-medium text-text-primary truncate";
|
|
|
536
609
|
var NOTE_CLASSES = "text-small tracking-wide leading-tight truncate";
|
|
537
610
|
function TypeIcon({ name }) {
|
|
538
611
|
const Icon = ICON_BY_EXTENSION[extensionOf(name)] ?? IconFile;
|
|
539
|
-
return /* @__PURE__ */
|
|
612
|
+
return /* @__PURE__ */ jsx12(Icon, { size: 20, stroke: 1.5 });
|
|
540
613
|
}
|
|
541
614
|
function Truncating({ text, hint, className, wrapperClassName, placement }) {
|
|
542
|
-
const ref =
|
|
615
|
+
const ref = useRef3(null);
|
|
543
616
|
const [cut, setCut] = useState(false);
|
|
544
617
|
useLayoutEffect(() => {
|
|
545
618
|
const el = ref.current;
|
|
@@ -558,15 +631,15 @@ function Truncating({ text, hint, className, wrapperClassName, placement }) {
|
|
|
558
631
|
observer.disconnect();
|
|
559
632
|
};
|
|
560
633
|
}, [text, cut]);
|
|
561
|
-
const line = /* @__PURE__ */
|
|
634
|
+
const line = /* @__PURE__ */ jsx12("span", { ref, className, children: text });
|
|
562
635
|
if (!hint && !cut) return line;
|
|
563
|
-
return /* @__PURE__ */
|
|
636
|
+
return /* @__PURE__ */ jsx12(WithTooltip, { label: hint ?? text, placement, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
|
|
564
637
|
}
|
|
565
638
|
function useRemoteImage(url, fetchImage) {
|
|
566
639
|
const [result, setResult] = useState({});
|
|
567
|
-
const fetcher =
|
|
640
|
+
const fetcher = useRef3(fetchImage);
|
|
568
641
|
fetcher.current = fetchImage;
|
|
569
|
-
|
|
642
|
+
useEffect2(() => {
|
|
570
643
|
if (!url || !fetcher.current) return;
|
|
571
644
|
let live = true;
|
|
572
645
|
fetcher.current(url).then(
|
|
@@ -639,7 +712,7 @@ function AttachmentCard({
|
|
|
639
712
|
const full = useRemoteImage(opened ? remoteFullSrc : void 0, fetchImage);
|
|
640
713
|
const openable = image && !!picture && !pending;
|
|
641
714
|
const openPicture = onOpen ?? (openable ? () => setOpened(true) : void 0);
|
|
642
|
-
const viewer = opened && picture ? /* @__PURE__ */
|
|
715
|
+
const viewer = opened && picture ? /* @__PURE__ */ jsx12(Lightbox, { src: full.src ?? picture, alt: alt ?? name, onClose: () => setOpened(false) }) : null;
|
|
643
716
|
const saveHere = download ? () => {
|
|
644
717
|
const source = remoteFullSrc ?? remoteSrc;
|
|
645
718
|
if (source && fetchImage) {
|
|
@@ -668,10 +741,10 @@ function AttachmentCard({
|
|
|
668
741
|
className: cn("group relative flex items-center gap-2 w-[200px] p-1.5 pr-3", failed ? "border-error-default" : warning && "border-warning-default", className),
|
|
669
742
|
...props,
|
|
670
743
|
children: [
|
|
671
|
-
/* @__PURE__ */
|
|
744
|
+
/* @__PURE__ */ jsx12("div", { className: cn(TILE_CLASSES, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx12(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx12(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx12(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx12("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx12("span", { className: "text-menu font-semibold", children: typeLabelOf(name) }) }),
|
|
672
745
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0", children: [
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
746
|
+
/* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES, placement: onRemove ? "bottom" : void 0 }),
|
|
747
|
+
/* @__PURE__ */ jsx12(
|
|
675
748
|
Truncating,
|
|
676
749
|
{
|
|
677
750
|
text: (failed || warning ? note : state === "uploading" ? note ?? "Uploading\u2026" : note ?? sizeText) ?? "",
|
|
@@ -680,8 +753,8 @@ function AttachmentCard({
|
|
|
680
753
|
}
|
|
681
754
|
)
|
|
682
755
|
] }),
|
|
683
|
-
onRemove && /* @__PURE__ */
|
|
684
|
-
|
|
756
|
+
onRemove && /* @__PURE__ */ jsx12(
|
|
757
|
+
BaseButton3,
|
|
685
758
|
{
|
|
686
759
|
type: "button",
|
|
687
760
|
"aria-label": `Remove ${name}`,
|
|
@@ -690,7 +763,7 @@ function AttachmentCard({
|
|
|
690
763
|
event.stopPropagation();
|
|
691
764
|
onRemove();
|
|
692
765
|
},
|
|
693
|
-
children: /* @__PURE__ */
|
|
766
|
+
children: /* @__PURE__ */ jsx12(IconX2, { size: 11, stroke: 1.75 })
|
|
694
767
|
}
|
|
695
768
|
)
|
|
696
769
|
]
|
|
@@ -700,7 +773,7 @@ function AttachmentCard({
|
|
|
700
773
|
}
|
|
701
774
|
const downloadControl = saving ? (
|
|
702
775
|
// @estiva-escape(no-restyled-part): Download shows when its card is pointed at or focused, AttachmentCard's own action; IconButton has no reveal on its card's hover (UIG-9, Katerina 17 September)
|
|
703
|
-
/* @__PURE__ */
|
|
776
|
+
/* @__PURE__ */ jsx12(
|
|
704
777
|
IconButton,
|
|
705
778
|
{
|
|
706
779
|
variant: "muted",
|
|
@@ -711,7 +784,7 @@ function AttachmentCard({
|
|
|
711
784
|
event.stopPropagation();
|
|
712
785
|
saving();
|
|
713
786
|
},
|
|
714
|
-
children: /* @__PURE__ */
|
|
787
|
+
children: /* @__PURE__ */ jsx12(IconDownload, { size: 16, stroke: 1.5 })
|
|
715
788
|
}
|
|
716
789
|
)
|
|
717
790
|
) : null;
|
|
@@ -720,27 +793,27 @@ function AttachmentCard({
|
|
|
720
793
|
// `role="status"`: a plain box may not carry a name (axe, aria-prohibited-attr), and a
|
|
721
794
|
// status says what it is doing — loading — to a reader that cannot see the pulse.
|
|
722
795
|
// @estiva-escape(no-restyled-part): the loading pulse is AttachmentCard's own state; Card has no loading state (UIG-9, Katerina 17 September)
|
|
723
|
-
/* @__PURE__ */
|
|
796
|
+
/* @__PURE__ */ jsx12(Card, { role: "status", fill: "inset", "aria-busy": "true", "aria-label": `Loading ${name}`, className: cn("w-[180px] h-28 animate-pulse", className), ...props, children: null })
|
|
724
797
|
);
|
|
725
798
|
}
|
|
726
799
|
if (drawnState === "unreadable") {
|
|
727
800
|
return (
|
|
728
801
|
// @estiva-escape(no-restyled-part): a file that could not be read is faded as well as dashed, AttachmentCard's own state; Card has no faded state (UIG-9, Katerina 17 September)
|
|
729
802
|
/* @__PURE__ */ jsxs6(Card, { fill: "inset", unreadable: true, className: cn("flex items-center gap-2 w-[240px] p-1.5 opacity-70", className), ...props, children: [
|
|
730
|
-
/* @__PURE__ */
|
|
803
|
+
/* @__PURE__ */ jsx12("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx12(TypeIcon, { name }) }),
|
|
731
804
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
|
|
732
|
-
/* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
805
|
+
/* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES }),
|
|
806
|
+
/* @__PURE__ */ jsx12("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? "Could not be loaded" })
|
|
734
807
|
] })
|
|
735
808
|
] })
|
|
736
809
|
);
|
|
737
810
|
}
|
|
738
811
|
if (image && picture) {
|
|
739
|
-
const thumbnail = /* @__PURE__ */
|
|
812
|
+
const thumbnail = /* @__PURE__ */ jsx12("img", { src: picture, alt: alt ?? name, className: "w-full h-28 object-cover" });
|
|
740
813
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
741
814
|
/* @__PURE__ */ jsxs6(Card, { fill: "inset", hover: "hairline", clip: true, className: cn("group relative flex flex-col w-[180px]", className), ...props, children: [
|
|
742
|
-
openPicture ? /* @__PURE__ */
|
|
743
|
-
|
|
815
|
+
openPicture ? /* @__PURE__ */ jsx12(
|
|
816
|
+
BaseButton3,
|
|
744
817
|
{
|
|
745
818
|
type: "button",
|
|
746
819
|
className: "block w-full",
|
|
@@ -751,9 +824,9 @@ function AttachmentCard({
|
|
|
751
824
|
},
|
|
752
825
|
children: thumbnail
|
|
753
826
|
}
|
|
754
|
-
) : /* @__PURE__ */
|
|
827
|
+
) : /* @__PURE__ */ jsx12("div", { className: "block w-full", children: thumbnail }),
|
|
755
828
|
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 pl-2 pr-1 py-1 min-w-0", children: [
|
|
756
|
-
/* @__PURE__ */
|
|
829
|
+
/* @__PURE__ */ jsx12(Truncating, { text: name, className: "flex-1 text-caption text-text-primary truncate", wrapperClassName: "flex-1" }),
|
|
757
830
|
downloadControl
|
|
758
831
|
] })
|
|
759
832
|
] }),
|
|
@@ -761,16 +834,16 @@ function AttachmentCard({
|
|
|
761
834
|
] });
|
|
762
835
|
}
|
|
763
836
|
const body = /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
764
|
-
/* @__PURE__ */
|
|
837
|
+
/* @__PURE__ */ jsx12("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx12(TypeIcon, { name }) }),
|
|
765
838
|
/* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
|
|
766
|
-
/* @__PURE__ */
|
|
767
|
-
/* @__PURE__ */
|
|
839
|
+
/* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES }),
|
|
840
|
+
/* @__PURE__ */ jsx12("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
|
|
768
841
|
] })
|
|
769
842
|
] });
|
|
770
843
|
return (
|
|
771
844
|
// @estiva-escape(no-restyled-part): a file that cannot be opened is faded, AttachmentCard's own state; Card has no faded state (UIG-9, Katerina 17 September)
|
|
772
845
|
/* @__PURE__ */ jsxs6(Card, { fill: "inset", hover: address ? "hairline" : "none", className: cn("group flex items-center gap-2 w-[240px] p-1.5 pr-1", !address && "opacity-70", className), ...props, children: [
|
|
773
|
-
address ? /* @__PURE__ */
|
|
846
|
+
address ? /* @__PURE__ */ jsx12(Link, { href: address, external: true, variant: "plain", className: "flex items-center gap-2 min-w-0 flex-1", onClick: (event) => event.stopPropagation(), children: body }) : /* @__PURE__ */ jsx12("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: body }),
|
|
774
847
|
downloadControl
|
|
775
848
|
] })
|
|
776
849
|
);
|
|
@@ -779,7 +852,7 @@ function AttachmentCard({
|
|
|
779
852
|
// src/Avatar.tsx
|
|
780
853
|
import { Avatar as BaseAvatar } from "@base-ui/react/avatar";
|
|
781
854
|
import { IconUserFilled } from "@tabler/icons-react";
|
|
782
|
-
import { jsx as
|
|
855
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
783
856
|
var HUES = ["#56c8ff", "#ff8f6b", "#4ade8c", "#b18cff", "#ffc94d", "#ff7eb0", "#7ea8ff", "#5fdfd6"];
|
|
784
857
|
var hueFor = (key) => {
|
|
785
858
|
let h = 0;
|
|
@@ -793,27 +866,29 @@ var initialsFor = (name) => {
|
|
|
793
866
|
};
|
|
794
867
|
function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
795
868
|
const label = name || alt;
|
|
869
|
+
const pictureFor = usePictureFor();
|
|
870
|
+
const picture = src ?? (label && pictureFor ? pictureFor(label) ?? void 0 : void 0);
|
|
796
871
|
return /* @__PURE__ */ jsxs7(
|
|
797
872
|
BaseAvatar.Root,
|
|
798
873
|
{
|
|
799
|
-
render: /* @__PURE__ */
|
|
874
|
+
render: /* @__PURE__ */ jsx13("div", {}),
|
|
800
875
|
...spoken ? { role: "img", "aria-label": spoken } : { "aria-hidden": true },
|
|
801
876
|
className: cn("rounded-sm overflow-hidden shrink-0 bg-bg-inset", className),
|
|
802
877
|
style: { width: size, height: size },
|
|
803
878
|
children: [
|
|
804
|
-
|
|
879
|
+
picture && /* @__PURE__ */ jsx13(
|
|
805
880
|
BaseAvatar.Image,
|
|
806
881
|
{
|
|
807
|
-
src,
|
|
882
|
+
src: picture,
|
|
808
883
|
alt: "",
|
|
809
884
|
keepMounted: true,
|
|
810
885
|
className: "w-full h-full object-cover data-[error]:hidden"
|
|
811
886
|
}
|
|
812
887
|
),
|
|
813
|
-
label ? /* @__PURE__ */
|
|
888
|
+
label ? /* @__PURE__ */ jsx13(
|
|
814
889
|
BaseAvatar.Fallback,
|
|
815
890
|
{
|
|
816
|
-
render: /* @__PURE__ */
|
|
891
|
+
render: /* @__PURE__ */ jsx13("div", {}),
|
|
817
892
|
className: "w-full h-full flex items-center justify-center font-semibold leading-none",
|
|
818
893
|
style: {
|
|
819
894
|
/* eslint-disable no-restricted-syntax -- @estiva-escape: the per-person palette (the note at
|
|
@@ -827,44 +902,41 @@ function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
|
827
902
|
background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
|
|
828
903
|
/* eslint-enable no-restricted-syntax */
|
|
829
904
|
},
|
|
830
|
-
children: /* @__PURE__ */
|
|
905
|
+
children: /* @__PURE__ */ jsx13("span", { className: "[text-box:trim-both_cap_alphabetic]", children: initialsFor(label) })
|
|
831
906
|
}
|
|
832
|
-
) : /* @__PURE__ */
|
|
907
|
+
) : /* @__PURE__ */ jsx13(BaseAvatar.Fallback, { render: /* @__PURE__ */ jsx13("div", {}), className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx13(IconUserFilled, { size: Math.round(size * 0.5) }) })
|
|
833
908
|
]
|
|
834
909
|
}
|
|
835
910
|
);
|
|
836
911
|
}
|
|
837
912
|
|
|
838
913
|
// src/AvatarGroup.tsx
|
|
839
|
-
import { jsx as
|
|
914
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
840
915
|
function AvatarGroup({ members, size = 24 }) {
|
|
841
916
|
const visible = members.slice(0, 3);
|
|
842
917
|
const overlap = Math.round(size / 3);
|
|
843
918
|
const ring = size / 12;
|
|
844
|
-
return /* @__PURE__ */
|
|
919
|
+
return /* @__PURE__ */ jsx14("div", { className: "flex items-center", style: { paddingRight: overlap }, children: visible.map((member, i) => (
|
|
845
920
|
/*
|
|
846
921
|
The wrapper carries the overlap and the ring; the face carries
|
|
847
922
|
neither. It must never clip — see the note at the top of the file —
|
|
848
923
|
so it has the avatar's own radius and no overflow of its own.
|
|
849
924
|
*/
|
|
850
|
-
/* @__PURE__ */
|
|
925
|
+
/* @__PURE__ */ jsx14(
|
|
851
926
|
"span",
|
|
852
927
|
{
|
|
853
928
|
className: "relative flex rounded-sm",
|
|
854
929
|
style: { marginRight: -overlap, boxShadow: `0 0 0 ${ring}px var(--bg-surface)` },
|
|
855
|
-
children: /* @__PURE__ */
|
|
930
|
+
children: /* @__PURE__ */ jsx14(Avatar, { size, name: member.name, src: member.picture, label: member.name })
|
|
856
931
|
},
|
|
857
932
|
i
|
|
858
933
|
)
|
|
859
934
|
)) });
|
|
860
935
|
}
|
|
861
936
|
|
|
862
|
-
// src/Banner.tsx
|
|
863
|
-
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
864
|
-
|
|
865
937
|
// src/Button.tsx
|
|
866
|
-
import { Button as
|
|
867
|
-
import { jsx as
|
|
938
|
+
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
939
|
+
import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
868
940
|
function Button({
|
|
869
941
|
variant = "muted",
|
|
870
942
|
size = "default",
|
|
@@ -879,7 +951,7 @@ function Button({
|
|
|
879
951
|
const hasLeadingIcon = !!leadingIcon;
|
|
880
952
|
const formBusy = useFormBusy();
|
|
881
953
|
const button = /* @__PURE__ */ jsxs8(
|
|
882
|
-
|
|
954
|
+
BaseButton4,
|
|
883
955
|
{
|
|
884
956
|
type,
|
|
885
957
|
disabled: disabled || !!disabledReason || formBusy,
|
|
@@ -926,64 +998,89 @@ function Button({
|
|
|
926
998
|
]
|
|
927
999
|
}
|
|
928
1000
|
);
|
|
929
|
-
return disabledReason ? /* @__PURE__ */
|
|
1001
|
+
return disabledReason ? /* @__PURE__ */ jsx15(TooltipTrigger, { label: disabledReason, children: button }) : button;
|
|
930
1002
|
}
|
|
931
1003
|
|
|
932
|
-
// src/
|
|
933
|
-
import { jsx as
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1004
|
+
// src/MembersPill.tsx
|
|
1005
|
+
import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1006
|
+
function MembersPill({ members, count, onClick, className }) {
|
|
1007
|
+
const total = count ?? members.length;
|
|
1008
|
+
if (total === 0) return null;
|
|
1009
|
+
return /* @__PURE__ */ jsxs9(Button, { variant: "outlined", "aria-label": `${total} ${total === 1 ? "member" : "members"}`, disabled: !onClick, onClick, className: cn("gap-2 pl-[3px] pr-2", className), children: [
|
|
1010
|
+
/* @__PURE__ */ jsx16(AvatarGroup, { members }),
|
|
1011
|
+
/* @__PURE__ */ jsx16("span", { className: cn(MONO_CAPTION_CLASSES, "signal:tabular-nums"), children: total })
|
|
1012
|
+
] });
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// src/MembersDialog.tsx
|
|
1016
|
+
import { useId, useState as useState3 } from "react";
|
|
1017
|
+
import { IconArrowLeft, IconUserMinus, IconUserPlus } from "@tabler/icons-react";
|
|
1018
|
+
|
|
1019
|
+
// src/Chip.tsx
|
|
1020
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1021
|
+
var typeStyles = {
|
|
1022
|
+
neutral: "bg-bg-inset text-text-primary",
|
|
1023
|
+
brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
|
|
1024
|
+
info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
|
|
1025
|
+
warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
|
|
1026
|
+
success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
|
|
1027
|
+
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
939
1028
|
};
|
|
940
|
-
function
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1029
|
+
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
|
|
1030
|
+
const inApp = useInAppClick(href, onClick);
|
|
1031
|
+
const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
|
|
1032
|
+
const inside = /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1033
|
+
leadingIcon && /* @__PURE__ */ jsx17("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
1034
|
+
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
1035
|
+
// of growing past it — Ship's project chip on an issue row
|
|
1036
|
+
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
1037
|
+
// `truncate`, because `truncate` is `overflow: hidden` on both axes and
|
|
1038
|
+
// the label's line box (11px under Signal) is tighter than its glyphs —
|
|
1039
|
+
// the screenshot diff caught every descender cut off. `clip` is the
|
|
1040
|
+
// one overflow that leaves the other axis visible. A chip with no cap
|
|
1041
|
+
// draws exactly as before.
|
|
1042
|
+
/* @__PURE__ */ jsx17("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
|
|
1043
|
+
trailingIcon && /* @__PURE__ */ jsx17("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
951
1044
|
] });
|
|
1045
|
+
if (href) return /* @__PURE__ */ jsx17("a", { href, onClick: inApp, className: cn("relative", classes), children: inside });
|
|
1046
|
+
return /* @__PURE__ */ jsx17("div", { className: classes, children: inside });
|
|
952
1047
|
}
|
|
953
1048
|
|
|
954
|
-
// src/
|
|
955
|
-
import {
|
|
956
|
-
import {
|
|
1049
|
+
// src/ChipInput.tsx
|
|
1050
|
+
import { useMemo as useMemo2, useState as useState2 } from "react";
|
|
1051
|
+
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1052
|
+
import { Combobox } from "@base-ui/react/combobox";
|
|
1053
|
+
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
957
1054
|
|
|
958
1055
|
// src/Menu.tsx
|
|
959
|
-
import { createContext as
|
|
1056
|
+
import { createContext as createContext5, useContext as useContext5 } from "react";
|
|
960
1057
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
961
1058
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
962
1059
|
|
|
963
1060
|
// src/Divider.tsx
|
|
964
|
-
import { createContext as
|
|
1061
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
965
1062
|
import { Separator } from "@base-ui/react/separator";
|
|
966
|
-
import { jsx as
|
|
967
|
-
var DividerInPanel =
|
|
1063
|
+
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1064
|
+
var DividerInPanel = createContext4(false);
|
|
968
1065
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
969
|
-
const inset =
|
|
1066
|
+
const inset = useContext4(DividerInPanel) ? "mx-0" : "mx-3";
|
|
970
1067
|
if (label && orientation === "horizontal") {
|
|
971
1068
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
972
|
-
return /* @__PURE__ */
|
|
1069
|
+
return /* @__PURE__ */ jsxs11(
|
|
973
1070
|
Separator,
|
|
974
1071
|
{
|
|
975
1072
|
orientation: "horizontal",
|
|
976
1073
|
"aria-label": label,
|
|
977
1074
|
className: cn("flex shrink-0 items-center gap-2", inset, className),
|
|
978
1075
|
children: [
|
|
979
|
-
/* @__PURE__ */
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
/* @__PURE__ */
|
|
1076
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
|
|
1077
|
+
/* @__PURE__ */ jsx18("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
|
|
1078
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
|
|
982
1079
|
]
|
|
983
1080
|
}
|
|
984
1081
|
);
|
|
985
1082
|
}
|
|
986
|
-
return /* @__PURE__ */
|
|
1083
|
+
return /* @__PURE__ */ jsx18(
|
|
987
1084
|
Separator,
|
|
988
1085
|
{
|
|
989
1086
|
orientation,
|
|
@@ -999,7 +1096,7 @@ function triggerDisabled(trigger) {
|
|
|
999
1096
|
}
|
|
1000
1097
|
|
|
1001
1098
|
// src/SectionLabel.tsx
|
|
1002
|
-
import { jsx as
|
|
1099
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1003
1100
|
function SectionLabel({
|
|
1004
1101
|
children,
|
|
1005
1102
|
tone = "primary",
|
|
@@ -1007,7 +1104,7 @@ function SectionLabel({
|
|
|
1007
1104
|
folds = false,
|
|
1008
1105
|
className
|
|
1009
1106
|
}) {
|
|
1010
|
-
return /* @__PURE__ */
|
|
1107
|
+
return /* @__PURE__ */ jsx19(
|
|
1011
1108
|
"span",
|
|
1012
1109
|
{
|
|
1013
1110
|
className: cn(
|
|
@@ -1028,10 +1125,10 @@ function SectionLabel({
|
|
|
1028
1125
|
}
|
|
1029
1126
|
|
|
1030
1127
|
// src/Menu.tsx
|
|
1031
|
-
import { Fragment as
|
|
1032
|
-
var MenuContext =
|
|
1128
|
+
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1129
|
+
var MenuContext = createContext5(null);
|
|
1033
1130
|
function MenuPanel({ children, className, ...props }) {
|
|
1034
|
-
return /* @__PURE__ */
|
|
1131
|
+
return /* @__PURE__ */ jsx20(
|
|
1035
1132
|
"div",
|
|
1036
1133
|
{
|
|
1037
1134
|
className: cn(
|
|
@@ -1063,7 +1160,7 @@ var VIEWPORT_PAD2 = 8;
|
|
|
1063
1160
|
var HOVER_OPEN_DELAY = 0;
|
|
1064
1161
|
var HOVER_CLOSE_DELAY = 150;
|
|
1065
1162
|
function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
|
|
1066
|
-
return /* @__PURE__ */
|
|
1163
|
+
return /* @__PURE__ */ jsxs12(
|
|
1067
1164
|
BaseMenu.Root,
|
|
1068
1165
|
{
|
|
1069
1166
|
open,
|
|
@@ -1071,7 +1168,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1071
1168
|
actionsRef,
|
|
1072
1169
|
modal: false,
|
|
1073
1170
|
children: [
|
|
1074
|
-
/* @__PURE__ */
|
|
1171
|
+
/* @__PURE__ */ jsx20(
|
|
1075
1172
|
BaseMenu.Trigger,
|
|
1076
1173
|
{
|
|
1077
1174
|
render: trigger,
|
|
@@ -1081,7 +1178,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1081
1178
|
closeDelay: HOVER_CLOSE_DELAY
|
|
1082
1179
|
}
|
|
1083
1180
|
),
|
|
1084
|
-
/* @__PURE__ */
|
|
1181
|
+
/* @__PURE__ */ jsx20(BaseMenu.Portal, { children: /* @__PURE__ */ jsx20(
|
|
1085
1182
|
BaseMenu.Positioner,
|
|
1086
1183
|
{
|
|
1087
1184
|
side: "bottom",
|
|
@@ -1089,13 +1186,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1089
1186
|
sideOffset: GAP2,
|
|
1090
1187
|
collisionPadding: VIEWPORT_PAD2,
|
|
1091
1188
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1092
|
-
children: /* @__PURE__ */
|
|
1189
|
+
children: /* @__PURE__ */ jsx20(
|
|
1093
1190
|
BaseMenu.Popup,
|
|
1094
1191
|
{
|
|
1095
1192
|
"data-interactive": true,
|
|
1096
1193
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
1097
|
-
render: /* @__PURE__ */
|
|
1098
|
-
children: /* @__PURE__ */
|
|
1194
|
+
render: /* @__PURE__ */ jsx20(MenuPanel, {}),
|
|
1195
|
+
children: /* @__PURE__ */ jsx20(ScrollArea, { viewportClassName: "max-h-[var(--available-height)]", contentClassName: cn("flex flex-col gap-0.5 p-2", contentClassName), children: /* @__PURE__ */ jsx20(MenuContext.Provider, { value: { openOnHover }, children: /* @__PURE__ */ jsx20(DividerInPanel.Provider, { value: true, children }) }) })
|
|
1099
1196
|
}
|
|
1100
1197
|
)
|
|
1101
1198
|
}
|
|
@@ -1105,26 +1202,26 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1105
1202
|
);
|
|
1106
1203
|
}
|
|
1107
1204
|
function MenuSub({ label, leading, selected, children, className }) {
|
|
1108
|
-
const menu =
|
|
1205
|
+
const menu = useContext5(MenuContext);
|
|
1109
1206
|
if (!isProduction() && menu?.openOnHover) {
|
|
1110
1207
|
console.error(
|
|
1111
1208
|
'[@estiva-app/ui] Menu: `openOnHover` and `MenuSub` cannot be used together \u2014 leaving the submenu panel strands the menu open. Open this menu on a press instead. See Menu.mdx, "Hover-opened menus".'
|
|
1112
1209
|
);
|
|
1113
1210
|
}
|
|
1114
|
-
return /* @__PURE__ */
|
|
1115
|
-
/* @__PURE__ */
|
|
1211
|
+
return /* @__PURE__ */ jsxs12(BaseMenu.SubmenuRoot, { children: [
|
|
1212
|
+
/* @__PURE__ */ jsx20(
|
|
1116
1213
|
BaseMenu.SubmenuTrigger,
|
|
1117
1214
|
{
|
|
1118
1215
|
openOnHover: true,
|
|
1119
1216
|
delay: 0,
|
|
1120
1217
|
closeDelay: 150,
|
|
1121
1218
|
nativeButton: true,
|
|
1122
|
-
render: /* @__PURE__ */
|
|
1219
|
+
render: /* @__PURE__ */ jsx20("button", { type: "button" }),
|
|
1123
1220
|
className: menuItemClassName({ size: "default", selected }),
|
|
1124
|
-
children: /* @__PURE__ */
|
|
1221
|
+
children: /* @__PURE__ */ jsx20(MenuItemBody, { label, leading, submenu: true })
|
|
1125
1222
|
}
|
|
1126
1223
|
),
|
|
1127
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsx20(BaseMenu.Portal, { children: /* @__PURE__ */ jsx20(
|
|
1128
1225
|
BaseMenu.Positioner,
|
|
1129
1226
|
{
|
|
1130
1227
|
side: "inline-end",
|
|
@@ -1132,7 +1229,7 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
1132
1229
|
sideOffset: GAP2,
|
|
1133
1230
|
collisionPadding: VIEWPORT_PAD2,
|
|
1134
1231
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1135
|
-
children: /* @__PURE__ */
|
|
1232
|
+
children: /* @__PURE__ */ jsx20(BaseMenu.Popup, { className: cn("w-[160px]", className), "data-interactive": true, render: /* @__PURE__ */ jsx20(MenuPanel, {}), children })
|
|
1136
1233
|
}
|
|
1137
1234
|
) })
|
|
1138
1235
|
] });
|
|
@@ -1167,25 +1264,25 @@ function menuItemClassName({ size, selected, className }) {
|
|
|
1167
1264
|
);
|
|
1168
1265
|
}
|
|
1169
1266
|
function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
|
|
1170
|
-
const edge = trailing ?? (shortcut ? /* @__PURE__ */
|
|
1171
|
-
return /* @__PURE__ */
|
|
1172
|
-
leading && /* @__PURE__ */
|
|
1173
|
-
children ?? /* @__PURE__ */
|
|
1174
|
-
/* @__PURE__ */
|
|
1175
|
-
description && /* @__PURE__ */
|
|
1267
|
+
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx20(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx20(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
1268
|
+
return /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
1269
|
+
leading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1270
|
+
children ?? /* @__PURE__ */ jsxs12("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
1271
|
+
/* @__PURE__ */ jsx20("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
1272
|
+
description && /* @__PURE__ */ jsx20("span", { className: "truncate text-caption text-text-secondary", children: description })
|
|
1176
1273
|
] }),
|
|
1177
1274
|
(edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
|
|
1178
1275
|
// the wider of the two and never changes, so revealing the hint moves
|
|
1179
1276
|
// nothing. No transition here either — the hint switches on the same
|
|
1180
1277
|
// :hover / `selected` as the fill, in the same frame.
|
|
1181
|
-
/* @__PURE__ */
|
|
1182
|
-
edge && /* @__PURE__ */
|
|
1183
|
-
hint && /* @__PURE__ */
|
|
1278
|
+
/* @__PURE__ */ jsxs12("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
1279
|
+
edge && /* @__PURE__ */ jsx20("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
1280
|
+
hint && /* @__PURE__ */ jsx20("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
|
|
1184
1281
|
] })
|
|
1185
1282
|
] });
|
|
1186
1283
|
}
|
|
1187
1284
|
function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
1188
|
-
const body = /* @__PURE__ */
|
|
1285
|
+
const body = /* @__PURE__ */ jsx20(
|
|
1189
1286
|
MenuItemBody,
|
|
1190
1287
|
{
|
|
1191
1288
|
label,
|
|
@@ -1202,14 +1299,14 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1202
1299
|
}
|
|
1203
1300
|
);
|
|
1204
1301
|
const rowClassName = menuItemClassName({ size, selected, className });
|
|
1205
|
-
if (!
|
|
1206
|
-
return /* @__PURE__ */
|
|
1302
|
+
if (!useContext5(MenuContext)) {
|
|
1303
|
+
return /* @__PURE__ */ jsx20("button", { type: "button", className: rowClassName, ...props, children: body });
|
|
1207
1304
|
}
|
|
1208
|
-
return /* @__PURE__ */
|
|
1305
|
+
return /* @__PURE__ */ jsx20(
|
|
1209
1306
|
BaseMenu.Item,
|
|
1210
1307
|
{
|
|
1211
1308
|
nativeButton: true,
|
|
1212
|
-
render: /* @__PURE__ */
|
|
1309
|
+
render: /* @__PURE__ */ jsx20("button", { type: "button" }),
|
|
1213
1310
|
className: rowClassName,
|
|
1214
1311
|
...props,
|
|
1215
1312
|
children: body
|
|
@@ -1217,86 +1314,581 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1217
1314
|
);
|
|
1218
1315
|
}
|
|
1219
1316
|
function EnterHint({ target }) {
|
|
1220
|
-
return /* @__PURE__ */
|
|
1221
|
-
/* @__PURE__ */
|
|
1222
|
-
target && /* @__PURE__ */
|
|
1317
|
+
return /* @__PURE__ */ jsxs12("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
1318
|
+
/* @__PURE__ */ jsx20(Kbd, { children: "\u21A9 Enter" }),
|
|
1319
|
+
target && /* @__PURE__ */ jsx20("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider leaf:font-mono leaf:text-small leaf:tracking-wider", children: target })
|
|
1223
1320
|
] });
|
|
1224
1321
|
}
|
|
1225
1322
|
function MenuSection({ label, children, className }) {
|
|
1226
|
-
const inMenu =
|
|
1227
|
-
const heading = /* @__PURE__ */
|
|
1323
|
+
const inMenu = useContext5(MenuContext) !== null;
|
|
1324
|
+
const heading = /* @__PURE__ */ jsx20("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx20(SectionLabel, { tone: "secondary", children: label }) });
|
|
1228
1325
|
if (!inMenu) {
|
|
1229
|
-
return /* @__PURE__ */
|
|
1326
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-0.5", children: [
|
|
1230
1327
|
heading,
|
|
1231
1328
|
children
|
|
1232
1329
|
] });
|
|
1233
1330
|
}
|
|
1234
|
-
return /* @__PURE__ */
|
|
1235
|
-
/* @__PURE__ */
|
|
1331
|
+
return /* @__PURE__ */ jsxs12(BaseMenu.Group, { className: "flex flex-col gap-0.5", children: [
|
|
1332
|
+
/* @__PURE__ */ jsx20(BaseMenu.GroupLabel, { render: heading }),
|
|
1236
1333
|
children
|
|
1237
1334
|
] });
|
|
1238
1335
|
}
|
|
1239
1336
|
function MenuSeparator() {
|
|
1240
|
-
return /* @__PURE__ */
|
|
1337
|
+
return /* @__PURE__ */ jsx20(Divider, { className: "my-1" });
|
|
1241
1338
|
}
|
|
1242
1339
|
function MenuRow({ children, className }) {
|
|
1243
|
-
return /* @__PURE__ */
|
|
1340
|
+
return /* @__PURE__ */ jsx20("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
|
|
1244
1341
|
}
|
|
1245
1342
|
|
|
1246
|
-
// src/
|
|
1247
|
-
import { jsx as
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
return
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1343
|
+
// src/ChipInput.tsx
|
|
1344
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1345
|
+
var CHIP_BOX = (
|
|
1346
|
+
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
1347
|
+
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
1348
|
+
// follows concentrically: 4px face + 2px inset = rounded-md.
|
|
1349
|
+
"inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
|
|
1350
|
+
);
|
|
1351
|
+
var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
1352
|
+
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
1353
|
+
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
1354
|
+
function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
|
|
1355
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1356
|
+
leading && /* @__PURE__ */ jsx21("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1357
|
+
/* @__PURE__ */ jsx21("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
|
|
1358
|
+
onRemove && /* @__PURE__ */ jsx21(
|
|
1359
|
+
BaseButton5,
|
|
1360
|
+
{
|
|
1361
|
+
type: "button",
|
|
1362
|
+
onClick: (e) => {
|
|
1363
|
+
e.stopPropagation();
|
|
1364
|
+
onRemove();
|
|
1365
|
+
},
|
|
1366
|
+
className: cn(CHIP_REMOVE, truncate && "shrink-0"),
|
|
1367
|
+
"aria-label": removeLabel ?? `Remove ${label}`,
|
|
1368
|
+
children: /* @__PURE__ */ jsx21(IconX3, { size: 10, stroke: 1.5 })
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
] });
|
|
1271
1372
|
}
|
|
1272
|
-
function
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1373
|
+
function ChipInput({
|
|
1374
|
+
value,
|
|
1375
|
+
onChange,
|
|
1376
|
+
options,
|
|
1377
|
+
placeholder = "Search\u2026",
|
|
1378
|
+
autoFocus,
|
|
1379
|
+
excludeIds = [],
|
|
1380
|
+
chipLeading,
|
|
1381
|
+
rowLeading,
|
|
1382
|
+
...aria
|
|
1383
|
+
}) {
|
|
1384
|
+
const [query, setQuery] = useState2("");
|
|
1385
|
+
const [box, setBox] = useState2(null);
|
|
1386
|
+
const available = useMemo2(() => {
|
|
1387
|
+
const chosen = new Set(value.map((o) => o.id));
|
|
1388
|
+
const excluded = new Set(excludeIds);
|
|
1389
|
+
return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
|
|
1390
|
+
}, [options, value, excludeIds]);
|
|
1391
|
+
const filter = useMemo2(
|
|
1392
|
+
() => (item, q) => {
|
|
1393
|
+
const needle = q.trim().toLowerCase();
|
|
1394
|
+
if (!needle) return true;
|
|
1395
|
+
return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
|
|
1284
1396
|
},
|
|
1285
|
-
[
|
|
1397
|
+
[]
|
|
1286
1398
|
);
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1399
|
+
const open = query.trim().length > 0;
|
|
1400
|
+
const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
|
|
1401
|
+
const naming = {
|
|
1402
|
+
...ariaLabel !== void 0 && { "aria-label": ariaLabel },
|
|
1403
|
+
...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
|
|
1404
|
+
};
|
|
1405
|
+
function removeLast() {
|
|
1406
|
+
if (value.length > 0) onChange(value.slice(0, -1));
|
|
1407
|
+
}
|
|
1408
|
+
function onInputKeyDown(event) {
|
|
1409
|
+
if (event.key === "Backspace" && query === "" && value.length > 0) {
|
|
1410
|
+
event.preventDefault();
|
|
1411
|
+
event.stopPropagation();
|
|
1412
|
+
removeLast();
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (event.key === "Escape" && query !== "") {
|
|
1416
|
+
event.preventDefault();
|
|
1417
|
+
event.stopPropagation();
|
|
1418
|
+
setQuery("");
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return /* @__PURE__ */ jsxs13(
|
|
1422
|
+
Combobox.Root,
|
|
1423
|
+
{
|
|
1424
|
+
multiple: true,
|
|
1425
|
+
items: available,
|
|
1426
|
+
value,
|
|
1427
|
+
onValueChange: (next) => {
|
|
1428
|
+
onChange(next);
|
|
1429
|
+
setQuery("");
|
|
1430
|
+
},
|
|
1431
|
+
inputValue: query,
|
|
1432
|
+
onInputValueChange: setQuery,
|
|
1433
|
+
open,
|
|
1434
|
+
openOnInputClick: false,
|
|
1435
|
+
filter,
|
|
1436
|
+
itemToStringLabel: (option) => option.label,
|
|
1437
|
+
children: [
|
|
1438
|
+
/* @__PURE__ */ jsxs13(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
|
|
1439
|
+
value.map((option) => /* @__PURE__ */ jsxs13(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1440
|
+
chipLeading && /* @__PURE__ */ jsx21("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1441
|
+
/* @__PURE__ */ jsx21("span", { className: CHIP_LABEL, children: option.label }),
|
|
1442
|
+
/* @__PURE__ */ jsx21(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx21(IconX3, { size: 10, stroke: 1.5 }) })
|
|
1443
|
+
] }, option.id)),
|
|
1444
|
+
/* @__PURE__ */ jsx21(
|
|
1445
|
+
Combobox.Input,
|
|
1446
|
+
{
|
|
1447
|
+
autoFocus,
|
|
1448
|
+
placeholder: value.length === 0 ? placeholder : "",
|
|
1449
|
+
"aria-required": aria["aria-required"],
|
|
1450
|
+
...naming,
|
|
1451
|
+
onKeyDown: onInputKeyDown,
|
|
1452
|
+
className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
|
|
1453
|
+
}
|
|
1454
|
+
)
|
|
1455
|
+
] }),
|
|
1456
|
+
/* @__PURE__ */ jsx21(Combobox.Portal, { children: /* @__PURE__ */ jsx21(
|
|
1457
|
+
Combobox.Positioner,
|
|
1458
|
+
{
|
|
1459
|
+
anchor: box,
|
|
1460
|
+
sideOffset: GAP3,
|
|
1461
|
+
collisionPadding: VIEWPORT_PAD3,
|
|
1462
|
+
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1463
|
+
children: /* @__PURE__ */ jsx21(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx21(MenuPanel, {}), children: /* @__PURE__ */ jsx21(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx21(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx21(
|
|
1464
|
+
Combobox.Item,
|
|
1465
|
+
{
|
|
1466
|
+
value: option,
|
|
1467
|
+
render: /* @__PURE__ */ jsx21(
|
|
1468
|
+
MenuItem,
|
|
1469
|
+
{
|
|
1470
|
+
size: "tall",
|
|
1471
|
+
leading: rowLeading?.(option),
|
|
1472
|
+
label: option.label,
|
|
1473
|
+
description: option.description
|
|
1474
|
+
}
|
|
1475
|
+
)
|
|
1476
|
+
},
|
|
1477
|
+
option.id
|
|
1478
|
+
) }) }) })
|
|
1479
|
+
}
|
|
1480
|
+
) })
|
|
1481
|
+
]
|
|
1482
|
+
}
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
var GAP3 = 4;
|
|
1486
|
+
var VIEWPORT_PAD3 = 8;
|
|
1487
|
+
|
|
1488
|
+
// src/DialogShell.tsx
|
|
1489
|
+
import { useRef as useRef4 } from "react";
|
|
1490
|
+
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1491
|
+
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1492
|
+
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1493
|
+
|
|
1494
|
+
// src/ContainerHeader.tsx
|
|
1495
|
+
import { IconChevronDown } from "@tabler/icons-react";
|
|
1496
|
+
import { Button as BaseButton6 } from "@base-ui/react/button";
|
|
1497
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1498
|
+
function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
|
|
1499
|
+
const text = typeof title === "string";
|
|
1500
|
+
const name = /* @__PURE__ */ jsxs14("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
|
|
1501
|
+
text ? /* @__PURE__ */ jsx22("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: title }),
|
|
1502
|
+
(chevron || titleMenu != null) && /* @__PURE__ */ jsx22(IconChevronDown, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1503
|
+
] });
|
|
1504
|
+
return (
|
|
1505
|
+
// The title 16px in, where the column's content starts (Katerina, 7 October; it was 20px).
|
|
1506
|
+
// With a title menu the bar gives the button 6px of its left padding
|
|
1507
|
+
// (pl-2.5 + the button's px-1.5 = pl-4): the words stay where a title's
|
|
1508
|
+
// are, and the fill is inside the bar — a negative margin had it clipped
|
|
1509
|
+
// (Katerina, 5 October).
|
|
1510
|
+
/* @__PURE__ */ jsxs14("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-2.5" : "pl-4", className), children: [
|
|
1511
|
+
/* @__PURE__ */ jsx22("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx22(
|
|
1512
|
+
Menu,
|
|
1513
|
+
{
|
|
1514
|
+
trigger: /* @__PURE__ */ jsx22(BaseButton6, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
|
|
1515
|
+
children: titleMenu
|
|
1516
|
+
}
|
|
1517
|
+
) : name }),
|
|
1518
|
+
actions && /* @__PURE__ */ jsx22("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx22("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
|
|
1519
|
+
] })
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// src/DialogShell.tsx
|
|
1524
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1525
|
+
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1526
|
+
const Parts = alert ? AlertDialog : Dialog2;
|
|
1527
|
+
const popupRef = useRef4(null);
|
|
1528
|
+
return /* @__PURE__ */ jsx23(
|
|
1529
|
+
Parts.Root,
|
|
1530
|
+
{
|
|
1531
|
+
open: true,
|
|
1532
|
+
onOpenChange: (open) => {
|
|
1533
|
+
if (!open) onClose();
|
|
1534
|
+
},
|
|
1535
|
+
children: /* @__PURE__ */ jsxs15(Parts.Portal, { children: [
|
|
1536
|
+
/* @__PURE__ */ jsx23(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1537
|
+
/* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs15(
|
|
1538
|
+
Parts.Popup,
|
|
1539
|
+
{
|
|
1540
|
+
ref: popupRef,
|
|
1541
|
+
initialFocus: popupRef,
|
|
1542
|
+
"aria-label": headerContent != null ? title : void 0,
|
|
1543
|
+
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1544
|
+
style: { width },
|
|
1545
|
+
children: [
|
|
1546
|
+
/* @__PURE__ */ jsx23(
|
|
1547
|
+
ContainerHeader,
|
|
1548
|
+
{
|
|
1549
|
+
className: "pl-5",
|
|
1550
|
+
title: headerContent ?? /* @__PURE__ */ jsx23(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx23("span", {}), children: title }),
|
|
1551
|
+
actions: (
|
|
1552
|
+
/*
|
|
1553
|
+
The ✕ IS the `Close` part now, rather than a button that calls
|
|
1554
|
+
`onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
|
|
1555
|
+
this: an `IconButton` carrying a `tooltip` returned the tooltip
|
|
1556
|
+
wrapper `<div>` as its root, so the part composed onto the
|
|
1557
|
+
wrapper and not the button. Porting Tooltip removed the wrapper
|
|
1558
|
+
— the trigger is the button itself — and the composition works.
|
|
1559
|
+
|
|
1560
|
+
What it buys: the dialog closes through its own state machine,
|
|
1561
|
+
so the ✕, Escape and the outside press are one path with one
|
|
1562
|
+
reason attached, instead of one of the three going around.
|
|
1563
|
+
*/
|
|
1564
|
+
/* @__PURE__ */ jsx23(
|
|
1565
|
+
Parts.Close,
|
|
1566
|
+
{
|
|
1567
|
+
render: /* @__PURE__ */ jsx23(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx23(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1568
|
+
}
|
|
1569
|
+
)
|
|
1570
|
+
)
|
|
1571
|
+
}
|
|
1572
|
+
),
|
|
1573
|
+
bodyMaxHeight ? (
|
|
1574
|
+
// The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
|
|
1575
|
+
/* @__PURE__ */ jsx23("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx23(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
|
|
1576
|
+
) : /* @__PURE__ */ jsx23("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1577
|
+
footer != null && /* @__PURE__ */ jsx23("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1578
|
+
]
|
|
1579
|
+
}
|
|
1580
|
+
) })
|
|
1581
|
+
] })
|
|
1582
|
+
}
|
|
1583
|
+
);
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// src/Field.tsx
|
|
1587
|
+
import { cloneElement, isValidElement } from "react";
|
|
1588
|
+
import { Field as BaseField } from "@base-ui/react/field";
|
|
1589
|
+
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1590
|
+
var LINE_STYLES = {
|
|
1591
|
+
helper: "text-caption text-text-muted",
|
|
1592
|
+
warning: "text-caption text-warning-default",
|
|
1593
|
+
error: "text-caption text-error-default"
|
|
1594
|
+
};
|
|
1595
|
+
function Field({ label, required = false, helper, error, children }) {
|
|
1596
|
+
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1597
|
+
"aria-required": children.props["aria-required"] ?? true
|
|
1598
|
+
}) : children;
|
|
1599
|
+
return (
|
|
1600
|
+
// `group/field`: the label, the box and the line under it are one thing under the pointer —
|
|
1601
|
+
// anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
|
|
1602
|
+
// Before, the 8px between the label and the box was a gap where the border went out again.
|
|
1603
|
+
/* @__PURE__ */ jsxs16(BaseField.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
|
|
1604
|
+
/* @__PURE__ */ jsxs16(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1605
|
+
label,
|
|
1606
|
+
required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1607
|
+
] }),
|
|
1608
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
|
|
1609
|
+
control,
|
|
1610
|
+
error != null ? /* @__PURE__ */ jsx24(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1611
|
+
] })
|
|
1612
|
+
] })
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
function FieldLine({ tone = "helper", children, className }) {
|
|
1616
|
+
return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// src/Form.tsx
|
|
1620
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef5 } from "react";
|
|
1621
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1622
|
+
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1623
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1624
|
+
var FIELDS_CLASSES = "flex flex-col gap-6";
|
|
1625
|
+
var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1626
|
+
var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1627
|
+
function usable(element) {
|
|
1628
|
+
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1629
|
+
}
|
|
1630
|
+
function firstInvalid(form) {
|
|
1631
|
+
for (const marked of form.querySelectorAll("[data-invalid]")) {
|
|
1632
|
+
if (usable(marked)) return marked;
|
|
1633
|
+
const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
|
|
1634
|
+
if (inside) return inside;
|
|
1635
|
+
}
|
|
1636
|
+
return void 0;
|
|
1637
|
+
}
|
|
1638
|
+
function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
|
|
1639
|
+
const outerBusy = useFormBusy();
|
|
1640
|
+
const busy = ownBusy || outerBusy;
|
|
1641
|
+
const form = useRef5(null);
|
|
1642
|
+
const busyNow = useRef5(busy);
|
|
1643
|
+
busyNow.current = busy;
|
|
1644
|
+
const sender = useRef5(null);
|
|
1645
|
+
const holding = useRef5(false);
|
|
1646
|
+
const lastInside = useRef5(null);
|
|
1647
|
+
useLayoutEffect2(() => {
|
|
1648
|
+
const element = form.current;
|
|
1649
|
+
if (!element) return;
|
|
1650
|
+
if (busy) {
|
|
1651
|
+
const active = document.activeElement;
|
|
1652
|
+
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1653
|
+
if (from?.isConnected) {
|
|
1654
|
+
sender.current = from;
|
|
1655
|
+
holding.current = true;
|
|
1656
|
+
element.focus();
|
|
1657
|
+
}
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
if (!holding.current) return;
|
|
1661
|
+
holding.current = false;
|
|
1662
|
+
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1663
|
+
const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
|
|
1664
|
+
sender.current = null;
|
|
1665
|
+
target?.focus();
|
|
1666
|
+
}, [busy]);
|
|
1667
|
+
const onKeyDown = (event) => {
|
|
1668
|
+
props.onKeyDown?.(event);
|
|
1669
|
+
if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
|
|
1670
|
+
const target = event.target;
|
|
1671
|
+
const inInput = target instanceof HTMLInputElement;
|
|
1672
|
+
if (inInput) event.preventDefault();
|
|
1673
|
+
if (event.altKey || event.shiftKey) return;
|
|
1674
|
+
if (event.ctrlKey || event.metaKey) {
|
|
1675
|
+
event.preventDefault();
|
|
1676
|
+
form.current?.requestSubmit();
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
if (!inInput) return;
|
|
1680
|
+
const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
|
|
1681
|
+
if (enterSends && oneLine) form.current?.requestSubmit();
|
|
1682
|
+
};
|
|
1683
|
+
return /* @__PURE__ */ jsx25(
|
|
1684
|
+
BaseForm,
|
|
1685
|
+
{
|
|
1686
|
+
ref: form,
|
|
1687
|
+
...props,
|
|
1688
|
+
tabIndex: busy ? -1 : props.tabIndex,
|
|
1689
|
+
className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
|
|
1690
|
+
onFocus: (event) => {
|
|
1691
|
+
if (event.target !== form.current) lastInside.current = event.target;
|
|
1692
|
+
props.onFocus?.(event);
|
|
1693
|
+
},
|
|
1694
|
+
onBlur: (event) => {
|
|
1695
|
+
const next = event.relatedTarget;
|
|
1696
|
+
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1697
|
+
props.onBlur?.(event);
|
|
1698
|
+
},
|
|
1699
|
+
onKeyDown,
|
|
1700
|
+
onSubmit: (event) => {
|
|
1701
|
+
if (event.target !== event.currentTarget) return;
|
|
1702
|
+
event.preventDefault();
|
|
1703
|
+
if (busyNow.current) return;
|
|
1704
|
+
void onSubmit();
|
|
1705
|
+
},
|
|
1706
|
+
children: /* @__PURE__ */ jsx25(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx25(FormBusyContext.Provider, { value: busy, children }) })
|
|
1707
|
+
}
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// src/MembersDialog.tsx
|
|
1712
|
+
import { Fragment as Fragment5, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1713
|
+
var LEADING_CLASSES = "size-8 rounded-md bg-accent-muted flex items-center justify-center shrink-0 text-accent-primary";
|
|
1714
|
+
function MembersDialog({ members, count, self, candidates = [], onAdd, note, initialView = "list", onClose }) {
|
|
1715
|
+
const [view, setView] = useState3(onAdd ? initialView : "list");
|
|
1716
|
+
const [chosen, setChosen] = useState3([]);
|
|
1717
|
+
const [toggling, setToggling] = useState3(false);
|
|
1718
|
+
const formId = useId();
|
|
1719
|
+
const toggle = async () => {
|
|
1720
|
+
if (!self || toggling) return;
|
|
1721
|
+
setToggling(true);
|
|
1722
|
+
try {
|
|
1723
|
+
await self.onToggle();
|
|
1724
|
+
} finally {
|
|
1725
|
+
setToggling(false);
|
|
1726
|
+
}
|
|
1727
|
+
};
|
|
1728
|
+
const add = async () => {
|
|
1729
|
+
if (!onAdd || chosen.length === 0) return;
|
|
1730
|
+
if (await onAdd(chosen) === false) return;
|
|
1731
|
+
setChosen([]);
|
|
1732
|
+
setView("list");
|
|
1733
|
+
};
|
|
1734
|
+
if (view === "add" && onAdd) {
|
|
1735
|
+
return /* @__PURE__ */ jsx26(
|
|
1736
|
+
DialogShell,
|
|
1737
|
+
{
|
|
1738
|
+
title: "Add members",
|
|
1739
|
+
onClose,
|
|
1740
|
+
headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1741
|
+
/* @__PURE__ */ jsx26(IconButton, { tooltip: "Back to members", "aria-label": "Back to members", className: "-ml-2", onClick: () => setView("list"), children: /* @__PURE__ */ jsx26(IconArrowLeft, { size: 16, stroke: 1.5 }) }),
|
|
1742
|
+
/* @__PURE__ */ jsx26("span", { className: "truncate text-h4 text-text-primary", children: "Add members" })
|
|
1743
|
+
] }),
|
|
1744
|
+
bodyClassName: "flex flex-col gap-6",
|
|
1745
|
+
footer: /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
1746
|
+
/* @__PURE__ */ jsx26(Button, { variant: "muted", onClick: onClose, children: "Cancel" }),
|
|
1747
|
+
/* @__PURE__ */ jsx26(Button, { variant: "primary", type: "submit", form: formId, disabled: chosen.length === 0, children: "Invite" })
|
|
1748
|
+
] }),
|
|
1749
|
+
children: /* @__PURE__ */ jsx26(Form, { id: formId, onSubmit: add, children: /* @__PURE__ */ jsx26(Field, { label: "Invite people", required: true, children: /* @__PURE__ */ jsx26(
|
|
1750
|
+
ChipInput,
|
|
1751
|
+
{
|
|
1752
|
+
value: chosen,
|
|
1753
|
+
onChange: setChosen,
|
|
1754
|
+
options: candidates,
|
|
1755
|
+
placeholder: "Search people...",
|
|
1756
|
+
excludeIds: members.map((m) => m.id),
|
|
1757
|
+
chipLeading: (o) => /* @__PURE__ */ jsx26(Avatar, { name: o.label, src: o.picture, size: 16 }),
|
|
1758
|
+
rowLeading: (o) => /* @__PURE__ */ jsx26(Avatar, { name: o.label, src: o.picture, size: 32 }),
|
|
1759
|
+
autoFocus: true
|
|
1760
|
+
}
|
|
1761
|
+
) }) })
|
|
1762
|
+
}
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
return /* @__PURE__ */ jsxs17(
|
|
1766
|
+
DialogShell,
|
|
1767
|
+
{
|
|
1768
|
+
title: "Members",
|
|
1769
|
+
onClose,
|
|
1770
|
+
headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1771
|
+
/* @__PURE__ */ jsx26("span", { className: "truncate text-h4 text-text-primary", children: "Members" }),
|
|
1772
|
+
/* @__PURE__ */ jsx26(Chip, { label: String(count ?? members.length) })
|
|
1773
|
+
] }),
|
|
1774
|
+
bodyMaxHeight: "max-h-[400px]",
|
|
1775
|
+
bodyClassName: "p-0 py-2",
|
|
1776
|
+
children: [
|
|
1777
|
+
(self || onAdd) && /* @__PURE__ */ jsxs17("div", { className: "flex flex-col px-2", children: [
|
|
1778
|
+
self && /* @__PURE__ */ jsx26(
|
|
1779
|
+
MenuItem,
|
|
1780
|
+
{
|
|
1781
|
+
size: "tall",
|
|
1782
|
+
className: "py-2",
|
|
1783
|
+
disabled: toggling,
|
|
1784
|
+
onClick: () => void toggle(),
|
|
1785
|
+
leading: /* @__PURE__ */ jsx26("span", { className: LEADING_CLASSES, children: self.action === "join" ? /* @__PURE__ */ jsx26(IconUserPlus, { size: 16, stroke: 1.5 }) : /* @__PURE__ */ jsx26(IconUserMinus, { size: 16, stroke: 1.5 }) }),
|
|
1786
|
+
label: self.action === "join" ? "Join" : "Leave"
|
|
1787
|
+
}
|
|
1788
|
+
),
|
|
1789
|
+
onAdd && /* @__PURE__ */ jsx26(
|
|
1790
|
+
MenuItem,
|
|
1791
|
+
{
|
|
1792
|
+
size: "tall",
|
|
1793
|
+
className: "py-2",
|
|
1794
|
+
onClick: () => setView("add"),
|
|
1795
|
+
leading: /* @__PURE__ */ jsx26("span", { className: LEADING_CLASSES, children: /* @__PURE__ */ jsx26(IconUserPlus, { size: 16, stroke: 1.5 }) }),
|
|
1796
|
+
label: "Add members"
|
|
1797
|
+
}
|
|
1798
|
+
)
|
|
1799
|
+
] }),
|
|
1800
|
+
members.map((member) => /* @__PURE__ */ jsxs17("div", { className: "flex h-12 items-center gap-3 px-5", children: [
|
|
1801
|
+
/* @__PURE__ */ jsx26(Avatar, { size: 32, name: member.name, src: member.picture }),
|
|
1802
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-[2px]", children: [
|
|
1803
|
+
/* @__PURE__ */ jsx26("div", { className: "truncate text-body-2 text-text-primary", children: member.name }),
|
|
1804
|
+
member.caption && /* @__PURE__ */ jsx26("div", { className: "truncate text-caption text-text-secondary", children: member.caption })
|
|
1805
|
+
] })
|
|
1806
|
+
] }, member.id)),
|
|
1807
|
+
note && /* @__PURE__ */ jsx26("div", { className: "px-5 pb-2 pt-3 text-caption text-text-secondary", children: note })
|
|
1808
|
+
]
|
|
1809
|
+
}
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
// src/Banner.tsx
|
|
1814
|
+
import { IconX as IconX5 } from "@tabler/icons-react";
|
|
1815
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1816
|
+
var TONE_STYLES = {
|
|
1817
|
+
ok: "bg-success-muted text-success-default",
|
|
1818
|
+
error: "bg-error-muted text-error-default",
|
|
1819
|
+
info: "bg-info-muted text-info-default",
|
|
1820
|
+
warning: "bg-warning-muted text-warning-default"
|
|
1821
|
+
};
|
|
1822
|
+
function Banner({ tone, children, icon, action, onDismiss, dismissLabel = "Dismiss", className }) {
|
|
1823
|
+
const role = tone === "error" ? "alert" : "status";
|
|
1824
|
+
if (!onDismiss && !icon && !action) {
|
|
1825
|
+
return /* @__PURE__ */ jsx27("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
|
|
1826
|
+
}
|
|
1827
|
+
const oneLine = Boolean(icon || action);
|
|
1828
|
+
return /* @__PURE__ */ jsxs18("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
|
|
1829
|
+
icon && /* @__PURE__ */ jsx27("span", { className: "flex shrink-0", children: icon }),
|
|
1830
|
+
/* @__PURE__ */ jsx27("span", { className: cn("min-w-0 flex-1", oneLine && "truncate"), children }),
|
|
1831
|
+
action && /* @__PURE__ */ jsx27(Button, { variant: "muted", size: "small", className: "shrink-0", onClick: action.onClick, children: action.label }),
|
|
1832
|
+
onDismiss && /* @__PURE__ */ jsx27(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx27(IconX5, { size: 16, stroke: 1.5 }) })
|
|
1833
|
+
] });
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
// src/BlockHandle.tsx
|
|
1837
|
+
import { useCallback, useEffect as useEffect3, useRef as useRef6, useState as useState4 } from "react";
|
|
1838
|
+
import { IconGripVertical } from "@tabler/icons-react";
|
|
1839
|
+
import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1840
|
+
function readId(element) {
|
|
1841
|
+
const own = element.getAttribute("data-block-id") ?? element.querySelector("[data-block-id]")?.getAttribute("data-block-id");
|
|
1842
|
+
return own || void 0;
|
|
1843
|
+
}
|
|
1844
|
+
function blockAtY(blocks, y) {
|
|
1845
|
+
let found = null;
|
|
1846
|
+
for (const block of blocks) {
|
|
1847
|
+
if (block.element.getBoundingClientRect().top > y) break;
|
|
1848
|
+
found = block;
|
|
1849
|
+
}
|
|
1850
|
+
return found ?? blocks[0] ?? null;
|
|
1851
|
+
}
|
|
1852
|
+
function readingBlocks(root) {
|
|
1853
|
+
if (!root) return [];
|
|
1854
|
+
return Array.from(root.children).filter((el) => el instanceof HTMLElement).map((element) => ({ id: readId(element), element })).filter((b) => b.id !== void 0);
|
|
1855
|
+
}
|
|
1856
|
+
var HANDLE = 24;
|
|
1857
|
+
function firstLineOffset(element) {
|
|
1858
|
+
const text = element.querySelector("p, h1, h2, h3, pre, li") ?? element;
|
|
1859
|
+
const line = parseFloat(getComputedStyle(text).lineHeight);
|
|
1860
|
+
if (!Number.isFinite(line)) return 0;
|
|
1861
|
+
const inset = text === element ? 0 : text.getBoundingClientRect().top - element.getBoundingClientRect().top;
|
|
1862
|
+
return inset + (line - HANDLE) / 2;
|
|
1863
|
+
}
|
|
1864
|
+
function BlockHandle({ actions, editing, children, className }) {
|
|
1865
|
+
const frame = useRef6(null);
|
|
1866
|
+
const content = useRef6(null);
|
|
1867
|
+
const [block, setBlock] = useState4(null);
|
|
1868
|
+
const [top, setTop] = useState4(0);
|
|
1869
|
+
const [open, setOpen] = useState4(false);
|
|
1870
|
+
const follow = useCallback(
|
|
1871
|
+
(y) => {
|
|
1872
|
+
if (!content.current || !frame.current) return;
|
|
1873
|
+
const found = editing ? editing.find(y) : blockAtY(readingBlocks(content.current.firstElementChild), y);
|
|
1874
|
+
setBlock(found);
|
|
1875
|
+
if (found) setTop(found.element.getBoundingClientRect().top - frame.current.getBoundingClientRect().top + firstLineOffset(found.element));
|
|
1876
|
+
},
|
|
1877
|
+
[editing]
|
|
1878
|
+
);
|
|
1879
|
+
useEffect3(() => {
|
|
1880
|
+
if (!editing) return;
|
|
1881
|
+
return editing.onChange(() => {
|
|
1882
|
+
if (!open) setBlock(null);
|
|
1883
|
+
});
|
|
1884
|
+
}, [editing, open]);
|
|
1885
|
+
const rows = editing && block ? editing.rows(block) : null;
|
|
1886
|
+
const own = actions && block ? actions(block) : null;
|
|
1887
|
+
const dragging = useRef6(false);
|
|
1888
|
+
const [line, setLine] = useState4(null);
|
|
1889
|
+
const inGutter = (e) => dragging.current && !!editing && !!content.current && !content.current.contains(e.target);
|
|
1890
|
+
const landing = (y) => {
|
|
1891
|
+
const target = editing?.find(y);
|
|
1300
1892
|
if (!target || !frame.current) return null;
|
|
1301
1893
|
const box = target.element.getBoundingClientRect();
|
|
1302
1894
|
const after = y > box.top + box.height / 2;
|
|
@@ -1309,7 +1901,7 @@ function BlockHandle({ actions, editing, children, className }) {
|
|
|
1309
1901
|
setLine(null);
|
|
1310
1902
|
editing?.endDrag();
|
|
1311
1903
|
};
|
|
1312
|
-
return /* @__PURE__ */
|
|
1904
|
+
return /* @__PURE__ */ jsxs19(
|
|
1313
1905
|
"div",
|
|
1314
1906
|
{
|
|
1315
1907
|
ref: frame,
|
|
@@ -1337,16 +1929,16 @@ function BlockHandle({ actions, editing, children, className }) {
|
|
|
1337
1929
|
if (!frame.current?.contains(e.relatedTarget)) setLine(null);
|
|
1338
1930
|
},
|
|
1339
1931
|
children: [
|
|
1340
|
-
/* @__PURE__ */
|
|
1341
|
-
/* @__PURE__ */
|
|
1342
|
-
line !== null && /* @__PURE__ */
|
|
1932
|
+
/* @__PURE__ */ jsx28("div", { ref: content, children }),
|
|
1933
|
+
/* @__PURE__ */ jsx28("div", { "aria-hidden": true, className: "absolute inset-y-0 -left-7 w-7" }),
|
|
1934
|
+
line !== null && /* @__PURE__ */ jsx28("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-x-0 h-px bg-accent-primary", style: { top: line } }),
|
|
1343
1935
|
block && (rows || own) && // The top is the block's, measured: it depends on the document, not on a size of ours.
|
|
1344
|
-
/* @__PURE__ */
|
|
1936
|
+
/* @__PURE__ */ jsx28("div", { className: cn("absolute -left-7", rows && "cursor-grab active:cursor-grabbing"), style: { top }, children: /* @__PURE__ */ jsxs19(
|
|
1345
1937
|
Menu,
|
|
1346
1938
|
{
|
|
1347
1939
|
open,
|
|
1348
1940
|
onOpenChange: setOpen,
|
|
1349
|
-
trigger: /* @__PURE__ */
|
|
1941
|
+
trigger: /* @__PURE__ */ jsx28(
|
|
1350
1942
|
IconButton,
|
|
1351
1943
|
{
|
|
1352
1944
|
"aria-label": "Block menu",
|
|
@@ -1367,12 +1959,12 @@ function BlockHandle({ actions, editing, children, className }) {
|
|
|
1367
1959
|
endDrag();
|
|
1368
1960
|
setBlock(null);
|
|
1369
1961
|
},
|
|
1370
|
-
children: /* @__PURE__ */
|
|
1962
|
+
children: /* @__PURE__ */ jsx28(IconGripVertical, { size: 16, stroke: 1.5 })
|
|
1371
1963
|
}
|
|
1372
1964
|
),
|
|
1373
1965
|
children: [
|
|
1374
1966
|
rows,
|
|
1375
|
-
rows && own && /* @__PURE__ */
|
|
1967
|
+
rows && own && /* @__PURE__ */ jsx28(MenuSeparator, {}),
|
|
1376
1968
|
own
|
|
1377
1969
|
]
|
|
1378
1970
|
}
|
|
@@ -1384,9 +1976,9 @@ function BlockHandle({ actions, editing, children, className }) {
|
|
|
1384
1976
|
|
|
1385
1977
|
// src/Checkbox.tsx
|
|
1386
1978
|
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
1387
|
-
import { Field as
|
|
1979
|
+
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1388
1980
|
import { IconCheck } from "@tabler/icons-react";
|
|
1389
|
-
import { jsx as
|
|
1981
|
+
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1390
1982
|
function squareClasses(checked, disabled, interactive, className) {
|
|
1391
1983
|
return cn(
|
|
1392
1984
|
"inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
|
|
@@ -1403,392 +1995,89 @@ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, row
|
|
|
1403
1995
|
const formBusy = useFormBusy();
|
|
1404
1996
|
const disabled = ownDisabled || formBusy;
|
|
1405
1997
|
if (!onChange) {
|
|
1406
|
-
const picture = /* @__PURE__ */
|
|
1998
|
+
const picture = /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx29("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx29(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
1407
1999
|
if (label === void 0) return picture;
|
|
1408
|
-
return /* @__PURE__ */
|
|
2000
|
+
return /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-2", children: [
|
|
1409
2001
|
picture,
|
|
1410
|
-
/* @__PURE__ */
|
|
2002
|
+
/* @__PURE__ */ jsx29("span", { className: WORDS_CLASSES, children: label })
|
|
1411
2003
|
] });
|
|
1412
2004
|
}
|
|
1413
|
-
const box = /* @__PURE__ */
|
|
2005
|
+
const box = /* @__PURE__ */ jsx29(
|
|
1414
2006
|
BaseCheckbox.Root,
|
|
1415
2007
|
{
|
|
1416
2008
|
checked,
|
|
1417
2009
|
disabled,
|
|
1418
|
-
"aria-label": aria["aria-label"],
|
|
1419
|
-
"aria-required": aria["aria-required"],
|
|
1420
|
-
onCheckedChange: (next) => onChange(next),
|
|
1421
|
-
onClick: (e) => e.stopPropagation(),
|
|
1422
|
-
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
1423
|
-
children: /* @__PURE__ */
|
|
1424
|
-
}
|
|
1425
|
-
);
|
|
1426
|
-
if (label === void 0) return box;
|
|
1427
|
-
if (row) {
|
|
1428
|
-
return /* @__PURE__ */ jsx20(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs13(BaseField.Label, { className: cn(ROW_CLASSES, checked && "bg-bg-selected", !disabled && "cursor-pointer hover:bg-bg-hover"), children: [
|
|
1429
|
-
leading,
|
|
1430
|
-
/* @__PURE__ */ jsx20("span", { className: cn("flex-1 min-w-0 truncate", WORDS_CLASSES), children: label }),
|
|
1431
|
-
box
|
|
1432
|
-
] }) });
|
|
1433
|
-
}
|
|
1434
|
-
return /* @__PURE__ */ jsx20(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs13(BaseField.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
|
|
1435
|
-
box,
|
|
1436
|
-
/* @__PURE__ */ jsx20("span", { className: WORDS_CLASSES, children: label })
|
|
1437
|
-
] }) });
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
// src/Chip.tsx
|
|
1441
|
-
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1442
|
-
var typeStyles = {
|
|
1443
|
-
neutral: "bg-bg-inset text-text-primary",
|
|
1444
|
-
brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
|
|
1445
|
-
info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
|
|
1446
|
-
warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
|
|
1447
|
-
success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
|
|
1448
|
-
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
1449
|
-
};
|
|
1450
|
-
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
|
|
1451
|
-
const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
|
|
1452
|
-
const inside = /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1453
|
-
leadingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
1454
|
-
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
1455
|
-
// of growing past it — Ship's project chip on an issue row
|
|
1456
|
-
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
1457
|
-
// `truncate`, because `truncate` is `overflow: hidden` on both axes and
|
|
1458
|
-
// the label's line box (11px under Signal) is tighter than its glyphs —
|
|
1459
|
-
// the screenshot diff caught every descender cut off. `clip` is the
|
|
1460
|
-
// one overflow that leaves the other axis visible. A chip with no cap
|
|
1461
|
-
// draws exactly as before.
|
|
1462
|
-
/* @__PURE__ */ jsx21("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
|
|
1463
|
-
trailingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
1464
|
-
] });
|
|
1465
|
-
if (href) return /* @__PURE__ */ jsx21("a", { href, onClick, className: cn("relative", classes), children: inside });
|
|
1466
|
-
return /* @__PURE__ */ jsx21("div", { className: classes, children: inside });
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
// src/CommandPalette.tsx
|
|
1470
|
-
import {
|
|
1471
|
-
createContext as createContext5,
|
|
1472
|
-
useContext as useContext5,
|
|
1473
|
-
useEffect as useEffect3,
|
|
1474
|
-
useLayoutEffect as useLayoutEffect3,
|
|
1475
|
-
useMemo as useMemo2,
|
|
1476
|
-
useRef as useRef5,
|
|
1477
|
-
useState as useState4
|
|
1478
|
-
} from "react";
|
|
1479
|
-
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1480
|
-
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
1481
|
-
import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
|
|
1482
|
-
|
|
1483
|
-
// src/ChipInput.tsx
|
|
1484
|
-
import { useMemo, useState as useState3 } from "react";
|
|
1485
|
-
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
1486
|
-
import { Combobox } from "@base-ui/react/combobox";
|
|
1487
|
-
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1488
|
-
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1489
|
-
var CHIP_BOX = (
|
|
1490
|
-
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
1491
|
-
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
1492
|
-
// follows concentrically: 4px face + 2px inset = rounded-md.
|
|
1493
|
-
"inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
|
|
1494
|
-
);
|
|
1495
|
-
var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
1496
|
-
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
1497
|
-
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
1498
|
-
function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
|
|
1499
|
-
return /* @__PURE__ */ jsxs15("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1500
|
-
leading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1501
|
-
/* @__PURE__ */ jsx22("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
|
|
1502
|
-
onRemove && /* @__PURE__ */ jsx22(
|
|
1503
|
-
BaseButton4,
|
|
1504
|
-
{
|
|
1505
|
-
type: "button",
|
|
1506
|
-
onClick: (e) => {
|
|
1507
|
-
e.stopPropagation();
|
|
1508
|
-
onRemove();
|
|
1509
|
-
},
|
|
1510
|
-
className: cn(CHIP_REMOVE, truncate && "shrink-0"),
|
|
1511
|
-
"aria-label": removeLabel ?? `Remove ${label}`,
|
|
1512
|
-
children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 })
|
|
1513
|
-
}
|
|
1514
|
-
)
|
|
1515
|
-
] });
|
|
1516
|
-
}
|
|
1517
|
-
function ChipInput({
|
|
1518
|
-
value,
|
|
1519
|
-
onChange,
|
|
1520
|
-
options,
|
|
1521
|
-
placeholder = "Search\u2026",
|
|
1522
|
-
autoFocus,
|
|
1523
|
-
excludeIds = [],
|
|
1524
|
-
chipLeading,
|
|
1525
|
-
rowLeading,
|
|
1526
|
-
...aria
|
|
1527
|
-
}) {
|
|
1528
|
-
const [query, setQuery] = useState3("");
|
|
1529
|
-
const [box, setBox] = useState3(null);
|
|
1530
|
-
const available = useMemo(() => {
|
|
1531
|
-
const chosen = new Set(value.map((o) => o.id));
|
|
1532
|
-
const excluded = new Set(excludeIds);
|
|
1533
|
-
return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
|
|
1534
|
-
}, [options, value, excludeIds]);
|
|
1535
|
-
const filter = useMemo(
|
|
1536
|
-
() => (item, q) => {
|
|
1537
|
-
const needle = q.trim().toLowerCase();
|
|
1538
|
-
if (!needle) return true;
|
|
1539
|
-
return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
|
|
1540
|
-
},
|
|
1541
|
-
[]
|
|
1542
|
-
);
|
|
1543
|
-
const open = query.trim().length > 0;
|
|
1544
|
-
const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
|
|
1545
|
-
const naming = {
|
|
1546
|
-
...ariaLabel !== void 0 && { "aria-label": ariaLabel },
|
|
1547
|
-
...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
|
|
1548
|
-
};
|
|
1549
|
-
function removeLast() {
|
|
1550
|
-
if (value.length > 0) onChange(value.slice(0, -1));
|
|
1551
|
-
}
|
|
1552
|
-
function onInputKeyDown(event) {
|
|
1553
|
-
if (event.key === "Backspace" && query === "" && value.length > 0) {
|
|
1554
|
-
event.preventDefault();
|
|
1555
|
-
event.stopPropagation();
|
|
1556
|
-
removeLast();
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
if (event.key === "Escape" && query !== "") {
|
|
1560
|
-
event.preventDefault();
|
|
1561
|
-
event.stopPropagation();
|
|
1562
|
-
setQuery("");
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
return /* @__PURE__ */ jsxs15(
|
|
1566
|
-
Combobox.Root,
|
|
1567
|
-
{
|
|
1568
|
-
multiple: true,
|
|
1569
|
-
items: available,
|
|
1570
|
-
value,
|
|
1571
|
-
onValueChange: (next) => {
|
|
1572
|
-
onChange(next);
|
|
1573
|
-
setQuery("");
|
|
1574
|
-
},
|
|
1575
|
-
inputValue: query,
|
|
1576
|
-
onInputValueChange: setQuery,
|
|
1577
|
-
open,
|
|
1578
|
-
openOnInputClick: false,
|
|
1579
|
-
filter,
|
|
1580
|
-
itemToStringLabel: (option) => option.label,
|
|
1581
|
-
children: [
|
|
1582
|
-
/* @__PURE__ */ jsxs15(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
|
|
1583
|
-
value.map((option) => /* @__PURE__ */ jsxs15(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1584
|
-
chipLeading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1585
|
-
/* @__PURE__ */ jsx22("span", { className: CHIP_LABEL, children: option.label }),
|
|
1586
|
-
/* @__PURE__ */ jsx22(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 }) })
|
|
1587
|
-
] }, option.id)),
|
|
1588
|
-
/* @__PURE__ */ jsx22(
|
|
1589
|
-
Combobox.Input,
|
|
1590
|
-
{
|
|
1591
|
-
autoFocus,
|
|
1592
|
-
placeholder: value.length === 0 ? placeholder : "",
|
|
1593
|
-
"aria-required": aria["aria-required"],
|
|
1594
|
-
...naming,
|
|
1595
|
-
onKeyDown: onInputKeyDown,
|
|
1596
|
-
className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
|
|
1597
|
-
}
|
|
1598
|
-
)
|
|
1599
|
-
] }),
|
|
1600
|
-
/* @__PURE__ */ jsx22(Combobox.Portal, { children: /* @__PURE__ */ jsx22(
|
|
1601
|
-
Combobox.Positioner,
|
|
1602
|
-
{
|
|
1603
|
-
anchor: box,
|
|
1604
|
-
sideOffset: GAP3,
|
|
1605
|
-
collisionPadding: VIEWPORT_PAD3,
|
|
1606
|
-
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1607
|
-
children: /* @__PURE__ */ jsx22(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx22(MenuPanel, {}), children: /* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx22(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx22(
|
|
1608
|
-
Combobox.Item,
|
|
1609
|
-
{
|
|
1610
|
-
value: option,
|
|
1611
|
-
render: /* @__PURE__ */ jsx22(
|
|
1612
|
-
MenuItem,
|
|
1613
|
-
{
|
|
1614
|
-
size: "tall",
|
|
1615
|
-
leading: rowLeading?.(option),
|
|
1616
|
-
label: option.label,
|
|
1617
|
-
description: option.description
|
|
1618
|
-
}
|
|
1619
|
-
)
|
|
1620
|
-
},
|
|
1621
|
-
option.id
|
|
1622
|
-
) }) }) })
|
|
1623
|
-
}
|
|
1624
|
-
) })
|
|
1625
|
-
]
|
|
2010
|
+
"aria-label": aria["aria-label"],
|
|
2011
|
+
"aria-required": aria["aria-required"],
|
|
2012
|
+
onCheckedChange: (next) => onChange(next),
|
|
2013
|
+
onClick: (e) => e.stopPropagation(),
|
|
2014
|
+
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
2015
|
+
children: /* @__PURE__ */ jsx29(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx29(IconCheck, { size: 12, stroke: 3 }) })
|
|
1626
2016
|
}
|
|
1627
2017
|
);
|
|
2018
|
+
if (label === void 0) return box;
|
|
2019
|
+
if (row) {
|
|
2020
|
+
return /* @__PURE__ */ jsx29(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn(ROW_CLASSES, checked && "bg-bg-selected", !disabled && "cursor-pointer hover:bg-bg-hover"), children: [
|
|
2021
|
+
leading,
|
|
2022
|
+
/* @__PURE__ */ jsx29("span", { className: cn("flex-1 min-w-0 truncate", WORDS_CLASSES), children: label }),
|
|
2023
|
+
box
|
|
2024
|
+
] }) });
|
|
2025
|
+
}
|
|
2026
|
+
return /* @__PURE__ */ jsx29(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
|
|
2027
|
+
box,
|
|
2028
|
+
/* @__PURE__ */ jsx29("span", { className: WORDS_CLASSES, children: label })
|
|
2029
|
+
] }) });
|
|
1628
2030
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
2031
|
+
|
|
2032
|
+
// src/CommandPalette.tsx
|
|
2033
|
+
import {
|
|
2034
|
+
createContext as createContext6,
|
|
2035
|
+
useContext as useContext6,
|
|
2036
|
+
useEffect as useEffect4,
|
|
2037
|
+
useLayoutEffect as useLayoutEffect3,
|
|
2038
|
+
useMemo as useMemo3,
|
|
2039
|
+
useRef as useRef7,
|
|
2040
|
+
useState as useState5
|
|
2041
|
+
} from "react";
|
|
2042
|
+
import { Dialog as Dialog3 } from "@base-ui/react/dialog";
|
|
2043
|
+
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
2044
|
+
import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
|
|
1631
2045
|
|
|
1632
2046
|
// src/EmptyState.tsx
|
|
1633
2047
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1634
|
-
import { jsx as
|
|
2048
|
+
import { jsx as jsx30, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1635
2049
|
function EmptyState({ icon, message, scope = "page", action, className }) {
|
|
1636
2050
|
if (scope === "section") {
|
|
1637
|
-
return /* @__PURE__ */
|
|
2051
|
+
return /* @__PURE__ */ jsx30("p", { className: cn("text-caption text-text-muted", className), children: message });
|
|
1638
2052
|
}
|
|
1639
|
-
return /* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
action && /* @__PURE__ */
|
|
2053
|
+
return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
2054
|
+
/* @__PURE__ */ jsx30("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx30(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
2055
|
+
/* @__PURE__ */ jsx30("p", { className: "text-body-2 text-text-secondary text-center", children: message }),
|
|
2056
|
+
action && /* @__PURE__ */ jsx30(Button, { variant: "outlined", className: "mt-2", onClick: action.onClick, children: action.label })
|
|
1643
2057
|
] });
|
|
1644
2058
|
}
|
|
1645
2059
|
|
|
1646
|
-
// src/Field.tsx
|
|
1647
|
-
import { cloneElement, isValidElement } from "react";
|
|
1648
|
-
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1649
|
-
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1650
|
-
var LINE_STYLES = {
|
|
1651
|
-
helper: "text-caption text-text-muted",
|
|
1652
|
-
warning: "text-caption text-warning-default",
|
|
1653
|
-
error: "text-caption text-error-default"
|
|
1654
|
-
};
|
|
1655
|
-
function Field({ label, required = false, helper, error, children }) {
|
|
1656
|
-
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1657
|
-
"aria-required": children.props["aria-required"] ?? true
|
|
1658
|
-
}) : children;
|
|
1659
|
-
return (
|
|
1660
|
-
// `group/field`: the label, the box and the line under it are one thing under the pointer —
|
|
1661
|
-
// anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
|
|
1662
|
-
// Before, the 8px between the label and the box was a gap where the border went out again.
|
|
1663
|
-
/* @__PURE__ */ jsxs17(BaseField2.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
|
|
1664
|
-
/* @__PURE__ */ jsxs17(BaseField2.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1665
|
-
label,
|
|
1666
|
-
required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1667
|
-
] }),
|
|
1668
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-1.5", children: [
|
|
1669
|
-
control,
|
|
1670
|
-
error != null ? /* @__PURE__ */ jsx24(BaseField2.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField2.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1671
|
-
] })
|
|
1672
|
-
] })
|
|
1673
|
-
);
|
|
1674
|
-
}
|
|
1675
|
-
function FieldLine({ tone = "helper", children, className }) {
|
|
1676
|
-
return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
// src/Form.tsx
|
|
1680
|
-
import { useLayoutEffect as useLayoutEffect2, useRef as useRef4 } from "react";
|
|
1681
|
-
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1682
|
-
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1683
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1684
|
-
var FIELDS_CLASSES = "flex flex-col gap-6";
|
|
1685
|
-
var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1686
|
-
var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1687
|
-
function usable(element) {
|
|
1688
|
-
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1689
|
-
}
|
|
1690
|
-
function firstInvalid(form) {
|
|
1691
|
-
for (const marked of form.querySelectorAll("[data-invalid]")) {
|
|
1692
|
-
if (usable(marked)) return marked;
|
|
1693
|
-
const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
|
|
1694
|
-
if (inside) return inside;
|
|
1695
|
-
}
|
|
1696
|
-
return void 0;
|
|
1697
|
-
}
|
|
1698
|
-
function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
|
|
1699
|
-
const outerBusy = useFormBusy();
|
|
1700
|
-
const busy = ownBusy || outerBusy;
|
|
1701
|
-
const form = useRef4(null);
|
|
1702
|
-
const busyNow = useRef4(busy);
|
|
1703
|
-
busyNow.current = busy;
|
|
1704
|
-
const sender = useRef4(null);
|
|
1705
|
-
const holding = useRef4(false);
|
|
1706
|
-
const lastInside = useRef4(null);
|
|
1707
|
-
useLayoutEffect2(() => {
|
|
1708
|
-
const element = form.current;
|
|
1709
|
-
if (!element) return;
|
|
1710
|
-
if (busy) {
|
|
1711
|
-
const active = document.activeElement;
|
|
1712
|
-
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1713
|
-
if (from?.isConnected) {
|
|
1714
|
-
sender.current = from;
|
|
1715
|
-
holding.current = true;
|
|
1716
|
-
element.focus();
|
|
1717
|
-
}
|
|
1718
|
-
return;
|
|
1719
|
-
}
|
|
1720
|
-
if (!holding.current) return;
|
|
1721
|
-
holding.current = false;
|
|
1722
|
-
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1723
|
-
const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
|
|
1724
|
-
sender.current = null;
|
|
1725
|
-
target?.focus();
|
|
1726
|
-
}, [busy]);
|
|
1727
|
-
const onKeyDown = (event) => {
|
|
1728
|
-
props.onKeyDown?.(event);
|
|
1729
|
-
if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
|
|
1730
|
-
const target = event.target;
|
|
1731
|
-
const inInput = target instanceof HTMLInputElement;
|
|
1732
|
-
if (inInput) event.preventDefault();
|
|
1733
|
-
if (event.altKey || event.shiftKey) return;
|
|
1734
|
-
if (event.ctrlKey || event.metaKey) {
|
|
1735
|
-
event.preventDefault();
|
|
1736
|
-
form.current?.requestSubmit();
|
|
1737
|
-
return;
|
|
1738
|
-
}
|
|
1739
|
-
if (!inInput) return;
|
|
1740
|
-
const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
|
|
1741
|
-
if (enterSends && oneLine) form.current?.requestSubmit();
|
|
1742
|
-
};
|
|
1743
|
-
return /* @__PURE__ */ jsx25(
|
|
1744
|
-
BaseForm,
|
|
1745
|
-
{
|
|
1746
|
-
ref: form,
|
|
1747
|
-
...props,
|
|
1748
|
-
tabIndex: busy ? -1 : props.tabIndex,
|
|
1749
|
-
className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
|
|
1750
|
-
onFocus: (event) => {
|
|
1751
|
-
if (event.target !== form.current) lastInside.current = event.target;
|
|
1752
|
-
props.onFocus?.(event);
|
|
1753
|
-
},
|
|
1754
|
-
onBlur: (event) => {
|
|
1755
|
-
const next = event.relatedTarget;
|
|
1756
|
-
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1757
|
-
props.onBlur?.(event);
|
|
1758
|
-
},
|
|
1759
|
-
onKeyDown,
|
|
1760
|
-
onSubmit: (event) => {
|
|
1761
|
-
if (event.target !== event.currentTarget) return;
|
|
1762
|
-
event.preventDefault();
|
|
1763
|
-
if (busyNow.current) return;
|
|
1764
|
-
void onSubmit();
|
|
1765
|
-
},
|
|
1766
|
-
children: /* @__PURE__ */ jsx25(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx25(FormBusyContext.Provider, { value: busy, children }) })
|
|
1767
|
-
}
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
2060
|
// src/Skeleton.tsx
|
|
1772
|
-
import { jsx as
|
|
2061
|
+
import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1773
2062
|
function SkeletonBar({ className, style }) {
|
|
1774
|
-
return /* @__PURE__ */
|
|
2063
|
+
return /* @__PURE__ */ jsx31("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1775
2064
|
}
|
|
1776
2065
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1777
2066
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1778
|
-
return /* @__PURE__ */
|
|
1779
|
-
/* @__PURE__ */
|
|
1780
|
-
/* @__PURE__ */
|
|
2067
|
+
return /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
2068
|
+
/* @__PURE__ */ jsx31(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
2069
|
+
/* @__PURE__ */ jsx31(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1781
2070
|
] });
|
|
1782
2071
|
}
|
|
1783
2072
|
function SkeletonList({ rows = 8, className }) {
|
|
1784
|
-
return /* @__PURE__ */
|
|
2073
|
+
return /* @__PURE__ */ jsx31("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx31(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1785
2074
|
}
|
|
1786
2075
|
|
|
1787
2076
|
// src/CommandPalette.tsx
|
|
1788
|
-
import { Fragment as
|
|
1789
|
-
var PaletteContext =
|
|
2077
|
+
import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2078
|
+
var PaletteContext = createContext6(null);
|
|
1790
2079
|
function usePalette(part) {
|
|
1791
|
-
const palette =
|
|
2080
|
+
const palette = useContext6(PaletteContext);
|
|
1792
2081
|
if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
|
|
1793
2082
|
return palette;
|
|
1794
2083
|
}
|
|
@@ -1800,8 +2089,8 @@ function firstControl(popup) {
|
|
|
1800
2089
|
return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL2) ?? null;
|
|
1801
2090
|
}
|
|
1802
2091
|
function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
|
|
1803
|
-
const popupRef =
|
|
1804
|
-
|
|
2092
|
+
const popupRef = useRef7(null);
|
|
2093
|
+
useEffect4(() => {
|
|
1805
2094
|
if (!open) return;
|
|
1806
2095
|
const frame = requestAnimationFrame(() => {
|
|
1807
2096
|
const popup = popupRef.current;
|
|
@@ -1810,11 +2099,11 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1810
2099
|
});
|
|
1811
2100
|
return () => cancelAnimationFrame(frame);
|
|
1812
2101
|
});
|
|
1813
|
-
const context =
|
|
1814
|
-
return /* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
1817
|
-
|
|
2102
|
+
const context = useMemo3(() => ({ where, modKey, popupRef }), [where, modKey]);
|
|
2103
|
+
return /* @__PURE__ */ jsx32(Dialog3.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs23(Dialog3.Portal, { children: [
|
|
2104
|
+
/* @__PURE__ */ jsx32(Dialog3.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
2105
|
+
/* @__PURE__ */ jsx32(Dialog3.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx32(
|
|
2106
|
+
Dialog3.Popup,
|
|
1818
2107
|
{
|
|
1819
2108
|
ref: popupRef,
|
|
1820
2109
|
"aria-label": label,
|
|
@@ -1823,13 +2112,13 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1823
2112
|
if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
|
|
1824
2113
|
},
|
|
1825
2114
|
className: "flex w-[658px] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-lg border border-border-default bg-bg-elevated shadow-lg outline-none",
|
|
1826
|
-
children: /* @__PURE__ */
|
|
2115
|
+
children: /* @__PURE__ */ jsx32(PaletteContext.Provider, { value: context, children })
|
|
1827
2116
|
}
|
|
1828
2117
|
) })
|
|
1829
2118
|
] }) });
|
|
1830
2119
|
}
|
|
1831
2120
|
function LevelChip({ chip, onBack }) {
|
|
1832
|
-
return /* @__PURE__ */
|
|
2121
|
+
return /* @__PURE__ */ jsx32(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
|
|
1833
2122
|
}
|
|
1834
2123
|
function useBack(chip, popupRef) {
|
|
1835
2124
|
return () => {
|
|
@@ -1840,10 +2129,10 @@ function useBack(chip, popupRef) {
|
|
|
1840
2129
|
}
|
|
1841
2130
|
function Footer({ keys }) {
|
|
1842
2131
|
const { where } = usePalette("The footer");
|
|
1843
|
-
return /* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1845
|
-
keys.map(([key, word]) => /* @__PURE__ */
|
|
1846
|
-
/* @__PURE__ */
|
|
2132
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5", MONO_CAPTION_CLASSES, "signal:text-text-muted leaf:font-mono leaf:text-small"), children: [
|
|
2133
|
+
/* @__PURE__ */ jsx32("span", { className: "min-w-0 flex-1 truncate", children: where }),
|
|
2134
|
+
keys.map(([key, word]) => /* @__PURE__ */ jsxs23("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
2135
|
+
/* @__PURE__ */ jsx32(Kbd, { children: key }),
|
|
1847
2136
|
" ",
|
|
1848
2137
|
word
|
|
1849
2138
|
] }, key))
|
|
@@ -1853,14 +2142,14 @@ var lowerFirst = (s) => s.charAt(0).toLowerCase() + s.slice(1);
|
|
|
1853
2142
|
function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip, pending, notes = [], empty, children }) {
|
|
1854
2143
|
const { modKey, popupRef } = usePalette("CommandPaletteSearch");
|
|
1855
2144
|
const back = useBack(chip, popupRef);
|
|
1856
|
-
const items =
|
|
2145
|
+
const items = useMemo3(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
|
|
1857
2146
|
const rows = items.flatMap((g) => g.items);
|
|
1858
|
-
const [litId, setLitId] =
|
|
2147
|
+
const [litId, setLitId] = useState5();
|
|
1859
2148
|
const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
|
|
1860
|
-
const inputRef =
|
|
1861
|
-
const reported =
|
|
1862
|
-
const settled =
|
|
1863
|
-
const moved =
|
|
2149
|
+
const inputRef = useRef7(null);
|
|
2150
|
+
const reported = useRef7({});
|
|
2151
|
+
const settled = useRef7(null);
|
|
2152
|
+
const moved = useRef7(false);
|
|
1864
2153
|
useLayoutEffect3(() => {
|
|
1865
2154
|
const before = settled.current;
|
|
1866
2155
|
const now = reported.current;
|
|
@@ -1920,7 +2209,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1920
2209
|
...chip && query === "" ? [["Backspace", "back"]] : [],
|
|
1921
2210
|
["Esc", "close"]
|
|
1922
2211
|
];
|
|
1923
|
-
return /* @__PURE__ */
|
|
2212
|
+
return /* @__PURE__ */ jsxs23(
|
|
1924
2213
|
Autocomplete.Root,
|
|
1925
2214
|
{
|
|
1926
2215
|
items,
|
|
@@ -1943,10 +2232,10 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1943
2232
|
setLitId(id);
|
|
1944
2233
|
},
|
|
1945
2234
|
children: [
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
1948
|
-
chip && /* @__PURE__ */
|
|
1949
|
-
/* @__PURE__ */
|
|
2235
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
2236
|
+
/* @__PURE__ */ jsx32(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
2237
|
+
chip && /* @__PURE__ */ jsx32(LevelChip, { chip, onBack: back }),
|
|
2238
|
+
/* @__PURE__ */ jsx32(
|
|
1950
2239
|
Autocomplete.Input,
|
|
1951
2240
|
{
|
|
1952
2241
|
ref: inputRef,
|
|
@@ -1958,43 +2247,43 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1958
2247
|
}
|
|
1959
2248
|
)
|
|
1960
2249
|
] }),
|
|
1961
|
-
/* @__PURE__ */
|
|
1962
|
-
children != null && /* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
/* @__PURE__ */
|
|
1965
|
-
/* @__PURE__ */
|
|
2250
|
+
/* @__PURE__ */ jsxs23(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
2251
|
+
children != null && /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
2252
|
+
/* @__PURE__ */ jsx32(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs23(Autocomplete.Group, { items: group.items, className: "flex flex-col gap-0.5", children: [
|
|
2253
|
+
/* @__PURE__ */ jsx32(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx32(SectionLabel, { tone: "secondary", children: group.value }) }),
|
|
2254
|
+
/* @__PURE__ */ jsx32(Autocomplete.Collection, { children: (row) => (
|
|
1966
2255
|
/* The menu row, as the list's own option — the way Select
|
|
1967
2256
|
puts it on `Select.Item`. One row, two parts. */
|
|
1968
|
-
/* @__PURE__ */
|
|
2257
|
+
/* @__PURE__ */ jsx32(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx32(
|
|
1969
2258
|
MenuItemBody,
|
|
1970
2259
|
{
|
|
1971
2260
|
size: "tall",
|
|
1972
2261
|
label: row.label,
|
|
1973
2262
|
description: row.description,
|
|
1974
|
-
leading: /* @__PURE__ */
|
|
2263
|
+
leading: /* @__PURE__ */ jsx32(RowLeading, { row }),
|
|
1975
2264
|
submenu: !!row.onGoIn,
|
|
1976
|
-
hint: row.onGoIn ? /* @__PURE__ */
|
|
2265
|
+
hint: row.onGoIn ? /* @__PURE__ */ jsx32(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx32(EnterHint, {})
|
|
1977
2266
|
}
|
|
1978
2267
|
) }, row.id)
|
|
1979
2268
|
) })
|
|
1980
2269
|
] }, group.value) }),
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
1983
|
-
/* @__PURE__ */
|
|
2270
|
+
/* @__PURE__ */ jsx32(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs23(Fragment6, { children: [
|
|
2271
|
+
/* @__PURE__ */ jsx32(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
2272
|
+
/* @__PURE__ */ jsx32("span", { className: "text-caption text-text-muted", children: pending })
|
|
1984
2273
|
] }) }),
|
|
1985
|
-
notes.map((note) => /* @__PURE__ */
|
|
1986
|
-
/* @__PURE__ */
|
|
2274
|
+
notes.map((note) => /* @__PURE__ */ jsx32("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx32(FieldLine, { children: note }) }, note)),
|
|
2275
|
+
/* @__PURE__ */ jsx32(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx32(EmptyState, { scope: "section", message: empty }) })
|
|
1987
2276
|
] }),
|
|
1988
|
-
/* @__PURE__ */
|
|
2277
|
+
/* @__PURE__ */ jsx32(Footer, { keys })
|
|
1989
2278
|
]
|
|
1990
2279
|
}
|
|
1991
2280
|
);
|
|
1992
2281
|
}
|
|
1993
2282
|
function RowLeading({ row }) {
|
|
1994
2283
|
if (row.icon != null) {
|
|
1995
|
-
return /* @__PURE__ */
|
|
2284
|
+
return /* @__PURE__ */ jsx32("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
|
|
1996
2285
|
}
|
|
1997
|
-
return /* @__PURE__ */
|
|
2286
|
+
return /* @__PURE__ */ jsx32("span", { className: "flex size-8 items-center justify-center", children: row.leading });
|
|
1998
2287
|
}
|
|
1999
2288
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
2000
2289
|
function isTextField(el) {
|
|
@@ -2004,9 +2293,9 @@ function isTextField(el) {
|
|
|
2004
2293
|
function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
|
|
2005
2294
|
const { modKey, popupRef } = usePalette("CommandPaletteForm");
|
|
2006
2295
|
const back = useBack(chip, popupRef);
|
|
2007
|
-
const frameRef =
|
|
2296
|
+
const frameRef = useRef7(null);
|
|
2008
2297
|
const busy = !!working;
|
|
2009
|
-
const busyRef =
|
|
2298
|
+
const busyRef = useRef7(busy);
|
|
2010
2299
|
busyRef.current = busy;
|
|
2011
2300
|
const firstInvalid2 = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL2) ?? null;
|
|
2012
2301
|
const submit = () => {
|
|
@@ -2022,7 +2311,7 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
2022
2311
|
if (isTextField(el)) return el.value === "";
|
|
2023
2312
|
return ![...frame.querySelectorAll("input, textarea")].some(isTextField);
|
|
2024
2313
|
};
|
|
2025
|
-
const [backNamed, setBackNamed] =
|
|
2314
|
+
const [backNamed, setBackNamed] = useState5(false);
|
|
2026
2315
|
const measure = () => setBackNamed(backWorksFrom(document.activeElement));
|
|
2027
2316
|
useLayoutEffect3(measure);
|
|
2028
2317
|
const onKeyDown = (e) => {
|
|
@@ -2036,65 +2325,65 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
2036
2325
|
...backNamed ? [["Backspace", "back"]] : [],
|
|
2037
2326
|
["Esc", "close"]
|
|
2038
2327
|
];
|
|
2039
|
-
return /* @__PURE__ */
|
|
2040
|
-
/* @__PURE__ */
|
|
2041
|
-
icon != null && /* @__PURE__ */
|
|
2042
|
-
/* @__PURE__ */
|
|
2328
|
+
return /* @__PURE__ */ jsxs23("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
|
|
2329
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
2330
|
+
icon != null && /* @__PURE__ */ jsx32("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
2331
|
+
/* @__PURE__ */ jsx32(LevelChip, { chip, onBack: back })
|
|
2043
2332
|
] }),
|
|
2044
|
-
/* @__PURE__ */
|
|
2045
|
-
/* @__PURE__ */
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
2048
|
-
/* @__PURE__ */
|
|
2333
|
+
/* @__PURE__ */ jsxs23(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, layout: "free", className: "flex min-h-0 flex-col", children: [
|
|
2334
|
+
/* @__PURE__ */ jsx32(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx32("div", { className: FIELDS_CLASSES, children }) }),
|
|
2335
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
2336
|
+
/* @__PURE__ */ jsx32("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx32(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx32(FieldLine, { tone: "error", children: error }) : null }),
|
|
2337
|
+
/* @__PURE__ */ jsx32(
|
|
2049
2338
|
Button,
|
|
2050
2339
|
{
|
|
2051
2340
|
type: "submit",
|
|
2052
2341
|
variant: "primary",
|
|
2053
2342
|
disabled: busy,
|
|
2054
2343
|
disabledReason: busy ? void 0 : submitWaits,
|
|
2055
|
-
leadingIcon: busy ? /* @__PURE__ */
|
|
2344
|
+
leadingIcon: busy ? /* @__PURE__ */ jsx32(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
|
|
2056
2345
|
children: working ? working.button : submitLabel
|
|
2057
2346
|
}
|
|
2058
2347
|
)
|
|
2059
2348
|
] })
|
|
2060
2349
|
] }),
|
|
2061
|
-
/* @__PURE__ */
|
|
2350
|
+
/* @__PURE__ */ jsx32(Footer, { keys })
|
|
2062
2351
|
] });
|
|
2063
2352
|
}
|
|
2064
2353
|
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
2065
2354
|
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
2066
|
-
return /* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2355
|
+
return /* @__PURE__ */ jsxs23("div", { role: "status", className: "flex flex-col gap-2", children: [
|
|
2356
|
+
/* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
2357
|
+
/* @__PURE__ */ jsx32(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
2069
2358
|
children
|
|
2070
2359
|
] }),
|
|
2071
|
-
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */
|
|
2360
|
+
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx32(SkeletonBar, { className: cn("h-3", width) }, width))
|
|
2072
2361
|
] });
|
|
2073
2362
|
}
|
|
2074
2363
|
function CommandPaletteAnswer({ children, note }) {
|
|
2075
2364
|
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
2076
|
-
return /* @__PURE__ */
|
|
2077
|
-
paragraphs.map((paragraph, i) => /* @__PURE__ */
|
|
2078
|
-
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */
|
|
2365
|
+
return /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-2", children: [
|
|
2366
|
+
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx32("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
2367
|
+
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx32("sup", { className: "ml-0.5 font-mono text-small text-accent-text", children: part.slice(1, -1) }, j) : part
|
|
2079
2368
|
) }, i)),
|
|
2080
|
-
note && /* @__PURE__ */
|
|
2369
|
+
note && /* @__PURE__ */ jsx32(FieldLine, { children: note })
|
|
2081
2370
|
] });
|
|
2082
2371
|
}
|
|
2083
2372
|
function CommandPaletteQuote({ children }) {
|
|
2084
|
-
return /* @__PURE__ */
|
|
2373
|
+
return /* @__PURE__ */ jsx32("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
|
|
2085
2374
|
}
|
|
2086
2375
|
function CommandPaletteProposal({ source, mark, children }) {
|
|
2087
|
-
return /* @__PURE__ */
|
|
2088
|
-
/* @__PURE__ */
|
|
2376
|
+
return /* @__PURE__ */ jsxs23(Card, { fill: "surface", className: "flex flex-col gap-1 p-3", children: [
|
|
2377
|
+
/* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
2089
2378
|
mark,
|
|
2090
2379
|
source
|
|
2091
2380
|
] }),
|
|
2092
|
-
/* @__PURE__ */
|
|
2381
|
+
/* @__PURE__ */ jsx32("span", { className: "text-body-2 text-text-primary", children })
|
|
2093
2382
|
] });
|
|
2094
2383
|
}
|
|
2095
2384
|
|
|
2096
2385
|
// src/InlineChip.tsx
|
|
2097
|
-
import { Fragment as
|
|
2386
|
+
import { Fragment as Fragment7, jsx as jsx33, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2098
2387
|
var INLINE_CHIP_CLASSES = "inline-flex h-[1.4em] items-center gap-1 rounded-sm px-1 mx-0.5 align-top text-body-2 font-normal select-none";
|
|
2099
2388
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
2100
2389
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -2116,19 +2405,20 @@ function inlineChipClassName(tone, className) {
|
|
|
2116
2405
|
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
2117
2406
|
}
|
|
2118
2407
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2408
|
+
const inApp = useInAppClick(href, props.onClick);
|
|
2409
|
+
const body = /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
2410
|
+
icon && /* @__PURE__ */ jsx33("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
2121
2411
|
children
|
|
2122
2412
|
] });
|
|
2123
2413
|
const classes = inlineChipClassName(tone, className);
|
|
2124
2414
|
if (href === void 0) {
|
|
2125
|
-
return /* @__PURE__ */
|
|
2415
|
+
return /* @__PURE__ */ jsx33("span", { className: classes, ...props, children: body });
|
|
2126
2416
|
}
|
|
2127
|
-
return /* @__PURE__ */
|
|
2417
|
+
return /* @__PURE__ */ jsx33("a", { href, className: classes, ...props, onClick: inApp, children: body });
|
|
2128
2418
|
}
|
|
2129
2419
|
|
|
2130
2420
|
// src/RichText.tsx
|
|
2131
|
-
import { Fragment as
|
|
2421
|
+
import { Fragment as Fragment8, jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2132
2422
|
var RICH_TEXT_CLASSES = {
|
|
2133
2423
|
base: "flex flex-col gap-1 break-words text-text-secondary",
|
|
2134
2424
|
/* A heading binds to what follows it: 12px above (8 and the 4px gap), 8px below (4 and the gap); two headings in a row, 12px apart. Level 3 keeps the text's colour, one step lower. */
|
|
@@ -2160,35 +2450,35 @@ function textWithLinks(text, renderText) {
|
|
|
2160
2450
|
return parts.map((part, i) => {
|
|
2161
2451
|
const written = part.match(WRITTEN_LINK);
|
|
2162
2452
|
if (written) {
|
|
2163
|
-
return /* @__PURE__ */
|
|
2453
|
+
return /* @__PURE__ */ jsx34("span", { className: "break-words", children: /* @__PURE__ */ jsx34(Link, { href: written[2], external: true, onClick: keepToLink, children: written[1] }) }, i);
|
|
2164
2454
|
}
|
|
2165
2455
|
const bare = i % 2 === 1 ? part.match(BARE_LINK) : null;
|
|
2166
2456
|
if (bare) {
|
|
2167
2457
|
return (
|
|
2168
2458
|
// An address has no spaces to wrap at, so it may break anywhere.
|
|
2169
|
-
/* @__PURE__ */
|
|
2170
|
-
/* @__PURE__ */
|
|
2459
|
+
/* @__PURE__ */ jsxs25("span", { className: "break-all", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx34(Link, { href: bare[1], external: true, onClick: keepToLink, children: bare[1] }),
|
|
2171
2461
|
bare[2]
|
|
2172
2462
|
] }, i)
|
|
2173
2463
|
);
|
|
2174
2464
|
}
|
|
2175
|
-
return part ? /* @__PURE__ */
|
|
2465
|
+
return part ? /* @__PURE__ */ jsx34("span", { children: renderText(part) }, i) : null;
|
|
2176
2466
|
});
|
|
2177
2467
|
}
|
|
2178
2468
|
function Runs({ runs, draw }) {
|
|
2179
|
-
return /* @__PURE__ */
|
|
2180
|
-
if (run.reference) return /* @__PURE__ */
|
|
2469
|
+
return /* @__PURE__ */ jsx34(Fragment8, { children: (runs ?? []).map((run, i) => {
|
|
2470
|
+
if (run.reference) return /* @__PURE__ */ jsx34("span", { children: draw.renderReference(run.reference, run) }, i);
|
|
2181
2471
|
if (run.marks.includes("code")) {
|
|
2182
|
-
return /* @__PURE__ */
|
|
2472
|
+
return /* @__PURE__ */ jsx34("code", { children: run.text }, i);
|
|
2183
2473
|
}
|
|
2184
|
-
let node = run.text.split("\n").map((line, j) => /* @__PURE__ */
|
|
2185
|
-
j > 0 && /* @__PURE__ */
|
|
2474
|
+
let node = run.text.split("\n").map((line, j) => /* @__PURE__ */ jsxs25("span", { children: [
|
|
2475
|
+
j > 0 && /* @__PURE__ */ jsx34("br", {}),
|
|
2186
2476
|
textWithLinks(line, draw.renderText)
|
|
2187
2477
|
] }, j));
|
|
2188
|
-
if (run.marks.includes("underline")) node = /* @__PURE__ */
|
|
2189
|
-
if (run.marks.includes("italic")) node = /* @__PURE__ */
|
|
2190
|
-
if (run.marks.includes("bold")) node = /* @__PURE__ */
|
|
2191
|
-
return /* @__PURE__ */
|
|
2478
|
+
if (run.marks.includes("underline")) node = /* @__PURE__ */ jsx34("u", { children: node });
|
|
2479
|
+
if (run.marks.includes("italic")) node = /* @__PURE__ */ jsx34("em", { children: node });
|
|
2480
|
+
if (run.marks.includes("bold")) node = /* @__PURE__ */ jsx34("strong", { children: node });
|
|
2481
|
+
return /* @__PURE__ */ jsx34("span", { children: node }, i);
|
|
2192
2482
|
}) });
|
|
2193
2483
|
}
|
|
2194
2484
|
var named = (block) => block.typeName ?? block.type;
|
|
@@ -2199,15 +2489,15 @@ function Table({ block, draw }) {
|
|
|
2199
2489
|
const header = named(cell) === "tableHeader";
|
|
2200
2490
|
const Cell = header ? "th" : "td";
|
|
2201
2491
|
const { colspan, rowspan } = cell.attrs ?? {};
|
|
2202
|
-
return /* @__PURE__ */
|
|
2492
|
+
return /* @__PURE__ */ jsxs25(
|
|
2203
2493
|
Cell,
|
|
2204
2494
|
{
|
|
2205
2495
|
"data-block-id": cell.id,
|
|
2206
2496
|
colSpan: colspan && colspan > 1 ? colspan : void 0,
|
|
2207
2497
|
rowSpan: rowspan && rowspan > 1 ? rowspan : void 0,
|
|
2208
2498
|
children: [
|
|
2209
|
-
(cell.children ?? []).map((child, j) => /* @__PURE__ */
|
|
2210
|
-
/* @__PURE__ */
|
|
2499
|
+
(cell.children ?? []).map((child, j) => /* @__PURE__ */ jsx34(Runs, { runs: child.inline, draw }, j)),
|
|
2500
|
+
/* @__PURE__ */ jsx34(Runs, { runs: cell.inline, draw })
|
|
2211
2501
|
]
|
|
2212
2502
|
},
|
|
2213
2503
|
cell.id ?? i
|
|
@@ -2215,43 +2505,43 @@ function Table({ block, draw }) {
|
|
|
2215
2505
|
});
|
|
2216
2506
|
const first = rows[0].children ?? [];
|
|
2217
2507
|
const headerRow = first.length > 0 && first.every((cell) => named(cell) === "tableHeader");
|
|
2218
|
-
return /* @__PURE__ */
|
|
2219
|
-
headerRow && /* @__PURE__ */
|
|
2220
|
-
/* @__PURE__ */
|
|
2508
|
+
return /* @__PURE__ */ jsxs25("table", { "data-block-id": block.id, children: [
|
|
2509
|
+
headerRow && /* @__PURE__ */ jsx34("thead", { children: /* @__PURE__ */ jsx34("tr", { "data-block-id": rows[0].id, children: cells(rows[0]) }) }),
|
|
2510
|
+
/* @__PURE__ */ jsx34("tbody", { children: (headerRow ? rows.slice(1) : rows).map((row, i) => /* @__PURE__ */ jsx34("tr", { "data-block-id": row.id, children: cells(row) }, row.id ?? i)) })
|
|
2221
2511
|
] });
|
|
2222
2512
|
}
|
|
2223
2513
|
function Block({ block, draw }) {
|
|
2224
2514
|
const own = draw.renderBlock?.(block);
|
|
2225
2515
|
if (own !== void 0) return own;
|
|
2226
|
-
const runs = /* @__PURE__ */
|
|
2516
|
+
const runs = /* @__PURE__ */ jsx34(Runs, { runs: block.inline, draw });
|
|
2227
2517
|
switch (block.type) {
|
|
2228
2518
|
case "heading": {
|
|
2229
|
-
if (block.level === 1) return /* @__PURE__ */
|
|
2230
|
-
if (block.level === 3) return /* @__PURE__ */
|
|
2231
|
-
return /* @__PURE__ */
|
|
2519
|
+
if (block.level === 1) return /* @__PURE__ */ jsx34("h1", { "data-block-id": block.id, children: runs });
|
|
2520
|
+
if (block.level === 3) return /* @__PURE__ */ jsx34("h3", { "data-block-id": block.id, children: runs });
|
|
2521
|
+
return /* @__PURE__ */ jsx34("h2", { "data-block-id": block.id, children: runs });
|
|
2232
2522
|
}
|
|
2233
2523
|
case "paragraph":
|
|
2234
|
-
return /* @__PURE__ */
|
|
2524
|
+
return /* @__PURE__ */ jsx34("p", { "data-block-id": block.id, children: runs });
|
|
2235
2525
|
case "bulletList":
|
|
2236
2526
|
case "orderedList": {
|
|
2237
|
-
const items = (block.children ?? []).map((item, i) => /* @__PURE__ */
|
|
2238
|
-
return block.type === "bulletList" ? /* @__PURE__ */
|
|
2527
|
+
const items = (block.children ?? []).map((item, i) => /* @__PURE__ */ jsx34("li", { "data-block-id": item.id, children: /* @__PURE__ */ jsx34(Runs, { runs: item.inline, draw }) }, item.id ?? i));
|
|
2528
|
+
return block.type === "bulletList" ? /* @__PURE__ */ jsx34("ul", { "data-block-id": block.id, children: items }) : /* @__PURE__ */ jsx34("ol", { "data-block-id": block.id, start: block.start, children: items });
|
|
2239
2529
|
}
|
|
2240
2530
|
case "blockquote":
|
|
2241
|
-
return /* @__PURE__ */
|
|
2531
|
+
return /* @__PURE__ */ jsx34("blockquote", { "data-block-id": block.id, children: runs });
|
|
2242
2532
|
case "codeBlock":
|
|
2243
|
-
return /* @__PURE__ */
|
|
2533
|
+
return /* @__PURE__ */ jsx34("pre", { "data-block-id": block.id, "data-language": block.language, children: /* @__PURE__ */ jsx34("code", { children: (block.inline ?? []).map((run) => run.text).join("") }) });
|
|
2244
2534
|
case "horizontalRule":
|
|
2245
|
-
return /* @__PURE__ */
|
|
2535
|
+
return /* @__PURE__ */ jsx34("hr", { "data-block-id": block.id });
|
|
2246
2536
|
case "table": {
|
|
2247
|
-
const table = /* @__PURE__ */
|
|
2537
|
+
const table = /* @__PURE__ */ jsx34(Table, { block, draw });
|
|
2248
2538
|
if ((block.children ?? []).some((row) => named(row) === "tableRow")) return table;
|
|
2249
2539
|
break;
|
|
2250
2540
|
}
|
|
2251
2541
|
}
|
|
2252
|
-
return /* @__PURE__ */
|
|
2542
|
+
return /* @__PURE__ */ jsxs25("div", { "data-block-id": block.id, "data-block-type": named(block), children: [
|
|
2253
2543
|
runs,
|
|
2254
|
-
(block.children ?? []).map((child, i) => /* @__PURE__ */
|
|
2544
|
+
(block.children ?? []).map((child, i) => /* @__PURE__ */ jsx34(Block, { block: child, draw }, child.id ?? i))
|
|
2255
2545
|
] });
|
|
2256
2546
|
}
|
|
2257
2547
|
function RichText({
|
|
@@ -2263,34 +2553,34 @@ function RichText({
|
|
|
2263
2553
|
}) {
|
|
2264
2554
|
if (blocks.length === 0) return null;
|
|
2265
2555
|
const draw = { renderText, renderReference, renderBlock };
|
|
2266
|
-
return /* @__PURE__ */
|
|
2556
|
+
return /* @__PURE__ */ jsx34("div", { "data-rich-text": true, className: richTextClassName(size), children: blocks.map((block, i) => /* @__PURE__ */ jsx34(Block, { block, draw }, block.id ?? i)) });
|
|
2267
2557
|
}
|
|
2268
2558
|
|
|
2269
2559
|
// src/IdentityMenu.tsx
|
|
2270
|
-
import { useCallback as useCallback2, useRef as
|
|
2560
|
+
import { useCallback as useCallback2, useRef as useRef8 } from "react";
|
|
2271
2561
|
|
|
2272
2562
|
// src/Person.tsx
|
|
2273
|
-
import { jsx as
|
|
2563
|
+
import { jsx as jsx35, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2274
2564
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
2275
2565
|
return (
|
|
2276
2566
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
2277
2567
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
2278
2568
|
// row agree by construction.
|
|
2279
|
-
/* @__PURE__ */
|
|
2280
|
-
/* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2569
|
+
/* @__PURE__ */ jsxs26("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
2570
|
+
/* @__PURE__ */ jsx35(Avatar, { name, src: picture, size }),
|
|
2571
|
+
/* @__PURE__ */ jsx35("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
2282
2572
|
] })
|
|
2283
2573
|
);
|
|
2284
2574
|
}
|
|
2285
2575
|
|
|
2286
2576
|
// src/PersonTrigger.tsx
|
|
2287
|
-
import { Button as
|
|
2288
|
-
import { IconChevronDown } from "@tabler/icons-react";
|
|
2289
|
-
import { jsx as
|
|
2577
|
+
import { Button as BaseButton7 } from "@base-ui/react/button";
|
|
2578
|
+
import { IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
2579
|
+
import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2290
2580
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
2291
2581
|
if (compact) {
|
|
2292
|
-
return /* @__PURE__ */
|
|
2293
|
-
|
|
2582
|
+
return /* @__PURE__ */ jsx36(
|
|
2583
|
+
BaseButton7,
|
|
2294
2584
|
{
|
|
2295
2585
|
type: "button",
|
|
2296
2586
|
"aria-haspopup": "menu",
|
|
@@ -2298,14 +2588,14 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2298
2588
|
"aria-label": props["aria-label"] ?? name ?? fallback,
|
|
2299
2589
|
className: cn("cursor-pointer rounded-full", className),
|
|
2300
2590
|
...props,
|
|
2301
|
-
children: /* @__PURE__ */
|
|
2591
|
+
children: /* @__PURE__ */ jsx36(Avatar, { name, src: picture, size: size ?? 36 })
|
|
2302
2592
|
}
|
|
2303
2593
|
);
|
|
2304
2594
|
}
|
|
2305
2595
|
return (
|
|
2306
2596
|
// @estiva-escape(no-copied-look): N5 (Katerina, 24 September: record only): a row that fills on hover, as NavItem also does
|
|
2307
|
-
/* @__PURE__ */
|
|
2308
|
-
|
|
2597
|
+
/* @__PURE__ */ jsxs27(
|
|
2598
|
+
BaseButton7,
|
|
2309
2599
|
{
|
|
2310
2600
|
type: "button",
|
|
2311
2601
|
"aria-haspopup": "menu",
|
|
@@ -2322,8 +2612,8 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2322
2612
|
),
|
|
2323
2613
|
...props,
|
|
2324
2614
|
children: [
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2615
|
+
/* @__PURE__ */ jsx36(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
2616
|
+
/* @__PURE__ */ jsx36(IconChevronDown2, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
2327
2617
|
]
|
|
2328
2618
|
}
|
|
2329
2619
|
)
|
|
@@ -2331,10 +2621,10 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2331
2621
|
}
|
|
2332
2622
|
|
|
2333
2623
|
// src/IdentityMenu.tsx
|
|
2334
|
-
import { Fragment as
|
|
2624
|
+
import { Fragment as Fragment9, jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2335
2625
|
function IdentityPanel({ className, onClose = () => {
|
|
2336
2626
|
}, ...rest }) {
|
|
2337
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsx37(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx37(IdentityRows, { ...rest, onClose }) });
|
|
2338
2628
|
}
|
|
2339
2629
|
function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
|
|
2340
2630
|
const act = (action) => () => {
|
|
@@ -2342,53 +2632,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
2342
2632
|
action();
|
|
2343
2633
|
};
|
|
2344
2634
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
2345
|
-
return /* @__PURE__ */
|
|
2346
|
-
/* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2348
|
-
/* @__PURE__ */
|
|
2349
|
-
me.email && /* @__PURE__ */
|
|
2635
|
+
return /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2636
|
+
/* @__PURE__ */ jsxs28(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
2637
|
+
/* @__PURE__ */ jsx37(MenuRow, { children: /* @__PURE__ */ jsx37("div", { className: "flex min-w-0 text-body-2-strong", children: /* @__PURE__ */ jsx37(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28 }) }) }),
|
|
2638
|
+
/* @__PURE__ */ jsx37(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
|
|
2639
|
+
me.email && /* @__PURE__ */ jsxs28(Note, { children: [
|
|
2350
2640
|
me.email,
|
|
2351
2641
|
" \xB7 known to Estiva, never published to the relay"
|
|
2352
2642
|
] })
|
|
2353
2643
|
] }),
|
|
2354
|
-
relayUrl && /* @__PURE__ */
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
/* @__PURE__ */
|
|
2358
|
-
/* @__PURE__ */
|
|
2644
|
+
relayUrl && /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2645
|
+
/* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }),
|
|
2646
|
+
/* @__PURE__ */ jsxs28(MenuSection, { label: "Workspace", children: [
|
|
2647
|
+
/* @__PURE__ */ jsx37(MenuRow, { children: /* @__PURE__ */ jsx37("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
2648
|
+
/* @__PURE__ */ jsx37(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
2359
2649
|
] })
|
|
2360
2650
|
] }),
|
|
2361
|
-
appRows && /* @__PURE__ */
|
|
2362
|
-
/* @__PURE__ */
|
|
2651
|
+
appRows && /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2652
|
+
/* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }),
|
|
2363
2653
|
appRows
|
|
2364
2654
|
] }),
|
|
2365
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
2366
|
-
signedIn && idBase && /* @__PURE__ */
|
|
2655
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }) : null,
|
|
2656
|
+
signedIn && idBase && /* @__PURE__ */ jsx37(
|
|
2367
2657
|
MenuItem,
|
|
2368
2658
|
{
|
|
2369
2659
|
label: "Edit your profile in Estiva ID",
|
|
2370
2660
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
2371
2661
|
}
|
|
2372
2662
|
),
|
|
2373
|
-
onCopyKey && /* @__PURE__ */
|
|
2374
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
2663
|
+
onCopyKey && /* @__PURE__ */ jsx37(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
2664
|
+
idBase && onSignOut && /* @__PURE__ */ jsx37(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
2375
2665
|
] });
|
|
2376
2666
|
}
|
|
2377
2667
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
2378
|
-
const actions =
|
|
2668
|
+
const actions = useRef8(null);
|
|
2379
2669
|
const close = useCallback2(() => actions.current?.close(), []);
|
|
2380
2670
|
return (
|
|
2381
2671
|
/* The wrapper carries the caller's `className` and nothing else. It used
|
|
2382
2672
|
to be `relative`, because the panel was positioned against it; the panel
|
|
2383
2673
|
hangs from the trigger and portals now, so a positioning context here
|
|
2384
2674
|
would only be a lie about what this box does. */
|
|
2385
|
-
/* @__PURE__ */
|
|
2675
|
+
/* @__PURE__ */ jsx37("div", { className, children: /* @__PURE__ */ jsx37(
|
|
2386
2676
|
Menu,
|
|
2387
2677
|
{
|
|
2388
2678
|
align: "right",
|
|
2389
2679
|
actionsRef: actions,
|
|
2390
2680
|
className: "w-72",
|
|
2391
|
-
trigger: /* @__PURE__ */
|
|
2681
|
+
trigger: /* @__PURE__ */ jsx37(
|
|
2392
2682
|
PersonTrigger,
|
|
2393
2683
|
{
|
|
2394
2684
|
name: me.name,
|
|
@@ -2399,7 +2689,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
2399
2689
|
"aria-label": compact ? "Account menu" : void 0
|
|
2400
2690
|
}
|
|
2401
2691
|
),
|
|
2402
|
-
children: /* @__PURE__ */
|
|
2692
|
+
children: /* @__PURE__ */ jsx37(
|
|
2403
2693
|
IdentityRows,
|
|
2404
2694
|
{
|
|
2405
2695
|
me,
|
|
@@ -2417,14 +2707,14 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
2417
2707
|
);
|
|
2418
2708
|
}
|
|
2419
2709
|
function Note({ children }) {
|
|
2420
|
-
return /* @__PURE__ */
|
|
2710
|
+
return /* @__PURE__ */ jsx37("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
2421
2711
|
}
|
|
2422
2712
|
|
|
2423
2713
|
// src/FilePicker.tsx
|
|
2424
2714
|
import { forwardRef } from "react";
|
|
2425
|
-
import { jsx as
|
|
2715
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
2426
2716
|
var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
2427
|
-
return /* @__PURE__ */
|
|
2717
|
+
return /* @__PURE__ */ jsx38(
|
|
2428
2718
|
"input",
|
|
2429
2719
|
{
|
|
2430
2720
|
ref,
|
|
@@ -2443,9 +2733,9 @@ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
|
2443
2733
|
});
|
|
2444
2734
|
|
|
2445
2735
|
// src/Select.tsx
|
|
2446
|
-
import { IconCheck as IconCheck2, IconChevronDown as
|
|
2736
|
+
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
2447
2737
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
2448
|
-
import { jsx as
|
|
2738
|
+
import { jsx as jsx39, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2449
2739
|
var GAP4 = 4;
|
|
2450
2740
|
var VIEWPORT_PAD4 = 8;
|
|
2451
2741
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, disabledReason, className, ...aria }) {
|
|
@@ -2453,7 +2743,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2453
2743
|
const held = Boolean(disabledReason);
|
|
2454
2744
|
const trigger = (
|
|
2455
2745
|
// @estiva-escape(no-copied-look): N1 (Katerina, 24 September: record only): Select's box drops the hover while held, so it cannot take FIELD_SHELL_CLASSES as it is
|
|
2456
|
-
/* @__PURE__ */
|
|
2746
|
+
/* @__PURE__ */ jsxs29(
|
|
2457
2747
|
BaseSelect.Trigger,
|
|
2458
2748
|
{
|
|
2459
2749
|
"aria-label": ariaLabel,
|
|
@@ -2486,21 +2776,21 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2486
2776
|
className
|
|
2487
2777
|
),
|
|
2488
2778
|
children: [
|
|
2489
|
-
/* @__PURE__ */
|
|
2490
|
-
selected?.leading && /* @__PURE__ */
|
|
2491
|
-
/* @__PURE__ */
|
|
2779
|
+
/* @__PURE__ */ jsxs29("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
2780
|
+
selected?.leading && /* @__PURE__ */ jsx39("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
2781
|
+
/* @__PURE__ */ jsx39(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
|
|
2492
2782
|
] }),
|
|
2493
|
-
/* @__PURE__ */
|
|
2783
|
+
/* @__PURE__ */ jsx39(
|
|
2494
2784
|
BaseSelect.Icon,
|
|
2495
2785
|
{
|
|
2496
|
-
render: /* @__PURE__ */
|
|
2786
|
+
render: /* @__PURE__ */ jsx39(IconChevronDown3, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2497
2787
|
}
|
|
2498
2788
|
)
|
|
2499
2789
|
]
|
|
2500
2790
|
}
|
|
2501
2791
|
)
|
|
2502
2792
|
);
|
|
2503
|
-
return /* @__PURE__ */
|
|
2793
|
+
return /* @__PURE__ */ jsxs29(
|
|
2504
2794
|
BaseSelect.Root,
|
|
2505
2795
|
{
|
|
2506
2796
|
value,
|
|
@@ -2512,8 +2802,8 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2512
2802
|
disabled: disabled && !held,
|
|
2513
2803
|
modal: false,
|
|
2514
2804
|
children: [
|
|
2515
|
-
held ? /* @__PURE__ */
|
|
2516
|
-
/* @__PURE__ */
|
|
2805
|
+
held ? /* @__PURE__ */ jsx39(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
|
|
2806
|
+
/* @__PURE__ */ jsx39(BaseSelect.Portal, { children: /* @__PURE__ */ jsx39(
|
|
2517
2807
|
BaseSelect.Positioner,
|
|
2518
2808
|
{
|
|
2519
2809
|
side: "bottom",
|
|
@@ -2522,25 +2812,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2522
2812
|
collisionPadding: VIEWPORT_PAD4,
|
|
2523
2813
|
alignItemWithTrigger: false,
|
|
2524
2814
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2525
|
-
children: /* @__PURE__ */
|
|
2815
|
+
children: /* @__PURE__ */ jsx39(
|
|
2526
2816
|
BaseSelect.Popup,
|
|
2527
2817
|
{
|
|
2528
|
-
render: /* @__PURE__ */
|
|
2818
|
+
render: /* @__PURE__ */ jsx39(MenuPanel, {}),
|
|
2529
2819
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
2530
|
-
children: /* @__PURE__ */
|
|
2820
|
+
children: /* @__PURE__ */ jsx39(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col gap-0.5 p-2", children: options.map((option) => /* @__PURE__ */ jsxs29(
|
|
2531
2821
|
BaseSelect.Item,
|
|
2532
2822
|
{
|
|
2533
2823
|
value: option.value,
|
|
2534
2824
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
2535
2825
|
children: [
|
|
2536
|
-
/* @__PURE__ */
|
|
2537
|
-
option.leading && /* @__PURE__ */
|
|
2538
|
-
/* @__PURE__ */
|
|
2826
|
+
/* @__PURE__ */ jsxs29("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2827
|
+
option.leading && /* @__PURE__ */ jsx39("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
2828
|
+
/* @__PURE__ */ jsx39(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
|
|
2539
2829
|
] }),
|
|
2540
|
-
/* @__PURE__ */
|
|
2830
|
+
/* @__PURE__ */ jsx39(
|
|
2541
2831
|
BaseSelect.ItemIndicator,
|
|
2542
2832
|
{
|
|
2543
|
-
render: /* @__PURE__ */
|
|
2833
|
+
render: /* @__PURE__ */ jsx39(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2544
2834
|
}
|
|
2545
2835
|
)
|
|
2546
2836
|
]
|
|
@@ -2559,9 +2849,9 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2559
2849
|
// src/TextInput.tsx
|
|
2560
2850
|
import { forwardRef as forwardRef2 } from "react";
|
|
2561
2851
|
import { Input } from "@base-ui/react/input";
|
|
2562
|
-
import { jsx as
|
|
2852
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2563
2853
|
var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
|
|
2564
|
-
return /* @__PURE__ */
|
|
2854
|
+
return /* @__PURE__ */ jsx40(
|
|
2565
2855
|
Input,
|
|
2566
2856
|
{
|
|
2567
2857
|
ref,
|
|
@@ -2587,13 +2877,13 @@ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size
|
|
|
2587
2877
|
// src/Textarea.tsx
|
|
2588
2878
|
import { forwardRef as forwardRef3 } from "react";
|
|
2589
2879
|
import { Field as BaseField3 } from "@base-ui/react/field";
|
|
2590
|
-
import { jsx as
|
|
2880
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
2591
2881
|
var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
|
|
2592
|
-
return /* @__PURE__ */
|
|
2882
|
+
return /* @__PURE__ */ jsx41(
|
|
2593
2883
|
BaseField3.Control,
|
|
2594
2884
|
{
|
|
2595
2885
|
ref,
|
|
2596
|
-
render: /* @__PURE__ */
|
|
2886
|
+
render: /* @__PURE__ */ jsx41("textarea", {}),
|
|
2597
2887
|
className: cn(
|
|
2598
2888
|
// The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
|
|
2599
2889
|
// "aren't there hover states in text input and text area?"). Focus comes after hover in
|
|
@@ -2612,110 +2902,10 @@ var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
|
|
|
2612
2902
|
});
|
|
2613
2903
|
|
|
2614
2904
|
// src/ConfirmDialog.tsx
|
|
2615
|
-
import { useState as
|
|
2616
|
-
|
|
2617
|
-
// src/DialogShell.tsx
|
|
2618
|
-
import { useRef as useRef7 } from "react";
|
|
2619
|
-
import { Dialog as Dialog3 } from "@base-ui/react/dialog";
|
|
2620
|
-
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
2621
|
-
import { IconX as IconX5 } from "@tabler/icons-react";
|
|
2622
|
-
|
|
2623
|
-
// src/ContainerHeader.tsx
|
|
2624
|
-
import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
2625
|
-
import { Button as BaseButton6 } from "@base-ui/react/button";
|
|
2626
|
-
import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2627
|
-
function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
|
|
2628
|
-
const text = typeof title === "string";
|
|
2629
|
-
const name = /* @__PURE__ */ jsxs26("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
|
|
2630
|
-
text ? /* @__PURE__ */ jsx37("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx37("div", { className: "min-w-0 flex-1", children: title }),
|
|
2631
|
-
(chevron || titleMenu != null) && /* @__PURE__ */ jsx37(IconChevronDown3, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2632
|
-
] });
|
|
2633
|
-
return (
|
|
2634
|
-
// The title 16px in, where the column's content starts (Katerina, 7 October; it was 20px).
|
|
2635
|
-
// With a title menu the bar gives the button 6px of its left padding
|
|
2636
|
-
// (pl-2.5 + the button's px-1.5 = pl-4): the words stay where a title's
|
|
2637
|
-
// are, and the fill is inside the bar — a negative margin had it clipped
|
|
2638
|
-
// (Katerina, 5 October).
|
|
2639
|
-
/* @__PURE__ */ jsxs26("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-2.5" : "pl-4", className), children: [
|
|
2640
|
-
/* @__PURE__ */ jsx37("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx37(
|
|
2641
|
-
Menu,
|
|
2642
|
-
{
|
|
2643
|
-
trigger: /* @__PURE__ */ jsx37(BaseButton6, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
|
|
2644
|
-
children: titleMenu
|
|
2645
|
-
}
|
|
2646
|
-
) : name }),
|
|
2647
|
-
actions && /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
|
|
2648
|
-
] })
|
|
2649
|
-
);
|
|
2650
|
-
}
|
|
2651
|
-
|
|
2652
|
-
// src/DialogShell.tsx
|
|
2653
|
-
import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2654
|
-
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
2655
|
-
const Parts = alert ? AlertDialog : Dialog3;
|
|
2656
|
-
const popupRef = useRef7(null);
|
|
2657
|
-
return /* @__PURE__ */ jsx38(
|
|
2658
|
-
Parts.Root,
|
|
2659
|
-
{
|
|
2660
|
-
open: true,
|
|
2661
|
-
onOpenChange: (open) => {
|
|
2662
|
-
if (!open) onClose();
|
|
2663
|
-
},
|
|
2664
|
-
children: /* @__PURE__ */ jsxs27(Parts.Portal, { children: [
|
|
2665
|
-
/* @__PURE__ */ jsx38(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
2666
|
-
/* @__PURE__ */ jsx38("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs27(
|
|
2667
|
-
Parts.Popup,
|
|
2668
|
-
{
|
|
2669
|
-
ref: popupRef,
|
|
2670
|
-
initialFocus: popupRef,
|
|
2671
|
-
"aria-label": headerContent != null ? title : void 0,
|
|
2672
|
-
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
2673
|
-
style: { width },
|
|
2674
|
-
children: [
|
|
2675
|
-
/* @__PURE__ */ jsx38(
|
|
2676
|
-
ContainerHeader,
|
|
2677
|
-
{
|
|
2678
|
-
className: "pl-5",
|
|
2679
|
-
title: headerContent ?? /* @__PURE__ */ jsx38(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx38("span", {}), children: title }),
|
|
2680
|
-
actions: (
|
|
2681
|
-
/*
|
|
2682
|
-
The ✕ IS the `Close` part now, rather than a button that calls
|
|
2683
|
-
`onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
|
|
2684
|
-
this: an `IconButton` carrying a `tooltip` returned the tooltip
|
|
2685
|
-
wrapper `<div>` as its root, so the part composed onto the
|
|
2686
|
-
wrapper and not the button. Porting Tooltip removed the wrapper
|
|
2687
|
-
— the trigger is the button itself — and the composition works.
|
|
2688
|
-
|
|
2689
|
-
What it buys: the dialog closes through its own state machine,
|
|
2690
|
-
so the ✕, Escape and the outside press are one path with one
|
|
2691
|
-
reason attached, instead of one of the three going around.
|
|
2692
|
-
*/
|
|
2693
|
-
/* @__PURE__ */ jsx38(
|
|
2694
|
-
Parts.Close,
|
|
2695
|
-
{
|
|
2696
|
-
render: /* @__PURE__ */ jsx38(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx38(IconX5, { size: 16, stroke: 1.5 }) })
|
|
2697
|
-
}
|
|
2698
|
-
)
|
|
2699
|
-
)
|
|
2700
|
-
}
|
|
2701
|
-
),
|
|
2702
|
-
bodyMaxHeight ? (
|
|
2703
|
-
// The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
|
|
2704
|
-
/* @__PURE__ */ jsx38("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx38(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
|
|
2705
|
-
) : /* @__PURE__ */ jsx38("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
2706
|
-
footer != null && /* @__PURE__ */ jsx38("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
2707
|
-
]
|
|
2708
|
-
}
|
|
2709
|
-
) })
|
|
2710
|
-
] })
|
|
2711
|
-
}
|
|
2712
|
-
);
|
|
2713
|
-
}
|
|
2714
|
-
|
|
2715
|
-
// src/ConfirmDialog.tsx
|
|
2716
|
-
import { Fragment as Fragment9, jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2905
|
+
import { useState as useState6 } from "react";
|
|
2906
|
+
import { Fragment as Fragment10, jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2717
2907
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
2718
|
-
const [busy, setBusy] =
|
|
2908
|
+
const [busy, setBusy] = useState6(false);
|
|
2719
2909
|
const confirm = async () => {
|
|
2720
2910
|
setBusy(true);
|
|
2721
2911
|
try {
|
|
@@ -2725,32 +2915,32 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
2725
2915
|
setBusy(false);
|
|
2726
2916
|
}
|
|
2727
2917
|
};
|
|
2728
|
-
return /* @__PURE__ */
|
|
2918
|
+
return /* @__PURE__ */ jsx42(
|
|
2729
2919
|
DialogShell,
|
|
2730
2920
|
{
|
|
2731
2921
|
alert: true,
|
|
2732
2922
|
title,
|
|
2733
2923
|
onClose,
|
|
2734
|
-
footer: /* @__PURE__ */
|
|
2735
|
-
/* @__PURE__ */
|
|
2736
|
-
/* @__PURE__ */
|
|
2924
|
+
footer: /* @__PURE__ */ jsxs30(Fragment10, { children: [
|
|
2925
|
+
/* @__PURE__ */ jsx42(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2926
|
+
/* @__PURE__ */ jsx42(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
2737
2927
|
] }),
|
|
2738
|
-
children: /* @__PURE__ */
|
|
2928
|
+
children: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-3 text-body-2 text-text-primary", children })
|
|
2739
2929
|
}
|
|
2740
2930
|
);
|
|
2741
2931
|
}
|
|
2742
2932
|
|
|
2743
2933
|
// src/EditableText.tsx
|
|
2744
|
-
import { useEffect as
|
|
2934
|
+
import { useEffect as useEffect5, useRef as useRef9, useState as useState7 } from "react";
|
|
2745
2935
|
import { Field as BaseField4 } from "@base-ui/react/field";
|
|
2746
2936
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
2747
|
-
import { jsx as
|
|
2937
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
2748
2938
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
2749
|
-
const [editing, setEditing] =
|
|
2750
|
-
const [draft, setDraft] =
|
|
2751
|
-
const [busy, setBusy] =
|
|
2752
|
-
const fieldRef =
|
|
2753
|
-
|
|
2939
|
+
const [editing, setEditing] = useState7(false);
|
|
2940
|
+
const [draft, setDraft] = useState7(value);
|
|
2941
|
+
const [busy, setBusy] = useState7(false);
|
|
2942
|
+
const fieldRef = useRef9(null);
|
|
2943
|
+
useEffect5(() => {
|
|
2754
2944
|
if (editing) {
|
|
2755
2945
|
fieldRef.current?.focus();
|
|
2756
2946
|
fieldRef.current?.select();
|
|
@@ -2802,7 +2992,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2802
2992
|
written and never read. Read-only, this is a line of text: whatever
|
|
2803
2993
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
2804
2994
|
*/
|
|
2805
|
-
/* @__PURE__ */
|
|
2995
|
+
/* @__PURE__ */ jsx43(
|
|
2806
2996
|
"div",
|
|
2807
2997
|
{
|
|
2808
2998
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -2812,11 +3002,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2812
3002
|
);
|
|
2813
3003
|
}
|
|
2814
3004
|
if (editing) {
|
|
2815
|
-
return multiline ? /* @__PURE__ */
|
|
3005
|
+
return multiline ? /* @__PURE__ */ jsx43(
|
|
2816
3006
|
BaseField4.Control,
|
|
2817
3007
|
{
|
|
2818
3008
|
ref: fieldRef,
|
|
2819
|
-
render: /* @__PURE__ */
|
|
3009
|
+
render: /* @__PURE__ */ jsx43("textarea", { rows: 4 }),
|
|
2820
3010
|
"aria-label": label,
|
|
2821
3011
|
value: draft,
|
|
2822
3012
|
disabled: busy,
|
|
@@ -2825,7 +3015,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2825
3015
|
onBlur: () => void commit(),
|
|
2826
3016
|
className: fieldClass
|
|
2827
3017
|
}
|
|
2828
|
-
) : /* @__PURE__ */
|
|
3018
|
+
) : /* @__PURE__ */ jsx43(
|
|
2829
3019
|
Input2,
|
|
2830
3020
|
{
|
|
2831
3021
|
ref: fieldRef,
|
|
@@ -2839,7 +3029,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2839
3029
|
}
|
|
2840
3030
|
);
|
|
2841
3031
|
}
|
|
2842
|
-
return /* @__PURE__ */
|
|
3032
|
+
return /* @__PURE__ */ jsx43(
|
|
2843
3033
|
"button",
|
|
2844
3034
|
{
|
|
2845
3035
|
type: "button",
|
|
@@ -2859,7 +3049,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2859
3049
|
// src/ErrorBoundary.tsx
|
|
2860
3050
|
import { Component } from "react";
|
|
2861
3051
|
import { IconAlertTriangle as IconAlertTriangle2 } from "@tabler/icons-react";
|
|
2862
|
-
import { jsx as
|
|
3052
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
2863
3053
|
var ErrorBoundary = class extends Component {
|
|
2864
3054
|
state = { hasError: false };
|
|
2865
3055
|
static getDerivedStateFromError() {
|
|
@@ -2870,22 +3060,22 @@ var ErrorBoundary = class extends Component {
|
|
|
2870
3060
|
}
|
|
2871
3061
|
render() {
|
|
2872
3062
|
if (!this.state.hasError) return this.props.children;
|
|
2873
|
-
const message = /* @__PURE__ */
|
|
3063
|
+
const message = /* @__PURE__ */ jsx44(
|
|
2874
3064
|
EmptyState,
|
|
2875
3065
|
{
|
|
2876
|
-
icon: /* @__PURE__ */
|
|
3066
|
+
icon: /* @__PURE__ */ jsx44(IconAlertTriangle2, { size: 16, stroke: 1.5 }),
|
|
2877
3067
|
message: `Something went wrong${this.props.label ? ` in the ${this.props.label}` : ""}. Your data is safe \u2014 try again.`,
|
|
2878
3068
|
action: { label: "Try again", onClick: () => this.setState({ hasError: false }) }
|
|
2879
3069
|
}
|
|
2880
3070
|
);
|
|
2881
3071
|
if (this.props.frame) return this.props.frame(message);
|
|
2882
|
-
return this.props.fallbackClassName ? /* @__PURE__ */
|
|
3072
|
+
return this.props.fallbackClassName ? /* @__PURE__ */ jsx44("div", { className: this.props.fallbackClassName, children: message }) : message;
|
|
2883
3073
|
}
|
|
2884
3074
|
};
|
|
2885
3075
|
|
|
2886
3076
|
// src/ProgressBar.tsx
|
|
2887
3077
|
import { Progress } from "@base-ui/react/progress";
|
|
2888
|
-
import { jsx as
|
|
3078
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
2889
3079
|
var TRACK_CLASSES = {
|
|
2890
3080
|
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
2891
3081
|
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
@@ -2898,17 +3088,17 @@ var INDICATOR_CLASSES = {
|
|
|
2898
3088
|
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
2899
3089
|
return (
|
|
2900
3090
|
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
2901
|
-
/* @__PURE__ */
|
|
3091
|
+
/* @__PURE__ */ jsx45(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx45(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx45(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
|
|
2902
3092
|
);
|
|
2903
3093
|
}
|
|
2904
3094
|
|
|
2905
3095
|
// src/Breadcrumb.tsx
|
|
2906
|
-
import { Fragment as
|
|
2907
|
-
import { jsx as
|
|
3096
|
+
import { Fragment as Fragment11, useCallback as useCallback3, useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState8 } from "react";
|
|
3097
|
+
import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2908
3098
|
function Breadcrumb({ items, className }) {
|
|
2909
|
-
const navRef =
|
|
2910
|
-
const labelRefs =
|
|
2911
|
-
const [truncated, setTruncated] =
|
|
3099
|
+
const navRef = useRef10(null);
|
|
3100
|
+
const labelRefs = useRef10([]);
|
|
3101
|
+
const [truncated, setTruncated] = useState8(/* @__PURE__ */ new Set());
|
|
2912
3102
|
const measure = useCallback3(() => {
|
|
2913
3103
|
const next = /* @__PURE__ */ new Set();
|
|
2914
3104
|
labelRefs.current.forEach((el, index) => {
|
|
@@ -2924,7 +3114,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2924
3114
|
observer.observe(nav);
|
|
2925
3115
|
return () => observer.disconnect();
|
|
2926
3116
|
}, [measure, items]);
|
|
2927
|
-
return /* @__PURE__ */
|
|
3117
|
+
return /* @__PURE__ */ jsx46("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
|
|
2928
3118
|
const last = index === items.length - 1;
|
|
2929
3119
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
2930
3120
|
const text = cn(
|
|
@@ -2945,34 +3135,34 @@ function Breadcrumb({ items, className }) {
|
|
|
2945
3135
|
// on a box around it, which the link takes them from, rather than
|
|
2946
3136
|
// pushed into it (UIG-9); the link is still the one element that
|
|
2947
3137
|
// truncates and is measured.
|
|
2948
|
-
/* @__PURE__ */
|
|
2949
|
-
) : /* @__PURE__ */
|
|
2950
|
-
return /* @__PURE__ */
|
|
2951
|
-
index > 0 && /* @__PURE__ */
|
|
2952
|
-
item.icon && /* @__PURE__ */
|
|
3138
|
+
/* @__PURE__ */ jsx46("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx46(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
|
|
3139
|
+
) : /* @__PURE__ */ jsx46("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
3140
|
+
return /* @__PURE__ */ jsxs31(Fragment11, { children: [
|
|
3141
|
+
index > 0 && /* @__PURE__ */ jsx46("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
3142
|
+
item.icon && /* @__PURE__ */ jsx46("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
|
|
2953
3143
|
truncated.has(index) ? (
|
|
2954
3144
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
2955
3145
|
// must keep truncating inside it, or wrapping it would widen the
|
|
2956
3146
|
// trail and the tooltip would never be needed again.
|
|
2957
|
-
/* @__PURE__ */
|
|
3147
|
+
/* @__PURE__ */ jsx46(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
2958
3148
|
) : crumb
|
|
2959
3149
|
] }, `${item.label}-${index}`);
|
|
2960
3150
|
}) });
|
|
2961
3151
|
}
|
|
2962
3152
|
|
|
2963
3153
|
// src/NavItem.tsx
|
|
2964
|
-
import { useId, useState as
|
|
3154
|
+
import { useId as useId2, useState as useState9 } from "react";
|
|
2965
3155
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2966
3156
|
import { IconAlertSquareRounded, IconChevronRight as IconChevronRight2, IconDotsVertical } from "@tabler/icons-react";
|
|
2967
3157
|
|
|
2968
3158
|
// src/UnreadDot.tsx
|
|
2969
|
-
import { jsx as
|
|
3159
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
2970
3160
|
function UnreadDot({ className }) {
|
|
2971
|
-
return /* @__PURE__ */
|
|
3161
|
+
return /* @__PURE__ */ jsx47("div", { className: cn("flex h-6 w-6 shrink-0 items-center justify-center", className), "data-unread": true, children: /* @__PURE__ */ jsx47("div", { className: "h-1.5 w-1.5 rounded-full bg-accent-primary" }) });
|
|
2972
3162
|
}
|
|
2973
3163
|
|
|
2974
3164
|
// src/NavItem.tsx
|
|
2975
|
-
import { jsx as
|
|
3165
|
+
import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2976
3166
|
function NavItem({
|
|
2977
3167
|
label,
|
|
2978
3168
|
href,
|
|
@@ -2990,10 +3180,12 @@ function NavItem({
|
|
|
2990
3180
|
open: openProp,
|
|
2991
3181
|
onOpenChange,
|
|
2992
3182
|
className,
|
|
3183
|
+
onClick,
|
|
2993
3184
|
...props
|
|
2994
3185
|
}) {
|
|
2995
|
-
const
|
|
2996
|
-
const
|
|
3186
|
+
const inApp = useInAppClick(href, onClick);
|
|
3187
|
+
const [openState, setOpenState] = useState9(defaultOpen);
|
|
3188
|
+
const panelId = useId2();
|
|
2997
3189
|
const hasRows = children != null && children !== false;
|
|
2998
3190
|
const open = openProp ?? openState;
|
|
2999
3191
|
const setOpen = (next) => {
|
|
@@ -3001,9 +3193,9 @@ function NavItem({
|
|
|
3001
3193
|
onOpenChange?.(next);
|
|
3002
3194
|
};
|
|
3003
3195
|
const besides = menu != null || hasRows;
|
|
3004
|
-
const mark = unread ? urgent ? /* @__PURE__ */
|
|
3196
|
+
const mark = unread ? urgent ? /* @__PURE__ */ jsx48(UrgentMark, {}) : /* @__PURE__ */ jsx48(UnreadDot, {}) : null;
|
|
3005
3197
|
const stepsAside = menu != null && "transition-opacity group-hover/nav:opacity-0 group-has-[:focus-visible]/nav:opacity-0 group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:opacity-0 [@media(hover:none)]:opacity-0";
|
|
3006
|
-
const row = /* @__PURE__ */
|
|
3198
|
+
const row = /* @__PURE__ */ jsxs32(
|
|
3007
3199
|
"a",
|
|
3008
3200
|
{
|
|
3009
3201
|
href,
|
|
@@ -3023,8 +3215,9 @@ function NavItem({
|
|
|
3023
3215
|
className
|
|
3024
3216
|
),
|
|
3025
3217
|
...props,
|
|
3218
|
+
onClick: inApp,
|
|
3026
3219
|
children: [
|
|
3027
|
-
(icon || hasRows) && /* @__PURE__ */
|
|
3220
|
+
(icon || hasRows) && /* @__PURE__ */ jsx48(
|
|
3028
3221
|
"span",
|
|
3029
3222
|
{
|
|
3030
3223
|
className: cn(
|
|
@@ -3035,10 +3228,10 @@ function NavItem({
|
|
|
3035
3228
|
children: icon
|
|
3036
3229
|
}
|
|
3037
3230
|
),
|
|
3038
|
-
/* @__PURE__ */
|
|
3231
|
+
/* @__PURE__ */ jsx48("span", { className: cn("flex-1 truncate", unread && "font-medium"), children: label }),
|
|
3039
3232
|
hint != null && // Takes room only while it shows, so the label gives way to it.
|
|
3040
|
-
/* @__PURE__ */
|
|
3041
|
-
count ? /* @__PURE__ */
|
|
3233
|
+
/* @__PURE__ */ jsx48("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-has-[:focus-visible]/nav:flex", children: hint }),
|
|
3234
|
+
count ? /* @__PURE__ */ jsx48(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx48(
|
|
3042
3235
|
"span",
|
|
3043
3236
|
{
|
|
3044
3237
|
className: cn(
|
|
@@ -3054,7 +3247,7 @@ function NavItem({
|
|
|
3054
3247
|
// `-mr-1`: the 24px slot's dot then sits on the axis of a count and
|
|
3055
3248
|
// of the ⋮ (8px from the edge to the 16px box), one column with a
|
|
3056
3249
|
// folder heading's dot and ⋮ (Katerina, 5 October).
|
|
3057
|
-
/* @__PURE__ */
|
|
3250
|
+
/* @__PURE__ */ jsx48("span", { className: cn("-mr-1 flex shrink-0", stepsAside), children: mark })
|
|
3058
3251
|
) : menu != null && !count ? (
|
|
3059
3252
|
// Nothing at the right, but a menu: no room is kept at rest, so the
|
|
3060
3253
|
// label has the row's whole width; while the ⋮ shows, its 24px slot
|
|
@@ -3062,18 +3255,18 @@ function NavItem({
|
|
|
3062
3255
|
// `-mr-1`: the ⋮ sits at `right-1`, 4px into the row's padding, so the
|
|
3063
3256
|
// slot does too — at the padding's edge it kept 4px the ⋮ never
|
|
3064
3257
|
// covers, and the label stopped 12px short of the button, not 8.
|
|
3065
|
-
/* @__PURE__ */
|
|
3258
|
+
/* @__PURE__ */ jsx48("span", { "aria-hidden": "true", className: "-mr-1 hidden w-6 shrink-0 group-hover/nav:block group-has-[:focus-visible]/nav:block group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:block [@media(hover:none)]:block" })
|
|
3066
3259
|
) : null
|
|
3067
3260
|
]
|
|
3068
3261
|
}
|
|
3069
3262
|
);
|
|
3070
3263
|
if (!besides && hint == null) return row;
|
|
3071
3264
|
const name = menuLabel ?? `More options for ${label}`;
|
|
3072
|
-
const line = /* @__PURE__ */
|
|
3265
|
+
const line = /* @__PURE__ */ jsxs32("div", { className: "group/nav relative shrink-0", children: [
|
|
3073
3266
|
row,
|
|
3074
3267
|
hasRows && // `left-1`: the 24px button's 16px arrow then sits where the icon
|
|
3075
3268
|
// sits (the row's px-2), so the icon turns into the arrow in place.
|
|
3076
|
-
/* @__PURE__ */
|
|
3269
|
+
/* @__PURE__ */ jsx48("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100", children: /* @__PURE__ */ jsx48(
|
|
3077
3270
|
IconButton,
|
|
3078
3271
|
{
|
|
3079
3272
|
tooltip: open ? "Collapse" : "Expand",
|
|
@@ -3081,7 +3274,7 @@ function NavItem({
|
|
|
3081
3274
|
"aria-expanded": open,
|
|
3082
3275
|
"aria-controls": panelId,
|
|
3083
3276
|
onClick: () => setOpen(!open),
|
|
3084
|
-
children: /* @__PURE__ */
|
|
3277
|
+
children: /* @__PURE__ */ jsx48(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
|
|
3085
3278
|
}
|
|
3086
3279
|
) }),
|
|
3087
3280
|
menu != null && // `right-1`: the 24px button's 16px icon ends 8px from the row's
|
|
@@ -3092,61 +3285,61 @@ function NavItem({
|
|
|
3092
3285
|
// right of the slot's centre.
|
|
3093
3286
|
// On a screen with no hover it always shows: nothing there can point
|
|
3094
3287
|
// at the row, and the menu has no other way in.
|
|
3095
|
-
/* @__PURE__ */
|
|
3288
|
+
/* @__PURE__ */ jsx48("div", { "data-nav-menu": true, className: cn("absolute inset-y-0 right-1 flex items-center", "opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100"), children: /* @__PURE__ */ jsx48(
|
|
3096
3289
|
Menu,
|
|
3097
3290
|
{
|
|
3098
3291
|
align: "right",
|
|
3099
|
-
trigger: /* @__PURE__ */
|
|
3292
|
+
trigger: /* @__PURE__ */ jsx48(IconButton, { tooltip: "More options", "aria-label": name, children: /* @__PURE__ */ jsx48(IconDotsVertical, { size: 16, stroke: 1.5 }) }),
|
|
3100
3293
|
children: menu
|
|
3101
3294
|
}
|
|
3102
3295
|
) })
|
|
3103
3296
|
] });
|
|
3104
3297
|
if (!hasRows) return line;
|
|
3105
|
-
return /* @__PURE__ */
|
|
3298
|
+
return /* @__PURE__ */ jsxs32(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
|
|
3106
3299
|
line,
|
|
3107
|
-
/* @__PURE__ */
|
|
3300
|
+
/* @__PURE__ */ jsx48(
|
|
3108
3301
|
Collapsible.Panel,
|
|
3109
3302
|
{
|
|
3110
3303
|
id: panelId,
|
|
3111
3304
|
hiddenUntilFound: true,
|
|
3112
3305
|
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
3113
|
-
children: /* @__PURE__ */
|
|
3306
|
+
children: /* @__PURE__ */ jsx48("div", { className: "flex flex-col gap-0.5 pt-0.5 pl-6", children })
|
|
3114
3307
|
}
|
|
3115
3308
|
)
|
|
3116
3309
|
] });
|
|
3117
3310
|
}
|
|
3118
3311
|
function UrgentMark() {
|
|
3119
|
-
return /* @__PURE__ */
|
|
3312
|
+
return /* @__PURE__ */ jsx48("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center", "data-urgent": true, children: /* @__PURE__ */ jsx48("div", { className: "flex items-center rounded-full bg-warning-muted p-0.5 signal:shadow-glow-warning", children: /* @__PURE__ */ jsx48(IconAlertSquareRounded, { size: 12, stroke: 2.5, className: "text-warning-default" }) }) });
|
|
3120
3313
|
}
|
|
3121
3314
|
|
|
3122
3315
|
// src/NavTree.tsx
|
|
3123
|
-
import { useEffect as
|
|
3316
|
+
import { useEffect as useEffect6, useRef as useRef11 } from "react";
|
|
3124
3317
|
|
|
3125
3318
|
// src/CollapsibleSection.tsx
|
|
3126
|
-
import { useState as
|
|
3319
|
+
import { useState as useState10 } from "react";
|
|
3127
3320
|
import { Collapsible as Collapsible2 } from "@base-ui/react/collapsible";
|
|
3128
3321
|
|
|
3129
3322
|
// src/SectionHeader.tsx
|
|
3130
3323
|
import { IconChevronRight as IconChevronRight3, IconDotsVertical as IconDotsVertical2 } from "@tabler/icons-react";
|
|
3131
3324
|
import { useRender } from "@base-ui/react/use-render";
|
|
3132
|
-
import { Fragment as
|
|
3325
|
+
import { Fragment as Fragment12, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3133
3326
|
function SectionHeader({ title, chevron = false, icon, isExpanded = true, onToggle, trailing, count, actions, menu, menuLabel, showActions = "hover", hover = "fill", look = "heading", render, className }) {
|
|
3134
3327
|
const row = look === "row";
|
|
3135
3328
|
const acts = actions && actions.length > 0 || menu != null;
|
|
3136
3329
|
const trailingClasses = !acts ? "has-[[data-unread]]:-mr-1" : showActions === "hover" && "has-[[data-unread]]:pointer-events-none has-[[data-unread]]:absolute has-[[data-unread]]:inset-y-0 has-[[data-unread]]:right-1 has-[[data-unread]]:w-6 has-[[data-unread]]:justify-center has-[[data-unread]]:transition-opacity group-hover:has-[[data-unread]]:opacity-0 group-has-[:focus-visible]:has-[[data-unread]]:opacity-0 group-has-[[data-section-menu]_[aria-expanded=true]]:has-[[data-unread]]:opacity-0 [@media(hover:none)]:has-[[data-unread]]:opacity-0";
|
|
3137
3330
|
const reveal = showActions === "hover" && "opacity-0 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100";
|
|
3138
3331
|
const titleElement = useRender({
|
|
3139
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
3332
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
|
|
3140
3333
|
props: {
|
|
3141
3334
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
3142
3335
|
// whole row up to the actions is the hit target, as it was when the
|
|
3143
3336
|
// row itself carried the click.
|
|
3144
3337
|
// An icon is a row's: NavItem's 8px after it.
|
|
3145
3338
|
className: cn("flex h-full min-w-0 flex-1 items-center text-left", row || chevron || icon != null ? "gap-2" : "gap-1"),
|
|
3146
|
-
children: /* @__PURE__ */
|
|
3147
|
-
icon != null ? /* @__PURE__ */
|
|
3148
|
-
/* @__PURE__ */
|
|
3149
|
-
chevron && /* @__PURE__ */
|
|
3339
|
+
children: /* @__PURE__ */ jsxs33(Fragment12, { children: [
|
|
3340
|
+
icon != null ? /* @__PURE__ */ jsxs33("span", { className: "relative flex size-4 shrink-0 items-center justify-center text-text-secondary", children: [
|
|
3341
|
+
/* @__PURE__ */ jsx49("span", { className: cn("flex", chevron && "transition-opacity group-hover:opacity-0 group-has-[:focus-visible]:opacity-0"), children: icon }),
|
|
3342
|
+
chevron && /* @__PURE__ */ jsx49(
|
|
3150
3343
|
IconChevronRight3,
|
|
3151
3344
|
{
|
|
3152
3345
|
size: 16,
|
|
@@ -3154,7 +3347,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3154
3347
|
className: cn("absolute opacity-0 transition-[opacity,transform] duration-150 group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", isExpanded && "rotate-90")
|
|
3155
3348
|
}
|
|
3156
3349
|
)
|
|
3157
|
-
] }) : chevron && /* @__PURE__ */
|
|
3350
|
+
] }) : chevron && /* @__PURE__ */ jsx49(
|
|
3158
3351
|
IconChevronRight3,
|
|
3159
3352
|
{
|
|
3160
3353
|
size: 16,
|
|
@@ -3162,15 +3355,15 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3162
3355
|
className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
|
|
3163
3356
|
}
|
|
3164
3357
|
),
|
|
3165
|
-
look === "quiet" ? /* @__PURE__ */
|
|
3358
|
+
look === "quiet" ? /* @__PURE__ */ jsx49("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
|
|
3166
3359
|
// A row's words: NavItem's size and colour, brightening under the pointer with the row.
|
|
3167
|
-
/* @__PURE__ */
|
|
3168
|
-
) : /* @__PURE__ */
|
|
3169
|
-
count != null && /* @__PURE__ */
|
|
3360
|
+
/* @__PURE__ */ jsx49("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
|
|
3361
|
+
) : /* @__PURE__ */ jsx49(SectionLabel, { folds: chevron, children: title }),
|
|
3362
|
+
count != null && /* @__PURE__ */ jsx49("span", { className: cn("ml-1 shrink-0", COUNT_TEXT_CLASSES), children: count })
|
|
3170
3363
|
] })
|
|
3171
3364
|
}
|
|
3172
3365
|
});
|
|
3173
|
-
return /* @__PURE__ */
|
|
3366
|
+
return /* @__PURE__ */ jsxs33(
|
|
3174
3367
|
"div",
|
|
3175
3368
|
{
|
|
3176
3369
|
className: cn(
|
|
@@ -3191,18 +3384,18 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3191
3384
|
),
|
|
3192
3385
|
children: [
|
|
3193
3386
|
titleElement,
|
|
3194
|
-
trailing != null && /* @__PURE__ */
|
|
3195
|
-
acts && /* @__PURE__ */
|
|
3387
|
+
trailing != null && /* @__PURE__ */ jsx49("div", { className: cn("flex shrink-0 items-center", trailingClasses), children: trailing }),
|
|
3388
|
+
acts && /* @__PURE__ */ jsx49(
|
|
3196
3389
|
"div",
|
|
3197
3390
|
{
|
|
3198
3391
|
className: "-mr-1 flex shrink-0 items-center",
|
|
3199
|
-
children: /* @__PURE__ */
|
|
3200
|
-
actions?.map((action) => /* @__PURE__ */
|
|
3201
|
-
menu != null && /* @__PURE__ */
|
|
3392
|
+
children: /* @__PURE__ */ jsxs33("div", { className: cn("flex items-center gap-1", reveal), children: [
|
|
3393
|
+
actions?.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip)),
|
|
3394
|
+
menu != null && /* @__PURE__ */ jsx49("div", { "data-section-menu": true, className: "flex items-center", children: /* @__PURE__ */ jsx49(
|
|
3202
3395
|
Menu,
|
|
3203
3396
|
{
|
|
3204
3397
|
align: "right",
|
|
3205
|
-
trigger: /* @__PURE__ */
|
|
3398
|
+
trigger: /* @__PURE__ */ jsx49(IconButton, { tooltip: "More options", "aria-label": menuLabel ?? `More options for ${title}`, children: /* @__PURE__ */ jsx49(IconDotsVertical2, { size: 16, stroke: 1.5 }) }),
|
|
3206
3399
|
children: menu
|
|
3207
3400
|
}
|
|
3208
3401
|
) })
|
|
@@ -3215,7 +3408,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3215
3408
|
}
|
|
3216
3409
|
|
|
3217
3410
|
// src/CollapsibleSection.tsx
|
|
3218
|
-
import { jsx as
|
|
3411
|
+
import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3219
3412
|
var OPEN = "open";
|
|
3220
3413
|
var CLOSED = "closed";
|
|
3221
3414
|
function readStored(key) {
|
|
@@ -3235,38 +3428,38 @@ function writeStored(key, open) {
|
|
|
3235
3428
|
}
|
|
3236
3429
|
}
|
|
3237
3430
|
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, icon, trailing, actions, menu, menuLabel, showActions, look = "heading", indent = false, children, className, contentClassName }) {
|
|
3238
|
-
const [openState, setOpenState] =
|
|
3431
|
+
const [openState, setOpenState] = useState10(() => readStored(storageKey) ?? defaultOpen);
|
|
3239
3432
|
const open = openProp ?? openState;
|
|
3240
3433
|
const setOpen = (next) => {
|
|
3241
3434
|
setOpenState(next);
|
|
3242
3435
|
writeStored(storageKey, next);
|
|
3243
3436
|
onOpenChange?.(next);
|
|
3244
3437
|
};
|
|
3245
|
-
return /* @__PURE__ */
|
|
3246
|
-
/* @__PURE__ */
|
|
3247
|
-
/* @__PURE__ */
|
|
3438
|
+
return /* @__PURE__ */ jsxs34(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
3439
|
+
/* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, icon, isExpanded: open, trailing, actions, menu, menuLabel, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible2.Trigger, {}) }),
|
|
3440
|
+
/* @__PURE__ */ jsx50(
|
|
3248
3441
|
Collapsible2.Panel,
|
|
3249
3442
|
{
|
|
3250
3443
|
hiddenUntilFound: true,
|
|
3251
3444
|
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
3252
|
-
children: /* @__PURE__ */
|
|
3445
|
+
children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col pt-0.5", (look === "row" || indent) && "pl-6", contentClassName), children })
|
|
3253
3446
|
}
|
|
3254
3447
|
)
|
|
3255
3448
|
] });
|
|
3256
3449
|
}
|
|
3257
3450
|
|
|
3258
3451
|
// src/NavTree.tsx
|
|
3259
|
-
import { Fragment as
|
|
3452
|
+
import { Fragment as Fragment13, jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3260
3453
|
var NAV_TREE_INTENT_MS = 150;
|
|
3261
3454
|
function holds(nodes, id) {
|
|
3262
3455
|
return !!nodes && id !== void 0 && nodes.some((node) => node.id === id || holds(node.children ?? null, id));
|
|
3263
3456
|
}
|
|
3264
3457
|
function Line({ message }) {
|
|
3265
|
-
return /* @__PURE__ */
|
|
3458
|
+
return /* @__PURE__ */ jsx51("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx51(EmptyState, { scope: "section", message }) });
|
|
3266
3459
|
}
|
|
3267
3460
|
function Row({ node, selected, onSelect }) {
|
|
3268
|
-
const under = node.childrenMessage !== void 0 ? /* @__PURE__ */
|
|
3269
|
-
return /* @__PURE__ */
|
|
3461
|
+
const under = node.childrenMessage !== void 0 ? /* @__PURE__ */ jsx51(Line, { message: node.childrenMessage }) : node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx51(Row, { node: child, selected, onSelect }, child.id)) : node.children === null || node.hasChildren && node.children === void 0 ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 2 }) : void 0;
|
|
3462
|
+
return /* @__PURE__ */ jsx51(
|
|
3270
3463
|
NavItem,
|
|
3271
3464
|
{
|
|
3272
3465
|
href: node.href,
|
|
@@ -3288,7 +3481,7 @@ function Row({ node, selected, onSelect }) {
|
|
|
3288
3481
|
);
|
|
3289
3482
|
}
|
|
3290
3483
|
function Group({ group, selected, onSelect, storageKey }) {
|
|
3291
|
-
return /* @__PURE__ */
|
|
3484
|
+
return /* @__PURE__ */ jsx51(
|
|
3292
3485
|
NavTreeSection,
|
|
3293
3486
|
{
|
|
3294
3487
|
id: group.id,
|
|
@@ -3304,15 +3497,15 @@ function Group({ group, selected, onSelect, storageKey }) {
|
|
|
3304
3497
|
onOpenChange: group.onOpenChange,
|
|
3305
3498
|
storageKey: storageKey ? `${storageKey}.${group.id}` : void 0,
|
|
3306
3499
|
onIntent: group.onIntent,
|
|
3307
|
-
children: group.nodes?.map((node) => /* @__PURE__ */
|
|
3500
|
+
children: group.nodes?.map((node) => /* @__PURE__ */ jsx51(Row, { node, selected, onSelect }, node.id))
|
|
3308
3501
|
}
|
|
3309
3502
|
);
|
|
3310
3503
|
}
|
|
3311
3504
|
function NavTreeSection({ id, title, message, loading = false, trailing, actions, menu, icon, defaultOpen = true, open, onOpenChange, storageKey, onIntent, children }) {
|
|
3312
|
-
const timer =
|
|
3313
|
-
|
|
3505
|
+
const timer = useRef11(void 0);
|
|
3506
|
+
useEffect6(() => () => clearTimeout(timer.current), []);
|
|
3314
3507
|
const intent = onIntent;
|
|
3315
|
-
return /* @__PURE__ */
|
|
3508
|
+
return /* @__PURE__ */ jsx51(
|
|
3316
3509
|
"div",
|
|
3317
3510
|
{
|
|
3318
3511
|
className: "shrink-0 [&+&]:mt-1",
|
|
@@ -3323,7 +3516,7 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
|
|
|
3323
3516
|
} : void 0,
|
|
3324
3517
|
onPointerLeave: intent ? () => clearTimeout(timer.current) : void 0,
|
|
3325
3518
|
onFocus: intent,
|
|
3326
|
-
children: /* @__PURE__ */
|
|
3519
|
+
children: /* @__PURE__ */ jsx51(
|
|
3327
3520
|
CollapsibleSection,
|
|
3328
3521
|
{
|
|
3329
3522
|
title,
|
|
@@ -3338,35 +3531,35 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
|
|
|
3338
3531
|
icon,
|
|
3339
3532
|
className: "shrink-0",
|
|
3340
3533
|
contentClassName: "gap-0.5",
|
|
3341
|
-
children: message !== void 0 ? /* @__PURE__ */
|
|
3534
|
+
children: message !== void 0 ? /* @__PURE__ */ jsx51(Line, { message }) : loading ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 3 }) : children
|
|
3342
3535
|
}
|
|
3343
3536
|
)
|
|
3344
3537
|
}
|
|
3345
3538
|
);
|
|
3346
3539
|
}
|
|
3347
3540
|
function NavTree({ title, titleActions, groups, children, selected, onSelect, emptyMessage = "", storageKey }) {
|
|
3348
|
-
return /* @__PURE__ */
|
|
3349
|
-
title && /* @__PURE__ */
|
|
3350
|
-
groups === void 0 ? children : groups === null ? /* @__PURE__ */
|
|
3541
|
+
return /* @__PURE__ */ jsxs35(Fragment13, { children: [
|
|
3542
|
+
title && /* @__PURE__ */ jsx51(SectionHeader, { title, look: "quiet", showActions: "always", actions: titleActions, className: "mt-4 shrink-0" }),
|
|
3543
|
+
groups === void 0 ? children : groups === null ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
|
|
3351
3544
|
// No words, no line: an app that says nothing when it has no groups.
|
|
3352
|
-
emptyMessage ? /* @__PURE__ */
|
|
3353
|
-
) : groups.map((group) => /* @__PURE__ */
|
|
3545
|
+
emptyMessage ? /* @__PURE__ */ jsx51(Line, { message: emptyMessage }) : null
|
|
3546
|
+
) : groups.map((group) => /* @__PURE__ */ jsx51(Group, { group, selected, onSelect, storageKey }, group.id))
|
|
3354
3547
|
] });
|
|
3355
3548
|
}
|
|
3356
3549
|
|
|
3357
3550
|
// src/Popover.tsx
|
|
3358
|
-
import { useMemo as
|
|
3551
|
+
import { useMemo as useMemo4 } from "react";
|
|
3359
3552
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
3360
|
-
import { jsx as
|
|
3553
|
+
import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3361
3554
|
var GAP5 = 4;
|
|
3362
3555
|
var VIEWPORT_PAD5 = 8;
|
|
3363
3556
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
3364
|
-
const anchorTarget =
|
|
3557
|
+
const anchorTarget = useMemo4(() => {
|
|
3365
3558
|
if (!anchor) return void 0;
|
|
3366
3559
|
if (anchor instanceof Element) return anchor;
|
|
3367
3560
|
return { getBoundingClientRect: () => anchor };
|
|
3368
3561
|
}, [anchor]);
|
|
3369
|
-
return /* @__PURE__ */
|
|
3562
|
+
return /* @__PURE__ */ jsxs36(
|
|
3370
3563
|
BasePopover.Root,
|
|
3371
3564
|
{
|
|
3372
3565
|
open,
|
|
@@ -3374,8 +3567,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3374
3567
|
actionsRef,
|
|
3375
3568
|
modal: false,
|
|
3376
3569
|
children: [
|
|
3377
|
-
trigger && /* @__PURE__ */
|
|
3378
|
-
/* @__PURE__ */
|
|
3570
|
+
trigger && /* @__PURE__ */ jsx52(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
3571
|
+
/* @__PURE__ */ jsx52(BasePopover.Portal, { children: /* @__PURE__ */ jsx52(
|
|
3379
3572
|
BasePopover.Positioner,
|
|
3380
3573
|
{
|
|
3381
3574
|
anchor: anchorTarget,
|
|
@@ -3384,20 +3577,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3384
3577
|
sideOffset: GAP5,
|
|
3385
3578
|
collisionPadding: VIEWPORT_PAD5,
|
|
3386
3579
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
3387
|
-
children: /* @__PURE__ */
|
|
3580
|
+
children: /* @__PURE__ */ jsx52(
|
|
3388
3581
|
BasePopover.Popup,
|
|
3389
3582
|
{
|
|
3390
3583
|
"aria-label": ariaLabel,
|
|
3391
3584
|
initialFocus: trigger ? void 0 : false,
|
|
3392
3585
|
finalFocus,
|
|
3393
3586
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
3394
|
-
render: /* @__PURE__ */
|
|
3395
|
-
children: /* @__PURE__ */
|
|
3587
|
+
render: /* @__PURE__ */ jsx52(MenuPanel, {}),
|
|
3588
|
+
children: /* @__PURE__ */ jsx52(
|
|
3396
3589
|
ScrollArea,
|
|
3397
3590
|
{
|
|
3398
3591
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
3399
3592
|
contentClassName: cn("flex flex-col p-2", contentClassName),
|
|
3400
|
-
children: /* @__PURE__ */
|
|
3593
|
+
children: /* @__PURE__ */ jsx52(DividerInPanel.Provider, { value: true, children })
|
|
3401
3594
|
}
|
|
3402
3595
|
)
|
|
3403
3596
|
}
|
|
@@ -3410,18 +3603,18 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3410
3603
|
}
|
|
3411
3604
|
|
|
3412
3605
|
// src/SuggestionMenu.tsx
|
|
3413
|
-
import { useCallback as useCallback4, useEffect as
|
|
3414
|
-
import { jsx as
|
|
3606
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useId as useId3, useImperativeHandle, useMemo as useMemo5, useRef as useRef12, useState as useState11 } from "react";
|
|
3607
|
+
import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3415
3608
|
function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
|
|
3416
|
-
const shown =
|
|
3417
|
-
const items =
|
|
3609
|
+
const shown = useMemo5(() => sections.filter((section) => section.items.length > 0), [sections]);
|
|
3610
|
+
const items = useMemo5(() => shown.flatMap((section) => section.items), [shown]);
|
|
3418
3611
|
const keys = items.map(itemKey).join("\n");
|
|
3419
|
-
const [highlight, setHighlight] =
|
|
3420
|
-
const base =
|
|
3612
|
+
const [highlight, setHighlight] = useState11(0);
|
|
3613
|
+
const base = useId3();
|
|
3421
3614
|
const listboxId = `${base}-list`;
|
|
3422
|
-
const chosen =
|
|
3423
|
-
|
|
3424
|
-
|
|
3615
|
+
const chosen = useRef12(null);
|
|
3616
|
+
useEffect7(() => void (chosen.current = highlight > 0 ? keys.split("\n")[highlight] ?? null : null), [highlight]);
|
|
3617
|
+
useEffect7(() => {
|
|
3425
3618
|
const at = chosen.current ? keys.split("\n").indexOf(chosen.current) : -1;
|
|
3426
3619
|
setHighlight(at > 0 ? at : 0);
|
|
3427
3620
|
}, [keys]);
|
|
@@ -3446,7 +3639,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3446
3639
|
}
|
|
3447
3640
|
}), [items, highlight, onSelect]);
|
|
3448
3641
|
const open = rect !== null && items.length > 0;
|
|
3449
|
-
|
|
3642
|
+
useEffect7(() => {
|
|
3450
3643
|
if (!editorElement || !open) return;
|
|
3451
3644
|
editorElement.setAttribute("aria-autocomplete", "list");
|
|
3452
3645
|
editorElement.setAttribute("aria-haspopup", "listbox");
|
|
@@ -3455,7 +3648,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3455
3648
|
for (const name of ["aria-autocomplete", "aria-haspopup", "aria-controls", "aria-activedescendant"]) editorElement.removeAttribute(name);
|
|
3456
3649
|
};
|
|
3457
3650
|
}, [editorElement, open, listboxId]);
|
|
3458
|
-
|
|
3651
|
+
useEffect7(() => {
|
|
3459
3652
|
if (!editorElement || !open) return;
|
|
3460
3653
|
editorElement.setAttribute("aria-activedescendant", `${base}-${highlight}`);
|
|
3461
3654
|
}, [editorElement, open, base, highlight]);
|
|
@@ -3476,7 +3669,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3476
3669
|
const { label, description, leading, shortcut, hint, size } = row(item);
|
|
3477
3670
|
return (
|
|
3478
3671
|
// A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
|
|
3479
|
-
/* @__PURE__ */
|
|
3672
|
+
/* @__PURE__ */ jsx53(
|
|
3480
3673
|
MenuItem,
|
|
3481
3674
|
{
|
|
3482
3675
|
role: "option",
|
|
@@ -3503,21 +3696,21 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3503
3696
|
};
|
|
3504
3697
|
return (
|
|
3505
3698
|
// finalFocus={false}: focus never left the text, and a list that closes because focus moved elsewhere must not pull it back (71a4577b).
|
|
3506
|
-
/* @__PURE__ */
|
|
3507
|
-
i > 0 && /* @__PURE__ */
|
|
3508
|
-
section.label ? /* @__PURE__ */
|
|
3699
|
+
/* @__PURE__ */ jsx53(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, finalFocus: false, children: /* @__PURE__ */ jsx53("div", { ref: keepFocus, id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col gap-0.5", children: shown.map((section, i) => /* @__PURE__ */ jsxs37("div", { className: "contents", children: [
|
|
3700
|
+
i > 0 && /* @__PURE__ */ jsx53(MenuSeparator, {}),
|
|
3701
|
+
section.label ? /* @__PURE__ */ jsx53("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx53(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
|
|
3509
3702
|
] }, section.label ?? i)) }) })
|
|
3510
3703
|
);
|
|
3511
3704
|
}
|
|
3512
3705
|
|
|
3513
3706
|
// src/ShowMore.tsx
|
|
3514
|
-
import { useLayoutEffect as useLayoutEffect5, useRef as
|
|
3515
|
-
import { jsx as
|
|
3707
|
+
import { useLayoutEffect as useLayoutEffect5, useRef as useRef13, useState as useState12 } from "react";
|
|
3708
|
+
import { jsx as jsx54, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3516
3709
|
var FADE_CLASSES = { surface: "from-bg-surface", inset: "from-bg-inset" };
|
|
3517
3710
|
function ShowMore({ children, maxHeight = 96, surface = "surface", className }) {
|
|
3518
|
-
const box =
|
|
3519
|
-
const [open, setOpen] =
|
|
3520
|
-
const [overflows, setOverflows] =
|
|
3711
|
+
const box = useRef13(null);
|
|
3712
|
+
const [open, setOpen] = useState12(false);
|
|
3713
|
+
const [overflows, setOverflows] = useState12(false);
|
|
3521
3714
|
useLayoutEffect5(() => {
|
|
3522
3715
|
const el = box.current;
|
|
3523
3716
|
if (!el) return;
|
|
@@ -3529,21 +3722,21 @@ function ShowMore({ children, maxHeight = 96, surface = "surface", className })
|
|
|
3529
3722
|
return () => observer.disconnect();
|
|
3530
3723
|
}, [maxHeight]);
|
|
3531
3724
|
const cut = overflows && !open;
|
|
3532
|
-
return /* @__PURE__ */
|
|
3533
|
-
/* @__PURE__ */
|
|
3725
|
+
return /* @__PURE__ */ jsxs38("div", { className: cn("flex flex-col items-start", className), children: [
|
|
3726
|
+
/* @__PURE__ */ jsxs38("div", { ref: box, className: cn("relative w-full", cut && "overflow-hidden"), style: cut ? { maxHeight } : void 0, onFocus: cut ? () => setOpen(true) : void 0, children: [
|
|
3534
3727
|
children,
|
|
3535
|
-
cut && /* @__PURE__ */
|
|
3728
|
+
cut && /* @__PURE__ */ jsx54("div", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent", FADE_CLASSES[surface]) })
|
|
3536
3729
|
] }),
|
|
3537
3730
|
overflows && // `-ml-1.5`: the small button's own 6px inset, so its words start where the content's do.
|
|
3538
|
-
/* @__PURE__ */
|
|
3731
|
+
/* @__PURE__ */ jsx54(Button, { variant: "muted", size: "small", className: "-ml-1.5 mt-1", "aria-expanded": open, onClick: () => setOpen((o) => !o), children: open ? "Show less" : "Show more" })
|
|
3539
3732
|
] });
|
|
3540
3733
|
}
|
|
3541
3734
|
|
|
3542
3735
|
// src/Toolbar.tsx
|
|
3543
3736
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
3544
|
-
import { jsx as
|
|
3737
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
3545
3738
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
3546
|
-
const strip = /* @__PURE__ */
|
|
3739
|
+
const strip = /* @__PURE__ */ jsx55(
|
|
3547
3740
|
BaseToolbar.Root,
|
|
3548
3741
|
{
|
|
3549
3742
|
"aria-label": ariaLabel,
|
|
@@ -3554,27 +3747,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
3554
3747
|
}
|
|
3555
3748
|
);
|
|
3556
3749
|
if (!surface) return strip;
|
|
3557
|
-
return /* @__PURE__ */
|
|
3750
|
+
return /* @__PURE__ */ jsx55(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
3558
3751
|
}
|
|
3559
3752
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
3560
|
-
return /* @__PURE__ */
|
|
3753
|
+
return /* @__PURE__ */ jsx55(
|
|
3561
3754
|
BaseToolbar.Button,
|
|
3562
3755
|
{
|
|
3563
3756
|
ref,
|
|
3564
3757
|
disabled: disabled || !!disabledReason,
|
|
3565
3758
|
focusableWhenDisabled: true,
|
|
3566
|
-
render: /* @__PURE__ */
|
|
3759
|
+
render: /* @__PURE__ */ jsx55(IconButton, { disabled, disabledReason, ...props })
|
|
3567
3760
|
}
|
|
3568
3761
|
);
|
|
3569
3762
|
}
|
|
3570
3763
|
function ToolbarLink({ ref, href, ...props }) {
|
|
3571
|
-
return /* @__PURE__ */
|
|
3764
|
+
return /* @__PURE__ */ jsx55(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx55(IconButton, { href, ...props }) });
|
|
3572
3765
|
}
|
|
3573
3766
|
function ToolbarInput({ size, ...props }) {
|
|
3574
|
-
return /* @__PURE__ */
|
|
3767
|
+
return /* @__PURE__ */ jsx55(BaseToolbar.Input, { render: /* @__PURE__ */ jsx55(TextInput, { size }), ...props });
|
|
3575
3768
|
}
|
|
3576
3769
|
function ToolbarSeparator({ className }) {
|
|
3577
|
-
return /* @__PURE__ */
|
|
3770
|
+
return /* @__PURE__ */ jsx55(
|
|
3578
3771
|
BaseToolbar.Separator,
|
|
3579
3772
|
{
|
|
3580
3773
|
orientation: "vertical",
|
|
@@ -3584,9 +3777,9 @@ function ToolbarSeparator({ className }) {
|
|
|
3584
3777
|
}
|
|
3585
3778
|
|
|
3586
3779
|
// src/ReactionPicker.tsx
|
|
3587
|
-
import { jsx as
|
|
3780
|
+
import { jsx as jsx56 } from "react/jsx-runtime";
|
|
3588
3781
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
3589
|
-
return /* @__PURE__ */
|
|
3782
|
+
return /* @__PURE__ */ jsx56(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
3590
3783
|
/*
|
|
3591
3784
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
3592
3785
|
would become the toolbar's item and the button inside it would never
|
|
@@ -3596,14 +3789,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3596
3789
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
3597
3790
|
and both say the meaning rather than the glyph.
|
|
3598
3791
|
*/
|
|
3599
|
-
/* @__PURE__ */
|
|
3792
|
+
/* @__PURE__ */ jsx56(
|
|
3600
3793
|
ToolbarButton,
|
|
3601
3794
|
{
|
|
3602
3795
|
"aria-label": option.label,
|
|
3603
3796
|
tooltip: option.label,
|
|
3604
3797
|
onClick: () => onSelect(option.emoji),
|
|
3605
3798
|
className: "size-7",
|
|
3606
|
-
children: /* @__PURE__ */
|
|
3799
|
+
children: /* @__PURE__ */ jsx56("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
|
|
3607
3800
|
},
|
|
3608
3801
|
option.emoji
|
|
3609
3802
|
)
|
|
@@ -3612,23 +3805,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3612
3805
|
|
|
3613
3806
|
// src/PreviewCard.tsx
|
|
3614
3807
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
3615
|
-
import { jsx as
|
|
3808
|
+
import { jsx as jsx57, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3616
3809
|
var GAP6 = 12;
|
|
3617
3810
|
var VIEWPORT_PAD6 = 8;
|
|
3618
3811
|
var OPEN_DELAY2 = 350;
|
|
3619
3812
|
var CLOSE_DELAY = 200;
|
|
3620
3813
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
|
|
3621
|
-
return /* @__PURE__ */
|
|
3622
|
-
/* @__PURE__ */
|
|
3814
|
+
return /* @__PURE__ */ jsxs39(BasePreviewCard.Root, { children: [
|
|
3815
|
+
/* @__PURE__ */ jsx57(
|
|
3623
3816
|
BasePreviewCard.Trigger,
|
|
3624
3817
|
{
|
|
3625
3818
|
delay,
|
|
3626
3819
|
closeDelay,
|
|
3627
|
-
render: /* @__PURE__ */
|
|
3820
|
+
render: /* @__PURE__ */ jsx57("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
3628
3821
|
children
|
|
3629
3822
|
}
|
|
3630
3823
|
),
|
|
3631
|
-
/* @__PURE__ */
|
|
3824
|
+
/* @__PURE__ */ jsx57(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx57(
|
|
3632
3825
|
BasePreviewCard.Positioner,
|
|
3633
3826
|
{
|
|
3634
3827
|
side,
|
|
@@ -3636,12 +3829,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3636
3829
|
sideOffset: GAP6,
|
|
3637
3830
|
collisionPadding: VIEWPORT_PAD6,
|
|
3638
3831
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
3639
|
-
children: /* @__PURE__ */
|
|
3832
|
+
children: /* @__PURE__ */ jsx57(
|
|
3640
3833
|
BasePreviewCard.Popup,
|
|
3641
3834
|
{
|
|
3642
3835
|
className: cn("w-[360px] p-0 outline-none", className),
|
|
3643
|
-
render: /* @__PURE__ */
|
|
3644
|
-
children: /* @__PURE__ */
|
|
3836
|
+
render: /* @__PURE__ */ jsx57(MenuPanel, {}),
|
|
3837
|
+
children: /* @__PURE__ */ jsx57(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
|
|
3645
3838
|
}
|
|
3646
3839
|
)
|
|
3647
3840
|
}
|
|
@@ -3650,30 +3843,32 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3650
3843
|
}
|
|
3651
3844
|
|
|
3652
3845
|
// src/Rail.tsx
|
|
3653
|
-
import { jsx as
|
|
3846
|
+
import { jsx as jsx58 } from "react/jsx-runtime";
|
|
3654
3847
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
3655
|
-
return /* @__PURE__ */
|
|
3848
|
+
return /* @__PURE__ */ jsx58("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
3656
3849
|
}
|
|
3657
3850
|
|
|
3658
3851
|
// src/RailItem.tsx
|
|
3659
|
-
import { jsx as
|
|
3660
|
-
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
3661
|
-
|
|
3852
|
+
import { jsx as jsx59, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3853
|
+
function RailItem({ href, icon, label, active = false, className, onClick, ...props }) {
|
|
3854
|
+
const inApp = useInAppClick(href, onClick);
|
|
3855
|
+
return /* @__PURE__ */ jsxs40(
|
|
3662
3856
|
"a",
|
|
3663
3857
|
{
|
|
3664
3858
|
href,
|
|
3665
3859
|
"aria-current": active ? "page" : void 0,
|
|
3666
3860
|
className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
3667
3861
|
...props,
|
|
3862
|
+
onClick: inApp,
|
|
3668
3863
|
children: [
|
|
3669
|
-
/* @__PURE__ */
|
|
3864
|
+
/* @__PURE__ */ jsx59(
|
|
3670
3865
|
"div",
|
|
3671
3866
|
{
|
|
3672
3867
|
className: cn(
|
|
3673
3868
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
3674
3869
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
3675
3870
|
),
|
|
3676
|
-
children: /* @__PURE__ */
|
|
3871
|
+
children: /* @__PURE__ */ jsx59(
|
|
3677
3872
|
"span",
|
|
3678
3873
|
{
|
|
3679
3874
|
className: cn(
|
|
@@ -3685,14 +3880,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
3685
3880
|
)
|
|
3686
3881
|
}
|
|
3687
3882
|
),
|
|
3688
|
-
/* @__PURE__ */
|
|
3883
|
+
/* @__PURE__ */ jsx59("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
3689
3884
|
]
|
|
3690
3885
|
}
|
|
3691
3886
|
);
|
|
3692
3887
|
}
|
|
3693
3888
|
|
|
3694
3889
|
// src/Property.tsx
|
|
3695
|
-
import { jsx as
|
|
3890
|
+
import { jsx as jsx60, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3696
3891
|
var VALUE_CLASSES = "contents";
|
|
3697
3892
|
function Property({ label, layout = "row", children, className }) {
|
|
3698
3893
|
if (layout === "stacked") {
|
|
@@ -3700,25 +3895,25 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
3700
3895
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
3701
3896
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
3702
3897
|
// 6px, and unifying means the bigger, calmer one.
|
|
3703
|
-
/* @__PURE__ */
|
|
3704
|
-
/* @__PURE__ */
|
|
3705
|
-
/* @__PURE__ */
|
|
3898
|
+
/* @__PURE__ */ jsxs41("dl", { className: cn("flex flex-col gap-3", className), children: [
|
|
3899
|
+
/* @__PURE__ */ jsx60("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
|
|
3900
|
+
/* @__PURE__ */ jsx60("dd", { className: VALUE_CLASSES, children })
|
|
3706
3901
|
] })
|
|
3707
3902
|
);
|
|
3708
3903
|
}
|
|
3709
|
-
return /* @__PURE__ */
|
|
3710
|
-
/* @__PURE__ */
|
|
3711
|
-
/* @__PURE__ */
|
|
3904
|
+
return /* @__PURE__ */ jsxs41("dl", { className: cn("flex items-center gap-2", className), children: [
|
|
3905
|
+
/* @__PURE__ */ jsx60("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
3906
|
+
/* @__PURE__ */ jsx60("dd", { className: VALUE_CLASSES, children })
|
|
3712
3907
|
] });
|
|
3713
3908
|
}
|
|
3714
3909
|
|
|
3715
3910
|
// src/Reaction.tsx
|
|
3716
3911
|
import { Toggle } from "@base-ui/react/toggle";
|
|
3717
|
-
import { jsx as
|
|
3912
|
+
import { jsx as jsx61, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3718
3913
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
3719
3914
|
return (
|
|
3720
3915
|
// @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
|
|
3721
|
-
/* @__PURE__ */
|
|
3916
|
+
/* @__PURE__ */ jsxs42(
|
|
3722
3917
|
Toggle,
|
|
3723
3918
|
{
|
|
3724
3919
|
pressed,
|
|
@@ -3740,8 +3935,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3740
3935
|
),
|
|
3741
3936
|
...props,
|
|
3742
3937
|
children: [
|
|
3743
|
-
/* @__PURE__ */
|
|
3744
|
-
/* @__PURE__ */
|
|
3938
|
+
/* @__PURE__ */ jsx61("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
|
|
3939
|
+
/* @__PURE__ */ jsx61("span", { className: CHIP_TEXT_CLASSES, children: count })
|
|
3745
3940
|
]
|
|
3746
3941
|
}
|
|
3747
3942
|
)
|
|
@@ -3751,9 +3946,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3751
3946
|
// src/SearchInput.tsx
|
|
3752
3947
|
import "react";
|
|
3753
3948
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
3754
|
-
import { jsx as
|
|
3949
|
+
import { jsx as jsx62, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3755
3950
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
3756
|
-
return /* @__PURE__ */
|
|
3951
|
+
return /* @__PURE__ */ jsxs43(
|
|
3757
3952
|
"div",
|
|
3758
3953
|
{
|
|
3759
3954
|
className: cn(
|
|
@@ -3765,7 +3960,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3765
3960
|
className
|
|
3766
3961
|
),
|
|
3767
3962
|
children: [
|
|
3768
|
-
/* @__PURE__ */
|
|
3963
|
+
/* @__PURE__ */ jsx62(
|
|
3769
3964
|
Input3,
|
|
3770
3965
|
{
|
|
3771
3966
|
className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
|
|
@@ -3773,42 +3968,42 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3773
3968
|
...props
|
|
3774
3969
|
}
|
|
3775
3970
|
),
|
|
3776
|
-
shortcut && /* @__PURE__ */
|
|
3971
|
+
shortcut && /* @__PURE__ */ jsx62(Kbd, { children: shortcut })
|
|
3777
3972
|
]
|
|
3778
3973
|
}
|
|
3779
3974
|
);
|
|
3780
3975
|
}
|
|
3781
3976
|
|
|
3782
3977
|
// src/Panel.tsx
|
|
3783
|
-
import { jsx as
|
|
3978
|
+
import { jsx as jsx63, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3784
3979
|
function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
|
|
3785
|
-
return /* @__PURE__ */
|
|
3786
|
-
/* @__PURE__ */
|
|
3980
|
+
return /* @__PURE__ */ jsxs44("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
|
|
3981
|
+
/* @__PURE__ */ jsx63(ContainerHeader, { title, chevron, actions }),
|
|
3787
3982
|
broken ? (
|
|
3788
3983
|
// The message takes the room the body had and centres itself in it.
|
|
3789
|
-
/* @__PURE__ */
|
|
3790
|
-
) : /* @__PURE__ */
|
|
3791
|
-
!broken && footer && /* @__PURE__ */
|
|
3984
|
+
/* @__PURE__ */ jsx63("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
|
|
3985
|
+
) : /* @__PURE__ */ jsx63(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
|
|
3986
|
+
!broken && footer && /* @__PURE__ */ jsx63("div", { className: "shrink-0", children: footer })
|
|
3792
3987
|
] });
|
|
3793
3988
|
}
|
|
3794
3989
|
function Panel(props) {
|
|
3795
|
-
return /* @__PURE__ */
|
|
3990
|
+
return /* @__PURE__ */ jsx63(
|
|
3796
3991
|
ErrorBoundary,
|
|
3797
3992
|
{
|
|
3798
3993
|
label: "panel",
|
|
3799
3994
|
frame: (message) => (
|
|
3800
3995
|
// Only the name comes back with the message: the actions and the footer may be what threw.
|
|
3801
|
-
/* @__PURE__ */
|
|
3996
|
+
/* @__PURE__ */ jsx63(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
|
|
3802
3997
|
),
|
|
3803
|
-
children: /* @__PURE__ */
|
|
3998
|
+
children: /* @__PURE__ */ jsx63(Frame, { ...props })
|
|
3804
3999
|
}
|
|
3805
4000
|
);
|
|
3806
4001
|
}
|
|
3807
4002
|
|
|
3808
4003
|
// src/ListColumn.tsx
|
|
3809
|
-
import { jsx as
|
|
4004
|
+
import { jsx as jsx64, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3810
4005
|
function Column({ title, chevron = false, titleMenu, actions, above, collapsed = false, children, className, broken = false }) {
|
|
3811
|
-
return /* @__PURE__ */
|
|
4006
|
+
return /* @__PURE__ */ jsxs45(
|
|
3812
4007
|
"div",
|
|
3813
4008
|
{
|
|
3814
4009
|
className: cn(
|
|
@@ -3819,35 +4014,35 @@ function Column({ title, chevron = false, titleMenu, actions, above, collapsed =
|
|
|
3819
4014
|
),
|
|
3820
4015
|
"data-collapsed": collapsed || void 0,
|
|
3821
4016
|
children: [
|
|
3822
|
-
/* @__PURE__ */
|
|
4017
|
+
/* @__PURE__ */ jsx64(ContainerHeader, { title, chevron, titleMenu, actions }),
|
|
3823
4018
|
above,
|
|
3824
4019
|
broken ? (
|
|
3825
4020
|
// The message takes the room the list had and centres itself in it (Katerina, 19 September).
|
|
3826
|
-
/* @__PURE__ */
|
|
3827
|
-
) : /* @__PURE__ */
|
|
4021
|
+
/* @__PURE__ */ jsx64("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
|
|
4022
|
+
) : /* @__PURE__ */ jsx64(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
|
|
3828
4023
|
]
|
|
3829
4024
|
}
|
|
3830
4025
|
);
|
|
3831
4026
|
}
|
|
3832
4027
|
function ListColumn(props) {
|
|
3833
|
-
return /* @__PURE__ */
|
|
4028
|
+
return /* @__PURE__ */ jsx64(
|
|
3834
4029
|
ErrorBoundary,
|
|
3835
4030
|
{
|
|
3836
4031
|
label: "list panel",
|
|
3837
4032
|
frame: (message) => (
|
|
3838
4033
|
// Only the name comes back with the message: the actions and the row above may be what threw.
|
|
3839
|
-
/* @__PURE__ */
|
|
4034
|
+
/* @__PURE__ */ jsx64(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
|
|
3840
4035
|
),
|
|
3841
|
-
children: /* @__PURE__ */
|
|
4036
|
+
children: /* @__PURE__ */ jsx64(Column, { ...props })
|
|
3842
4037
|
}
|
|
3843
4038
|
);
|
|
3844
4039
|
}
|
|
3845
4040
|
|
|
3846
4041
|
// src/Tabs.tsx
|
|
3847
4042
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
3848
|
-
import { jsx as
|
|
4043
|
+
import { Fragment as Fragment14, jsx as jsx65, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3849
4044
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
3850
|
-
return /* @__PURE__ */
|
|
4045
|
+
return /* @__PURE__ */ jsx65(
|
|
3851
4046
|
BaseTabs.Root,
|
|
3852
4047
|
{
|
|
3853
4048
|
value: active,
|
|
@@ -3855,14 +4050,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3855
4050
|
if (details.reason === "none") onChange(value);
|
|
3856
4051
|
},
|
|
3857
4052
|
className,
|
|
3858
|
-
children: /* @__PURE__ */
|
|
4053
|
+
children: /* @__PURE__ */ jsx65(
|
|
3859
4054
|
BaseTabs.List,
|
|
3860
4055
|
{
|
|
3861
4056
|
activateOnFocus: true,
|
|
3862
4057
|
"aria-label": aria["aria-label"],
|
|
3863
4058
|
"aria-labelledby": aria["aria-labelledby"],
|
|
3864
4059
|
className: "flex items-center gap-2",
|
|
3865
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
4060
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs46(
|
|
3866
4061
|
BaseTabs.Tab,
|
|
3867
4062
|
{
|
|
3868
4063
|
value: tab.id,
|
|
@@ -3875,10 +4070,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3875
4070
|
),
|
|
3876
4071
|
children: [
|
|
3877
4072
|
tab.icon,
|
|
3878
|
-
/* @__PURE__ */
|
|
4073
|
+
/* @__PURE__ */ jsxs46("span", { className: "flex items-baseline", children: [
|
|
3879
4074
|
tab.label,
|
|
3880
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
3881
|
-
] })
|
|
4075
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx65("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
4076
|
+
] }),
|
|
4077
|
+
tab.unread ? /* @__PURE__ */ jsxs46(Fragment14, { children: [
|
|
4078
|
+
/* @__PURE__ */ jsx65(UnreadDot, { className: "h-auto w-auto" }),
|
|
4079
|
+
/* @__PURE__ */ jsx65("span", { className: "sr-only", children: "new" })
|
|
4080
|
+
] }) : null
|
|
3882
4081
|
]
|
|
3883
4082
|
},
|
|
3884
4083
|
tab.id
|
|
@@ -3890,10 +4089,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3890
4089
|
}
|
|
3891
4090
|
|
|
3892
4091
|
// src/Toast.tsx
|
|
3893
|
-
import { createContext as
|
|
4092
|
+
import { createContext as createContext7, useContext as useContext7, useMemo as useMemo6 } from "react";
|
|
3894
4093
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
3895
4094
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
3896
|
-
import { jsx as
|
|
4095
|
+
import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3897
4096
|
var SURFACE_STYLES = {
|
|
3898
4097
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
3899
4098
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
@@ -3929,23 +4128,23 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
3929
4128
|
);
|
|
3930
4129
|
function LeadingIcon({ type }) {
|
|
3931
4130
|
const Icon = ICONS[type];
|
|
3932
|
-
return /* @__PURE__ */
|
|
4131
|
+
return /* @__PURE__ */ jsx66(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
3933
4132
|
}
|
|
3934
4133
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
3935
4134
|
const hasAction = !!(actionLabel && onAction);
|
|
3936
|
-
return /* @__PURE__ */
|
|
3937
|
-
/* @__PURE__ */
|
|
3938
|
-
leadingIcon && /* @__PURE__ */
|
|
3939
|
-
/* @__PURE__ */
|
|
4135
|
+
return /* @__PURE__ */ jsxs47("div", { className: pillClassName(type, hasAction, className), children: [
|
|
4136
|
+
/* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4137
|
+
leadingIcon && /* @__PURE__ */ jsx66(LeadingIcon, { type }),
|
|
4138
|
+
/* @__PURE__ */ jsx66("span", { className: LABEL_CLASSES, children: label })
|
|
3940
4139
|
] }),
|
|
3941
|
-
hasAction && /* @__PURE__ */
|
|
4140
|
+
hasAction && /* @__PURE__ */ jsx66(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
3942
4141
|
] });
|
|
3943
4142
|
}
|
|
3944
|
-
var ToastContext =
|
|
4143
|
+
var ToastContext = createContext7(null);
|
|
3945
4144
|
var VISIBLE_TOASTS = 3;
|
|
3946
4145
|
function ToastProvider({ children }) {
|
|
3947
|
-
const manager =
|
|
3948
|
-
const value =
|
|
4146
|
+
const manager = useMemo6(() => BaseToast.createToastManager(), []);
|
|
4147
|
+
const value = useMemo6(
|
|
3949
4148
|
() => ({
|
|
3950
4149
|
showToast: ({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, durationMs = 5e3 }) => manager.add({
|
|
3951
4150
|
title: label,
|
|
@@ -3959,9 +4158,9 @@ function ToastProvider({ children }) {
|
|
|
3959
4158
|
}),
|
|
3960
4159
|
[manager]
|
|
3961
4160
|
);
|
|
3962
|
-
return /* @__PURE__ */
|
|
4161
|
+
return /* @__PURE__ */ jsx66(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs47(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
3963
4162
|
children,
|
|
3964
|
-
/* @__PURE__ */
|
|
4163
|
+
/* @__PURE__ */ jsx66(BaseToast.Portal, { children: /* @__PURE__ */ jsx66(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx66(ToastList, {}) }) })
|
|
3965
4164
|
] }) });
|
|
3966
4165
|
}
|
|
3967
4166
|
function ToastList() {
|
|
@@ -3969,25 +4168,25 @@ function ToastList() {
|
|
|
3969
4168
|
return toasts.map((toast) => {
|
|
3970
4169
|
const type = toast.type ?? "neutral";
|
|
3971
4170
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
3972
|
-
return /* @__PURE__ */
|
|
4171
|
+
return /* @__PURE__ */ jsxs47(
|
|
3973
4172
|
BaseToast.Root,
|
|
3974
4173
|
{
|
|
3975
4174
|
toast,
|
|
3976
4175
|
swipeDirection: ["left", "down"],
|
|
3977
4176
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
3978
4177
|
children: [
|
|
3979
|
-
/* @__PURE__ */
|
|
3980
|
-
leadingIcon && /* @__PURE__ */
|
|
3981
|
-
/* @__PURE__ */
|
|
4178
|
+
/* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4179
|
+
leadingIcon && /* @__PURE__ */ jsx66(LeadingIcon, { type }),
|
|
4180
|
+
/* @__PURE__ */ jsx66(BaseToast.Title, { render: /* @__PURE__ */ jsx66("span", {}), className: LABEL_CLASSES })
|
|
3982
4181
|
] }),
|
|
3983
|
-
actionLabel && /* @__PURE__ */
|
|
4182
|
+
actionLabel && /* @__PURE__ */ jsx66(
|
|
3984
4183
|
BaseToast.Action,
|
|
3985
4184
|
{
|
|
3986
4185
|
onClick: () => {
|
|
3987
4186
|
onAction?.();
|
|
3988
4187
|
close(toast.id);
|
|
3989
4188
|
},
|
|
3990
|
-
render: /* @__PURE__ */
|
|
4189
|
+
render: /* @__PURE__ */ jsx66(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
3991
4190
|
}
|
|
3992
4191
|
)
|
|
3993
4192
|
]
|
|
@@ -3997,24 +4196,12 @@ function ToastList() {
|
|
|
3997
4196
|
});
|
|
3998
4197
|
}
|
|
3999
4198
|
function useToast() {
|
|
4000
|
-
const ctx =
|
|
4199
|
+
const ctx = useContext7(ToastContext);
|
|
4001
4200
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
4002
4201
|
return ctx;
|
|
4003
4202
|
}
|
|
4004
|
-
|
|
4005
|
-
// src/shortcuts.ts
|
|
4006
|
-
function isApplePlatform() {
|
|
4007
|
-
if (typeof navigator === "undefined") return false;
|
|
4008
|
-
return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
|
|
4009
|
-
}
|
|
4010
|
-
function shortcutLabel(keys, apple = isApplePlatform()) {
|
|
4011
|
-
return keys.split("-").map((part, i, all) => {
|
|
4012
|
-
if (i === all.length - 1) return part.length === 1 ? part.toUpperCase() : part;
|
|
4013
|
-
if (part === "Mod") return apple ? "Cmd" : "Ctrl";
|
|
4014
|
-
return part;
|
|
4015
|
-
}).join("+");
|
|
4016
|
-
}
|
|
4017
4203
|
export {
|
|
4204
|
+
AppProvider,
|
|
4018
4205
|
AppShell,
|
|
4019
4206
|
AttachmentCard,
|
|
4020
4207
|
Avatar,
|
|
@@ -4058,6 +4245,8 @@ export {
|
|
|
4058
4245
|
Lightbox,
|
|
4059
4246
|
Link,
|
|
4060
4247
|
ListColumn,
|
|
4248
|
+
MembersDialog,
|
|
4249
|
+
MembersPill,
|
|
4061
4250
|
Menu,
|
|
4062
4251
|
MenuItem,
|
|
4063
4252
|
MenuPanel,
|