@ai-matrx/context-menu 0.1.2 → 0.1.4
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/CHANGELOG.md +12 -0
- package/dist/builder.cjs +4185 -128
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +1 -1
- package/dist/builder.d.ts +1 -1
- package/dist/builder.js +4193 -136
- package/dist/builder.js.map +1 -1
- package/dist/design-store.cjs.map +1 -1
- package/dist/design-store.d.cts +1 -1
- package/dist/design-store.d.ts +1 -1
- package/dist/design-store.js.map +1 -1
- package/dist/index.cjs +202 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +203 -83
- package/dist/index.js.map +1 -1
- package/dist/{model-CkLCR6WY.d.cts → model-C_7QZRE0.d.cts} +46 -4
- package/dist/{model-CkLCR6WY.d.ts → model-C_7QZRE0.d.ts} +46 -4
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/design/model.ts
|
|
4
|
+
var MENU_TONES = [
|
|
5
|
+
"default",
|
|
6
|
+
"primary",
|
|
7
|
+
"success",
|
|
8
|
+
"warning",
|
|
9
|
+
"info",
|
|
10
|
+
"destructive",
|
|
11
|
+
"sky",
|
|
12
|
+
"blue",
|
|
13
|
+
"indigo",
|
|
14
|
+
"violet",
|
|
15
|
+
"fuchsia",
|
|
16
|
+
"rose",
|
|
17
|
+
"orange",
|
|
18
|
+
"amber",
|
|
19
|
+
"lime",
|
|
20
|
+
"emerald",
|
|
21
|
+
"teal",
|
|
22
|
+
"cyan",
|
|
23
|
+
"slate"
|
|
24
|
+
];
|
|
25
|
+
var UNAVAILABLE_MODES = ["disable", "hide", "required"];
|
|
4
26
|
var MENU_SURFACES = [
|
|
5
27
|
"text-selection",
|
|
6
28
|
"editable-field",
|
|
@@ -312,54 +334,92 @@ function slotOptions(fills, placed) {
|
|
|
312
334
|
}
|
|
313
335
|
|
|
314
336
|
// src/design/MenuPreview.tsx
|
|
315
|
-
import { useMemo, useState } from "react";
|
|
337
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
316
338
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
317
|
-
function
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
return node.label.toLowerCase().includes(q) || node.children.some((c) => matches(c, q));
|
|
339
|
+
function searchable(node) {
|
|
340
|
+
if (node.kind === "divider" || node.kind === "search") return "";
|
|
341
|
+
const hint = node.kind === "item" || node.kind === "submenu" ? node.hint ?? "" : "";
|
|
342
|
+
return [node.label, hint, ...node.keywords ?? []].join(" ").toLowerCase();
|
|
322
343
|
}
|
|
323
|
-
function
|
|
344
|
+
function searchMenu(nodes, q, trail = [], out = []) {
|
|
345
|
+
const words = q.split(/\s+/).filter(Boolean);
|
|
324
346
|
for (const n of nodes) {
|
|
325
|
-
if (n.kind === "item"
|
|
326
|
-
|
|
347
|
+
if (n.kind === "item") {
|
|
348
|
+
const text = `${searchable(n)} ${trail.join(" ").toLowerCase()}`;
|
|
349
|
+
if (words.every((w) => text.includes(w))) out.push({ node: n, path: trail.join(" \u203A ") });
|
|
350
|
+
} else if (isContainer(n)) {
|
|
351
|
+
searchMenu(n.children, q, n.kind === "submenu" ? [...trail, n.label] : n.label ? [...trail, n.label] : trail, out);
|
|
352
|
+
}
|
|
327
353
|
}
|
|
328
354
|
return out;
|
|
329
355
|
}
|
|
330
|
-
function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, className, style }) {
|
|
356
|
+
function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, availability = "available", className, style }) {
|
|
331
357
|
const [query, setQuery] = useState("");
|
|
332
358
|
const q = query.trim().toLowerCase();
|
|
333
359
|
const { look } = design;
|
|
334
|
-
const results = useMemo(() => q ? flatten(design.nodes, q) : null, [design.nodes, q]);
|
|
335
360
|
const placed = useMemo(() => placedCatalogIds(design.nodes), [design.nodes]);
|
|
336
|
-
const ctx = { design, renderIcon, highlightId, onSelectNode, onPick, placed };
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
)
|
|
361
|
+
const ctx = { design, renderIcon, highlightId, onSelectNode, onPick, placed, availability, query, setQuery };
|
|
362
|
+
const searchAt = design.nodes.findIndex((n) => n.kind === "search");
|
|
363
|
+
const topSearch = searchAt < 0 && look.search ? { id: "look-search", kind: "search", placeholder: "Type to filter\u2026", autofocus: true } : null;
|
|
364
|
+
const hits = useMemo(() => q ? searchMenu(design.nodes, q) : null, [design.nodes, q]);
|
|
365
|
+
const above = searchAt >= 0 ? design.nodes.slice(0, searchAt) : [];
|
|
366
|
+
return /* @__PURE__ */ jsxs("div", { role: "menu", "data-density": look.density, className: `cm-menu ${className ?? ""}`, style: { width: look.width, ...style }, children: [
|
|
367
|
+
topSearch && /* @__PURE__ */ jsx(SearchBox, { node: topSearch, ctx }),
|
|
368
|
+
design.nodes.length === 0 && !topSearch ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Empty menu \u2014 drag options in" }) : hits ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
369
|
+
/* @__PURE__ */ jsx(Nodes, { nodes: above, ctx }),
|
|
370
|
+
searchAt >= 0 && /* @__PURE__ */ jsx(SearchBox, { node: design.nodes[searchAt], ctx }),
|
|
371
|
+
hits.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "No matches" }) : hits.map((h) => /* @__PURE__ */ jsx(Item, { node: h.node, ctx, path: h.path }, h.node.id))
|
|
372
|
+
] }) : /* @__PURE__ */ jsx(Nodes, { nodes: design.nodes, ctx })
|
|
373
|
+
] });
|
|
374
|
+
}
|
|
375
|
+
function SearchBox({ node, ctx }) {
|
|
376
|
+
const ref = useRef(null);
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
if (node.autofocus) ref.current?.focus({ preventScroll: true });
|
|
379
|
+
}, [node.autofocus]);
|
|
380
|
+
return /* @__PURE__ */ jsxs("div", { className: `cm-search ${ctx.highlightId === node.id ? "cm-hl" : ""}`, onClick: () => ctx.onSelectNode?.(node.id), children: [
|
|
381
|
+
ctx.renderIcon("Search", "cm-icon"),
|
|
382
|
+
/* @__PURE__ */ jsx(
|
|
383
|
+
"input",
|
|
384
|
+
{
|
|
385
|
+
ref,
|
|
386
|
+
value: ctx.query,
|
|
387
|
+
onChange: (e) => ctx.setQuery(e.target.value),
|
|
388
|
+
onKeyDown: (e) => {
|
|
389
|
+
if (e.key === "Escape" && ctx.query) {
|
|
390
|
+
e.stopPropagation();
|
|
391
|
+
ctx.setQuery("");
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
placeholder: node.placeholder || "Type to filter\u2026",
|
|
395
|
+
"aria-label": "Filter menu"
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
] });
|
|
399
|
+
}
|
|
400
|
+
function shown(node, ctx) {
|
|
401
|
+
if (ctx.availability === "available" || !node.unavailableWhen) {
|
|
402
|
+
return { hidden: false, greyed: node.kind === "item" && Boolean(node.disabled) };
|
|
403
|
+
}
|
|
404
|
+
const mode = node.unavailable ?? "disable";
|
|
405
|
+
if (mode === "hide") return { hidden: true, greyed: false };
|
|
406
|
+
if (mode === "required") return { hidden: false, greyed: false };
|
|
407
|
+
return { hidden: false, greyed: true };
|
|
353
408
|
}
|
|
354
409
|
function Nodes({ nodes, ctx }) {
|
|
355
410
|
return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((n) => {
|
|
411
|
+
if (shown(n, ctx).hidden) return null;
|
|
356
412
|
if (n.kind === "divider") return /* @__PURE__ */ jsx("div", { role: "separator", className: "cm-divider" }, n.id);
|
|
357
413
|
if (n.kind === "item") return /* @__PURE__ */ jsx(Item, { node: n, ctx }, n.id);
|
|
358
414
|
if (n.kind === "submenu") return /* @__PURE__ */ jsx(Submenu, { node: n, ctx }, n.id);
|
|
359
|
-
if (n.kind === "slot") return /* @__PURE__ */ jsx(Slot, { node: n, ctx }, n.id);
|
|
415
|
+
if (n.kind === "slot") return n.shape === "feature" ? /* @__PURE__ */ jsx(FeatureSlot, { node: n, ctx }, n.id) : /* @__PURE__ */ jsx(Slot, { node: n, ctx }, n.id);
|
|
416
|
+
if (n.kind === "search") return /* @__PURE__ */ jsx(SearchBox, { node: n, ctx }, n.id);
|
|
360
417
|
return /* @__PURE__ */ jsx(Section, { node: n, ctx }, n.id);
|
|
361
418
|
}) });
|
|
362
419
|
}
|
|
420
|
+
function toneAttrs(tone, toneLabel) {
|
|
421
|
+
return tone && tone !== "default" ? { "data-tone": tone, ...toneLabel ? { "data-tone-label": "" } : {} } : {};
|
|
422
|
+
}
|
|
363
423
|
function Section({ node, ctx }) {
|
|
364
424
|
const [open, setOpen] = useState(!node.collapsible);
|
|
365
425
|
const layout = node.layout ?? "list";
|
|
@@ -381,11 +441,12 @@ function Section({ node, ctx }) {
|
|
|
381
441
|
}
|
|
382
442
|
),
|
|
383
443
|
open && /* @__PURE__ */ jsx("div", { className: "cm-section-body", children: layout === "list" ? /* @__PURE__ */ jsx(Nodes, { nodes: node.children, ctx }) : node.children.map(
|
|
384
|
-
(c) => c.kind === "item" ? /* @__PURE__ */ jsx(Tile, { node: c, ctx }, c.id) : /* @__PURE__ */ jsx(Nodes, { nodes: [c], ctx }, c.id)
|
|
444
|
+
(c) => shown(c, ctx).hidden ? null : c.kind === "item" ? /* @__PURE__ */ jsx(Tile, { node: c, ctx }, c.id) : /* @__PURE__ */ jsx(Nodes, { nodes: [c], ctx }, c.id)
|
|
385
445
|
) })
|
|
386
446
|
] });
|
|
387
447
|
}
|
|
388
448
|
function Tile({ node, ctx }) {
|
|
449
|
+
const { greyed } = shown(node, ctx);
|
|
389
450
|
return (
|
|
390
451
|
// ui-exception: a menu row of the menu component itself
|
|
391
452
|
/* @__PURE__ */ jsx(
|
|
@@ -394,7 +455,8 @@ function Tile({ node, ctx }) {
|
|
|
394
455
|
type: "button",
|
|
395
456
|
role: "menuitem",
|
|
396
457
|
title: node.label + (node.shortcut ? ` ${node.shortcut}` : ""),
|
|
397
|
-
disabled:
|
|
458
|
+
disabled: greyed,
|
|
459
|
+
...toneAttrs(node.tone, node.toneLabel),
|
|
398
460
|
className: `cm-tile ${node.danger ? "cm-danger" : ""} ${node.ai ? "cm-ai" : ""} ${ctx.highlightId === node.id ? "cm-hl" : ""}`,
|
|
399
461
|
onClick: () => {
|
|
400
462
|
ctx.onSelectNode?.(node.id);
|
|
@@ -405,31 +467,37 @@ function Tile({ node, ctx }) {
|
|
|
405
467
|
)
|
|
406
468
|
);
|
|
407
469
|
}
|
|
408
|
-
function Item({ node, ctx }) {
|
|
470
|
+
function Item({ node, ctx, path }) {
|
|
409
471
|
const { look } = ctx.design;
|
|
410
|
-
const [checked, setChecked] = useState(
|
|
472
|
+
const [checked, setChecked] = useState(Boolean(node.defaultOn));
|
|
473
|
+
useEffect(() => setChecked(Boolean(node.defaultOn)), [node.defaultOn]);
|
|
474
|
+
const { greyed } = shown(node, ctx);
|
|
475
|
+
const settable = node.toggle || node.switch;
|
|
476
|
+
const hint = path || (look.showHints ? node.hint : void 0);
|
|
411
477
|
return (
|
|
412
478
|
// ui-exception: a menu row of the menu component itself
|
|
413
479
|
/* @__PURE__ */ jsxs(
|
|
414
480
|
"button",
|
|
415
481
|
{
|
|
416
482
|
type: "button",
|
|
417
|
-
role:
|
|
418
|
-
"aria-checked":
|
|
419
|
-
disabled:
|
|
483
|
+
role: settable ? "menuitemcheckbox" : "menuitem",
|
|
484
|
+
"aria-checked": settable ? checked : void 0,
|
|
485
|
+
disabled: greyed,
|
|
486
|
+
...toneAttrs(node.tone, node.toneLabel),
|
|
420
487
|
className: `cm-item ${node.danger ? "cm-danger" : ""} ${node.ai ? "cm-ai" : ""} ${ctx.highlightId === node.id ? "cm-hl" : ""}`,
|
|
421
488
|
onClick: () => {
|
|
422
489
|
ctx.onSelectNode?.(node.id);
|
|
423
|
-
if (
|
|
490
|
+
if (settable) setChecked((c) => !c);
|
|
424
491
|
ctx.onPick?.(node);
|
|
425
492
|
},
|
|
426
493
|
children: [
|
|
427
494
|
look.showIcons && /* @__PURE__ */ jsx("span", { className: "cm-icon-slot", children: node.toggle ? checked ? ctx.renderIcon("Check", "cm-icon") : null : node.icon ? ctx.renderIcon(node.icon, "cm-icon") : null }),
|
|
428
495
|
/* @__PURE__ */ jsxs("span", { className: "cm-text", children: [
|
|
429
496
|
/* @__PURE__ */ jsx("span", { className: "cm-label", children: node.label }),
|
|
430
|
-
|
|
497
|
+
hint && /* @__PURE__ */ jsx("span", { className: "cm-hint", children: hint })
|
|
431
498
|
] }),
|
|
432
|
-
look.showShortcuts && node.shortcut && /* @__PURE__ */ jsx("kbd", { className: "cm-shortcut", children: node.shortcut })
|
|
499
|
+
look.showShortcuts && node.shortcut && !node.switch && /* @__PURE__ */ jsx("kbd", { className: "cm-shortcut", children: node.shortcut }),
|
|
500
|
+
node.switch && /* @__PURE__ */ jsx("span", { className: "cm-switch", "data-on": checked ? "" : void 0, "aria-hidden": "true" })
|
|
433
501
|
]
|
|
434
502
|
}
|
|
435
503
|
)
|
|
@@ -439,35 +507,46 @@ function Submenu({ node, ctx }) {
|
|
|
439
507
|
const { look } = ctx.design;
|
|
440
508
|
const [open, setOpen] = useState(false);
|
|
441
509
|
const [side, setSide] = useState("right");
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
510
|
+
const { greyed } = shown(node, ctx);
|
|
511
|
+
return /* @__PURE__ */ jsxs(
|
|
512
|
+
"div",
|
|
513
|
+
{
|
|
514
|
+
className: "cm-sub",
|
|
515
|
+
onMouseEnter: (e) => {
|
|
516
|
+
if (greyed) return;
|
|
517
|
+
setSide(flyoutSide(e.currentTarget, look.width));
|
|
518
|
+
setOpen(true);
|
|
519
|
+
},
|
|
520
|
+
onMouseLeave: () => setOpen(false),
|
|
521
|
+
children: [
|
|
522
|
+
/* @__PURE__ */ jsxs(
|
|
523
|
+
"button",
|
|
524
|
+
{
|
|
525
|
+
type: "button",
|
|
526
|
+
role: "menuitem",
|
|
527
|
+
"aria-haspopup": "menu",
|
|
528
|
+
"aria-expanded": open,
|
|
529
|
+
disabled: greyed,
|
|
530
|
+
...toneAttrs(node.tone, node.toneLabel),
|
|
531
|
+
className: `cm-item ${ctx.highlightId === node.id ? "cm-hl" : ""}`,
|
|
532
|
+
onClick: () => {
|
|
533
|
+
ctx.onSelectNode?.(node.id);
|
|
534
|
+
setOpen(true);
|
|
535
|
+
},
|
|
536
|
+
children: [
|
|
537
|
+
look.showIcons && /* @__PURE__ */ jsx("span", { className: "cm-icon-slot", children: node.icon ? ctx.renderIcon(node.icon, "cm-icon") : null }),
|
|
538
|
+
/* @__PURE__ */ jsxs("span", { className: "cm-text", children: [
|
|
539
|
+
/* @__PURE__ */ jsx("span", { className: "cm-label", children: node.label }),
|
|
540
|
+
look.showHints && node.hint && /* @__PURE__ */ jsx("span", { className: "cm-hint", children: node.hint })
|
|
541
|
+
] }),
|
|
542
|
+
ctx.renderIcon("ChevronRight", "cm-icon cm-chev")
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
open && /* @__PURE__ */ jsx("div", { role: "menu", className: "cm-menu cm-flyout", "data-side": side, "data-density": look.density, style: { width: look.width }, children: node.children.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Empty submenu" }) : /* @__PURE__ */ jsx(Nodes, { nodes: node.children, ctx }) })
|
|
547
|
+
]
|
|
548
|
+
}
|
|
549
|
+
);
|
|
471
550
|
}
|
|
472
551
|
function flyoutSide(row, width) {
|
|
473
552
|
const r = row.getBoundingClientRect();
|
|
@@ -476,37 +555,42 @@ function flyoutSide(row, width) {
|
|
|
476
555
|
if (r.left - width - 8 >= bounds.left) return "left";
|
|
477
556
|
return "below";
|
|
478
557
|
}
|
|
479
|
-
function
|
|
558
|
+
function SlotRow({ node, ctx, label, icon, count, more, onOpen }) {
|
|
480
559
|
const { look } = ctx.design;
|
|
481
560
|
const source = slotSource(node.fills);
|
|
482
|
-
|
|
483
|
-
const [open, setOpen] = useState(false);
|
|
484
|
-
const [side, setSide] = useState("right");
|
|
485
|
-
const count = source?.runtime ? "live" : String(options.length);
|
|
486
|
-
const row = (
|
|
561
|
+
return (
|
|
487
562
|
// ui-exception: a menu row of the menu component itself
|
|
488
563
|
/* @__PURE__ */ jsxs(
|
|
489
564
|
"button",
|
|
490
565
|
{
|
|
491
566
|
type: "button",
|
|
492
567
|
role: "menuitem",
|
|
493
|
-
"aria-haspopup":
|
|
568
|
+
"aria-haspopup": more ? "menu" : void 0,
|
|
494
569
|
title: source ? `Placeholder: ${source.label}` : "Placeholder",
|
|
495
570
|
className: `cm-item cm-slot ${ctx.highlightId === node.id ? "cm-hl" : ""}`,
|
|
496
571
|
onClick: () => {
|
|
497
572
|
ctx.onSelectNode?.(node.id);
|
|
498
|
-
|
|
573
|
+
onOpen?.();
|
|
499
574
|
},
|
|
500
575
|
children: [
|
|
501
|
-
look.showIcons && /* @__PURE__ */ jsx("span", { className: "cm-icon-slot", children: ctx.renderIcon(
|
|
502
|
-
/* @__PURE__ */ jsx("span", { className: "cm-text", children: /* @__PURE__ */ jsx("span", { className: "cm-label", children:
|
|
503
|
-
/* @__PURE__ */ jsx("span", { className: "cm-count", children: count }),
|
|
504
|
-
|
|
576
|
+
look.showIcons && /* @__PURE__ */ jsx("span", { className: "cm-icon-slot", children: ctx.renderIcon(icon, "cm-icon") }),
|
|
577
|
+
/* @__PURE__ */ jsx("span", { className: "cm-text", children: /* @__PURE__ */ jsx("span", { className: "cm-label", children: label }) }),
|
|
578
|
+
count && /* @__PURE__ */ jsx("span", { className: "cm-count", children: count }),
|
|
579
|
+
more && ctx.renderIcon("ChevronRight", "cm-icon cm-chev")
|
|
505
580
|
]
|
|
506
581
|
}
|
|
507
582
|
)
|
|
508
583
|
);
|
|
509
|
-
|
|
584
|
+
}
|
|
585
|
+
function Slot({ node, ctx }) {
|
|
586
|
+
const { look } = ctx.design;
|
|
587
|
+
const source = slotSource(node.fills);
|
|
588
|
+
const options = slotOptions(node.fills, ctx.placed);
|
|
589
|
+
const [open, setOpen] = useState(false);
|
|
590
|
+
const [side, setSide] = useState("right");
|
|
591
|
+
const icon = node.icon ?? source?.icon ?? "Ellipsis";
|
|
592
|
+
const count = source?.runtime ? "live" : String(options.length);
|
|
593
|
+
if (node.shape === "items") return /* @__PURE__ */ jsx(SlotRow, { node, ctx, label: node.label, icon, count });
|
|
510
594
|
return /* @__PURE__ */ jsxs(
|
|
511
595
|
"div",
|
|
512
596
|
{
|
|
@@ -517,24 +601,60 @@ function Slot({ node, ctx }) {
|
|
|
517
601
|
},
|
|
518
602
|
onMouseLeave: () => setOpen(false),
|
|
519
603
|
children: [
|
|
520
|
-
|
|
604
|
+
/* @__PURE__ */ jsx(SlotRow, { node, ctx, label: node.label, icon, count, more: true, onOpen: () => setOpen(true) }),
|
|
521
605
|
open && /* @__PURE__ */ jsx("div", { role: "menu", className: "cm-menu cm-flyout", "data-side": side, "data-density": look.density, style: { width: look.width }, children: source?.runtime ? /* @__PURE__ */ jsxs("div", { className: "cm-runtime", children: [
|
|
522
606
|
"Filled at runtime: ",
|
|
523
607
|
source.label
|
|
524
|
-
] }) : options.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Nothing left \u2014 every option of this kind is placed" }) : options.map((o2) => /* @__PURE__ */ jsx(
|
|
608
|
+
] }) : options.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Nothing left \u2014 every option of this kind is placed" }) : options.map((o2) => /* @__PURE__ */ jsx(
|
|
609
|
+
Item,
|
|
610
|
+
{
|
|
611
|
+
node: { id: `slot-${node.id}-${o2.id}`, kind: "item", label: o2.label, icon: o2.icon, catalogId: o2.id, ...o2.shortcut ? { shortcut: o2.shortcut } : {}, ...o2.ai ? { ai: true } : {}, ...o2.danger ? { danger: true } : {} },
|
|
612
|
+
ctx
|
|
613
|
+
},
|
|
614
|
+
o2.id
|
|
615
|
+
)) })
|
|
525
616
|
]
|
|
526
617
|
}
|
|
527
618
|
);
|
|
528
619
|
}
|
|
620
|
+
function FeatureSlot({ node, ctx }) {
|
|
621
|
+
const { look } = ctx.design;
|
|
622
|
+
const n = Math.max(0, Math.min(12, node.featureItems ?? 4));
|
|
623
|
+
const [open, setOpen] = useState(false);
|
|
624
|
+
const [side, setSide] = useState("right");
|
|
625
|
+
return /* @__PURE__ */ jsxs("div", { className: `cm-section ${ctx.highlightId === node.id ? "cm-hl" : ""}`, "data-layout": "list", children: [
|
|
626
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "cm-section-label cm-slot-label", onClick: () => ctx.onSelectNode?.(node.id), children: node.label || "This feature" }),
|
|
627
|
+
/* @__PURE__ */ jsxs("div", { className: "cm-section-body", children: [
|
|
628
|
+
Array.from({ length: n }, (_, i) => /* @__PURE__ */ jsx(SlotRow, { node, ctx, label: `Feature option ${i + 1}`, icon: "Circle" }, i)),
|
|
629
|
+
/* @__PURE__ */ jsxs(
|
|
630
|
+
"div",
|
|
631
|
+
{
|
|
632
|
+
className: "cm-sub",
|
|
633
|
+
onMouseEnter: (e) => {
|
|
634
|
+
setSide(flyoutSide(e.currentTarget, look.width));
|
|
635
|
+
setOpen(true);
|
|
636
|
+
},
|
|
637
|
+
onMouseLeave: () => setOpen(false),
|
|
638
|
+
children: [
|
|
639
|
+
/* @__PURE__ */ jsx(SlotRow, { node, ctx, label: "More", icon: "Ellipsis", more: true, onOpen: () => setOpen(true) }),
|
|
640
|
+
open && /* @__PURE__ */ jsx("div", { role: "menu", className: "cm-menu cm-flyout", "data-side": side, "data-density": look.density, style: { width: look.width }, children: /* @__PURE__ */ jsx("div", { className: "cm-runtime", children: "The rest of this feature's options, filled at runtime" }) })
|
|
641
|
+
]
|
|
642
|
+
}
|
|
643
|
+
)
|
|
644
|
+
] })
|
|
645
|
+
] });
|
|
646
|
+
}
|
|
529
647
|
export {
|
|
530
648
|
CATALOG,
|
|
531
649
|
CATALOG_GROUPS,
|
|
532
650
|
DEFAULT_LOOK,
|
|
533
651
|
DESIGN_FORMAT,
|
|
534
652
|
MENU_SURFACES,
|
|
653
|
+
MENU_TONES,
|
|
535
654
|
MenuPreview,
|
|
536
655
|
SLOT_SOURCES,
|
|
537
656
|
TEMPLATES,
|
|
657
|
+
UNAVAILABLE_MODES,
|
|
538
658
|
canMove,
|
|
539
659
|
catalogOption,
|
|
540
660
|
catalogUseCounts,
|