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