@estiva-app/ui 0.17.0 → 0.18.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/Form.d.ts +16 -1
- package/dist/Form.d.ts.map +1 -1
- package/dist/index.js +198 -186
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/CommandPalette.mdx +6 -2
- package/src/CommandPalette.stories.tsx +6 -3
- package/src/CommandPalette.test.tsx +15 -0
- package/src/CommandPalette.tsx +34 -46
- package/src/Form.mdx +12 -2
- package/src/Form.test.tsx +103 -0
- package/src/Form.tsx +64 -4
package/dist/index.js
CHANGED
|
@@ -817,9 +817,9 @@ import {
|
|
|
817
817
|
createContext as createContext3,
|
|
818
818
|
useContext as useContext3,
|
|
819
819
|
useEffect,
|
|
820
|
-
useLayoutEffect as
|
|
820
|
+
useLayoutEffect as useLayoutEffect3,
|
|
821
821
|
useMemo as useMemo2,
|
|
822
|
-
useRef as
|
|
822
|
+
useRef as useRef3,
|
|
823
823
|
useState as useState3
|
|
824
824
|
} from "react";
|
|
825
825
|
import { Dialog } from "@base-ui/react/dialog";
|
|
@@ -1255,39 +1255,129 @@ function FieldLine({ tone = "helper", children, className }) {
|
|
|
1255
1255
|
return /* @__PURE__ */ jsx20("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1256
1256
|
}
|
|
1257
1257
|
|
|
1258
|
+
// src/Form.tsx
|
|
1259
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef2 } from "react";
|
|
1260
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1261
|
+
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1262
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1263
|
+
var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1264
|
+
var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1265
|
+
function usable(element) {
|
|
1266
|
+
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1267
|
+
}
|
|
1268
|
+
function firstInvalid(form) {
|
|
1269
|
+
for (const marked of form.querySelectorAll("[data-invalid]")) {
|
|
1270
|
+
if (usable(marked)) return marked;
|
|
1271
|
+
const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
|
|
1272
|
+
if (inside) return inside;
|
|
1273
|
+
}
|
|
1274
|
+
return void 0;
|
|
1275
|
+
}
|
|
1276
|
+
function Form({ onSubmit, busy: ownBusy = false, enterSends = true, className, children, ...props }) {
|
|
1277
|
+
const outerBusy = useFormBusy();
|
|
1278
|
+
const busy = ownBusy || outerBusy;
|
|
1279
|
+
const form = useRef2(null);
|
|
1280
|
+
const busyNow = useRef2(busy);
|
|
1281
|
+
busyNow.current = busy;
|
|
1282
|
+
const sender = useRef2(null);
|
|
1283
|
+
const holding = useRef2(false);
|
|
1284
|
+
const lastInside = useRef2(null);
|
|
1285
|
+
useLayoutEffect2(() => {
|
|
1286
|
+
const element = form.current;
|
|
1287
|
+
if (!element) return;
|
|
1288
|
+
if (busy) {
|
|
1289
|
+
const active = document.activeElement;
|
|
1290
|
+
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1291
|
+
if (from?.isConnected) {
|
|
1292
|
+
sender.current = from;
|
|
1293
|
+
holding.current = true;
|
|
1294
|
+
element.focus();
|
|
1295
|
+
}
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
if (!holding.current) return;
|
|
1299
|
+
holding.current = false;
|
|
1300
|
+
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1301
|
+
const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
|
|
1302
|
+
sender.current = null;
|
|
1303
|
+
target?.focus();
|
|
1304
|
+
}, [busy]);
|
|
1305
|
+
const onKeyDown = (event) => {
|
|
1306
|
+
props.onKeyDown?.(event);
|
|
1307
|
+
if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
|
|
1308
|
+
const target = event.target;
|
|
1309
|
+
const inInput = target instanceof HTMLInputElement;
|
|
1310
|
+
if (inInput) event.preventDefault();
|
|
1311
|
+
if (event.altKey || event.shiftKey) return;
|
|
1312
|
+
if (event.ctrlKey || event.metaKey) {
|
|
1313
|
+
event.preventDefault();
|
|
1314
|
+
form.current?.requestSubmit();
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
if (!inInput) return;
|
|
1318
|
+
const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
|
|
1319
|
+
if (enterSends && oneLine) form.current?.requestSubmit();
|
|
1320
|
+
};
|
|
1321
|
+
return /* @__PURE__ */ jsx21(
|
|
1322
|
+
BaseForm,
|
|
1323
|
+
{
|
|
1324
|
+
ref: form,
|
|
1325
|
+
...props,
|
|
1326
|
+
tabIndex: busy ? -1 : props.tabIndex,
|
|
1327
|
+
className: cn("outline-none", className),
|
|
1328
|
+
onFocus: (event) => {
|
|
1329
|
+
if (event.target !== form.current) lastInside.current = event.target;
|
|
1330
|
+
props.onFocus?.(event);
|
|
1331
|
+
},
|
|
1332
|
+
onBlur: (event) => {
|
|
1333
|
+
const next = event.relatedTarget;
|
|
1334
|
+
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1335
|
+
props.onBlur?.(event);
|
|
1336
|
+
},
|
|
1337
|
+
onKeyDown,
|
|
1338
|
+
onSubmit: (event) => {
|
|
1339
|
+
event.preventDefault();
|
|
1340
|
+
if (busyNow.current) return;
|
|
1341
|
+
void onSubmit();
|
|
1342
|
+
},
|
|
1343
|
+
children: /* @__PURE__ */ jsx21(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx21(FormBusyContext.Provider, { value: busy, children }) })
|
|
1344
|
+
}
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1258
1348
|
// src/Skeleton.tsx
|
|
1259
|
-
import { jsx as
|
|
1349
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1260
1350
|
function SkeletonBar({ className, style }) {
|
|
1261
|
-
return /* @__PURE__ */
|
|
1351
|
+
return /* @__PURE__ */ jsx22("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1262
1352
|
}
|
|
1263
1353
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1264
1354
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1265
1355
|
return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsx22(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1357
|
+
/* @__PURE__ */ jsx22(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1268
1358
|
] });
|
|
1269
1359
|
}
|
|
1270
1360
|
function SkeletonList({ rows = 8, className }) {
|
|
1271
|
-
return /* @__PURE__ */
|
|
1361
|
+
return /* @__PURE__ */ jsx22("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx22(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1272
1362
|
}
|
|
1273
1363
|
|
|
1274
1364
|
// src/CommandPalette.tsx
|
|
1275
|
-
import { Fragment as Fragment3, jsx as
|
|
1365
|
+
import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1276
1366
|
var PaletteContext = createContext3(null);
|
|
1277
1367
|
function usePalette(part) {
|
|
1278
1368
|
const palette = useContext3(PaletteContext);
|
|
1279
1369
|
if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
|
|
1280
1370
|
return palette;
|
|
1281
1371
|
}
|
|
1282
|
-
var
|
|
1372
|
+
var CONTROL2 = 'input:not([type="hidden"]):not([tabindex="-1"]), textarea, button:not([tabindex="-1"]), [role="combobox"]';
|
|
1283
1373
|
function firstControl(popup) {
|
|
1284
1374
|
if (!popup) return null;
|
|
1285
1375
|
const field = popup.querySelector("[data-command-palette-field]");
|
|
1286
1376
|
if (field) return field;
|
|
1287
|
-
return popup.querySelector("[data-command-palette-fields]")?.querySelector(
|
|
1377
|
+
return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL2) ?? null;
|
|
1288
1378
|
}
|
|
1289
1379
|
function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
|
|
1290
|
-
const popupRef =
|
|
1380
|
+
const popupRef = useRef3(null);
|
|
1291
1381
|
useEffect(() => {
|
|
1292
1382
|
if (!open) return;
|
|
1293
1383
|
const frame = requestAnimationFrame(() => {
|
|
@@ -1298,9 +1388,9 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1298
1388
|
return () => cancelAnimationFrame(frame);
|
|
1299
1389
|
});
|
|
1300
1390
|
const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
|
|
1301
|
-
return /* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1391
|
+
return /* @__PURE__ */ jsx23(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs16(Dialog.Portal, { children: [
|
|
1392
|
+
/* @__PURE__ */ jsx23(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
|
|
1393
|
+
/* @__PURE__ */ jsx23(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx23(
|
|
1304
1394
|
Dialog.Popup,
|
|
1305
1395
|
{
|
|
1306
1396
|
ref: popupRef,
|
|
@@ -1310,13 +1400,13 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
|
|
|
1310
1400
|
if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
|
|
1311
1401
|
},
|
|
1312
1402
|
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",
|
|
1313
|
-
children: /* @__PURE__ */
|
|
1403
|
+
children: /* @__PURE__ */ jsx23(PaletteContext.Provider, { value: context, children })
|
|
1314
1404
|
}
|
|
1315
1405
|
) })
|
|
1316
1406
|
] }) });
|
|
1317
1407
|
}
|
|
1318
1408
|
function LevelChip({ chip, onBack }) {
|
|
1319
|
-
return /* @__PURE__ */
|
|
1409
|
+
return /* @__PURE__ */ jsx23(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
|
|
1320
1410
|
}
|
|
1321
1411
|
function useBack(chip, popupRef) {
|
|
1322
1412
|
return () => {
|
|
@@ -1328,9 +1418,9 @@ function useBack(chip, popupRef) {
|
|
|
1328
1418
|
function Footer({ keys }) {
|
|
1329
1419
|
const { where } = usePalette("The footer");
|
|
1330
1420
|
return /* @__PURE__ */ jsxs16("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: [
|
|
1331
|
-
/* @__PURE__ */
|
|
1421
|
+
/* @__PURE__ */ jsx23("span", { className: "min-w-0 flex-1 truncate", children: where }),
|
|
1332
1422
|
keys.map(([key, word]) => /* @__PURE__ */ jsxs16("span", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
1333
|
-
/* @__PURE__ */
|
|
1423
|
+
/* @__PURE__ */ jsx23(Kbd, { children: key }),
|
|
1334
1424
|
" ",
|
|
1335
1425
|
word
|
|
1336
1426
|
] }, key))
|
|
@@ -1344,11 +1434,11 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1344
1434
|
const rows = items.flatMap((g) => g.items);
|
|
1345
1435
|
const [litId, setLitId] = useState3();
|
|
1346
1436
|
const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
|
|
1347
|
-
const inputRef =
|
|
1348
|
-
const reported =
|
|
1349
|
-
const settled =
|
|
1350
|
-
const moved =
|
|
1351
|
-
|
|
1437
|
+
const inputRef = useRef3(null);
|
|
1438
|
+
const reported = useRef3({});
|
|
1439
|
+
const settled = useRef3(null);
|
|
1440
|
+
const moved = useRef3(false);
|
|
1441
|
+
useLayoutEffect3(() => {
|
|
1352
1442
|
const before = settled.current;
|
|
1353
1443
|
const now = reported.current;
|
|
1354
1444
|
const sameLevel = before?.query === query && before?.level === chip?.label;
|
|
@@ -1431,9 +1521,9 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1431
1521
|
},
|
|
1432
1522
|
children: [
|
|
1433
1523
|
/* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1434
|
-
/* @__PURE__ */
|
|
1435
|
-
chip && /* @__PURE__ */
|
|
1436
|
-
/* @__PURE__ */
|
|
1524
|
+
/* @__PURE__ */ jsx23(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
|
|
1525
|
+
chip && /* @__PURE__ */ jsx23(LevelChip, { chip, onBack: back }),
|
|
1526
|
+
/* @__PURE__ */ jsx23(
|
|
1437
1527
|
Autocomplete.Input,
|
|
1438
1528
|
{
|
|
1439
1529
|
ref: inputRef,
|
|
@@ -1446,42 +1536,42 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
|
|
|
1446
1536
|
)
|
|
1447
1537
|
] }),
|
|
1448
1538
|
/* @__PURE__ */ jsxs16(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
|
|
1449
|
-
children != null && /* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1451
|
-
/* @__PURE__ */
|
|
1452
|
-
/* @__PURE__ */
|
|
1539
|
+
children != null && /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
|
|
1540
|
+
/* @__PURE__ */ jsx23(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs16(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
|
|
1541
|
+
/* @__PURE__ */ jsx23(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx23(SectionLabel, { className: "text-text-secondary", children: group.value }) }),
|
|
1542
|
+
/* @__PURE__ */ jsx23(Autocomplete.Collection, { children: (row) => (
|
|
1453
1543
|
/* The menu row, as the list's own option — the way Select
|
|
1454
1544
|
puts it on `Select.Item`. One row, two parts. */
|
|
1455
|
-
/* @__PURE__ */
|
|
1545
|
+
/* @__PURE__ */ jsx23(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx23(
|
|
1456
1546
|
MenuItemBody,
|
|
1457
1547
|
{
|
|
1458
1548
|
size: "tall",
|
|
1459
1549
|
label: row.label,
|
|
1460
1550
|
description: row.description,
|
|
1461
|
-
leading: /* @__PURE__ */
|
|
1551
|
+
leading: /* @__PURE__ */ jsx23(RowLeading, { row }),
|
|
1462
1552
|
submenu: !!row.onGoIn,
|
|
1463
|
-
hint: row.onGoIn ? /* @__PURE__ */
|
|
1553
|
+
hint: row.onGoIn ? /* @__PURE__ */ jsx23(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx23(EnterHint, {})
|
|
1464
1554
|
}
|
|
1465
1555
|
) }, row.id)
|
|
1466
1556
|
) })
|
|
1467
1557
|
] }, group.value) }),
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
/* @__PURE__ */
|
|
1470
|
-
/* @__PURE__ */
|
|
1558
|
+
/* @__PURE__ */ jsx23(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs16(Fragment3, { children: [
|
|
1559
|
+
/* @__PURE__ */ jsx23(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
|
|
1560
|
+
/* @__PURE__ */ jsx23("span", { className: "text-caption text-text-muted", children: pending })
|
|
1471
1561
|
] }) }),
|
|
1472
|
-
notes.map((note) => /* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
1562
|
+
notes.map((note) => /* @__PURE__ */ jsx23("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx23(FieldLine, { children: note }) }, note)),
|
|
1563
|
+
/* @__PURE__ */ jsx23(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx23(EmptyState, { scope: "section", message: empty }) })
|
|
1474
1564
|
] }),
|
|
1475
|
-
/* @__PURE__ */
|
|
1565
|
+
/* @__PURE__ */ jsx23(Footer, { keys })
|
|
1476
1566
|
]
|
|
1477
1567
|
}
|
|
1478
1568
|
);
|
|
1479
1569
|
}
|
|
1480
1570
|
function RowLeading({ row }) {
|
|
1481
1571
|
if (row.icon != null) {
|
|
1482
|
-
return /* @__PURE__ */
|
|
1572
|
+
return /* @__PURE__ */ jsx23("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
|
|
1483
1573
|
}
|
|
1484
|
-
return /* @__PURE__ */
|
|
1574
|
+
return /* @__PURE__ */ jsx23("span", { className: "flex size-8 items-center justify-center", children: row.leading });
|
|
1485
1575
|
}
|
|
1486
1576
|
var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
|
|
1487
1577
|
function isTextField(el) {
|
|
@@ -1491,31 +1581,18 @@ function isTextField(el) {
|
|
|
1491
1581
|
function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
|
|
1492
1582
|
const { modKey, popupRef } = usePalette("CommandPaletteForm");
|
|
1493
1583
|
const back = useBack(chip, popupRef);
|
|
1494
|
-
const frameRef =
|
|
1584
|
+
const frameRef = useRef3(null);
|
|
1495
1585
|
const busy = !!working;
|
|
1496
|
-
const busyRef =
|
|
1586
|
+
const busyRef = useRef3(busy);
|
|
1497
1587
|
busyRef.current = busy;
|
|
1498
|
-
const
|
|
1499
|
-
const firstInvalid = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL) ?? null;
|
|
1588
|
+
const firstInvalid2 = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL2) ?? null;
|
|
1500
1589
|
const submit = () => {
|
|
1501
1590
|
if (busyRef.current || submitWaits) return;
|
|
1502
|
-
const active = document.activeElement;
|
|
1503
|
-
returnTo.current = active instanceof HTMLElement && frameRef.current?.contains(active) ? active : null;
|
|
1504
1591
|
onSubmit();
|
|
1505
1592
|
requestAnimationFrame(() => {
|
|
1506
|
-
if (!busyRef.current)
|
|
1593
|
+
if (!busyRef.current) firstInvalid2()?.focus();
|
|
1507
1594
|
});
|
|
1508
1595
|
};
|
|
1509
|
-
useLayoutEffect2(() => {
|
|
1510
|
-
if (busy) {
|
|
1511
|
-
frameRef.current?.focus();
|
|
1512
|
-
return;
|
|
1513
|
-
}
|
|
1514
|
-
if (document.activeElement !== frameRef.current) return;
|
|
1515
|
-
const was = returnTo.current;
|
|
1516
|
-
const target = firstInvalid() ?? (was?.isConnected && !was.disabled ? was : null) ?? firstControl(popupRef.current);
|
|
1517
|
-
target?.focus();
|
|
1518
|
-
}, [busy]);
|
|
1519
1596
|
const backWorksFrom = (el) => {
|
|
1520
1597
|
const frame = frameRef.current;
|
|
1521
1598
|
if (!frame || busy || !el || !frame.contains(el)) return false;
|
|
@@ -1524,13 +1601,8 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1524
1601
|
};
|
|
1525
1602
|
const [backNamed, setBackNamed] = useState3(false);
|
|
1526
1603
|
const measure = () => setBackNamed(backWorksFrom(document.activeElement));
|
|
1527
|
-
|
|
1604
|
+
useLayoutEffect3(measure);
|
|
1528
1605
|
const onKeyDown = (e) => {
|
|
1529
|
-
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
1530
|
-
e.preventDefault();
|
|
1531
|
-
submit();
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
1606
|
if (e.key === "Backspace" && !e.ctrlKey && !e.metaKey && !e.altKey && backWorksFrom(e.target)) {
|
|
1535
1607
|
e.preventDefault();
|
|
1536
1608
|
back();
|
|
@@ -1543,52 +1615,54 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
|
|
|
1543
1615
|
];
|
|
1544
1616
|
return /* @__PURE__ */ jsxs16("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
|
|
1545
1617
|
/* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
|
|
1546
|
-
icon != null && /* @__PURE__ */
|
|
1547
|
-
/* @__PURE__ */
|
|
1618
|
+
icon != null && /* @__PURE__ */ jsx23("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
|
|
1619
|
+
/* @__PURE__ */ jsx23(LevelChip, { chip, onBack: back })
|
|
1548
1620
|
] }),
|
|
1549
|
-
/* @__PURE__ */
|
|
1550
|
-
|
|
1551
|
-
/* @__PURE__ */
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1621
|
+
/* @__PURE__ */ jsxs16(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, className: "flex min-h-0 flex-col", children: [
|
|
1622
|
+
/* @__PURE__ */ jsx23(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-4", children }) }),
|
|
1623
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
|
|
1624
|
+
/* @__PURE__ */ jsx23("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx23(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx23(FieldLine, { tone: "error", children: error }) : null }),
|
|
1625
|
+
/* @__PURE__ */ jsx23(
|
|
1626
|
+
Button,
|
|
1627
|
+
{
|
|
1628
|
+
type: "submit",
|
|
1629
|
+
variant: "primary",
|
|
1630
|
+
disabled: busy,
|
|
1631
|
+
disabledReason: busy ? void 0 : submitWaits,
|
|
1632
|
+
leadingIcon: busy ? /* @__PURE__ */ jsx23(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
|
|
1633
|
+
children: working ? working.button : submitLabel
|
|
1634
|
+
}
|
|
1635
|
+
)
|
|
1636
|
+
] })
|
|
1563
1637
|
] }),
|
|
1564
|
-
/* @__PURE__ */
|
|
1638
|
+
/* @__PURE__ */ jsx23(Footer, { keys })
|
|
1565
1639
|
] });
|
|
1566
1640
|
}
|
|
1567
1641
|
var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
1568
1642
|
function CommandPaletteWorking({ children, bars = 2 }) {
|
|
1569
1643
|
return /* @__PURE__ */ jsxs16("div", { role: "status", className: "flex flex-col gap-2", children: [
|
|
1570
1644
|
/* @__PURE__ */ jsxs16("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
|
|
1571
|
-
/* @__PURE__ */
|
|
1645
|
+
/* @__PURE__ */ jsx23(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
|
|
1572
1646
|
children
|
|
1573
1647
|
] }),
|
|
1574
|
-
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */
|
|
1648
|
+
BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx23(SkeletonBar, { className: cn("h-3", width) }, width))
|
|
1575
1649
|
] });
|
|
1576
1650
|
}
|
|
1577
1651
|
function CommandPaletteAnswer({ children, note }) {
|
|
1578
1652
|
const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
|
|
1579
1653
|
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-2", children: [
|
|
1580
|
-
paragraphs.map((paragraph, i) => /* @__PURE__ */
|
|
1581
|
-
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */
|
|
1654
|
+
paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx23("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
|
|
1655
|
+
(part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx23("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
|
|
1582
1656
|
) }, i)),
|
|
1583
|
-
note && /* @__PURE__ */
|
|
1657
|
+
note && /* @__PURE__ */ jsx23(FieldLine, { children: note })
|
|
1584
1658
|
] });
|
|
1585
1659
|
}
|
|
1586
1660
|
function CommandPaletteQuote({ children }) {
|
|
1587
|
-
return /* @__PURE__ */
|
|
1661
|
+
return /* @__PURE__ */ jsx23("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
|
|
1588
1662
|
}
|
|
1589
1663
|
|
|
1590
1664
|
// src/InlineChip.tsx
|
|
1591
|
-
import { Fragment as Fragment4, jsx as
|
|
1665
|
+
import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1592
1666
|
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";
|
|
1593
1667
|
var INLINE_CHIP_TONE_CLASSES = {
|
|
1594
1668
|
/** A thing or a place — anything that is not a person. */
|
|
@@ -1611,22 +1685,22 @@ function inlineChipClassName(tone, className) {
|
|
|
1611
1685
|
}
|
|
1612
1686
|
function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
|
|
1613
1687
|
const body = /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
1614
|
-
icon && /* @__PURE__ */
|
|
1688
|
+
icon && /* @__PURE__ */ jsx24("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
|
|
1615
1689
|
children
|
|
1616
1690
|
] });
|
|
1617
1691
|
const classes = inlineChipClassName(tone, className);
|
|
1618
1692
|
if (href === void 0) {
|
|
1619
|
-
return /* @__PURE__ */
|
|
1693
|
+
return /* @__PURE__ */ jsx24("span", { className: classes, ...props, children: body });
|
|
1620
1694
|
}
|
|
1621
|
-
return /* @__PURE__ */
|
|
1695
|
+
return /* @__PURE__ */ jsx24("a", { href, className: classes, ...props, children: body });
|
|
1622
1696
|
}
|
|
1623
1697
|
|
|
1624
1698
|
// src/IdentityMenu.tsx
|
|
1625
|
-
import { useCallback, useRef as
|
|
1699
|
+
import { useCallback, useRef as useRef4 } from "react";
|
|
1626
1700
|
|
|
1627
1701
|
// src/Divider.tsx
|
|
1628
1702
|
import { Separator } from "@base-ui/react/separator";
|
|
1629
|
-
import { jsx as
|
|
1703
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1630
1704
|
function Divider({ orientation = "horizontal", label, tone = "default", className }) {
|
|
1631
1705
|
if (label && orientation === "horizontal") {
|
|
1632
1706
|
const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
|
|
@@ -1637,14 +1711,14 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
1637
1711
|
"aria-label": label,
|
|
1638
1712
|
className: cn("flex shrink-0 items-center gap-2 mx-3", className),
|
|
1639
1713
|
children: [
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
/* @__PURE__ */
|
|
1714
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
|
|
1715
|
+
/* @__PURE__ */ jsx25("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
|
|
1716
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
|
|
1643
1717
|
]
|
|
1644
1718
|
}
|
|
1645
1719
|
);
|
|
1646
1720
|
}
|
|
1647
|
-
return /* @__PURE__ */
|
|
1721
|
+
return /* @__PURE__ */ jsx25(
|
|
1648
1722
|
Separator,
|
|
1649
1723
|
{
|
|
1650
1724
|
orientation,
|
|
@@ -1654,15 +1728,15 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
|
|
|
1654
1728
|
}
|
|
1655
1729
|
|
|
1656
1730
|
// src/Person.tsx
|
|
1657
|
-
import { jsx as
|
|
1731
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1658
1732
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
1659
1733
|
return (
|
|
1660
1734
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
1661
1735
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
1662
1736
|
// row agree by construction.
|
|
1663
1737
|
/* @__PURE__ */ jsxs19("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
1738
|
+
/* @__PURE__ */ jsx26(Avatar, { name, src: picture, size }),
|
|
1739
|
+
/* @__PURE__ */ jsx26("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
1666
1740
|
] })
|
|
1667
1741
|
);
|
|
1668
1742
|
}
|
|
@@ -1670,10 +1744,10 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
|
1670
1744
|
// src/PersonTrigger.tsx
|
|
1671
1745
|
import { Button as BaseButton5 } from "@base-ui/react/button";
|
|
1672
1746
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
1673
|
-
import { jsx as
|
|
1747
|
+
import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1674
1748
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
1675
1749
|
if (compact) {
|
|
1676
|
-
return /* @__PURE__ */
|
|
1750
|
+
return /* @__PURE__ */ jsx27(
|
|
1677
1751
|
BaseButton5,
|
|
1678
1752
|
{
|
|
1679
1753
|
type: "button",
|
|
@@ -1682,7 +1756,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1682
1756
|
"aria-label": props["aria-label"] ?? name ?? fallback,
|
|
1683
1757
|
className: cn("cursor-pointer rounded-full", className),
|
|
1684
1758
|
...props,
|
|
1685
|
-
children: /* @__PURE__ */
|
|
1759
|
+
children: /* @__PURE__ */ jsx27(Avatar, { name, src: picture, size: size ?? 36 })
|
|
1686
1760
|
}
|
|
1687
1761
|
);
|
|
1688
1762
|
}
|
|
@@ -1704,18 +1778,18 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
|
|
|
1704
1778
|
),
|
|
1705
1779
|
...props,
|
|
1706
1780
|
children: [
|
|
1707
|
-
/* @__PURE__ */
|
|
1708
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsx27(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
1782
|
+
/* @__PURE__ */ jsx27(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
1709
1783
|
]
|
|
1710
1784
|
}
|
|
1711
1785
|
);
|
|
1712
1786
|
}
|
|
1713
1787
|
|
|
1714
1788
|
// src/IdentityMenu.tsx
|
|
1715
|
-
import { Fragment as Fragment5, jsx as
|
|
1789
|
+
import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1716
1790
|
function IdentityPanel({ className, onClose = () => {
|
|
1717
1791
|
}, ...rest }) {
|
|
1718
|
-
return /* @__PURE__ */
|
|
1792
|
+
return /* @__PURE__ */ jsx28(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx28(IdentityRows, { ...rest, onClose }) });
|
|
1719
1793
|
}
|
|
1720
1794
|
function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
|
|
1721
1795
|
const act = (action) => () => {
|
|
@@ -1725,51 +1799,51 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
|
|
|
1725
1799
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
1726
1800
|
return /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1727
1801
|
/* @__PURE__ */ jsxs21(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
1728
|
-
/* @__PURE__ */
|
|
1729
|
-
/* @__PURE__ */
|
|
1802
|
+
/* @__PURE__ */ jsx28(MenuRow, { children: /* @__PURE__ */ jsx28(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
1803
|
+
/* @__PURE__ */ jsx28(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." }),
|
|
1730
1804
|
me.email && /* @__PURE__ */ jsxs21(Note, { children: [
|
|
1731
1805
|
me.email,
|
|
1732
1806
|
" \xB7 known to Estiva, never published to the relay"
|
|
1733
1807
|
] })
|
|
1734
1808
|
] }),
|
|
1735
1809
|
relayUrl && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1736
|
-
/* @__PURE__ */
|
|
1810
|
+
/* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }),
|
|
1737
1811
|
/* @__PURE__ */ jsxs21(MenuSection, { label: "Workspace", children: [
|
|
1738
|
-
/* @__PURE__ */
|
|
1739
|
-
/* @__PURE__ */
|
|
1812
|
+
/* @__PURE__ */ jsx28(MenuRow, { children: /* @__PURE__ */ jsx28("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
1813
|
+
/* @__PURE__ */ jsx28(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
1740
1814
|
] })
|
|
1741
1815
|
] }),
|
|
1742
1816
|
appRows && /* @__PURE__ */ jsxs21(Fragment5, { children: [
|
|
1743
|
-
/* @__PURE__ */
|
|
1817
|
+
/* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }),
|
|
1744
1818
|
appRows
|
|
1745
1819
|
] }),
|
|
1746
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
1747
|
-
signedIn && idBase && /* @__PURE__ */
|
|
1820
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }) : null,
|
|
1821
|
+
signedIn && idBase && /* @__PURE__ */ jsx28(
|
|
1748
1822
|
MenuItem,
|
|
1749
1823
|
{
|
|
1750
1824
|
label: "Edit your profile in Estiva ID",
|
|
1751
1825
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
1752
1826
|
}
|
|
1753
1827
|
),
|
|
1754
|
-
onCopyKey && /* @__PURE__ */
|
|
1755
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
1828
|
+
onCopyKey && /* @__PURE__ */ jsx28(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
1829
|
+
idBase && onSignOut && /* @__PURE__ */ jsx28(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
1756
1830
|
] });
|
|
1757
1831
|
}
|
|
1758
1832
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
1759
|
-
const actions =
|
|
1833
|
+
const actions = useRef4(null);
|
|
1760
1834
|
const close = useCallback(() => actions.current?.close(), []);
|
|
1761
1835
|
return (
|
|
1762
1836
|
/* The wrapper carries the caller's `className` and nothing else. It used
|
|
1763
1837
|
to be `relative`, because the panel was positioned against it; the panel
|
|
1764
1838
|
hangs from the trigger and portals now, so a positioning context here
|
|
1765
1839
|
would only be a lie about what this box does. */
|
|
1766
|
-
/* @__PURE__ */
|
|
1840
|
+
/* @__PURE__ */ jsx28("div", { className, children: /* @__PURE__ */ jsx28(
|
|
1767
1841
|
Menu,
|
|
1768
1842
|
{
|
|
1769
1843
|
align: "right",
|
|
1770
1844
|
actionsRef: actions,
|
|
1771
1845
|
className: "w-72",
|
|
1772
|
-
trigger: /* @__PURE__ */
|
|
1846
|
+
trigger: /* @__PURE__ */ jsx28(
|
|
1773
1847
|
PersonTrigger,
|
|
1774
1848
|
{
|
|
1775
1849
|
name: me.name,
|
|
@@ -1780,7 +1854,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1780
1854
|
"aria-label": compact ? "Account menu" : void 0
|
|
1781
1855
|
}
|
|
1782
1856
|
),
|
|
1783
|
-
children: /* @__PURE__ */
|
|
1857
|
+
children: /* @__PURE__ */ jsx28(
|
|
1784
1858
|
IdentityRows,
|
|
1785
1859
|
{
|
|
1786
1860
|
me,
|
|
@@ -1798,14 +1872,14 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
1798
1872
|
);
|
|
1799
1873
|
}
|
|
1800
1874
|
function Note({ children }) {
|
|
1801
|
-
return /* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ jsx28("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
1802
1876
|
}
|
|
1803
1877
|
|
|
1804
1878
|
// src/FilePicker.tsx
|
|
1805
1879
|
import { forwardRef } from "react";
|
|
1806
|
-
import { jsx as
|
|
1880
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1807
1881
|
var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
1808
|
-
return /* @__PURE__ */
|
|
1882
|
+
return /* @__PURE__ */ jsx29(
|
|
1809
1883
|
"input",
|
|
1810
1884
|
{
|
|
1811
1885
|
ref,
|
|
@@ -1823,68 +1897,6 @@ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
|
|
|
1823
1897
|
);
|
|
1824
1898
|
});
|
|
1825
1899
|
|
|
1826
|
-
// src/Form.tsx
|
|
1827
|
-
import { useLayoutEffect as useLayoutEffect3, useRef as useRef4 } from "react";
|
|
1828
|
-
import { Fieldset } from "@base-ui/react/fieldset";
|
|
1829
|
-
import { Form as BaseForm } from "@base-ui/react/form";
|
|
1830
|
-
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1831
|
-
var CONTROL2 = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
|
|
1832
|
-
function usable(element) {
|
|
1833
|
-
return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL2) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
|
|
1834
|
-
}
|
|
1835
|
-
function Form({ onSubmit, busy: ownBusy = false, className, children, ...props }) {
|
|
1836
|
-
const outerBusy = useFormBusy();
|
|
1837
|
-
const busy = ownBusy || outerBusy;
|
|
1838
|
-
const form = useRef4(null);
|
|
1839
|
-
const sender = useRef4(null);
|
|
1840
|
-
const holding = useRef4(false);
|
|
1841
|
-
const lastInside = useRef4(null);
|
|
1842
|
-
useLayoutEffect3(() => {
|
|
1843
|
-
const element = form.current;
|
|
1844
|
-
if (!element) return;
|
|
1845
|
-
if (busy) {
|
|
1846
|
-
const active = document.activeElement;
|
|
1847
|
-
const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
|
|
1848
|
-
if (from?.isConnected) {
|
|
1849
|
-
sender.current = from;
|
|
1850
|
-
holding.current = true;
|
|
1851
|
-
element.focus();
|
|
1852
|
-
}
|
|
1853
|
-
return;
|
|
1854
|
-
}
|
|
1855
|
-
if (!holding.current) return;
|
|
1856
|
-
holding.current = false;
|
|
1857
|
-
if (document.activeElement !== element && document.activeElement !== document.body) return;
|
|
1858
|
-
const invalid = Array.from(element.querySelectorAll("[data-invalid]")).find(usable);
|
|
1859
|
-
const target = invalid ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL2)).find(usable));
|
|
1860
|
-
sender.current = null;
|
|
1861
|
-
target?.focus();
|
|
1862
|
-
}, [busy]);
|
|
1863
|
-
return /* @__PURE__ */ jsx29(
|
|
1864
|
-
BaseForm,
|
|
1865
|
-
{
|
|
1866
|
-
ref: form,
|
|
1867
|
-
...props,
|
|
1868
|
-
tabIndex: busy ? -1 : props.tabIndex,
|
|
1869
|
-
className: cn("outline-none", className),
|
|
1870
|
-
onFocus: (event) => {
|
|
1871
|
-
if (event.target !== form.current) lastInside.current = event.target;
|
|
1872
|
-
props.onFocus?.(event);
|
|
1873
|
-
},
|
|
1874
|
-
onBlur: (event) => {
|
|
1875
|
-
const next = event.relatedTarget;
|
|
1876
|
-
if (next && !form.current?.contains(next)) lastInside.current = null;
|
|
1877
|
-
props.onBlur?.(event);
|
|
1878
|
-
},
|
|
1879
|
-
onSubmit: (event) => {
|
|
1880
|
-
event.preventDefault();
|
|
1881
|
-
void onSubmit();
|
|
1882
|
-
},
|
|
1883
|
-
children: /* @__PURE__ */ jsx29(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx29(FormBusyContext.Provider, { value: busy, children }) })
|
|
1884
|
-
}
|
|
1885
|
-
);
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
1900
|
// src/Select.tsx
|
|
1889
1901
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
1890
1902
|
import { Select as BaseSelect } from "@base-ui/react/select";
|