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