@estiva-app/ui 0.57.4 → 0.59.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/CommandPalette.d.ts.map +1 -1
- package/dist/ComposerTriggers.d.ts +13 -1
- package/dist/ComposerTriggers.d.ts.map +1 -1
- package/dist/ContainerHeader.d.ts.map +1 -1
- package/dist/DialogShell.d.ts.map +1 -1
- package/dist/Kbd.d.ts.map +1 -1
- package/dist/MembersDialog.d.ts +57 -0
- package/dist/MembersDialog.d.ts.map +1 -0
- package/dist/MembersPill.d.ts +22 -0
- package/dist/MembersPill.d.ts.map +1 -0
- package/dist/NavItem.d.ts.map +1 -1
- package/dist/SectionHeader.d.ts +7 -1
- package/dist/SectionHeader.d.ts.map +1 -1
- package/dist/ShowMore.d.ts +27 -0
- package/dist/ShowMore.d.ts.map +1 -0
- package/dist/Tabs.d.ts +2 -0
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/editor.js +4 -4
- package/dist/editor.js.map +2 -2
- package/dist/eslint/index.js +1 -0
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-restyled-part.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1150 -994
- package/dist/index.js.map +4 -4
- package/dist/looks.d.ts +4 -0
- package/dist/looks.d.ts.map +1 -1
- package/package.json +1 -1
- package/registry.json +212 -8
- package/src/CommandPalette.tsx +2 -1
- package/src/ComposerTriggers.mdx +7 -0
- package/src/ComposerTriggers.stories.tsx +43 -4
- package/src/ComposerTriggers.test.tsx +33 -0
- package/src/ComposerTriggers.tsx +17 -5
- package/src/ContainerHeader.mdx +1 -1
- package/src/ContainerHeader.tsx +3 -2
- package/src/DialogShell.tsx +2 -0
- package/src/Kbd.tsx +4 -2
- package/src/ListColumn.mdx +1 -1
- package/src/MembersDialog.mdx +69 -0
- package/src/MembersDialog.stories.tsx +68 -0
- package/src/MembersDialog.test.tsx +69 -0
- package/src/MembersDialog.tsx +184 -0
- package/src/MembersPill.mdx +45 -0
- package/src/MembersPill.stories.tsx +38 -0
- package/src/MembersPill.tsx +35 -0
- package/src/NavItem.tsx +3 -2
- package/src/SectionHeader.mdx +6 -4
- package/src/SectionHeader.stories.tsx +7 -2
- package/src/SectionHeader.test.tsx +6 -0
- package/src/SectionHeader.tsx +10 -2
- package/src/ShowMore.mdx +62 -0
- package/src/ShowMore.stories.tsx +39 -0
- package/src/ShowMore.test.tsx +44 -0
- package/src/ShowMore.tsx +63 -0
- package/src/Tabs.mdx +5 -0
- package/src/Tabs.stories.tsx +15 -0
- package/src/Tabs.test.tsx +8 -0
- package/src/Tabs.tsx +12 -0
- package/src/eslint/no-restyled-part.ts +1 -0
- package/src/index.ts +3 -0
- package/src/looks.ts +6 -0
- package/src/registry/registry.test.ts +4 -4
- package/stories/Choosing.mdx +4 -1
package/dist/index.js
CHANGED
|
@@ -287,7 +287,9 @@ var FIELD_SIZE_CLASSES = {
|
|
|
287
287
|
};
|
|
288
288
|
var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong rounded-lg transition-colors";
|
|
289
289
|
var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
|
|
290
|
+
var COUNT_TEXT_CLASSES = "font-mono text-caption tabular-nums text-text-muted";
|
|
290
291
|
var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
|
|
292
|
+
var MONO_CAPTION_CLASSES = "text-caption text-text-secondary signal:font-mono signal:text-small";
|
|
291
293
|
var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
|
|
292
294
|
var SIDEBAR_ROW_CLASSES = "rounded-lg transition-colors";
|
|
293
295
|
var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
|
|
@@ -312,8 +314,9 @@ function Kbd({ children, className, tone = "default" }) {
|
|
|
312
314
|
"kbd",
|
|
313
315
|
{
|
|
314
316
|
className: cn(
|
|
315
|
-
"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
|
|
316
|
-
|
|
317
|
+
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans",
|
|
318
|
+
MONO_CAPTION_CLASSES,
|
|
319
|
+
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash",
|
|
317
320
|
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
|
|
318
321
|
// Leaf sets its keys in mono, as Signal does (Katerina, 28 September): the type, not the key's shape.
|
|
319
322
|
"leaf:font-mono leaf:text-small",
|
|
@@ -858,9 +861,6 @@ function AvatarGroup({ members, size = 24 }) {
|
|
|
858
861
|
)) });
|
|
859
862
|
}
|
|
860
863
|
|
|
861
|
-
// src/Banner.tsx
|
|
862
|
-
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
863
|
-
|
|
864
864
|
// src/Button.tsx
|
|
865
865
|
import { Button as BaseButton3 } from "@base-ui/react/button";
|
|
866
866
|
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
@@ -928,31 +928,55 @@ function Button({
|
|
|
928
928
|
return disabledReason ? /* @__PURE__ */ jsx14(TooltipTrigger, { label: disabledReason, children: button }) : button;
|
|
929
929
|
}
|
|
930
930
|
|
|
931
|
-
// src/
|
|
931
|
+
// src/MembersPill.tsx
|
|
932
932
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
933
|
+
function MembersPill({ members, count, onClick, className }) {
|
|
934
|
+
const total = count ?? members.length;
|
|
935
|
+
if (total === 0) return null;
|
|
936
|
+
return /* @__PURE__ */ jsxs9(Button, { variant: "outlined", "aria-label": `${total} ${total === 1 ? "member" : "members"}`, disabled: !onClick, onClick, className: cn("gap-2 pl-[3px] pr-2", className), children: [
|
|
937
|
+
/* @__PURE__ */ jsx15(AvatarGroup, { members }),
|
|
938
|
+
/* @__PURE__ */ jsx15("span", { className: cn(MONO_CAPTION_CLASSES, "signal:tabular-nums"), children: total })
|
|
939
|
+
] });
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// src/MembersDialog.tsx
|
|
943
|
+
import { useId, useState as useState3 } from "react";
|
|
944
|
+
import { IconArrowLeft, IconUserMinus, IconUserPlus } from "@tabler/icons-react";
|
|
945
|
+
|
|
946
|
+
// src/Chip.tsx
|
|
947
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
948
|
+
var typeStyles = {
|
|
949
|
+
neutral: "bg-bg-inset text-text-primary",
|
|
950
|
+
brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
|
|
951
|
+
info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
|
|
952
|
+
warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
|
|
953
|
+
success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
|
|
954
|
+
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
938
955
|
};
|
|
939
|
-
function
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
956
|
+
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
|
|
957
|
+
const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
|
|
958
|
+
const inside = /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
959
|
+
leadingIcon && /* @__PURE__ */ jsx16("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
960
|
+
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
961
|
+
// of growing past it — Ship's project chip on an issue row
|
|
962
|
+
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
963
|
+
// `truncate`, because `truncate` is `overflow: hidden` on both axes and
|
|
964
|
+
// the label's line box (11px under Signal) is tighter than its glyphs —
|
|
965
|
+
// the screenshot diff caught every descender cut off. `clip` is the
|
|
966
|
+
// one overflow that leaves the other axis visible. A chip with no cap
|
|
967
|
+
// draws exactly as before.
|
|
968
|
+
/* @__PURE__ */ jsx16("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
|
|
969
|
+
trailingIcon && /* @__PURE__ */ jsx16("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
950
970
|
] });
|
|
971
|
+
if (href) return /* @__PURE__ */ jsx16("a", { href, onClick, className: cn("relative", classes), children: inside });
|
|
972
|
+
return /* @__PURE__ */ jsx16("div", { className: classes, children: inside });
|
|
951
973
|
}
|
|
952
974
|
|
|
953
|
-
// src/
|
|
954
|
-
import {
|
|
955
|
-
import {
|
|
975
|
+
// src/ChipInput.tsx
|
|
976
|
+
import { useMemo, useState as useState2 } from "react";
|
|
977
|
+
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
978
|
+
import { Combobox } from "@base-ui/react/combobox";
|
|
979
|
+
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
956
980
|
|
|
957
981
|
// src/Menu.tsx
|
|
958
982
|
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
@@ -962,27 +986,27 @@ import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
|
962
986
|
// src/Divider.tsx
|
|
963
987
|
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
964
988
|
import { Separator } from "@base-ui/react/separator";
|
|
965
|
-
import { jsx as
|
|
989
|
+
import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
966
990
|
var DividerInPanel = createContext3(false);
|
|
967
991
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
968
992
|
const inset = useContext3(DividerInPanel) ? "mx-0" : "mx-3";
|
|
969
993
|
if (label && orientation === "horizontal") {
|
|
970
994
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
971
|
-
return /* @__PURE__ */
|
|
995
|
+
return /* @__PURE__ */ jsxs11(
|
|
972
996
|
Separator,
|
|
973
997
|
{
|
|
974
998
|
orientation: "horizontal",
|
|
975
999
|
"aria-label": label,
|
|
976
1000
|
className: cn("flex shrink-0 items-center gap-2", inset, className),
|
|
977
1001
|
children: [
|
|
978
|
-
/* @__PURE__ */
|
|
979
|
-
/* @__PURE__ */
|
|
980
|
-
/* @__PURE__ */
|
|
1002
|
+
/* @__PURE__ */ jsx17("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
|
|
1003
|
+
/* @__PURE__ */ jsx17("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
|
|
1004
|
+
/* @__PURE__ */ jsx17("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
|
|
981
1005
|
]
|
|
982
1006
|
}
|
|
983
1007
|
);
|
|
984
1008
|
}
|
|
985
|
-
return /* @__PURE__ */
|
|
1009
|
+
return /* @__PURE__ */ jsx17(
|
|
986
1010
|
Separator,
|
|
987
1011
|
{
|
|
988
1012
|
orientation,
|
|
@@ -998,7 +1022,7 @@ function triggerDisabled(trigger) {
|
|
|
998
1022
|
}
|
|
999
1023
|
|
|
1000
1024
|
// src/SectionLabel.tsx
|
|
1001
|
-
import { jsx as
|
|
1025
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1002
1026
|
function SectionLabel({
|
|
1003
1027
|
children,
|
|
1004
1028
|
tone = "primary",
|
|
@@ -1006,7 +1030,7 @@ function SectionLabel({
|
|
|
1006
1030
|
folds = false,
|
|
1007
1031
|
className
|
|
1008
1032
|
}) {
|
|
1009
|
-
return /* @__PURE__ */
|
|
1033
|
+
return /* @__PURE__ */ jsx18(
|
|
1010
1034
|
"span",
|
|
1011
1035
|
{
|
|
1012
1036
|
className: cn(
|
|
@@ -1027,10 +1051,10 @@ function SectionLabel({
|
|
|
1027
1051
|
}
|
|
1028
1052
|
|
|
1029
1053
|
// src/Menu.tsx
|
|
1030
|
-
import { Fragment as
|
|
1054
|
+
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1031
1055
|
var MenuContext = createContext4(null);
|
|
1032
1056
|
function MenuPanel({ children, className, ...props }) {
|
|
1033
|
-
return /* @__PURE__ */
|
|
1057
|
+
return /* @__PURE__ */ jsx19(
|
|
1034
1058
|
"div",
|
|
1035
1059
|
{
|
|
1036
1060
|
className: cn(
|
|
@@ -1062,7 +1086,7 @@ var VIEWPORT_PAD2 = 8;
|
|
|
1062
1086
|
var HOVER_OPEN_DELAY = 0;
|
|
1063
1087
|
var HOVER_CLOSE_DELAY = 150;
|
|
1064
1088
|
function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
|
|
1065
|
-
return /* @__PURE__ */
|
|
1089
|
+
return /* @__PURE__ */ jsxs12(
|
|
1066
1090
|
BaseMenu.Root,
|
|
1067
1091
|
{
|
|
1068
1092
|
open,
|
|
@@ -1070,7 +1094,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1070
1094
|
actionsRef,
|
|
1071
1095
|
modal: false,
|
|
1072
1096
|
children: [
|
|
1073
|
-
/* @__PURE__ */
|
|
1097
|
+
/* @__PURE__ */ jsx19(
|
|
1074
1098
|
BaseMenu.Trigger,
|
|
1075
1099
|
{
|
|
1076
1100
|
render: trigger,
|
|
@@ -1080,7 +1104,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1080
1104
|
closeDelay: HOVER_CLOSE_DELAY
|
|
1081
1105
|
}
|
|
1082
1106
|
),
|
|
1083
|
-
/* @__PURE__ */
|
|
1107
|
+
/* @__PURE__ */ jsx19(BaseMenu.Portal, { children: /* @__PURE__ */ jsx19(
|
|
1084
1108
|
BaseMenu.Positioner,
|
|
1085
1109
|
{
|
|
1086
1110
|
side: "bottom",
|
|
@@ -1088,13 +1112,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
|
|
|
1088
1112
|
sideOffset: GAP2,
|
|
1089
1113
|
collisionPadding: VIEWPORT_PAD2,
|
|
1090
1114
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1091
|
-
children: /* @__PURE__ */
|
|
1115
|
+
children: /* @__PURE__ */ jsx19(
|
|
1092
1116
|
BaseMenu.Popup,
|
|
1093
1117
|
{
|
|
1094
1118
|
"data-interactive": true,
|
|
1095
1119
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
1096
|
-
render: /* @__PURE__ */
|
|
1097
|
-
children: /* @__PURE__ */
|
|
1120
|
+
render: /* @__PURE__ */ jsx19(MenuPanel, {}),
|
|
1121
|
+
children: /* @__PURE__ */ jsx19(ScrollArea, { viewportClassName: "max-h-[var(--available-height)]", contentClassName: cn("flex flex-col gap-0.5 p-2", contentClassName), children: /* @__PURE__ */ jsx19(MenuContext.Provider, { value: { openOnHover }, children: /* @__PURE__ */ jsx19(DividerInPanel.Provider, { value: true, children }) }) })
|
|
1098
1122
|
}
|
|
1099
1123
|
)
|
|
1100
1124
|
}
|
|
@@ -1110,20 +1134,20 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
1110
1134
|
'[@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".'
|
|
1111
1135
|
);
|
|
1112
1136
|
}
|
|
1113
|
-
return /* @__PURE__ */
|
|
1114
|
-
/* @__PURE__ */
|
|
1137
|
+
return /* @__PURE__ */ jsxs12(BaseMenu.SubmenuRoot, { children: [
|
|
1138
|
+
/* @__PURE__ */ jsx19(
|
|
1115
1139
|
BaseMenu.SubmenuTrigger,
|
|
1116
1140
|
{
|
|
1117
1141
|
openOnHover: true,
|
|
1118
1142
|
delay: 0,
|
|
1119
1143
|
closeDelay: 150,
|
|
1120
1144
|
nativeButton: true,
|
|
1121
|
-
render: /* @__PURE__ */
|
|
1145
|
+
render: /* @__PURE__ */ jsx19("button", { type: "button" }),
|
|
1122
1146
|
className: menuItemClassName({ size: "default", selected }),
|
|
1123
|
-
children: /* @__PURE__ */
|
|
1147
|
+
children: /* @__PURE__ */ jsx19(MenuItemBody, { label, leading, submenu: true })
|
|
1124
1148
|
}
|
|
1125
1149
|
),
|
|
1126
|
-
/* @__PURE__ */
|
|
1150
|
+
/* @__PURE__ */ jsx19(BaseMenu.Portal, { children: /* @__PURE__ */ jsx19(
|
|
1127
1151
|
BaseMenu.Positioner,
|
|
1128
1152
|
{
|
|
1129
1153
|
side: "inline-end",
|
|
@@ -1131,7 +1155,7 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
1131
1155
|
sideOffset: GAP2,
|
|
1132
1156
|
collisionPadding: VIEWPORT_PAD2,
|
|
1133
1157
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1134
|
-
children: /* @__PURE__ */
|
|
1158
|
+
children: /* @__PURE__ */ jsx19(BaseMenu.Popup, { className: cn("w-[160px]", className), "data-interactive": true, render: /* @__PURE__ */ jsx19(MenuPanel, {}), children })
|
|
1135
1159
|
}
|
|
1136
1160
|
) })
|
|
1137
1161
|
] });
|
|
@@ -1166,25 +1190,25 @@ function menuItemClassName({ size, selected, className }) {
|
|
|
1166
1190
|
);
|
|
1167
1191
|
}
|
|
1168
1192
|
function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
|
|
1169
|
-
const edge = trailing ?? (shortcut ? /* @__PURE__ */
|
|
1170
|
-
return /* @__PURE__ */
|
|
1171
|
-
leading && /* @__PURE__ */
|
|
1172
|
-
children ?? /* @__PURE__ */
|
|
1173
|
-
/* @__PURE__ */
|
|
1174
|
-
description && /* @__PURE__ */
|
|
1193
|
+
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx19(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx19(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
1194
|
+
return /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
1195
|
+
leading && /* @__PURE__ */ jsx19("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1196
|
+
children ?? /* @__PURE__ */ jsxs12("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
1197
|
+
/* @__PURE__ */ jsx19("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
1198
|
+
description && /* @__PURE__ */ jsx19("span", { className: "truncate text-caption text-text-secondary", children: description })
|
|
1175
1199
|
] }),
|
|
1176
1200
|
(edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
|
|
1177
1201
|
// the wider of the two and never changes, so revealing the hint moves
|
|
1178
1202
|
// nothing. No transition here either — the hint switches on the same
|
|
1179
1203
|
// :hover / `selected` as the fill, in the same frame.
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
edge && /* @__PURE__ */
|
|
1182
|
-
hint && /* @__PURE__ */
|
|
1204
|
+
/* @__PURE__ */ jsxs12("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
1205
|
+
edge && /* @__PURE__ */ jsx19("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
1206
|
+
hint && /* @__PURE__ */ jsx19("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
|
|
1183
1207
|
] })
|
|
1184
1208
|
] });
|
|
1185
1209
|
}
|
|
1186
1210
|
function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
1187
|
-
const body = /* @__PURE__ */
|
|
1211
|
+
const body = /* @__PURE__ */ jsx19(
|
|
1188
1212
|
MenuItemBody,
|
|
1189
1213
|
{
|
|
1190
1214
|
label,
|
|
@@ -1202,13 +1226,13 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1202
1226
|
);
|
|
1203
1227
|
const rowClassName = menuItemClassName({ size, selected, className });
|
|
1204
1228
|
if (!useContext4(MenuContext)) {
|
|
1205
|
-
return /* @__PURE__ */
|
|
1229
|
+
return /* @__PURE__ */ jsx19("button", { type: "button", className: rowClassName, ...props, children: body });
|
|
1206
1230
|
}
|
|
1207
|
-
return /* @__PURE__ */
|
|
1231
|
+
return /* @__PURE__ */ jsx19(
|
|
1208
1232
|
BaseMenu.Item,
|
|
1209
1233
|
{
|
|
1210
1234
|
nativeButton: true,
|
|
1211
|
-
render: /* @__PURE__ */
|
|
1235
|
+
render: /* @__PURE__ */ jsx19("button", { type: "button" }),
|
|
1212
1236
|
className: rowClassName,
|
|
1213
1237
|
...props,
|
|
1214
1238
|
children: body
|
|
@@ -1216,166 +1240,661 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
1216
1240
|
);
|
|
1217
1241
|
}
|
|
1218
1242
|
function EnterHint({ target }) {
|
|
1219
|
-
return /* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1221
|
-
target && /* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs12("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
1244
|
+
/* @__PURE__ */ jsx19(Kbd, { children: "\u21A9 Enter" }),
|
|
1245
|
+
target && /* @__PURE__ */ jsx19("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider leaf:font-mono leaf:text-small leaf:tracking-wider", children: target })
|
|
1222
1246
|
] });
|
|
1223
1247
|
}
|
|
1224
1248
|
function MenuSection({ label, children, className }) {
|
|
1225
1249
|
const inMenu = useContext4(MenuContext) !== null;
|
|
1226
|
-
const heading = /* @__PURE__ */
|
|
1250
|
+
const heading = /* @__PURE__ */ jsx19("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx19(SectionLabel, { tone: "secondary", children: label }) });
|
|
1227
1251
|
if (!inMenu) {
|
|
1228
|
-
return /* @__PURE__ */
|
|
1252
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-0.5", children: [
|
|
1229
1253
|
heading,
|
|
1230
1254
|
children
|
|
1231
1255
|
] });
|
|
1232
1256
|
}
|
|
1233
|
-
return /* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1257
|
+
return /* @__PURE__ */ jsxs12(BaseMenu.Group, { className: "flex flex-col gap-0.5", children: [
|
|
1258
|
+
/* @__PURE__ */ jsx19(BaseMenu.GroupLabel, { render: heading }),
|
|
1235
1259
|
children
|
|
1236
1260
|
] });
|
|
1237
1261
|
}
|
|
1238
1262
|
function MenuSeparator() {
|
|
1239
|
-
return /* @__PURE__ */
|
|
1263
|
+
return /* @__PURE__ */ jsx19(Divider, { className: "my-1" });
|
|
1240
1264
|
}
|
|
1241
1265
|
function MenuRow({ children, className }) {
|
|
1242
|
-
return /* @__PURE__ */
|
|
1266
|
+
return /* @__PURE__ */ jsx19("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
|
|
1243
1267
|
}
|
|
1244
1268
|
|
|
1245
|
-
// src/
|
|
1246
|
-
import { jsx as
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
return
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1269
|
+
// src/ChipInput.tsx
|
|
1270
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1271
|
+
var CHIP_BOX = (
|
|
1272
|
+
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
1273
|
+
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
1274
|
+
// follows concentrically: 4px face + 2px inset = rounded-md.
|
|
1275
|
+
"inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
|
|
1276
|
+
);
|
|
1277
|
+
var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
1278
|
+
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
1279
|
+
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
1280
|
+
function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
|
|
1281
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1282
|
+
leading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1283
|
+
/* @__PURE__ */ jsx20("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
|
|
1284
|
+
onRemove && /* @__PURE__ */ jsx20(
|
|
1285
|
+
BaseButton4,
|
|
1286
|
+
{
|
|
1287
|
+
type: "button",
|
|
1288
|
+
onClick: (e) => {
|
|
1289
|
+
e.stopPropagation();
|
|
1290
|
+
onRemove();
|
|
1291
|
+
},
|
|
1292
|
+
className: cn(CHIP_REMOVE, truncate && "shrink-0"),
|
|
1293
|
+
"aria-label": removeLabel ?? `Remove ${label}`,
|
|
1294
|
+
children: /* @__PURE__ */ jsx20(IconX3, { size: 10, stroke: 1.5 })
|
|
1295
|
+
}
|
|
1296
|
+
)
|
|
1297
|
+
] });
|
|
1270
1298
|
}
|
|
1271
|
-
function
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1299
|
+
function ChipInput({
|
|
1300
|
+
value,
|
|
1301
|
+
onChange,
|
|
1302
|
+
options,
|
|
1303
|
+
placeholder = "Search\u2026",
|
|
1304
|
+
autoFocus,
|
|
1305
|
+
excludeIds = [],
|
|
1306
|
+
chipLeading,
|
|
1307
|
+
rowLeading,
|
|
1308
|
+
...aria
|
|
1309
|
+
}) {
|
|
1310
|
+
const [query, setQuery] = useState2("");
|
|
1311
|
+
const [box, setBox] = useState2(null);
|
|
1312
|
+
const available = useMemo(() => {
|
|
1313
|
+
const chosen = new Set(value.map((o) => o.id));
|
|
1314
|
+
const excluded = new Set(excludeIds);
|
|
1315
|
+
return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
|
|
1316
|
+
}, [options, value, excludeIds]);
|
|
1317
|
+
const filter = useMemo(
|
|
1318
|
+
() => (item, q) => {
|
|
1319
|
+
const needle = q.trim().toLowerCase();
|
|
1320
|
+
if (!needle) return true;
|
|
1321
|
+
return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
|
|
1283
1322
|
},
|
|
1284
|
-
[
|
|
1323
|
+
[]
|
|
1285
1324
|
);
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
}
|
|
1291
|
-
}, [editing, open]);
|
|
1292
|
-
const rows = editing && block ? editing.rows(block) : null;
|
|
1293
|
-
const own = actions && block ? actions(block) : null;
|
|
1294
|
-
const dragging = useRef3(false);
|
|
1295
|
-
const [line, setLine] = useState2(null);
|
|
1296
|
-
const inGutter = (e) => dragging.current && !!editing && !!content.current && !content.current.contains(e.target);
|
|
1297
|
-
const landing = (y) => {
|
|
1298
|
-
const target = editing?.find(y);
|
|
1299
|
-
if (!target || !frame.current) return null;
|
|
1300
|
-
const box = target.element.getBoundingClientRect();
|
|
1301
|
-
const after = y > box.top + box.height / 2;
|
|
1302
|
-
const neighbour = (after ? target.element.nextElementSibling : target.element.previousElementSibling)?.getBoundingClientRect();
|
|
1303
|
-
const edge = after ? neighbour ? (box.bottom + neighbour.top) / 2 : box.bottom : neighbour ? (neighbour.bottom + box.top) / 2 : box.top;
|
|
1304
|
-
return { target, after, top: edge - frame.current.getBoundingClientRect().top };
|
|
1305
|
-
};
|
|
1306
|
-
const endDrag = () => {
|
|
1307
|
-
dragging.current = false;
|
|
1308
|
-
setLine(null);
|
|
1309
|
-
editing?.endDrag();
|
|
1325
|
+
const open = query.trim().length > 0;
|
|
1326
|
+
const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
|
|
1327
|
+
const naming = {
|
|
1328
|
+
...ariaLabel !== void 0 && { "aria-label": ariaLabel },
|
|
1329
|
+
...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
|
|
1310
1330
|
};
|
|
1311
|
-
|
|
1312
|
-
|
|
1331
|
+
function removeLast() {
|
|
1332
|
+
if (value.length > 0) onChange(value.slice(0, -1));
|
|
1333
|
+
}
|
|
1334
|
+
function onInputKeyDown(event) {
|
|
1335
|
+
if (event.key === "Backspace" && query === "" && value.length > 0) {
|
|
1336
|
+
event.preventDefault();
|
|
1337
|
+
event.stopPropagation();
|
|
1338
|
+
removeLast();
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
if (event.key === "Escape" && query !== "") {
|
|
1342
|
+
event.preventDefault();
|
|
1343
|
+
event.stopPropagation();
|
|
1344
|
+
setQuery("");
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
return /* @__PURE__ */ jsxs13(
|
|
1348
|
+
Combobox.Root,
|
|
1313
1349
|
{
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
if (!open) setBlock(null);
|
|
1321
|
-
},
|
|
1322
|
-
onDragOver: (e) => {
|
|
1323
|
-
if (!inGutter(e)) return setLine(null);
|
|
1324
|
-
e.preventDefault();
|
|
1325
|
-
setLine(landing(e.clientY)?.top ?? null);
|
|
1326
|
-
},
|
|
1327
|
-
onDrop: (e) => {
|
|
1328
|
-
if (inGutter(e)) {
|
|
1329
|
-
e.preventDefault();
|
|
1330
|
-
const at = landing(e.clientY);
|
|
1331
|
-
if (at) editing?.drop(at.target, at.after);
|
|
1332
|
-
}
|
|
1333
|
-
endDrag();
|
|
1334
|
-
},
|
|
1335
|
-
onDragLeave: (e) => {
|
|
1336
|
-
if (!frame.current?.contains(e.relatedTarget)) setLine(null);
|
|
1350
|
+
multiple: true,
|
|
1351
|
+
items: available,
|
|
1352
|
+
value,
|
|
1353
|
+
onValueChange: (next) => {
|
|
1354
|
+
onChange(next);
|
|
1355
|
+
setQuery("");
|
|
1337
1356
|
},
|
|
1357
|
+
inputValue: query,
|
|
1358
|
+
onInputValueChange: setQuery,
|
|
1359
|
+
open,
|
|
1360
|
+
openOnInputClick: false,
|
|
1361
|
+
filter,
|
|
1362
|
+
itemToStringLabel: (option) => option.label,
|
|
1338
1363
|
children: [
|
|
1339
|
-
/* @__PURE__ */
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1364
|
+
/* @__PURE__ */ jsxs13(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
|
|
1365
|
+
value.map((option) => /* @__PURE__ */ jsxs13(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1366
|
+
chipLeading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1367
|
+
/* @__PURE__ */ jsx20("span", { className: CHIP_LABEL, children: option.label }),
|
|
1368
|
+
/* @__PURE__ */ jsx20(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx20(IconX3, { size: 10, stroke: 1.5 }) })
|
|
1369
|
+
] }, option.id)),
|
|
1370
|
+
/* @__PURE__ */ jsx20(
|
|
1371
|
+
Combobox.Input,
|
|
1372
|
+
{
|
|
1373
|
+
autoFocus,
|
|
1374
|
+
placeholder: value.length === 0 ? placeholder : "",
|
|
1375
|
+
"aria-required": aria["aria-required"],
|
|
1376
|
+
...naming,
|
|
1377
|
+
onKeyDown: onInputKeyDown,
|
|
1378
|
+
className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
|
|
1379
|
+
}
|
|
1380
|
+
)
|
|
1381
|
+
] }),
|
|
1382
|
+
/* @__PURE__ */ jsx20(Combobox.Portal, { children: /* @__PURE__ */ jsx20(
|
|
1383
|
+
Combobox.Positioner,
|
|
1345
1384
|
{
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1385
|
+
anchor: box,
|
|
1386
|
+
sideOffset: GAP3,
|
|
1387
|
+
collisionPadding: VIEWPORT_PAD3,
|
|
1388
|
+
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1389
|
+
children: /* @__PURE__ */ jsx20(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx20(MenuPanel, {}), children: /* @__PURE__ */ jsx20(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx20(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx20(
|
|
1390
|
+
Combobox.Item,
|
|
1350
1391
|
{
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1392
|
+
value: option,
|
|
1393
|
+
render: /* @__PURE__ */ jsx20(
|
|
1394
|
+
MenuItem,
|
|
1395
|
+
{
|
|
1396
|
+
size: "tall",
|
|
1397
|
+
leading: rowLeading?.(option),
|
|
1398
|
+
label: option.label,
|
|
1399
|
+
description: option.description
|
|
1400
|
+
}
|
|
1401
|
+
)
|
|
1402
|
+
},
|
|
1403
|
+
option.id
|
|
1404
|
+
) }) }) })
|
|
1405
|
+
}
|
|
1406
|
+
) })
|
|
1407
|
+
]
|
|
1408
|
+
}
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
var GAP3 = 4;
|
|
1412
|
+
var VIEWPORT_PAD3 = 8;
|
|
1413
|
+
|
|
1414
|
+
// src/DialogShell.tsx
|
|
1415
|
+
import { useRef as useRef3 } from "react";
|
|
1416
|
+
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1417
|
+
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1418
|
+
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1419
|
+
|
|
1420
|
+
// src/ContainerHeader.tsx
|
|
1421
|
+
import { IconChevronDown } from "@tabler/icons-react";
|
|
1422
|
+
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1423
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1424
|
+
function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
|
|
1425
|
+
const text = typeof title === "string";
|
|
1426
|
+
const name = /* @__PURE__ */ jsxs14("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
|
|
1427
|
+
text ? /* @__PURE__ */ jsx21("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx21("div", { className: "min-w-0 flex-1", children: title }),
|
|
1428
|
+
(chevron || titleMenu != null) && /* @__PURE__ */ jsx21(IconChevronDown, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1429
|
+
] });
|
|
1430
|
+
return (
|
|
1431
|
+
// The title 16px in, where the column's content starts (Katerina, 7 October; it was 20px).
|
|
1432
|
+
// With a title menu the bar gives the button 6px of its left padding
|
|
1433
|
+
// (pl-2.5 + the button's px-1.5 = pl-4): the words stay where a title's
|
|
1434
|
+
// are, and the fill is inside the bar — a negative margin had it clipped
|
|
1435
|
+
// (Katerina, 5 October).
|
|
1436
|
+
/* @__PURE__ */ jsxs14("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-2.5" : "pl-4", className), children: [
|
|
1437
|
+
/* @__PURE__ */ jsx21("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx21(
|
|
1438
|
+
Menu,
|
|
1439
|
+
{
|
|
1440
|
+
trigger: /* @__PURE__ */ jsx21(BaseButton5, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
|
|
1441
|
+
children: titleMenu
|
|
1442
|
+
}
|
|
1443
|
+
) : name }),
|
|
1444
|
+
actions && /* @__PURE__ */ jsx21("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx21("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
|
|
1445
|
+
] })
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
// src/DialogShell.tsx
|
|
1450
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1451
|
+
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1452
|
+
const Parts = alert ? AlertDialog : Dialog2;
|
|
1453
|
+
const popupRef = useRef3(null);
|
|
1454
|
+
return /* @__PURE__ */ jsx22(
|
|
1455
|
+
Parts.Root,
|
|
1456
|
+
{
|
|
1457
|
+
open: true,
|
|
1458
|
+
onOpenChange: (open) => {
|
|
1459
|
+
if (!open) onClose();
|
|
1460
|
+
},
|
|
1461
|
+
children: /* @__PURE__ */ jsxs15(Parts.Portal, { children: [
|
|
1462
|
+
/* @__PURE__ */ jsx22(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1463
|
+
/* @__PURE__ */ jsx22("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs15(
|
|
1464
|
+
Parts.Popup,
|
|
1465
|
+
{
|
|
1466
|
+
ref: popupRef,
|
|
1467
|
+
initialFocus: popupRef,
|
|
1468
|
+
"aria-label": headerContent != null ? title : void 0,
|
|
1469
|
+
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1470
|
+
style: { width },
|
|
1471
|
+
children: [
|
|
1472
|
+
/* @__PURE__ */ jsx22(
|
|
1473
|
+
ContainerHeader,
|
|
1474
|
+
{
|
|
1475
|
+
className: "pl-5",
|
|
1476
|
+
title: headerContent ?? /* @__PURE__ */ jsx22(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx22("span", {}), children: title }),
|
|
1477
|
+
actions: (
|
|
1478
|
+
/*
|
|
1479
|
+
The ✕ IS the `Close` part now, rather than a button that calls
|
|
1480
|
+
`onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
|
|
1481
|
+
this: an `IconButton` carrying a `tooltip` returned the tooltip
|
|
1482
|
+
wrapper `<div>` as its root, so the part composed onto the
|
|
1483
|
+
wrapper and not the button. Porting Tooltip removed the wrapper
|
|
1484
|
+
— the trigger is the button itself — and the composition works.
|
|
1485
|
+
|
|
1486
|
+
What it buys: the dialog closes through its own state machine,
|
|
1487
|
+
so the ✕, Escape and the outside press are one path with one
|
|
1488
|
+
reason attached, instead of one of the three going around.
|
|
1489
|
+
*/
|
|
1490
|
+
/* @__PURE__ */ jsx22(
|
|
1491
|
+
Parts.Close,
|
|
1492
|
+
{
|
|
1493
|
+
render: /* @__PURE__ */ jsx22(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx22(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1494
|
+
}
|
|
1495
|
+
)
|
|
1496
|
+
)
|
|
1497
|
+
}
|
|
1498
|
+
),
|
|
1499
|
+
bodyMaxHeight ? (
|
|
1500
|
+
// The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
|
|
1501
|
+
/* @__PURE__ */ jsx22("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
|
|
1502
|
+
) : /* @__PURE__ */ jsx22("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1503
|
+
footer != null && /* @__PURE__ */ jsx22("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1504
|
+
]
|
|
1505
|
+
}
|
|
1506
|
+
) })
|
|
1507
|
+
] })
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// src/Field.tsx
|
|
1513
|
+
import { cloneElement, isValidElement } from "react";
|
|
1514
|
+
import { Field as BaseField } from "@base-ui/react/field";
|
|
1515
|
+
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1516
|
+
var LINE_STYLES = {
|
|
1517
|
+
helper: "text-caption text-text-muted",
|
|
1518
|
+
warning: "text-caption text-warning-default",
|
|
1519
|
+
error: "text-caption text-error-default"
|
|
1520
|
+
};
|
|
1521
|
+
function Field({ label, required = false, helper, error, children }) {
|
|
1522
|
+
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1523
|
+
"aria-required": children.props["aria-required"] ?? true
|
|
1524
|
+
}) : children;
|
|
1525
|
+
return (
|
|
1526
|
+
// `group/field`: the label, the box and the line under it are one thing under the pointer —
|
|
1527
|
+
// anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
|
|
1528
|
+
// Before, the 8px between the label and the box was a gap where the border went out again.
|
|
1529
|
+
/* @__PURE__ */ jsxs16(BaseField.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
|
|
1530
|
+
/* @__PURE__ */ jsxs16(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1531
|
+
label,
|
|
1532
|
+
required && /* @__PURE__ */ jsx23("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1533
|
+
] }),
|
|
1534
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
|
|
1535
|
+
control,
|
|
1536
|
+
error != null ? /* @__PURE__ */ jsx23(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx23(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1537
|
+
] })
|
|
1538
|
+
] })
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1541
|
+
function FieldLine({ tone = "helper", children, className }) {
|
|
1542
|
+
return /* @__PURE__ */ jsx23("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// src/Form.tsx
|
|
1546
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef4 } from "react";
|
|
1547
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1548
|
+
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1549
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1550
|
+
var FIELDS_CLASSES = "flex flex-col gap-6";
|
|
1551
|
+
var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1552
|
+
var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1553
|
+
function usable(element) {
|
|
1554
|
+
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1555
|
+
}
|
|
1556
|
+
function firstInvalid(form) {
|
|
1557
|
+
for (const marked of form.querySelectorAll("[data-invalid]")) {
|
|
1558
|
+
if (usable(marked)) return marked;
|
|
1559
|
+
const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
|
|
1560
|
+
if (inside) return inside;
|
|
1561
|
+
}
|
|
1562
|
+
return void 0;
|
|
1563
|
+
}
|
|
1564
|
+
function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
|
|
1565
|
+
const outerBusy = useFormBusy();
|
|
1566
|
+
const busy = ownBusy || outerBusy;
|
|
1567
|
+
const form = useRef4(null);
|
|
1568
|
+
const busyNow = useRef4(busy);
|
|
1569
|
+
busyNow.current = busy;
|
|
1570
|
+
const sender = useRef4(null);
|
|
1571
|
+
const holding = useRef4(false);
|
|
1572
|
+
const lastInside = useRef4(null);
|
|
1573
|
+
useLayoutEffect2(() => {
|
|
1574
|
+
const element = form.current;
|
|
1575
|
+
if (!element) return;
|
|
1576
|
+
if (busy) {
|
|
1577
|
+
const active = document.activeElement;
|
|
1578
|
+
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1579
|
+
if (from?.isConnected) {
|
|
1580
|
+
sender.current = from;
|
|
1581
|
+
holding.current = true;
|
|
1582
|
+
element.focus();
|
|
1583
|
+
}
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
if (!holding.current) return;
|
|
1587
|
+
holding.current = false;
|
|
1588
|
+
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1589
|
+
const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
|
|
1590
|
+
sender.current = null;
|
|
1591
|
+
target?.focus();
|
|
1592
|
+
}, [busy]);
|
|
1593
|
+
const onKeyDown = (event) => {
|
|
1594
|
+
props.onKeyDown?.(event);
|
|
1595
|
+
if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
|
|
1596
|
+
const target = event.target;
|
|
1597
|
+
const inInput = target instanceof HTMLInputElement;
|
|
1598
|
+
if (inInput) event.preventDefault();
|
|
1599
|
+
if (event.altKey || event.shiftKey) return;
|
|
1600
|
+
if (event.ctrlKey || event.metaKey) {
|
|
1601
|
+
event.preventDefault();
|
|
1602
|
+
form.current?.requestSubmit();
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
if (!inInput) return;
|
|
1606
|
+
const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
|
|
1607
|
+
if (enterSends && oneLine) form.current?.requestSubmit();
|
|
1608
|
+
};
|
|
1609
|
+
return /* @__PURE__ */ jsx24(
|
|
1610
|
+
BaseForm,
|
|
1611
|
+
{
|
|
1612
|
+
ref: form,
|
|
1613
|
+
...props,
|
|
1614
|
+
tabIndex: busy ? -1 : props.tabIndex,
|
|
1615
|
+
className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
|
|
1616
|
+
onFocus: (event) => {
|
|
1617
|
+
if (event.target !== form.current) lastInside.current = event.target;
|
|
1618
|
+
props.onFocus?.(event);
|
|
1619
|
+
},
|
|
1620
|
+
onBlur: (event) => {
|
|
1621
|
+
const next = event.relatedTarget;
|
|
1622
|
+
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1623
|
+
props.onBlur?.(event);
|
|
1624
|
+
},
|
|
1625
|
+
onKeyDown,
|
|
1626
|
+
onSubmit: (event) => {
|
|
1627
|
+
if (event.target !== event.currentTarget) return;
|
|
1628
|
+
event.preventDefault();
|
|
1629
|
+
if (busyNow.current) return;
|
|
1630
|
+
void onSubmit();
|
|
1631
|
+
},
|
|
1632
|
+
children: /* @__PURE__ */ jsx24(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx24(FormBusyContext.Provider, { value: busy, children }) })
|
|
1633
|
+
}
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// src/MembersDialog.tsx
|
|
1638
|
+
import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1639
|
+
var LEADING_CLASSES = "size-8 rounded-md bg-accent-muted flex items-center justify-center shrink-0 text-accent-primary";
|
|
1640
|
+
function MembersDialog({ members, count, self, candidates = [], onAdd, note, initialView = "list", onClose }) {
|
|
1641
|
+
const [view, setView] = useState3(onAdd ? initialView : "list");
|
|
1642
|
+
const [chosen, setChosen] = useState3([]);
|
|
1643
|
+
const [toggling, setToggling] = useState3(false);
|
|
1644
|
+
const formId = useId();
|
|
1645
|
+
const toggle = async () => {
|
|
1646
|
+
if (!self || toggling) return;
|
|
1647
|
+
setToggling(true);
|
|
1648
|
+
try {
|
|
1649
|
+
await self.onToggle();
|
|
1650
|
+
} finally {
|
|
1651
|
+
setToggling(false);
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
const add = async () => {
|
|
1655
|
+
if (!onAdd || chosen.length === 0) return;
|
|
1656
|
+
if (await onAdd(chosen) === false) return;
|
|
1657
|
+
setChosen([]);
|
|
1658
|
+
setView("list");
|
|
1659
|
+
};
|
|
1660
|
+
if (view === "add" && onAdd) {
|
|
1661
|
+
return /* @__PURE__ */ jsx25(
|
|
1662
|
+
DialogShell,
|
|
1663
|
+
{
|
|
1664
|
+
title: "Add members",
|
|
1665
|
+
onClose,
|
|
1666
|
+
headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1667
|
+
/* @__PURE__ */ jsx25(IconButton, { tooltip: "Back to members", "aria-label": "Back to members", className: "-ml-2", onClick: () => setView("list"), children: /* @__PURE__ */ jsx25(IconArrowLeft, { size: 16, stroke: 1.5 }) }),
|
|
1668
|
+
/* @__PURE__ */ jsx25("span", { className: "truncate text-h4 text-text-primary", children: "Add members" })
|
|
1669
|
+
] }),
|
|
1670
|
+
bodyClassName: "flex flex-col gap-6",
|
|
1671
|
+
footer: /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
1672
|
+
/* @__PURE__ */ jsx25(Button, { variant: "muted", onClick: onClose, children: "Cancel" }),
|
|
1673
|
+
/* @__PURE__ */ jsx25(Button, { variant: "primary", type: "submit", form: formId, disabled: chosen.length === 0, children: "Invite" })
|
|
1674
|
+
] }),
|
|
1675
|
+
children: /* @__PURE__ */ jsx25(Form, { id: formId, onSubmit: add, children: /* @__PURE__ */ jsx25(Field, { label: "Invite people", required: true, children: /* @__PURE__ */ jsx25(
|
|
1676
|
+
ChipInput,
|
|
1677
|
+
{
|
|
1678
|
+
value: chosen,
|
|
1679
|
+
onChange: setChosen,
|
|
1680
|
+
options: candidates,
|
|
1681
|
+
placeholder: "Search people...",
|
|
1682
|
+
excludeIds: members.map((m) => m.id),
|
|
1683
|
+
chipLeading: (o) => /* @__PURE__ */ jsx25(Avatar, { name: o.label, src: o.picture, size: 16 }),
|
|
1684
|
+
rowLeading: (o) => /* @__PURE__ */ jsx25(Avatar, { name: o.label, src: o.picture, size: 32 }),
|
|
1685
|
+
autoFocus: true
|
|
1686
|
+
}
|
|
1687
|
+
) }) })
|
|
1688
|
+
}
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
return /* @__PURE__ */ jsxs17(
|
|
1692
|
+
DialogShell,
|
|
1693
|
+
{
|
|
1694
|
+
title: "Members",
|
|
1695
|
+
onClose,
|
|
1696
|
+
headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1697
|
+
/* @__PURE__ */ jsx25("span", { className: "truncate text-h4 text-text-primary", children: "Members" }),
|
|
1698
|
+
/* @__PURE__ */ jsx25(Chip, { label: String(count ?? members.length) })
|
|
1699
|
+
] }),
|
|
1700
|
+
bodyMaxHeight: "max-h-[400px]",
|
|
1701
|
+
bodyClassName: "p-0 py-2",
|
|
1702
|
+
children: [
|
|
1703
|
+
(self || onAdd) && /* @__PURE__ */ jsxs17("div", { className: "flex flex-col px-2", children: [
|
|
1704
|
+
self && /* @__PURE__ */ jsx25(
|
|
1705
|
+
MenuItem,
|
|
1706
|
+
{
|
|
1707
|
+
size: "tall",
|
|
1708
|
+
className: "py-2",
|
|
1709
|
+
disabled: toggling,
|
|
1710
|
+
onClick: () => void toggle(),
|
|
1711
|
+
leading: /* @__PURE__ */ jsx25("span", { className: LEADING_CLASSES, children: self.action === "join" ? /* @__PURE__ */ jsx25(IconUserPlus, { size: 16, stroke: 1.5 }) : /* @__PURE__ */ jsx25(IconUserMinus, { size: 16, stroke: 1.5 }) }),
|
|
1712
|
+
label: self.action === "join" ? "Join" : "Leave"
|
|
1713
|
+
}
|
|
1714
|
+
),
|
|
1715
|
+
onAdd && /* @__PURE__ */ jsx25(
|
|
1716
|
+
MenuItem,
|
|
1717
|
+
{
|
|
1718
|
+
size: "tall",
|
|
1719
|
+
className: "py-2",
|
|
1720
|
+
onClick: () => setView("add"),
|
|
1721
|
+
leading: /* @__PURE__ */ jsx25("span", { className: LEADING_CLASSES, children: /* @__PURE__ */ jsx25(IconUserPlus, { size: 16, stroke: 1.5 }) }),
|
|
1722
|
+
label: "Add members"
|
|
1723
|
+
}
|
|
1724
|
+
)
|
|
1725
|
+
] }),
|
|
1726
|
+
members.map((member) => /* @__PURE__ */ jsxs17("div", { className: "flex h-12 items-center gap-3 px-5", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx25(Avatar, { size: 32, name: member.name, src: member.picture }),
|
|
1728
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-[2px]", children: [
|
|
1729
|
+
/* @__PURE__ */ jsx25("div", { className: "truncate text-body-2 text-text-primary", children: member.name }),
|
|
1730
|
+
member.caption && /* @__PURE__ */ jsx25("div", { className: "truncate text-caption text-text-secondary", children: member.caption })
|
|
1731
|
+
] })
|
|
1732
|
+
] }, member.id)),
|
|
1733
|
+
note && /* @__PURE__ */ jsx25("div", { className: "px-5 pb-2 pt-3 text-caption text-text-secondary", children: note })
|
|
1734
|
+
]
|
|
1735
|
+
}
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// src/Banner.tsx
|
|
1740
|
+
import { IconX as IconX5 } from "@tabler/icons-react";
|
|
1741
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1742
|
+
var TONE_STYLES = {
|
|
1743
|
+
ok: "bg-success-muted text-success-default",
|
|
1744
|
+
error: "bg-error-muted text-error-default",
|
|
1745
|
+
info: "bg-info-muted text-info-default",
|
|
1746
|
+
warning: "bg-warning-muted text-warning-default"
|
|
1747
|
+
};
|
|
1748
|
+
function Banner({ tone, children, icon, action, onDismiss, dismissLabel = "Dismiss", className }) {
|
|
1749
|
+
const role = tone === "error" ? "alert" : "status";
|
|
1750
|
+
if (!onDismiss && !icon && !action) {
|
|
1751
|
+
return /* @__PURE__ */ jsx26("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
|
|
1752
|
+
}
|
|
1753
|
+
const oneLine = Boolean(icon || action);
|
|
1754
|
+
return /* @__PURE__ */ jsxs18("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
|
|
1755
|
+
icon && /* @__PURE__ */ jsx26("span", { className: "flex shrink-0", children: icon }),
|
|
1756
|
+
/* @__PURE__ */ jsx26("span", { className: cn("min-w-0 flex-1", oneLine && "truncate"), children }),
|
|
1757
|
+
action && /* @__PURE__ */ jsx26(Button, { variant: "muted", size: "small", className: "shrink-0", onClick: action.onClick, children: action.label }),
|
|
1758
|
+
onDismiss && /* @__PURE__ */ jsx26(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx26(IconX5, { size: 16, stroke: 1.5 }) })
|
|
1759
|
+
] });
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
// src/BlockHandle.tsx
|
|
1763
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef5, useState as useState4 } from "react";
|
|
1764
|
+
import { IconGripVertical } from "@tabler/icons-react";
|
|
1765
|
+
import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1766
|
+
function readId(element) {
|
|
1767
|
+
const own = element.getAttribute("data-block-id") ?? element.querySelector("[data-block-id]")?.getAttribute("data-block-id");
|
|
1768
|
+
return own || void 0;
|
|
1769
|
+
}
|
|
1770
|
+
function blockAtY(blocks, y) {
|
|
1771
|
+
let found = null;
|
|
1772
|
+
for (const block of blocks) {
|
|
1773
|
+
if (block.element.getBoundingClientRect().top > y) break;
|
|
1774
|
+
found = block;
|
|
1775
|
+
}
|
|
1776
|
+
return found ?? blocks[0] ?? null;
|
|
1777
|
+
}
|
|
1778
|
+
function readingBlocks(root) {
|
|
1779
|
+
if (!root) return [];
|
|
1780
|
+
return Array.from(root.children).filter((el) => el instanceof HTMLElement).map((element) => ({ id: readId(element), element })).filter((b) => b.id !== void 0);
|
|
1781
|
+
}
|
|
1782
|
+
var HANDLE = 24;
|
|
1783
|
+
function firstLineOffset(element) {
|
|
1784
|
+
const text = element.querySelector("p, h1, h2, h3, pre, li") ?? element;
|
|
1785
|
+
const line = parseFloat(getComputedStyle(text).lineHeight);
|
|
1786
|
+
if (!Number.isFinite(line)) return 0;
|
|
1787
|
+
const inset = text === element ? 0 : text.getBoundingClientRect().top - element.getBoundingClientRect().top;
|
|
1788
|
+
return inset + (line - HANDLE) / 2;
|
|
1789
|
+
}
|
|
1790
|
+
function BlockHandle({ actions, editing, children, className }) {
|
|
1791
|
+
const frame = useRef5(null);
|
|
1792
|
+
const content = useRef5(null);
|
|
1793
|
+
const [block, setBlock] = useState4(null);
|
|
1794
|
+
const [top, setTop] = useState4(0);
|
|
1795
|
+
const [open, setOpen] = useState4(false);
|
|
1796
|
+
const follow = useCallback(
|
|
1797
|
+
(y) => {
|
|
1798
|
+
if (!content.current || !frame.current) return;
|
|
1799
|
+
const found = editing ? editing.find(y) : blockAtY(readingBlocks(content.current.firstElementChild), y);
|
|
1800
|
+
setBlock(found);
|
|
1801
|
+
if (found) setTop(found.element.getBoundingClientRect().top - frame.current.getBoundingClientRect().top + firstLineOffset(found.element));
|
|
1802
|
+
},
|
|
1803
|
+
[editing]
|
|
1804
|
+
);
|
|
1805
|
+
useEffect2(() => {
|
|
1806
|
+
if (!editing) return;
|
|
1807
|
+
return editing.onChange(() => {
|
|
1808
|
+
if (!open) setBlock(null);
|
|
1809
|
+
});
|
|
1810
|
+
}, [editing, open]);
|
|
1811
|
+
const rows = editing && block ? editing.rows(block) : null;
|
|
1812
|
+
const own = actions && block ? actions(block) : null;
|
|
1813
|
+
const dragging = useRef5(false);
|
|
1814
|
+
const [line, setLine] = useState4(null);
|
|
1815
|
+
const inGutter = (e) => dragging.current && !!editing && !!content.current && !content.current.contains(e.target);
|
|
1816
|
+
const landing = (y) => {
|
|
1817
|
+
const target = editing?.find(y);
|
|
1818
|
+
if (!target || !frame.current) return null;
|
|
1819
|
+
const box = target.element.getBoundingClientRect();
|
|
1820
|
+
const after = y > box.top + box.height / 2;
|
|
1821
|
+
const neighbour = (after ? target.element.nextElementSibling : target.element.previousElementSibling)?.getBoundingClientRect();
|
|
1822
|
+
const edge = after ? neighbour ? (box.bottom + neighbour.top) / 2 : box.bottom : neighbour ? (neighbour.bottom + box.top) / 2 : box.top;
|
|
1823
|
+
return { target, after, top: edge - frame.current.getBoundingClientRect().top };
|
|
1824
|
+
};
|
|
1825
|
+
const endDrag = () => {
|
|
1826
|
+
dragging.current = false;
|
|
1827
|
+
setLine(null);
|
|
1828
|
+
editing?.endDrag();
|
|
1829
|
+
};
|
|
1830
|
+
return /* @__PURE__ */ jsxs19(
|
|
1831
|
+
"div",
|
|
1832
|
+
{
|
|
1833
|
+
ref: frame,
|
|
1834
|
+
className: cn("relative", className),
|
|
1835
|
+
onMouseMove: (e) => {
|
|
1836
|
+
if (!open) follow(e.clientY);
|
|
1837
|
+
},
|
|
1838
|
+
onMouseLeave: () => {
|
|
1839
|
+
if (!open) setBlock(null);
|
|
1840
|
+
},
|
|
1841
|
+
onDragOver: (e) => {
|
|
1842
|
+
if (!inGutter(e)) return setLine(null);
|
|
1843
|
+
e.preventDefault();
|
|
1844
|
+
setLine(landing(e.clientY)?.top ?? null);
|
|
1845
|
+
},
|
|
1846
|
+
onDrop: (e) => {
|
|
1847
|
+
if (inGutter(e)) {
|
|
1848
|
+
e.preventDefault();
|
|
1849
|
+
const at = landing(e.clientY);
|
|
1850
|
+
if (at) editing?.drop(at.target, at.after);
|
|
1851
|
+
}
|
|
1852
|
+
endDrag();
|
|
1853
|
+
},
|
|
1854
|
+
onDragLeave: (e) => {
|
|
1855
|
+
if (!frame.current?.contains(e.relatedTarget)) setLine(null);
|
|
1856
|
+
},
|
|
1857
|
+
children: [
|
|
1858
|
+
/* @__PURE__ */ jsx27("div", { ref: content, children }),
|
|
1859
|
+
/* @__PURE__ */ jsx27("div", { "aria-hidden": true, className: "absolute inset-y-0 -left-7 w-7" }),
|
|
1860
|
+
line !== null && /* @__PURE__ */ jsx27("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-x-0 h-px bg-accent-primary", style: { top: line } }),
|
|
1861
|
+
block && (rows || own) && // The top is the block's, measured: it depends on the document, not on a size of ours.
|
|
1862
|
+
/* @__PURE__ */ jsx27("div", { className: cn("absolute -left-7", rows && "cursor-grab active:cursor-grabbing"), style: { top }, children: /* @__PURE__ */ jsxs19(
|
|
1863
|
+
Menu,
|
|
1864
|
+
{
|
|
1865
|
+
open,
|
|
1866
|
+
onOpenChange: setOpen,
|
|
1867
|
+
trigger: /* @__PURE__ */ jsx27(
|
|
1868
|
+
IconButton,
|
|
1869
|
+
{
|
|
1870
|
+
"aria-label": "Block menu",
|
|
1871
|
+
tooltip: rows ? "Drag to move, click for the menu" : "Menu",
|
|
1872
|
+
draggable: !!rows,
|
|
1873
|
+
onMouseDown: (e) => e.preventBaseUIHandler(),
|
|
1874
|
+
onClick: (e) => {
|
|
1875
|
+
e.preventBaseUIHandler();
|
|
1876
|
+
setOpen((was) => !was);
|
|
1877
|
+
},
|
|
1878
|
+
onDragStart: (e) => {
|
|
1879
|
+
if (!editing || !rows) return;
|
|
1880
|
+
setOpen(false);
|
|
1881
|
+
dragging.current = true;
|
|
1882
|
+
editing.startDrag(block, e.nativeEvent);
|
|
1883
|
+
},
|
|
1884
|
+
onDragEnd: () => {
|
|
1885
|
+
endDrag();
|
|
1886
|
+
setBlock(null);
|
|
1887
|
+
},
|
|
1888
|
+
children: /* @__PURE__ */ jsx27(IconGripVertical, { size: 16, stroke: 1.5 })
|
|
1889
|
+
}
|
|
1890
|
+
),
|
|
1891
|
+
children: [
|
|
1892
|
+
rows,
|
|
1893
|
+
rows && own && /* @__PURE__ */ jsx27(MenuSeparator, {}),
|
|
1894
|
+
own
|
|
1895
|
+
]
|
|
1896
|
+
}
|
|
1897
|
+
) })
|
|
1379
1898
|
]
|
|
1380
1899
|
}
|
|
1381
1900
|
);
|
|
@@ -1383,9 +1902,9 @@ function BlockHandle({ actions, editing, children, className }) {
|
|
|
1383
1902
|
|
|
1384
1903
|
// src/Checkbox.tsx
|
|
1385
1904
|
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
1386
|
-
import { Field as
|
|
1905
|
+
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1387
1906
|
import { IconCheck } from "@tabler/icons-react";
|
|
1388
|
-
import { jsx as
|
|
1907
|
+
import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1389
1908
|
function squareClasses(checked, disabled, interactive, className) {
|
|
1390
1909
|
return cn(
|
|
1391
1910
|
"inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
|
|
@@ -1402,14 +1921,14 @@ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, row
|
|
|
1402
1921
|
const formBusy = useFormBusy();
|
|
1403
1922
|
const disabled = ownDisabled || formBusy;
|
|
1404
1923
|
if (!onChange) {
|
|
1405
|
-
const picture = /* @__PURE__ */
|
|
1924
|
+
const picture = /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx28("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx28(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
1406
1925
|
if (label === void 0) return picture;
|
|
1407
|
-
return /* @__PURE__ */
|
|
1926
|
+
return /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-2", children: [
|
|
1408
1927
|
picture,
|
|
1409
|
-
/* @__PURE__ */
|
|
1928
|
+
/* @__PURE__ */ jsx28("span", { className: WORDS_CLASSES, children: label })
|
|
1410
1929
|
] });
|
|
1411
1930
|
}
|
|
1412
|
-
const box = /* @__PURE__ */
|
|
1931
|
+
const box = /* @__PURE__ */ jsx28(
|
|
1413
1932
|
BaseCheckbox.Root,
|
|
1414
1933
|
{
|
|
1415
1934
|
checked,
|
|
@@ -1419,372 +1938,69 @@ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, row
|
|
|
1419
1938
|
onCheckedChange: (next) => onChange(next),
|
|
1420
1939
|
onClick: (e) => e.stopPropagation(),
|
|
1421
1940
|
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
1422
|
-
children: /* @__PURE__ */
|
|
1941
|
+
children: /* @__PURE__ */ jsx28(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx28(IconCheck, { size: 12, stroke: 3 }) })
|
|
1423
1942
|
}
|
|
1424
1943
|
);
|
|
1425
1944
|
if (label === void 0) return box;
|
|
1426
1945
|
if (row) {
|
|
1427
|
-
return /* @__PURE__ */
|
|
1946
|
+
return /* @__PURE__ */ jsx28(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn(ROW_CLASSES, checked && "bg-bg-selected", !disabled && "cursor-pointer hover:bg-bg-hover"), children: [
|
|
1428
1947
|
leading,
|
|
1429
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx28("span", { className: cn("flex-1 min-w-0 truncate", WORDS_CLASSES), children: label }),
|
|
1430
1949
|
box
|
|
1431
1950
|
] }) });
|
|
1432
1951
|
}
|
|
1433
|
-
return /* @__PURE__ */
|
|
1952
|
+
return /* @__PURE__ */ jsx28(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
|
|
1434
1953
|
box,
|
|
1435
|
-
/* @__PURE__ */
|
|
1436
|
-
] }) });
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
// src/Chip.tsx
|
|
1440
|
-
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1441
|
-
var typeStyles = {
|
|
1442
|
-
neutral: "bg-bg-inset text-text-primary",
|
|
1443
|
-
brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
|
|
1444
|
-
info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
|
|
1445
|
-
warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
|
|
1446
|
-
success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
|
|
1447
|
-
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
1448
|
-
};
|
|
1449
|
-
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
|
|
1450
|
-
const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
|
|
1451
|
-
const inside = /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1452
|
-
leadingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
1453
|
-
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
1454
|
-
// of growing past it — Ship's project chip on an issue row
|
|
1455
|
-
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
1456
|
-
// `truncate`, because `truncate` is `overflow: hidden` on both axes and
|
|
1457
|
-
// the label's line box (11px under Signal) is tighter than its glyphs —
|
|
1458
|
-
// the screenshot diff caught every descender cut off. `clip` is the
|
|
1459
|
-
// one overflow that leaves the other axis visible. A chip with no cap
|
|
1460
|
-
// draws exactly as before.
|
|
1461
|
-
/* @__PURE__ */ jsx21("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
|
|
1462
|
-
trailingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
1463
|
-
] });
|
|
1464
|
-
if (href) return /* @__PURE__ */ jsx21("a", { href, onClick, className: cn("relative", classes), children: inside });
|
|
1465
|
-
return /* @__PURE__ */ jsx21("div", { className: classes, children: inside });
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
// src/CommandPalette.tsx
|
|
1469
|
-
import {
|
|
1470
|
-
createContext as createContext5,
|
|
1471
|
-
useContext as useContext5,
|
|
1472
|
-
useEffect as useEffect3,
|
|
1473
|
-
useLayoutEffect as useLayoutEffect3,
|
|
1474
|
-
useMemo as useMemo2,
|
|
1475
|
-
useRef as useRef5,
|
|
1476
|
-
useState as useState4
|
|
1477
|
-
} from "react";
|
|
1478
|
-
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1479
|
-
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
1480
|
-
import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
|
|
1481
|
-
|
|
1482
|
-
// src/ChipInput.tsx
|
|
1483
|
-
import { useMemo, useState as useState3 } from "react";
|
|
1484
|
-
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
1485
|
-
import { Combobox } from "@base-ui/react/combobox";
|
|
1486
|
-
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1487
|
-
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1488
|
-
var CHIP_BOX = (
|
|
1489
|
-
// Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
|
|
1490
|
-
// rounded-sm corners — never a forced circle — and the chip's corner
|
|
1491
|
-
// follows concentrically: 4px face + 2px inset = rounded-md.
|
|
1492
|
-
"inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
|
|
1493
|
-
);
|
|
1494
|
-
var CHIP_LABEL = "text-caption font-medium text-text-primary";
|
|
1495
|
-
var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
|
|
1496
|
-
var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
|
|
1497
|
-
function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
|
|
1498
|
-
return /* @__PURE__ */ jsxs15("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
|
|
1499
|
-
leading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
1500
|
-
/* @__PURE__ */ jsx22("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
|
|
1501
|
-
onRemove && /* @__PURE__ */ jsx22(
|
|
1502
|
-
BaseButton4,
|
|
1503
|
-
{
|
|
1504
|
-
type: "button",
|
|
1505
|
-
onClick: (e) => {
|
|
1506
|
-
e.stopPropagation();
|
|
1507
|
-
onRemove();
|
|
1508
|
-
},
|
|
1509
|
-
className: cn(CHIP_REMOVE, truncate && "shrink-0"),
|
|
1510
|
-
"aria-label": removeLabel ?? `Remove ${label}`,
|
|
1511
|
-
children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 })
|
|
1512
|
-
}
|
|
1513
|
-
)
|
|
1514
|
-
] });
|
|
1515
|
-
}
|
|
1516
|
-
function ChipInput({
|
|
1517
|
-
value,
|
|
1518
|
-
onChange,
|
|
1519
|
-
options,
|
|
1520
|
-
placeholder = "Search\u2026",
|
|
1521
|
-
autoFocus,
|
|
1522
|
-
excludeIds = [],
|
|
1523
|
-
chipLeading,
|
|
1524
|
-
rowLeading,
|
|
1525
|
-
...aria
|
|
1526
|
-
}) {
|
|
1527
|
-
const [query, setQuery] = useState3("");
|
|
1528
|
-
const [box, setBox] = useState3(null);
|
|
1529
|
-
const available = useMemo(() => {
|
|
1530
|
-
const chosen = new Set(value.map((o) => o.id));
|
|
1531
|
-
const excluded = new Set(excludeIds);
|
|
1532
|
-
return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
|
|
1533
|
-
}, [options, value, excludeIds]);
|
|
1534
|
-
const filter = useMemo(
|
|
1535
|
-
() => (item, q) => {
|
|
1536
|
-
const needle = q.trim().toLowerCase();
|
|
1537
|
-
if (!needle) return true;
|
|
1538
|
-
return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
|
|
1539
|
-
},
|
|
1540
|
-
[]
|
|
1541
|
-
);
|
|
1542
|
-
const open = query.trim().length > 0;
|
|
1543
|
-
const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
|
|
1544
|
-
const naming = {
|
|
1545
|
-
...ariaLabel !== void 0 && { "aria-label": ariaLabel },
|
|
1546
|
-
...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
|
|
1547
|
-
};
|
|
1548
|
-
function removeLast() {
|
|
1549
|
-
if (value.length > 0) onChange(value.slice(0, -1));
|
|
1550
|
-
}
|
|
1551
|
-
function onInputKeyDown(event) {
|
|
1552
|
-
if (event.key === "Backspace" && query === "" && value.length > 0) {
|
|
1553
|
-
event.preventDefault();
|
|
1554
|
-
event.stopPropagation();
|
|
1555
|
-
removeLast();
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
|
-
if (event.key === "Escape" && query !== "") {
|
|
1559
|
-
event.preventDefault();
|
|
1560
|
-
event.stopPropagation();
|
|
1561
|
-
setQuery("");
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
return /* @__PURE__ */ jsxs15(
|
|
1565
|
-
Combobox.Root,
|
|
1566
|
-
{
|
|
1567
|
-
multiple: true,
|
|
1568
|
-
items: available,
|
|
1569
|
-
value,
|
|
1570
|
-
onValueChange: (next) => {
|
|
1571
|
-
onChange(next);
|
|
1572
|
-
setQuery("");
|
|
1573
|
-
},
|
|
1574
|
-
inputValue: query,
|
|
1575
|
-
onInputValueChange: setQuery,
|
|
1576
|
-
open,
|
|
1577
|
-
openOnInputClick: false,
|
|
1578
|
-
filter,
|
|
1579
|
-
itemToStringLabel: (option) => option.label,
|
|
1580
|
-
children: [
|
|
1581
|
-
/* @__PURE__ */ jsxs15(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
|
|
1582
|
-
value.map((option) => /* @__PURE__ */ jsxs15(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
|
|
1583
|
-
chipLeading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
|
|
1584
|
-
/* @__PURE__ */ jsx22("span", { className: CHIP_LABEL, children: option.label }),
|
|
1585
|
-
/* @__PURE__ */ jsx22(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 }) })
|
|
1586
|
-
] }, option.id)),
|
|
1587
|
-
/* @__PURE__ */ jsx22(
|
|
1588
|
-
Combobox.Input,
|
|
1589
|
-
{
|
|
1590
|
-
autoFocus,
|
|
1591
|
-
placeholder: value.length === 0 ? placeholder : "",
|
|
1592
|
-
"aria-required": aria["aria-required"],
|
|
1593
|
-
...naming,
|
|
1594
|
-
onKeyDown: onInputKeyDown,
|
|
1595
|
-
className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
|
|
1596
|
-
}
|
|
1597
|
-
)
|
|
1598
|
-
] }),
|
|
1599
|
-
/* @__PURE__ */ jsx22(Combobox.Portal, { children: /* @__PURE__ */ jsx22(
|
|
1600
|
-
Combobox.Positioner,
|
|
1601
|
-
{
|
|
1602
|
-
anchor: box,
|
|
1603
|
-
sideOffset: GAP3,
|
|
1604
|
-
collisionPadding: VIEWPORT_PAD3,
|
|
1605
|
-
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1606
|
-
children: /* @__PURE__ */ jsx22(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx22(MenuPanel, {}), children: /* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx22(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx22(
|
|
1607
|
-
Combobox.Item,
|
|
1608
|
-
{
|
|
1609
|
-
value: option,
|
|
1610
|
-
render: /* @__PURE__ */ jsx22(
|
|
1611
|
-
MenuItem,
|
|
1612
|
-
{
|
|
1613
|
-
size: "tall",
|
|
1614
|
-
leading: rowLeading?.(option),
|
|
1615
|
-
label: option.label,
|
|
1616
|
-
description: option.description
|
|
1617
|
-
}
|
|
1618
|
-
)
|
|
1619
|
-
},
|
|
1620
|
-
option.id
|
|
1621
|
-
) }) }) })
|
|
1622
|
-
}
|
|
1623
|
-
) })
|
|
1624
|
-
]
|
|
1625
|
-
}
|
|
1626
|
-
);
|
|
1954
|
+
/* @__PURE__ */ jsx28("span", { className: WORDS_CLASSES, children: label })
|
|
1955
|
+
] }) });
|
|
1627
1956
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1957
|
+
|
|
1958
|
+
// src/CommandPalette.tsx
|
|
1959
|
+
import {
|
|
1960
|
+
createContext as createContext5,
|
|
1961
|
+
useContext as useContext5,
|
|
1962
|
+
useEffect as useEffect3,
|
|
1963
|
+
useLayoutEffect as useLayoutEffect3,
|
|
1964
|
+
useMemo as useMemo2,
|
|
1965
|
+
useRef as useRef6,
|
|
1966
|
+
useState as useState5
|
|
1967
|
+
} from "react";
|
|
1968
|
+
import { Dialog as Dialog3 } from "@base-ui/react/dialog";
|
|
1969
|
+
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
1970
|
+
import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
|
|
1630
1971
|
|
|
1631
1972
|
// src/EmptyState.tsx
|
|
1632
1973
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1633
|
-
import { jsx as
|
|
1974
|
+
import { jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1634
1975
|
function EmptyState({ icon, message, scope = "page", action, className }) {
|
|
1635
1976
|
if (scope === "section") {
|
|
1636
|
-
return /* @__PURE__ */
|
|
1977
|
+
return /* @__PURE__ */ jsx29("p", { className: cn("text-caption text-text-muted", className), children: message });
|
|
1637
1978
|
}
|
|
1638
|
-
return /* @__PURE__ */
|
|
1639
|
-
/* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
action && /* @__PURE__ */
|
|
1979
|
+
return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
1980
|
+
/* @__PURE__ */ jsx29("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx29(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1981
|
+
/* @__PURE__ */ jsx29("p", { className: "text-body-2 text-text-secondary text-center", children: message }),
|
|
1982
|
+
action && /* @__PURE__ */ jsx29(Button, { variant: "outlined", className: "mt-2", onClick: action.onClick, children: action.label })
|
|
1642
1983
|
] });
|
|
1643
1984
|
}
|
|
1644
1985
|
|
|
1645
|
-
// src/Field.tsx
|
|
1646
|
-
import { cloneElement, isValidElement } from "react";
|
|
1647
|
-
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1648
|
-
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1649
|
-
var LINE_STYLES = {
|
|
1650
|
-
helper: "text-caption text-text-muted",
|
|
1651
|
-
warning: "text-caption text-warning-default",
|
|
1652
|
-
error: "text-caption text-error-default"
|
|
1653
|
-
};
|
|
1654
|
-
function Field({ label, required = false, helper, error, children }) {
|
|
1655
|
-
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1656
|
-
"aria-required": children.props["aria-required"] ?? true
|
|
1657
|
-
}) : children;
|
|
1658
|
-
return (
|
|
1659
|
-
// `group/field`: the label, the box and the line under it are one thing under the pointer —
|
|
1660
|
-
// anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
|
|
1661
|
-
// Before, the 8px between the label and the box was a gap where the border went out again.
|
|
1662
|
-
/* @__PURE__ */ jsxs17(BaseField2.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
|
|
1663
|
-
/* @__PURE__ */ jsxs17(BaseField2.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1664
|
-
label,
|
|
1665
|
-
required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1666
|
-
] }),
|
|
1667
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-1.5", children: [
|
|
1668
|
-
control,
|
|
1669
|
-
error != null ? /* @__PURE__ */ jsx24(BaseField2.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField2.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1670
|
-
] })
|
|
1671
|
-
] })
|
|
1672
|
-
);
|
|
1673
|
-
}
|
|
1674
|
-
function FieldLine({ tone = "helper", children, className }) {
|
|
1675
|
-
return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
// src/Form.tsx
|
|
1679
|
-
import { useLayoutEffect as useLayoutEffect2, useRef as useRef4 } from "react";
|
|
1680
|
-
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1681
|
-
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1682
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1683
|
-
var FIELDS_CLASSES = "flex flex-col gap-6";
|
|
1684
|
-
var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1685
|
-
var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1686
|
-
function usable(element) {
|
|
1687
|
-
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1688
|
-
}
|
|
1689
|
-
function firstInvalid(form) {
|
|
1690
|
-
for (const marked of form.querySelectorAll("[data-invalid]")) {
|
|
1691
|
-
if (usable(marked)) return marked;
|
|
1692
|
-
const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
|
|
1693
|
-
if (inside) return inside;
|
|
1694
|
-
}
|
|
1695
|
-
return void 0;
|
|
1696
|
-
}
|
|
1697
|
-
function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
|
|
1698
|
-
const outerBusy = useFormBusy();
|
|
1699
|
-
const busy = ownBusy || outerBusy;
|
|
1700
|
-
const form = useRef4(null);
|
|
1701
|
-
const busyNow = useRef4(busy);
|
|
1702
|
-
busyNow.current = busy;
|
|
1703
|
-
const sender = useRef4(null);
|
|
1704
|
-
const holding = useRef4(false);
|
|
1705
|
-
const lastInside = useRef4(null);
|
|
1706
|
-
useLayoutEffect2(() => {
|
|
1707
|
-
const element = form.current;
|
|
1708
|
-
if (!element) return;
|
|
1709
|
-
if (busy) {
|
|
1710
|
-
const active = document.activeElement;
|
|
1711
|
-
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1712
|
-
if (from?.isConnected) {
|
|
1713
|
-
sender.current = from;
|
|
1714
|
-
holding.current = true;
|
|
1715
|
-
element.focus();
|
|
1716
|
-
}
|
|
1717
|
-
return;
|
|
1718
|
-
}
|
|
1719
|
-
if (!holding.current) return;
|
|
1720
|
-
holding.current = false;
|
|
1721
|
-
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1722
|
-
const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
|
|
1723
|
-
sender.current = null;
|
|
1724
|
-
target?.focus();
|
|
1725
|
-
}, [busy]);
|
|
1726
|
-
const onKeyDown = (event) => {
|
|
1727
|
-
props.onKeyDown?.(event);
|
|
1728
|
-
if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
|
|
1729
|
-
const target = event.target;
|
|
1730
|
-
const inInput = target instanceof HTMLInputElement;
|
|
1731
|
-
if (inInput) event.preventDefault();
|
|
1732
|
-
if (event.altKey || event.shiftKey) return;
|
|
1733
|
-
if (event.ctrlKey || event.metaKey) {
|
|
1734
|
-
event.preventDefault();
|
|
1735
|
-
form.current?.requestSubmit();
|
|
1736
|
-
return;
|
|
1737
|
-
}
|
|
1738
|
-
if (!inInput) return;
|
|
1739
|
-
const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
|
|
1740
|
-
if (enterSends && oneLine) form.current?.requestSubmit();
|
|
1741
|
-
};
|
|
1742
|
-
return /* @__PURE__ */ jsx25(
|
|
1743
|
-
BaseForm,
|
|
1744
|
-
{
|
|
1745
|
-
ref: form,
|
|
1746
|
-
...props,
|
|
1747
|
-
tabIndex: busy ? -1 : props.tabIndex,
|
|
1748
|
-
className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
|
|
1749
|
-
onFocus: (event) => {
|
|
1750
|
-
if (event.target !== form.current) lastInside.current = event.target;
|
|
1751
|
-
props.onFocus?.(event);
|
|
1752
|
-
},
|
|
1753
|
-
onBlur: (event) => {
|
|
1754
|
-
const next = event.relatedTarget;
|
|
1755
|
-
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1756
|
-
props.onBlur?.(event);
|
|
1757
|
-
},
|
|
1758
|
-
onKeyDown,
|
|
1759
|
-
onSubmit: (event) => {
|
|
1760
|
-
if (event.target !== event.currentTarget) return;
|
|
1761
|
-
event.preventDefault();
|
|
1762
|
-
if (busyNow.current) return;
|
|
1763
|
-
void onSubmit();
|
|
1764
|
-
},
|
|
1765
|
-
children: /* @__PURE__ */ jsx25(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx25(FormBusyContext.Provider, { value: busy, children }) })
|
|
1766
|
-
}
|
|
1767
|
-
);
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
1986
|
// src/Skeleton.tsx
|
|
1771
|
-
import { jsx as
|
|
1987
|
+
import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1772
1988
|
function SkeletonBar({ className, style }) {
|
|
1773
|
-
return /* @__PURE__ */
|
|
1989
|
+
return /* @__PURE__ */ jsx30("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1774
1990
|
}
|
|
1775
1991
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1776
1992
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1777
|
-
return /* @__PURE__ */
|
|
1778
|
-
/* @__PURE__ */
|
|
1779
|
-
/* @__PURE__ */
|
|
1993
|
+
return /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1994
|
+
/* @__PURE__ */ jsx30(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1995
|
+
/* @__PURE__ */ jsx30(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1780
1996
|
] });
|
|
1781
1997
|
}
|
|
1782
1998
|
function SkeletonList({ rows = 8, className }) {
|
|
1783
|
-
return /* @__PURE__ */
|
|
1999
|
+
return /* @__PURE__ */ jsx30("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx30(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1784
2000
|
}
|
|
1785
2001
|
|
|
1786
2002
|
// src/CommandPalette.tsx
|
|
1787
|
-
import { Fragment as
|
|
2003
|
+
import { Fragment as Fragment6, jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1788
2004
|
var PaletteContext = createContext5(null);
|
|
1789
2005
|
function usePalette(part) {
|
|
1790
2006
|
const palette = useContext5(PaletteContext);
|
|
@@ -1799,7 +2015,7 @@ function firstControl(popup) {
|
|
|
1799
2015
|
return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL2) ?? null;
|
|
1800
2016
|
}
|
|
1801
2017
|
function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
|
|
1802
|
-
const popupRef =
|
|
2018
|
+
const popupRef = useRef6(null);
|
|
1803
2019
|
useEffect3(() => {
|
|
1804
2020
|
if (!open) return;
|
|
1805
2021
|
const frame = requestAnimationFrame(() => {
|
|
@@ -1810,10 +2026,10 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1810
2026
|
return () => cancelAnimationFrame(frame);
|
|
1811
2027
|
});
|
|
1812
2028
|
const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
|
|
1813
|
-
return /* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
|
|
2029
|
+
return /* @__PURE__ */ jsx31(Dialog3.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs23(Dialog3.Portal, { children: [
|
|
2030
|
+
/* @__PURE__ */ jsx31(Dialog3.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
2031
|
+
/* @__PURE__ */ jsx31(Dialog3.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx31(
|
|
2032
|
+
Dialog3.Popup,
|
|
1817
2033
|
{
|
|
1818
2034
|
ref: popupRef,
|
|
1819
2035
|
"aria-label": label,
|
|
@@ -1822,13 +2038,13 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1822
2038
|
if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
|
|
1823
2039
|
},
|
|
1824
2040
|
className: "flex w-[658px] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-lg border border-border-default bg-bg-elevated shadow-lg outline-none",
|
|
1825
|
-
children: /* @__PURE__ */
|
|
2041
|
+
children: /* @__PURE__ */ jsx31(PaletteContext.Provider, { value: context, children })
|
|
1826
2042
|
}
|
|
1827
2043
|
) })
|
|
1828
2044
|
] }) });
|
|
1829
2045
|
}
|
|
1830
2046
|
function LevelChip({ chip, onBack }) {
|
|
1831
|
-
return /* @__PURE__ */
|
|
2047
|
+
return /* @__PURE__ */ jsx31(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
|
|
1832
2048
|
}
|
|
1833
2049
|
function useBack(chip, popupRef) {
|
|
1834
2050
|
return () => {
|
|
@@ -1839,10 +2055,10 @@ function useBack(chip, popupRef) {
|
|
|
1839
2055
|
}
|
|
1840
2056
|
function Footer({ keys }) {
|
|
1841
2057
|
const { where } = usePalette("The footer");
|
|
1842
|
-
return /* @__PURE__ */
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
keys.map(([key, word]) => /* @__PURE__ */
|
|
1845
|
-
/* @__PURE__ */
|
|
2058
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5", MONO_CAPTION_CLASSES, "signal:text-text-muted leaf:font-mono leaf:text-small"), children: [
|
|
2059
|
+
/* @__PURE__ */ jsx31("span", { className: "min-w-0 flex-1 truncate", children: where }),
|
|
2060
|
+
keys.map(([key, word]) => /* @__PURE__ */ jsxs23("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
2061
|
+
/* @__PURE__ */ jsx31(Kbd, { children: key }),
|
|
1846
2062
|
" ",
|
|
1847
2063
|
word
|
|
1848
2064
|
] }, key))
|
|
@@ -1854,12 +2070,12 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1854
2070
|
const back = useBack(chip, popupRef);
|
|
1855
2071
|
const items = useMemo2(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
|
|
1856
2072
|
const rows = items.flatMap((g) => g.items);
|
|
1857
|
-
const [litId, setLitId] =
|
|
2073
|
+
const [litId, setLitId] = useState5();
|
|
1858
2074
|
const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
|
|
1859
|
-
const inputRef =
|
|
1860
|
-
const reported =
|
|
1861
|
-
const settled =
|
|
1862
|
-
const moved =
|
|
2075
|
+
const inputRef = useRef6(null);
|
|
2076
|
+
const reported = useRef6({});
|
|
2077
|
+
const settled = useRef6(null);
|
|
2078
|
+
const moved = useRef6(false);
|
|
1863
2079
|
useLayoutEffect3(() => {
|
|
1864
2080
|
const before = settled.current;
|
|
1865
2081
|
const now = reported.current;
|
|
@@ -1919,7 +2135,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1919
2135
|
...chip && query === "" ? [["Backspace", "back"]] : [],
|
|
1920
2136
|
["Esc", "close"]
|
|
1921
2137
|
];
|
|
1922
|
-
return /* @__PURE__ */
|
|
2138
|
+
return /* @__PURE__ */ jsxs23(
|
|
1923
2139
|
Autocomplete.Root,
|
|
1924
2140
|
{
|
|
1925
2141
|
items,
|
|
@@ -1942,10 +2158,10 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1942
2158
|
setLitId(id);
|
|
1943
2159
|
},
|
|
1944
2160
|
children: [
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
chip && /* @__PURE__ */
|
|
1948
|
-
/* @__PURE__ */
|
|
2161
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
2162
|
+
/* @__PURE__ */ jsx31(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
2163
|
+
chip && /* @__PURE__ */ jsx31(LevelChip, { chip, onBack: back }),
|
|
2164
|
+
/* @__PURE__ */ jsx31(
|
|
1949
2165
|
Autocomplete.Input,
|
|
1950
2166
|
{
|
|
1951
2167
|
ref: inputRef,
|
|
@@ -1957,43 +2173,43 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1957
2173
|
}
|
|
1958
2174
|
)
|
|
1959
2175
|
] }),
|
|
1960
|
-
/* @__PURE__ */
|
|
1961
|
-
children != null && /* @__PURE__ */
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
/* @__PURE__ */
|
|
2176
|
+
/* @__PURE__ */ jsxs23(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
2177
|
+
children != null && /* @__PURE__ */ jsx31("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
2178
|
+
/* @__PURE__ */ jsx31(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs23(Autocomplete.Group, { items: group.items, className: "flex flex-col gap-0.5", children: [
|
|
2179
|
+
/* @__PURE__ */ jsx31(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx31(SectionLabel, { tone: "secondary", children: group.value }) }),
|
|
2180
|
+
/* @__PURE__ */ jsx31(Autocomplete.Collection, { children: (row) => (
|
|
1965
2181
|
/* The menu row, as the list's own option — the way Select
|
|
1966
2182
|
puts it on `Select.Item`. One row, two parts. */
|
|
1967
|
-
/* @__PURE__ */
|
|
2183
|
+
/* @__PURE__ */ jsx31(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx31(
|
|
1968
2184
|
MenuItemBody,
|
|
1969
2185
|
{
|
|
1970
2186
|
size: "tall",
|
|
1971
2187
|
label: row.label,
|
|
1972
2188
|
description: row.description,
|
|
1973
|
-
leading: /* @__PURE__ */
|
|
2189
|
+
leading: /* @__PURE__ */ jsx31(RowLeading, { row }),
|
|
1974
2190
|
submenu: !!row.onGoIn,
|
|
1975
|
-
hint: row.onGoIn ? /* @__PURE__ */
|
|
2191
|
+
hint: row.onGoIn ? /* @__PURE__ */ jsx31(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx31(EnterHint, {})
|
|
1976
2192
|
}
|
|
1977
2193
|
) }, row.id)
|
|
1978
2194
|
) })
|
|
1979
2195
|
] }, group.value) }),
|
|
1980
|
-
/* @__PURE__ */
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
2196
|
+
/* @__PURE__ */ jsx31(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs23(Fragment6, { children: [
|
|
2197
|
+
/* @__PURE__ */ jsx31(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
2198
|
+
/* @__PURE__ */ jsx31("span", { className: "text-caption text-text-muted", children: pending })
|
|
1983
2199
|
] }) }),
|
|
1984
|
-
notes.map((note) => /* @__PURE__ */
|
|
1985
|
-
/* @__PURE__ */
|
|
2200
|
+
notes.map((note) => /* @__PURE__ */ jsx31("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx31(FieldLine, { children: note }) }, note)),
|
|
2201
|
+
/* @__PURE__ */ jsx31(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx31(EmptyState, { scope: "section", message: empty }) })
|
|
1986
2202
|
] }),
|
|
1987
|
-
/* @__PURE__ */
|
|
2203
|
+
/* @__PURE__ */ jsx31(Footer, { keys })
|
|
1988
2204
|
]
|
|
1989
2205
|
}
|
|
1990
2206
|
);
|
|
1991
2207
|
}
|
|
1992
2208
|
function RowLeading({ row }) {
|
|
1993
2209
|
if (row.icon != null) {
|
|
1994
|
-
return /* @__PURE__ */
|
|
2210
|
+
return /* @__PURE__ */ jsx31("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
|
|
1995
2211
|
}
|
|
1996
|
-
return /* @__PURE__ */
|
|
2212
|
+
return /* @__PURE__ */ jsx31("span", { className: "flex size-8 items-center justify-center", children: row.leading });
|
|
1997
2213
|
}
|
|
1998
2214
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1999
2215
|
function isTextField(el) {
|
|
@@ -2003,9 +2219,9 @@ function isTextField(el) {
|
|
|
2003
2219
|
function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
|
|
2004
2220
|
const { modKey, popupRef } = usePalette("CommandPaletteForm");
|
|
2005
2221
|
const back = useBack(chip, popupRef);
|
|
2006
|
-
const frameRef =
|
|
2222
|
+
const frameRef = useRef6(null);
|
|
2007
2223
|
const busy = !!working;
|
|
2008
|
-
const busyRef =
|
|
2224
|
+
const busyRef = useRef6(busy);
|
|
2009
2225
|
busyRef.current = busy;
|
|
2010
2226
|
const firstInvalid2 = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL2) ?? null;
|
|
2011
2227
|
const submit = () => {
|
|
@@ -2021,7 +2237,7 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
2021
2237
|
if (isTextField(el)) return el.value === "";
|
|
2022
2238
|
return ![...frame.querySelectorAll("input, textarea")].some(isTextField);
|
|
2023
2239
|
};
|
|
2024
|
-
const [backNamed, setBackNamed] =
|
|
2240
|
+
const [backNamed, setBackNamed] = useState5(false);
|
|
2025
2241
|
const measure = () => setBackNamed(backWorksFrom(document.activeElement));
|
|
2026
2242
|
useLayoutEffect3(measure);
|
|
2027
2243
|
const onKeyDown = (e) => {
|
|
@@ -2035,65 +2251,65 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
2035
2251
|
...backNamed ? [["Backspace", "back"]] : [],
|
|
2036
2252
|
["Esc", "close"]
|
|
2037
2253
|
];
|
|
2038
|
-
return /* @__PURE__ */
|
|
2039
|
-
/* @__PURE__ */
|
|
2040
|
-
icon != null && /* @__PURE__ */
|
|
2041
|
-
/* @__PURE__ */
|
|
2254
|
+
return /* @__PURE__ */ jsxs23("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
|
|
2255
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
2256
|
+
icon != null && /* @__PURE__ */ jsx31("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
2257
|
+
/* @__PURE__ */ jsx31(LevelChip, { chip, onBack: back })
|
|
2042
2258
|
] }),
|
|
2043
|
-
/* @__PURE__ */
|
|
2044
|
-
/* @__PURE__ */
|
|
2045
|
-
/* @__PURE__ */
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
2259
|
+
/* @__PURE__ */ jsxs23(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, layout: "free", className: "flex min-h-0 flex-col", children: [
|
|
2260
|
+
/* @__PURE__ */ jsx31(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx31("div", { className: FIELDS_CLASSES, children }) }),
|
|
2261
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
2262
|
+
/* @__PURE__ */ jsx31("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx31(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx31(FieldLine, { tone: "error", children: error }) : null }),
|
|
2263
|
+
/* @__PURE__ */ jsx31(
|
|
2048
2264
|
Button,
|
|
2049
2265
|
{
|
|
2050
2266
|
type: "submit",
|
|
2051
2267
|
variant: "primary",
|
|
2052
2268
|
disabled: busy,
|
|
2053
2269
|
disabledReason: busy ? void 0 : submitWaits,
|
|
2054
|
-
leadingIcon: busy ? /* @__PURE__ */
|
|
2270
|
+
leadingIcon: busy ? /* @__PURE__ */ jsx31(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
|
|
2055
2271
|
children: working ? working.button : submitLabel
|
|
2056
2272
|
}
|
|
2057
2273
|
)
|
|
2058
2274
|
] })
|
|
2059
2275
|
] }),
|
|
2060
|
-
/* @__PURE__ */
|
|
2276
|
+
/* @__PURE__ */ jsx31(Footer, { keys })
|
|
2061
2277
|
] });
|
|
2062
2278
|
}
|
|
2063
2279
|
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
2064
2280
|
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
2065
|
-
return /* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2281
|
+
return /* @__PURE__ */ jsxs23("div", { role: "status", className: "flex flex-col gap-2", children: [
|
|
2282
|
+
/* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
2283
|
+
/* @__PURE__ */ jsx31(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
2068
2284
|
children
|
|
2069
2285
|
] }),
|
|
2070
|
-
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */
|
|
2286
|
+
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx31(SkeletonBar, { className: cn("h-3", width) }, width))
|
|
2071
2287
|
] });
|
|
2072
2288
|
}
|
|
2073
2289
|
function CommandPaletteAnswer({ children, note }) {
|
|
2074
2290
|
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
2075
|
-
return /* @__PURE__ */
|
|
2076
|
-
paragraphs.map((paragraph, i) => /* @__PURE__ */
|
|
2077
|
-
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */
|
|
2291
|
+
return /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-2", children: [
|
|
2292
|
+
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx31("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
2293
|
+
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx31("sup", { className: "ml-0.5 font-mono text-small text-accent-text", children: part.slice(1, -1) }, j) : part
|
|
2078
2294
|
) }, i)),
|
|
2079
|
-
note && /* @__PURE__ */
|
|
2295
|
+
note && /* @__PURE__ */ jsx31(FieldLine, { children: note })
|
|
2080
2296
|
] });
|
|
2081
2297
|
}
|
|
2082
2298
|
function CommandPaletteQuote({ children }) {
|
|
2083
|
-
return /* @__PURE__ */
|
|
2299
|
+
return /* @__PURE__ */ jsx31("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
|
|
2084
2300
|
}
|
|
2085
2301
|
function CommandPaletteProposal({ source, mark, children }) {
|
|
2086
|
-
return /* @__PURE__ */
|
|
2087
|
-
/* @__PURE__ */
|
|
2302
|
+
return /* @__PURE__ */ jsxs23(Card, { fill: "surface", className: "flex flex-col gap-1 p-3", children: [
|
|
2303
|
+
/* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
2088
2304
|
mark,
|
|
2089
2305
|
source
|
|
2090
2306
|
] }),
|
|
2091
|
-
/* @__PURE__ */
|
|
2307
|
+
/* @__PURE__ */ jsx31("span", { className: "text-body-2 text-text-primary", children })
|
|
2092
2308
|
] });
|
|
2093
2309
|
}
|
|
2094
2310
|
|
|
2095
2311
|
// src/InlineChip.tsx
|
|
2096
|
-
import { Fragment as
|
|
2312
|
+
import { Fragment as Fragment7, jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2097
2313
|
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";
|
|
2098
2314
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
2099
2315
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -2115,19 +2331,19 @@ function inlineChipClassName(tone, className) {
|
|
|
2115
2331
|
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
2116
2332
|
}
|
|
2117
2333
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
2118
|
-
const body = /* @__PURE__ */
|
|
2119
|
-
icon && /* @__PURE__ */
|
|
2334
|
+
const body = /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
2335
|
+
icon && /* @__PURE__ */ jsx32("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
2120
2336
|
children
|
|
2121
2337
|
] });
|
|
2122
2338
|
const classes = inlineChipClassName(tone, className);
|
|
2123
2339
|
if (href === void 0) {
|
|
2124
|
-
return /* @__PURE__ */
|
|
2340
|
+
return /* @__PURE__ */ jsx32("span", { className: classes, ...props, children: body });
|
|
2125
2341
|
}
|
|
2126
|
-
return /* @__PURE__ */
|
|
2342
|
+
return /* @__PURE__ */ jsx32("a", { href, className: classes, ...props, children: body });
|
|
2127
2343
|
}
|
|
2128
2344
|
|
|
2129
2345
|
// src/RichText.tsx
|
|
2130
|
-
import { Fragment as
|
|
2346
|
+
import { Fragment as Fragment8, jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2131
2347
|
var RICH_TEXT_CLASSES = {
|
|
2132
2348
|
base: "flex flex-col gap-1 break-words text-text-secondary",
|
|
2133
2349
|
/* A heading binds to what follows it: 12px above (8 and the 4px gap), 8px below (4 and the gap); two headings in a row, 12px apart. Level 3 keeps the text's colour, one step lower. */
|
|
@@ -2159,35 +2375,35 @@ function textWithLinks(text, renderText) {
|
|
|
2159
2375
|
return parts.map((part, i) => {
|
|
2160
2376
|
const written = part.match(WRITTEN_LINK);
|
|
2161
2377
|
if (written) {
|
|
2162
|
-
return /* @__PURE__ */
|
|
2378
|
+
return /* @__PURE__ */ jsx33("span", { className: "break-words", children: /* @__PURE__ */ jsx33(Link, { href: written[2], external: true, onClick: keepToLink, children: written[1] }) }, i);
|
|
2163
2379
|
}
|
|
2164
2380
|
const bare = i % 2 === 1 ? part.match(BARE_LINK) : null;
|
|
2165
2381
|
if (bare) {
|
|
2166
2382
|
return (
|
|
2167
2383
|
// An address has no spaces to wrap at, so it may break anywhere.
|
|
2168
|
-
/* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2384
|
+
/* @__PURE__ */ jsxs25("span", { className: "break-all", children: [
|
|
2385
|
+
/* @__PURE__ */ jsx33(Link, { href: bare[1], external: true, onClick: keepToLink, children: bare[1] }),
|
|
2170
2386
|
bare[2]
|
|
2171
2387
|
] }, i)
|
|
2172
2388
|
);
|
|
2173
2389
|
}
|
|
2174
|
-
return part ? /* @__PURE__ */
|
|
2390
|
+
return part ? /* @__PURE__ */ jsx33("span", { children: renderText(part) }, i) : null;
|
|
2175
2391
|
});
|
|
2176
2392
|
}
|
|
2177
2393
|
function Runs({ runs, draw }) {
|
|
2178
|
-
return /* @__PURE__ */
|
|
2179
|
-
if (run.reference) return /* @__PURE__ */
|
|
2394
|
+
return /* @__PURE__ */ jsx33(Fragment8, { children: (runs ?? []).map((run, i) => {
|
|
2395
|
+
if (run.reference) return /* @__PURE__ */ jsx33("span", { children: draw.renderReference(run.reference, run) }, i);
|
|
2180
2396
|
if (run.marks.includes("code")) {
|
|
2181
|
-
return /* @__PURE__ */
|
|
2397
|
+
return /* @__PURE__ */ jsx33("code", { children: run.text }, i);
|
|
2182
2398
|
}
|
|
2183
|
-
let node = run.text.split("\n").map((line, j) => /* @__PURE__ */
|
|
2184
|
-
j > 0 && /* @__PURE__ */
|
|
2399
|
+
let node = run.text.split("\n").map((line, j) => /* @__PURE__ */ jsxs25("span", { children: [
|
|
2400
|
+
j > 0 && /* @__PURE__ */ jsx33("br", {}),
|
|
2185
2401
|
textWithLinks(line, draw.renderText)
|
|
2186
2402
|
] }, j));
|
|
2187
|
-
if (run.marks.includes("underline")) node = /* @__PURE__ */
|
|
2188
|
-
if (run.marks.includes("italic")) node = /* @__PURE__ */
|
|
2189
|
-
if (run.marks.includes("bold")) node = /* @__PURE__ */
|
|
2190
|
-
return /* @__PURE__ */
|
|
2403
|
+
if (run.marks.includes("underline")) node = /* @__PURE__ */ jsx33("u", { children: node });
|
|
2404
|
+
if (run.marks.includes("italic")) node = /* @__PURE__ */ jsx33("em", { children: node });
|
|
2405
|
+
if (run.marks.includes("bold")) node = /* @__PURE__ */ jsx33("strong", { children: node });
|
|
2406
|
+
return /* @__PURE__ */ jsx33("span", { children: node }, i);
|
|
2191
2407
|
}) });
|
|
2192
2408
|
}
|
|
2193
2409
|
var named = (block) => block.typeName ?? block.type;
|
|
@@ -2198,15 +2414,15 @@ function Table({ block, draw }) {
|
|
|
2198
2414
|
const header = named(cell) === "tableHeader";
|
|
2199
2415
|
const Cell = header ? "th" : "td";
|
|
2200
2416
|
const { colspan, rowspan } = cell.attrs ?? {};
|
|
2201
|
-
return /* @__PURE__ */
|
|
2417
|
+
return /* @__PURE__ */ jsxs25(
|
|
2202
2418
|
Cell,
|
|
2203
2419
|
{
|
|
2204
2420
|
"data-block-id": cell.id,
|
|
2205
2421
|
colSpan: colspan && colspan > 1 ? colspan : void 0,
|
|
2206
2422
|
rowSpan: rowspan && rowspan > 1 ? rowspan : void 0,
|
|
2207
2423
|
children: [
|
|
2208
|
-
(cell.children ?? []).map((child, j) => /* @__PURE__ */
|
|
2209
|
-
/* @__PURE__ */
|
|
2424
|
+
(cell.children ?? []).map((child, j) => /* @__PURE__ */ jsx33(Runs, { runs: child.inline, draw }, j)),
|
|
2425
|
+
/* @__PURE__ */ jsx33(Runs, { runs: cell.inline, draw })
|
|
2210
2426
|
]
|
|
2211
2427
|
},
|
|
2212
2428
|
cell.id ?? i
|
|
@@ -2214,43 +2430,43 @@ function Table({ block, draw }) {
|
|
|
2214
2430
|
});
|
|
2215
2431
|
const first = rows[0].children ?? [];
|
|
2216
2432
|
const headerRow = first.length > 0 && first.every((cell) => named(cell) === "tableHeader");
|
|
2217
|
-
return /* @__PURE__ */
|
|
2218
|
-
headerRow && /* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2433
|
+
return /* @__PURE__ */ jsxs25("table", { "data-block-id": block.id, children: [
|
|
2434
|
+
headerRow && /* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsx33("tr", { "data-block-id": rows[0].id, children: cells(rows[0]) }) }),
|
|
2435
|
+
/* @__PURE__ */ jsx33("tbody", { children: (headerRow ? rows.slice(1) : rows).map((row, i) => /* @__PURE__ */ jsx33("tr", { "data-block-id": row.id, children: cells(row) }, row.id ?? i)) })
|
|
2220
2436
|
] });
|
|
2221
2437
|
}
|
|
2222
2438
|
function Block({ block, draw }) {
|
|
2223
2439
|
const own = draw.renderBlock?.(block);
|
|
2224
2440
|
if (own !== void 0) return own;
|
|
2225
|
-
const runs = /* @__PURE__ */
|
|
2441
|
+
const runs = /* @__PURE__ */ jsx33(Runs, { runs: block.inline, draw });
|
|
2226
2442
|
switch (block.type) {
|
|
2227
2443
|
case "heading": {
|
|
2228
|
-
if (block.level === 1) return /* @__PURE__ */
|
|
2229
|
-
if (block.level === 3) return /* @__PURE__ */
|
|
2230
|
-
return /* @__PURE__ */
|
|
2444
|
+
if (block.level === 1) return /* @__PURE__ */ jsx33("h1", { "data-block-id": block.id, children: runs });
|
|
2445
|
+
if (block.level === 3) return /* @__PURE__ */ jsx33("h3", { "data-block-id": block.id, children: runs });
|
|
2446
|
+
return /* @__PURE__ */ jsx33("h2", { "data-block-id": block.id, children: runs });
|
|
2231
2447
|
}
|
|
2232
2448
|
case "paragraph":
|
|
2233
|
-
return /* @__PURE__ */
|
|
2449
|
+
return /* @__PURE__ */ jsx33("p", { "data-block-id": block.id, children: runs });
|
|
2234
2450
|
case "bulletList":
|
|
2235
2451
|
case "orderedList": {
|
|
2236
|
-
const items = (block.children ?? []).map((item, i) => /* @__PURE__ */
|
|
2237
|
-
return block.type === "bulletList" ? /* @__PURE__ */
|
|
2452
|
+
const items = (block.children ?? []).map((item, i) => /* @__PURE__ */ jsx33("li", { "data-block-id": item.id, children: /* @__PURE__ */ jsx33(Runs, { runs: item.inline, draw }) }, item.id ?? i));
|
|
2453
|
+
return block.type === "bulletList" ? /* @__PURE__ */ jsx33("ul", { "data-block-id": block.id, children: items }) : /* @__PURE__ */ jsx33("ol", { "data-block-id": block.id, start: block.start, children: items });
|
|
2238
2454
|
}
|
|
2239
2455
|
case "blockquote":
|
|
2240
|
-
return /* @__PURE__ */
|
|
2456
|
+
return /* @__PURE__ */ jsx33("blockquote", { "data-block-id": block.id, children: runs });
|
|
2241
2457
|
case "codeBlock":
|
|
2242
|
-
return /* @__PURE__ */
|
|
2458
|
+
return /* @__PURE__ */ jsx33("pre", { "data-block-id": block.id, "data-language": block.language, children: /* @__PURE__ */ jsx33("code", { children: (block.inline ?? []).map((run) => run.text).join("") }) });
|
|
2243
2459
|
case "horizontalRule":
|
|
2244
|
-
return /* @__PURE__ */
|
|
2460
|
+
return /* @__PURE__ */ jsx33("hr", { "data-block-id": block.id });
|
|
2245
2461
|
case "table": {
|
|
2246
|
-
const table = /* @__PURE__ */
|
|
2462
|
+
const table = /* @__PURE__ */ jsx33(Table, { block, draw });
|
|
2247
2463
|
if ((block.children ?? []).some((row) => named(row) === "tableRow")) return table;
|
|
2248
2464
|
break;
|
|
2249
2465
|
}
|
|
2250
2466
|
}
|
|
2251
|
-
return /* @__PURE__ */
|
|
2467
|
+
return /* @__PURE__ */ jsxs25("div", { "data-block-id": block.id, "data-block-type": named(block), children: [
|
|
2252
2468
|
runs,
|
|
2253
|
-
(block.children ?? []).map((child, i) => /* @__PURE__ */
|
|
2469
|
+
(block.children ?? []).map((child, i) => /* @__PURE__ */ jsx33(Block, { block: child, draw }, child.id ?? i))
|
|
2254
2470
|
] });
|
|
2255
2471
|
}
|
|
2256
2472
|
function RichText({
|
|
@@ -2262,34 +2478,34 @@ function RichText({
|
|
|
2262
2478
|
}) {
|
|
2263
2479
|
if (blocks.length === 0) return null;
|
|
2264
2480
|
const draw = { renderText, renderReference, renderBlock };
|
|
2265
|
-
return /* @__PURE__ */
|
|
2481
|
+
return /* @__PURE__ */ jsx33("div", { "data-rich-text": true, className: richTextClassName(size), children: blocks.map((block, i) => /* @__PURE__ */ jsx33(Block, { block, draw }, block.id ?? i)) });
|
|
2266
2482
|
}
|
|
2267
2483
|
|
|
2268
2484
|
// src/IdentityMenu.tsx
|
|
2269
|
-
import { useCallback as useCallback2, useRef as
|
|
2485
|
+
import { useCallback as useCallback2, useRef as useRef7 } from "react";
|
|
2270
2486
|
|
|
2271
2487
|
// src/Person.tsx
|
|
2272
|
-
import { jsx as
|
|
2488
|
+
import { jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2273
2489
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
2274
2490
|
return (
|
|
2275
2491
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
2276
2492
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
2277
2493
|
// row agree by construction.
|
|
2278
|
-
/* @__PURE__ */
|
|
2279
|
-
/* @__PURE__ */
|
|
2280
|
-
/* @__PURE__ */
|
|
2494
|
+
/* @__PURE__ */ jsxs26("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
2495
|
+
/* @__PURE__ */ jsx34(Avatar, { name, src: picture, size }),
|
|
2496
|
+
/* @__PURE__ */ jsx34("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
2281
2497
|
] })
|
|
2282
2498
|
);
|
|
2283
2499
|
}
|
|
2284
2500
|
|
|
2285
2501
|
// src/PersonTrigger.tsx
|
|
2286
|
-
import { Button as
|
|
2287
|
-
import { IconChevronDown } from "@tabler/icons-react";
|
|
2288
|
-
import { jsx as
|
|
2502
|
+
import { Button as BaseButton6 } from "@base-ui/react/button";
|
|
2503
|
+
import { IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
2504
|
+
import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2289
2505
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
2290
2506
|
if (compact) {
|
|
2291
|
-
return /* @__PURE__ */
|
|
2292
|
-
|
|
2507
|
+
return /* @__PURE__ */ jsx35(
|
|
2508
|
+
BaseButton6,
|
|
2293
2509
|
{
|
|
2294
2510
|
type: "button",
|
|
2295
2511
|
"aria-haspopup": "menu",
|
|
@@ -2297,14 +2513,14 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2297
2513
|
"aria-label": props["aria-label"] ?? name ?? fallback,
|
|
2298
2514
|
className: cn("cursor-pointer rounded-full", className),
|
|
2299
2515
|
...props,
|
|
2300
|
-
children: /* @__PURE__ */
|
|
2516
|
+
children: /* @__PURE__ */ jsx35(Avatar, { name, src: picture, size: size ?? 36 })
|
|
2301
2517
|
}
|
|
2302
2518
|
);
|
|
2303
2519
|
}
|
|
2304
2520
|
return (
|
|
2305
2521
|
// @estiva-escape(no-copied-look): N5 (Katerina, 24 September: record only): a row that fills on hover, as NavItem also does
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
|
|
2522
|
+
/* @__PURE__ */ jsxs27(
|
|
2523
|
+
BaseButton6,
|
|
2308
2524
|
{
|
|
2309
2525
|
type: "button",
|
|
2310
2526
|
"aria-haspopup": "menu",
|
|
@@ -2321,8 +2537,8 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2321
2537
|
),
|
|
2322
2538
|
...props,
|
|
2323
2539
|
children: [
|
|
2324
|
-
/* @__PURE__ */
|
|
2325
|
-
/* @__PURE__ */
|
|
2540
|
+
/* @__PURE__ */ jsx35(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
2541
|
+
/* @__PURE__ */ jsx35(IconChevronDown2, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
2326
2542
|
]
|
|
2327
2543
|
}
|
|
2328
2544
|
)
|
|
@@ -2330,10 +2546,10 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
2330
2546
|
}
|
|
2331
2547
|
|
|
2332
2548
|
// src/IdentityMenu.tsx
|
|
2333
|
-
import { Fragment as
|
|
2549
|
+
import { Fragment as Fragment9, jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2334
2550
|
function IdentityPanel({ className, onClose = () => {
|
|
2335
2551
|
}, ...rest }) {
|
|
2336
|
-
return /* @__PURE__ */
|
|
2552
|
+
return /* @__PURE__ */ jsx36(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx36(IdentityRows, { ...rest, onClose }) });
|
|
2337
2553
|
}
|
|
2338
2554
|
function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
|
|
2339
2555
|
const act = (action) => () => {
|
|
@@ -2341,53 +2557,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
2341
2557
|
action();
|
|
2342
2558
|
};
|
|
2343
2559
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
2344
|
-
return /* @__PURE__ */
|
|
2345
|
-
/* @__PURE__ */
|
|
2346
|
-
/* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2348
|
-
me.email && /* @__PURE__ */
|
|
2560
|
+
return /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2561
|
+
/* @__PURE__ */ jsxs28(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
2562
|
+
/* @__PURE__ */ jsx36(MenuRow, { children: /* @__PURE__ */ jsx36("div", { className: "flex min-w-0 text-body-2-strong", children: /* @__PURE__ */ jsx36(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28 }) }) }),
|
|
2563
|
+
/* @__PURE__ */ jsx36(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
|
|
2564
|
+
me.email && /* @__PURE__ */ jsxs28(Note, { children: [
|
|
2349
2565
|
me.email,
|
|
2350
2566
|
" \xB7 known to Estiva, never published to the relay"
|
|
2351
2567
|
] })
|
|
2352
2568
|
] }),
|
|
2353
|
-
relayUrl && /* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
/* @__PURE__ */
|
|
2569
|
+
relayUrl && /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2570
|
+
/* @__PURE__ */ jsx36(Divider, { className: "mx-0 my-2" }),
|
|
2571
|
+
/* @__PURE__ */ jsxs28(MenuSection, { label: "Workspace", children: [
|
|
2572
|
+
/* @__PURE__ */ jsx36(MenuRow, { children: /* @__PURE__ */ jsx36("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
2573
|
+
/* @__PURE__ */ jsx36(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
2358
2574
|
] })
|
|
2359
2575
|
] }),
|
|
2360
|
-
appRows && /* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2576
|
+
appRows && /* @__PURE__ */ jsxs28(Fragment9, { children: [
|
|
2577
|
+
/* @__PURE__ */ jsx36(Divider, { className: "mx-0 my-2" }),
|
|
2362
2578
|
appRows
|
|
2363
2579
|
] }),
|
|
2364
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
2365
|
-
signedIn && idBase && /* @__PURE__ */
|
|
2580
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx36(Divider, { className: "mx-0 my-2" }) : null,
|
|
2581
|
+
signedIn && idBase && /* @__PURE__ */ jsx36(
|
|
2366
2582
|
MenuItem,
|
|
2367
2583
|
{
|
|
2368
2584
|
label: "Edit your profile in Estiva ID",
|
|
2369
2585
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
2370
2586
|
}
|
|
2371
2587
|
),
|
|
2372
|
-
onCopyKey && /* @__PURE__ */
|
|
2373
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
2588
|
+
onCopyKey && /* @__PURE__ */ jsx36(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
2589
|
+
idBase && onSignOut && /* @__PURE__ */ jsx36(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
2374
2590
|
] });
|
|
2375
2591
|
}
|
|
2376
2592
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
2377
|
-
const actions =
|
|
2593
|
+
const actions = useRef7(null);
|
|
2378
2594
|
const close = useCallback2(() => actions.current?.close(), []);
|
|
2379
2595
|
return (
|
|
2380
2596
|
/* The wrapper carries the caller's `className` and nothing else. It used
|
|
2381
2597
|
to be `relative`, because the panel was positioned against it; the panel
|
|
2382
2598
|
hangs from the trigger and portals now, so a positioning context here
|
|
2383
2599
|
would only be a lie about what this box does. */
|
|
2384
|
-
/* @__PURE__ */
|
|
2600
|
+
/* @__PURE__ */ jsx36("div", { className, children: /* @__PURE__ */ jsx36(
|
|
2385
2601
|
Menu,
|
|
2386
2602
|
{
|
|
2387
2603
|
align: "right",
|
|
2388
2604
|
actionsRef: actions,
|
|
2389
2605
|
className: "w-72",
|
|
2390
|
-
trigger: /* @__PURE__ */
|
|
2606
|
+
trigger: /* @__PURE__ */ jsx36(
|
|
2391
2607
|
PersonTrigger,
|
|
2392
2608
|
{
|
|
2393
2609
|
name: me.name,
|
|
@@ -2398,7 +2614,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
2398
2614
|
"aria-label": compact ? "Account menu" : void 0
|
|
2399
2615
|
}
|
|
2400
2616
|
),
|
|
2401
|
-
children: /* @__PURE__ */
|
|
2617
|
+
children: /* @__PURE__ */ jsx36(
|
|
2402
2618
|
IdentityRows,
|
|
2403
2619
|
{
|
|
2404
2620
|
me,
|
|
@@ -2416,14 +2632,14 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
2416
2632
|
);
|
|
2417
2633
|
}
|
|
2418
2634
|
function Note({ children }) {
|
|
2419
|
-
return /* @__PURE__ */
|
|
2635
|
+
return /* @__PURE__ */ jsx36("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
2420
2636
|
}
|
|
2421
2637
|
|
|
2422
2638
|
// src/FilePicker.tsx
|
|
2423
2639
|
import { forwardRef } from "react";
|
|
2424
|
-
import { jsx as
|
|
2640
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
2425
2641
|
var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
2426
|
-
return /* @__PURE__ */
|
|
2642
|
+
return /* @__PURE__ */ jsx37(
|
|
2427
2643
|
"input",
|
|
2428
2644
|
{
|
|
2429
2645
|
ref,
|
|
@@ -2442,9 +2658,9 @@ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
|
2442
2658
|
});
|
|
2443
2659
|
|
|
2444
2660
|
// src/Select.tsx
|
|
2445
|
-
import { IconCheck as IconCheck2, IconChevronDown as
|
|
2661
|
+
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
2446
2662
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
2447
|
-
import { jsx as
|
|
2663
|
+
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2448
2664
|
var GAP4 = 4;
|
|
2449
2665
|
var VIEWPORT_PAD4 = 8;
|
|
2450
2666
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, disabledReason, className, ...aria }) {
|
|
@@ -2452,7 +2668,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2452
2668
|
const held = Boolean(disabledReason);
|
|
2453
2669
|
const trigger = (
|
|
2454
2670
|
// @estiva-escape(no-copied-look): N1 (Katerina, 24 September: record only): Select's box drops the hover while held, so it cannot take FIELD_SHELL_CLASSES as it is
|
|
2455
|
-
/* @__PURE__ */
|
|
2671
|
+
/* @__PURE__ */ jsxs29(
|
|
2456
2672
|
BaseSelect.Trigger,
|
|
2457
2673
|
{
|
|
2458
2674
|
"aria-label": ariaLabel,
|
|
@@ -2485,21 +2701,21 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2485
2701
|
className
|
|
2486
2702
|
),
|
|
2487
2703
|
children: [
|
|
2488
|
-
/* @__PURE__ */
|
|
2489
|
-
selected?.leading && /* @__PURE__ */
|
|
2490
|
-
/* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ jsxs29("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
2705
|
+
selected?.leading && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
2706
|
+
/* @__PURE__ */ jsx38(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
|
|
2491
2707
|
] }),
|
|
2492
|
-
/* @__PURE__ */
|
|
2708
|
+
/* @__PURE__ */ jsx38(
|
|
2493
2709
|
BaseSelect.Icon,
|
|
2494
2710
|
{
|
|
2495
|
-
render: /* @__PURE__ */
|
|
2711
|
+
render: /* @__PURE__ */ jsx38(IconChevronDown3, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2496
2712
|
}
|
|
2497
2713
|
)
|
|
2498
2714
|
]
|
|
2499
2715
|
}
|
|
2500
2716
|
)
|
|
2501
2717
|
);
|
|
2502
|
-
return /* @__PURE__ */
|
|
2718
|
+
return /* @__PURE__ */ jsxs29(
|
|
2503
2719
|
BaseSelect.Root,
|
|
2504
2720
|
{
|
|
2505
2721
|
value,
|
|
@@ -2511,8 +2727,8 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2511
2727
|
disabled: disabled && !held,
|
|
2512
2728
|
modal: false,
|
|
2513
2729
|
children: [
|
|
2514
|
-
held ? /* @__PURE__ */
|
|
2515
|
-
/* @__PURE__ */
|
|
2730
|
+
held ? /* @__PURE__ */ jsx38(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
|
|
2731
|
+
/* @__PURE__ */ jsx38(BaseSelect.Portal, { children: /* @__PURE__ */ jsx38(
|
|
2516
2732
|
BaseSelect.Positioner,
|
|
2517
2733
|
{
|
|
2518
2734
|
side: "bottom",
|
|
@@ -2521,25 +2737,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2521
2737
|
collisionPadding: VIEWPORT_PAD4,
|
|
2522
2738
|
alignItemWithTrigger: false,
|
|
2523
2739
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2524
|
-
children: /* @__PURE__ */
|
|
2740
|
+
children: /* @__PURE__ */ jsx38(
|
|
2525
2741
|
BaseSelect.Popup,
|
|
2526
2742
|
{
|
|
2527
|
-
render: /* @__PURE__ */
|
|
2743
|
+
render: /* @__PURE__ */ jsx38(MenuPanel, {}),
|
|
2528
2744
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
2529
|
-
children: /* @__PURE__ */
|
|
2745
|
+
children: /* @__PURE__ */ jsx38(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col gap-0.5 p-2", children: options.map((option) => /* @__PURE__ */ jsxs29(
|
|
2530
2746
|
BaseSelect.Item,
|
|
2531
2747
|
{
|
|
2532
2748
|
value: option.value,
|
|
2533
2749
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
2534
2750
|
children: [
|
|
2535
|
-
/* @__PURE__ */
|
|
2536
|
-
option.leading && /* @__PURE__ */
|
|
2537
|
-
/* @__PURE__ */
|
|
2751
|
+
/* @__PURE__ */ jsxs29("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2752
|
+
option.leading && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
2753
|
+
/* @__PURE__ */ jsx38(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
|
|
2538
2754
|
] }),
|
|
2539
|
-
/* @__PURE__ */
|
|
2755
|
+
/* @__PURE__ */ jsx38(
|
|
2540
2756
|
BaseSelect.ItemIndicator,
|
|
2541
2757
|
{
|
|
2542
|
-
render: /* @__PURE__ */
|
|
2758
|
+
render: /* @__PURE__ */ jsx38(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2543
2759
|
}
|
|
2544
2760
|
)
|
|
2545
2761
|
]
|
|
@@ -2558,9 +2774,9 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
2558
2774
|
// src/TextInput.tsx
|
|
2559
2775
|
import { forwardRef as forwardRef2 } from "react";
|
|
2560
2776
|
import { Input } from "@base-ui/react/input";
|
|
2561
|
-
import { jsx as
|
|
2777
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
2562
2778
|
var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
|
|
2563
|
-
return /* @__PURE__ */
|
|
2779
|
+
return /* @__PURE__ */ jsx39(
|
|
2564
2780
|
Input,
|
|
2565
2781
|
{
|
|
2566
2782
|
ref,
|
|
@@ -2586,13 +2802,13 @@ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size
|
|
|
2586
2802
|
// src/Textarea.tsx
|
|
2587
2803
|
import { forwardRef as forwardRef3 } from "react";
|
|
2588
2804
|
import { Field as BaseField3 } from "@base-ui/react/field";
|
|
2589
|
-
import { jsx as
|
|
2805
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2590
2806
|
var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
|
|
2591
|
-
return /* @__PURE__ */
|
|
2807
|
+
return /* @__PURE__ */ jsx40(
|
|
2592
2808
|
BaseField3.Control,
|
|
2593
2809
|
{
|
|
2594
2810
|
ref,
|
|
2595
|
-
render: /* @__PURE__ */
|
|
2811
|
+
render: /* @__PURE__ */ jsx40("textarea", {}),
|
|
2596
2812
|
className: cn(
|
|
2597
2813
|
// The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
|
|
2598
2814
|
// "aren't there hover states in text input and text area?"). Focus comes after hover in
|
|
@@ -2611,108 +2827,10 @@ var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
|
|
|
2611
2827
|
});
|
|
2612
2828
|
|
|
2613
2829
|
// src/ConfirmDialog.tsx
|
|
2614
|
-
import { useState as
|
|
2615
|
-
|
|
2616
|
-
// src/DialogShell.tsx
|
|
2617
|
-
import { useRef as useRef7 } from "react";
|
|
2618
|
-
import { Dialog as Dialog3 } from "@base-ui/react/dialog";
|
|
2619
|
-
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
2620
|
-
import { IconX as IconX5 } from "@tabler/icons-react";
|
|
2621
|
-
|
|
2622
|
-
// src/ContainerHeader.tsx
|
|
2623
|
-
import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
|
|
2624
|
-
import { Button as BaseButton6 } from "@base-ui/react/button";
|
|
2625
|
-
import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2626
|
-
function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
|
|
2627
|
-
const text = typeof title === "string";
|
|
2628
|
-
const name = /* @__PURE__ */ jsxs26("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
|
|
2629
|
-
text ? /* @__PURE__ */ jsx37("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx37("div", { className: "min-w-0 flex-1", children: title }),
|
|
2630
|
-
(chevron || titleMenu != null) && /* @__PURE__ */ jsx37(IconChevronDown3, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
2631
|
-
] });
|
|
2632
|
-
return (
|
|
2633
|
-
// With a title menu the bar gives the button 6px of its left padding
|
|
2634
|
-
// (pl-3.5 + the button's px-1.5 = pl-5): the words stay where a title's
|
|
2635
|
-
// are, and the fill is inside the bar — a negative margin had it clipped
|
|
2636
|
-
// (Katerina, 5 October).
|
|
2637
|
-
/* @__PURE__ */ jsxs26("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-3.5" : "pl-5", className), children: [
|
|
2638
|
-
/* @__PURE__ */ jsx37("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx37(
|
|
2639
|
-
Menu,
|
|
2640
|
-
{
|
|
2641
|
-
trigger: /* @__PURE__ */ jsx37(BaseButton6, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
|
|
2642
|
-
children: titleMenu
|
|
2643
|
-
}
|
|
2644
|
-
) : name }),
|
|
2645
|
-
actions && /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
|
|
2646
|
-
] })
|
|
2647
|
-
);
|
|
2648
|
-
}
|
|
2649
|
-
|
|
2650
|
-
// src/DialogShell.tsx
|
|
2651
|
-
import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2652
|
-
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
2653
|
-
const Parts = alert ? AlertDialog : Dialog3;
|
|
2654
|
-
const popupRef = useRef7(null);
|
|
2655
|
-
return /* @__PURE__ */ jsx38(
|
|
2656
|
-
Parts.Root,
|
|
2657
|
-
{
|
|
2658
|
-
open: true,
|
|
2659
|
-
onOpenChange: (open) => {
|
|
2660
|
-
if (!open) onClose();
|
|
2661
|
-
},
|
|
2662
|
-
children: /* @__PURE__ */ jsxs27(Parts.Portal, { children: [
|
|
2663
|
-
/* @__PURE__ */ jsx38(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
2664
|
-
/* @__PURE__ */ jsx38("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs27(
|
|
2665
|
-
Parts.Popup,
|
|
2666
|
-
{
|
|
2667
|
-
ref: popupRef,
|
|
2668
|
-
initialFocus: popupRef,
|
|
2669
|
-
"aria-label": headerContent != null ? title : void 0,
|
|
2670
|
-
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
2671
|
-
style: { width },
|
|
2672
|
-
children: [
|
|
2673
|
-
/* @__PURE__ */ jsx38(
|
|
2674
|
-
ContainerHeader,
|
|
2675
|
-
{
|
|
2676
|
-
title: headerContent ?? /* @__PURE__ */ jsx38(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx38("span", {}), children: title }),
|
|
2677
|
-
actions: (
|
|
2678
|
-
/*
|
|
2679
|
-
The ✕ IS the `Close` part now, rather than a button that calls
|
|
2680
|
-
`onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
|
|
2681
|
-
this: an `IconButton` carrying a `tooltip` returned the tooltip
|
|
2682
|
-
wrapper `<div>` as its root, so the part composed onto the
|
|
2683
|
-
wrapper and not the button. Porting Tooltip removed the wrapper
|
|
2684
|
-
— the trigger is the button itself — and the composition works.
|
|
2685
|
-
|
|
2686
|
-
What it buys: the dialog closes through its own state machine,
|
|
2687
|
-
so the ✕, Escape and the outside press are one path with one
|
|
2688
|
-
reason attached, instead of one of the three going around.
|
|
2689
|
-
*/
|
|
2690
|
-
/* @__PURE__ */ jsx38(
|
|
2691
|
-
Parts.Close,
|
|
2692
|
-
{
|
|
2693
|
-
render: /* @__PURE__ */ jsx38(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx38(IconX5, { size: 16, stroke: 1.5 }) })
|
|
2694
|
-
}
|
|
2695
|
-
)
|
|
2696
|
-
)
|
|
2697
|
-
}
|
|
2698
|
-
),
|
|
2699
|
-
bodyMaxHeight ? (
|
|
2700
|
-
// The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
|
|
2701
|
-
/* @__PURE__ */ jsx38("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx38(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
|
|
2702
|
-
) : /* @__PURE__ */ jsx38("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
2703
|
-
footer != null && /* @__PURE__ */ jsx38("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
2704
|
-
]
|
|
2705
|
-
}
|
|
2706
|
-
) })
|
|
2707
|
-
] })
|
|
2708
|
-
}
|
|
2709
|
-
);
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
// src/ConfirmDialog.tsx
|
|
2713
|
-
import { Fragment as Fragment9, jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2830
|
+
import { useState as useState6 } from "react";
|
|
2831
|
+
import { Fragment as Fragment10, jsx as jsx41, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2714
2832
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
2715
|
-
const [busy, setBusy] =
|
|
2833
|
+
const [busy, setBusy] = useState6(false);
|
|
2716
2834
|
const confirm = async () => {
|
|
2717
2835
|
setBusy(true);
|
|
2718
2836
|
try {
|
|
@@ -2722,30 +2840,30 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
2722
2840
|
setBusy(false);
|
|
2723
2841
|
}
|
|
2724
2842
|
};
|
|
2725
|
-
return /* @__PURE__ */
|
|
2843
|
+
return /* @__PURE__ */ jsx41(
|
|
2726
2844
|
DialogShell,
|
|
2727
2845
|
{
|
|
2728
2846
|
alert: true,
|
|
2729
2847
|
title,
|
|
2730
2848
|
onClose,
|
|
2731
|
-
footer: /* @__PURE__ */
|
|
2732
|
-
/* @__PURE__ */
|
|
2733
|
-
/* @__PURE__ */
|
|
2849
|
+
footer: /* @__PURE__ */ jsxs30(Fragment10, { children: [
|
|
2850
|
+
/* @__PURE__ */ jsx41(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2851
|
+
/* @__PURE__ */ jsx41(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
2734
2852
|
] }),
|
|
2735
|
-
children: /* @__PURE__ */
|
|
2853
|
+
children: /* @__PURE__ */ jsx41("div", { className: "flex flex-col gap-3 text-body-2 text-text-primary", children })
|
|
2736
2854
|
}
|
|
2737
2855
|
);
|
|
2738
2856
|
}
|
|
2739
2857
|
|
|
2740
2858
|
// src/EditableText.tsx
|
|
2741
|
-
import { useEffect as useEffect4, useRef as useRef8, useState as
|
|
2859
|
+
import { useEffect as useEffect4, useRef as useRef8, useState as useState7 } from "react";
|
|
2742
2860
|
import { Field as BaseField4 } from "@base-ui/react/field";
|
|
2743
2861
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
2744
|
-
import { jsx as
|
|
2862
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
2745
2863
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
2746
|
-
const [editing, setEditing] =
|
|
2747
|
-
const [draft, setDraft] =
|
|
2748
|
-
const [busy, setBusy] =
|
|
2864
|
+
const [editing, setEditing] = useState7(false);
|
|
2865
|
+
const [draft, setDraft] = useState7(value);
|
|
2866
|
+
const [busy, setBusy] = useState7(false);
|
|
2749
2867
|
const fieldRef = useRef8(null);
|
|
2750
2868
|
useEffect4(() => {
|
|
2751
2869
|
if (editing) {
|
|
@@ -2799,7 +2917,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2799
2917
|
written and never read. Read-only, this is a line of text: whatever
|
|
2800
2918
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
2801
2919
|
*/
|
|
2802
|
-
/* @__PURE__ */
|
|
2920
|
+
/* @__PURE__ */ jsx42(
|
|
2803
2921
|
"div",
|
|
2804
2922
|
{
|
|
2805
2923
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -2809,11 +2927,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2809
2927
|
);
|
|
2810
2928
|
}
|
|
2811
2929
|
if (editing) {
|
|
2812
|
-
return multiline ? /* @__PURE__ */
|
|
2930
|
+
return multiline ? /* @__PURE__ */ jsx42(
|
|
2813
2931
|
BaseField4.Control,
|
|
2814
2932
|
{
|
|
2815
2933
|
ref: fieldRef,
|
|
2816
|
-
render: /* @__PURE__ */
|
|
2934
|
+
render: /* @__PURE__ */ jsx42("textarea", { rows: 4 }),
|
|
2817
2935
|
"aria-label": label,
|
|
2818
2936
|
value: draft,
|
|
2819
2937
|
disabled: busy,
|
|
@@ -2822,7 +2940,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2822
2940
|
onBlur: () => void commit(),
|
|
2823
2941
|
className: fieldClass
|
|
2824
2942
|
}
|
|
2825
|
-
) : /* @__PURE__ */
|
|
2943
|
+
) : /* @__PURE__ */ jsx42(
|
|
2826
2944
|
Input2,
|
|
2827
2945
|
{
|
|
2828
2946
|
ref: fieldRef,
|
|
@@ -2836,7 +2954,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2836
2954
|
}
|
|
2837
2955
|
);
|
|
2838
2956
|
}
|
|
2839
|
-
return /* @__PURE__ */
|
|
2957
|
+
return /* @__PURE__ */ jsx42(
|
|
2840
2958
|
"button",
|
|
2841
2959
|
{
|
|
2842
2960
|
type: "button",
|
|
@@ -2856,7 +2974,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
2856
2974
|
// src/ErrorBoundary.tsx
|
|
2857
2975
|
import { Component } from "react";
|
|
2858
2976
|
import { IconAlertTriangle as IconAlertTriangle2 } from "@tabler/icons-react";
|
|
2859
|
-
import { jsx as
|
|
2977
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
2860
2978
|
var ErrorBoundary = class extends Component {
|
|
2861
2979
|
state = { hasError: false };
|
|
2862
2980
|
static getDerivedStateFromError() {
|
|
@@ -2867,22 +2985,22 @@ var ErrorBoundary = class extends Component {
|
|
|
2867
2985
|
}
|
|
2868
2986
|
render() {
|
|
2869
2987
|
if (!this.state.hasError) return this.props.children;
|
|
2870
|
-
const message = /* @__PURE__ */
|
|
2988
|
+
const message = /* @__PURE__ */ jsx43(
|
|
2871
2989
|
EmptyState,
|
|
2872
2990
|
{
|
|
2873
|
-
icon: /* @__PURE__ */
|
|
2991
|
+
icon: /* @__PURE__ */ jsx43(IconAlertTriangle2, { size: 16, stroke: 1.5 }),
|
|
2874
2992
|
message: `Something went wrong${this.props.label ? ` in the ${this.props.label}` : ""}. Your data is safe \u2014 try again.`,
|
|
2875
2993
|
action: { label: "Try again", onClick: () => this.setState({ hasError: false }) }
|
|
2876
2994
|
}
|
|
2877
2995
|
);
|
|
2878
2996
|
if (this.props.frame) return this.props.frame(message);
|
|
2879
|
-
return this.props.fallbackClassName ? /* @__PURE__ */
|
|
2997
|
+
return this.props.fallbackClassName ? /* @__PURE__ */ jsx43("div", { className: this.props.fallbackClassName, children: message }) : message;
|
|
2880
2998
|
}
|
|
2881
2999
|
};
|
|
2882
3000
|
|
|
2883
3001
|
// src/ProgressBar.tsx
|
|
2884
3002
|
import { Progress } from "@base-ui/react/progress";
|
|
2885
|
-
import { jsx as
|
|
3003
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
2886
3004
|
var TRACK_CLASSES = {
|
|
2887
3005
|
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
2888
3006
|
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
@@ -2895,17 +3013,17 @@ var INDICATOR_CLASSES = {
|
|
|
2895
3013
|
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
2896
3014
|
return (
|
|
2897
3015
|
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
2898
|
-
/* @__PURE__ */
|
|
3016
|
+
/* @__PURE__ */ jsx44(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx44(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx44(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
|
|
2899
3017
|
);
|
|
2900
3018
|
}
|
|
2901
3019
|
|
|
2902
3020
|
// src/Breadcrumb.tsx
|
|
2903
|
-
import { Fragment as
|
|
2904
|
-
import { jsx as
|
|
3021
|
+
import { Fragment as Fragment11, useCallback as useCallback3, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState8 } from "react";
|
|
3022
|
+
import { jsx as jsx45, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2905
3023
|
function Breadcrumb({ items, className }) {
|
|
2906
3024
|
const navRef = useRef9(null);
|
|
2907
3025
|
const labelRefs = useRef9([]);
|
|
2908
|
-
const [truncated, setTruncated] =
|
|
3026
|
+
const [truncated, setTruncated] = useState8(/* @__PURE__ */ new Set());
|
|
2909
3027
|
const measure = useCallback3(() => {
|
|
2910
3028
|
const next = /* @__PURE__ */ new Set();
|
|
2911
3029
|
labelRefs.current.forEach((el, index) => {
|
|
@@ -2921,7 +3039,7 @@ function Breadcrumb({ items, className }) {
|
|
|
2921
3039
|
observer.observe(nav);
|
|
2922
3040
|
return () => observer.disconnect();
|
|
2923
3041
|
}, [measure, items]);
|
|
2924
|
-
return /* @__PURE__ */
|
|
3042
|
+
return /* @__PURE__ */ jsx45("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
|
|
2925
3043
|
const last = index === items.length - 1;
|
|
2926
3044
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
2927
3045
|
const text = cn(
|
|
@@ -2942,34 +3060,34 @@ function Breadcrumb({ items, className }) {
|
|
|
2942
3060
|
// on a box around it, which the link takes them from, rather than
|
|
2943
3061
|
// pushed into it (UIG-9); the link is still the one element that
|
|
2944
3062
|
// truncates and is measured.
|
|
2945
|
-
/* @__PURE__ */
|
|
2946
|
-
) : /* @__PURE__ */
|
|
2947
|
-
return /* @__PURE__ */
|
|
2948
|
-
index > 0 && /* @__PURE__ */
|
|
2949
|
-
item.icon && /* @__PURE__ */
|
|
3063
|
+
/* @__PURE__ */ jsx45("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx45(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
|
|
3064
|
+
) : /* @__PURE__ */ jsx45("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
3065
|
+
return /* @__PURE__ */ jsxs31(Fragment11, { children: [
|
|
3066
|
+
index > 0 && /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
3067
|
+
item.icon && /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
|
|
2950
3068
|
truncated.has(index) ? (
|
|
2951
3069
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
2952
3070
|
// must keep truncating inside it, or wrapping it would widen the
|
|
2953
3071
|
// trail and the tooltip would never be needed again.
|
|
2954
|
-
/* @__PURE__ */
|
|
3072
|
+
/* @__PURE__ */ jsx45(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
2955
3073
|
) : crumb
|
|
2956
3074
|
] }, `${item.label}-${index}`);
|
|
2957
3075
|
}) });
|
|
2958
3076
|
}
|
|
2959
3077
|
|
|
2960
3078
|
// src/NavItem.tsx
|
|
2961
|
-
import { useId, useState as
|
|
3079
|
+
import { useId as useId2, useState as useState9 } from "react";
|
|
2962
3080
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2963
3081
|
import { IconAlertSquareRounded, IconChevronRight as IconChevronRight2, IconDotsVertical } from "@tabler/icons-react";
|
|
2964
3082
|
|
|
2965
3083
|
// src/UnreadDot.tsx
|
|
2966
|
-
import { jsx as
|
|
3084
|
+
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
2967
3085
|
function UnreadDot({ className }) {
|
|
2968
|
-
return /* @__PURE__ */
|
|
3086
|
+
return /* @__PURE__ */ jsx46("div", { className: cn("flex h-6 w-6 shrink-0 items-center justify-center", className), "data-unread": true, children: /* @__PURE__ */ jsx46("div", { className: "h-1.5 w-1.5 rounded-full bg-accent-primary" }) });
|
|
2969
3087
|
}
|
|
2970
3088
|
|
|
2971
3089
|
// src/NavItem.tsx
|
|
2972
|
-
import { jsx as
|
|
3090
|
+
import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2973
3091
|
function NavItem({
|
|
2974
3092
|
label,
|
|
2975
3093
|
href,
|
|
@@ -2989,8 +3107,8 @@ function NavItem({
|
|
|
2989
3107
|
className,
|
|
2990
3108
|
...props
|
|
2991
3109
|
}) {
|
|
2992
|
-
const [openState, setOpenState] =
|
|
2993
|
-
const panelId =
|
|
3110
|
+
const [openState, setOpenState] = useState9(defaultOpen);
|
|
3111
|
+
const panelId = useId2();
|
|
2994
3112
|
const hasRows = children != null && children !== false;
|
|
2995
3113
|
const open = openProp ?? openState;
|
|
2996
3114
|
const setOpen = (next) => {
|
|
@@ -2998,9 +3116,9 @@ function NavItem({
|
|
|
2998
3116
|
onOpenChange?.(next);
|
|
2999
3117
|
};
|
|
3000
3118
|
const besides = menu != null || hasRows;
|
|
3001
|
-
const mark = unread ? urgent ? /* @__PURE__ */
|
|
3119
|
+
const mark = unread ? urgent ? /* @__PURE__ */ jsx47(UrgentMark, {}) : /* @__PURE__ */ jsx47(UnreadDot, {}) : null;
|
|
3002
3120
|
const stepsAside = menu != null && "transition-opacity group-hover/nav:opacity-0 group-has-[:focus-visible]/nav:opacity-0 group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:opacity-0 [@media(hover:none)]:opacity-0";
|
|
3003
|
-
const row = /* @__PURE__ */
|
|
3121
|
+
const row = /* @__PURE__ */ jsxs32(
|
|
3004
3122
|
"a",
|
|
3005
3123
|
{
|
|
3006
3124
|
href,
|
|
@@ -3021,7 +3139,7 @@ function NavItem({
|
|
|
3021
3139
|
),
|
|
3022
3140
|
...props,
|
|
3023
3141
|
children: [
|
|
3024
|
-
(icon || hasRows) && /* @__PURE__ */
|
|
3142
|
+
(icon || hasRows) && /* @__PURE__ */ jsx47(
|
|
3025
3143
|
"span",
|
|
3026
3144
|
{
|
|
3027
3145
|
className: cn(
|
|
@@ -3032,14 +3150,15 @@ function NavItem({
|
|
|
3032
3150
|
children: icon
|
|
3033
3151
|
}
|
|
3034
3152
|
),
|
|
3035
|
-
/* @__PURE__ */
|
|
3153
|
+
/* @__PURE__ */ jsx47("span", { className: cn("flex-1 truncate", unread && "font-medium"), children: label }),
|
|
3036
3154
|
hint != null && // Takes room only while it shows, so the label gives way to it.
|
|
3037
|
-
/* @__PURE__ */
|
|
3038
|
-
count ? /* @__PURE__ */
|
|
3155
|
+
/* @__PURE__ */ jsx47("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-has-[:focus-visible]/nav:flex", children: hint }),
|
|
3156
|
+
count ? /* @__PURE__ */ jsx47(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx47(
|
|
3039
3157
|
"span",
|
|
3040
3158
|
{
|
|
3041
3159
|
className: cn(
|
|
3042
|
-
"min-w-4 shrink-0 text-center
|
|
3160
|
+
"min-w-4 shrink-0 text-center",
|
|
3161
|
+
COUNT_TEXT_CLASSES,
|
|
3043
3162
|
// With a menu and no mark after it, the ⋮ takes this place while it shows.
|
|
3044
3163
|
!mark && stepsAside
|
|
3045
3164
|
),
|
|
@@ -3050,7 +3169,7 @@ function NavItem({
|
|
|
3050
3169
|
// `-mr-1`: the 24px slot's dot then sits on the axis of a count and
|
|
3051
3170
|
// of the ⋮ (8px from the edge to the 16px box), one column with a
|
|
3052
3171
|
// folder heading's dot and ⋮ (Katerina, 5 October).
|
|
3053
|
-
/* @__PURE__ */
|
|
3172
|
+
/* @__PURE__ */ jsx47("span", { className: cn("-mr-1 flex shrink-0", stepsAside), children: mark })
|
|
3054
3173
|
) : menu != null && !count ? (
|
|
3055
3174
|
// Nothing at the right, but a menu: no room is kept at rest, so the
|
|
3056
3175
|
// label has the row's whole width; while the ⋮ shows, its 24px slot
|
|
@@ -3058,18 +3177,18 @@ function NavItem({
|
|
|
3058
3177
|
// `-mr-1`: the ⋮ sits at `right-1`, 4px into the row's padding, so the
|
|
3059
3178
|
// slot does too — at the padding's edge it kept 4px the ⋮ never
|
|
3060
3179
|
// covers, and the label stopped 12px short of the button, not 8.
|
|
3061
|
-
/* @__PURE__ */
|
|
3180
|
+
/* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "-mr-1 hidden w-6 shrink-0 group-hover/nav:block group-has-[:focus-visible]/nav:block group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:block [@media(hover:none)]:block" })
|
|
3062
3181
|
) : null
|
|
3063
3182
|
]
|
|
3064
3183
|
}
|
|
3065
3184
|
);
|
|
3066
3185
|
if (!besides && hint == null) return row;
|
|
3067
3186
|
const name = menuLabel ?? `More options for ${label}`;
|
|
3068
|
-
const line = /* @__PURE__ */
|
|
3187
|
+
const line = /* @__PURE__ */ jsxs32("div", { className: "group/nav relative shrink-0", children: [
|
|
3069
3188
|
row,
|
|
3070
3189
|
hasRows && // `left-1`: the 24px button's 16px arrow then sits where the icon
|
|
3071
3190
|
// sits (the row's px-2), so the icon turns into the arrow in place.
|
|
3072
|
-
/* @__PURE__ */
|
|
3191
|
+
/* @__PURE__ */ jsx47("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100", children: /* @__PURE__ */ jsx47(
|
|
3073
3192
|
IconButton,
|
|
3074
3193
|
{
|
|
3075
3194
|
tooltip: open ? "Collapse" : "Expand",
|
|
@@ -3077,7 +3196,7 @@ function NavItem({
|
|
|
3077
3196
|
"aria-expanded": open,
|
|
3078
3197
|
"aria-controls": panelId,
|
|
3079
3198
|
onClick: () => setOpen(!open),
|
|
3080
|
-
children: /* @__PURE__ */
|
|
3199
|
+
children: /* @__PURE__ */ jsx47(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
|
|
3081
3200
|
}
|
|
3082
3201
|
) }),
|
|
3083
3202
|
menu != null && // `right-1`: the 24px button's 16px icon ends 8px from the row's
|
|
@@ -3088,61 +3207,61 @@ function NavItem({
|
|
|
3088
3207
|
// right of the slot's centre.
|
|
3089
3208
|
// On a screen with no hover it always shows: nothing there can point
|
|
3090
3209
|
// at the row, and the menu has no other way in.
|
|
3091
|
-
/* @__PURE__ */
|
|
3210
|
+
/* @__PURE__ */ jsx47("div", { "data-nav-menu": true, className: cn("absolute inset-y-0 right-1 flex items-center", "opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100"), children: /* @__PURE__ */ jsx47(
|
|
3092
3211
|
Menu,
|
|
3093
3212
|
{
|
|
3094
3213
|
align: "right",
|
|
3095
|
-
trigger: /* @__PURE__ */
|
|
3214
|
+
trigger: /* @__PURE__ */ jsx47(IconButton, { tooltip: "More options", "aria-label": name, children: /* @__PURE__ */ jsx47(IconDotsVertical, { size: 16, stroke: 1.5 }) }),
|
|
3096
3215
|
children: menu
|
|
3097
3216
|
}
|
|
3098
3217
|
) })
|
|
3099
3218
|
] });
|
|
3100
3219
|
if (!hasRows) return line;
|
|
3101
|
-
return /* @__PURE__ */
|
|
3220
|
+
return /* @__PURE__ */ jsxs32(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
|
|
3102
3221
|
line,
|
|
3103
|
-
/* @__PURE__ */
|
|
3222
|
+
/* @__PURE__ */ jsx47(
|
|
3104
3223
|
Collapsible.Panel,
|
|
3105
3224
|
{
|
|
3106
3225
|
id: panelId,
|
|
3107
3226
|
hiddenUntilFound: true,
|
|
3108
3227
|
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
3109
|
-
children: /* @__PURE__ */
|
|
3228
|
+
children: /* @__PURE__ */ jsx47("div", { className: "flex flex-col gap-0.5 pt-0.5 pl-6", children })
|
|
3110
3229
|
}
|
|
3111
3230
|
)
|
|
3112
3231
|
] });
|
|
3113
3232
|
}
|
|
3114
3233
|
function UrgentMark() {
|
|
3115
|
-
return /* @__PURE__ */
|
|
3234
|
+
return /* @__PURE__ */ jsx47("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center", "data-urgent": true, children: /* @__PURE__ */ jsx47("div", { className: "flex items-center rounded-full bg-warning-muted p-0.5 signal:shadow-glow-warning", children: /* @__PURE__ */ jsx47(IconAlertSquareRounded, { size: 12, stroke: 2.5, className: "text-warning-default" }) }) });
|
|
3116
3235
|
}
|
|
3117
3236
|
|
|
3118
3237
|
// src/NavTree.tsx
|
|
3119
3238
|
import { useEffect as useEffect5, useRef as useRef10 } from "react";
|
|
3120
3239
|
|
|
3121
3240
|
// src/CollapsibleSection.tsx
|
|
3122
|
-
import { useState as
|
|
3241
|
+
import { useState as useState10 } from "react";
|
|
3123
3242
|
import { Collapsible as Collapsible2 } from "@base-ui/react/collapsible";
|
|
3124
3243
|
|
|
3125
3244
|
// src/SectionHeader.tsx
|
|
3126
3245
|
import { IconChevronRight as IconChevronRight3, IconDotsVertical as IconDotsVertical2 } from "@tabler/icons-react";
|
|
3127
3246
|
import { useRender } from "@base-ui/react/use-render";
|
|
3128
|
-
import { Fragment as
|
|
3129
|
-
function SectionHeader({ title, chevron = false, icon, isExpanded = true, onToggle, trailing, actions, menu, menuLabel, showActions = "hover", hover = "fill", look = "heading", render, className }) {
|
|
3247
|
+
import { Fragment as Fragment12, jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3248
|
+
function SectionHeader({ title, chevron = false, icon, isExpanded = true, onToggle, trailing, count, actions, menu, menuLabel, showActions = "hover", hover = "fill", look = "heading", render, className }) {
|
|
3130
3249
|
const row = look === "row";
|
|
3131
3250
|
const acts = actions && actions.length > 0 || menu != null;
|
|
3132
3251
|
const trailingClasses = !acts ? "has-[[data-unread]]:-mr-1" : showActions === "hover" && "has-[[data-unread]]:pointer-events-none has-[[data-unread]]:absolute has-[[data-unread]]:inset-y-0 has-[[data-unread]]:right-1 has-[[data-unread]]:w-6 has-[[data-unread]]:justify-center has-[[data-unread]]:transition-opacity group-hover:has-[[data-unread]]:opacity-0 group-has-[:focus-visible]:has-[[data-unread]]:opacity-0 group-has-[[data-section-menu]_[aria-expanded=true]]:has-[[data-unread]]:opacity-0 [@media(hover:none)]:has-[[data-unread]]:opacity-0";
|
|
3133
3252
|
const reveal = showActions === "hover" && "opacity-0 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100";
|
|
3134
3253
|
const titleElement = useRender({
|
|
3135
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
3254
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx48("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx48("span", {})),
|
|
3136
3255
|
props: {
|
|
3137
3256
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
3138
3257
|
// whole row up to the actions is the hit target, as it was when the
|
|
3139
3258
|
// row itself carried the click.
|
|
3140
3259
|
// An icon is a row's: NavItem's 8px after it.
|
|
3141
3260
|
className: cn("flex h-full min-w-0 flex-1 items-center text-left", row || chevron || icon != null ? "gap-2" : "gap-1"),
|
|
3142
|
-
children: /* @__PURE__ */
|
|
3143
|
-
icon != null ? /* @__PURE__ */
|
|
3144
|
-
/* @__PURE__ */
|
|
3145
|
-
chevron && /* @__PURE__ */
|
|
3261
|
+
children: /* @__PURE__ */ jsxs33(Fragment12, { children: [
|
|
3262
|
+
icon != null ? /* @__PURE__ */ jsxs33("span", { className: "relative flex size-4 shrink-0 items-center justify-center text-text-secondary", children: [
|
|
3263
|
+
/* @__PURE__ */ jsx48("span", { className: cn("flex", chevron && "transition-opacity group-hover:opacity-0 group-has-[:focus-visible]:opacity-0"), children: icon }),
|
|
3264
|
+
chevron && /* @__PURE__ */ jsx48(
|
|
3146
3265
|
IconChevronRight3,
|
|
3147
3266
|
{
|
|
3148
3267
|
size: 16,
|
|
@@ -3150,7 +3269,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3150
3269
|
className: cn("absolute opacity-0 transition-[opacity,transform] duration-150 group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", isExpanded && "rotate-90")
|
|
3151
3270
|
}
|
|
3152
3271
|
)
|
|
3153
|
-
] }) : chevron && /* @__PURE__ */
|
|
3272
|
+
] }) : chevron && /* @__PURE__ */ jsx48(
|
|
3154
3273
|
IconChevronRight3,
|
|
3155
3274
|
{
|
|
3156
3275
|
size: 16,
|
|
@@ -3158,14 +3277,15 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3158
3277
|
className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
|
|
3159
3278
|
}
|
|
3160
3279
|
),
|
|
3161
|
-
look === "quiet" ? /* @__PURE__ */
|
|
3280
|
+
look === "quiet" ? /* @__PURE__ */ jsx48("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
|
|
3162
3281
|
// A row's words: NavItem's size and colour, brightening under the pointer with the row.
|
|
3163
|
-
/* @__PURE__ */
|
|
3164
|
-
) : /* @__PURE__ */
|
|
3282
|
+
/* @__PURE__ */ jsx48("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
|
|
3283
|
+
) : /* @__PURE__ */ jsx48(SectionLabel, { folds: chevron, children: title }),
|
|
3284
|
+
count != null && /* @__PURE__ */ jsx48("span", { className: cn("ml-1 shrink-0", COUNT_TEXT_CLASSES), children: count })
|
|
3165
3285
|
] })
|
|
3166
3286
|
}
|
|
3167
3287
|
});
|
|
3168
|
-
return /* @__PURE__ */
|
|
3288
|
+
return /* @__PURE__ */ jsxs33(
|
|
3169
3289
|
"div",
|
|
3170
3290
|
{
|
|
3171
3291
|
className: cn(
|
|
@@ -3186,18 +3306,18 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3186
3306
|
),
|
|
3187
3307
|
children: [
|
|
3188
3308
|
titleElement,
|
|
3189
|
-
trailing != null && /* @__PURE__ */
|
|
3190
|
-
acts && /* @__PURE__ */
|
|
3309
|
+
trailing != null && /* @__PURE__ */ jsx48("div", { className: cn("flex shrink-0 items-center", trailingClasses), children: trailing }),
|
|
3310
|
+
acts && /* @__PURE__ */ jsx48(
|
|
3191
3311
|
"div",
|
|
3192
3312
|
{
|
|
3193
3313
|
className: "-mr-1 flex shrink-0 items-center",
|
|
3194
|
-
children: /* @__PURE__ */
|
|
3195
|
-
actions?.map((action) => /* @__PURE__ */
|
|
3196
|
-
menu != null && /* @__PURE__ */
|
|
3314
|
+
children: /* @__PURE__ */ jsxs33("div", { className: cn("flex items-center gap-1", reveal), children: [
|
|
3315
|
+
actions?.map((action) => /* @__PURE__ */ jsx48(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip)),
|
|
3316
|
+
menu != null && /* @__PURE__ */ jsx48("div", { "data-section-menu": true, className: "flex items-center", children: /* @__PURE__ */ jsx48(
|
|
3197
3317
|
Menu,
|
|
3198
3318
|
{
|
|
3199
3319
|
align: "right",
|
|
3200
|
-
trigger: /* @__PURE__ */
|
|
3320
|
+
trigger: /* @__PURE__ */ jsx48(IconButton, { tooltip: "More options", "aria-label": menuLabel ?? `More options for ${title}`, children: /* @__PURE__ */ jsx48(IconDotsVertical2, { size: 16, stroke: 1.5 }) }),
|
|
3201
3321
|
children: menu
|
|
3202
3322
|
}
|
|
3203
3323
|
) })
|
|
@@ -3210,7 +3330,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
|
|
|
3210
3330
|
}
|
|
3211
3331
|
|
|
3212
3332
|
// src/CollapsibleSection.tsx
|
|
3213
|
-
import { jsx as
|
|
3333
|
+
import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3214
3334
|
var OPEN = "open";
|
|
3215
3335
|
var CLOSED = "closed";
|
|
3216
3336
|
function readStored(key) {
|
|
@@ -3230,38 +3350,38 @@ function writeStored(key, open) {
|
|
|
3230
3350
|
}
|
|
3231
3351
|
}
|
|
3232
3352
|
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, icon, trailing, actions, menu, menuLabel, showActions, look = "heading", indent = false, children, className, contentClassName }) {
|
|
3233
|
-
const [openState, setOpenState] =
|
|
3353
|
+
const [openState, setOpenState] = useState10(() => readStored(storageKey) ?? defaultOpen);
|
|
3234
3354
|
const open = openProp ?? openState;
|
|
3235
3355
|
const setOpen = (next) => {
|
|
3236
3356
|
setOpenState(next);
|
|
3237
3357
|
writeStored(storageKey, next);
|
|
3238
3358
|
onOpenChange?.(next);
|
|
3239
3359
|
};
|
|
3240
|
-
return /* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3242
|
-
/* @__PURE__ */
|
|
3360
|
+
return /* @__PURE__ */ jsxs34(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
3361
|
+
/* @__PURE__ */ jsx49(SectionHeader, { title, chevron: true, icon, isExpanded: open, trailing, actions, menu, menuLabel, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx49(Collapsible2.Trigger, {}) }),
|
|
3362
|
+
/* @__PURE__ */ jsx49(
|
|
3243
3363
|
Collapsible2.Panel,
|
|
3244
3364
|
{
|
|
3245
3365
|
hiddenUntilFound: true,
|
|
3246
3366
|
className: COLLAPSIBLE_PANEL_CLASSES,
|
|
3247
|
-
children: /* @__PURE__ */
|
|
3367
|
+
children: /* @__PURE__ */ jsx49("div", { className: cn("flex flex-col pt-0.5", (look === "row" || indent) && "pl-6", contentClassName), children })
|
|
3248
3368
|
}
|
|
3249
3369
|
)
|
|
3250
3370
|
] });
|
|
3251
3371
|
}
|
|
3252
3372
|
|
|
3253
3373
|
// src/NavTree.tsx
|
|
3254
|
-
import { Fragment as
|
|
3374
|
+
import { Fragment as Fragment13, jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3255
3375
|
var NAV_TREE_INTENT_MS = 150;
|
|
3256
3376
|
function holds(nodes, id) {
|
|
3257
3377
|
return !!nodes && id !== void 0 && nodes.some((node) => node.id === id || holds(node.children ?? null, id));
|
|
3258
3378
|
}
|
|
3259
3379
|
function Line({ message }) {
|
|
3260
|
-
return /* @__PURE__ */
|
|
3380
|
+
return /* @__PURE__ */ jsx50("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx50(EmptyState, { scope: "section", message }) });
|
|
3261
3381
|
}
|
|
3262
3382
|
function Row({ node, selected, onSelect }) {
|
|
3263
|
-
const under = node.childrenMessage !== void 0 ? /* @__PURE__ */
|
|
3264
|
-
return /* @__PURE__ */
|
|
3383
|
+
const under = node.childrenMessage !== void 0 ? /* @__PURE__ */ jsx50(Line, { message: node.childrenMessage }) : node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx50(Row, { node: child, selected, onSelect }, child.id)) : node.children === null || node.hasChildren && node.children === void 0 ? /* @__PURE__ */ jsx50(SkeletonList, { rows: 2 }) : void 0;
|
|
3384
|
+
return /* @__PURE__ */ jsx50(
|
|
3265
3385
|
NavItem,
|
|
3266
3386
|
{
|
|
3267
3387
|
href: node.href,
|
|
@@ -3283,7 +3403,7 @@ function Row({ node, selected, onSelect }) {
|
|
|
3283
3403
|
);
|
|
3284
3404
|
}
|
|
3285
3405
|
function Group({ group, selected, onSelect, storageKey }) {
|
|
3286
|
-
return /* @__PURE__ */
|
|
3406
|
+
return /* @__PURE__ */ jsx50(
|
|
3287
3407
|
NavTreeSection,
|
|
3288
3408
|
{
|
|
3289
3409
|
id: group.id,
|
|
@@ -3299,7 +3419,7 @@ function Group({ group, selected, onSelect, storageKey }) {
|
|
|
3299
3419
|
onOpenChange: group.onOpenChange,
|
|
3300
3420
|
storageKey: storageKey ? `${storageKey}.${group.id}` : void 0,
|
|
3301
3421
|
onIntent: group.onIntent,
|
|
3302
|
-
children: group.nodes?.map((node) => /* @__PURE__ */
|
|
3422
|
+
children: group.nodes?.map((node) => /* @__PURE__ */ jsx50(Row, { node, selected, onSelect }, node.id))
|
|
3303
3423
|
}
|
|
3304
3424
|
);
|
|
3305
3425
|
}
|
|
@@ -3307,7 +3427,7 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
|
|
|
3307
3427
|
const timer = useRef10(void 0);
|
|
3308
3428
|
useEffect5(() => () => clearTimeout(timer.current), []);
|
|
3309
3429
|
const intent = onIntent;
|
|
3310
|
-
return /* @__PURE__ */
|
|
3430
|
+
return /* @__PURE__ */ jsx50(
|
|
3311
3431
|
"div",
|
|
3312
3432
|
{
|
|
3313
3433
|
className: "shrink-0 [&+&]:mt-1",
|
|
@@ -3318,7 +3438,7 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
|
|
|
3318
3438
|
} : void 0,
|
|
3319
3439
|
onPointerLeave: intent ? () => clearTimeout(timer.current) : void 0,
|
|
3320
3440
|
onFocus: intent,
|
|
3321
|
-
children: /* @__PURE__ */
|
|
3441
|
+
children: /* @__PURE__ */ jsx50(
|
|
3322
3442
|
CollapsibleSection,
|
|
3323
3443
|
{
|
|
3324
3444
|
title,
|
|
@@ -3333,26 +3453,26 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
|
|
|
3333
3453
|
icon,
|
|
3334
3454
|
className: "shrink-0",
|
|
3335
3455
|
contentClassName: "gap-0.5",
|
|
3336
|
-
children: message !== void 0 ? /* @__PURE__ */
|
|
3456
|
+
children: message !== void 0 ? /* @__PURE__ */ jsx50(Line, { message }) : loading ? /* @__PURE__ */ jsx50(SkeletonList, { rows: 3 }) : children
|
|
3337
3457
|
}
|
|
3338
3458
|
)
|
|
3339
3459
|
}
|
|
3340
3460
|
);
|
|
3341
3461
|
}
|
|
3342
3462
|
function NavTree({ title, titleActions, groups, children, selected, onSelect, emptyMessage = "", storageKey }) {
|
|
3343
|
-
return /* @__PURE__ */
|
|
3344
|
-
title && /* @__PURE__ */
|
|
3345
|
-
groups === void 0 ? children : groups === null ? /* @__PURE__ */
|
|
3463
|
+
return /* @__PURE__ */ jsxs35(Fragment13, { children: [
|
|
3464
|
+
title && /* @__PURE__ */ jsx50(SectionHeader, { title, look: "quiet", showActions: "always", actions: titleActions, className: "mt-4 shrink-0" }),
|
|
3465
|
+
groups === void 0 ? children : groups === null ? /* @__PURE__ */ jsx50(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
|
|
3346
3466
|
// No words, no line: an app that says nothing when it has no groups.
|
|
3347
|
-
emptyMessage ? /* @__PURE__ */
|
|
3348
|
-
) : groups.map((group) => /* @__PURE__ */
|
|
3467
|
+
emptyMessage ? /* @__PURE__ */ jsx50(Line, { message: emptyMessage }) : null
|
|
3468
|
+
) : groups.map((group) => /* @__PURE__ */ jsx50(Group, { group, selected, onSelect, storageKey }, group.id))
|
|
3349
3469
|
] });
|
|
3350
3470
|
}
|
|
3351
3471
|
|
|
3352
3472
|
// src/Popover.tsx
|
|
3353
3473
|
import { useMemo as useMemo3 } from "react";
|
|
3354
3474
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
3355
|
-
import { jsx as
|
|
3475
|
+
import { jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3356
3476
|
var GAP5 = 4;
|
|
3357
3477
|
var VIEWPORT_PAD5 = 8;
|
|
3358
3478
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
@@ -3361,7 +3481,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3361
3481
|
if (anchor instanceof Element) return anchor;
|
|
3362
3482
|
return { getBoundingClientRect: () => anchor };
|
|
3363
3483
|
}, [anchor]);
|
|
3364
|
-
return /* @__PURE__ */
|
|
3484
|
+
return /* @__PURE__ */ jsxs36(
|
|
3365
3485
|
BasePopover.Root,
|
|
3366
3486
|
{
|
|
3367
3487
|
open,
|
|
@@ -3369,8 +3489,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3369
3489
|
actionsRef,
|
|
3370
3490
|
modal: false,
|
|
3371
3491
|
children: [
|
|
3372
|
-
trigger && /* @__PURE__ */
|
|
3373
|
-
/* @__PURE__ */
|
|
3492
|
+
trigger && /* @__PURE__ */ jsx51(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
3493
|
+
/* @__PURE__ */ jsx51(BasePopover.Portal, { children: /* @__PURE__ */ jsx51(
|
|
3374
3494
|
BasePopover.Positioner,
|
|
3375
3495
|
{
|
|
3376
3496
|
anchor: anchorTarget,
|
|
@@ -3379,20 +3499,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3379
3499
|
sideOffset: GAP5,
|
|
3380
3500
|
collisionPadding: VIEWPORT_PAD5,
|
|
3381
3501
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
3382
|
-
children: /* @__PURE__ */
|
|
3502
|
+
children: /* @__PURE__ */ jsx51(
|
|
3383
3503
|
BasePopover.Popup,
|
|
3384
3504
|
{
|
|
3385
3505
|
"aria-label": ariaLabel,
|
|
3386
3506
|
initialFocus: trigger ? void 0 : false,
|
|
3387
3507
|
finalFocus,
|
|
3388
3508
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
3389
|
-
render: /* @__PURE__ */
|
|
3390
|
-
children: /* @__PURE__ */
|
|
3509
|
+
render: /* @__PURE__ */ jsx51(MenuPanel, {}),
|
|
3510
|
+
children: /* @__PURE__ */ jsx51(
|
|
3391
3511
|
ScrollArea,
|
|
3392
3512
|
{
|
|
3393
3513
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
3394
3514
|
contentClassName: cn("flex flex-col p-2", contentClassName),
|
|
3395
|
-
children: /* @__PURE__ */
|
|
3515
|
+
children: /* @__PURE__ */ jsx51(DividerInPanel.Provider, { value: true, children })
|
|
3396
3516
|
}
|
|
3397
3517
|
)
|
|
3398
3518
|
}
|
|
@@ -3405,14 +3525,14 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
3405
3525
|
}
|
|
3406
3526
|
|
|
3407
3527
|
// src/SuggestionMenu.tsx
|
|
3408
|
-
import { useCallback as useCallback4, useEffect as useEffect6, useId as
|
|
3409
|
-
import { jsx as
|
|
3528
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useId as useId3, useImperativeHandle, useMemo as useMemo4, useRef as useRef11, useState as useState11 } from "react";
|
|
3529
|
+
import { jsx as jsx52, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3410
3530
|
function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
|
|
3411
3531
|
const shown = useMemo4(() => sections.filter((section) => section.items.length > 0), [sections]);
|
|
3412
3532
|
const items = useMemo4(() => shown.flatMap((section) => section.items), [shown]);
|
|
3413
3533
|
const keys = items.map(itemKey).join("\n");
|
|
3414
|
-
const [highlight, setHighlight] =
|
|
3415
|
-
const base =
|
|
3534
|
+
const [highlight, setHighlight] = useState11(0);
|
|
3535
|
+
const base = useId3();
|
|
3416
3536
|
const listboxId = `${base}-list`;
|
|
3417
3537
|
const chosen = useRef11(null);
|
|
3418
3538
|
useEffect6(() => void (chosen.current = highlight > 0 ? keys.split("\n")[highlight] ?? null : null), [highlight]);
|
|
@@ -3471,7 +3591,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3471
3591
|
const { label, description, leading, shortcut, hint, size } = row(item);
|
|
3472
3592
|
return (
|
|
3473
3593
|
// A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
|
|
3474
|
-
/* @__PURE__ */
|
|
3594
|
+
/* @__PURE__ */ jsx52(
|
|
3475
3595
|
MenuItem,
|
|
3476
3596
|
{
|
|
3477
3597
|
role: "option",
|
|
@@ -3498,18 +3618,47 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
|
|
|
3498
3618
|
};
|
|
3499
3619
|
return (
|
|
3500
3620
|
// finalFocus={false}: focus never left the text, and a list that closes because focus moved elsewhere must not pull it back (71a4577b).
|
|
3501
|
-
/* @__PURE__ */
|
|
3502
|
-
i > 0 && /* @__PURE__ */
|
|
3503
|
-
section.label ? /* @__PURE__ */
|
|
3621
|
+
/* @__PURE__ */ jsx52(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, finalFocus: false, children: /* @__PURE__ */ jsx52("div", { ref: keepFocus, id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col gap-0.5", children: shown.map((section, i) => /* @__PURE__ */ jsxs37("div", { className: "contents", children: [
|
|
3622
|
+
i > 0 && /* @__PURE__ */ jsx52(MenuSeparator, {}),
|
|
3623
|
+
section.label ? /* @__PURE__ */ jsx52("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx52(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
|
|
3504
3624
|
] }, section.label ?? i)) }) })
|
|
3505
3625
|
);
|
|
3506
3626
|
}
|
|
3507
3627
|
|
|
3628
|
+
// src/ShowMore.tsx
|
|
3629
|
+
import { useLayoutEffect as useLayoutEffect5, useRef as useRef12, useState as useState12 } from "react";
|
|
3630
|
+
import { jsx as jsx53, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3631
|
+
var FADE_CLASSES = { surface: "from-bg-surface", inset: "from-bg-inset" };
|
|
3632
|
+
function ShowMore({ children, maxHeight = 96, surface = "surface", className }) {
|
|
3633
|
+
const box = useRef12(null);
|
|
3634
|
+
const [open, setOpen] = useState12(false);
|
|
3635
|
+
const [overflows, setOverflows] = useState12(false);
|
|
3636
|
+
useLayoutEffect5(() => {
|
|
3637
|
+
const el = box.current;
|
|
3638
|
+
if (!el) return;
|
|
3639
|
+
const measure = () => setOverflows(el.scrollHeight > maxHeight + 1);
|
|
3640
|
+
measure();
|
|
3641
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
3642
|
+
const observer = new ResizeObserver(measure);
|
|
3643
|
+
observer.observe(el);
|
|
3644
|
+
return () => observer.disconnect();
|
|
3645
|
+
}, [maxHeight]);
|
|
3646
|
+
const cut = overflows && !open;
|
|
3647
|
+
return /* @__PURE__ */ jsxs38("div", { className: cn("flex flex-col items-start", className), children: [
|
|
3648
|
+
/* @__PURE__ */ jsxs38("div", { ref: box, className: cn("relative w-full", cut && "overflow-hidden"), style: cut ? { maxHeight } : void 0, onFocus: cut ? () => setOpen(true) : void 0, children: [
|
|
3649
|
+
children,
|
|
3650
|
+
cut && /* @__PURE__ */ jsx53("div", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent", FADE_CLASSES[surface]) })
|
|
3651
|
+
] }),
|
|
3652
|
+
overflows && // `-ml-1.5`: the small button's own 6px inset, so its words start where the content's do.
|
|
3653
|
+
/* @__PURE__ */ jsx53(Button, { variant: "muted", size: "small", className: "-ml-1.5 mt-1", "aria-expanded": open, onClick: () => setOpen((o) => !o), children: open ? "Show less" : "Show more" })
|
|
3654
|
+
] });
|
|
3655
|
+
}
|
|
3656
|
+
|
|
3508
3657
|
// src/Toolbar.tsx
|
|
3509
3658
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
3510
|
-
import { jsx as
|
|
3659
|
+
import { jsx as jsx54 } from "react/jsx-runtime";
|
|
3511
3660
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
3512
|
-
const strip = /* @__PURE__ */
|
|
3661
|
+
const strip = /* @__PURE__ */ jsx54(
|
|
3513
3662
|
BaseToolbar.Root,
|
|
3514
3663
|
{
|
|
3515
3664
|
"aria-label": ariaLabel,
|
|
@@ -3520,27 +3669,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
3520
3669
|
}
|
|
3521
3670
|
);
|
|
3522
3671
|
if (!surface) return strip;
|
|
3523
|
-
return /* @__PURE__ */
|
|
3672
|
+
return /* @__PURE__ */ jsx54(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
3524
3673
|
}
|
|
3525
3674
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
3526
|
-
return /* @__PURE__ */
|
|
3675
|
+
return /* @__PURE__ */ jsx54(
|
|
3527
3676
|
BaseToolbar.Button,
|
|
3528
3677
|
{
|
|
3529
3678
|
ref,
|
|
3530
3679
|
disabled: disabled || !!disabledReason,
|
|
3531
3680
|
focusableWhenDisabled: true,
|
|
3532
|
-
render: /* @__PURE__ */
|
|
3681
|
+
render: /* @__PURE__ */ jsx54(IconButton, { disabled, disabledReason, ...props })
|
|
3533
3682
|
}
|
|
3534
3683
|
);
|
|
3535
3684
|
}
|
|
3536
3685
|
function ToolbarLink({ ref, href, ...props }) {
|
|
3537
|
-
return /* @__PURE__ */
|
|
3686
|
+
return /* @__PURE__ */ jsx54(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx54(IconButton, { href, ...props }) });
|
|
3538
3687
|
}
|
|
3539
3688
|
function ToolbarInput({ size, ...props }) {
|
|
3540
|
-
return /* @__PURE__ */
|
|
3689
|
+
return /* @__PURE__ */ jsx54(BaseToolbar.Input, { render: /* @__PURE__ */ jsx54(TextInput, { size }), ...props });
|
|
3541
3690
|
}
|
|
3542
3691
|
function ToolbarSeparator({ className }) {
|
|
3543
|
-
return /* @__PURE__ */
|
|
3692
|
+
return /* @__PURE__ */ jsx54(
|
|
3544
3693
|
BaseToolbar.Separator,
|
|
3545
3694
|
{
|
|
3546
3695
|
orientation: "vertical",
|
|
@@ -3550,9 +3699,9 @@ function ToolbarSeparator({ className }) {
|
|
|
3550
3699
|
}
|
|
3551
3700
|
|
|
3552
3701
|
// src/ReactionPicker.tsx
|
|
3553
|
-
import { jsx as
|
|
3702
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
3554
3703
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
3555
|
-
return /* @__PURE__ */
|
|
3704
|
+
return /* @__PURE__ */ jsx55(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
3556
3705
|
/*
|
|
3557
3706
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
3558
3707
|
would become the toolbar's item and the button inside it would never
|
|
@@ -3562,14 +3711,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3562
3711
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
3563
3712
|
and both say the meaning rather than the glyph.
|
|
3564
3713
|
*/
|
|
3565
|
-
/* @__PURE__ */
|
|
3714
|
+
/* @__PURE__ */ jsx55(
|
|
3566
3715
|
ToolbarButton,
|
|
3567
3716
|
{
|
|
3568
3717
|
"aria-label": option.label,
|
|
3569
3718
|
tooltip: option.label,
|
|
3570
3719
|
onClick: () => onSelect(option.emoji),
|
|
3571
3720
|
className: "size-7",
|
|
3572
|
-
children: /* @__PURE__ */
|
|
3721
|
+
children: /* @__PURE__ */ jsx55("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
|
|
3573
3722
|
},
|
|
3574
3723
|
option.emoji
|
|
3575
3724
|
)
|
|
@@ -3578,23 +3727,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
3578
3727
|
|
|
3579
3728
|
// src/PreviewCard.tsx
|
|
3580
3729
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
3581
|
-
import { jsx as
|
|
3730
|
+
import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3582
3731
|
var GAP6 = 12;
|
|
3583
3732
|
var VIEWPORT_PAD6 = 8;
|
|
3584
3733
|
var OPEN_DELAY2 = 350;
|
|
3585
3734
|
var CLOSE_DELAY = 200;
|
|
3586
3735
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
|
|
3587
|
-
return /* @__PURE__ */
|
|
3588
|
-
/* @__PURE__ */
|
|
3736
|
+
return /* @__PURE__ */ jsxs39(BasePreviewCard.Root, { children: [
|
|
3737
|
+
/* @__PURE__ */ jsx56(
|
|
3589
3738
|
BasePreviewCard.Trigger,
|
|
3590
3739
|
{
|
|
3591
3740
|
delay,
|
|
3592
3741
|
closeDelay,
|
|
3593
|
-
render: /* @__PURE__ */
|
|
3742
|
+
render: /* @__PURE__ */ jsx56("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
3594
3743
|
children
|
|
3595
3744
|
}
|
|
3596
3745
|
),
|
|
3597
|
-
/* @__PURE__ */
|
|
3746
|
+
/* @__PURE__ */ jsx56(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx56(
|
|
3598
3747
|
BasePreviewCard.Positioner,
|
|
3599
3748
|
{
|
|
3600
3749
|
side,
|
|
@@ -3602,12 +3751,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3602
3751
|
sideOffset: GAP6,
|
|
3603
3752
|
collisionPadding: VIEWPORT_PAD6,
|
|
3604
3753
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
3605
|
-
children: /* @__PURE__ */
|
|
3754
|
+
children: /* @__PURE__ */ jsx56(
|
|
3606
3755
|
BasePreviewCard.Popup,
|
|
3607
3756
|
{
|
|
3608
3757
|
className: cn("w-[360px] p-0 outline-none", className),
|
|
3609
|
-
render: /* @__PURE__ */
|
|
3610
|
-
children: /* @__PURE__ */
|
|
3758
|
+
render: /* @__PURE__ */ jsx56(MenuPanel, {}),
|
|
3759
|
+
children: /* @__PURE__ */ jsx56(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
|
|
3611
3760
|
}
|
|
3612
3761
|
)
|
|
3613
3762
|
}
|
|
@@ -3616,15 +3765,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
3616
3765
|
}
|
|
3617
3766
|
|
|
3618
3767
|
// src/Rail.tsx
|
|
3619
|
-
import { jsx as
|
|
3768
|
+
import { jsx as jsx57 } from "react/jsx-runtime";
|
|
3620
3769
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
3621
|
-
return /* @__PURE__ */
|
|
3770
|
+
return /* @__PURE__ */ jsx57("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
3622
3771
|
}
|
|
3623
3772
|
|
|
3624
3773
|
// src/RailItem.tsx
|
|
3625
|
-
import { jsx as
|
|
3774
|
+
import { jsx as jsx58, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3626
3775
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
3627
|
-
return /* @__PURE__ */
|
|
3776
|
+
return /* @__PURE__ */ jsxs40(
|
|
3628
3777
|
"a",
|
|
3629
3778
|
{
|
|
3630
3779
|
href,
|
|
@@ -3632,14 +3781,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
3632
3781
|
className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
3633
3782
|
...props,
|
|
3634
3783
|
children: [
|
|
3635
|
-
/* @__PURE__ */
|
|
3784
|
+
/* @__PURE__ */ jsx58(
|
|
3636
3785
|
"div",
|
|
3637
3786
|
{
|
|
3638
3787
|
className: cn(
|
|
3639
3788
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
3640
3789
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
3641
3790
|
),
|
|
3642
|
-
children: /* @__PURE__ */
|
|
3791
|
+
children: /* @__PURE__ */ jsx58(
|
|
3643
3792
|
"span",
|
|
3644
3793
|
{
|
|
3645
3794
|
className: cn(
|
|
@@ -3651,14 +3800,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
3651
3800
|
)
|
|
3652
3801
|
}
|
|
3653
3802
|
),
|
|
3654
|
-
/* @__PURE__ */
|
|
3803
|
+
/* @__PURE__ */ jsx58("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
3655
3804
|
]
|
|
3656
3805
|
}
|
|
3657
3806
|
);
|
|
3658
3807
|
}
|
|
3659
3808
|
|
|
3660
3809
|
// src/Property.tsx
|
|
3661
|
-
import { jsx as
|
|
3810
|
+
import { jsx as jsx59, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3662
3811
|
var VALUE_CLASSES = "contents";
|
|
3663
3812
|
function Property({ label, layout = "row", children, className }) {
|
|
3664
3813
|
if (layout === "stacked") {
|
|
@@ -3666,25 +3815,25 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
3666
3815
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
3667
3816
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
3668
3817
|
// 6px, and unifying means the bigger, calmer one.
|
|
3669
|
-
/* @__PURE__ */
|
|
3670
|
-
/* @__PURE__ */
|
|
3671
|
-
/* @__PURE__ */
|
|
3818
|
+
/* @__PURE__ */ jsxs41("dl", { className: cn("flex flex-col gap-3", className), children: [
|
|
3819
|
+
/* @__PURE__ */ jsx59("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
|
|
3820
|
+
/* @__PURE__ */ jsx59("dd", { className: VALUE_CLASSES, children })
|
|
3672
3821
|
] })
|
|
3673
3822
|
);
|
|
3674
3823
|
}
|
|
3675
|
-
return /* @__PURE__ */
|
|
3676
|
-
/* @__PURE__ */
|
|
3677
|
-
/* @__PURE__ */
|
|
3824
|
+
return /* @__PURE__ */ jsxs41("dl", { className: cn("flex items-center gap-2", className), children: [
|
|
3825
|
+
/* @__PURE__ */ jsx59("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
3826
|
+
/* @__PURE__ */ jsx59("dd", { className: VALUE_CLASSES, children })
|
|
3678
3827
|
] });
|
|
3679
3828
|
}
|
|
3680
3829
|
|
|
3681
3830
|
// src/Reaction.tsx
|
|
3682
3831
|
import { Toggle } from "@base-ui/react/toggle";
|
|
3683
|
-
import { jsx as
|
|
3832
|
+
import { jsx as jsx60, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3684
3833
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
3685
3834
|
return (
|
|
3686
3835
|
// @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
|
|
3687
|
-
/* @__PURE__ */
|
|
3836
|
+
/* @__PURE__ */ jsxs42(
|
|
3688
3837
|
Toggle,
|
|
3689
3838
|
{
|
|
3690
3839
|
pressed,
|
|
@@ -3706,8 +3855,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3706
3855
|
),
|
|
3707
3856
|
...props,
|
|
3708
3857
|
children: [
|
|
3709
|
-
/* @__PURE__ */
|
|
3710
|
-
/* @__PURE__ */
|
|
3858
|
+
/* @__PURE__ */ jsx60("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
|
|
3859
|
+
/* @__PURE__ */ jsx60("span", { className: CHIP_TEXT_CLASSES, children: count })
|
|
3711
3860
|
]
|
|
3712
3861
|
}
|
|
3713
3862
|
)
|
|
@@ -3717,9 +3866,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
3717
3866
|
// src/SearchInput.tsx
|
|
3718
3867
|
import "react";
|
|
3719
3868
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
3720
|
-
import { jsx as
|
|
3869
|
+
import { jsx as jsx61, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3721
3870
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
3722
|
-
return /* @__PURE__ */
|
|
3871
|
+
return /* @__PURE__ */ jsxs43(
|
|
3723
3872
|
"div",
|
|
3724
3873
|
{
|
|
3725
3874
|
className: cn(
|
|
@@ -3731,7 +3880,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3731
3880
|
className
|
|
3732
3881
|
),
|
|
3733
3882
|
children: [
|
|
3734
|
-
/* @__PURE__ */
|
|
3883
|
+
/* @__PURE__ */ jsx61(
|
|
3735
3884
|
Input3,
|
|
3736
3885
|
{
|
|
3737
3886
|
className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
|
|
@@ -3739,42 +3888,42 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
3739
3888
|
...props
|
|
3740
3889
|
}
|
|
3741
3890
|
),
|
|
3742
|
-
shortcut && /* @__PURE__ */
|
|
3891
|
+
shortcut && /* @__PURE__ */ jsx61(Kbd, { children: shortcut })
|
|
3743
3892
|
]
|
|
3744
3893
|
}
|
|
3745
3894
|
);
|
|
3746
3895
|
}
|
|
3747
3896
|
|
|
3748
3897
|
// src/Panel.tsx
|
|
3749
|
-
import { jsx as
|
|
3898
|
+
import { jsx as jsx62, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3750
3899
|
function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
|
|
3751
|
-
return /* @__PURE__ */
|
|
3752
|
-
/* @__PURE__ */
|
|
3900
|
+
return /* @__PURE__ */ jsxs44("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
|
|
3901
|
+
/* @__PURE__ */ jsx62(ContainerHeader, { title, chevron, actions }),
|
|
3753
3902
|
broken ? (
|
|
3754
3903
|
// The message takes the room the body had and centres itself in it.
|
|
3755
|
-
/* @__PURE__ */
|
|
3756
|
-
) : /* @__PURE__ */
|
|
3757
|
-
!broken && footer && /* @__PURE__ */
|
|
3904
|
+
/* @__PURE__ */ jsx62("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
|
|
3905
|
+
) : /* @__PURE__ */ jsx62(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
|
|
3906
|
+
!broken && footer && /* @__PURE__ */ jsx62("div", { className: "shrink-0", children: footer })
|
|
3758
3907
|
] });
|
|
3759
3908
|
}
|
|
3760
3909
|
function Panel(props) {
|
|
3761
|
-
return /* @__PURE__ */
|
|
3910
|
+
return /* @__PURE__ */ jsx62(
|
|
3762
3911
|
ErrorBoundary,
|
|
3763
3912
|
{
|
|
3764
3913
|
label: "panel",
|
|
3765
3914
|
frame: (message) => (
|
|
3766
3915
|
// Only the name comes back with the message: the actions and the footer may be what threw.
|
|
3767
|
-
/* @__PURE__ */
|
|
3916
|
+
/* @__PURE__ */ jsx62(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
|
|
3768
3917
|
),
|
|
3769
|
-
children: /* @__PURE__ */
|
|
3918
|
+
children: /* @__PURE__ */ jsx62(Frame, { ...props })
|
|
3770
3919
|
}
|
|
3771
3920
|
);
|
|
3772
3921
|
}
|
|
3773
3922
|
|
|
3774
3923
|
// src/ListColumn.tsx
|
|
3775
|
-
import { jsx as
|
|
3924
|
+
import { jsx as jsx63, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3776
3925
|
function Column({ title, chevron = false, titleMenu, actions, above, collapsed = false, children, className, broken = false }) {
|
|
3777
|
-
return /* @__PURE__ */
|
|
3926
|
+
return /* @__PURE__ */ jsxs45(
|
|
3778
3927
|
"div",
|
|
3779
3928
|
{
|
|
3780
3929
|
className: cn(
|
|
@@ -3785,35 +3934,35 @@ function Column({ title, chevron = false, titleMenu, actions, above, collapsed =
|
|
|
3785
3934
|
),
|
|
3786
3935
|
"data-collapsed": collapsed || void 0,
|
|
3787
3936
|
children: [
|
|
3788
|
-
/* @__PURE__ */
|
|
3937
|
+
/* @__PURE__ */ jsx63(ContainerHeader, { title, chevron, titleMenu, actions }),
|
|
3789
3938
|
above,
|
|
3790
3939
|
broken ? (
|
|
3791
3940
|
// The message takes the room the list had and centres itself in it (Katerina, 19 September).
|
|
3792
|
-
/* @__PURE__ */
|
|
3793
|
-
) : /* @__PURE__ */
|
|
3941
|
+
/* @__PURE__ */ jsx63("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
|
|
3942
|
+
) : /* @__PURE__ */ jsx63(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
|
|
3794
3943
|
]
|
|
3795
3944
|
}
|
|
3796
3945
|
);
|
|
3797
3946
|
}
|
|
3798
3947
|
function ListColumn(props) {
|
|
3799
|
-
return /* @__PURE__ */
|
|
3948
|
+
return /* @__PURE__ */ jsx63(
|
|
3800
3949
|
ErrorBoundary,
|
|
3801
3950
|
{
|
|
3802
3951
|
label: "list panel",
|
|
3803
3952
|
frame: (message) => (
|
|
3804
3953
|
// Only the name comes back with the message: the actions and the row above may be what threw.
|
|
3805
|
-
/* @__PURE__ */
|
|
3954
|
+
/* @__PURE__ */ jsx63(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
|
|
3806
3955
|
),
|
|
3807
|
-
children: /* @__PURE__ */
|
|
3956
|
+
children: /* @__PURE__ */ jsx63(Column, { ...props })
|
|
3808
3957
|
}
|
|
3809
3958
|
);
|
|
3810
3959
|
}
|
|
3811
3960
|
|
|
3812
3961
|
// src/Tabs.tsx
|
|
3813
3962
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
3814
|
-
import { jsx as
|
|
3963
|
+
import { Fragment as Fragment14, jsx as jsx64, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3815
3964
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
3816
|
-
return /* @__PURE__ */
|
|
3965
|
+
return /* @__PURE__ */ jsx64(
|
|
3817
3966
|
BaseTabs.Root,
|
|
3818
3967
|
{
|
|
3819
3968
|
value: active,
|
|
@@ -3821,14 +3970,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3821
3970
|
if (details.reason === "none") onChange(value);
|
|
3822
3971
|
},
|
|
3823
3972
|
className,
|
|
3824
|
-
children: /* @__PURE__ */
|
|
3973
|
+
children: /* @__PURE__ */ jsx64(
|
|
3825
3974
|
BaseTabs.List,
|
|
3826
3975
|
{
|
|
3827
3976
|
activateOnFocus: true,
|
|
3828
3977
|
"aria-label": aria["aria-label"],
|
|
3829
3978
|
"aria-labelledby": aria["aria-labelledby"],
|
|
3830
3979
|
className: "flex items-center gap-2",
|
|
3831
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
3980
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs46(
|
|
3832
3981
|
BaseTabs.Tab,
|
|
3833
3982
|
{
|
|
3834
3983
|
value: tab.id,
|
|
@@ -3841,10 +3990,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3841
3990
|
),
|
|
3842
3991
|
children: [
|
|
3843
3992
|
tab.icon,
|
|
3844
|
-
/* @__PURE__ */
|
|
3993
|
+
/* @__PURE__ */ jsxs46("span", { className: "flex items-baseline", children: [
|
|
3845
3994
|
tab.label,
|
|
3846
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
3847
|
-
] })
|
|
3995
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx64("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
3996
|
+
] }),
|
|
3997
|
+
tab.unread ? /* @__PURE__ */ jsxs46(Fragment14, { children: [
|
|
3998
|
+
/* @__PURE__ */ jsx64(UnreadDot, { className: "h-auto w-auto" }),
|
|
3999
|
+
/* @__PURE__ */ jsx64("span", { className: "sr-only", children: "new" })
|
|
4000
|
+
] }) : null
|
|
3848
4001
|
]
|
|
3849
4002
|
},
|
|
3850
4003
|
tab.id
|
|
@@ -3859,7 +4012,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
3859
4012
|
import { createContext as createContext6, useContext as useContext6, useMemo as useMemo5 } from "react";
|
|
3860
4013
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
3861
4014
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
3862
|
-
import { jsx as
|
|
4015
|
+
import { jsx as jsx65, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3863
4016
|
var SURFACE_STYLES = {
|
|
3864
4017
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
3865
4018
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
|
|
@@ -3895,16 +4048,16 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
3895
4048
|
);
|
|
3896
4049
|
function LeadingIcon({ type }) {
|
|
3897
4050
|
const Icon = ICONS[type];
|
|
3898
|
-
return /* @__PURE__ */
|
|
4051
|
+
return /* @__PURE__ */ jsx65(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
3899
4052
|
}
|
|
3900
4053
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
3901
4054
|
const hasAction = !!(actionLabel && onAction);
|
|
3902
|
-
return /* @__PURE__ */
|
|
3903
|
-
/* @__PURE__ */
|
|
3904
|
-
leadingIcon && /* @__PURE__ */
|
|
3905
|
-
/* @__PURE__ */
|
|
4055
|
+
return /* @__PURE__ */ jsxs47("div", { className: pillClassName(type, hasAction, className), children: [
|
|
4056
|
+
/* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4057
|
+
leadingIcon && /* @__PURE__ */ jsx65(LeadingIcon, { type }),
|
|
4058
|
+
/* @__PURE__ */ jsx65("span", { className: LABEL_CLASSES, children: label })
|
|
3906
4059
|
] }),
|
|
3907
|
-
hasAction && /* @__PURE__ */
|
|
4060
|
+
hasAction && /* @__PURE__ */ jsx65(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
3908
4061
|
] });
|
|
3909
4062
|
}
|
|
3910
4063
|
var ToastContext = createContext6(null);
|
|
@@ -3925,9 +4078,9 @@ function ToastProvider({ children }) {
|
|
|
3925
4078
|
}),
|
|
3926
4079
|
[manager]
|
|
3927
4080
|
);
|
|
3928
|
-
return /* @__PURE__ */
|
|
4081
|
+
return /* @__PURE__ */ jsx65(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs47(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
3929
4082
|
children,
|
|
3930
|
-
/* @__PURE__ */
|
|
4083
|
+
/* @__PURE__ */ jsx65(BaseToast.Portal, { children: /* @__PURE__ */ jsx65(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx65(ToastList, {}) }) })
|
|
3931
4084
|
] }) });
|
|
3932
4085
|
}
|
|
3933
4086
|
function ToastList() {
|
|
@@ -3935,25 +4088,25 @@ function ToastList() {
|
|
|
3935
4088
|
return toasts.map((toast) => {
|
|
3936
4089
|
const type = toast.type ?? "neutral";
|
|
3937
4090
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
3938
|
-
return /* @__PURE__ */
|
|
4091
|
+
return /* @__PURE__ */ jsxs47(
|
|
3939
4092
|
BaseToast.Root,
|
|
3940
4093
|
{
|
|
3941
4094
|
toast,
|
|
3942
4095
|
swipeDirection: ["left", "down"],
|
|
3943
4096
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
3944
4097
|
children: [
|
|
3945
|
-
/* @__PURE__ */
|
|
3946
|
-
leadingIcon && /* @__PURE__ */
|
|
3947
|
-
/* @__PURE__ */
|
|
4098
|
+
/* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4099
|
+
leadingIcon && /* @__PURE__ */ jsx65(LeadingIcon, { type }),
|
|
4100
|
+
/* @__PURE__ */ jsx65(BaseToast.Title, { render: /* @__PURE__ */ jsx65("span", {}), className: LABEL_CLASSES })
|
|
3948
4101
|
] }),
|
|
3949
|
-
actionLabel && /* @__PURE__ */
|
|
4102
|
+
actionLabel && /* @__PURE__ */ jsx65(
|
|
3950
4103
|
BaseToast.Action,
|
|
3951
4104
|
{
|
|
3952
4105
|
onClick: () => {
|
|
3953
4106
|
onAction?.();
|
|
3954
4107
|
close(toast.id);
|
|
3955
4108
|
},
|
|
3956
|
-
render: /* @__PURE__ */
|
|
4109
|
+
render: /* @__PURE__ */ jsx65(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
3957
4110
|
}
|
|
3958
4111
|
)
|
|
3959
4112
|
]
|
|
@@ -4024,6 +4177,8 @@ export {
|
|
|
4024
4177
|
Lightbox,
|
|
4025
4178
|
Link,
|
|
4026
4179
|
ListColumn,
|
|
4180
|
+
MembersDialog,
|
|
4181
|
+
MembersPill,
|
|
4027
4182
|
Menu,
|
|
4028
4183
|
MenuItem,
|
|
4029
4184
|
MenuPanel,
|
|
@@ -4051,6 +4206,7 @@ export {
|
|
|
4051
4206
|
SectionHeader,
|
|
4052
4207
|
SectionLabel,
|
|
4053
4208
|
Select,
|
|
4209
|
+
ShowMore,
|
|
4054
4210
|
Sidebar,
|
|
4055
4211
|
SkeletonBar,
|
|
4056
4212
|
SkeletonList,
|