@estiva-app/ui 0.5.0 → 0.7.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/Divider.d.ts.map +1 -1
- package/dist/IconButton.d.ts +4 -1
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/Kbd.d.ts +27 -0
- package/dist/Kbd.d.ts.map +1 -0
- package/dist/Menu.d.ts +56 -5
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Reaction.d.ts +54 -0
- package/dist/Reaction.d.ts.map +1 -0
- package/dist/SearchInput.d.ts +1 -1
- package/dist/SearchInput.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +8 -2
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -147
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/AppShell.stories.tsx +2 -2
- package/src/Divider.tsx +5 -1
- package/src/IconButton.tsx +5 -1
- package/src/Kbd.mdx +77 -0
- package/src/Kbd.stories.tsx +58 -0
- package/src/Kbd.tsx +42 -0
- package/src/Menu.mdx +8 -1
- package/src/Menu.stories.tsx +1 -1
- package/src/Menu.tsx +112 -18
- package/src/MenuItem.mdx +1 -1
- package/src/MenuItem.stories.tsx +5 -5
- package/src/Reaction.mdx +49 -0
- package/src/Reaction.stories.tsx +49 -0
- package/src/Reaction.tsx +86 -0
- package/src/SearchInput.mdx +2 -2
- package/src/SearchInput.stories.tsx +2 -2
- package/src/SearchInput.tsx +3 -6
- package/src/Tooltip.mdx +9 -0
- package/src/Tooltip.stories.tsx +15 -0
- package/src/Tooltip.tsx +12 -4
- package/src/TopBar.mdx +1 -1
- package/src/TopBar.stories.tsx +2 -2
- package/src/index.ts +3 -1
- package/tailwind-preset.js +9 -1
package/dist/index.js
CHANGED
|
@@ -299,10 +299,27 @@ import { createContext, useCallback, useContext, useEffect, useLayoutEffect, use
|
|
|
299
299
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
300
300
|
import { createPortal } from "react-dom";
|
|
301
301
|
|
|
302
|
-
// src/
|
|
302
|
+
// src/Kbd.tsx
|
|
303
303
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
304
|
-
function
|
|
304
|
+
function Kbd({ children, className }) {
|
|
305
305
|
return /* @__PURE__ */ jsx8(
|
|
306
|
+
"kbd",
|
|
307
|
+
{
|
|
308
|
+
className: cn(
|
|
309
|
+
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-[12px] leading-[120%] font-normal text-text-secondary",
|
|
310
|
+
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-[rgba(255,255,255,.05)] signal:font-mono signal:text-[10px]",
|
|
311
|
+
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-[rgba(255,255,255,.05)] ship:font-mono ship:text-[10px]",
|
|
312
|
+
className
|
|
313
|
+
),
|
|
314
|
+
children
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/SectionLabel.tsx
|
|
320
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
321
|
+
function SectionLabel({ children, className }) {
|
|
322
|
+
return /* @__PURE__ */ jsx9(
|
|
306
323
|
"span",
|
|
307
324
|
{
|
|
308
325
|
className: cn(
|
|
@@ -315,8 +332,18 @@ function SectionLabel({ children, className }) {
|
|
|
315
332
|
}
|
|
316
333
|
|
|
317
334
|
// src/Menu.tsx
|
|
318
|
-
import { jsx as
|
|
335
|
+
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
319
336
|
var MenuHoverContext = createContext(null);
|
|
337
|
+
function MenuPanel({ children, className, ...props }) {
|
|
338
|
+
return /* @__PURE__ */ jsx10(
|
|
339
|
+
"div",
|
|
340
|
+
{
|
|
341
|
+
className: cn("flex flex-col rounded-lg border border-border-default bg-bg-elevated p-2 shadow-lg", className),
|
|
342
|
+
...props,
|
|
343
|
+
children
|
|
344
|
+
}
|
|
345
|
+
);
|
|
346
|
+
}
|
|
320
347
|
function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false, children, className }) {
|
|
321
348
|
const ref = useRef(null);
|
|
322
349
|
const leaveTimer = useRef(void 0);
|
|
@@ -382,14 +409,14 @@ function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false,
|
|
|
382
409
|
// The provisional render: measured by the layout effect, never seen.
|
|
383
410
|
{ left: 0, top: 0, visibility: "hidden" }
|
|
384
411
|
) : void 0;
|
|
385
|
-
const node = /* @__PURE__ */
|
|
386
|
-
|
|
412
|
+
const node = /* @__PURE__ */ jsx10(MenuHoverContext.Provider, { value: { hold, release }, children: /* @__PURE__ */ jsx10(
|
|
413
|
+
MenuPanel,
|
|
387
414
|
{
|
|
388
415
|
ref,
|
|
389
416
|
role: "menu",
|
|
390
417
|
"data-interactive": true,
|
|
391
418
|
className: cn(
|
|
392
|
-
"z-50
|
|
419
|
+
"z-50 min-w-[180px]",
|
|
393
420
|
portalled ? "fixed overflow-y-auto" : "absolute right-0 top-full mt-1",
|
|
394
421
|
className
|
|
395
422
|
),
|
|
@@ -434,15 +461,15 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
434
461
|
);
|
|
435
462
|
}, [open]);
|
|
436
463
|
return /* @__PURE__ */ jsxs5("div", { ref: rowRef, onMouseEnter: enter, onMouseLeave: leave, children: [
|
|
437
|
-
/* @__PURE__ */
|
|
464
|
+
/* @__PURE__ */ jsx10(MenuItem, { label, leading, selected, submenu: true }),
|
|
438
465
|
open && createPortal(
|
|
439
|
-
/* @__PURE__ */
|
|
440
|
-
|
|
466
|
+
/* @__PURE__ */ jsx10(
|
|
467
|
+
MenuPanel,
|
|
441
468
|
{
|
|
442
469
|
ref: panelRef,
|
|
443
470
|
role: "menu",
|
|
444
471
|
"data-interactive": true,
|
|
445
|
-
className: cn("fixed z-50
|
|
472
|
+
className: cn("fixed z-50 w-[160px]", className),
|
|
446
473
|
style: placed ?? { left: 0, top: 0, visibility: "hidden" },
|
|
447
474
|
onMouseEnter: enter,
|
|
448
475
|
onMouseLeave: leave,
|
|
@@ -453,15 +480,29 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
453
480
|
)
|
|
454
481
|
] });
|
|
455
482
|
}
|
|
456
|
-
function MenuItem({ label, children, size = "default", description, leading, trailing, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
457
|
-
const edge = trailing ?? (shortcut ? /* @__PURE__ */
|
|
483
|
+
function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
484
|
+
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx10(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx10(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
458
485
|
return /* @__PURE__ */ jsxs5(
|
|
459
486
|
"button",
|
|
460
487
|
{
|
|
461
488
|
type: "button",
|
|
462
489
|
role: "menuitem",
|
|
463
490
|
className: cn(
|
|
464
|
-
|
|
491
|
+
// shrink-0: a menu is a flex column that scrolls at its max height,
|
|
492
|
+
// and a flex child shrinks before its container does — so every row
|
|
493
|
+
// in an overflowing menu was squashed to its `min-h`, and a row given
|
|
494
|
+
// an explicit height silently lost it (Peek's `[` menu: h-12 rows
|
|
495
|
+
// measured 40px). The same fix NavItem took on 2026-09-02.
|
|
496
|
+
// `group`: the `hint` slot reveals itself from this row's own :hover,
|
|
497
|
+
// so the hint and the fill are one CSS state change, not two engines.
|
|
498
|
+
//
|
|
499
|
+
// No transition on the fill (Katerina, 2026-09-05). It faded over
|
|
500
|
+
// 150ms, and anything appearing with it had to fade too or arrive
|
|
501
|
+
// ahead of it — which, sweeping a pointer down a list, read as the
|
|
502
|
+
// hint flickering in and out. Both are instant now: they still change
|
|
503
|
+
// on exactly the same :hover, so they cannot come apart, and a row
|
|
504
|
+
// lights and unlights crisply as the pointer crosses it.
|
|
505
|
+
"group flex w-full shrink-0 cursor-pointer items-center rounded-lg text-left hover:bg-bg-hover",
|
|
465
506
|
// tall: as tall as its content, never shorter than 40px (Katerina,
|
|
466
507
|
// 2026-09-01) — a single-line picker row sits at 40, a row with a
|
|
467
508
|
// 32px face and a role line comes out at its natural 48. One rule,
|
|
@@ -472,34 +513,41 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
472
513
|
),
|
|
473
514
|
...props,
|
|
474
515
|
children: [
|
|
475
|
-
leading && /* @__PURE__ */
|
|
516
|
+
leading && /* @__PURE__ */ jsx10("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
476
517
|
children ?? /* @__PURE__ */ jsxs5("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
477
|
-
/* @__PURE__ */
|
|
478
|
-
description && /* @__PURE__ */
|
|
518
|
+
/* @__PURE__ */ jsx10("span", { className: cn("truncate text-[14px] leading-[140%]", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
519
|
+
description && /* @__PURE__ */ jsx10("span", { className: "truncate text-[12px] leading-[120%] text-text-secondary", children: description })
|
|
479
520
|
] }),
|
|
480
|
-
edge &&
|
|
521
|
+
(edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
|
|
522
|
+
// the wider of the two and never changes, so revealing the hint moves
|
|
523
|
+
// nothing. No transition here either — the hint switches on the same
|
|
524
|
+
// :hover / `selected` as the fill, in the same frame.
|
|
525
|
+
/* @__PURE__ */ jsxs5("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
526
|
+
edge && /* @__PURE__ */ jsx10("span", { className: cn("flex items-center", hint && "group-hover:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
527
|
+
hint && /* @__PURE__ */ jsx10("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100", selected && "opacity-100"), children: hint })
|
|
528
|
+
] })
|
|
481
529
|
]
|
|
482
530
|
}
|
|
483
531
|
);
|
|
484
532
|
}
|
|
485
|
-
function EnterHint({
|
|
486
|
-
return /* @__PURE__ */ jsxs5("span", { className: "flex shrink-0 items-center gap-
|
|
487
|
-
/* @__PURE__ */
|
|
488
|
-
/* @__PURE__ */
|
|
533
|
+
function EnterHint({ target }) {
|
|
534
|
+
return /* @__PURE__ */ jsxs5("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
535
|
+
/* @__PURE__ */ jsx10(Kbd, { children: "\u21A9 Enter" }),
|
|
536
|
+
target && /* @__PURE__ */ jsx10("span", { className: "text-[9px] font-medium leading-[115%] signal:font-mono signal:text-[9.5px] signal:tracking-[0.04em]", children: target })
|
|
489
537
|
] });
|
|
490
538
|
}
|
|
491
539
|
function MenuSection({ label, children, className }) {
|
|
492
540
|
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col", children: [
|
|
493
|
-
/* @__PURE__ */
|
|
541
|
+
/* @__PURE__ */ jsx10("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx10(SectionLabel, { className: "text-text-secondary", children: label }) }),
|
|
494
542
|
children
|
|
495
543
|
] });
|
|
496
544
|
}
|
|
497
545
|
function MenuRow({ children, className }) {
|
|
498
|
-
return /* @__PURE__ */
|
|
546
|
+
return /* @__PURE__ */ jsx10("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
|
|
499
547
|
}
|
|
500
548
|
|
|
501
549
|
// src/ChipInput.tsx
|
|
502
|
-
import { jsx as
|
|
550
|
+
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
503
551
|
function InputChip({ label, leading, onRemove, className }) {
|
|
504
552
|
return /* @__PURE__ */ jsxs6(
|
|
505
553
|
"div",
|
|
@@ -517,9 +565,9 @@ function InputChip({ label, leading, onRemove, className }) {
|
|
|
517
565
|
className
|
|
518
566
|
),
|
|
519
567
|
children: [
|
|
520
|
-
leading && /* @__PURE__ */
|
|
521
|
-
/* @__PURE__ */
|
|
522
|
-
onRemove && /* @__PURE__ */
|
|
568
|
+
leading && /* @__PURE__ */ jsx11("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
569
|
+
/* @__PURE__ */ jsx11("span", { className: "text-caption font-medium text-text-primary", children: label }),
|
|
570
|
+
onRemove && /* @__PURE__ */ jsx11(
|
|
523
571
|
"button",
|
|
524
572
|
{
|
|
525
573
|
type: "button",
|
|
@@ -529,7 +577,7 @@ function InputChip({ label, leading, onRemove, className }) {
|
|
|
529
577
|
},
|
|
530
578
|
className: "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary",
|
|
531
579
|
"aria-label": `Remove ${label}`,
|
|
532
|
-
children: /* @__PURE__ */
|
|
580
|
+
children: /* @__PURE__ */ jsx11(IconX, { size: 10, stroke: 1.5 })
|
|
533
581
|
}
|
|
534
582
|
)
|
|
535
583
|
]
|
|
@@ -625,8 +673,8 @@ function ChipInput({
|
|
|
625
673
|
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",
|
|
626
674
|
onClick: () => inputRef.current?.focus(),
|
|
627
675
|
children: [
|
|
628
|
-
value.map((o) => /* @__PURE__ */
|
|
629
|
-
/* @__PURE__ */
|
|
676
|
+
value.map((o) => /* @__PURE__ */ jsx11(InputChip, { label: o.label, leading: chipLeading?.(o), onRemove: () => removeOption(o.id) }, o.id)),
|
|
677
|
+
/* @__PURE__ */ jsx11(
|
|
630
678
|
"input",
|
|
631
679
|
{
|
|
632
680
|
ref: inputRef,
|
|
@@ -647,7 +695,7 @@ function ChipInput({
|
|
|
647
695
|
}
|
|
648
696
|
),
|
|
649
697
|
showDropdown && anchorRect && createPortal2(
|
|
650
|
-
/* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsx11(
|
|
651
699
|
"div",
|
|
652
700
|
{
|
|
653
701
|
className: "fixed z-[60] overflow-y-auto bg-bg-elevated border border-border-default rounded-lg shadow-lg",
|
|
@@ -660,7 +708,7 @@ function ChipInput({
|
|
|
660
708
|
}),
|
|
661
709
|
width: anchorRect.width
|
|
662
710
|
},
|
|
663
|
-
children: matches.map((o, i) => /* @__PURE__ */
|
|
711
|
+
children: matches.map((o, i) => /* @__PURE__ */ jsx11(
|
|
664
712
|
MenuItem,
|
|
665
713
|
{
|
|
666
714
|
size: "tall",
|
|
@@ -687,13 +735,16 @@ function ChipInput({
|
|
|
687
735
|
// src/Tooltip.tsx
|
|
688
736
|
import { useCallback as useCallback2, useLayoutEffect as useLayoutEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
689
737
|
import { createPortal as createPortal3 } from "react-dom";
|
|
690
|
-
import { jsx as
|
|
691
|
-
function Tooltip({ label, className }) {
|
|
692
|
-
return /* @__PURE__ */
|
|
738
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
739
|
+
function Tooltip({ label, shortcut, className }) {
|
|
740
|
+
return /* @__PURE__ */ jsxs7("div", { role: "tooltip", className: cn("bg-bg-elevated border border-border-default rounded-lg h-[30px] flex items-center justify-center gap-1.5 px-2 shadow-lg", className), children: [
|
|
741
|
+
/* @__PURE__ */ jsx12("span", { className: "text-caption text-text-primary whitespace-nowrap", children: label }),
|
|
742
|
+
shortcut && /* @__PURE__ */ jsx12(Kbd, { children: shortcut })
|
|
743
|
+
] });
|
|
693
744
|
}
|
|
694
745
|
var GAP2 = 6;
|
|
695
746
|
var VIEWPORT_PAD = 8;
|
|
696
|
-
function WithTooltip({ label, placement = "top", wrapperClassName, children }) {
|
|
747
|
+
function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, children }) {
|
|
697
748
|
const [show, setShow] = useState4(false);
|
|
698
749
|
const ref = useRef3(null);
|
|
699
750
|
const tooltipRef = useRef3(null);
|
|
@@ -718,25 +769,26 @@ function WithTooltip({ label, placement = "top", wrapperClassName, children }) {
|
|
|
718
769
|
return /* @__PURE__ */ jsxs7("div", { ref, className: cn("inline-flex shrink-0", wrapperClassName), onMouseEnter: () => setShow(true), onMouseLeave: () => setShow(false), children: [
|
|
719
770
|
children,
|
|
720
771
|
show && createPortal3(
|
|
721
|
-
/* @__PURE__ */
|
|
772
|
+
/* @__PURE__ */ jsx12("div", { ref: tooltipRef, style, children: /* @__PURE__ */ jsx12(Tooltip, { label, shortcut }) }),
|
|
722
773
|
document.body
|
|
723
774
|
)
|
|
724
775
|
] });
|
|
725
776
|
}
|
|
726
777
|
|
|
727
778
|
// src/IconButton.tsx
|
|
728
|
-
import { jsx as
|
|
779
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
729
780
|
function IconButton({
|
|
730
781
|
variant = "muted",
|
|
731
782
|
className,
|
|
732
783
|
children,
|
|
733
784
|
disabled,
|
|
734
785
|
tooltip,
|
|
786
|
+
tooltipShortcut,
|
|
735
787
|
tooltipPlacement,
|
|
736
788
|
type = "button",
|
|
737
789
|
...props
|
|
738
790
|
}) {
|
|
739
|
-
const button = /* @__PURE__ */
|
|
791
|
+
const button = /* @__PURE__ */ jsx13(
|
|
740
792
|
"button",
|
|
741
793
|
{
|
|
742
794
|
type,
|
|
@@ -757,7 +809,7 @@ function IconButton({
|
|
|
757
809
|
}
|
|
758
810
|
);
|
|
759
811
|
if (tooltip) {
|
|
760
|
-
return /* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsx13(WithTooltip, { label: tooltip, shortcut: tooltipShortcut, placement: tooltipPlacement, children: button });
|
|
761
813
|
}
|
|
762
814
|
return button;
|
|
763
815
|
}
|
|
@@ -766,38 +818,38 @@ function IconButton({
|
|
|
766
818
|
import { useRef as useRef4, useState as useState5 } from "react";
|
|
767
819
|
|
|
768
820
|
// src/Divider.tsx
|
|
769
|
-
import { jsx as
|
|
821
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
770
822
|
function Divider({ orientation = "horizontal", className }) {
|
|
771
|
-
return /* @__PURE__ */
|
|
823
|
+
return /* @__PURE__ */ jsx14(
|
|
772
824
|
"div",
|
|
773
825
|
{
|
|
774
826
|
role: "separator",
|
|
775
827
|
"aria-orientation": orientation,
|
|
776
|
-
className: cn("bg-border-subtle", orientation === "horizontal" ? "h-px mx-3" : "w-px self-stretch
|
|
828
|
+
className: cn("shrink-0 bg-border-subtle", orientation === "horizontal" ? "h-px mx-3" : "w-px self-stretch", className)
|
|
777
829
|
}
|
|
778
830
|
);
|
|
779
831
|
}
|
|
780
832
|
|
|
781
833
|
// src/Person.tsx
|
|
782
|
-
import { jsx as
|
|
834
|
+
import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
783
835
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
784
836
|
return (
|
|
785
837
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
786
838
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
787
839
|
// row agree by construction.
|
|
788
840
|
/* @__PURE__ */ jsxs8("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
789
|
-
/* @__PURE__ */
|
|
790
|
-
/* @__PURE__ */
|
|
841
|
+
/* @__PURE__ */ jsx15(Avatar, { name, src: picture, size }),
|
|
842
|
+
/* @__PURE__ */ jsx15("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
791
843
|
] })
|
|
792
844
|
);
|
|
793
845
|
}
|
|
794
846
|
|
|
795
847
|
// src/PersonTrigger.tsx
|
|
796
848
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
797
|
-
import { jsx as
|
|
849
|
+
import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
798
850
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
799
851
|
if (compact) {
|
|
800
|
-
return /* @__PURE__ */
|
|
852
|
+
return /* @__PURE__ */ jsx16(
|
|
801
853
|
"button",
|
|
802
854
|
{
|
|
803
855
|
type: "button",
|
|
@@ -805,7 +857,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
805
857
|
"aria-expanded": open,
|
|
806
858
|
className: cn("cursor-pointer rounded-full focus:outline-none", className),
|
|
807
859
|
...props,
|
|
808
|
-
children: /* @__PURE__ */
|
|
860
|
+
children: /* @__PURE__ */ jsx16(Avatar, { name, src: picture, size: size ?? 36 })
|
|
809
861
|
}
|
|
810
862
|
);
|
|
811
863
|
}
|
|
@@ -825,15 +877,15 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
825
877
|
),
|
|
826
878
|
...props,
|
|
827
879
|
children: [
|
|
828
|
-
/* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
880
|
+
/* @__PURE__ */ jsx16(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
881
|
+
/* @__PURE__ */ jsx16(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
830
882
|
]
|
|
831
883
|
}
|
|
832
884
|
);
|
|
833
885
|
}
|
|
834
886
|
|
|
835
887
|
// src/IdentityMenu.tsx
|
|
836
|
-
import { Fragment, jsx as
|
|
888
|
+
import { Fragment, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
837
889
|
function IdentityPanel({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, anchor, className, children }) {
|
|
838
890
|
const act = (action) => () => {
|
|
839
891
|
onClose();
|
|
@@ -842,41 +894,41 @@ function IdentityPanel({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, o
|
|
|
842
894
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
843
895
|
return /* @__PURE__ */ jsxs10(Menu, { onClose, anchor, align: "right", className: cn("w-72", className), children: [
|
|
844
896
|
/* @__PURE__ */ jsxs10(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
897
|
+
/* @__PURE__ */ jsx17(MenuRow, { children: /* @__PURE__ */ jsx17(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
898
|
+
/* @__PURE__ */ jsx17(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." }),
|
|
847
899
|
me.email && /* @__PURE__ */ jsxs10(Note, { children: [
|
|
848
900
|
me.email,
|
|
849
901
|
" \xB7 known to Estiva, never published to the relay"
|
|
850
902
|
] })
|
|
851
903
|
] }),
|
|
852
904
|
relayUrl && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
853
|
-
/* @__PURE__ */
|
|
905
|
+
/* @__PURE__ */ jsx17(Divider, { className: "mx-0 my-2" }),
|
|
854
906
|
/* @__PURE__ */ jsxs10(MenuSection, { label: "Workspace", children: [
|
|
855
|
-
/* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
907
|
+
/* @__PURE__ */ jsx17(MenuRow, { children: /* @__PURE__ */ jsx17("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
908
|
+
/* @__PURE__ */ jsx17(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
857
909
|
] })
|
|
858
910
|
] }),
|
|
859
911
|
appRows && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
860
|
-
/* @__PURE__ */
|
|
912
|
+
/* @__PURE__ */ jsx17(Divider, { className: "mx-0 my-2" }),
|
|
861
913
|
appRows
|
|
862
914
|
] }),
|
|
863
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
864
|
-
signedIn && idBase && /* @__PURE__ */
|
|
915
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx17(Divider, { className: "mx-0 my-2" }) : null,
|
|
916
|
+
signedIn && idBase && /* @__PURE__ */ jsx17(
|
|
865
917
|
MenuItem,
|
|
866
918
|
{
|
|
867
919
|
label: "Edit your profile in Estiva ID",
|
|
868
920
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
869
921
|
}
|
|
870
922
|
),
|
|
871
|
-
onCopyKey && /* @__PURE__ */
|
|
872
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
923
|
+
onCopyKey && /* @__PURE__ */ jsx17(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
924
|
+
idBase && onSignOut && /* @__PURE__ */ jsx17(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
873
925
|
] });
|
|
874
926
|
}
|
|
875
927
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
876
928
|
const [open, setOpen] = useState5(false);
|
|
877
929
|
const anchorRef = useRef4(null);
|
|
878
930
|
return /* @__PURE__ */ jsxs10("div", { ref: anchorRef, className: cn("relative", className), children: [
|
|
879
|
-
/* @__PURE__ */
|
|
931
|
+
/* @__PURE__ */ jsx17(
|
|
880
932
|
PersonTrigger,
|
|
881
933
|
{
|
|
882
934
|
name: me.name,
|
|
@@ -890,7 +942,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
890
942
|
"aria-label": compact ? "Account menu" : void 0
|
|
891
943
|
}
|
|
892
944
|
),
|
|
893
|
-
open && /* @__PURE__ */
|
|
945
|
+
open && /* @__PURE__ */ jsx17(
|
|
894
946
|
IdentityPanel,
|
|
895
947
|
{
|
|
896
948
|
me,
|
|
@@ -907,12 +959,12 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
907
959
|
] });
|
|
908
960
|
}
|
|
909
961
|
function Note({ children }) {
|
|
910
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ jsx17("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
911
963
|
}
|
|
912
964
|
|
|
913
965
|
// src/Field.tsx
|
|
914
966
|
import { createContext as createContext2, useContext as useContext2, useId } from "react";
|
|
915
|
-
import { jsx as
|
|
967
|
+
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
916
968
|
var FieldControlIdContext = createContext2(void 0);
|
|
917
969
|
function useFieldControlId(ownId) {
|
|
918
970
|
const fromField = useContext2(FieldControlIdContext);
|
|
@@ -929,11 +981,11 @@ function Field({ label, required = false, htmlFor, children }) {
|
|
|
929
981
|
className: `text-input-label text-text-primary${required ? " flex items-center" : ""}`,
|
|
930
982
|
children: [
|
|
931
983
|
label,
|
|
932
|
-
required && /* @__PURE__ */
|
|
984
|
+
required && /* @__PURE__ */ jsx18("span", { className: "text-error-default ml-0.5", children: "*" })
|
|
933
985
|
]
|
|
934
986
|
}
|
|
935
987
|
),
|
|
936
|
-
/* @__PURE__ */
|
|
988
|
+
/* @__PURE__ */ jsx18(FieldControlIdContext.Provider, { value: id, children })
|
|
937
989
|
] });
|
|
938
990
|
}
|
|
939
991
|
|
|
@@ -941,7 +993,7 @@ function Field({ label, required = false, htmlFor, children }) {
|
|
|
941
993
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
942
994
|
import { useCallback as useCallback3, useEffect as useEffect3, useId as useId2, useLayoutEffect as useLayoutEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState6 } from "react";
|
|
943
995
|
import { createPortal as createPortal4 } from "react-dom";
|
|
944
|
-
import { Fragment as Fragment2, jsx as
|
|
996
|
+
import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
945
997
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className }) {
|
|
946
998
|
const id = useId2();
|
|
947
999
|
const triggerRef = useRef5(null);
|
|
@@ -1081,15 +1133,15 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1081
1133
|
),
|
|
1082
1134
|
children: [
|
|
1083
1135
|
/* @__PURE__ */ jsxs12("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
1084
|
-
selected?.leading && /* @__PURE__ */
|
|
1085
|
-
/* @__PURE__ */
|
|
1136
|
+
selected?.leading && /* @__PURE__ */ jsx19("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
1137
|
+
/* @__PURE__ */ jsx19("span", { className: "truncate", children: selected?.label ?? placeholder })
|
|
1086
1138
|
] }),
|
|
1087
|
-
/* @__PURE__ */
|
|
1139
|
+
/* @__PURE__ */ jsx19(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1088
1140
|
]
|
|
1089
1141
|
}
|
|
1090
1142
|
),
|
|
1091
1143
|
open && rect && createPortal4(
|
|
1092
|
-
/* @__PURE__ */
|
|
1144
|
+
/* @__PURE__ */ jsx19(
|
|
1093
1145
|
"div",
|
|
1094
1146
|
{
|
|
1095
1147
|
ref: menuRef,
|
|
@@ -1122,10 +1174,10 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1122
1174
|
),
|
|
1123
1175
|
children: [
|
|
1124
1176
|
/* @__PURE__ */ jsxs12("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1125
|
-
option.leading && /* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1177
|
+
option.leading && /* @__PURE__ */ jsx19("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
1178
|
+
/* @__PURE__ */ jsx19("span", { className: "truncate", children: option.label })
|
|
1127
1179
|
] }),
|
|
1128
|
-
option.value === value && /* @__PURE__ */
|
|
1180
|
+
option.value === value && /* @__PURE__ */ jsx19(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1129
1181
|
]
|
|
1130
1182
|
},
|
|
1131
1183
|
option.value
|
|
@@ -1139,10 +1191,10 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1139
1191
|
|
|
1140
1192
|
// src/TextInput.tsx
|
|
1141
1193
|
import { forwardRef } from "react";
|
|
1142
|
-
import { jsx as
|
|
1194
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1143
1195
|
var TextInput = forwardRef(function TextInput2({ className, type = "text", id, ...props }, ref) {
|
|
1144
1196
|
const controlId = useFieldControlId(id);
|
|
1145
|
-
return /* @__PURE__ */
|
|
1197
|
+
return /* @__PURE__ */ jsx20(
|
|
1146
1198
|
"input",
|
|
1147
1199
|
{
|
|
1148
1200
|
ref,
|
|
@@ -1163,10 +1215,10 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", id, .
|
|
|
1163
1215
|
|
|
1164
1216
|
// src/Textarea.tsx
|
|
1165
1217
|
import { forwardRef as forwardRef2 } from "react";
|
|
1166
|
-
import { jsx as
|
|
1218
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1167
1219
|
var Textarea = forwardRef2(function Textarea2({ className, id, ...props }, ref) {
|
|
1168
1220
|
const controlId = useFieldControlId(id);
|
|
1169
|
-
return /* @__PURE__ */
|
|
1221
|
+
return /* @__PURE__ */ jsx21(
|
|
1170
1222
|
"textarea",
|
|
1171
1223
|
{
|
|
1172
1224
|
ref,
|
|
@@ -1191,7 +1243,7 @@ import { useState as useState7 } from "react";
|
|
|
1191
1243
|
import { useEffect as useEffect4 } from "react";
|
|
1192
1244
|
import { createPortal as createPortal5 } from "react-dom";
|
|
1193
1245
|
import { IconX as IconX2 } from "@tabler/icons-react";
|
|
1194
|
-
import { Fragment as Fragment3, jsx as
|
|
1246
|
+
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1195
1247
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, width = 502 }) {
|
|
1196
1248
|
useEffect4(() => {
|
|
1197
1249
|
const onKey = (event) => {
|
|
@@ -1202,8 +1254,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1202
1254
|
}, [onClose]);
|
|
1203
1255
|
return createPortal5(
|
|
1204
1256
|
/* @__PURE__ */ jsxs13(Fragment3, { children: [
|
|
1205
|
-
/* @__PURE__ */
|
|
1206
|
-
/* @__PURE__ */
|
|
1257
|
+
/* @__PURE__ */ jsx22("div", { className: "fixed inset-0 z-40 bg-black/50", onClick: onClose }),
|
|
1258
|
+
/* @__PURE__ */ jsx22("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs13(
|
|
1207
1259
|
"div",
|
|
1208
1260
|
{
|
|
1209
1261
|
role: "dialog",
|
|
@@ -1213,11 +1265,11 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1213
1265
|
style: { width },
|
|
1214
1266
|
children: [
|
|
1215
1267
|
/* @__PURE__ */ jsxs13("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
|
|
1216
|
-
headerContent ?? /* @__PURE__ */
|
|
1217
|
-
/* @__PURE__ */
|
|
1268
|
+
headerContent ?? /* @__PURE__ */ jsx22("span", { className: "text-h4 text-text-primary", children: title }),
|
|
1269
|
+
/* @__PURE__ */ jsx22(IconButton, { tooltip: "Close", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx22(IconX2, { size: 16, stroke: 1.5 }) })
|
|
1218
1270
|
] }),
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
footer != null && /* @__PURE__ */
|
|
1271
|
+
/* @__PURE__ */ jsx22("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1272
|
+
footer != null && /* @__PURE__ */ jsx22("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1221
1273
|
]
|
|
1222
1274
|
}
|
|
1223
1275
|
) })
|
|
@@ -1227,7 +1279,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1227
1279
|
}
|
|
1228
1280
|
|
|
1229
1281
|
// src/ConfirmDialog.tsx
|
|
1230
|
-
import { Fragment as Fragment4, jsx as
|
|
1282
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1231
1283
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1232
1284
|
const [busy, setBusy] = useState7(false);
|
|
1233
1285
|
const confirm = async () => {
|
|
@@ -1239,15 +1291,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1239
1291
|
setBusy(false);
|
|
1240
1292
|
}
|
|
1241
1293
|
};
|
|
1242
|
-
return /* @__PURE__ */
|
|
1294
|
+
return /* @__PURE__ */ jsx23(
|
|
1243
1295
|
DialogShell,
|
|
1244
1296
|
{
|
|
1245
1297
|
title,
|
|
1246
1298
|
onClose,
|
|
1247
1299
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
1248
1300
|
footer: /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1249
|
-
/* @__PURE__ */
|
|
1250
|
-
/* @__PURE__ */
|
|
1301
|
+
/* @__PURE__ */ jsx23(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
1302
|
+
/* @__PURE__ */ jsx23(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
1251
1303
|
] }),
|
|
1252
1304
|
children
|
|
1253
1305
|
}
|
|
@@ -1256,7 +1308,7 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1256
1308
|
|
|
1257
1309
|
// src/EditableText.tsx
|
|
1258
1310
|
import { useEffect as useEffect5, useRef as useRef6, useState as useState8 } from "react";
|
|
1259
|
-
import { jsx as
|
|
1311
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1260
1312
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
1261
1313
|
const [editing, setEditing] = useState8(false);
|
|
1262
1314
|
const [draft, setDraft] = useState8(value);
|
|
@@ -1307,7 +1359,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1307
1359
|
className
|
|
1308
1360
|
);
|
|
1309
1361
|
if (readOnly) {
|
|
1310
|
-
return /* @__PURE__ */
|
|
1362
|
+
return /* @__PURE__ */ jsx24(
|
|
1311
1363
|
"div",
|
|
1312
1364
|
{
|
|
1313
1365
|
"aria-label": label,
|
|
@@ -1317,7 +1369,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1317
1369
|
);
|
|
1318
1370
|
}
|
|
1319
1371
|
if (editing) {
|
|
1320
|
-
return multiline ? /* @__PURE__ */
|
|
1372
|
+
return multiline ? /* @__PURE__ */ jsx24(
|
|
1321
1373
|
"textarea",
|
|
1322
1374
|
{
|
|
1323
1375
|
ref: fieldRef,
|
|
@@ -1330,7 +1382,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1330
1382
|
onBlur: () => void commit(),
|
|
1331
1383
|
className: fieldClass
|
|
1332
1384
|
}
|
|
1333
|
-
) : /* @__PURE__ */
|
|
1385
|
+
) : /* @__PURE__ */ jsx24(
|
|
1334
1386
|
"input",
|
|
1335
1387
|
{
|
|
1336
1388
|
ref: fieldRef,
|
|
@@ -1344,7 +1396,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1344
1396
|
}
|
|
1345
1397
|
);
|
|
1346
1398
|
}
|
|
1347
|
-
return /* @__PURE__ */
|
|
1399
|
+
return /* @__PURE__ */ jsx24(
|
|
1348
1400
|
"button",
|
|
1349
1401
|
{
|
|
1350
1402
|
type: "button",
|
|
@@ -1364,33 +1416,33 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1364
1416
|
|
|
1365
1417
|
// src/EmptyState.tsx
|
|
1366
1418
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1367
|
-
import { jsx as
|
|
1419
|
+
import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1368
1420
|
function EmptyState({ icon, message, className }) {
|
|
1369
1421
|
return /* @__PURE__ */ jsxs15("div", { className: cn("flex flex-col gap-2 items-center", className), children: [
|
|
1370
|
-
/* @__PURE__ */
|
|
1371
|
-
/* @__PURE__ */
|
|
1422
|
+
/* @__PURE__ */ jsx25("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx25(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1423
|
+
/* @__PURE__ */ jsx25("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1372
1424
|
] });
|
|
1373
1425
|
}
|
|
1374
1426
|
|
|
1375
1427
|
// src/Skeleton.tsx
|
|
1376
|
-
import { jsx as
|
|
1428
|
+
import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1377
1429
|
function SkeletonBar({ className, style }) {
|
|
1378
|
-
return /* @__PURE__ */
|
|
1430
|
+
return /* @__PURE__ */ jsx26("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1379
1431
|
}
|
|
1380
1432
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1381
1433
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1382
1434
|
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1383
|
-
/* @__PURE__ */
|
|
1384
|
-
/* @__PURE__ */
|
|
1435
|
+
/* @__PURE__ */ jsx26(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1436
|
+
/* @__PURE__ */ jsx26(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1385
1437
|
] });
|
|
1386
1438
|
}
|
|
1387
1439
|
function SkeletonList({ rows = 8, className }) {
|
|
1388
|
-
return /* @__PURE__ */
|
|
1440
|
+
return /* @__PURE__ */ jsx26("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx26(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1389
1441
|
}
|
|
1390
1442
|
|
|
1391
1443
|
// src/Breadcrumb.tsx
|
|
1392
1444
|
import { Fragment as Fragment5, useCallback as useCallback4, useLayoutEffect as useLayoutEffect5, useRef as useRef7, useState as useState9 } from "react";
|
|
1393
|
-
import { jsx as
|
|
1445
|
+
import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1394
1446
|
function Breadcrumb({ items, className }) {
|
|
1395
1447
|
const navRef = useRef7(null);
|
|
1396
1448
|
const labelRefs = useRef7([]);
|
|
@@ -1410,7 +1462,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1410
1462
|
observer.observe(nav);
|
|
1411
1463
|
return () => observer.disconnect();
|
|
1412
1464
|
}, [measure, items]);
|
|
1413
|
-
return /* @__PURE__ */
|
|
1465
|
+
return /* @__PURE__ */ jsx27("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) => {
|
|
1414
1466
|
const last = index === items.length - 1;
|
|
1415
1467
|
const text = cn(
|
|
1416
1468
|
"truncate",
|
|
@@ -1423,21 +1475,21 @@ function Breadcrumb({ items, className }) {
|
|
|
1423
1475
|
const setLabelRef = (el) => {
|
|
1424
1476
|
labelRefs.current[index] = el;
|
|
1425
1477
|
};
|
|
1426
|
-
const crumb = item.href ? /* @__PURE__ */
|
|
1478
|
+
const crumb = item.href ? /* @__PURE__ */ jsx27("a", { ref: setLabelRef, href: item.href, className: cn(text, "hover:text-text-primary"), children: item.label }) : /* @__PURE__ */ jsx27("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
1427
1479
|
return /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
1428
|
-
index > 0 && /* @__PURE__ */
|
|
1480
|
+
index > 0 && /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
1429
1481
|
truncated.has(index) ? (
|
|
1430
1482
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
1431
1483
|
// must keep truncating inside it, or wrapping it would widen the
|
|
1432
1484
|
// trail and the tooltip would never be needed again.
|
|
1433
|
-
/* @__PURE__ */
|
|
1485
|
+
/* @__PURE__ */ jsx27(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
1434
1486
|
) : crumb
|
|
1435
1487
|
] }, `${item.label}-${index}`);
|
|
1436
1488
|
}) });
|
|
1437
1489
|
}
|
|
1438
1490
|
|
|
1439
1491
|
// src/NavItem.tsx
|
|
1440
|
-
import { jsx as
|
|
1492
|
+
import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1441
1493
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
1442
1494
|
return /* @__PURE__ */ jsxs18(
|
|
1443
1495
|
"a",
|
|
@@ -1454,22 +1506,22 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
1454
1506
|
),
|
|
1455
1507
|
...props,
|
|
1456
1508
|
children: [
|
|
1457
|
-
icon && /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
count ? /* @__PURE__ */
|
|
1509
|
+
icon && /* @__PURE__ */ jsx28("span", { className: "flex shrink-0 items-center", children: icon }),
|
|
1510
|
+
/* @__PURE__ */ jsx28("span", { className: "flex-1 truncate", children: label }),
|
|
1511
|
+
count ? /* @__PURE__ */ jsx28(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx28("span", { className: "shrink-0 font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
|
|
1460
1512
|
]
|
|
1461
1513
|
}
|
|
1462
1514
|
);
|
|
1463
1515
|
}
|
|
1464
1516
|
|
|
1465
1517
|
// src/Rail.tsx
|
|
1466
|
-
import { jsx as
|
|
1518
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1467
1519
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
1468
|
-
return /* @__PURE__ */
|
|
1520
|
+
return /* @__PURE__ */ jsx29("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
1469
1521
|
}
|
|
1470
1522
|
|
|
1471
1523
|
// src/RailItem.tsx
|
|
1472
|
-
import { jsx as
|
|
1524
|
+
import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1473
1525
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
1474
1526
|
return /* @__PURE__ */ jsxs19(
|
|
1475
1527
|
"a",
|
|
@@ -1479,14 +1531,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1479
1531
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
1480
1532
|
...props,
|
|
1481
1533
|
children: [
|
|
1482
|
-
/* @__PURE__ */
|
|
1534
|
+
/* @__PURE__ */ jsx30(
|
|
1483
1535
|
"div",
|
|
1484
1536
|
{
|
|
1485
1537
|
className: cn(
|
|
1486
1538
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
1487
1539
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
1488
1540
|
),
|
|
1489
|
-
children: /* @__PURE__ */
|
|
1541
|
+
children: /* @__PURE__ */ jsx30(
|
|
1490
1542
|
"span",
|
|
1491
1543
|
{
|
|
1492
1544
|
className: cn(
|
|
@@ -1498,16 +1550,16 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1498
1550
|
)
|
|
1499
1551
|
}
|
|
1500
1552
|
),
|
|
1501
|
-
/* @__PURE__ */
|
|
1553
|
+
/* @__PURE__ */ jsx30("span", { className: cn("text-center text-[9px] font-medium leading-[115%]", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
1502
1554
|
]
|
|
1503
1555
|
}
|
|
1504
1556
|
);
|
|
1505
1557
|
}
|
|
1506
1558
|
|
|
1507
1559
|
// src/Sidebar.tsx
|
|
1508
|
-
import { jsx as
|
|
1560
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1509
1561
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
1510
|
-
return /* @__PURE__ */
|
|
1562
|
+
return /* @__PURE__ */ jsx31(
|
|
1511
1563
|
"nav",
|
|
1512
1564
|
{
|
|
1513
1565
|
"aria-label": ariaLabel,
|
|
@@ -1521,7 +1573,7 @@ function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className })
|
|
|
1521
1573
|
}
|
|
1522
1574
|
|
|
1523
1575
|
// src/Property.tsx
|
|
1524
|
-
import { jsx as
|
|
1576
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1525
1577
|
function Property({ label, layout = "row", children, className }) {
|
|
1526
1578
|
if (layout === "stacked") {
|
|
1527
1579
|
return (
|
|
@@ -1529,22 +1581,48 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
1529
1581
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
1530
1582
|
// 6px, and unifying means the bigger, calmer one.
|
|
1531
1583
|
/* @__PURE__ */ jsxs20("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
1532
|
-
/* @__PURE__ */
|
|
1584
|
+
/* @__PURE__ */ jsx32("span", { className: "text-menu uppercase tracking-[0.08em] text-text-secondary", children: label }),
|
|
1533
1585
|
children
|
|
1534
1586
|
] })
|
|
1535
1587
|
);
|
|
1536
1588
|
}
|
|
1537
1589
|
return /* @__PURE__ */ jsxs20("div", { className: cn("flex items-center gap-2", className), children: [
|
|
1538
|
-
/* @__PURE__ */
|
|
1590
|
+
/* @__PURE__ */ jsx32("span", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
1539
1591
|
children
|
|
1540
1592
|
] });
|
|
1541
1593
|
}
|
|
1542
1594
|
|
|
1595
|
+
// src/Reaction.tsx
|
|
1596
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1597
|
+
function Reaction({ emoji, count, pressed = false, className, type, ...props }) {
|
|
1598
|
+
return /* @__PURE__ */ jsxs21(
|
|
1599
|
+
"button",
|
|
1600
|
+
{
|
|
1601
|
+
type: type ?? "button",
|
|
1602
|
+
"aria-pressed": pressed,
|
|
1603
|
+
className: cn(
|
|
1604
|
+
// Chip's pill at a control's height, so a reaction and a status chip
|
|
1605
|
+
// read as the same family — 24px matches Button `small`.
|
|
1606
|
+
"inline-flex h-6 items-center justify-center gap-1.5 rounded-full px-2",
|
|
1607
|
+
"border transition-colors",
|
|
1608
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1609
|
+
pressed ? "border-accent-primary bg-accent-muted text-accent-primary hover:border-accent-hover" : "border-border-default bg-bg-inset text-text-primary hover:border-border-strong hover:bg-bg-hover",
|
|
1610
|
+
className
|
|
1611
|
+
),
|
|
1612
|
+
...props,
|
|
1613
|
+
children: [
|
|
1614
|
+
/* @__PURE__ */ jsx33("span", { "aria-hidden": "true", className: "shrink-0 text-[16px] leading-none", children: emoji }),
|
|
1615
|
+
/* @__PURE__ */ jsx33("span", { className: "text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tabular-nums", children: count })
|
|
1616
|
+
]
|
|
1617
|
+
}
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1543
1621
|
// src/SearchInput.tsx
|
|
1544
1622
|
import "react";
|
|
1545
|
-
import { jsx as
|
|
1623
|
+
import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1546
1624
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
1547
|
-
return /* @__PURE__ */
|
|
1625
|
+
return /* @__PURE__ */ jsxs22(
|
|
1548
1626
|
"div",
|
|
1549
1627
|
{
|
|
1550
1628
|
className: cn(
|
|
@@ -1554,7 +1632,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1554
1632
|
className
|
|
1555
1633
|
),
|
|
1556
1634
|
children: [
|
|
1557
|
-
/* @__PURE__ */
|
|
1635
|
+
/* @__PURE__ */ jsx34(
|
|
1558
1636
|
"input",
|
|
1559
1637
|
{
|
|
1560
1638
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -1562,7 +1640,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1562
1640
|
...props
|
|
1563
1641
|
}
|
|
1564
1642
|
),
|
|
1565
|
-
shortcut && /* @__PURE__ */
|
|
1643
|
+
shortcut && /* @__PURE__ */ jsx34(Kbd, { children: shortcut })
|
|
1566
1644
|
]
|
|
1567
1645
|
}
|
|
1568
1646
|
);
|
|
@@ -1571,10 +1649,10 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1571
1649
|
// src/SectionHeader.tsx
|
|
1572
1650
|
import { useState as useState10 } from "react";
|
|
1573
1651
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
1574
|
-
import { jsx as
|
|
1652
|
+
import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1575
1653
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", className }) {
|
|
1576
1654
|
const [isHovered, setIsHovered] = useState10(false);
|
|
1577
|
-
return /* @__PURE__ */
|
|
1655
|
+
return /* @__PURE__ */ jsxs23(
|
|
1578
1656
|
"div",
|
|
1579
1657
|
{
|
|
1580
1658
|
className: cn(
|
|
@@ -1587,8 +1665,8 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1587
1665
|
onMouseEnter: () => setIsHovered(true),
|
|
1588
1666
|
onMouseLeave: () => setIsHovered(false),
|
|
1589
1667
|
children: [
|
|
1590
|
-
/* @__PURE__ */
|
|
1591
|
-
chevron && /* @__PURE__ */
|
|
1668
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1669
|
+
chevron && /* @__PURE__ */ jsx35(
|
|
1592
1670
|
IconChevronRight2,
|
|
1593
1671
|
{
|
|
1594
1672
|
size: 12,
|
|
@@ -1596,9 +1674,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1596
1674
|
className: cn("text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
1597
1675
|
}
|
|
1598
1676
|
),
|
|
1599
|
-
/* @__PURE__ */
|
|
1677
|
+
/* @__PURE__ */ jsx35(SectionLabel, { children: title })
|
|
1600
1678
|
] }),
|
|
1601
|
-
(showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */
|
|
1679
|
+
(showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */ jsx35("div", { className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ jsx35(
|
|
1602
1680
|
IconButton,
|
|
1603
1681
|
{
|
|
1604
1682
|
tooltip: action.tooltip,
|
|
@@ -1617,9 +1695,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1617
1695
|
}
|
|
1618
1696
|
|
|
1619
1697
|
// src/Tabs.tsx
|
|
1620
|
-
import { jsx as
|
|
1698
|
+
import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1621
1699
|
function Tabs({ tabs, active, onChange, size = "default", className }) {
|
|
1622
|
-
return /* @__PURE__ */
|
|
1700
|
+
return /* @__PURE__ */ jsx36("div", { role: "tablist", className: cn("flex items-center gap-2", className), children: tabs.map((tab) => /* @__PURE__ */ jsxs24(
|
|
1623
1701
|
"button",
|
|
1624
1702
|
{
|
|
1625
1703
|
type: "button",
|
|
@@ -1638,9 +1716,9 @@ function Tabs({ tabs, active, onChange, size = "default", className }) {
|
|
|
1638
1716
|
),
|
|
1639
1717
|
children: [
|
|
1640
1718
|
tab.icon,
|
|
1641
|
-
/* @__PURE__ */
|
|
1719
|
+
/* @__PURE__ */ jsxs24("span", { className: "flex items-baseline", children: [
|
|
1642
1720
|
tab.label,
|
|
1643
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
1721
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx36("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
1644
1722
|
] })
|
|
1645
1723
|
]
|
|
1646
1724
|
},
|
|
@@ -1652,7 +1730,7 @@ function Tabs({ tabs, active, onChange, size = "default", className }) {
|
|
|
1652
1730
|
import { createContext as createContext3, useCallback as useCallback5, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo3, useState as useState11 } from "react";
|
|
1653
1731
|
import { createPortal as createPortal6 } from "react-dom";
|
|
1654
1732
|
import { IconCircleCheck } from "@tabler/icons-react";
|
|
1655
|
-
import { jsx as
|
|
1733
|
+
import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1656
1734
|
var SURFACE_BY_TYPE = {
|
|
1657
1735
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1658
1736
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
@@ -1670,7 +1748,7 @@ var ACTION_BORDER_BY_TYPE = {
|
|
|
1670
1748
|
};
|
|
1671
1749
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
1672
1750
|
const hasAction = !!(actionLabel && onAction);
|
|
1673
|
-
return /* @__PURE__ */
|
|
1751
|
+
return /* @__PURE__ */ jsxs25(
|
|
1674
1752
|
"div",
|
|
1675
1753
|
{
|
|
1676
1754
|
className: cn(
|
|
@@ -1682,11 +1760,11 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
1682
1760
|
className
|
|
1683
1761
|
),
|
|
1684
1762
|
children: [
|
|
1685
|
-
/* @__PURE__ */
|
|
1686
|
-
leadingIcon && /* @__PURE__ */
|
|
1687
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
1764
|
+
leadingIcon && /* @__PURE__ */ jsx37(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_BY_TYPE[type]) }),
|
|
1765
|
+
/* @__PURE__ */ jsx37("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
|
|
1688
1766
|
] }),
|
|
1689
|
-
hasAction && /* @__PURE__ */
|
|
1767
|
+
hasAction && /* @__PURE__ */ jsx37(
|
|
1690
1768
|
"button",
|
|
1691
1769
|
{
|
|
1692
1770
|
type: "button",
|
|
@@ -1696,7 +1774,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
1696
1774
|
ACTION_BORDER_BY_TYPE[type],
|
|
1697
1775
|
type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
|
|
1698
1776
|
),
|
|
1699
|
-
children: /* @__PURE__ */
|
|
1777
|
+
children: /* @__PURE__ */ jsx37("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
|
|
1700
1778
|
}
|
|
1701
1779
|
)
|
|
1702
1780
|
]
|
|
@@ -1723,10 +1801,10 @@ function ToastProvider({ children }) {
|
|
|
1723
1801
|
return () => clearTimeout(timer);
|
|
1724
1802
|
}, [toast]);
|
|
1725
1803
|
const value = useMemo3(() => ({ showToast, dismissToast }), [showToast, dismissToast]);
|
|
1726
|
-
return /* @__PURE__ */
|
|
1804
|
+
return /* @__PURE__ */ jsxs25(ToastContext.Provider, { value, children: [
|
|
1727
1805
|
children,
|
|
1728
1806
|
toast && createPortal6(
|
|
1729
|
-
/* @__PURE__ */
|
|
1807
|
+
/* @__PURE__ */ jsx37("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx37(
|
|
1730
1808
|
Toast,
|
|
1731
1809
|
{
|
|
1732
1810
|
className: "pointer-events-auto",
|
|
@@ -1770,8 +1848,10 @@ export {
|
|
|
1770
1848
|
IdentityMenu,
|
|
1771
1849
|
IdentityPanel,
|
|
1772
1850
|
InputChip,
|
|
1851
|
+
Kbd,
|
|
1773
1852
|
Menu,
|
|
1774
1853
|
MenuItem,
|
|
1854
|
+
MenuPanel,
|
|
1775
1855
|
MenuRow,
|
|
1776
1856
|
MenuSection,
|
|
1777
1857
|
MenuSub,
|
|
@@ -1781,6 +1861,7 @@ export {
|
|
|
1781
1861
|
Property,
|
|
1782
1862
|
Rail,
|
|
1783
1863
|
RailItem,
|
|
1864
|
+
Reaction,
|
|
1784
1865
|
SearchInput,
|
|
1785
1866
|
SectionHeader,
|
|
1786
1867
|
SectionLabel,
|