@estiva-app/ui 0.15.0 → 0.16.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/Breadcrumb.d.ts.map +1 -1
- package/dist/CommandPalette.d.ts +114 -0
- package/dist/CommandPalette.d.ts.map +1 -0
- package/dist/Menu.d.ts +4 -0
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Toast.d.ts.map +1 -1
- package/dist/eslint/has-a-page-and-a-story.d.ts +4 -0
- package/dist/eslint/has-a-page-and-a-story.d.ts.map +1 -0
- package/dist/eslint/index.d.ts +15 -1
- package/dist/eslint/index.d.ts.map +1 -1
- package/dist/eslint/index.js +176 -8
- package/dist/eslint/index.js.map +3 -3
- package/dist/eslint/no-hand-rolled-behaviour.d.ts +3 -0
- package/dist/eslint/no-hand-rolled-behaviour.d.ts.map +1 -0
- package/dist/eslint/raw-element-outside-a-wrapper.d.ts +29 -0
- package/dist/eslint/raw-element-outside-a-wrapper.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +609 -287
- package/dist/index.js.map +4 -4
- package/package.json +5 -1
- package/src/Breadcrumb.tsx +6 -2
- package/src/CommandPalette.mdx +133 -0
- package/src/CommandPalette.stories.tsx +416 -0
- package/src/CommandPalette.test.tsx +392 -0
- package/src/CommandPalette.tsx +643 -0
- package/src/Menu.tsx +4 -2
- package/src/Toast.tsx +12 -24
- package/src/eslint/has-a-page-and-a-story.test.ts +57 -0
- package/src/eslint/has-a-page-and-a-story.ts +97 -0
- package/src/eslint/index.test.ts +35 -3
- package/src/eslint/index.ts +58 -13
- package/src/eslint/no-hand-rolled-behaviour.test.ts +70 -0
- package/src/eslint/no-hand-rolled-behaviour.ts +116 -0
- package/src/eslint/raw-element-outside-a-wrapper.test.ts +82 -0
- package/src/eslint/raw-element-outside-a-wrapper.ts +85 -0
- package/src/index.ts +17 -0
- package/stories/Choosing.mdx +1 -0
package/dist/index.js
CHANGED
|
@@ -789,6 +789,20 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
|
|
|
789
789
|
] });
|
|
790
790
|
}
|
|
791
791
|
|
|
792
|
+
// src/CommandPalette.tsx
|
|
793
|
+
import {
|
|
794
|
+
createContext as createContext2,
|
|
795
|
+
useContext as useContext2,
|
|
796
|
+
useEffect,
|
|
797
|
+
useLayoutEffect as useLayoutEffect2,
|
|
798
|
+
useMemo as useMemo2,
|
|
799
|
+
useRef as useRef2,
|
|
800
|
+
useState as useState3
|
|
801
|
+
} from "react";
|
|
802
|
+
import { Dialog } from "@base-ui/react/dialog";
|
|
803
|
+
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
804
|
+
import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
|
|
805
|
+
|
|
792
806
|
// src/ChipInput.tsx
|
|
793
807
|
import { useMemo, useState as useState2 } from "react";
|
|
794
808
|
import { Button as BaseButton4 } from "@base-ui/react/button";
|
|
@@ -1177,8 +1191,376 @@ function ChipInput({
|
|
|
1177
1191
|
var GAP3 = 4;
|
|
1178
1192
|
var VIEWPORT_PAD3 = 8;
|
|
1179
1193
|
|
|
1194
|
+
// src/EmptyState.tsx
|
|
1195
|
+
import { IconMessage2 } from "@tabler/icons-react";
|
|
1196
|
+
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1197
|
+
function EmptyState({ icon, message, scope = "page", className }) {
|
|
1198
|
+
if (scope === "section") {
|
|
1199
|
+
return /* @__PURE__ */ jsx19("p", { className: cn("text-caption text-text-muted", className), children: message });
|
|
1200
|
+
}
|
|
1201
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
1202
|
+
/* @__PURE__ */ jsx19("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx19(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1203
|
+
/* @__PURE__ */ jsx19("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1204
|
+
] });
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// src/Field.tsx
|
|
1208
|
+
import { cloneElement, isValidElement } from "react";
|
|
1209
|
+
import { Field as BaseField } from "@base-ui/react/field";
|
|
1210
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1211
|
+
var LINE_STYLES = {
|
|
1212
|
+
helper: "text-caption text-text-muted",
|
|
1213
|
+
warning: "text-caption text-warning-default",
|
|
1214
|
+
error: "text-caption text-error-default"
|
|
1215
|
+
};
|
|
1216
|
+
function Field({ label, required = false, helper, error, children }) {
|
|
1217
|
+
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1218
|
+
"aria-required": children.props["aria-required"] ?? true
|
|
1219
|
+
}) : children;
|
|
1220
|
+
return /* @__PURE__ */ jsxs13(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
|
|
1221
|
+
/* @__PURE__ */ jsxs13(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1222
|
+
label,
|
|
1223
|
+
required && /* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1224
|
+
] }),
|
|
1225
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1.5", children: [
|
|
1226
|
+
control,
|
|
1227
|
+
error != null ? /* @__PURE__ */ jsx20(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx20(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1228
|
+
] })
|
|
1229
|
+
] });
|
|
1230
|
+
}
|
|
1231
|
+
function FieldLine({ tone = "helper", children, className }) {
|
|
1232
|
+
return /* @__PURE__ */ jsx20("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/Skeleton.tsx
|
|
1236
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1237
|
+
function SkeletonBar({ className, style }) {
|
|
1238
|
+
return /* @__PURE__ */ jsx21("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1239
|
+
}
|
|
1240
|
+
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1241
|
+
function SkeletonRow({ barWidth = 130 }) {
|
|
1242
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1243
|
+
/* @__PURE__ */ jsx21(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1244
|
+
/* @__PURE__ */ jsx21(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1245
|
+
] });
|
|
1246
|
+
}
|
|
1247
|
+
function SkeletonList({ rows = 8, className }) {
|
|
1248
|
+
return /* @__PURE__ */ jsx21("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx21(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// src/CommandPalette.tsx
|
|
1252
|
+
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1253
|
+
var PaletteContext = createContext2(null);
|
|
1254
|
+
function usePalette(part) {
|
|
1255
|
+
const palette = useContext2(PaletteContext);
|
|
1256
|
+
if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
|
|
1257
|
+
return palette;
|
|
1258
|
+
}
|
|
1259
|
+
var CONTROL = 'input:not([type="hidden"]):not([tabindex="-1"]), textarea, button:not([tabindex="-1"]), [role="combobox"]';
|
|
1260
|
+
function firstControl(popup) {
|
|
1261
|
+
if (!popup) return null;
|
|
1262
|
+
const field = popup.querySelector("[data-command-palette-field]");
|
|
1263
|
+
if (field) return field;
|
|
1264
|
+
return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL) ?? null;
|
|
1265
|
+
}
|
|
1266
|
+
function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
|
|
1267
|
+
const popupRef = useRef2(null);
|
|
1268
|
+
useEffect(() => {
|
|
1269
|
+
if (!open) return;
|
|
1270
|
+
const frame = requestAnimationFrame(() => {
|
|
1271
|
+
const popup = popupRef.current;
|
|
1272
|
+
const active = document.activeElement;
|
|
1273
|
+
if (popup && (!active || active === document.body || active === popup)) firstControl(popup)?.focus();
|
|
1274
|
+
});
|
|
1275
|
+
return () => cancelAnimationFrame(frame);
|
|
1276
|
+
});
|
|
1277
|
+
const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
|
|
1278
|
+
return /* @__PURE__ */ jsx22(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs15(Dialog.Portal, { children: [
|
|
1279
|
+
/* @__PURE__ */ jsx22(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1280
|
+
/* @__PURE__ */ jsx22(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx22(
|
|
1281
|
+
Dialog.Popup,
|
|
1282
|
+
{
|
|
1283
|
+
ref: popupRef,
|
|
1284
|
+
"aria-label": label,
|
|
1285
|
+
initialFocus: () => firstControl(popupRef.current) ?? true,
|
|
1286
|
+
onFocus: (e) => {
|
|
1287
|
+
if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
|
|
1288
|
+
},
|
|
1289
|
+
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",
|
|
1290
|
+
children: /* @__PURE__ */ jsx22(PaletteContext.Provider, { value: context, children })
|
|
1291
|
+
}
|
|
1292
|
+
) })
|
|
1293
|
+
] }) });
|
|
1294
|
+
}
|
|
1295
|
+
function LevelChip({ chip, onBack }) {
|
|
1296
|
+
return /* @__PURE__ */ jsx22(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
|
|
1297
|
+
}
|
|
1298
|
+
function useBack(chip, popupRef) {
|
|
1299
|
+
return () => {
|
|
1300
|
+
if (!chip) return;
|
|
1301
|
+
chip.onBack();
|
|
1302
|
+
requestAnimationFrame(() => firstControl(popupRef.current)?.focus());
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
function Footer({ keys }) {
|
|
1306
|
+
const { where } = usePalette("The footer");
|
|
1307
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5 text-caption text-text-secondary signal:font-mono signal:text-small signal:text-text-muted", children: [
|
|
1308
|
+
/* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1 truncate", children: where }),
|
|
1309
|
+
keys.map(([key, word]) => /* @__PURE__ */ jsxs15("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
1310
|
+
/* @__PURE__ */ jsx22(Kbd, { children: key }),
|
|
1311
|
+
" ",
|
|
1312
|
+
word
|
|
1313
|
+
] }, key))
|
|
1314
|
+
] });
|
|
1315
|
+
}
|
|
1316
|
+
var lowerFirst = (s) => s.charAt(0).toLowerCase() + s.slice(1);
|
|
1317
|
+
function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip, pending, empty, children }) {
|
|
1318
|
+
const { modKey, popupRef } = usePalette("CommandPaletteSearch");
|
|
1319
|
+
const back = useBack(chip, popupRef);
|
|
1320
|
+
const items = useMemo2(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
|
|
1321
|
+
const rows = items.flatMap((g) => g.items);
|
|
1322
|
+
const [litId, setLitId] = useState3();
|
|
1323
|
+
const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
|
|
1324
|
+
const inputRef = useRef2(null);
|
|
1325
|
+
const reported = useRef2({});
|
|
1326
|
+
const settled = useRef2(null);
|
|
1327
|
+
useLayoutEffect2(() => {
|
|
1328
|
+
const before = settled.current;
|
|
1329
|
+
const now = reported.current;
|
|
1330
|
+
if (before?.id && now.reason === "none" && now.id !== before.id && before.query === query && before.level === chip?.label) {
|
|
1331
|
+
const ids = rows.map((r) => r.id);
|
|
1332
|
+
const want = ids.indexOf(before.id);
|
|
1333
|
+
const at = now.id === void 0 ? -1 : ids.indexOf(now.id);
|
|
1334
|
+
const input = inputRef.current;
|
|
1335
|
+
if (input && want !== -1 && at !== -1) {
|
|
1336
|
+
const key = want > at ? "ArrowDown" : "ArrowUp";
|
|
1337
|
+
for (let step = 0; step < Math.abs(want - at); step++) {
|
|
1338
|
+
input.dispatchEvent(new KeyboardEvent("keydown", { key, bubbles: true, cancelable: true }));
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
settled.current = { id: reported.current.id, query, level: chip?.label };
|
|
1343
|
+
});
|
|
1344
|
+
const onKeyDown = (e) => {
|
|
1345
|
+
if (e.key === "Home" || e.key === "End") {
|
|
1346
|
+
e.preventBaseUIHandler();
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
const field = e.currentTarget;
|
|
1350
|
+
const collapsed = field.selectionStart === field.selectionEnd;
|
|
1351
|
+
const atStart = collapsed && field.selectionStart === 0;
|
|
1352
|
+
const atEnd = collapsed && field.selectionEnd === field.value.length;
|
|
1353
|
+
if (e.key === "Backspace" && (e.ctrlKey || e.metaKey)) {
|
|
1354
|
+
if (lit?.onForget) {
|
|
1355
|
+
e.preventDefault();
|
|
1356
|
+
lit.onForget();
|
|
1357
|
+
}
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
if (e.key === "Backspace" && atStart && chip && !e.shiftKey && !e.altKey) {
|
|
1361
|
+
e.preventDefault();
|
|
1362
|
+
back();
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
if (e.key === "Tab" && !e.shiftKey) {
|
|
1366
|
+
e.preventDefault();
|
|
1367
|
+
lit?.onGoIn?.();
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
if (e.key === "ArrowRight" && atEnd && lit?.onGoIn && !e.shiftKey) {
|
|
1371
|
+
e.preventDefault();
|
|
1372
|
+
lit.onGoIn();
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
const keys = [
|
|
1376
|
+
...rows.length > 1 ? [["\u2191\u2193", "move"]] : [],
|
|
1377
|
+
...lit ? [lit.onGoIn ? ["Tab", "go in"] : ["Enter", "open"]] : [],
|
|
1378
|
+
...lit?.onForget ? [[`${modKey}+Backspace`, "forget"]] : [],
|
|
1379
|
+
// Backspace goes back from the start of the field; it is named while the
|
|
1380
|
+
// field is empty, when that is what it will do.
|
|
1381
|
+
...chip && query === "" ? [["Backspace", "back"]] : [],
|
|
1382
|
+
["Esc", "close"]
|
|
1383
|
+
];
|
|
1384
|
+
return /* @__PURE__ */ jsxs15(
|
|
1385
|
+
Autocomplete.Root,
|
|
1386
|
+
{
|
|
1387
|
+
items,
|
|
1388
|
+
mode: "none",
|
|
1389
|
+
inline: true,
|
|
1390
|
+
open: true,
|
|
1391
|
+
value: query,
|
|
1392
|
+
onValueChange: (value, details) => {
|
|
1393
|
+
if (details.reason === "item-press") return;
|
|
1394
|
+
onQueryChange(value);
|
|
1395
|
+
},
|
|
1396
|
+
itemToStringValue: (row) => row.label,
|
|
1397
|
+
autoHighlight: "always",
|
|
1398
|
+
keepHighlight: true,
|
|
1399
|
+
loopFocus: false,
|
|
1400
|
+
onItemHighlighted: (row, details) => {
|
|
1401
|
+
const id = row?.id;
|
|
1402
|
+
reported.current = { id, reason: details.reason };
|
|
1403
|
+
setLitId(id);
|
|
1404
|
+
},
|
|
1405
|
+
children: [
|
|
1406
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1407
|
+
/* @__PURE__ */ jsx22(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
1408
|
+
chip && /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back }),
|
|
1409
|
+
/* @__PURE__ */ jsx22(
|
|
1410
|
+
Autocomplete.Input,
|
|
1411
|
+
{
|
|
1412
|
+
ref: inputRef,
|
|
1413
|
+
"data-command-palette-field": "",
|
|
1414
|
+
placeholder,
|
|
1415
|
+
"aria-label": placeholder,
|
|
1416
|
+
onKeyDown,
|
|
1417
|
+
className: "min-w-0 flex-1 bg-transparent text-input-value text-text-primary outline-none placeholder:text-text-muted"
|
|
1418
|
+
}
|
|
1419
|
+
)
|
|
1420
|
+
] }),
|
|
1421
|
+
/* @__PURE__ */ jsxs15(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
1422
|
+
children != null && /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
1423
|
+
/* @__PURE__ */ jsx22(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs15(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
|
|
1424
|
+
/* @__PURE__ */ jsx22(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx22(SectionLabel, { className: "text-text-secondary", children: group.value }) }),
|
|
1425
|
+
/* @__PURE__ */ jsx22(Autocomplete.Collection, { children: (row) => (
|
|
1426
|
+
/* The menu row, as the list's own option — the way Select
|
|
1427
|
+
puts it on `Select.Item`. One row, two parts. */
|
|
1428
|
+
/* @__PURE__ */ jsx22(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx22(
|
|
1429
|
+
MenuItemBody,
|
|
1430
|
+
{
|
|
1431
|
+
size: "tall",
|
|
1432
|
+
label: row.label,
|
|
1433
|
+
description: row.description,
|
|
1434
|
+
leading: /* @__PURE__ */ jsx22(RowLeading, { row }),
|
|
1435
|
+
submenu: !!row.onGoIn,
|
|
1436
|
+
hint: row.onGoIn ? /* @__PURE__ */ jsx22(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx22(EnterHint, {})
|
|
1437
|
+
}
|
|
1438
|
+
) }, row.id)
|
|
1439
|
+
) })
|
|
1440
|
+
] }, group.value) }),
|
|
1441
|
+
/* @__PURE__ */ jsx22(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs15(Fragment3, { children: [
|
|
1442
|
+
/* @__PURE__ */ jsx22(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
1443
|
+
/* @__PURE__ */ jsx22("span", { className: "text-caption text-text-muted", children: pending })
|
|
1444
|
+
] }) }),
|
|
1445
|
+
/* @__PURE__ */ jsx22(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx22(EmptyState, { scope: "section", message: empty }) })
|
|
1446
|
+
] }),
|
|
1447
|
+
/* @__PURE__ */ jsx22(Footer, { keys })
|
|
1448
|
+
]
|
|
1449
|
+
}
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
function RowLeading({ row }) {
|
|
1453
|
+
if (row.icon != null) {
|
|
1454
|
+
return /* @__PURE__ */ jsx22("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
|
|
1455
|
+
}
|
|
1456
|
+
return /* @__PURE__ */ jsx22("span", { className: "flex size-8 items-center justify-center", children: row.leading });
|
|
1457
|
+
}
|
|
1458
|
+
var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1459
|
+
function isTextField(el) {
|
|
1460
|
+
if (el instanceof HTMLTextAreaElement) return true;
|
|
1461
|
+
return el instanceof HTMLInputElement && TEXT_TYPES.has(el.getAttribute("type") ?? "") && el.getAttribute("role") !== "combobox" && el.tabIndex >= 0;
|
|
1462
|
+
}
|
|
1463
|
+
function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
|
|
1464
|
+
const { modKey, popupRef } = usePalette("CommandPaletteForm");
|
|
1465
|
+
const back = useBack(chip, popupRef);
|
|
1466
|
+
const frameRef = useRef2(null);
|
|
1467
|
+
const busy = !!working;
|
|
1468
|
+
const busyRef = useRef2(busy);
|
|
1469
|
+
busyRef.current = busy;
|
|
1470
|
+
const returnTo = useRef2(null);
|
|
1471
|
+
const firstInvalid = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL) ?? null;
|
|
1472
|
+
const submit = () => {
|
|
1473
|
+
if (busyRef.current || submitWaits) return;
|
|
1474
|
+
const active = document.activeElement;
|
|
1475
|
+
returnTo.current = active instanceof HTMLElement && frameRef.current?.contains(active) ? active : null;
|
|
1476
|
+
onSubmit();
|
|
1477
|
+
requestAnimationFrame(() => {
|
|
1478
|
+
if (!busyRef.current) firstInvalid()?.focus();
|
|
1479
|
+
});
|
|
1480
|
+
};
|
|
1481
|
+
useLayoutEffect2(() => {
|
|
1482
|
+
if (busy) {
|
|
1483
|
+
frameRef.current?.focus();
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
if (document.activeElement !== frameRef.current) return;
|
|
1487
|
+
const was = returnTo.current;
|
|
1488
|
+
const target = firstInvalid() ?? (was?.isConnected && !was.disabled ? was : null) ?? firstControl(popupRef.current);
|
|
1489
|
+
target?.focus();
|
|
1490
|
+
}, [busy]);
|
|
1491
|
+
const backWorksFrom = (el) => {
|
|
1492
|
+
const frame = frameRef.current;
|
|
1493
|
+
if (!frame || busy || !el || !frame.contains(el)) return false;
|
|
1494
|
+
if (isTextField(el)) return el.value === "";
|
|
1495
|
+
return ![...frame.querySelectorAll("input, textarea")].some(isTextField);
|
|
1496
|
+
};
|
|
1497
|
+
const [backNamed, setBackNamed] = useState3(false);
|
|
1498
|
+
const measure = () => setBackNamed(backWorksFrom(document.activeElement));
|
|
1499
|
+
useLayoutEffect2(measure);
|
|
1500
|
+
const onKeyDown = (e) => {
|
|
1501
|
+
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
1502
|
+
e.preventDefault();
|
|
1503
|
+
submit();
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
if (e.key === "Backspace" && !e.ctrlKey && !e.metaKey && !e.altKey && backWorksFrom(e.target)) {
|
|
1507
|
+
e.preventDefault();
|
|
1508
|
+
back();
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
const keys = [
|
|
1512
|
+
...!busy && !submitWaits ? [[`${modKey}+Enter`, lowerFirst(submitLabel)]] : [],
|
|
1513
|
+
...backNamed ? [["Backspace", "back"]] : [],
|
|
1514
|
+
["Esc", "close"]
|
|
1515
|
+
];
|
|
1516
|
+
return /* @__PURE__ */ jsxs15("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
|
|
1517
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1518
|
+
icon != null && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
1519
|
+
/* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back })
|
|
1520
|
+
] }),
|
|
1521
|
+
/* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx22("fieldset", { "data-command-palette-fields": "", disabled: busy, className: "contents", children: /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-4", children }) }) }),
|
|
1522
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
1523
|
+
/* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx22(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx22(FieldLine, { tone: "error", children: error }) : null }),
|
|
1524
|
+
/* @__PURE__ */ jsx22(
|
|
1525
|
+
Button,
|
|
1526
|
+
{
|
|
1527
|
+
variant: "primary",
|
|
1528
|
+
onClick: submit,
|
|
1529
|
+
disabled: busy,
|
|
1530
|
+
disabledReason: busy ? void 0 : submitWaits,
|
|
1531
|
+
leadingIcon: busy ? /* @__PURE__ */ jsx22(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
|
|
1532
|
+
children: working ? working.button : submitLabel
|
|
1533
|
+
}
|
|
1534
|
+
)
|
|
1535
|
+
] }),
|
|
1536
|
+
/* @__PURE__ */ jsx22(Footer, { keys })
|
|
1537
|
+
] });
|
|
1538
|
+
}
|
|
1539
|
+
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
1540
|
+
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
1541
|
+
return /* @__PURE__ */ jsxs15("div", { role: "status", className: "flex flex-col gap-2", children: [
|
|
1542
|
+
/* @__PURE__ */ jsxs15("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
1543
|
+
/* @__PURE__ */ jsx22(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
1544
|
+
children
|
|
1545
|
+
] }),
|
|
1546
|
+
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx22(SkeletonBar, { className: cn("h-3", width) }, width))
|
|
1547
|
+
] });
|
|
1548
|
+
}
|
|
1549
|
+
function CommandPaletteAnswer({ children, note }) {
|
|
1550
|
+
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
1551
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-2", children: [
|
|
1552
|
+
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
1553
|
+
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx22("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
|
|
1554
|
+
) }, i)),
|
|
1555
|
+
note && /* @__PURE__ */ jsx22(FieldLine, { children: note })
|
|
1556
|
+
] });
|
|
1557
|
+
}
|
|
1558
|
+
function CommandPaletteQuote({ children }) {
|
|
1559
|
+
return /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1180
1562
|
// src/InlineChip.tsx
|
|
1181
|
-
import { Fragment as
|
|
1563
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1182
1564
|
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";
|
|
1183
1565
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
1184
1566
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -1200,41 +1582,41 @@ function inlineChipClassName(tone, className) {
|
|
|
1200
1582
|
return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
|
|
1201
1583
|
}
|
|
1202
1584
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
1203
|
-
const body = /* @__PURE__ */
|
|
1204
|
-
icon && /* @__PURE__ */
|
|
1585
|
+
const body = /* @__PURE__ */ jsxs16(Fragment4, { children: [
|
|
1586
|
+
icon && /* @__PURE__ */ jsx23("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
1205
1587
|
children
|
|
1206
1588
|
] });
|
|
1207
1589
|
const classes = inlineChipClassName(tone, className);
|
|
1208
1590
|
if (href === void 0) {
|
|
1209
|
-
return /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsx23("span", { className: classes, ...props, children: body });
|
|
1210
1592
|
}
|
|
1211
|
-
return /* @__PURE__ */
|
|
1593
|
+
return /* @__PURE__ */ jsx23("a", { href, className: classes, ...props, children: body });
|
|
1212
1594
|
}
|
|
1213
1595
|
|
|
1214
1596
|
// src/IdentityMenu.tsx
|
|
1215
|
-
import { useCallback, useRef as
|
|
1597
|
+
import { useCallback, useRef as useRef3 } from "react";
|
|
1216
1598
|
|
|
1217
1599
|
// src/Divider.tsx
|
|
1218
1600
|
import { Separator } from "@base-ui/react/separator";
|
|
1219
|
-
import { jsx as
|
|
1601
|
+
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1220
1602
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
1221
1603
|
if (label && orientation === "horizontal") {
|
|
1222
1604
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
1223
|
-
return /* @__PURE__ */
|
|
1605
|
+
return /* @__PURE__ */ jsxs17(
|
|
1224
1606
|
Separator,
|
|
1225
1607
|
{
|
|
1226
1608
|
orientation: "horizontal",
|
|
1227
1609
|
"aria-label": label,
|
|
1228
1610
|
className: cn("flex shrink-0 items-center gap-2 mx-3", className),
|
|
1229
1611
|
children: [
|
|
1230
|
-
/* @__PURE__ */
|
|
1231
|
-
/* @__PURE__ */
|
|
1232
|
-
/* @__PURE__ */
|
|
1612
|
+
/* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
|
|
1613
|
+
/* @__PURE__ */ jsx24("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
|
|
1614
|
+
/* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
|
|
1233
1615
|
]
|
|
1234
1616
|
}
|
|
1235
1617
|
);
|
|
1236
1618
|
}
|
|
1237
|
-
return /* @__PURE__ */
|
|
1619
|
+
return /* @__PURE__ */ jsx24(
|
|
1238
1620
|
Separator,
|
|
1239
1621
|
{
|
|
1240
1622
|
orientation,
|
|
@@ -1244,15 +1626,15 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
1244
1626
|
}
|
|
1245
1627
|
|
|
1246
1628
|
// src/Person.tsx
|
|
1247
|
-
import { jsx as
|
|
1629
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1248
1630
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
1249
1631
|
return (
|
|
1250
1632
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
1251
1633
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
1252
1634
|
// row agree by construction.
|
|
1253
|
-
/* @__PURE__ */
|
|
1254
|
-
/* @__PURE__ */
|
|
1255
|
-
/* @__PURE__ */
|
|
1635
|
+
/* @__PURE__ */ jsxs18("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
1636
|
+
/* @__PURE__ */ jsx25(Avatar, { name, src: picture, size }),
|
|
1637
|
+
/* @__PURE__ */ jsx25("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
1256
1638
|
] })
|
|
1257
1639
|
);
|
|
1258
1640
|
}
|
|
@@ -1260,10 +1642,10 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
|
1260
1642
|
// src/PersonTrigger.tsx
|
|
1261
1643
|
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1262
1644
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
1263
|
-
import { jsx as
|
|
1645
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1264
1646
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
1265
1647
|
if (compact) {
|
|
1266
|
-
return /* @__PURE__ */
|
|
1648
|
+
return /* @__PURE__ */ jsx26(
|
|
1267
1649
|
BaseButton5,
|
|
1268
1650
|
{
|
|
1269
1651
|
type: "button",
|
|
@@ -1272,11 +1654,11 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1272
1654
|
"aria-label": props["aria-label"] ?? name ?? fallback,
|
|
1273
1655
|
className: cn("cursor-pointer rounded-full", className),
|
|
1274
1656
|
...props,
|
|
1275
|
-
children: /* @__PURE__ */
|
|
1657
|
+
children: /* @__PURE__ */ jsx26(Avatar, { name, src: picture, size: size ?? 36 })
|
|
1276
1658
|
}
|
|
1277
1659
|
);
|
|
1278
1660
|
}
|
|
1279
|
-
return /* @__PURE__ */
|
|
1661
|
+
return /* @__PURE__ */ jsxs19(
|
|
1280
1662
|
BaseButton5,
|
|
1281
1663
|
{
|
|
1282
1664
|
type: "button",
|
|
@@ -1294,18 +1676,18 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1294
1676
|
),
|
|
1295
1677
|
...props,
|
|
1296
1678
|
children: [
|
|
1297
|
-
/* @__PURE__ */
|
|
1298
|
-
/* @__PURE__ */
|
|
1679
|
+
/* @__PURE__ */ jsx26(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
1680
|
+
/* @__PURE__ */ jsx26(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
1299
1681
|
]
|
|
1300
1682
|
}
|
|
1301
1683
|
);
|
|
1302
1684
|
}
|
|
1303
1685
|
|
|
1304
1686
|
// src/IdentityMenu.tsx
|
|
1305
|
-
import { Fragment as
|
|
1687
|
+
import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1306
1688
|
function IdentityPanel({ className, onClose = () => {
|
|
1307
1689
|
}, ...rest }) {
|
|
1308
|
-
return /* @__PURE__ */
|
|
1690
|
+
return /* @__PURE__ */ jsx27(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx27(IdentityRows, { ...rest, onClose }) });
|
|
1309
1691
|
}
|
|
1310
1692
|
function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
|
|
1311
1693
|
const act = (action) => () => {
|
|
@@ -1313,53 +1695,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
1313
1695
|
action();
|
|
1314
1696
|
};
|
|
1315
1697
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
1316
|
-
return /* @__PURE__ */
|
|
1317
|
-
/* @__PURE__ */
|
|
1318
|
-
/* @__PURE__ */
|
|
1319
|
-
/* @__PURE__ */
|
|
1320
|
-
me.email && /* @__PURE__ */
|
|
1698
|
+
return /* @__PURE__ */ jsxs20(Fragment5, { children: [
|
|
1699
|
+
/* @__PURE__ */ jsxs20(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
1700
|
+
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
1701
|
+
/* @__PURE__ */ jsx27(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." }),
|
|
1702
|
+
me.email && /* @__PURE__ */ jsxs20(Note, { children: [
|
|
1321
1703
|
me.email,
|
|
1322
1704
|
" \xB7 known to Estiva, never published to the relay"
|
|
1323
1705
|
] })
|
|
1324
1706
|
] }),
|
|
1325
|
-
relayUrl && /* @__PURE__ */
|
|
1326
|
-
/* @__PURE__ */
|
|
1327
|
-
/* @__PURE__ */
|
|
1328
|
-
/* @__PURE__ */
|
|
1329
|
-
/* @__PURE__ */
|
|
1707
|
+
relayUrl && /* @__PURE__ */ jsxs20(Fragment5, { children: [
|
|
1708
|
+
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1709
|
+
/* @__PURE__ */ jsxs20(MenuSection, { label: "Workspace", children: [
|
|
1710
|
+
/* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
1711
|
+
/* @__PURE__ */ jsx27(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
1330
1712
|
] })
|
|
1331
1713
|
] }),
|
|
1332
|
-
appRows && /* @__PURE__ */
|
|
1333
|
-
/* @__PURE__ */
|
|
1714
|
+
appRows && /* @__PURE__ */ jsxs20(Fragment5, { children: [
|
|
1715
|
+
/* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
|
|
1334
1716
|
appRows
|
|
1335
1717
|
] }),
|
|
1336
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
1337
|
-
signedIn && idBase && /* @__PURE__ */
|
|
1718
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }) : null,
|
|
1719
|
+
signedIn && idBase && /* @__PURE__ */ jsx27(
|
|
1338
1720
|
MenuItem,
|
|
1339
1721
|
{
|
|
1340
1722
|
label: "Edit your profile in Estiva ID",
|
|
1341
1723
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
1342
1724
|
}
|
|
1343
1725
|
),
|
|
1344
|
-
onCopyKey && /* @__PURE__ */
|
|
1345
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
1726
|
+
onCopyKey && /* @__PURE__ */ jsx27(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
1727
|
+
idBase && onSignOut && /* @__PURE__ */ jsx27(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
1346
1728
|
] });
|
|
1347
1729
|
}
|
|
1348
1730
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
1349
|
-
const actions =
|
|
1731
|
+
const actions = useRef3(null);
|
|
1350
1732
|
const close = useCallback(() => actions.current?.close(), []);
|
|
1351
1733
|
return (
|
|
1352
1734
|
/* The wrapper carries the caller's `className` and nothing else. It used
|
|
1353
1735
|
to be `relative`, because the panel was positioned against it; the panel
|
|
1354
1736
|
hangs from the trigger and portals now, so a positioning context here
|
|
1355
1737
|
would only be a lie about what this box does. */
|
|
1356
|
-
/* @__PURE__ */
|
|
1738
|
+
/* @__PURE__ */ jsx27("div", { className, children: /* @__PURE__ */ jsx27(
|
|
1357
1739
|
Menu,
|
|
1358
1740
|
{
|
|
1359
1741
|
align: "right",
|
|
1360
1742
|
actionsRef: actions,
|
|
1361
1743
|
className: "w-72",
|
|
1362
|
-
trigger: /* @__PURE__ */
|
|
1744
|
+
trigger: /* @__PURE__ */ jsx27(
|
|
1363
1745
|
PersonTrigger,
|
|
1364
1746
|
{
|
|
1365
1747
|
name: me.name,
|
|
@@ -1370,7 +1752,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1370
1752
|
"aria-label": compact ? "Account menu" : void 0
|
|
1371
1753
|
}
|
|
1372
1754
|
),
|
|
1373
|
-
children: /* @__PURE__ */
|
|
1755
|
+
children: /* @__PURE__ */ jsx27(
|
|
1374
1756
|
IdentityRows,
|
|
1375
1757
|
{
|
|
1376
1758
|
me,
|
|
@@ -1388,46 +1770,18 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1388
1770
|
);
|
|
1389
1771
|
}
|
|
1390
1772
|
function Note({ children }) {
|
|
1391
|
-
return /* @__PURE__ */
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
// src/Field.tsx
|
|
1395
|
-
import { cloneElement, isValidElement } from "react";
|
|
1396
|
-
import { Field as BaseField } from "@base-ui/react/field";
|
|
1397
|
-
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1398
|
-
var LINE_STYLES = {
|
|
1399
|
-
helper: "text-caption text-text-muted",
|
|
1400
|
-
warning: "text-caption text-warning-default",
|
|
1401
|
-
error: "text-caption text-error-default"
|
|
1402
|
-
};
|
|
1403
|
-
function Field({ label, required = false, helper, error, children }) {
|
|
1404
|
-
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1405
|
-
"aria-required": children.props["aria-required"] ?? true
|
|
1406
|
-
}) : children;
|
|
1407
|
-
return /* @__PURE__ */ jsxs17(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
|
|
1408
|
-
/* @__PURE__ */ jsxs17(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
|
|
1409
|
-
label,
|
|
1410
|
-
required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
|
|
1411
|
-
] }),
|
|
1412
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-1.5", children: [
|
|
1413
|
-
control,
|
|
1414
|
-
error != null ? /* @__PURE__ */ jsx24(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1415
|
-
] })
|
|
1416
|
-
] });
|
|
1417
|
-
}
|
|
1418
|
-
function FieldLine({ tone = "helper", children, className }) {
|
|
1419
|
-
return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1773
|
+
return /* @__PURE__ */ jsx27("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
1420
1774
|
}
|
|
1421
1775
|
|
|
1422
1776
|
// src/Select.tsx
|
|
1423
1777
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
1424
1778
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
1425
|
-
import { jsx as
|
|
1779
|
+
import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1426
1780
|
var GAP4 = 4;
|
|
1427
1781
|
var VIEWPORT_PAD4 = 8;
|
|
1428
1782
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
|
|
1429
1783
|
const selected = options.find((o) => o.value === value);
|
|
1430
|
-
return /* @__PURE__ */
|
|
1784
|
+
return /* @__PURE__ */ jsxs21(
|
|
1431
1785
|
BaseSelect.Root,
|
|
1432
1786
|
{
|
|
1433
1787
|
value,
|
|
@@ -1435,7 +1789,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1435
1789
|
disabled,
|
|
1436
1790
|
modal: false,
|
|
1437
1791
|
children: [
|
|
1438
|
-
/* @__PURE__ */
|
|
1792
|
+
/* @__PURE__ */ jsxs21(
|
|
1439
1793
|
BaseSelect.Trigger,
|
|
1440
1794
|
{
|
|
1441
1795
|
"aria-label": ariaLabel,
|
|
@@ -1462,20 +1816,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1462
1816
|
className
|
|
1463
1817
|
),
|
|
1464
1818
|
children: [
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
selected?.leading && /* @__PURE__ */
|
|
1467
|
-
/* @__PURE__ */
|
|
1819
|
+
/* @__PURE__ */ jsxs21("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
1820
|
+
selected?.leading && /* @__PURE__ */ jsx28("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
1821
|
+
/* @__PURE__ */ jsx28(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
|
|
1468
1822
|
] }),
|
|
1469
|
-
/* @__PURE__ */
|
|
1823
|
+
/* @__PURE__ */ jsx28(
|
|
1470
1824
|
BaseSelect.Icon,
|
|
1471
1825
|
{
|
|
1472
|
-
render: /* @__PURE__ */
|
|
1826
|
+
render: /* @__PURE__ */ jsx28(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1473
1827
|
}
|
|
1474
1828
|
)
|
|
1475
1829
|
]
|
|
1476
1830
|
}
|
|
1477
1831
|
),
|
|
1478
|
-
/* @__PURE__ */
|
|
1832
|
+
/* @__PURE__ */ jsx28(BaseSelect.Portal, { children: /* @__PURE__ */ jsx28(
|
|
1479
1833
|
BaseSelect.Positioner,
|
|
1480
1834
|
{
|
|
1481
1835
|
side: "bottom",
|
|
@@ -1484,25 +1838,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1484
1838
|
collisionPadding: VIEWPORT_PAD4,
|
|
1485
1839
|
alignItemWithTrigger: false,
|
|
1486
1840
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1487
|
-
children: /* @__PURE__ */
|
|
1841
|
+
children: /* @__PURE__ */ jsx28(
|
|
1488
1842
|
BaseSelect.Popup,
|
|
1489
1843
|
{
|
|
1490
|
-
render: /* @__PURE__ */
|
|
1844
|
+
render: /* @__PURE__ */ jsx28(MenuPanel, {}),
|
|
1491
1845
|
className: "min-w-[var(--anchor-width)] p-0",
|
|
1492
|
-
children: /* @__PURE__ */
|
|
1846
|
+
children: /* @__PURE__ */ jsx28(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs21(
|
|
1493
1847
|
BaseSelect.Item,
|
|
1494
1848
|
{
|
|
1495
1849
|
value: option.value,
|
|
1496
1850
|
className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
|
|
1497
1851
|
children: [
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
option.leading && /* @__PURE__ */
|
|
1500
|
-
/* @__PURE__ */
|
|
1852
|
+
/* @__PURE__ */ jsxs21("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1853
|
+
option.leading && /* @__PURE__ */ jsx28("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
1854
|
+
/* @__PURE__ */ jsx28(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
|
|
1501
1855
|
] }),
|
|
1502
|
-
/* @__PURE__ */
|
|
1856
|
+
/* @__PURE__ */ jsx28(
|
|
1503
1857
|
BaseSelect.ItemIndicator,
|
|
1504
1858
|
{
|
|
1505
|
-
render: /* @__PURE__ */
|
|
1859
|
+
render: /* @__PURE__ */ jsx28(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1506
1860
|
}
|
|
1507
1861
|
)
|
|
1508
1862
|
]
|
|
@@ -1521,9 +1875,9 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1521
1875
|
// src/TextInput.tsx
|
|
1522
1876
|
import { forwardRef } from "react";
|
|
1523
1877
|
import { Input } from "@base-ui/react/input";
|
|
1524
|
-
import { jsx as
|
|
1878
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1525
1879
|
var TextInput = forwardRef(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
|
|
1526
|
-
return /* @__PURE__ */
|
|
1880
|
+
return /* @__PURE__ */ jsx29(
|
|
1527
1881
|
Input,
|
|
1528
1882
|
{
|
|
1529
1883
|
ref,
|
|
@@ -1547,13 +1901,13 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", size
|
|
|
1547
1901
|
// src/Textarea.tsx
|
|
1548
1902
|
import { forwardRef as forwardRef2 } from "react";
|
|
1549
1903
|
import { Field as BaseField2 } from "@base-ui/react/field";
|
|
1550
|
-
import { jsx as
|
|
1904
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1551
1905
|
var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
1552
|
-
return /* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsx30(
|
|
1553
1907
|
BaseField2.Control,
|
|
1554
1908
|
{
|
|
1555
1909
|
ref,
|
|
1556
|
-
render: /* @__PURE__ */
|
|
1910
|
+
render: /* @__PURE__ */ jsx30("textarea", {}),
|
|
1557
1911
|
className: cn(
|
|
1558
1912
|
"bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
|
|
1559
1913
|
"text-input-value text-text-primary placeholder:text-text-muted",
|
|
@@ -1568,27 +1922,27 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
|
|
|
1568
1922
|
});
|
|
1569
1923
|
|
|
1570
1924
|
// src/ConfirmDialog.tsx
|
|
1571
|
-
import { useState as
|
|
1925
|
+
import { useState as useState4 } from "react";
|
|
1572
1926
|
|
|
1573
1927
|
// src/DialogShell.tsx
|
|
1574
|
-
import { useRef as
|
|
1575
|
-
import { Dialog } from "@base-ui/react/dialog";
|
|
1928
|
+
import { useRef as useRef4 } from "react";
|
|
1929
|
+
import { Dialog as Dialog2 } from "@base-ui/react/dialog";
|
|
1576
1930
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1577
1931
|
import { IconX as IconX4 } from "@tabler/icons-react";
|
|
1578
|
-
import { jsx as
|
|
1932
|
+
import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1579
1933
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1580
|
-
const Parts = alert ? AlertDialog :
|
|
1581
|
-
const popupRef =
|
|
1582
|
-
return /* @__PURE__ */
|
|
1934
|
+
const Parts = alert ? AlertDialog : Dialog2;
|
|
1935
|
+
const popupRef = useRef4(null);
|
|
1936
|
+
return /* @__PURE__ */ jsx31(
|
|
1583
1937
|
Parts.Root,
|
|
1584
1938
|
{
|
|
1585
1939
|
open: true,
|
|
1586
1940
|
onOpenChange: (open) => {
|
|
1587
1941
|
if (!open) onClose();
|
|
1588
1942
|
},
|
|
1589
|
-
children: /* @__PURE__ */
|
|
1590
|
-
/* @__PURE__ */
|
|
1591
|
-
/* @__PURE__ */
|
|
1943
|
+
children: /* @__PURE__ */ jsxs22(Parts.Portal, { children: [
|
|
1944
|
+
/* @__PURE__ */ jsx31(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1945
|
+
/* @__PURE__ */ jsx31("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs22(
|
|
1592
1946
|
Parts.Popup,
|
|
1593
1947
|
{
|
|
1594
1948
|
ref: popupRef,
|
|
@@ -1597,16 +1951,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1597
1951
|
className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
|
|
1598
1952
|
style: { width },
|
|
1599
1953
|
children: [
|
|
1600
|
-
/* @__PURE__ */
|
|
1601
|
-
headerContent ?? /* @__PURE__ */
|
|
1602
|
-
/* @__PURE__ */
|
|
1954
|
+
/* @__PURE__ */ jsxs22("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
|
|
1955
|
+
headerContent ?? /* @__PURE__ */ jsx31(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx31("span", {}), children: title }),
|
|
1956
|
+
/* @__PURE__ */ jsx31(
|
|
1603
1957
|
Parts.Close,
|
|
1604
1958
|
{
|
|
1605
|
-
render: /* @__PURE__ */
|
|
1959
|
+
render: /* @__PURE__ */ jsx31(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx31(IconX4, { size: 16, stroke: 1.5 }) })
|
|
1606
1960
|
}
|
|
1607
1961
|
)
|
|
1608
1962
|
] }),
|
|
1609
|
-
bodyMaxHeight ? /* @__PURE__ */
|
|
1963
|
+
bodyMaxHeight ? /* @__PURE__ */ jsx31(
|
|
1610
1964
|
ScrollArea,
|
|
1611
1965
|
{
|
|
1612
1966
|
className: cn(footer != null && "border-b border-border-subtle"),
|
|
@@ -1614,8 +1968,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1614
1968
|
contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
|
|
1615
1969
|
children
|
|
1616
1970
|
}
|
|
1617
|
-
) : /* @__PURE__ */
|
|
1618
|
-
footer != null && /* @__PURE__ */
|
|
1971
|
+
) : /* @__PURE__ */ jsx31("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1972
|
+
footer != null && /* @__PURE__ */ jsx31("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1619
1973
|
]
|
|
1620
1974
|
}
|
|
1621
1975
|
) })
|
|
@@ -1625,9 +1979,9 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1625
1979
|
}
|
|
1626
1980
|
|
|
1627
1981
|
// src/ConfirmDialog.tsx
|
|
1628
|
-
import { Fragment as
|
|
1982
|
+
import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1629
1983
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1630
|
-
const [busy, setBusy] =
|
|
1984
|
+
const [busy, setBusy] = useState4(false);
|
|
1631
1985
|
const confirm = async () => {
|
|
1632
1986
|
setBusy(true);
|
|
1633
1987
|
try {
|
|
@@ -1637,16 +1991,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1637
1991
|
setBusy(false);
|
|
1638
1992
|
}
|
|
1639
1993
|
};
|
|
1640
|
-
return /* @__PURE__ */
|
|
1994
|
+
return /* @__PURE__ */ jsx32(
|
|
1641
1995
|
DialogShell,
|
|
1642
1996
|
{
|
|
1643
1997
|
alert: true,
|
|
1644
1998
|
title,
|
|
1645
1999
|
onClose,
|
|
1646
2000
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
1647
|
-
footer: /* @__PURE__ */
|
|
1648
|
-
/* @__PURE__ */
|
|
1649
|
-
/* @__PURE__ */
|
|
2001
|
+
footer: /* @__PURE__ */ jsxs23(Fragment6, { children: [
|
|
2002
|
+
/* @__PURE__ */ jsx32(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
2003
|
+
/* @__PURE__ */ jsx32(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
1650
2004
|
] }),
|
|
1651
2005
|
children
|
|
1652
2006
|
}
|
|
@@ -1654,16 +2008,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1654
2008
|
}
|
|
1655
2009
|
|
|
1656
2010
|
// src/EditableText.tsx
|
|
1657
|
-
import { useEffect, useRef as
|
|
2011
|
+
import { useEffect as useEffect2, useRef as useRef5, useState as useState5 } from "react";
|
|
1658
2012
|
import { Field as BaseField3 } from "@base-ui/react/field";
|
|
1659
2013
|
import { Input as Input2 } from "@base-ui/react/input";
|
|
1660
|
-
import { jsx as
|
|
2014
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1661
2015
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
1662
|
-
const [editing, setEditing] =
|
|
1663
|
-
const [draft, setDraft] =
|
|
1664
|
-
const [busy, setBusy] =
|
|
1665
|
-
const fieldRef =
|
|
1666
|
-
|
|
2016
|
+
const [editing, setEditing] = useState5(false);
|
|
2017
|
+
const [draft, setDraft] = useState5(value);
|
|
2018
|
+
const [busy, setBusy] = useState5(false);
|
|
2019
|
+
const fieldRef = useRef5(null);
|
|
2020
|
+
useEffect2(() => {
|
|
1667
2021
|
if (editing) {
|
|
1668
2022
|
fieldRef.current?.focus();
|
|
1669
2023
|
fieldRef.current?.select();
|
|
@@ -1715,7 +2069,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1715
2069
|
written and never read. Read-only, this is a line of text: whatever
|
|
1716
2070
|
names the region around it (a `Field`, a `Property`) names this too.
|
|
1717
2071
|
*/
|
|
1718
|
-
/* @__PURE__ */
|
|
2072
|
+
/* @__PURE__ */ jsx33(
|
|
1719
2073
|
"div",
|
|
1720
2074
|
{
|
|
1721
2075
|
className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
|
|
@@ -1725,11 +2079,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1725
2079
|
);
|
|
1726
2080
|
}
|
|
1727
2081
|
if (editing) {
|
|
1728
|
-
return multiline ? /* @__PURE__ */
|
|
2082
|
+
return multiline ? /* @__PURE__ */ jsx33(
|
|
1729
2083
|
BaseField3.Control,
|
|
1730
2084
|
{
|
|
1731
2085
|
ref: fieldRef,
|
|
1732
|
-
render: /* @__PURE__ */
|
|
2086
|
+
render: /* @__PURE__ */ jsx33("textarea", { rows: 4 }),
|
|
1733
2087
|
"aria-label": label,
|
|
1734
2088
|
value: draft,
|
|
1735
2089
|
disabled: busy,
|
|
@@ -1738,7 +2092,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1738
2092
|
onBlur: () => void commit(),
|
|
1739
2093
|
className: fieldClass
|
|
1740
2094
|
}
|
|
1741
|
-
) : /* @__PURE__ */
|
|
2095
|
+
) : /* @__PURE__ */ jsx33(
|
|
1742
2096
|
Input2,
|
|
1743
2097
|
{
|
|
1744
2098
|
ref: fieldRef,
|
|
@@ -1752,7 +2106,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1752
2106
|
}
|
|
1753
2107
|
);
|
|
1754
2108
|
}
|
|
1755
|
-
return /* @__PURE__ */
|
|
2109
|
+
return /* @__PURE__ */ jsx33(
|
|
1756
2110
|
"button",
|
|
1757
2111
|
{
|
|
1758
2112
|
type: "button",
|
|
@@ -1769,22 +2123,9 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1769
2123
|
);
|
|
1770
2124
|
}
|
|
1771
2125
|
|
|
1772
|
-
// src/EmptyState.tsx
|
|
1773
|
-
import { IconMessage2 } from "@tabler/icons-react";
|
|
1774
|
-
import { jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1775
|
-
function EmptyState({ icon, message, scope = "page", className }) {
|
|
1776
|
-
if (scope === "section") {
|
|
1777
|
-
return /* @__PURE__ */ jsx31("p", { className: cn("text-caption text-text-muted", className), children: message });
|
|
1778
|
-
}
|
|
1779
|
-
return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
|
|
1780
|
-
/* @__PURE__ */ jsx31("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx31(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1781
|
-
/* @__PURE__ */ jsx31("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1782
|
-
] });
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
2126
|
// src/ProgressBar.tsx
|
|
1786
2127
|
import { Progress } from "@base-ui/react/progress";
|
|
1787
|
-
import { jsx as
|
|
2128
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1788
2129
|
var TRACK_CLASSES = {
|
|
1789
2130
|
default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
|
|
1790
2131
|
// 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
|
|
@@ -1797,33 +2138,17 @@ var INDICATOR_CLASSES = {
|
|
|
1797
2138
|
function ProgressBar({ value, max, label, variant = "default", className }) {
|
|
1798
2139
|
return (
|
|
1799
2140
|
// `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
|
|
1800
|
-
/* @__PURE__ */
|
|
2141
|
+
/* @__PURE__ */ jsx34(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx34(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx34(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
|
|
1801
2142
|
);
|
|
1802
2143
|
}
|
|
1803
2144
|
|
|
1804
|
-
// src/Skeleton.tsx
|
|
1805
|
-
import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1806
|
-
function SkeletonBar({ className, style }) {
|
|
1807
|
-
return /* @__PURE__ */ jsx33("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1808
|
-
}
|
|
1809
|
-
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1810
|
-
function SkeletonRow({ barWidth = 130 }) {
|
|
1811
|
-
return /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1812
|
-
/* @__PURE__ */ jsx33(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1813
|
-
/* @__PURE__ */ jsx33(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1814
|
-
] });
|
|
1815
|
-
}
|
|
1816
|
-
function SkeletonList({ rows = 8, className }) {
|
|
1817
|
-
return /* @__PURE__ */ jsx33("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx33(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
2145
|
// src/Breadcrumb.tsx
|
|
1821
|
-
import { Fragment as
|
|
1822
|
-
import { jsx as
|
|
2146
|
+
import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect3, useRef as useRef6, useState as useState6 } from "react";
|
|
2147
|
+
import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1823
2148
|
function Breadcrumb({ items, className }) {
|
|
1824
|
-
const navRef =
|
|
1825
|
-
const labelRefs =
|
|
1826
|
-
const [truncated, setTruncated] =
|
|
2149
|
+
const navRef = useRef6(null);
|
|
2150
|
+
const labelRefs = useRef6([]);
|
|
2151
|
+
const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
|
|
1827
2152
|
const measure = useCallback2(() => {
|
|
1828
2153
|
const next = /* @__PURE__ */ new Set();
|
|
1829
2154
|
labelRefs.current.forEach((el, index) => {
|
|
@@ -1831,7 +2156,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1831
2156
|
});
|
|
1832
2157
|
setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
|
|
1833
2158
|
}, []);
|
|
1834
|
-
|
|
2159
|
+
useLayoutEffect3(() => {
|
|
1835
2160
|
measure();
|
|
1836
2161
|
const nav = navRef.current;
|
|
1837
2162
|
if (!nav || typeof ResizeObserver === "undefined") return;
|
|
@@ -1839,7 +2164,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1839
2164
|
observer.observe(nav);
|
|
1840
2165
|
return () => observer.disconnect();
|
|
1841
2166
|
}, [measure, items]);
|
|
1842
|
-
return /* @__PURE__ */
|
|
2167
|
+
return /* @__PURE__ */ jsx35("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) => {
|
|
1843
2168
|
const last = index === items.length - 1;
|
|
1844
2169
|
const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
|
|
1845
2170
|
const text = cn(
|
|
@@ -1853,24 +2178,29 @@ function Breadcrumb({ items, className }) {
|
|
|
1853
2178
|
const setLabelRef = (el) => {
|
|
1854
2179
|
labelRefs.current[index] = el;
|
|
1855
2180
|
};
|
|
1856
|
-
const crumb = item.href ?
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
2181
|
+
const crumb = item.href ? (
|
|
2182
|
+
// `plain` adds no look of its own: a crumb keeps the trail's size and
|
|
2183
|
+
// tone, and brightens on hover. The package's own Link, so a trail
|
|
2184
|
+
// follows whatever a link learns to do (UIG-5).
|
|
2185
|
+
/* @__PURE__ */ jsx35(Link, { ref: setLabelRef, variant: "plain", href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label })
|
|
2186
|
+
) : /* @__PURE__ */ jsx35("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
2187
|
+
return /* @__PURE__ */ jsxs24(Fragment7, { children: [
|
|
2188
|
+
index > 0 && /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
2189
|
+
item.icon && /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
|
|
1860
2190
|
truncated.has(index) ? (
|
|
1861
2191
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
1862
2192
|
// must keep truncating inside it, or wrapping it would widen the
|
|
1863
2193
|
// trail and the tooltip would never be needed again.
|
|
1864
|
-
/* @__PURE__ */
|
|
2194
|
+
/* @__PURE__ */ jsx35(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
1865
2195
|
) : crumb
|
|
1866
2196
|
] }, `${item.label}-${index}`);
|
|
1867
2197
|
}) });
|
|
1868
2198
|
}
|
|
1869
2199
|
|
|
1870
2200
|
// src/NavItem.tsx
|
|
1871
|
-
import { jsx as
|
|
2201
|
+
import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1872
2202
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
1873
|
-
return /* @__PURE__ */
|
|
2203
|
+
return /* @__PURE__ */ jsxs25(
|
|
1874
2204
|
"a",
|
|
1875
2205
|
{
|
|
1876
2206
|
href,
|
|
@@ -1885,27 +2215,27 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
1885
2215
|
),
|
|
1886
2216
|
...props,
|
|
1887
2217
|
children: [
|
|
1888
|
-
icon && /* @__PURE__ */
|
|
1889
|
-
/* @__PURE__ */
|
|
1890
|
-
count ? /* @__PURE__ */
|
|
2218
|
+
icon && /* @__PURE__ */ jsx36("span", { className: "flex shrink-0 items-center", children: icon }),
|
|
2219
|
+
/* @__PURE__ */ jsx36("span", { className: "flex-1 truncate", children: label }),
|
|
2220
|
+
count ? /* @__PURE__ */ jsx36(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx36("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
|
|
1891
2221
|
]
|
|
1892
2222
|
}
|
|
1893
2223
|
);
|
|
1894
2224
|
}
|
|
1895
2225
|
|
|
1896
2226
|
// src/Popover.tsx
|
|
1897
|
-
import { useMemo as
|
|
2227
|
+
import { useMemo as useMemo3 } from "react";
|
|
1898
2228
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
1899
|
-
import { jsx as
|
|
2229
|
+
import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1900
2230
|
var GAP5 = 4;
|
|
1901
2231
|
var VIEWPORT_PAD5 = 8;
|
|
1902
2232
|
function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
|
|
1903
|
-
const anchorTarget =
|
|
2233
|
+
const anchorTarget = useMemo3(() => {
|
|
1904
2234
|
if (!anchor) return void 0;
|
|
1905
2235
|
if (anchor instanceof Element) return anchor;
|
|
1906
2236
|
return { getBoundingClientRect: () => anchor };
|
|
1907
2237
|
}, [anchor]);
|
|
1908
|
-
return /* @__PURE__ */
|
|
2238
|
+
return /* @__PURE__ */ jsxs26(
|
|
1909
2239
|
BasePopover.Root,
|
|
1910
2240
|
{
|
|
1911
2241
|
open,
|
|
@@ -1913,8 +2243,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1913
2243
|
actionsRef,
|
|
1914
2244
|
modal: false,
|
|
1915
2245
|
children: [
|
|
1916
|
-
trigger && /* @__PURE__ */
|
|
1917
|
-
/* @__PURE__ */
|
|
2246
|
+
trigger && /* @__PURE__ */ jsx37(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
|
|
2247
|
+
/* @__PURE__ */ jsx37(BasePopover.Portal, { children: /* @__PURE__ */ jsx37(
|
|
1918
2248
|
BasePopover.Positioner,
|
|
1919
2249
|
{
|
|
1920
2250
|
anchor: anchorTarget,
|
|
@@ -1923,15 +2253,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1923
2253
|
sideOffset: GAP5,
|
|
1924
2254
|
collisionPadding: VIEWPORT_PAD5,
|
|
1925
2255
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
1926
|
-
children: /* @__PURE__ */
|
|
2256
|
+
children: /* @__PURE__ */ jsx37(
|
|
1927
2257
|
BasePopover.Popup,
|
|
1928
2258
|
{
|
|
1929
2259
|
"aria-label": ariaLabel,
|
|
1930
2260
|
initialFocus: trigger ? void 0 : false,
|
|
1931
2261
|
finalFocus,
|
|
1932
2262
|
className: cn("min-w-[180px] outline-none p-0", className),
|
|
1933
|
-
render: /* @__PURE__ */
|
|
1934
|
-
children: /* @__PURE__ */
|
|
2263
|
+
render: /* @__PURE__ */ jsx37(MenuPanel, {}),
|
|
2264
|
+
children: /* @__PURE__ */ jsx37(
|
|
1935
2265
|
ScrollArea,
|
|
1936
2266
|
{
|
|
1937
2267
|
viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
|
|
@@ -1950,9 +2280,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1950
2280
|
|
|
1951
2281
|
// src/Toolbar.tsx
|
|
1952
2282
|
import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
|
|
1953
|
-
import { jsx as
|
|
2283
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
1954
2284
|
function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
|
|
1955
|
-
const strip = /* @__PURE__ */
|
|
2285
|
+
const strip = /* @__PURE__ */ jsx38(
|
|
1956
2286
|
BaseToolbar.Root,
|
|
1957
2287
|
{
|
|
1958
2288
|
"aria-label": ariaLabel,
|
|
@@ -1963,24 +2293,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
|
|
|
1963
2293
|
}
|
|
1964
2294
|
);
|
|
1965
2295
|
if (!surface) return strip;
|
|
1966
|
-
return /* @__PURE__ */
|
|
2296
|
+
return /* @__PURE__ */ jsx38(MenuPanel, { className: "w-fit p-1", children: strip });
|
|
1967
2297
|
}
|
|
1968
2298
|
function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
|
|
1969
|
-
return /* @__PURE__ */
|
|
2299
|
+
return /* @__PURE__ */ jsx38(
|
|
1970
2300
|
BaseToolbar.Button,
|
|
1971
2301
|
{
|
|
1972
2302
|
ref,
|
|
1973
2303
|
disabled: disabled || !!disabledReason,
|
|
1974
2304
|
focusableWhenDisabled: true,
|
|
1975
|
-
render: /* @__PURE__ */
|
|
2305
|
+
render: /* @__PURE__ */ jsx38(IconButton, { disabled, disabledReason, ...props })
|
|
1976
2306
|
}
|
|
1977
2307
|
);
|
|
1978
2308
|
}
|
|
1979
2309
|
function ToolbarInput({ size, ...props }) {
|
|
1980
|
-
return /* @__PURE__ */
|
|
2310
|
+
return /* @__PURE__ */ jsx38(BaseToolbar.Input, { render: /* @__PURE__ */ jsx38(TextInput, { size }), ...props });
|
|
1981
2311
|
}
|
|
1982
2312
|
function ToolbarSeparator({ className }) {
|
|
1983
|
-
return /* @__PURE__ */
|
|
2313
|
+
return /* @__PURE__ */ jsx38(
|
|
1984
2314
|
BaseToolbar.Separator,
|
|
1985
2315
|
{
|
|
1986
2316
|
orientation: "vertical",
|
|
@@ -1990,9 +2320,9 @@ function ToolbarSeparator({ className }) {
|
|
|
1990
2320
|
}
|
|
1991
2321
|
|
|
1992
2322
|
// src/ReactionPicker.tsx
|
|
1993
|
-
import { jsx as
|
|
2323
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
1994
2324
|
function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
|
|
1995
|
-
return /* @__PURE__ */
|
|
2325
|
+
return /* @__PURE__ */ jsx39(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
|
|
1996
2326
|
/*
|
|
1997
2327
|
A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
|
|
1998
2328
|
would become the toolbar's item and the button inside it would never
|
|
@@ -2002,14 +2332,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2002
2332
|
The tooltip names it for a pointer, `aria-label` for everything else,
|
|
2003
2333
|
and both say the meaning rather than the glyph.
|
|
2004
2334
|
*/
|
|
2005
|
-
/* @__PURE__ */
|
|
2335
|
+
/* @__PURE__ */ jsx39(
|
|
2006
2336
|
ToolbarButton,
|
|
2007
2337
|
{
|
|
2008
2338
|
"aria-label": option.label,
|
|
2009
2339
|
tooltip: option.label,
|
|
2010
2340
|
onClick: () => onSelect(option.emoji),
|
|
2011
2341
|
className: "size-7 text-h3 leading-none",
|
|
2012
|
-
children: /* @__PURE__ */
|
|
2342
|
+
children: /* @__PURE__ */ jsx39("span", { "aria-hidden": "true", children: option.emoji })
|
|
2013
2343
|
},
|
|
2014
2344
|
option.emoji
|
|
2015
2345
|
)
|
|
@@ -2018,23 +2348,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
|
|
|
2018
2348
|
|
|
2019
2349
|
// src/PreviewCard.tsx
|
|
2020
2350
|
import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
|
|
2021
|
-
import { jsx as
|
|
2351
|
+
import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2022
2352
|
var GAP6 = 12;
|
|
2023
2353
|
var VIEWPORT_PAD6 = 8;
|
|
2024
2354
|
var OPEN_DELAY2 = 350;
|
|
2025
2355
|
var CLOSE_DELAY = 200;
|
|
2026
2356
|
function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
|
|
2027
|
-
return /* @__PURE__ */
|
|
2028
|
-
/* @__PURE__ */
|
|
2357
|
+
return /* @__PURE__ */ jsxs27(BasePreviewCard.Root, { children: [
|
|
2358
|
+
/* @__PURE__ */ jsx40(
|
|
2029
2359
|
BasePreviewCard.Trigger,
|
|
2030
2360
|
{
|
|
2031
2361
|
delay,
|
|
2032
2362
|
closeDelay,
|
|
2033
|
-
render: /* @__PURE__ */
|
|
2363
|
+
render: /* @__PURE__ */ jsx40("span", { className: cn("inline-flex", wrapperClassName) }),
|
|
2034
2364
|
children
|
|
2035
2365
|
}
|
|
2036
2366
|
),
|
|
2037
|
-
/* @__PURE__ */
|
|
2367
|
+
/* @__PURE__ */ jsx40(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx40(
|
|
2038
2368
|
BasePreviewCard.Positioner,
|
|
2039
2369
|
{
|
|
2040
2370
|
side,
|
|
@@ -2042,12 +2372,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2042
2372
|
sideOffset: GAP6,
|
|
2043
2373
|
collisionPadding: VIEWPORT_PAD6,
|
|
2044
2374
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
2045
|
-
children: /* @__PURE__ */
|
|
2375
|
+
children: /* @__PURE__ */ jsx40(
|
|
2046
2376
|
BasePreviewCard.Popup,
|
|
2047
2377
|
{
|
|
2048
2378
|
className: cn("w-[360px] p-3 outline-none", className),
|
|
2049
|
-
render: /* @__PURE__ */
|
|
2050
|
-
children: /* @__PURE__ */
|
|
2379
|
+
render: /* @__PURE__ */ jsx40(MenuPanel, {}),
|
|
2380
|
+
children: /* @__PURE__ */ jsx40(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3 [&>*]:shrink-0", children: content })
|
|
2051
2381
|
}
|
|
2052
2382
|
)
|
|
2053
2383
|
}
|
|
@@ -2056,15 +2386,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
|
|
|
2056
2386
|
}
|
|
2057
2387
|
|
|
2058
2388
|
// src/Rail.tsx
|
|
2059
|
-
import { jsx as
|
|
2389
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
2060
2390
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
2061
|
-
return /* @__PURE__ */
|
|
2391
|
+
return /* @__PURE__ */ jsx41("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
2062
2392
|
}
|
|
2063
2393
|
|
|
2064
2394
|
// src/RailItem.tsx
|
|
2065
|
-
import { jsx as
|
|
2395
|
+
import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2066
2396
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
2067
|
-
return /* @__PURE__ */
|
|
2397
|
+
return /* @__PURE__ */ jsxs28(
|
|
2068
2398
|
"a",
|
|
2069
2399
|
{
|
|
2070
2400
|
href,
|
|
@@ -2072,14 +2402,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2072
2402
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
2073
2403
|
...props,
|
|
2074
2404
|
children: [
|
|
2075
|
-
/* @__PURE__ */
|
|
2405
|
+
/* @__PURE__ */ jsx42(
|
|
2076
2406
|
"div",
|
|
2077
2407
|
{
|
|
2078
2408
|
className: cn(
|
|
2079
2409
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
2080
2410
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
2081
2411
|
),
|
|
2082
|
-
children: /* @__PURE__ */
|
|
2412
|
+
children: /* @__PURE__ */ jsx42(
|
|
2083
2413
|
"span",
|
|
2084
2414
|
{
|
|
2085
2415
|
className: cn(
|
|
@@ -2091,27 +2421,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
2091
2421
|
)
|
|
2092
2422
|
}
|
|
2093
2423
|
),
|
|
2094
|
-
/* @__PURE__ */
|
|
2424
|
+
/* @__PURE__ */ jsx42("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
2095
2425
|
]
|
|
2096
2426
|
}
|
|
2097
2427
|
);
|
|
2098
2428
|
}
|
|
2099
2429
|
|
|
2100
2430
|
// src/Sidebar.tsx
|
|
2101
|
-
import { jsx as
|
|
2431
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
2102
2432
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
2103
|
-
return /* @__PURE__ */
|
|
2433
|
+
return /* @__PURE__ */ jsx43(
|
|
2104
2434
|
"nav",
|
|
2105
2435
|
{
|
|
2106
2436
|
"aria-label": ariaLabel,
|
|
2107
2437
|
className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
|
|
2108
|
-
children: /* @__PURE__ */
|
|
2438
|
+
children: /* @__PURE__ */ jsx43(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
|
|
2109
2439
|
}
|
|
2110
2440
|
);
|
|
2111
2441
|
}
|
|
2112
2442
|
|
|
2113
2443
|
// src/Property.tsx
|
|
2114
|
-
import { jsx as
|
|
2444
|
+
import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2115
2445
|
var VALUE_CLASSES = "contents";
|
|
2116
2446
|
function Property({ label, layout = "row", children, className }) {
|
|
2117
2447
|
if (layout === "stacked") {
|
|
@@ -2119,23 +2449,23 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
2119
2449
|
// gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
|
|
2120
2450
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
2121
2451
|
// 6px, and unifying means the bigger, calmer one.
|
|
2122
|
-
/* @__PURE__ */
|
|
2123
|
-
/* @__PURE__ */
|
|
2124
|
-
/* @__PURE__ */
|
|
2452
|
+
/* @__PURE__ */ jsxs29("dl", { className: cn("flex flex-col gap-3", className), children: [
|
|
2453
|
+
/* @__PURE__ */ jsx44("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
|
|
2454
|
+
/* @__PURE__ */ jsx44("dd", { className: VALUE_CLASSES, children })
|
|
2125
2455
|
] })
|
|
2126
2456
|
);
|
|
2127
2457
|
}
|
|
2128
|
-
return /* @__PURE__ */
|
|
2129
|
-
/* @__PURE__ */
|
|
2130
|
-
/* @__PURE__ */
|
|
2458
|
+
return /* @__PURE__ */ jsxs29("dl", { className: cn("flex items-center gap-2", className), children: [
|
|
2459
|
+
/* @__PURE__ */ jsx44("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
2460
|
+
/* @__PURE__ */ jsx44("dd", { className: VALUE_CLASSES, children })
|
|
2131
2461
|
] });
|
|
2132
2462
|
}
|
|
2133
2463
|
|
|
2134
2464
|
// src/Reaction.tsx
|
|
2135
2465
|
import { Toggle } from "@base-ui/react/toggle";
|
|
2136
|
-
import { jsx as
|
|
2466
|
+
import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2137
2467
|
function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
2138
|
-
return /* @__PURE__ */
|
|
2468
|
+
return /* @__PURE__ */ jsxs30(
|
|
2139
2469
|
Toggle,
|
|
2140
2470
|
{
|
|
2141
2471
|
pressed,
|
|
@@ -2157,8 +2487,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2157
2487
|
),
|
|
2158
2488
|
...props,
|
|
2159
2489
|
children: [
|
|
2160
|
-
/* @__PURE__ */
|
|
2161
|
-
/* @__PURE__ */
|
|
2490
|
+
/* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
|
|
2491
|
+
/* @__PURE__ */ jsx45("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
|
|
2162
2492
|
]
|
|
2163
2493
|
}
|
|
2164
2494
|
);
|
|
@@ -2167,9 +2497,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
|
|
|
2167
2497
|
// src/SearchInput.tsx
|
|
2168
2498
|
import "react";
|
|
2169
2499
|
import { Input as Input3 } from "@base-ui/react/input";
|
|
2170
|
-
import { jsx as
|
|
2500
|
+
import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2171
2501
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
2172
|
-
return /* @__PURE__ */
|
|
2502
|
+
return /* @__PURE__ */ jsxs31(
|
|
2173
2503
|
"div",
|
|
2174
2504
|
{
|
|
2175
2505
|
className: cn(
|
|
@@ -2179,7 +2509,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2179
2509
|
className
|
|
2180
2510
|
),
|
|
2181
2511
|
children: [
|
|
2182
|
-
/* @__PURE__ */
|
|
2512
|
+
/* @__PURE__ */ jsx46(
|
|
2183
2513
|
Input3,
|
|
2184
2514
|
{
|
|
2185
2515
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -2187,7 +2517,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2187
2517
|
...props
|
|
2188
2518
|
}
|
|
2189
2519
|
),
|
|
2190
|
-
shortcut && /* @__PURE__ */
|
|
2520
|
+
shortcut && /* @__PURE__ */ jsx46(Kbd, { children: shortcut })
|
|
2191
2521
|
]
|
|
2192
2522
|
}
|
|
2193
2523
|
);
|
|
@@ -2196,17 +2526,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
2196
2526
|
// src/SectionHeader.tsx
|
|
2197
2527
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
2198
2528
|
import { useRender } from "@base-ui/react/use-render";
|
|
2199
|
-
import { Fragment as
|
|
2529
|
+
import { Fragment as Fragment8, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2200
2530
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
|
|
2201
2531
|
const titleElement = useRender({
|
|
2202
|
-
render: render ?? (chevron ? /* @__PURE__ */
|
|
2532
|
+
render: render ?? (chevron ? /* @__PURE__ */ jsx47("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx47("span", {})),
|
|
2203
2533
|
props: {
|
|
2204
2534
|
// `text-left`: a button centres its text. `h-full` and `flex-1`: the
|
|
2205
2535
|
// whole row up to the actions is the hit target, as it was when the
|
|
2206
2536
|
// row itself carried the click.
|
|
2207
2537
|
className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
|
|
2208
|
-
children: /* @__PURE__ */
|
|
2209
|
-
chevron && /* @__PURE__ */
|
|
2538
|
+
children: /* @__PURE__ */ jsxs32(Fragment8, { children: [
|
|
2539
|
+
chevron && /* @__PURE__ */ jsx47(
|
|
2210
2540
|
IconChevronRight2,
|
|
2211
2541
|
{
|
|
2212
2542
|
size: 12,
|
|
@@ -2214,11 +2544,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2214
2544
|
className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
2215
2545
|
}
|
|
2216
2546
|
),
|
|
2217
|
-
/* @__PURE__ */
|
|
2547
|
+
/* @__PURE__ */ jsx47(SectionLabel, { children: title })
|
|
2218
2548
|
] })
|
|
2219
2549
|
}
|
|
2220
2550
|
});
|
|
2221
|
-
return /* @__PURE__ */
|
|
2551
|
+
return /* @__PURE__ */ jsxs32(
|
|
2222
2552
|
"div",
|
|
2223
2553
|
{
|
|
2224
2554
|
className: cn(
|
|
@@ -2231,15 +2561,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2231
2561
|
),
|
|
2232
2562
|
children: [
|
|
2233
2563
|
titleElement,
|
|
2234
|
-
trailing != null && /* @__PURE__ */
|
|
2235
|
-
actions && actions.length > 0 && /* @__PURE__ */
|
|
2564
|
+
trailing != null && /* @__PURE__ */ jsx47("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
2565
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx47(
|
|
2236
2566
|
"div",
|
|
2237
2567
|
{
|
|
2238
2568
|
className: cn(
|
|
2239
2569
|
"-mr-1 flex shrink-0 items-center gap-1",
|
|
2240
2570
|
showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
|
|
2241
2571
|
),
|
|
2242
|
-
children: actions.map((action) => /* @__PURE__ */
|
|
2572
|
+
children: actions.map((action) => /* @__PURE__ */ jsx47(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
|
|
2243
2573
|
}
|
|
2244
2574
|
)
|
|
2245
2575
|
]
|
|
@@ -2248,9 +2578,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
|
|
|
2248
2578
|
}
|
|
2249
2579
|
|
|
2250
2580
|
// src/CollapsibleSection.tsx
|
|
2251
|
-
import { useState as
|
|
2581
|
+
import { useState as useState7 } from "react";
|
|
2252
2582
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
2253
|
-
import { jsx as
|
|
2583
|
+
import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2254
2584
|
var OPEN = "open";
|
|
2255
2585
|
var CLOSED = "closed";
|
|
2256
2586
|
function readStored(key) {
|
|
@@ -2270,21 +2600,21 @@ function writeStored(key, open) {
|
|
|
2270
2600
|
}
|
|
2271
2601
|
}
|
|
2272
2602
|
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, children, className, contentClassName }) {
|
|
2273
|
-
const [openState, setOpenState] =
|
|
2603
|
+
const [openState, setOpenState] = useState7(() => readStored(storageKey) ?? defaultOpen);
|
|
2274
2604
|
const open = openProp ?? openState;
|
|
2275
2605
|
const setOpen = (next) => {
|
|
2276
2606
|
setOpenState(next);
|
|
2277
2607
|
writeStored(storageKey, next);
|
|
2278
2608
|
onOpenChange?.(next);
|
|
2279
2609
|
};
|
|
2280
|
-
return /* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2282
|
-
/* @__PURE__ */
|
|
2610
|
+
return /* @__PURE__ */ jsxs33(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
2611
|
+
/* @__PURE__ */ jsx48(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx48(Collapsible.Trigger, {}) }),
|
|
2612
|
+
/* @__PURE__ */ jsx48(
|
|
2283
2613
|
Collapsible.Panel,
|
|
2284
2614
|
{
|
|
2285
2615
|
hiddenUntilFound: true,
|
|
2286
2616
|
className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
|
|
2287
|
-
children: /* @__PURE__ */
|
|
2617
|
+
children: /* @__PURE__ */ jsx48("div", { className: cn("flex flex-col", contentClassName), children })
|
|
2288
2618
|
}
|
|
2289
2619
|
)
|
|
2290
2620
|
] });
|
|
@@ -2292,9 +2622,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
2292
2622
|
|
|
2293
2623
|
// src/Tabs.tsx
|
|
2294
2624
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
2295
|
-
import { jsx as
|
|
2625
|
+
import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2296
2626
|
function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
|
|
2297
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsx49(
|
|
2298
2628
|
BaseTabs.Root,
|
|
2299
2629
|
{
|
|
2300
2630
|
value: active,
|
|
@@ -2302,14 +2632,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2302
2632
|
if (details.reason === "none") onChange(value);
|
|
2303
2633
|
},
|
|
2304
2634
|
className,
|
|
2305
|
-
children: /* @__PURE__ */
|
|
2635
|
+
children: /* @__PURE__ */ jsx49(
|
|
2306
2636
|
BaseTabs.List,
|
|
2307
2637
|
{
|
|
2308
2638
|
activateOnFocus: true,
|
|
2309
2639
|
"aria-label": aria["aria-label"],
|
|
2310
2640
|
"aria-labelledby": aria["aria-labelledby"],
|
|
2311
2641
|
className: "flex items-center gap-2",
|
|
2312
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
2642
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs34(
|
|
2313
2643
|
BaseTabs.Tab,
|
|
2314
2644
|
{
|
|
2315
2645
|
value: tab.id,
|
|
@@ -2322,9 +2652,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2322
2652
|
),
|
|
2323
2653
|
children: [
|
|
2324
2654
|
tab.icon,
|
|
2325
|
-
/* @__PURE__ */
|
|
2655
|
+
/* @__PURE__ */ jsxs34("span", { className: "flex items-baseline", children: [
|
|
2326
2656
|
tab.label,
|
|
2327
|
-
tab.count !== void 0 ? /* @__PURE__ */
|
|
2657
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx49("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
2328
2658
|
] })
|
|
2329
2659
|
]
|
|
2330
2660
|
},
|
|
@@ -2337,10 +2667,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
2337
2667
|
}
|
|
2338
2668
|
|
|
2339
2669
|
// src/Toast.tsx
|
|
2340
|
-
import { createContext as
|
|
2670
|
+
import { createContext as createContext3, useContext as useContext3, useMemo as useMemo4 } from "react";
|
|
2341
2671
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
2342
2672
|
import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
2343
|
-
import { jsx as
|
|
2673
|
+
import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2344
2674
|
var SURFACE_STYLES = {
|
|
2345
2675
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
2346
2676
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
|
|
@@ -2365,13 +2695,6 @@ var ICON_STYLES = {
|
|
|
2365
2695
|
// approximated here (D16).
|
|
2366
2696
|
error: "signal:text-error-default"
|
|
2367
2697
|
};
|
|
2368
|
-
var ACTION_BORDER_STYLES = {
|
|
2369
|
-
success: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2370
|
-
brand: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2371
|
-
neutral: "border border-border-default",
|
|
2372
|
-
warning: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2373
|
-
error: "signal:border signal:border-border-default signal:hover:border-border-strong"
|
|
2374
|
-
};
|
|
2375
2698
|
var LABEL_CLASSES = "text-body-2 text-text-primary whitespace-nowrap";
|
|
2376
2699
|
var pillClassName = (type, hasAction, className) => cn(
|
|
2377
2700
|
"inline-flex items-center min-h-[32px] pl-2 py-1 rounded-lg shadow-lg",
|
|
@@ -2381,31 +2704,25 @@ var pillClassName = (type, hasAction, className) => cn(
|
|
|
2381
2704
|
SURFACE_STYLES[type],
|
|
2382
2705
|
className
|
|
2383
2706
|
);
|
|
2384
|
-
var actionClassName = (type) => cn(
|
|
2385
|
-
"h-6 flex items-center justify-center gap-1 px-1 py-1 rounded-md shrink-0 transition-colors",
|
|
2386
|
-
ACTION_BORDER_STYLES[type],
|
|
2387
|
-
type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
|
|
2388
|
-
);
|
|
2389
2707
|
function LeadingIcon({ type }) {
|
|
2390
2708
|
const Icon = ICONS[type];
|
|
2391
|
-
return /* @__PURE__ */
|
|
2709
|
+
return /* @__PURE__ */ jsx50(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
|
|
2392
2710
|
}
|
|
2393
|
-
var ACTION_LABEL_CLASSES = "text-btn-small text-text-primary whitespace-nowrap";
|
|
2394
2711
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
2395
2712
|
const hasAction = !!(actionLabel && onAction);
|
|
2396
|
-
return /* @__PURE__ */
|
|
2397
|
-
/* @__PURE__ */
|
|
2398
|
-
leadingIcon && /* @__PURE__ */
|
|
2399
|
-
/* @__PURE__ */
|
|
2713
|
+
return /* @__PURE__ */ jsxs35("div", { className: pillClassName(type, hasAction, className), children: [
|
|
2714
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2715
|
+
leadingIcon && /* @__PURE__ */ jsx50(LeadingIcon, { type }),
|
|
2716
|
+
/* @__PURE__ */ jsx50("span", { className: LABEL_CLASSES, children: label })
|
|
2400
2717
|
] }),
|
|
2401
|
-
hasAction && /* @__PURE__ */
|
|
2718
|
+
hasAction && /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
|
|
2402
2719
|
] });
|
|
2403
2720
|
}
|
|
2404
|
-
var ToastContext =
|
|
2721
|
+
var ToastContext = createContext3(null);
|
|
2405
2722
|
var VISIBLE_TOASTS = 3;
|
|
2406
2723
|
function ToastProvider({ children }) {
|
|
2407
|
-
const manager =
|
|
2408
|
-
const value =
|
|
2724
|
+
const manager = useMemo4(() => BaseToast.createToastManager(), []);
|
|
2725
|
+
const value = useMemo4(
|
|
2409
2726
|
() => ({
|
|
2410
2727
|
showToast: ({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, durationMs = 5e3 }) => manager.add({
|
|
2411
2728
|
title: label,
|
|
@@ -2419,9 +2736,9 @@ function ToastProvider({ children }) {
|
|
|
2419
2736
|
}),
|
|
2420
2737
|
[manager]
|
|
2421
2738
|
);
|
|
2422
|
-
return /* @__PURE__ */
|
|
2739
|
+
return /* @__PURE__ */ jsx50(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs35(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
|
|
2423
2740
|
children,
|
|
2424
|
-
/* @__PURE__ */
|
|
2741
|
+
/* @__PURE__ */ jsx50(BaseToast.Portal, { children: /* @__PURE__ */ jsx50(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx50(ToastList, {}) }) })
|
|
2425
2742
|
] }) });
|
|
2426
2743
|
}
|
|
2427
2744
|
function ToastList() {
|
|
@@ -2429,26 +2746,25 @@ function ToastList() {
|
|
|
2429
2746
|
return toasts.map((toast) => {
|
|
2430
2747
|
const type = toast.type ?? "neutral";
|
|
2431
2748
|
const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
|
|
2432
|
-
return /* @__PURE__ */
|
|
2749
|
+
return /* @__PURE__ */ jsxs35(
|
|
2433
2750
|
BaseToast.Root,
|
|
2434
2751
|
{
|
|
2435
2752
|
toast,
|
|
2436
2753
|
swipeDirection: ["left", "down"],
|
|
2437
2754
|
className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
|
|
2438
2755
|
children: [
|
|
2439
|
-
/* @__PURE__ */
|
|
2440
|
-
leadingIcon && /* @__PURE__ */
|
|
2441
|
-
/* @__PURE__ */
|
|
2756
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2757
|
+
leadingIcon && /* @__PURE__ */ jsx50(LeadingIcon, { type }),
|
|
2758
|
+
/* @__PURE__ */ jsx50(BaseToast.Title, { render: /* @__PURE__ */ jsx50("span", {}), className: LABEL_CLASSES })
|
|
2442
2759
|
] }),
|
|
2443
|
-
actionLabel && /* @__PURE__ */
|
|
2760
|
+
actionLabel && /* @__PURE__ */ jsx50(
|
|
2444
2761
|
BaseToast.Action,
|
|
2445
2762
|
{
|
|
2446
2763
|
onClick: () => {
|
|
2447
2764
|
onAction?.();
|
|
2448
2765
|
close(toast.id);
|
|
2449
2766
|
},
|
|
2450
|
-
|
|
2451
|
-
children: /* @__PURE__ */ jsx49("span", { className: ACTION_LABEL_CLASSES, children: actionLabel })
|
|
2767
|
+
render: /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", children: actionLabel })
|
|
2452
2768
|
}
|
|
2453
2769
|
)
|
|
2454
2770
|
]
|
|
@@ -2458,7 +2774,7 @@ function ToastList() {
|
|
|
2458
2774
|
});
|
|
2459
2775
|
}
|
|
2460
2776
|
function useToast() {
|
|
2461
|
-
const ctx =
|
|
2777
|
+
const ctx = useContext3(ToastContext);
|
|
2462
2778
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
2463
2779
|
return ctx;
|
|
2464
2780
|
}
|
|
@@ -2475,6 +2791,12 @@ export {
|
|
|
2475
2791
|
Chip,
|
|
2476
2792
|
ChipInput,
|
|
2477
2793
|
CollapsibleSection,
|
|
2794
|
+
CommandPalette,
|
|
2795
|
+
CommandPaletteAnswer,
|
|
2796
|
+
CommandPaletteForm,
|
|
2797
|
+
CommandPaletteQuote,
|
|
2798
|
+
CommandPaletteSearch,
|
|
2799
|
+
CommandPaletteWorking,
|
|
2478
2800
|
ConfirmDialog,
|
|
2479
2801
|
DialogShell,
|
|
2480
2802
|
Divider,
|