@estiva-app/ui 0.12.10 → 0.13.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/AttachmentCard.d.ts +52 -0
- package/dist/AttachmentCard.d.ts.map +1 -0
- package/dist/Card.d.ts +48 -0
- package/dist/Card.d.ts.map +1 -0
- package/dist/InlineChip.d.ts +59 -0
- package/dist/InlineChip.d.ts.map +1 -0
- package/dist/Link.d.ts +37 -0
- package/dist/Link.d.ts.map +1 -0
- package/dist/ProgressBar.d.ts +32 -0
- package/dist/ProgressBar.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +694 -355
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/AttachmentCard.mdx +62 -0
- package/src/AttachmentCard.stories.tsx +92 -0
- package/src/AttachmentCard.test.tsx +172 -0
- package/src/AttachmentCard.tsx +324 -0
- package/src/Card.mdx +68 -0
- package/src/Card.stories.tsx +109 -0
- package/src/Card.test.tsx +106 -0
- package/src/Card.tsx +115 -0
- package/src/EmptyState.mdx +14 -0
- package/src/EmptyState.stories.tsx +28 -7
- package/src/EmptyState.test.tsx +8 -0
- package/src/InlineChip.mdx +56 -0
- package/src/InlineChip.stories.tsx +59 -0
- package/src/InlineChip.test.tsx +81 -0
- package/src/InlineChip.tsx +90 -0
- package/src/Link.mdx +59 -0
- package/src/Link.stories.tsx +102 -0
- package/src/Link.test.tsx +100 -0
- package/src/Link.tsx +58 -0
- package/src/Person.stories.tsx +1 -1
- package/src/PersonTrigger.stories.tsx +1 -1
- package/src/ProgressBar.mdx +47 -0
- package/src/ProgressBar.stories.tsx +48 -0
- package/src/ProgressBar.test.tsx +62 -0
- package/src/ProgressBar.tsx +56 -0
- package/src/ReactionPicker.stories.tsx +1 -1
- package/src/index.ts +12 -0
- package/stories/Choosing.mdx +5 -0
package/dist/index.js
CHANGED
|
@@ -133,77 +133,103 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
// src/
|
|
137
|
-
import { useState } from "react";
|
|
138
|
-
import {
|
|
136
|
+
// src/AttachmentCard.tsx
|
|
137
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
138
|
+
import { Button as BaseButton2 } from "@base-ui/react/button";
|
|
139
|
+
import {
|
|
140
|
+
IconAlertCircle,
|
|
141
|
+
IconAlertTriangle,
|
|
142
|
+
IconDownload,
|
|
143
|
+
IconFile,
|
|
144
|
+
IconFileTypeCsv,
|
|
145
|
+
IconFileTypeDocx,
|
|
146
|
+
IconFileTypePdf,
|
|
147
|
+
IconFileTypePpt,
|
|
148
|
+
IconFileTypeTxt,
|
|
149
|
+
IconFileTypeXls,
|
|
150
|
+
IconFileTypeZip,
|
|
151
|
+
IconJson,
|
|
152
|
+
IconLoader2,
|
|
153
|
+
IconMarkdown,
|
|
154
|
+
IconX
|
|
155
|
+
} from "@tabler/icons-react";
|
|
156
|
+
|
|
157
|
+
// src/Link.tsx
|
|
139
158
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
140
|
-
var
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
var VARIANT_CLASSES = {
|
|
160
|
+
text: "text-info-default underline underline-offset-2 hover:opacity-80",
|
|
161
|
+
quiet: "hover:underline",
|
|
162
|
+
underlined: "underline underline-offset-2 hover:text-text-primary",
|
|
163
|
+
plain: ""
|
|
145
164
|
};
|
|
146
|
-
|
|
147
|
-
const words = name.split(/\s+/).slice(0, 2).filter((w) => /^[\p{L}\p{N}]/u.test(w));
|
|
148
|
-
const initials = words.map((w) => w[0]).join("") || name.trim().charAt(0);
|
|
149
|
-
return initials.toUpperCase();
|
|
150
|
-
};
|
|
151
|
-
function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
152
|
-
const [broken, setBroken] = useState(false);
|
|
153
|
-
const label = name || alt;
|
|
154
|
-
const picture = src && !broken ? src : void 0;
|
|
165
|
+
function Link({ href, variant = "text", external = false, className, children, ...props }) {
|
|
155
166
|
return /* @__PURE__ */ jsx4(
|
|
156
|
-
"
|
|
167
|
+
"a",
|
|
157
168
|
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
className: "w-full h-full flex items-center justify-center font-semibold leading-none",
|
|
165
|
-
style: {
|
|
166
|
-
// The one ink colour that reads on all eight hues, which are a
|
|
167
|
-
// palette rather than tokens (see the note at the top) — so its
|
|
168
|
-
// ink cannot be a token either.
|
|
169
|
-
color: "#08121c",
|
|
170
|
-
fontSize: Math.round(size * 0.36),
|
|
171
|
-
background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
|
|
172
|
-
},
|
|
173
|
-
children: initialsFor(label)
|
|
174
|
-
}
|
|
175
|
-
) : /* @__PURE__ */ jsx4("div", { className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx4(IconUserFilled, { size: Math.round(size * 0.5) }) })
|
|
169
|
+
href,
|
|
170
|
+
...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
|
|
171
|
+
className: cn(VARIANT_CLASSES[variant], className),
|
|
172
|
+
...props,
|
|
173
|
+
children
|
|
176
174
|
}
|
|
177
175
|
);
|
|
178
176
|
}
|
|
179
177
|
|
|
180
|
-
// src/
|
|
178
|
+
// src/Card.tsx
|
|
181
179
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
180
|
+
var FILL_CLASSES = {
|
|
181
|
+
surface: "bg-bg-surface border-border-default",
|
|
182
|
+
elevated: "bg-bg-elevated border-border-default",
|
|
183
|
+
inset: "bg-bg-inset border-border-subtle",
|
|
184
|
+
none: "border-border-subtle"
|
|
185
|
+
};
|
|
186
|
+
var HAIRLINE_HOVER_CLASSES = {
|
|
187
|
+
surface: "hover:border-border-strong",
|
|
188
|
+
elevated: "hover:border-border-strong",
|
|
189
|
+
inset: "hover:border-border-default",
|
|
190
|
+
none: "hover:border-border-default"
|
|
191
|
+
};
|
|
192
|
+
var ATTENTION_CLASSES = {
|
|
193
|
+
accent: "border-accent-muted hover:border-accent-muted",
|
|
194
|
+
warning: "border-warning-muted hover:border-warning-muted"
|
|
195
|
+
};
|
|
196
|
+
function Card({
|
|
197
|
+
fill = "surface",
|
|
198
|
+
href,
|
|
199
|
+
hover = href ? "hairline" : "none",
|
|
200
|
+
quietUntilHover = false,
|
|
201
|
+
selected = false,
|
|
202
|
+
active = false,
|
|
203
|
+
attention,
|
|
204
|
+
unreadable = false,
|
|
205
|
+
className,
|
|
206
|
+
children,
|
|
207
|
+
...props
|
|
208
|
+
}) {
|
|
209
|
+
const still = selected || active;
|
|
210
|
+
const classes = cn(
|
|
211
|
+
"rounded-lg border",
|
|
212
|
+
// A card that never changes has nothing to ease between, and the apps' still cards carry no transition.
|
|
213
|
+
hover !== "none" && "transition-colors",
|
|
214
|
+
FILL_CLASSES[fill],
|
|
215
|
+
quietUntilHover && "border-transparent",
|
|
216
|
+
!still && hover === "hairline" && HAIRLINE_HOVER_CLASSES[fill],
|
|
217
|
+
!still && hover === "fill" && "hover:bg-bg-hover hover:border-border-default",
|
|
218
|
+
!still && hover !== "none" && !href && props.onClick && "cursor-pointer",
|
|
219
|
+
selected && "bg-bg-selected border-border-subtle",
|
|
220
|
+
active && "bg-bg-selected border-accent-primary",
|
|
221
|
+
!active && attention && ATTENTION_CLASSES[attention],
|
|
222
|
+
unreadable && "border-dashed",
|
|
223
|
+
href && "block",
|
|
224
|
+
className
|
|
225
|
+
);
|
|
226
|
+
if (href !== void 0) {
|
|
227
|
+
const { ref, ...anchorProps } = props;
|
|
228
|
+
return /* @__PURE__ */ jsx5(Link, { href, variant: "plain", ref, className: classes, ...anchorProps, children });
|
|
229
|
+
}
|
|
230
|
+
return /* @__PURE__ */ jsx5("div", { className: classes, ...props, children });
|
|
202
231
|
}
|
|
203
232
|
|
|
204
|
-
// src/Banner.tsx
|
|
205
|
-
import { IconX } from "@tabler/icons-react";
|
|
206
|
-
|
|
207
233
|
// src/IconButton.tsx
|
|
208
234
|
import { Button as BaseButton } from "@base-ui/react/button";
|
|
209
235
|
|
|
@@ -344,8 +370,260 @@ function IconButton({
|
|
|
344
370
|
return button;
|
|
345
371
|
}
|
|
346
372
|
|
|
373
|
+
// src/AttachmentCard.tsx
|
|
374
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
375
|
+
var ICON_BY_EXTENSION = {
|
|
376
|
+
pdf: IconFileTypePdf,
|
|
377
|
+
doc: IconFileTypeDocx,
|
|
378
|
+
docx: IconFileTypeDocx,
|
|
379
|
+
xls: IconFileTypeXls,
|
|
380
|
+
xlsx: IconFileTypeXls,
|
|
381
|
+
ppt: IconFileTypePpt,
|
|
382
|
+
pptx: IconFileTypePpt,
|
|
383
|
+
csv: IconFileTypeCsv,
|
|
384
|
+
txt: IconFileTypeTxt,
|
|
385
|
+
rtf: IconFileTypeTxt,
|
|
386
|
+
zip: IconFileTypeZip,
|
|
387
|
+
json: IconJson,
|
|
388
|
+
md: IconMarkdown
|
|
389
|
+
};
|
|
390
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "heic", "heif", "svg"]);
|
|
391
|
+
var extensionOf = (name) => {
|
|
392
|
+
const dot = name.lastIndexOf(".");
|
|
393
|
+
return dot >= 0 ? name.slice(dot + 1).toLowerCase() : "";
|
|
394
|
+
};
|
|
395
|
+
var isImage = (name, contentType) => IMAGE_EXTENSIONS.has(extensionOf(name)) || (contentType?.startsWith("image/") ?? false);
|
|
396
|
+
var formatBytes = (bytes) => {
|
|
397
|
+
if (bytes < 1024) return `${bytes} bytes`;
|
|
398
|
+
const kb = bytes / 1024;
|
|
399
|
+
if (kb < 1024) return `${Math.round(kb)} KB`;
|
|
400
|
+
return `${(kb / 1024).toFixed(1)} MB`;
|
|
401
|
+
};
|
|
402
|
+
var typeLabelOf = (name) => extensionOf(name).toUpperCase() || "FILE";
|
|
403
|
+
var TILE = "size-9 rounded-md bg-bg-active flex items-center justify-center shrink-0 text-text-secondary";
|
|
404
|
+
var NAME = "text-[12px] font-medium leading-[1.3] text-text-primary truncate";
|
|
405
|
+
var NOTE = "text-[10px] leading-[1.2] truncate";
|
|
406
|
+
function TypeIcon({ name }) {
|
|
407
|
+
const Icon = ICON_BY_EXTENSION[extensionOf(name)] ?? IconFile;
|
|
408
|
+
return /* @__PURE__ */ jsx9(Icon, { size: 20, stroke: 1.5 });
|
|
409
|
+
}
|
|
410
|
+
function Truncating({ text, hint, className, wrapperClassName }) {
|
|
411
|
+
const ref = useRef(null);
|
|
412
|
+
const [cut, setCut] = useState(false);
|
|
413
|
+
useLayoutEffect(() => {
|
|
414
|
+
const el = ref.current;
|
|
415
|
+
if (!el) return;
|
|
416
|
+
let live = true;
|
|
417
|
+
const measure = () => {
|
|
418
|
+
if (live) setCut(el.scrollWidth > el.clientWidth);
|
|
419
|
+
};
|
|
420
|
+
measure();
|
|
421
|
+
void document.fonts?.ready.then(measure);
|
|
422
|
+
if (typeof ResizeObserver === "undefined") return () => void (live = false);
|
|
423
|
+
const observer = new ResizeObserver(measure);
|
|
424
|
+
observer.observe(el);
|
|
425
|
+
return () => {
|
|
426
|
+
live = false;
|
|
427
|
+
observer.disconnect();
|
|
428
|
+
};
|
|
429
|
+
}, [text, cut]);
|
|
430
|
+
const line = /* @__PURE__ */ jsx9("span", { ref, className, children: text });
|
|
431
|
+
if (!hint && !cut) return line;
|
|
432
|
+
return /* @__PURE__ */ jsx9(WithTooltip, { label: hint ?? text, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
|
|
433
|
+
}
|
|
434
|
+
function AttachmentCard({
|
|
435
|
+
name,
|
|
436
|
+
size,
|
|
437
|
+
contentType,
|
|
438
|
+
href,
|
|
439
|
+
src,
|
|
440
|
+
onOpen,
|
|
441
|
+
onDownload,
|
|
442
|
+
pending = false,
|
|
443
|
+
onRemove,
|
|
444
|
+
state = "ready",
|
|
445
|
+
note,
|
|
446
|
+
noteHint,
|
|
447
|
+
className,
|
|
448
|
+
...props
|
|
449
|
+
}) {
|
|
450
|
+
const image = isImage(name, contentType);
|
|
451
|
+
const sizeText = size === void 0 ? "" : formatBytes(size);
|
|
452
|
+
if (pending) {
|
|
453
|
+
const failed = state === "failed";
|
|
454
|
+
const warning = state === "warning";
|
|
455
|
+
return /* @__PURE__ */ jsxs5(
|
|
456
|
+
Card,
|
|
457
|
+
{
|
|
458
|
+
fill: "elevated",
|
|
459
|
+
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),
|
|
460
|
+
...props,
|
|
461
|
+
children: [
|
|
462
|
+
/* @__PURE__ */ jsx9("div", { className: cn(TILE, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx9(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx9(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx9(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx9("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx9("span", { className: "text-[9px] font-semibold", children: typeLabelOf(name) }) }),
|
|
463
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0", children: [
|
|
464
|
+
/* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
|
|
465
|
+
/* @__PURE__ */ jsx9(
|
|
466
|
+
Truncating,
|
|
467
|
+
{
|
|
468
|
+
text: (failed || warning ? note : state === "uploading" ? note ?? "Uploading\u2026" : note ?? sizeText) ?? "",
|
|
469
|
+
hint: noteHint,
|
|
470
|
+
className: cn(NOTE, failed ? "text-error-default" : warning ? "text-warning-default" : "text-text-secondary")
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
] }),
|
|
474
|
+
onRemove && /* @__PURE__ */ jsx9(
|
|
475
|
+
BaseButton2,
|
|
476
|
+
{
|
|
477
|
+
type: "button",
|
|
478
|
+
"aria-label": `Remove ${name}`,
|
|
479
|
+
className: "absolute -top-1.5 -right-1.5 size-5 rounded-full bg-bg-elevated border border-border-strong flex items-center justify-center text-text-secondary hover:text-text-primary opacity-0 group-hover:opacity-100 transition-opacity",
|
|
480
|
+
onClick: (event) => {
|
|
481
|
+
event.stopPropagation();
|
|
482
|
+
onRemove();
|
|
483
|
+
},
|
|
484
|
+
children: /* @__PURE__ */ jsx9(IconX, { size: 11, stroke: 1.75 })
|
|
485
|
+
}
|
|
486
|
+
)
|
|
487
|
+
]
|
|
488
|
+
}
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
const download = onDownload ? /* @__PURE__ */ jsx9(
|
|
492
|
+
IconButton,
|
|
493
|
+
{
|
|
494
|
+
variant: "muted",
|
|
495
|
+
tooltip: "Download",
|
|
496
|
+
"aria-label": `Download ${name}`,
|
|
497
|
+
className: "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 transition-opacity",
|
|
498
|
+
onClick: (event) => {
|
|
499
|
+
event.stopPropagation();
|
|
500
|
+
onDownload();
|
|
501
|
+
},
|
|
502
|
+
children: /* @__PURE__ */ jsx9(IconDownload, { size: 16, stroke: 1.5 })
|
|
503
|
+
}
|
|
504
|
+
) : null;
|
|
505
|
+
if (state === "loading") {
|
|
506
|
+
return (
|
|
507
|
+
// `role="status"`: a plain box may not carry a name (axe, aria-prohibited-attr), and a
|
|
508
|
+
// status says what it is doing — loading — to a reader that cannot see the pulse.
|
|
509
|
+
/* @__PURE__ */ jsx9(Card, { role: "status", fill: "inset", "aria-busy": "true", "aria-label": `Loading ${name}`, className: cn("w-[180px] h-28 animate-pulse", className), ...props, children: null })
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
if (state === "unreadable") {
|
|
513
|
+
return /* @__PURE__ */ jsxs5(Card, { fill: "inset", unreadable: true, className: cn("flex items-center gap-2 w-[240px] p-1.5 opacity-70", className), ...props, children: [
|
|
514
|
+
/* @__PURE__ */ jsx9("div", { className: TILE, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
|
|
515
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
|
|
516
|
+
/* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
|
|
517
|
+
/* @__PURE__ */ jsx9("span", { className: cn(NOTE, "text-text-secondary"), children: note ?? "Could not be loaded" })
|
|
518
|
+
] })
|
|
519
|
+
] });
|
|
520
|
+
}
|
|
521
|
+
if (image && src) {
|
|
522
|
+
const picture = /* @__PURE__ */ jsx9("img", { src, alt: name, className: "w-full h-28 object-cover" });
|
|
523
|
+
return /* @__PURE__ */ jsxs5(Card, { fill: "inset", hover: "hairline", className: cn("group relative flex flex-col w-[180px] overflow-hidden", className), ...props, children: [
|
|
524
|
+
onOpen ? /* @__PURE__ */ jsx9(
|
|
525
|
+
BaseButton2,
|
|
526
|
+
{
|
|
527
|
+
type: "button",
|
|
528
|
+
className: "block w-full",
|
|
529
|
+
"aria-label": `Preview ${name}`,
|
|
530
|
+
onClick: (event) => {
|
|
531
|
+
event.stopPropagation();
|
|
532
|
+
onOpen();
|
|
533
|
+
},
|
|
534
|
+
children: picture
|
|
535
|
+
}
|
|
536
|
+
) : /* @__PURE__ */ jsx9("div", { className: "block w-full", children: picture }),
|
|
537
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 pl-2 pr-1 py-1 min-w-0", children: [
|
|
538
|
+
/* @__PURE__ */ jsx9(Truncating, { text: name, className: "flex-1 text-[12px] leading-[1.3] text-text-primary truncate", wrapperClassName: "flex-1" }),
|
|
539
|
+
download
|
|
540
|
+
] })
|
|
541
|
+
] });
|
|
542
|
+
}
|
|
543
|
+
const body = /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
544
|
+
/* @__PURE__ */ jsx9("div", { className: TILE, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
|
|
545
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
|
|
546
|
+
/* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
|
|
547
|
+
/* @__PURE__ */ jsx9("span", { className: cn(NOTE, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
|
|
548
|
+
] })
|
|
549
|
+
] });
|
|
550
|
+
return /* @__PURE__ */ jsxs5(Card, { fill: "inset", hover: href ? "hairline" : "none", className: cn("group flex items-center gap-2 w-[240px] p-1.5 pr-1", !href && "opacity-70", className), ...props, children: [
|
|
551
|
+
href ? /* @__PURE__ */ jsx9(Link, { href, external: true, variant: "plain", className: "flex items-center gap-2 min-w-0 flex-1 cursor-pointer", onClick: (event) => event.stopPropagation(), children: body }) : /* @__PURE__ */ jsx9("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: body }),
|
|
552
|
+
download
|
|
553
|
+
] });
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// src/Avatar.tsx
|
|
557
|
+
import { useState as useState2 } from "react";
|
|
558
|
+
import { IconUserFilled } from "@tabler/icons-react";
|
|
559
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
560
|
+
var HUES = ["#56c8ff", "#ff8f6b", "#4ade8c", "#b18cff", "#ffc94d", "#ff7eb0", "#7ea8ff", "#5fdfd6"];
|
|
561
|
+
var hueFor = (key) => {
|
|
562
|
+
let h = 0;
|
|
563
|
+
for (let i = 0; i < key.length; i++) h = h * 31 + key.charCodeAt(i) | 0;
|
|
564
|
+
return HUES[Math.abs(h) % HUES.length];
|
|
565
|
+
};
|
|
566
|
+
var initialsFor = (name) => {
|
|
567
|
+
const words = name.split(/\s+/).slice(0, 2).filter((w) => /^[\p{L}\p{N}]/u.test(w));
|
|
568
|
+
const initials = words.map((w) => w[0]).join("") || name.trim().charAt(0);
|
|
569
|
+
return initials.toUpperCase();
|
|
570
|
+
};
|
|
571
|
+
function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
572
|
+
const [broken, setBroken] = useState2(false);
|
|
573
|
+
const label = name || alt;
|
|
574
|
+
const picture = src && !broken ? src : void 0;
|
|
575
|
+
return /* @__PURE__ */ jsx10(
|
|
576
|
+
"div",
|
|
577
|
+
{
|
|
578
|
+
...spoken ? { role: "img", "aria-label": spoken } : { "aria-hidden": true },
|
|
579
|
+
className: cn("rounded-sm overflow-hidden shrink-0 bg-bg-inset", className),
|
|
580
|
+
style: { width: size, height: size },
|
|
581
|
+
children: picture ? /* @__PURE__ */ jsx10("img", { src: picture, alt: "", className: "w-full h-full object-cover", onError: () => setBroken(true) }) : label ? /* @__PURE__ */ jsx10(
|
|
582
|
+
"div",
|
|
583
|
+
{
|
|
584
|
+
className: "w-full h-full flex items-center justify-center font-semibold leading-none",
|
|
585
|
+
style: {
|
|
586
|
+
// The one ink colour that reads on all eight hues, which are a
|
|
587
|
+
// palette rather than tokens (see the note at the top) — so its
|
|
588
|
+
// ink cannot be a token either.
|
|
589
|
+
color: "#08121c",
|
|
590
|
+
fontSize: Math.round(size * 0.36),
|
|
591
|
+
background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
|
|
592
|
+
},
|
|
593
|
+
children: initialsFor(label)
|
|
594
|
+
}
|
|
595
|
+
) : /* @__PURE__ */ jsx10("div", { className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx10(IconUserFilled, { size: Math.round(size * 0.5) }) })
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/AvatarGroup.tsx
|
|
601
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
602
|
+
function AvatarGroup({ members, size = 24 }) {
|
|
603
|
+
const visible = members.slice(0, 3);
|
|
604
|
+
const overlap = Math.round(size / 3);
|
|
605
|
+
const ring = size / 12;
|
|
606
|
+
return /* @__PURE__ */ jsx11("div", { className: "flex items-center", style: { paddingRight: overlap }, children: visible.map((member, i) => (
|
|
607
|
+
/*
|
|
608
|
+
The wrapper carries the overlap and the ring; the face carries
|
|
609
|
+
neither. It must never clip — see the note at the top of the file —
|
|
610
|
+
so it has the avatar's own radius and no overflow of its own.
|
|
611
|
+
*/
|
|
612
|
+
/* @__PURE__ */ jsx11(
|
|
613
|
+
"span",
|
|
614
|
+
{
|
|
615
|
+
className: "relative flex rounded-sm",
|
|
616
|
+
style: { marginRight: -overlap, boxShadow: `0 0 0 ${ring}px var(--bg-surface)` },
|
|
617
|
+
children: /* @__PURE__ */ jsx11(Avatar, { size, name: member.name, src: member.picture, label: member.name })
|
|
618
|
+
},
|
|
619
|
+
i
|
|
620
|
+
)
|
|
621
|
+
)) });
|
|
622
|
+
}
|
|
623
|
+
|
|
347
624
|
// src/Banner.tsx
|
|
348
|
-
import {
|
|
625
|
+
import { IconX as IconX2 } from "@tabler/icons-react";
|
|
626
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
349
627
|
var TONE_STYLES = {
|
|
350
628
|
ok: "bg-success-muted text-success-default",
|
|
351
629
|
error: "bg-error-muted text-error-default",
|
|
@@ -355,17 +633,17 @@ var TONE_STYLES = {
|
|
|
355
633
|
function Banner({ tone, children, onDismiss, dismissLabel = "Dismiss", className }) {
|
|
356
634
|
const role = tone === "error" ? "alert" : "status";
|
|
357
635
|
if (!onDismiss) {
|
|
358
|
-
return /* @__PURE__ */
|
|
636
|
+
return /* @__PURE__ */ jsx12("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
|
|
359
637
|
}
|
|
360
|
-
return /* @__PURE__ */
|
|
361
|
-
/* @__PURE__ */
|
|
362
|
-
/* @__PURE__ */
|
|
638
|
+
return /* @__PURE__ */ jsxs6("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
|
|
639
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1", children }),
|
|
640
|
+
/* @__PURE__ */ jsx12(IconButton, { "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0 text-current hover:text-current", children: /* @__PURE__ */ jsx12(IconX2, { size: 16, stroke: 1.5 }) })
|
|
363
641
|
] });
|
|
364
642
|
}
|
|
365
643
|
|
|
366
644
|
// src/Button.tsx
|
|
367
|
-
import { Button as
|
|
368
|
-
import { jsx as
|
|
645
|
+
import { Button as BaseButton3 } from "@base-ui/react/button";
|
|
646
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
369
647
|
function Button({
|
|
370
648
|
variant = "muted",
|
|
371
649
|
size = "default",
|
|
@@ -378,8 +656,8 @@ function Button({
|
|
|
378
656
|
...props
|
|
379
657
|
}) {
|
|
380
658
|
const hasLeadingIcon = !!leadingIcon;
|
|
381
|
-
const button = /* @__PURE__ */
|
|
382
|
-
|
|
659
|
+
const button = /* @__PURE__ */ jsxs7(
|
|
660
|
+
BaseButton3,
|
|
383
661
|
{
|
|
384
662
|
type,
|
|
385
663
|
disabled: disabled || !!disabledReason,
|
|
@@ -423,13 +701,13 @@ function Button({
|
|
|
423
701
|
]
|
|
424
702
|
}
|
|
425
703
|
);
|
|
426
|
-
return disabledReason ? /* @__PURE__ */
|
|
704
|
+
return disabledReason ? /* @__PURE__ */ jsx13(TooltipTrigger, { label: disabledReason, children: button }) : button;
|
|
427
705
|
}
|
|
428
706
|
|
|
429
707
|
// src/Checkbox.tsx
|
|
430
708
|
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
431
709
|
import { IconCheck } from "@tabler/icons-react";
|
|
432
|
-
import { jsx as
|
|
710
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
433
711
|
function squareClasses(checked, disabled, interactive, className) {
|
|
434
712
|
return cn(
|
|
435
713
|
"inline-flex items-center justify-center size-4 shrink-0 rounded-[4px] border transition-colors",
|
|
@@ -442,9 +720,9 @@ function squareClasses(checked, disabled, interactive, className) {
|
|
|
442
720
|
var tickClasses = (checked) => cn("flex", !checked && "invisible");
|
|
443
721
|
function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
444
722
|
if (!onChange) {
|
|
445
|
-
return /* @__PURE__ */
|
|
723
|
+
return /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx14("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
446
724
|
}
|
|
447
|
-
return /* @__PURE__ */
|
|
725
|
+
return /* @__PURE__ */ jsx14(
|
|
448
726
|
BaseCheckbox.Root,
|
|
449
727
|
{
|
|
450
728
|
checked,
|
|
@@ -454,13 +732,13 @@ function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
|
454
732
|
onCheckedChange: (next) => onChange(next),
|
|
455
733
|
onClick: (e) => e.stopPropagation(),
|
|
456
734
|
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
457
|
-
children: /* @__PURE__ */
|
|
735
|
+
children: /* @__PURE__ */ jsx14(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) })
|
|
458
736
|
}
|
|
459
737
|
);
|
|
460
738
|
}
|
|
461
739
|
|
|
462
740
|
// src/Chip.tsx
|
|
463
|
-
import { jsx as
|
|
741
|
+
import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
464
742
|
var typeStyles = {
|
|
465
743
|
neutral: "bg-bg-inset text-text-primary",
|
|
466
744
|
brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
|
|
@@ -470,8 +748,8 @@ var typeStyles = {
|
|
|
470
748
|
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
471
749
|
};
|
|
472
750
|
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
|
|
473
|
-
return /* @__PURE__ */
|
|
474
|
-
leadingIcon && /* @__PURE__ */
|
|
751
|
+
return /* @__PURE__ */ jsxs8("div", { className: 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), children: [
|
|
752
|
+
leadingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
475
753
|
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
476
754
|
// of growing past it — Ship's project chip on an issue row
|
|
477
755
|
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
@@ -480,16 +758,16 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
|
|
|
480
758
|
// the screenshot diff caught every descender cut off. `clip` is the
|
|
481
759
|
// one overflow that leaves the other axis visible. A chip with no cap
|
|
482
760
|
// draws exactly as before.
|
|
483
|
-
/* @__PURE__ */
|
|
484
|
-
trailingIcon && /* @__PURE__ */
|
|
761
|
+
/* @__PURE__ */ jsx15("span", { className: "min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
|
|
762
|
+
trailingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
485
763
|
] });
|
|
486
764
|
}
|
|
487
765
|
|
|
488
766
|
// src/ChipInput.tsx
|
|
489
|
-
import { useMemo, useState as
|
|
490
|
-
import { Button as
|
|
767
|
+
import { useMemo, useState as useState3 } from "react";
|
|
768
|
+
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
491
769
|
import { Combobox } from "@base-ui/react/combobox";
|
|
492
|
-
import { IconX as
|
|
770
|
+
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
493
771
|
|
|
494
772
|
// src/Menu.tsx
|
|
495
773
|
import { createContext, useContext } from "react";
|
|
@@ -503,9 +781,9 @@ function triggerDisabled(trigger) {
|
|
|
503
781
|
}
|
|
504
782
|
|
|
505
783
|
// src/SectionLabel.tsx
|
|
506
|
-
import { jsx as
|
|
784
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
507
785
|
function SectionLabel({ children, className }) {
|
|
508
|
-
return /* @__PURE__ */
|
|
786
|
+
return /* @__PURE__ */ jsx16(
|
|
509
787
|
"span",
|
|
510
788
|
{
|
|
511
789
|
className: cn(
|
|
@@ -518,10 +796,10 @@ function SectionLabel({ children, className }) {
|
|
|
518
796
|
}
|
|
519
797
|
|
|
520
798
|
// src/Menu.tsx
|
|
521
|
-
import { Fragment, jsx as
|
|
799
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
522
800
|
var MenuContext = createContext(null);
|
|
523
801
|
function MenuPanel({ children, className, ...props }) {
|
|
524
|
-
return /* @__PURE__ */
|
|
802
|
+
return /* @__PURE__ */ jsx17(
|
|
525
803
|
"div",
|
|
526
804
|
{
|
|
527
805
|
className: cn(
|
|
@@ -551,7 +829,7 @@ var VIEWPORT_PAD2 = 8;
|
|
|
551
829
|
var HOVER_OPEN_DELAY = 0;
|
|
552
830
|
var HOVER_CLOSE_DELAY = 150;
|
|
553
831
|
function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
|
|
554
|
-
return /* @__PURE__ */
|
|
832
|
+
return /* @__PURE__ */ jsxs9(
|
|
555
833
|
BaseMenu.Root,
|
|
556
834
|
{
|
|
557
835
|
open,
|
|
@@ -559,7 +837,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
559
837
|
actionsRef,
|
|
560
838
|
modal: false,
|
|
561
839
|
children: [
|
|
562
|
-
/* @__PURE__ */
|
|
840
|
+
/* @__PURE__ */ jsx17(
|
|
563
841
|
BaseMenu.Trigger,
|
|
564
842
|
{
|
|
565
843
|
render: trigger,
|
|
@@ -569,7 +847,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
569
847
|
closeDelay: HOVER_CLOSE_DELAY
|
|
570
848
|
}
|
|
571
849
|
),
|
|
572
|
-
/* @__PURE__ */
|
|
850
|
+
/* @__PURE__ */ jsx17(BaseMenu.Portal, { children: /* @__PURE__ */ jsx17(
|
|
573
851
|
BaseMenu.Positioner,
|
|
574
852
|
{
|
|
575
853
|
side: "bottom",
|
|
@@ -577,13 +855,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
577
855
|
sideOffset: GAP2,
|
|
578
856
|
collisionPadding: VIEWPORT_PAD2,
|
|
579
857
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
580
|
-
children: /* @__PURE__ */
|
|
858
|
+
children: /* @__PURE__ */ jsx17(
|
|
581
859
|
BaseMenu.Popup,
|
|
582
860
|
{
|
|
583
861
|
"data-interactive": true,
|
|
584
862
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
585
|
-
render: /* @__PURE__ */
|
|
586
|
-
children: /* @__PURE__ */
|
|
863
|
+
render: /* @__PURE__ */ jsx17(MenuPanel, {}),
|
|
864
|
+
children: /* @__PURE__ */ jsx17(ScrollArea, { viewportClassName: "max-h-[var(--available-height)]", contentClassName: cn("flex flex-col p-2 [&>[role=separator]]:mx-0", contentClassName), children: /* @__PURE__ */ jsx17(MenuContext.Provider, { value: { openOnHover }, children }) })
|
|
587
865
|
}
|
|
588
866
|
)
|
|
589
867
|
}
|
|
@@ -599,20 +877,20 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
599
877
|
'[@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".'
|
|
600
878
|
);
|
|
601
879
|
}
|
|
602
|
-
return /* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
880
|
+
return /* @__PURE__ */ jsxs9(BaseMenu.SubmenuRoot, { children: [
|
|
881
|
+
/* @__PURE__ */ jsx17(
|
|
604
882
|
BaseMenu.SubmenuTrigger,
|
|
605
883
|
{
|
|
606
884
|
openOnHover: true,
|
|
607
885
|
delay: 0,
|
|
608
886
|
closeDelay: 150,
|
|
609
887
|
nativeButton: true,
|
|
610
|
-
render: /* @__PURE__ */
|
|
888
|
+
render: /* @__PURE__ */ jsx17("button", { type: "button" }),
|
|
611
889
|
className: menuItemClassName({ size: "default", selected }),
|
|
612
|
-
children: /* @__PURE__ */
|
|
890
|
+
children: /* @__PURE__ */ jsx17(MenuItemBody, { label, leading, submenu: true })
|
|
613
891
|
}
|
|
614
892
|
),
|
|
615
|
-
/* @__PURE__ */
|
|
893
|
+
/* @__PURE__ */ jsx17(BaseMenu.Portal, { children: /* @__PURE__ */ jsx17(
|
|
616
894
|
BaseMenu.Positioner,
|
|
617
895
|
{
|
|
618
896
|
side: "inline-end",
|
|
@@ -620,7 +898,7 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
620
898
|
sideOffset: GAP2,
|
|
621
899
|
collisionPadding: VIEWPORT_PAD2,
|
|
622
900
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
623
|
-
children: /* @__PURE__ */
|
|
901
|
+
children: /* @__PURE__ */ jsx17(BaseMenu.Popup, { className: cn("w-[160px]", className), "data-interactive": true, render: /* @__PURE__ */ jsx17(MenuPanel, {}), children })
|
|
624
902
|
}
|
|
625
903
|
) })
|
|
626
904
|
] });
|
|
@@ -655,25 +933,25 @@ function menuItemClassName({ size, selected, className }) {
|
|
|
655
933
|
);
|
|
656
934
|
}
|
|
657
935
|
function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
|
|
658
|
-
const edge = trailing ?? (shortcut ? /* @__PURE__ */
|
|
659
|
-
return /* @__PURE__ */
|
|
660
|
-
leading && /* @__PURE__ */
|
|
661
|
-
children ?? /* @__PURE__ */
|
|
662
|
-
/* @__PURE__ */
|
|
663
|
-
description && /* @__PURE__ */
|
|
936
|
+
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx17(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx17(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
937
|
+
return /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
938
|
+
leading && /* @__PURE__ */ jsx17("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
939
|
+
children ?? /* @__PURE__ */ jsxs9("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
940
|
+
/* @__PURE__ */ jsx17("span", { className: cn("truncate text-[14px] leading-[140%]", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
941
|
+
description && /* @__PURE__ */ jsx17("span", { className: "truncate text-[12px] leading-[120%] text-text-secondary", children: description })
|
|
664
942
|
] }),
|
|
665
943
|
(edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
|
|
666
944
|
// the wider of the two and never changes, so revealing the hint moves
|
|
667
945
|
// nothing. No transition here either — the hint switches on the same
|
|
668
946
|
// :hover / `selected` as the fill, in the same frame.
|
|
669
|
-
/* @__PURE__ */
|
|
670
|
-
edge && /* @__PURE__ */
|
|
671
|
-
hint && /* @__PURE__ */
|
|
947
|
+
/* @__PURE__ */ jsxs9("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
948
|
+
edge && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
949
|
+
hint && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
|
|
672
950
|
] })
|
|
673
951
|
] });
|
|
674
952
|
}
|
|
675
953
|
function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
676
|
-
const body = /* @__PURE__ */
|
|
954
|
+
const body = /* @__PURE__ */ jsx17(
|
|
677
955
|
MenuItemBody,
|
|
678
956
|
{
|
|
679
957
|
label,
|
|
@@ -691,13 +969,13 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
691
969
|
);
|
|
692
970
|
const rowClassName = menuItemClassName({ size, selected, className });
|
|
693
971
|
if (!useContext(MenuContext)) {
|
|
694
|
-
return /* @__PURE__ */
|
|
972
|
+
return /* @__PURE__ */ jsx17("button", { type: "button", className: rowClassName, ...props, children: body });
|
|
695
973
|
}
|
|
696
|
-
return /* @__PURE__ */
|
|
974
|
+
return /* @__PURE__ */ jsx17(
|
|
697
975
|
BaseMenu.Item,
|
|
698
976
|
{
|
|
699
977
|
nativeButton: true,
|
|
700
|
-
render: /* @__PURE__ */
|
|
978
|
+
render: /* @__PURE__ */ jsx17("button", { type: "button" }),
|
|
701
979
|
className: rowClassName,
|
|
702
980
|
...props,
|
|
703
981
|
children: body
|
|
@@ -705,31 +983,31 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
705
983
|
);
|
|
706
984
|
}
|
|
707
985
|
function EnterHint({ target }) {
|
|
708
|
-
return /* @__PURE__ */
|
|
709
|
-
/* @__PURE__ */
|
|
710
|
-
target && /* @__PURE__ */
|
|
986
|
+
return /* @__PURE__ */ jsxs9("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
987
|
+
/* @__PURE__ */ jsx17(Kbd, { children: "\u21A9 Enter" }),
|
|
988
|
+
target && /* @__PURE__ */ jsx17("span", { className: "text-[9px] font-medium leading-[115%] signal:font-mono signal:text-[9.5px] signal:tracking-[0.04em]", children: target })
|
|
711
989
|
] });
|
|
712
990
|
}
|
|
713
991
|
function MenuSection({ label, children, className }) {
|
|
714
992
|
const inMenu = useContext(MenuContext) !== null;
|
|
715
|
-
const heading = /* @__PURE__ */
|
|
993
|
+
const heading = /* @__PURE__ */ jsx17("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx17(SectionLabel, { className: "text-text-secondary", children: label }) });
|
|
716
994
|
if (!inMenu) {
|
|
717
|
-
return /* @__PURE__ */
|
|
995
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col", children: [
|
|
718
996
|
heading,
|
|
719
997
|
children
|
|
720
998
|
] });
|
|
721
999
|
}
|
|
722
|
-
return /* @__PURE__ */
|
|
723
|
-
/* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ jsxs9(BaseMenu.Group, { className: "flex flex-col", children: [
|
|
1001
|
+
/* @__PURE__ */ jsx17(BaseMenu.GroupLabel, { render: heading }),
|
|
724
1002
|
children
|
|
725
1003
|
] });
|
|
726
1004
|
}
|
|
727
1005
|
function MenuRow({ children, className }) {
|
|
728
|
-
return /* @__PURE__ */
|
|
1006
|
+
return /* @__PURE__ */ jsx17("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
|
|
729
1007
|
}
|
|
730
1008
|
|
|
731
1009
|
// src/ChipInput.tsx
|
|
732
|
-
import { jsx as
|
|
1010
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
733
1011
|
var CHIP_BOX = (
|
|
734
1012
|
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
735
1013
|
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
@@ -740,11 +1018,11 @@ var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
|
740
1018
|
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
741
1019
|
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
742
1020
|
function InputChip({ label, leading, onRemove, className }) {
|
|
743
|
-
return /* @__PURE__ */
|
|
744
|
-
leading && /* @__PURE__ */
|
|
745
|
-
/* @__PURE__ */
|
|
746
|
-
onRemove && /* @__PURE__ */
|
|
747
|
-
|
|
1021
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1022
|
+
leading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1023
|
+
/* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: label }),
|
|
1024
|
+
onRemove && /* @__PURE__ */ jsx18(
|
|
1025
|
+
BaseButton4,
|
|
748
1026
|
{
|
|
749
1027
|
type: "button",
|
|
750
1028
|
onClick: (e) => {
|
|
@@ -753,7 +1031,7 @@ function InputChip({ label, leading, onRemove, className }) {
|
|
|
753
1031
|
},
|
|
754
1032
|
className: CHIP_REMOVE,
|
|
755
1033
|
"aria-label": `Remove ${label}`,
|
|
756
|
-
children: /* @__PURE__ */
|
|
1034
|
+
children: /* @__PURE__ */ jsx18(IconX3, { size: 10, stroke: 1.5 })
|
|
757
1035
|
}
|
|
758
1036
|
)
|
|
759
1037
|
] });
|
|
@@ -769,8 +1047,8 @@ function ChipInput({
|
|
|
769
1047
|
rowLeading,
|
|
770
1048
|
...aria
|
|
771
1049
|
}) {
|
|
772
|
-
const [query, setQuery] =
|
|
773
|
-
const [box, setBox] =
|
|
1050
|
+
const [query, setQuery] = useState3("");
|
|
1051
|
+
const [box, setBox] = useState3(null);
|
|
774
1052
|
const available = useMemo(() => {
|
|
775
1053
|
const chosen = new Set(value.map((o) => o.id));
|
|
776
1054
|
const excluded = new Set(excludeIds);
|
|
@@ -806,7 +1084,7 @@ function ChipInput({
|
|
|
806
1084
|
setQuery("");
|
|
807
1085
|
}
|
|
808
1086
|
}
|
|
809
|
-
return /* @__PURE__ */
|
|
1087
|
+
return /* @__PURE__ */ jsxs10(
|
|
810
1088
|
Combobox.Root,
|
|
811
1089
|
{
|
|
812
1090
|
multiple: true,
|
|
@@ -823,13 +1101,13 @@ function ChipInput({
|
|
|
823
1101
|
filter,
|
|
824
1102
|
itemToStringLabel: (option) => option.label,
|
|
825
1103
|
children: [
|
|
826
|
-
/* @__PURE__ */
|
|
827
|
-
value.map((option) => /* @__PURE__ */
|
|
828
|
-
chipLeading && /* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
830
|
-
/* @__PURE__ */
|
|
1104
|
+
/* @__PURE__ */ jsxs10(Combobox.Chips, { ref: setBox, className: "bg-bg-inset border border-border-default hover:border-border-strong focus-within:border-border-focus focus-within:hover:border-border-focus rounded-lg px-3 py-1.5 flex flex-wrap items-center gap-1.5 transition-colors min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring", children: [
|
|
1105
|
+
value.map((option) => /* @__PURE__ */ jsxs10(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1106
|
+
chipLeading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1107
|
+
/* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: option.label }),
|
|
1108
|
+
/* @__PURE__ */ jsx18(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx18(IconX3, { size: 10, stroke: 1.5 }) })
|
|
831
1109
|
] }, option.id)),
|
|
832
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsx18(
|
|
833
1111
|
Combobox.Input,
|
|
834
1112
|
{
|
|
835
1113
|
autoFocus,
|
|
@@ -841,18 +1119,18 @@ function ChipInput({
|
|
|
841
1119
|
}
|
|
842
1120
|
)
|
|
843
1121
|
] }),
|
|
844
|
-
/* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsx18(Combobox.Portal, { children: /* @__PURE__ */ jsx18(
|
|
845
1123
|
Combobox.Positioner,
|
|
846
1124
|
{
|
|
847
1125
|
anchor: box,
|
|
848
1126
|
sideOffset: GAP3,
|
|
849
1127
|
collisionPadding: VIEWPORT_PAD3,
|
|
850
1128
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
851
|
-
children: /* @__PURE__ */
|
|
1129
|
+
children: /* @__PURE__ */ jsx18(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx18(MenuPanel, {}), children: /* @__PURE__ */ jsx18(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx18(Combobox.List, { children: (option) => /* @__PURE__ */ jsx18(
|
|
852
1130
|
Combobox.Item,
|
|
853
1131
|
{
|
|
854
1132
|
value: option,
|
|
855
|
-
render: /* @__PURE__ */
|
|
1133
|
+
render: /* @__PURE__ */ jsx18(
|
|
856
1134
|
MenuItem,
|
|
857
1135
|
{
|
|
858
1136
|
size: "tall",
|
|
@@ -873,15 +1151,49 @@ function ChipInput({
|
|
|
873
1151
|
var GAP3 = 4;
|
|
874
1152
|
var VIEWPORT_PAD3 = 8;
|
|
875
1153
|
|
|
1154
|
+
// src/InlineChip.tsx
|
|
1155
|
+
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1156
|
+
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";
|
|
1157
|
+
var INLINE_CHIP_TONE_CLASSES = {
|
|
1158
|
+
/** A thing or a place — anything that is not a person. */
|
|
1159
|
+
neutral: "bg-bg-active text-text-primary",
|
|
1160
|
+
/** A person. */
|
|
1161
|
+
person: "bg-accent-muted text-accent-primary",
|
|
1162
|
+
/** A person, called urgently. */
|
|
1163
|
+
urgent: "bg-warning-muted text-warning-default",
|
|
1164
|
+
/**
|
|
1165
|
+
* A reference nobody could resolve — still a mention, just an anonymous one.
|
|
1166
|
+
* Its height is the body line's 19.6px written out, because `1.4em` here is
|
|
1167
|
+
* the caption's em: 16.8px, with the letters 1.8px above the sentence's
|
|
1168
|
+
* baseline. At 19.6px they sit 0.4px off it (measured 2026-09-14; Peek's
|
|
1169
|
+
* copy of this chip still has the 16.8px box).
|
|
1170
|
+
*/
|
|
1171
|
+
quiet: "h-[19.6px] bg-bg-active text-text-muted font-mono text-caption"
|
|
1172
|
+
};
|
|
1173
|
+
function inlineChipClassName(tone, className) {
|
|
1174
|
+
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
1175
|
+
}
|
|
1176
|
+
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
1177
|
+
const body = /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
1178
|
+
icon && /* @__PURE__ */ jsx19("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
1179
|
+
children
|
|
1180
|
+
] });
|
|
1181
|
+
const classes = inlineChipClassName(tone, className);
|
|
1182
|
+
if (href === void 0) {
|
|
1183
|
+
return /* @__PURE__ */ jsx19("span", { className: classes, ...props, children: body });
|
|
1184
|
+
}
|
|
1185
|
+
return /* @__PURE__ */ jsx19("a", { href, className: classes, ...props, children: body });
|
|
1186
|
+
}
|
|
1187
|
+
|
|
876
1188
|
// src/IdentityMenu.tsx
|
|
877
|
-
import { useCallback, useRef } from "react";
|
|
1189
|
+
import { useCallback, useRef as useRef2 } from "react";
|
|
878
1190
|
|
|
879
1191
|
// src/Divider.tsx
|
|
880
|
-
import { jsx as
|
|
1192
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
881
1193
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
882
1194
|
if (label && orientation === "horizontal") {
|
|
883
1195
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
884
|
-
return /* @__PURE__ */
|
|
1196
|
+
return /* @__PURE__ */ jsxs12(
|
|
885
1197
|
"div",
|
|
886
1198
|
{
|
|
887
1199
|
role: "separator",
|
|
@@ -889,14 +1201,14 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
889
1201
|
"aria-label": label,
|
|
890
1202
|
className: cn("flex shrink-0 items-center gap-2 mx-3", className),
|
|
891
1203
|
children: [
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
894
|
-
/* @__PURE__ */
|
|
1204
|
+
/* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
|
|
1205
|
+
/* @__PURE__ */ jsx20("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
|
|
1206
|
+
/* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
|
|
895
1207
|
]
|
|
896
1208
|
}
|
|
897
1209
|
);
|
|
898
1210
|
}
|
|
899
|
-
return /* @__PURE__ */
|
|
1211
|
+
return /* @__PURE__ */ jsx20(
|
|
900
1212
|
"div",
|
|
901
1213
|
{
|
|
902
1214
|
role: "separator",
|
|
@@ -907,27 +1219,27 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
907
1219
|
}
|
|
908
1220
|
|
|
909
1221
|
// src/Person.tsx
|
|
910
|
-
import { jsx as
|
|
1222
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
911
1223
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
912
1224
|
return (
|
|
913
1225
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
914
1226
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
915
1227
|
// row agree by construction.
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
/* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
1228
|
+
/* @__PURE__ */ jsxs13("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
1229
|
+
/* @__PURE__ */ jsx21(Avatar, { name, src: picture, size }),
|
|
1230
|
+
/* @__PURE__ */ jsx21("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
919
1231
|
] })
|
|
920
1232
|
);
|
|
921
1233
|
}
|
|
922
1234
|
|
|
923
1235
|
// src/PersonTrigger.tsx
|
|
924
|
-
import { Button as
|
|
1236
|
+
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
925
1237
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
926
|
-
import { jsx as
|
|
1238
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
927
1239
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
928
1240
|
if (compact) {
|
|
929
|
-
return /* @__PURE__ */
|
|
930
|
-
|
|
1241
|
+
return /* @__PURE__ */ jsx22(
|
|
1242
|
+
BaseButton5,
|
|
931
1243
|
{
|
|
932
1244
|
type: "button",
|
|
933
1245
|
"aria-haspopup": "menu",
|
|
@@ -935,12 +1247,12 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
935
1247
|
"aria-label": props["aria-label"] ?? name ?? fallback,
|
|
936
1248
|
className: cn("cursor-pointer rounded-full", className),
|
|
937
1249
|
...props,
|
|
938
|
-
children: /* @__PURE__ */
|
|
1250
|
+
children: /* @__PURE__ */ jsx22(Avatar, { name, src: picture, size: size ?? 36 })
|
|
939
1251
|
}
|
|
940
1252
|
);
|
|
941
1253
|
}
|
|
942
|
-
return /* @__PURE__ */
|
|
943
|
-
|
|
1254
|
+
return /* @__PURE__ */ jsxs14(
|
|
1255
|
+
BaseButton5,
|
|
944
1256
|
{
|
|
945
1257
|
type: "button",
|
|
946
1258
|
"aria-haspopup": "menu",
|
|
@@ -957,18 +1269,18 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
957
1269
|
),
|
|
958
1270
|
...props,
|
|
959
1271
|
children: [
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
1272
|
+
/* @__PURE__ */ jsx22(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
1273
|
+
/* @__PURE__ */ jsx22(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
962
1274
|
]
|
|
963
1275
|
}
|
|
964
1276
|
);
|
|
965
1277
|
}
|
|
966
1278
|
|
|
967
1279
|
// src/IdentityMenu.tsx
|
|
968
|
-
import { Fragment as
|
|
1280
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
969
1281
|
function IdentityPanel({ className, onClose = () => {
|
|
970
1282
|
}, ...rest }) {
|
|
971
|
-
return /* @__PURE__ */
|
|
1283
|
+
return /* @__PURE__ */ jsx23(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx23(IdentityRows, { ...rest, onClose }) });
|
|
972
1284
|
}
|
|
973
1285
|
function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
|
|
974
1286
|
const act = (action) => () => {
|
|
@@ -976,53 +1288,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
976
1288
|
action();
|
|
977
1289
|
};
|
|
978
1290
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
979
|
-
return /* @__PURE__ */
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
/* @__PURE__ */
|
|
983
|
-
me.email && /* @__PURE__ */
|
|
1291
|
+
return /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
1292
|
+
/* @__PURE__ */ jsxs15(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
1293
|
+
/* @__PURE__ */ jsx23(MenuRow, { children: /* @__PURE__ */ jsx23(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
1294
|
+
/* @__PURE__ */ jsx23(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." }),
|
|
1295
|
+
me.email && /* @__PURE__ */ jsxs15(Note, { children: [
|
|
984
1296
|
me.email,
|
|
985
1297
|
" \xB7 known to Estiva, never published to the relay"
|
|
986
1298
|
] })
|
|
987
1299
|
] }),
|
|
988
|
-
relayUrl && /* @__PURE__ */
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
1300
|
+
relayUrl && /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
1301
|
+
/* @__PURE__ */ jsx23(Divider, { className: "mx-0 my-2" }),
|
|
1302
|
+
/* @__PURE__ */ jsxs15(MenuSection, { label: "Workspace", children: [
|
|
1303
|
+
/* @__PURE__ */ jsx23(MenuRow, { children: /* @__PURE__ */ jsx23("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
1304
|
+
/* @__PURE__ */ jsx23(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
993
1305
|
] })
|
|
994
1306
|
] }),
|
|
995
|
-
appRows && /* @__PURE__ */
|
|
996
|
-
/* @__PURE__ */
|
|
1307
|
+
appRows && /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
1308
|
+
/* @__PURE__ */ jsx23(Divider, { className: "mx-0 my-2" }),
|
|
997
1309
|
appRows
|
|
998
1310
|
] }),
|
|
999
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
1000
|
-
signedIn && idBase && /* @__PURE__ */
|
|
1311
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx23(Divider, { className: "mx-0 my-2" }) : null,
|
|
1312
|
+
signedIn && idBase && /* @__PURE__ */ jsx23(
|
|
1001
1313
|
MenuItem,
|
|
1002
1314
|
{
|
|
1003
1315
|
label: "Edit your profile in Estiva ID",
|
|
1004
1316
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
1005
1317
|
}
|
|
1006
1318
|
),
|
|
1007
|
-
onCopyKey && /* @__PURE__ */
|
|
1008
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
1319
|
+
onCopyKey && /* @__PURE__ */ jsx23(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
1320
|
+
idBase && onSignOut && /* @__PURE__ */ jsx23(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
1009
1321
|
] });
|
|
1010
1322
|
}
|
|
1011
1323
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
1012
|
-
const actions =
|
|
1324
|
+
const actions = useRef2(null);
|
|
1013
1325
|
const close = useCallback(() => actions.current?.close(), []);
|
|
1014
1326
|
return (
|
|
1015
1327
|
/* The wrapper carries the caller's `className` and nothing else. It used
|
|
1016
1328
|
to be `relative`, because the panel was positioned against it; the panel
|
|
1017
1329
|
hangs from the trigger and portals now, so a positioning context here
|
|
1018
1330
|
would only be a lie about what this box does. */
|
|
1019
|
-
/* @__PURE__ */
|
|
1331
|
+
/* @__PURE__ */ jsx23("div", { className, children: /* @__PURE__ */ jsx23(
|
|
1020
1332
|
Menu,
|
|
1021
1333
|
{
|
|
1022
1334
|
align: "right",
|
|
1023
1335
|
actionsRef: actions,
|
|
1024
1336
|
className: "w-72",
|
|
1025
|
-
trigger: /* @__PURE__ */
|
|
1337
|
+
trigger: /* @__PURE__ */ jsx23(
|
|
1026
1338
|
PersonTrigger,
|
|
1027
1339
|
{
|
|
1028
1340
|
name: me.name,
|
|
@@ -1033,7 +1345,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1033
1345
|
"aria-label": compact ? "Account menu" : void 0
|
|
1034
1346
|
}
|
|
1035
1347
|
),
|
|
1036
|
-
children: /* @__PURE__ */
|
|
1348
|
+
children: /* @__PURE__ */ jsx23(
|
|
1037
1349
|
IdentityRows,
|
|
1038
1350
|
{
|
|
1039
1351
|
me,
|
|
@@ -1051,13 +1363,13 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1051
1363
|
);
|
|
1052
1364
|
}
|
|
1053
1365
|
function Note({ children }) {
|
|
1054
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsx23("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
1055
1367
|
}
|
|
1056
1368
|
|
|
1057
1369
|
// src/Field.tsx
|
|
1058
1370
|
import { cloneElement, isValidElement } from "react";
|
|
1059
1371
|
import { Field as BaseField } from "@base-ui/react/field";
|
|
1060
|
-
import { jsx as
|
|
1372
|
+
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1061
1373
|
var LINE_STYLES = {
|
|
1062
1374
|
helper: "text-caption text-text-muted",
|
|
1063
1375
|
warning: "text-caption text-warning-default",
|
|
@@ -1067,30 +1379,30 @@ function Field({ label, required = false, helper, error, children }) {
|
|
|
1067
1379
|
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1068
1380
|
"aria-required": children.props["aria-required"] ?? true
|
|
1069
1381
|
}) : children;
|
|
1070
|
-
return /* @__PURE__ */
|
|
1071
|
-
/* @__PURE__ */
|
|
1382
|
+
return /* @__PURE__ */ jsxs16(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
|
|
1383
|
+
/* @__PURE__ */ jsxs16(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1072
1384
|
label,
|
|
1073
|
-
required && /* @__PURE__ */
|
|
1385
|
+
required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1074
1386
|
] }),
|
|
1075
|
-
/* @__PURE__ */
|
|
1387
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
|
|
1076
1388
|
control,
|
|
1077
|
-
error != null ? /* @__PURE__ */
|
|
1389
|
+
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
|
|
1078
1390
|
] })
|
|
1079
1391
|
] });
|
|
1080
1392
|
}
|
|
1081
1393
|
function FieldLine({ tone = "helper", children, className }) {
|
|
1082
|
-
return /* @__PURE__ */
|
|
1394
|
+
return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1083
1395
|
}
|
|
1084
1396
|
|
|
1085
1397
|
// src/Select.tsx
|
|
1086
1398
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
1087
1399
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
1088
|
-
import { jsx as
|
|
1400
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1089
1401
|
var GAP4 = 4;
|
|
1090
1402
|
var VIEWPORT_PAD4 = 8;
|
|
1091
1403
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
|
|
1092
1404
|
const selected = options.find((o) => o.value === value);
|
|
1093
|
-
return /* @__PURE__ */
|
|
1405
|
+
return /* @__PURE__ */ jsxs17(
|
|
1094
1406
|
BaseSelect.Root,
|
|
1095
1407
|
{
|
|
1096
1408
|
value,
|
|
@@ -1098,7 +1410,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1098
1410
|
disabled,
|
|
1099
1411
|
modal: false,
|
|
1100
1412
|
children: [
|
|
1101
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsxs17(
|
|
1102
1414
|
BaseSelect.Trigger,
|
|
1103
1415
|
{
|
|
1104
1416
|
"aria-label": ariaLabel,
|
|
@@ -1125,20 +1437,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1125
1437
|
className
|
|
1126
1438
|
),
|
|
1127
1439
|
children: [
|
|
1128
|
-
/* @__PURE__ */
|
|
1129
|
-
selected?.leading && /* @__PURE__ */
|
|
1130
|
-
/* @__PURE__ */
|
|
1440
|
+
/* @__PURE__ */ jsxs17("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
1441
|
+
selected?.leading && /* @__PURE__ */ jsx25("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
1442
|
+
/* @__PURE__ */ jsx25(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
|
|
1131
1443
|
] }),
|
|
1132
|
-
/* @__PURE__ */
|
|
1444
|
+
/* @__PURE__ */ jsx25(
|
|
1133
1445
|
BaseSelect.Icon,
|
|
1134
1446
|
{
|
|
1135
|
-
render: /* @__PURE__ */
|
|
1447
|
+
render: /* @__PURE__ */ jsx25(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1136
1448
|
}
|
|
1137
1449
|
)
|
|
1138
1450
|
]
|
|
1139
1451
|
}
|
|
1140
1452
|
),
|
|
1141
|
-
/* @__PURE__ */
|
|
1453
|
+
/* @__PURE__ */ jsx25(BaseSelect.Portal, { children: /* @__PURE__ */ jsx25(
|
|
1142
1454
|
BaseSelect.Positioner,
|
|
1143
1455
|
{
|
|
1144
1456
|
side: "bottom",
|
|
@@ -1147,25 +1459,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1147
1459
|
collisionPadding: VIEWPORT_PAD4,
|
|
1148
1460
|
alignItemWithTrigger: false,
|
|
1149
1461
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1150
|
-
children: /* @__PURE__ */
|
|
1462
|
+
children: /* @__PURE__ */ jsx25(
|
|
1151
1463
|
BaseSelect.Popup,
|
|
1152
1464
|
{
|
|
1153
|
-
render: /* @__PURE__ */
|
|
1465
|
+
render: /* @__PURE__ */ jsx25(MenuPanel, {}),
|
|
1154
1466
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
1155
|
-
children: /* @__PURE__ */
|
|
1467
|
+
children: /* @__PURE__ */ jsx25(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs17(
|
|
1156
1468
|
BaseSelect.Item,
|
|
1157
1469
|
{
|
|
1158
1470
|
value: option.value,
|
|
1159
1471
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
1160
1472
|
children: [
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
option.leading && /* @__PURE__ */
|
|
1163
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsxs17("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1474
|
+
option.leading && /* @__PURE__ */ jsx25("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
1475
|
+
/* @__PURE__ */ jsx25(BaseSelect.ItemText, { className: "truncate text-[14px] leading-[140%] text-text-primary", children: option.label })
|
|
1164
1476
|
] }),
|
|
1165
|
-
/* @__PURE__ */
|
|
1477
|
+
/* @__PURE__ */ jsx25(
|
|
1166
1478
|
BaseSelect.ItemIndicator,
|
|
1167
1479
|
{
|
|
1168
|
-
render: /* @__PURE__ */
|
|
1480
|
+
render: /* @__PURE__ */ jsx25(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1169
1481
|
}
|
|
1170
1482
|
)
|
|
1171
1483
|
]
|
|
@@ -1184,9 +1496,9 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1184
1496
|
// src/TextInput.tsx
|
|
1185
1497
|
import { forwardRef } from "react";
|
|
1186
1498
|
import { Input } from "@base-ui/react/input";
|
|
1187
|
-
import { jsx as
|
|
1499
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
1188
1500
|
var TextInput = forwardRef(function TextInput2({ className, type = "text", ...props }, ref) {
|
|
1189
|
-
return /* @__PURE__ */
|
|
1501
|
+
return /* @__PURE__ */ jsx26(
|
|
1190
1502
|
Input,
|
|
1191
1503
|
{
|
|
1192
1504
|
ref,
|
|
@@ -1207,13 +1519,13 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", ...pr
|
|
|
1207
1519
|
// src/Textarea.tsx
|
|
1208
1520
|
import { forwardRef as forwardRef2 } from "react";
|
|
1209
1521
|
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1210
|
-
import { jsx as
|
|
1522
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1211
1523
|
var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
1212
|
-
return /* @__PURE__ */
|
|
1524
|
+
return /* @__PURE__ */ jsx27(
|
|
1213
1525
|
BaseField2.Control,
|
|
1214
1526
|
{
|
|
1215
1527
|
ref,
|
|
1216
|
-
render: /* @__PURE__ */
|
|
1528
|
+
render: /* @__PURE__ */ jsx27("textarea", {}),
|
|
1217
1529
|
className: cn(
|
|
1218
1530
|
"bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
|
|
1219
1531
|
"text-[14px] leading-[1.4] font-normal text-text-primary placeholder:text-text-muted",
|
|
@@ -1228,27 +1540,27 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
|
1228
1540
|
});
|
|
1229
1541
|
|
|
1230
1542
|
// src/ConfirmDialog.tsx
|
|
1231
|
-
import { useState as
|
|
1543
|
+
import { useState as useState4 } from "react";
|
|
1232
1544
|
|
|
1233
1545
|
// src/DialogShell.tsx
|
|
1234
|
-
import { useRef as
|
|
1546
|
+
import { useRef as useRef3 } from "react";
|
|
1235
1547
|
import { Dialog } from "@base-ui/react/dialog";
|
|
1236
1548
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1237
|
-
import { IconX as
|
|
1238
|
-
import { jsx as
|
|
1549
|
+
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1550
|
+
import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1239
1551
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1240
1552
|
const Parts = alert ? AlertDialog : Dialog;
|
|
1241
|
-
const popupRef =
|
|
1242
|
-
return /* @__PURE__ */
|
|
1553
|
+
const popupRef = useRef3(null);
|
|
1554
|
+
return /* @__PURE__ */ jsx28(
|
|
1243
1555
|
Parts.Root,
|
|
1244
1556
|
{
|
|
1245
1557
|
open: true,
|
|
1246
1558
|
onOpenChange: (open) => {
|
|
1247
1559
|
if (!open) onClose();
|
|
1248
1560
|
},
|
|
1249
|
-
children: /* @__PURE__ */
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1561
|
+
children: /* @__PURE__ */ jsxs18(Parts.Portal, { children: [
|
|
1562
|
+
/* @__PURE__ */ jsx28(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1563
|
+
/* @__PURE__ */ jsx28("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs18(
|
|
1252
1564
|
Parts.Popup,
|
|
1253
1565
|
{
|
|
1254
1566
|
ref: popupRef,
|
|
@@ -1257,16 +1569,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1257
1569
|
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1258
1570
|
style: { width },
|
|
1259
1571
|
children: [
|
|
1260
|
-
/* @__PURE__ */
|
|
1261
|
-
headerContent ?? /* @__PURE__ */
|
|
1262
|
-
/* @__PURE__ */
|
|
1572
|
+
/* @__PURE__ */ jsxs18("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
|
|
1573
|
+
headerContent ?? /* @__PURE__ */ jsx28(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx28("span", {}), children: title }),
|
|
1574
|
+
/* @__PURE__ */ jsx28(
|
|
1263
1575
|
Parts.Close,
|
|
1264
1576
|
{
|
|
1265
|
-
render: /* @__PURE__ */
|
|
1577
|
+
render: /* @__PURE__ */ jsx28(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx28(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1266
1578
|
}
|
|
1267
1579
|
)
|
|
1268
1580
|
] }),
|
|
1269
|
-
bodyMaxHeight ? /* @__PURE__ */
|
|
1581
|
+
bodyMaxHeight ? /* @__PURE__ */ jsx28(
|
|
1270
1582
|
ScrollArea,
|
|
1271
1583
|
{
|
|
1272
1584
|
className: cn(footer != null && "border-b border-border-subtle"),
|
|
@@ -1274,8 +1586,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1274
1586
|
contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
|
|
1275
1587
|
children
|
|
1276
1588
|
}
|
|
1277
|
-
) : /* @__PURE__ */
|
|
1278
|
-
footer != null && /* @__PURE__ */
|
|
1589
|
+
) : /* @__PURE__ */ jsx28("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1590
|
+
footer != null && /* @__PURE__ */ jsx28("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1279
1591
|
]
|
|
1280
1592
|
}
|
|
1281
1593
|
) })
|
|
@@ -1285,9 +1597,9 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1285
1597
|
}
|
|
1286
1598
|
|
|
1287
1599
|
// src/ConfirmDialog.tsx
|
|
1288
|
-
import { Fragment as
|
|
1600
|
+
import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1289
1601
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1290
|
-
const [busy, setBusy] =
|
|
1602
|
+
const [busy, setBusy] = useState4(false);
|
|
1291
1603
|
const confirm = async () => {
|
|
1292
1604
|
setBusy(true);
|
|
1293
1605
|
try {
|
|
@@ -1297,16 +1609,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1297
1609
|
setBusy(false);
|
|
1298
1610
|
}
|
|
1299
1611
|
};
|
|
1300
|
-
return /* @__PURE__ */
|
|
1612
|
+
return /* @__PURE__ */ jsx29(
|
|
1301
1613
|
DialogShell,
|
|
1302
1614
|
{
|
|
1303
1615
|
alert: true,
|
|
1304
1616
|
title,
|
|
1305
1617
|
onClose,
|
|
1306
1618
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
1307
|
-
footer: /* @__PURE__ */
|
|
1308
|
-
/* @__PURE__ */
|
|
1309
|
-
/* @__PURE__ */
|
|
1619
|
+
footer: /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
1620
|
+
/* @__PURE__ */ jsx29(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
1621
|
+
/* @__PURE__ */ jsx29(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
1310
1622
|
] }),
|
|
1311
1623
|
children
|
|
1312
1624
|
}
|
|
@@ -1314,15 +1626,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1314
1626
|
}
|
|
1315
1627
|
|
|
1316
1628
|
// src/EditableText.tsx
|
|
1317
|
-
import { useEffect, useRef as
|
|
1629
|
+
import { useEffect, useRef as useRef4, useState as useState5 } from "react";
|
|
1318
1630
|
import { Field as BaseField3 } from "@base-ui/react/field";
|
|
1319
1631
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
1320
|
-
import { jsx as
|
|
1632
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1321
1633
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
1322
|
-
const [editing, setEditing] =
|
|
1323
|
-
const [draft, setDraft] =
|
|
1324
|
-
const [busy, setBusy] =
|
|
1325
|
-
const fieldRef =
|
|
1634
|
+
const [editing, setEditing] = useState5(false);
|
|
1635
|
+
const [draft, setDraft] = useState5(value);
|
|
1636
|
+
const [busy, setBusy] = useState5(false);
|
|
1637
|
+
const fieldRef = useRef4(null);
|
|
1326
1638
|
useEffect(() => {
|
|
1327
1639
|
if (editing) {
|
|
1328
1640
|
fieldRef.current?.focus();
|
|
@@ -1375,7 +1687,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1375
1687
|
written and never read. Read-only, this is a line of text: whatever
|
|
1376
1688
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
1377
1689
|
*/
|
|
1378
|
-
/* @__PURE__ */
|
|
1690
|
+
/* @__PURE__ */ jsx30(
|
|
1379
1691
|
"div",
|
|
1380
1692
|
{
|
|
1381
1693
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -1385,11 +1697,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1385
1697
|
);
|
|
1386
1698
|
}
|
|
1387
1699
|
if (editing) {
|
|
1388
|
-
return multiline ? /* @__PURE__ */
|
|
1700
|
+
return multiline ? /* @__PURE__ */ jsx30(
|
|
1389
1701
|
BaseField3.Control,
|
|
1390
1702
|
{
|
|
1391
1703
|
ref: fieldRef,
|
|
1392
|
-
render: /* @__PURE__ */
|
|
1704
|
+
render: /* @__PURE__ */ jsx30("textarea", { rows: 4 }),
|
|
1393
1705
|
"aria-label": label,
|
|
1394
1706
|
value: draft,
|
|
1395
1707
|
disabled: busy,
|
|
@@ -1398,7 +1710,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1398
1710
|
onBlur: () => void commit(),
|
|
1399
1711
|
className: fieldClass
|
|
1400
1712
|
}
|
|
1401
|
-
) : /* @__PURE__ */
|
|
1713
|
+
) : /* @__PURE__ */ jsx30(
|
|
1402
1714
|
Input2,
|
|
1403
1715
|
{
|
|
1404
1716
|
ref: fieldRef,
|
|
@@ -1412,7 +1724,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1412
1724
|
}
|
|
1413
1725
|
);
|
|
1414
1726
|
}
|
|
1415
|
-
return /* @__PURE__ */
|
|
1727
|
+
return /* @__PURE__ */ jsx30(
|
|
1416
1728
|
"button",
|
|
1417
1729
|
{
|
|
1418
1730
|
type: "button",
|
|
@@ -1431,40 +1743,59 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1431
1743
|
|
|
1432
1744
|
// src/EmptyState.tsx
|
|
1433
1745
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1434
|
-
import { jsx as
|
|
1746
|
+
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1435
1747
|
function EmptyState({ icon, message, scope = "page", className }) {
|
|
1436
1748
|
if (scope === "section") {
|
|
1437
|
-
return /* @__PURE__ */
|
|
1749
|
+
return /* @__PURE__ */ jsx31("p", { className: cn("text-body-2 text-text-secondary", className), children: message });
|
|
1438
1750
|
}
|
|
1439
|
-
return /* @__PURE__ */
|
|
1440
|
-
/* @__PURE__ */
|
|
1441
|
-
/* @__PURE__ */
|
|
1751
|
+
return /* @__PURE__ */ jsxs20("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
1752
|
+
/* @__PURE__ */ jsx31("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx31(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1753
|
+
/* @__PURE__ */ jsx31("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1442
1754
|
] });
|
|
1443
1755
|
}
|
|
1444
1756
|
|
|
1757
|
+
// src/ProgressBar.tsx
|
|
1758
|
+
import { Progress } from "@base-ui/react/progress";
|
|
1759
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
1760
|
+
var TRACK_CLASSES = {
|
|
1761
|
+
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
1762
|
+
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
1763
|
+
quiet: "h-1 w-full overflow-hidden rounded-full bg-bg-inset"
|
|
1764
|
+
};
|
|
1765
|
+
var INDICATOR_CLASSES = {
|
|
1766
|
+
default: "h-full rounded-full bg-success-default transition-[width]",
|
|
1767
|
+
quiet: "h-full rounded-full bg-success-muted transition-[width] duration-300"
|
|
1768
|
+
};
|
|
1769
|
+
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
1770
|
+
return (
|
|
1771
|
+
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
1772
|
+
/* @__PURE__ */ jsx32(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx32(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx32(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1445
1776
|
// src/Skeleton.tsx
|
|
1446
|
-
import { jsx as
|
|
1777
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1447
1778
|
function SkeletonBar({ className, style }) {
|
|
1448
|
-
return /* @__PURE__ */
|
|
1779
|
+
return /* @__PURE__ */ jsx33("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1449
1780
|
}
|
|
1450
1781
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1451
1782
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1452
|
-
return /* @__PURE__ */
|
|
1453
|
-
/* @__PURE__ */
|
|
1454
|
-
/* @__PURE__ */
|
|
1783
|
+
return /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1784
|
+
/* @__PURE__ */ jsx33(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1785
|
+
/* @__PURE__ */ jsx33(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1455
1786
|
] });
|
|
1456
1787
|
}
|
|
1457
1788
|
function SkeletonList({ rows = 8, className }) {
|
|
1458
|
-
return /* @__PURE__ */
|
|
1789
|
+
return /* @__PURE__ */ jsx33("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx33(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1459
1790
|
}
|
|
1460
1791
|
|
|
1461
1792
|
// src/Breadcrumb.tsx
|
|
1462
|
-
import { Fragment as
|
|
1463
|
-
import { jsx as
|
|
1793
|
+
import { Fragment as Fragment6, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState6 } from "react";
|
|
1794
|
+
import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1464
1795
|
function Breadcrumb({ items, className }) {
|
|
1465
|
-
const navRef =
|
|
1466
|
-
const labelRefs =
|
|
1467
|
-
const [truncated, setTruncated] =
|
|
1796
|
+
const navRef = useRef5(null);
|
|
1797
|
+
const labelRefs = useRef5([]);
|
|
1798
|
+
const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
|
|
1468
1799
|
const measure = useCallback2(() => {
|
|
1469
1800
|
const next = /* @__PURE__ */ new Set();
|
|
1470
1801
|
labelRefs.current.forEach((el, index) => {
|
|
@@ -1472,7 +1803,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1472
1803
|
});
|
|
1473
1804
|
setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
|
|
1474
1805
|
}, []);
|
|
1475
|
-
|
|
1806
|
+
useLayoutEffect2(() => {
|
|
1476
1807
|
measure();
|
|
1477
1808
|
const nav = navRef.current;
|
|
1478
1809
|
if (!nav || typeof ResizeObserver === "undefined") return;
|
|
@@ -1480,7 +1811,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1480
1811
|
observer.observe(nav);
|
|
1481
1812
|
return () => observer.disconnect();
|
|
1482
1813
|
}, [measure, items]);
|
|
1483
|
-
return /* @__PURE__ */
|
|
1814
|
+
return /* @__PURE__ */ jsx34("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-[14px] leading-[140%]", className), children: items.map((item, index) => {
|
|
1484
1815
|
const last = index === items.length - 1;
|
|
1485
1816
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
1486
1817
|
const text = cn(
|
|
@@ -1494,24 +1825,24 @@ function Breadcrumb({ items, className }) {
|
|
|
1494
1825
|
const setLabelRef = (el) => {
|
|
1495
1826
|
labelRefs.current[index] = el;
|
|
1496
1827
|
};
|
|
1497
|
-
const crumb = item.href ? /* @__PURE__ */
|
|
1498
|
-
return /* @__PURE__ */
|
|
1499
|
-
index > 0 && /* @__PURE__ */
|
|
1500
|
-
item.icon && /* @__PURE__ */
|
|
1828
|
+
const crumb = item.href ? /* @__PURE__ */ jsx34("a", { ref: setLabelRef, href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label }) : /* @__PURE__ */ jsx34("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
1829
|
+
return /* @__PURE__ */ jsxs22(Fragment6, { children: [
|
|
1830
|
+
index > 0 && /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
1831
|
+
item.icon && /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
|
|
1501
1832
|
truncated.has(index) ? (
|
|
1502
1833
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
1503
1834
|
// must keep truncating inside it, or wrapping it would widen the
|
|
1504
1835
|
// trail and the tooltip would never be needed again.
|
|
1505
|
-
/* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsx34(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
1506
1837
|
) : crumb
|
|
1507
1838
|
] }, `${item.label}-${index}`);
|
|
1508
1839
|
}) });
|
|
1509
1840
|
}
|
|
1510
1841
|
|
|
1511
1842
|
// src/NavItem.tsx
|
|
1512
|
-
import { jsx as
|
|
1843
|
+
import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1513
1844
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
1514
|
-
return /* @__PURE__ */
|
|
1845
|
+
return /* @__PURE__ */ jsxs23(
|
|
1515
1846
|
"a",
|
|
1516
1847
|
{
|
|
1517
1848
|
href,
|
|
@@ -1526,9 +1857,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
1526
1857
|
),
|
|
1527
1858
|
...props,
|
|
1528
1859
|
children: [
|
|
1529
|
-
icon && /* @__PURE__ */
|
|
1530
|
-
/* @__PURE__ */
|
|
1531
|
-
count ? /* @__PURE__ */
|
|
1860
|
+
icon && /* @__PURE__ */ jsx35("span", { className: "flex shrink-0 items-center", children: icon }),
|
|
1861
|
+
/* @__PURE__ */ jsx35("span", { className: "flex-1 truncate", children: label }),
|
|
1862
|
+
count ? /* @__PURE__ */ jsx35(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx35("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
|
|
1532
1863
|
]
|
|
1533
1864
|
}
|
|
1534
1865
|
);
|
|
@@ -1537,7 +1868,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
1537
1868
|
// src/Popover.tsx
|
|
1538
1869
|
import { useMemo as useMemo2 } from "react";
|
|
1539
1870
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
1540
|
-
import { jsx as
|
|
1871
|
+
import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1541
1872
|
var GAP5 = 4;
|
|
1542
1873
|
var VIEWPORT_PAD5 = 8;
|
|
1543
1874
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
@@ -1546,7 +1877,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1546
1877
|
if (anchor instanceof Element) return anchor;
|
|
1547
1878
|
return { getBoundingClientRect: () => anchor };
|
|
1548
1879
|
}, [anchor]);
|
|
1549
|
-
return /* @__PURE__ */
|
|
1880
|
+
return /* @__PURE__ */ jsxs24(
|
|
1550
1881
|
BasePopover.Root,
|
|
1551
1882
|
{
|
|
1552
1883
|
open,
|
|
@@ -1554,8 +1885,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1554
1885
|
actionsRef,
|
|
1555
1886
|
modal: false,
|
|
1556
1887
|
children: [
|
|
1557
|
-
trigger && /* @__PURE__ */
|
|
1558
|
-
/* @__PURE__ */
|
|
1888
|
+
trigger && /* @__PURE__ */ jsx36(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
1889
|
+
/* @__PURE__ */ jsx36(BasePopover.Portal, { children: /* @__PURE__ */ jsx36(
|
|
1559
1890
|
BasePopover.Positioner,
|
|
1560
1891
|
{
|
|
1561
1892
|
anchor: anchorTarget,
|
|
@@ -1564,15 +1895,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1564
1895
|
sideOffset: GAP5,
|
|
1565
1896
|
collisionPadding: VIEWPORT_PAD5,
|
|
1566
1897
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1567
|
-
children: /* @__PURE__ */
|
|
1898
|
+
children: /* @__PURE__ */ jsx36(
|
|
1568
1899
|
BasePopover.Popup,
|
|
1569
1900
|
{
|
|
1570
1901
|
"aria-label": ariaLabel,
|
|
1571
1902
|
initialFocus: trigger ? void 0 : false,
|
|
1572
1903
|
finalFocus,
|
|
1573
1904
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
1574
|
-
render: /* @__PURE__ */
|
|
1575
|
-
children: /* @__PURE__ */
|
|
1905
|
+
render: /* @__PURE__ */ jsx36(MenuPanel, {}),
|
|
1906
|
+
children: /* @__PURE__ */ jsx36(
|
|
1576
1907
|
ScrollArea,
|
|
1577
1908
|
{
|
|
1578
1909
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
@@ -1591,9 +1922,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1591
1922
|
|
|
1592
1923
|
// src/Toolbar.tsx
|
|
1593
1924
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
1594
|
-
import { jsx as
|
|
1925
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
1595
1926
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
1596
|
-
const strip = /* @__PURE__ */
|
|
1927
|
+
const strip = /* @__PURE__ */ jsx37(
|
|
1597
1928
|
BaseToolbar.Root,
|
|
1598
1929
|
{
|
|
1599
1930
|
"aria-label": ariaLabel,
|
|
@@ -1604,24 +1935,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
1604
1935
|
}
|
|
1605
1936
|
);
|
|
1606
1937
|
if (!surface) return strip;
|
|
1607
|
-
return /* @__PURE__ */
|
|
1938
|
+
return /* @__PURE__ */ jsx37(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
1608
1939
|
}
|
|
1609
1940
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
1610
|
-
return /* @__PURE__ */
|
|
1941
|
+
return /* @__PURE__ */ jsx37(
|
|
1611
1942
|
BaseToolbar.Button,
|
|
1612
1943
|
{
|
|
1613
1944
|
ref,
|
|
1614
1945
|
disabled: disabled || !!disabledReason,
|
|
1615
1946
|
focusableWhenDisabled: true,
|
|
1616
|
-
render: /* @__PURE__ */
|
|
1947
|
+
render: /* @__PURE__ */ jsx37(IconButton, { disabled, disabledReason, ...props })
|
|
1617
1948
|
}
|
|
1618
1949
|
);
|
|
1619
1950
|
}
|
|
1620
1951
|
function ToolbarInput(props) {
|
|
1621
|
-
return /* @__PURE__ */
|
|
1952
|
+
return /* @__PURE__ */ jsx37(BaseToolbar.Input, { render: /* @__PURE__ */ jsx37(TextInput, {}), ...props });
|
|
1622
1953
|
}
|
|
1623
1954
|
function ToolbarSeparator({ className }) {
|
|
1624
|
-
return /* @__PURE__ */
|
|
1955
|
+
return /* @__PURE__ */ jsx37(
|
|
1625
1956
|
BaseToolbar.Separator,
|
|
1626
1957
|
{
|
|
1627
1958
|
orientation: "vertical",
|
|
@@ -1631,9 +1962,9 @@ function ToolbarSeparator({ className }) {
|
|
|
1631
1962
|
}
|
|
1632
1963
|
|
|
1633
1964
|
// src/ReactionPicker.tsx
|
|
1634
|
-
import { jsx as
|
|
1965
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
1635
1966
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
1636
|
-
return /* @__PURE__ */
|
|
1967
|
+
return /* @__PURE__ */ jsx38(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
1637
1968
|
/*
|
|
1638
1969
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
1639
1970
|
would become the toolbar's item and the button inside it would never
|
|
@@ -1643,14 +1974,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
1643
1974
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
1644
1975
|
and both say the meaning rather than the glyph.
|
|
1645
1976
|
*/
|
|
1646
|
-
/* @__PURE__ */
|
|
1977
|
+
/* @__PURE__ */ jsx38(
|
|
1647
1978
|
ToolbarButton,
|
|
1648
1979
|
{
|
|
1649
1980
|
"aria-label": option.label,
|
|
1650
1981
|
tooltip: option.label,
|
|
1651
1982
|
onClick: () => onSelect(option.emoji),
|
|
1652
1983
|
className: "size-7 text-[18px] leading-none",
|
|
1653
|
-
children: /* @__PURE__ */
|
|
1984
|
+
children: /* @__PURE__ */ jsx38("span", { "aria-hidden": "true", children: option.emoji })
|
|
1654
1985
|
},
|
|
1655
1986
|
option.emoji
|
|
1656
1987
|
)
|
|
@@ -1659,23 +1990,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
1659
1990
|
|
|
1660
1991
|
// src/PreviewCard.tsx
|
|
1661
1992
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
1662
|
-
import { jsx as
|
|
1993
|
+
import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1663
1994
|
var GAP6 = 12;
|
|
1664
1995
|
var VIEWPORT_PAD6 = 8;
|
|
1665
1996
|
var OPEN_DELAY2 = 350;
|
|
1666
1997
|
var CLOSE_DELAY = 200;
|
|
1667
1998
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
|
|
1668
|
-
return /* @__PURE__ */
|
|
1669
|
-
/* @__PURE__ */
|
|
1999
|
+
return /* @__PURE__ */ jsxs25(BasePreviewCard.Root, { children: [
|
|
2000
|
+
/* @__PURE__ */ jsx39(
|
|
1670
2001
|
BasePreviewCard.Trigger,
|
|
1671
2002
|
{
|
|
1672
2003
|
delay,
|
|
1673
2004
|
closeDelay,
|
|
1674
|
-
render: /* @__PURE__ */
|
|
2005
|
+
render: /* @__PURE__ */ jsx39("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
1675
2006
|
children
|
|
1676
2007
|
}
|
|
1677
2008
|
),
|
|
1678
|
-
/* @__PURE__ */
|
|
2009
|
+
/* @__PURE__ */ jsx39(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx39(
|
|
1679
2010
|
BasePreviewCard.Positioner,
|
|
1680
2011
|
{
|
|
1681
2012
|
side,
|
|
@@ -1683,12 +2014,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
1683
2014
|
sideOffset: GAP6,
|
|
1684
2015
|
collisionPadding: VIEWPORT_PAD6,
|
|
1685
2016
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1686
|
-
children: /* @__PURE__ */
|
|
2017
|
+
children: /* @__PURE__ */ jsx39(
|
|
1687
2018
|
BasePreviewCard.Popup,
|
|
1688
2019
|
{
|
|
1689
2020
|
className: cn("w-[360px] p-3 outline-none", className),
|
|
1690
|
-
render: /* @__PURE__ */
|
|
1691
|
-
children: /* @__PURE__ */
|
|
2021
|
+
render: /* @__PURE__ */ jsx39(MenuPanel, {}),
|
|
2022
|
+
children: /* @__PURE__ */ jsx39(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3 [&>*]:shrink-0", children: content })
|
|
1692
2023
|
}
|
|
1693
2024
|
)
|
|
1694
2025
|
}
|
|
@@ -1697,15 +2028,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
1697
2028
|
}
|
|
1698
2029
|
|
|
1699
2030
|
// src/Rail.tsx
|
|
1700
|
-
import { jsx as
|
|
2031
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
1701
2032
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
1702
|
-
return /* @__PURE__ */
|
|
2033
|
+
return /* @__PURE__ */ jsx40("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
1703
2034
|
}
|
|
1704
2035
|
|
|
1705
2036
|
// src/RailItem.tsx
|
|
1706
|
-
import { jsx as
|
|
2037
|
+
import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1707
2038
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
1708
|
-
return /* @__PURE__ */
|
|
2039
|
+
return /* @__PURE__ */ jsxs26(
|
|
1709
2040
|
"a",
|
|
1710
2041
|
{
|
|
1711
2042
|
href,
|
|
@@ -1713,14 +2044,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1713
2044
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
1714
2045
|
...props,
|
|
1715
2046
|
children: [
|
|
1716
|
-
/* @__PURE__ */
|
|
2047
|
+
/* @__PURE__ */ jsx41(
|
|
1717
2048
|
"div",
|
|
1718
2049
|
{
|
|
1719
2050
|
className: cn(
|
|
1720
2051
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
1721
2052
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
1722
2053
|
),
|
|
1723
|
-
children: /* @__PURE__ */
|
|
2054
|
+
children: /* @__PURE__ */ jsx41(
|
|
1724
2055
|
"span",
|
|
1725
2056
|
{
|
|
1726
2057
|
className: cn(
|
|
@@ -1732,49 +2063,49 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1732
2063
|
)
|
|
1733
2064
|
}
|
|
1734
2065
|
),
|
|
1735
|
-
/* @__PURE__ */
|
|
2066
|
+
/* @__PURE__ */ jsx41("span", { className: cn("text-center text-[9px] font-medium leading-[115%]", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
1736
2067
|
]
|
|
1737
2068
|
}
|
|
1738
2069
|
);
|
|
1739
2070
|
}
|
|
1740
2071
|
|
|
1741
2072
|
// src/Sidebar.tsx
|
|
1742
|
-
import { jsx as
|
|
2073
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
1743
2074
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
1744
|
-
return /* @__PURE__ */
|
|
2075
|
+
return /* @__PURE__ */ jsx42(
|
|
1745
2076
|
"nav",
|
|
1746
2077
|
{
|
|
1747
2078
|
"aria-label": ariaLabel,
|
|
1748
2079
|
className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
|
|
1749
|
-
children: /* @__PURE__ */
|
|
2080
|
+
children: /* @__PURE__ */ jsx42(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
|
|
1750
2081
|
}
|
|
1751
2082
|
);
|
|
1752
2083
|
}
|
|
1753
2084
|
|
|
1754
2085
|
// src/Property.tsx
|
|
1755
|
-
import { jsx as
|
|
2086
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1756
2087
|
function Property({ label, layout = "row", children, className }) {
|
|
1757
2088
|
if (layout === "stacked") {
|
|
1758
2089
|
return (
|
|
1759
2090
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
1760
2091
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
1761
2092
|
// 6px, and unifying means the bigger, calmer one.
|
|
1762
|
-
/* @__PURE__ */
|
|
1763
|
-
/* @__PURE__ */
|
|
2093
|
+
/* @__PURE__ */ jsxs27("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
2094
|
+
/* @__PURE__ */ jsx43("span", { className: "text-menu uppercase tracking-[0.08em] text-text-secondary", children: label }),
|
|
1764
2095
|
children
|
|
1765
2096
|
] })
|
|
1766
2097
|
);
|
|
1767
2098
|
}
|
|
1768
|
-
return /* @__PURE__ */
|
|
1769
|
-
/* @__PURE__ */
|
|
2099
|
+
return /* @__PURE__ */ jsxs27("div", { className: cn("flex items-center gap-2", className), children: [
|
|
2100
|
+
/* @__PURE__ */ jsx43("span", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
1770
2101
|
children
|
|
1771
2102
|
] });
|
|
1772
2103
|
}
|
|
1773
2104
|
|
|
1774
2105
|
// src/Reaction.tsx
|
|
1775
|
-
import { jsx as
|
|
2106
|
+
import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
1776
2107
|
function Reaction({ emoji, count, pressed = false, className, type, ...props }) {
|
|
1777
|
-
return /* @__PURE__ */
|
|
2108
|
+
return /* @__PURE__ */ jsxs28(
|
|
1778
2109
|
"button",
|
|
1779
2110
|
{
|
|
1780
2111
|
type: type ?? "button",
|
|
@@ -1797,8 +2128,8 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
|
|
|
1797
2128
|
),
|
|
1798
2129
|
...props,
|
|
1799
2130
|
children: [
|
|
1800
|
-
/* @__PURE__ */
|
|
1801
|
-
/* @__PURE__ */
|
|
2131
|
+
/* @__PURE__ */ jsx44("span", { "aria-hidden": "true", className: "shrink-0 text-[16px] leading-none", children: emoji }),
|
|
2132
|
+
/* @__PURE__ */ jsx44("span", { className: "text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tabular-nums", children: count })
|
|
1802
2133
|
]
|
|
1803
2134
|
}
|
|
1804
2135
|
);
|
|
@@ -1807,9 +2138,9 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
|
|
|
1807
2138
|
// src/SearchInput.tsx
|
|
1808
2139
|
import "react";
|
|
1809
2140
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
1810
|
-
import { jsx as
|
|
2141
|
+
import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1811
2142
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
1812
|
-
return /* @__PURE__ */
|
|
2143
|
+
return /* @__PURE__ */ jsxs29(
|
|
1813
2144
|
"div",
|
|
1814
2145
|
{
|
|
1815
2146
|
className: cn(
|
|
@@ -1819,7 +2150,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1819
2150
|
className
|
|
1820
2151
|
),
|
|
1821
2152
|
children: [
|
|
1822
|
-
/* @__PURE__ */
|
|
2153
|
+
/* @__PURE__ */ jsx45(
|
|
1823
2154
|
Input3,
|
|
1824
2155
|
{
|
|
1825
2156
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -1827,7 +2158,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1827
2158
|
...props
|
|
1828
2159
|
}
|
|
1829
2160
|
),
|
|
1830
|
-
shortcut && /* @__PURE__ */
|
|
2161
|
+
shortcut && /* @__PURE__ */ jsx45(Kbd, { children: shortcut })
|
|
1831
2162
|
]
|
|
1832
2163
|
}
|
|
1833
2164
|
);
|
|
@@ -1836,17 +2167,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1836
2167
|
// src/SectionHeader.tsx
|
|
1837
2168
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
1838
2169
|
import { useRender } from "@base-ui/react/use-render";
|
|
1839
|
-
import { Fragment as
|
|
2170
|
+
import { Fragment as Fragment7, jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
1840
2171
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
|
|
1841
2172
|
const titleElement = useRender({
|
|
1842
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
2173
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx46("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx46("span", {})),
|
|
1843
2174
|
props: {
|
|
1844
2175
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
1845
2176
|
// whole row up to the actions is the hit target, as it was when the
|
|
1846
2177
|
// row itself carried the click.
|
|
1847
2178
|
className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
|
|
1848
|
-
children: /* @__PURE__ */
|
|
1849
|
-
chevron && /* @__PURE__ */
|
|
2179
|
+
children: /* @__PURE__ */ jsxs30(Fragment7, { children: [
|
|
2180
|
+
chevron && /* @__PURE__ */ jsx46(
|
|
1850
2181
|
IconChevronRight2,
|
|
1851
2182
|
{
|
|
1852
2183
|
size: 12,
|
|
@@ -1854,11 +2185,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
1854
2185
|
className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
1855
2186
|
}
|
|
1856
2187
|
),
|
|
1857
|
-
/* @__PURE__ */
|
|
2188
|
+
/* @__PURE__ */ jsx46(SectionLabel, { children: title })
|
|
1858
2189
|
] })
|
|
1859
2190
|
}
|
|
1860
2191
|
});
|
|
1861
|
-
return /* @__PURE__ */
|
|
2192
|
+
return /* @__PURE__ */ jsxs30(
|
|
1862
2193
|
"div",
|
|
1863
2194
|
{
|
|
1864
2195
|
className: cn(
|
|
@@ -1871,15 +2202,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
1871
2202
|
),
|
|
1872
2203
|
children: [
|
|
1873
2204
|
titleElement,
|
|
1874
|
-
trailing != null && /* @__PURE__ */
|
|
1875
|
-
actions && actions.length > 0 && /* @__PURE__ */
|
|
2205
|
+
trailing != null && /* @__PURE__ */ jsx46("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
2206
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx46(
|
|
1876
2207
|
"div",
|
|
1877
2208
|
{
|
|
1878
2209
|
className: cn(
|
|
1879
2210
|
"-mr-1 flex shrink-0 items-center gap-1",
|
|
1880
2211
|
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
1881
2212
|
),
|
|
1882
|
-
children: actions.map((action) => /* @__PURE__ */
|
|
2213
|
+
children: actions.map((action) => /* @__PURE__ */ jsx46(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
|
|
1883
2214
|
}
|
|
1884
2215
|
)
|
|
1885
2216
|
]
|
|
@@ -1888,9 +2219,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
1888
2219
|
}
|
|
1889
2220
|
|
|
1890
2221
|
// src/CollapsibleSection.tsx
|
|
1891
|
-
import { useState as
|
|
2222
|
+
import { useState as useState7 } from "react";
|
|
1892
2223
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
1893
|
-
import { jsx as
|
|
2224
|
+
import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
1894
2225
|
var OPEN = "open";
|
|
1895
2226
|
var CLOSED = "closed";
|
|
1896
2227
|
function readStored(key) {
|
|
@@ -1910,21 +2241,21 @@ function writeStored(key, open) {
|
|
|
1910
2241
|
}
|
|
1911
2242
|
}
|
|
1912
2243
|
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, children, className, contentClassName }) {
|
|
1913
|
-
const [openState, setOpenState] =
|
|
2244
|
+
const [openState, setOpenState] = useState7(() => readStored(storageKey) ?? defaultOpen);
|
|
1914
2245
|
const open = openProp ?? openState;
|
|
1915
2246
|
const setOpen = (next) => {
|
|
1916
2247
|
setOpenState(next);
|
|
1917
2248
|
writeStored(storageKey, next);
|
|
1918
2249
|
onOpenChange?.(next);
|
|
1919
2250
|
};
|
|
1920
|
-
return /* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
2251
|
+
return /* @__PURE__ */ jsxs31(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
2252
|
+
/* @__PURE__ */ jsx47(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx47(Collapsible.Trigger, {}) }),
|
|
2253
|
+
/* @__PURE__ */ jsx47(
|
|
1923
2254
|
Collapsible.Panel,
|
|
1924
2255
|
{
|
|
1925
2256
|
hiddenUntilFound: true,
|
|
1926
2257
|
className: "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",
|
|
1927
|
-
children: /* @__PURE__ */
|
|
2258
|
+
children: /* @__PURE__ */ jsx47("div", { className: cn("flex flex-col", contentClassName), children })
|
|
1928
2259
|
}
|
|
1929
2260
|
)
|
|
1930
2261
|
] });
|
|
@@ -1932,9 +2263,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
1932
2263
|
|
|
1933
2264
|
// src/Tabs.tsx
|
|
1934
2265
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
1935
|
-
import { jsx as
|
|
2266
|
+
import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
1936
2267
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
1937
|
-
return /* @__PURE__ */
|
|
2268
|
+
return /* @__PURE__ */ jsx48(
|
|
1938
2269
|
BaseTabs.Root,
|
|
1939
2270
|
{
|
|
1940
2271
|
value: active,
|
|
@@ -1942,14 +2273,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
1942
2273
|
if (details.reason === "none") onChange(value);
|
|
1943
2274
|
},
|
|
1944
2275
|
className,
|
|
1945
|
-
children: /* @__PURE__ */
|
|
2276
|
+
children: /* @__PURE__ */ jsx48(
|
|
1946
2277
|
BaseTabs.List,
|
|
1947
2278
|
{
|
|
1948
2279
|
activateOnFocus: true,
|
|
1949
2280
|
"aria-label": aria["aria-label"],
|
|
1950
2281
|
"aria-labelledby": aria["aria-labelledby"],
|
|
1951
2282
|
className: "flex items-center gap-2",
|
|
1952
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
2283
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs32(
|
|
1953
2284
|
BaseTabs.Tab,
|
|
1954
2285
|
{
|
|
1955
2286
|
value: tab.id,
|
|
@@ -1962,9 +2293,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
1962
2293
|
),
|
|
1963
2294
|
children: [
|
|
1964
2295
|
tab.icon,
|
|
1965
|
-
/* @__PURE__ */
|
|
2296
|
+
/* @__PURE__ */ jsxs32("span", { className: "flex items-baseline", children: [
|
|
1966
2297
|
tab.label,
|
|
1967
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
2298
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx48("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
1968
2299
|
] })
|
|
1969
2300
|
]
|
|
1970
2301
|
},
|
|
@@ -1977,10 +2308,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
1977
2308
|
}
|
|
1978
2309
|
|
|
1979
2310
|
// src/Toast.tsx
|
|
1980
|
-
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo3, useState as
|
|
2311
|
+
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo3, useState as useState8 } from "react";
|
|
1981
2312
|
import { createPortal } from "react-dom";
|
|
1982
|
-
import { IconAlertCircle, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
1983
|
-
import { jsx as
|
|
2313
|
+
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
2314
|
+
import { jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
1984
2315
|
var SURFACE_STYLES = {
|
|
1985
2316
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1986
2317
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
@@ -1992,7 +2323,7 @@ var ICONS = {
|
|
|
1992
2323
|
success: IconCircleCheck,
|
|
1993
2324
|
brand: IconCircleCheck,
|
|
1994
2325
|
neutral: IconCircleCheck,
|
|
1995
|
-
warning:
|
|
2326
|
+
warning: IconAlertCircle2,
|
|
1996
2327
|
error: IconCircleX
|
|
1997
2328
|
};
|
|
1998
2329
|
var ICON_STYLES = {
|
|
@@ -2015,7 +2346,7 @@ var ACTION_BORDER_STYLES = {
|
|
|
2015
2346
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
2016
2347
|
const hasAction = !!(actionLabel && onAction);
|
|
2017
2348
|
const LeadingIcon = ICONS[type];
|
|
2018
|
-
return /* @__PURE__ */
|
|
2349
|
+
return /* @__PURE__ */ jsxs33(
|
|
2019
2350
|
"div",
|
|
2020
2351
|
{
|
|
2021
2352
|
className: cn(
|
|
@@ -2027,11 +2358,11 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
2027
2358
|
className
|
|
2028
2359
|
),
|
|
2029
2360
|
children: [
|
|
2030
|
-
/* @__PURE__ */
|
|
2031
|
-
leadingIcon && /* @__PURE__ */
|
|
2032
|
-
/* @__PURE__ */
|
|
2361
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2362
|
+
leadingIcon && /* @__PURE__ */ jsx49(LeadingIcon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
|
|
2363
|
+
/* @__PURE__ */ jsx49("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
|
|
2033
2364
|
] }),
|
|
2034
|
-
hasAction && /* @__PURE__ */
|
|
2365
|
+
hasAction && /* @__PURE__ */ jsx49(
|
|
2035
2366
|
"button",
|
|
2036
2367
|
{
|
|
2037
2368
|
type: "button",
|
|
@@ -2041,7 +2372,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
2041
2372
|
ACTION_BORDER_STYLES[type],
|
|
2042
2373
|
type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
|
|
2043
2374
|
),
|
|
2044
|
-
children: /* @__PURE__ */
|
|
2375
|
+
children: /* @__PURE__ */ jsx49("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
|
|
2045
2376
|
}
|
|
2046
2377
|
)
|
|
2047
2378
|
]
|
|
@@ -2051,7 +2382,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
2051
2382
|
var ToastContext = createContext2(null);
|
|
2052
2383
|
var toastSeq = 0;
|
|
2053
2384
|
function ToastProvider({ children }) {
|
|
2054
|
-
const [toast, setToast] =
|
|
2385
|
+
const [toast, setToast] = useState8(null);
|
|
2055
2386
|
const showToast = useCallback3((opts) => {
|
|
2056
2387
|
setToast({ ...opts, id: ++toastSeq });
|
|
2057
2388
|
}, []);
|
|
@@ -2068,10 +2399,10 @@ function ToastProvider({ children }) {
|
|
|
2068
2399
|
return () => clearTimeout(timer);
|
|
2069
2400
|
}, [toast]);
|
|
2070
2401
|
const value = useMemo3(() => ({ showToast, dismissToast }), [showToast, dismissToast]);
|
|
2071
|
-
return /* @__PURE__ */
|
|
2402
|
+
return /* @__PURE__ */ jsxs33(ToastContext.Provider, { value, children: [
|
|
2072
2403
|
children,
|
|
2073
2404
|
toast && createPortal(
|
|
2074
|
-
/* @__PURE__ */
|
|
2405
|
+
/* @__PURE__ */ jsx49("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx49(
|
|
2075
2406
|
Toast,
|
|
2076
2407
|
{
|
|
2077
2408
|
className: "pointer-events-auto",
|
|
@@ -2096,11 +2427,13 @@ function useToast() {
|
|
|
2096
2427
|
}
|
|
2097
2428
|
export {
|
|
2098
2429
|
AppShell,
|
|
2430
|
+
AttachmentCard,
|
|
2099
2431
|
Avatar,
|
|
2100
2432
|
AvatarGroup,
|
|
2101
2433
|
Banner,
|
|
2102
2434
|
Breadcrumb,
|
|
2103
2435
|
Button,
|
|
2436
|
+
Card,
|
|
2104
2437
|
Checkbox,
|
|
2105
2438
|
Chip,
|
|
2106
2439
|
ChipInput,
|
|
@@ -2113,11 +2446,15 @@ export {
|
|
|
2113
2446
|
EnterHint,
|
|
2114
2447
|
Field,
|
|
2115
2448
|
FieldLine,
|
|
2449
|
+
INLINE_CHIP_CLASSES,
|
|
2450
|
+
INLINE_CHIP_TONE_CLASSES,
|
|
2116
2451
|
IconButton,
|
|
2117
2452
|
IdentityMenu,
|
|
2118
2453
|
IdentityPanel,
|
|
2454
|
+
InlineChip,
|
|
2119
2455
|
InputChip,
|
|
2120
2456
|
Kbd,
|
|
2457
|
+
Link,
|
|
2121
2458
|
Menu,
|
|
2122
2459
|
MenuItem,
|
|
2123
2460
|
MenuPanel,
|
|
@@ -2129,6 +2466,7 @@ export {
|
|
|
2129
2466
|
PersonTrigger,
|
|
2130
2467
|
Popover,
|
|
2131
2468
|
PreviewCard,
|
|
2469
|
+
ProgressBar,
|
|
2132
2470
|
Property,
|
|
2133
2471
|
Rail,
|
|
2134
2472
|
RailItem,
|
|
@@ -2159,6 +2497,7 @@ export {
|
|
|
2159
2497
|
cn,
|
|
2160
2498
|
hueFor,
|
|
2161
2499
|
initialsFor,
|
|
2500
|
+
inlineChipClassName,
|
|
2162
2501
|
useToast
|
|
2163
2502
|
};
|
|
2164
2503
|
//# sourceMappingURL=index.js.map
|