@ai-matrx/context-menu 0.1.3 → 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 +6 -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 +4 -4
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/design/model.ts","../src/design/catalog.ts","../src/design/MenuPreview.tsx"],"sourcesContent":["// @ai-matrx/context-menu — the menu design model, the option catalog, and the menu renderer.\n// The live context menu engine is moving here from matrx-frontend (features/context-menu-v3).\nexport * from \"./design/model\";\nexport * from \"./design/catalog\";\nexport { MenuPreview, type MenuPreviewProps } from \"./design/MenuPreview\";\n","// src/design/model.ts — @ai-matrx/context-menu: THE MENU DESIGN.\n//\n// A design is the whole menu a person drew in the builder: an ordered tree of items, sections,\n// submenus and dividers, plus the few presentation choices that change how it reads. It is plain\n// JSON (no functions, no React) so it saves as one record, travels in a URL or a chat, and is the\n// exact thing the real menu is later built from. Every edit is a pure function returning a new\n// design; nothing here mutates.\n\nexport type MenuNodeKind = \"item\" | \"section\" | \"submenu\" | \"divider\" | \"slot\";\n\ninterface NodeBase {\n /** Stable within the design. */\n id: string;\n /** The catalog option this was dragged from, when it came from one. */\n catalogId?: string;\n /** A designer's note on this one entry (\"only on a table row\", \"merge with Copy\"). */\n note?: string;\n}\n\nexport interface MenuItemNode extends NodeBase {\n kind: \"item\";\n label: string;\n /** A lucide icon name (`Sparkles`, `Copy`). */\n icon?: string;\n /** Shown right-aligned (`⌘C`). */\n shortcut?: string;\n /** One short line under the label. */\n hint?: string;\n /** Shown greyed out — the design says \"this exists here but is unavailable now\". */\n disabled?: boolean;\n /** Red, for actions that remove or discard. */\n danger?: boolean;\n /** A checkbox-style toggle item. */\n toggle?: boolean;\n /** Drawn as a highlighted, AI-flavoured item. */\n ai?: boolean;\n}\n\nexport interface MenuSectionNode extends NodeBase {\n kind: \"section\";\n /** The small heading. Empty = an unlabelled group. */\n label: string;\n children: MenuNode[];\n /** Starts folded; a click on the heading opens it. */\n collapsible?: boolean;\n /** How the section's items are laid out. */\n layout?: \"list\" | \"grid\" | \"row\";\n}\n\nexport interface MenuSubmenuNode extends NodeBase {\n kind: \"submenu\";\n label: string;\n icon?: string;\n hint?: string;\n children: MenuNode[];\n}\n\nexport interface MenuDividerNode extends NodeBase {\n kind: \"divider\";\n}\n\n/**\n * A PLACEHOLDER: \"every other option of this kind goes here\". `shape: \"items\"` lays them out as rows\n * where the placeholder sits; `shape: \"submenu\"` gathers them into one submenu. `fills` names the\n * kind (a catalog group, the agent library, the page's own rows, or everything not placed).\n */\nexport interface MenuSlotNode extends NodeBase {\n kind: \"slot\";\n label: string;\n fills: string;\n shape: \"items\" | \"submenu\";\n icon?: string;\n}\n\nexport type MenuNode = MenuItemNode | MenuSectionNode | MenuSubmenuNode | MenuDividerNode | MenuSlotNode;\nexport type MenuContainerNode = MenuSectionNode | MenuSubmenuNode;\n\n/** Where the menu opens; the builder previews each the way it appears there. */\nexport const MENU_SURFACES = [\n \"text-selection\",\n \"editable-field\",\n \"table-row\",\n \"page\",\n \"chat-message\",\n \"file\",\n \"anywhere\",\n] as const;\nexport type MenuSurface = (typeof MENU_SURFACES)[number];\n\nexport interface MenuLook {\n density: \"compact\" | \"comfortable\";\n width: number;\n showIcons: boolean;\n showShortcuts: boolean;\n showHints: boolean;\n /** A search box at the top of the menu. */\n search: boolean;\n}\n\nexport const DEFAULT_LOOK: MenuLook = {\n density: \"comfortable\",\n width: 280,\n showIcons: true,\n showShortcuts: true,\n showHints: false,\n search: false,\n};\n\nexport interface MenuDesign {\n /** The design's identity; every version shares it. */\n designId: string;\n name: string;\n surface: MenuSurface;\n look: MenuLook;\n nodes: MenuNode[];\n /** Free notes for whoever builds it. */\n notes: string;\n}\n\nexport const DESIGN_FORMAT = 1;\n\n// ── ids ──────────────────────────────────────────────────────────────────────\n\nexport function newId(prefix = \"n\"): string {\n const rnd =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID().slice(0, 8)\n : Math.random().toString(36).slice(2, 10);\n return `${prefix}_${rnd}`;\n}\n\nexport function emptyDesign(name = \"Untitled menu\"): MenuDesign {\n return { designId: newId(\"d\"), name, surface: \"anywhere\", look: { ...DEFAULT_LOOK }, nodes: [], notes: \"\" };\n}\n\nexport function isContainer(node: MenuNode): node is MenuContainerNode {\n return node.kind === \"section\" || node.kind === \"submenu\";\n}\n\n/** Every catalog option the design already places (so a placeholder holds only the rest). */\nexport function placedCatalogIds(nodes: readonly MenuNode[], out = new Set<string>()): Set<string> {\n for (const n of nodes) {\n if (n.catalogId) out.add(n.catalogId);\n if (isContainer(n)) placedCatalogIds(n.children, out);\n }\n return out;\n}\n\n/** How many times each catalog option appears in the design (a duplicate counts twice). */\nexport function catalogUseCounts(nodes: readonly MenuNode[], out = new Map<string, number>()): Map<string, number> {\n for (const n of nodes) {\n if (n.catalogId) out.set(n.catalogId, (out.get(n.catalogId) ?? 0) + 1);\n if (isContainer(n)) catalogUseCounts(n.children, out);\n }\n return out;\n}\n\n/** A deep copy with every id renewed — what a duplicate or a second drop of a template gets. */\nexport function cloneNode<N extends MenuNode>(node: N): N {\n const copy = { ...node, id: newId(node.kind[0]) } as N;\n if (isContainer(copy)) (copy as MenuContainerNode).children = (copy as MenuContainerNode).children.map(cloneNode);\n return copy;\n}\n\n// ── reading the tree ─────────────────────────────────────────────────────────\n\nexport interface Located {\n node: MenuNode;\n /** The container's id, or null at the top. */\n parentId: string | null;\n index: number;\n depth: number;\n}\n\nexport function locate(nodes: readonly MenuNode[], id: string, parentId: string | null = null, depth = 0): Located | null {\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i] as MenuNode;\n if (node.id === id) return { node, parentId, index: i, depth };\n if (isContainer(node)) {\n const inner = locate(node.children, id, node.id, depth + 1);\n if (inner) return inner;\n }\n }\n return null;\n}\n\nexport function contains(node: MenuNode, id: string): boolean {\n if (node.id === id) return true;\n return isContainer(node) && node.children.some((c) => contains(c, id));\n}\n\nexport function countItems(nodes: readonly MenuNode[]): number {\n let n = 0;\n for (const node of nodes) {\n if (node.kind === \"item\" || node.kind === \"slot\") n += 1;\n else if (isContainer(node)) n += countItems(node.children) + (node.kind === \"submenu\" ? 1 : 0);\n }\n return n;\n}\n\n// ── editing the tree (pure) ──────────────────────────────────────────────────\n\nfunction mapChildren(nodes: readonly MenuNode[], parentId: string | null, fn: (list: MenuNode[]) => MenuNode[]): MenuNode[] {\n if (parentId === null) return fn([...nodes]);\n return nodes.map((node) => {\n if (!isContainer(node)) return node;\n if (node.id === parentId) return { ...node, children: fn([...node.children]) };\n return { ...node, children: mapChildren(node.children, parentId, fn) };\n });\n}\n\nexport function insertNode(nodes: readonly MenuNode[], parentId: string | null, index: number, node: MenuNode): MenuNode[] {\n return mapChildren(nodes, parentId, (list) => {\n list.splice(Math.max(0, Math.min(index, list.length)), 0, node);\n return list;\n });\n}\n\nexport function removeNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n return nodes\n .filter((n) => n.id !== id)\n .map((n) => (isContainer(n) ? { ...n, children: removeNode(n.children, id) } : n));\n}\n\nexport function updateNode(nodes: readonly MenuNode[], id: string, patch: Partial<MenuNode>): MenuNode[] {\n return nodes.map((n) => {\n if (n.id === id) return { ...n, ...patch, id: n.id, kind: n.kind } as MenuNode;\n if (isContainer(n)) return { ...n, children: updateNode(n.children, id, patch) };\n return n;\n });\n}\n\n/**\n * Move `id` to `index` inside `parentId`. Refuses (returns the tree unchanged) a move into itself\n * or its own descendant. `index` is in the destination list as it reads BEFORE the move.\n */\nexport function canMove(nodes: readonly MenuNode[], id: string, parentId: string | null): boolean {\n const from = locate(nodes, id);\n return Boolean(from) && (parentId === null || !contains((from as Located).node, parentId));\n}\n\nexport function moveNode(nodes: readonly MenuNode[], id: string, parentId: string | null, index: number): MenuNode[] {\n const from = locate(nodes, id);\n // A refused move answers the SAME array, so a caller can tell \"nothing happened\" by identity.\n if (!from) return nodes as MenuNode[];\n if (parentId !== null && contains(from.node, parentId)) return nodes as MenuNode[];\n let target = index;\n if (from.parentId === parentId && from.index < index) target -= 1;\n return insertNode(removeNode(nodes, id), parentId, target, from.node);\n}\n\nexport function duplicateNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n const at = locate(nodes, id);\n if (!at) return [...nodes];\n return insertNode(nodes, at.parentId, at.index + 1, cloneNode(at.node));\n}\n\n/** Wrap a node into a new section (or submenu) in its place. */\nexport function wrapNode(nodes: readonly MenuNode[], id: string, kind: \"section\" | \"submenu\"): MenuNode[] {\n const at = locate(nodes, id);\n if (!at) return [...nodes];\n const wrapper: MenuContainerNode =\n kind === \"section\"\n ? { id: newId(\"s\"), kind: \"section\", label: \"New section\", children: [at.node] }\n : { id: newId(\"m\"), kind: \"submenu\", label: \"More\", icon: \"ChevronRight\", children: [at.node] };\n return insertNode(removeNode(nodes, id), at.parentId, at.index, wrapper);\n}\n\n/** Replace a container by its children. */\nexport function unwrapNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n const at = locate(nodes, id);\n if (!at || !isContainer(at.node)) return [...nodes];\n let out = removeNode(nodes, id);\n at.node.children.forEach((child, i) => {\n out = insertNode(out, at.parentId, at.index + i, child);\n });\n return out;\n}\n\n// ── reading a saved design defensively ──────────────────────────────────────\n\n/** A saved document back into a design; anything unreadable becomes an empty design, never a throw. */\nexport function parseDesign(raw: unknown): MenuDesign {\n let value: unknown = raw;\n if (typeof raw === \"string\") {\n try {\n value = JSON.parse(raw);\n } catch {\n return emptyDesign(\"Unreadable design\");\n }\n }\n const v = (value ?? {}) as Partial<MenuDesign> & { design?: MenuDesign };\n const d = v.design ?? v;\n return {\n designId: typeof d.designId === \"string\" ? d.designId : newId(\"d\"),\n name: typeof d.name === \"string\" ? d.name : \"Untitled menu\",\n surface: MENU_SURFACES.includes(d.surface as MenuSurface) ? (d.surface as MenuSurface) : \"anywhere\",\n look: { ...DEFAULT_LOOK, ...(d.look ?? {}) },\n nodes: Array.isArray(d.nodes) ? (d.nodes as MenuNode[]) : [],\n notes: typeof d.notes === \"string\" ? d.notes : \"\",\n };\n}\n\nexport function serializeDesign(design: MenuDesign): string {\n return JSON.stringify({ format: DESIGN_FORMAT, design });\n}\n","// src/design/catalog.ts — @ai-matrx/context-menu: EVERY OPTION A MENU CAN OFFER, as a palette.\n//\n// The builder's left column. Each entry is something the live menu shows somewhere today, taken\n// from the real menu's own lists in matrx-frontend (features/context-menu-v3):\n// - regroup/engine-rows.ts → the engine rows (`cm:*`)\n// - regroup/proposed-grouping.ts → the 13 \"grouped by what you get\" groups and their rules\n// - proposed/proposed-arrangement.ts → the three icon strips and the object-first submenus\n// - the page rows the demos show (notes, quiz row, table row, chat message)\n// Ids are the live menu's ids wherever one exists, so a saved design names the real row.\n// When the menu source moves into this package, this list is generated from it instead.\n\nimport type { MenuNode } from \"./model\";\n\nexport type CatalogGroup =\n | \"Clipboard\"\n | \"Edit\"\n | \"AI\"\n | \"Save & export\"\n | \"Share & publish\"\n | \"Organize\"\n | \"History & compare\"\n | \"Listen\"\n | \"Page: notes\"\n | \"Page: record\"\n | \"Page: chat message\"\n | \"Tools & admin\";\n\nexport interface CatalogOption {\n /** The live menu's id where one exists (`cm:copy`), else this catalog's own. */\n id: string;\n label: string;\n icon: string;\n group: CatalogGroup;\n shortcut?: string;\n hint?: string;\n danger?: boolean;\n ai?: boolean;\n /** \"Live\" = drawn by today's menu; \"Proposed\" = only in a proposal page so far. */\n status: \"live\" | \"proposed\";\n}\n\nconst o = (\n id: string,\n label: string,\n icon: string,\n group: CatalogGroup,\n extra: Partial<Omit<CatalogOption, \"id\" | \"label\" | \"icon\" | \"group\">> = {},\n): CatalogOption => ({ id, label, icon, group, status: \"live\", ...extra });\n\nexport const CATALOG: readonly CatalogOption[] = [\n // Clipboard — the verb strip\n o(\"cm:copy\", \"Copy\", \"Copy\", \"Clipboard\", { shortcut: \"⌘C\" }),\n o(\"cm:cut\", \"Cut\", \"Scissors\", \"Clipboard\", { shortcut: \"⌘X\" }),\n o(\"cm:paste\", \"Paste\", \"ClipboardPaste\", \"Clipboard\", { shortcut: \"⌘V\" }),\n o(\"cm:undo\", \"Undo\", \"Undo2\", \"Clipboard\", { shortcut: \"⌘Z\" }),\n o(\"cm:redo\", \"Redo\", \"Redo2\", \"Clipboard\", { shortcut: \"⇧⌘Z\" }),\n o(\"cm:find\", \"Find & Replace\", \"Search\", \"Clipboard\", { shortcut: \"⌘F\" }),\n o(\"cm:select-all\", \"Select All\", \"TextSelect\", \"Clipboard\", { shortcut: \"⌘A\" }),\n o(\"cm:copy-as\", \"Copy as…\", \"CopyPlus\", \"Clipboard\"),\n o(\"cm:json\", \"Copy as JSON\", \"Braces\", \"Clipboard\"),\n o(\"copy-html-page\", \"Copy as HTML page\", \"FileCode\", \"Clipboard\"),\n o(\"cm:insert-reference\", \"Insert / Copy reference…\", \"AtSign\", \"Clipboard\"),\n\n // Edit\n o(\"cm:save\", \"Save\", \"Save\", \"Edit\", { shortcut: \"⌘S\" }),\n o(\"duplicate\", \"Duplicate\", \"CopyPlus\", \"Edit\"),\n o(\"rename\", \"Rename\", \"PenLine\", \"Edit\"),\n o(\"edit\", \"Edit\", \"Pencil\", \"Edit\"),\n o(\"favorite\", \"Add to favorites\", \"Star\", \"Edit\"),\n o(\"archive\", \"Archive\", \"Archive\", \"Edit\", { danger: true }),\n o(\"cm:delete\", \"Delete\", \"Trash2\", \"Edit\", { danger: true }),\n\n // AI\n o(\"cm:chat\", \"Chat about this\", \"MessageSquare\", \"AI\", { ai: true }),\n o(\"cm:quick-actions\", \"Quick Actions\", \"Zap\", \"AI\", { ai: true }),\n o(\"cm:placement:ai-action\", \"AI Actions\", \"Sparkles\", \"AI\", { ai: true }),\n o(\"cm:placement:content-block\", \"Content blocks\", \"Blocks\", \"AI\", { ai: true }),\n o(\"cm:placement:organization-tool\", \"Org Items\", \"Building2\", \"AI\", { ai: true }),\n o(\"cm:placement:user-tool\", \"My Items\", \"User\", \"AI\", { ai: true }),\n o(\"cm:placement:quick-action\", \"Quick actions (placement)\", \"Zap\", \"AI\", { ai: true }),\n o(\"cm:placement:bound-agent\", \"Agents\", \"Bot\", \"AI\", { ai: true }),\n o(\"send-to-agent\", \"Send to agent…\", \"Send\", \"AI\", { ai: true }),\n o(\"continue-in-chat\", \"Continue in chat\", \"MessagesSquare\", \"AI\", { ai: true }),\n o(\"regenerate-response\", \"Regenerate\", \"RefreshCw\", \"AI\", { ai: true }),\n o(\"code-block-chart\", \"Make a chart\", \"ChartColumn\", \"AI\", { ai: true }),\n o(\"ai-improve\", \"Improve writing\", \"Wand2\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-summarize\", \"Summarize\", \"ListCollapse\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-explain\", \"Explain\", \"Lightbulb\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-translate\", \"Translate…\", \"Languages\", \"AI\", { ai: true, status: \"proposed\" }),\n\n // Save & export\n o(\"cm:export\", \"Export\", \"FileOutput\", \"Save & export\"),\n o(\"cm:convert\", \"Convert to…\", \"ArrowRightLeft\", \"Save & export\"),\n o(\"save-as-file\", \"Save as file\", \"FileDown\", \"Save & export\"),\n o(\"download-pdf\", \"Download PDF\", \"FileText\", \"Save & export\"),\n o(\"download-docx\", \"Download Word\", \"FileType\", \"Save & export\"),\n o(\"download-html\", \"Download HTML\", \"FileCode2\", \"Save & export\"),\n o(\"print\", \"Print\", \"Printer\", \"Save & export\", { shortcut: \"⌘P\" }),\n\n // Share & publish\n o(\"cm:share\", \"Share…\", \"Share2\", \"Share & publish\"),\n o(\"share-link\", \"Copy share link\", \"Link\", \"Share & publish\"),\n o(\"send-google-doc\", \"Send to Google Docs\", \"FileUp\", \"Share & publish\"),\n o(\"email-to-me\", \"Email to me\", \"Mail\", \"Share & publish\"),\n o(\"html-preview\", \"Preview as web page\", \"Eye\", \"Share & publish\"),\n o(\"share-webpage\", \"Publish as web page\", \"Globe\", \"Share & publish\"),\n\n // Organize\n o(\"cm:attach\", \"Attach to…\", \"Paperclip\", \"Organize\"),\n o(\"set-context-value\", \"Set as context\", \"Pin\", \"Organize\"),\n o(\"pin-message\", \"Pin\", \"Pin\", \"Organize\"),\n o(\"notes-and-comments\", \"Notes & comments\", \"StickyNote\", \"Organize\"),\n o(\"move\", \"Move to folder…\", \"FolderInput\", \"Organize\"),\n o(\"tags\", \"Tags…\", \"Tags\", \"Organize\"),\n\n // History & compare\n o(\"cm:view-history\", \"View history\", \"History\", \"History & compare\"),\n o(\"edit-history\", \"Edit history\", \"GitCommitVertical\", \"History & compare\"),\n o(\"fork-at-message\", \"Fork from here\", \"GitBranch\", \"History & compare\"),\n o(\"cm:compare\", \"Compare…\", \"GitCompareArrows\", \"History & compare\"),\n o(\"compare-with-clipboard\", \"Compare with clipboard\", \"ClipboardList\", \"History & compare\"),\n o(\"set-compare-base\", \"Set as compare base\", \"Flag\", \"History & compare\"),\n\n // Listen\n o(\"cm:speak\", \"Read aloud\", \"Volume2\", \"Listen\"),\n o(\"cm:listen\", \"Dictate\", \"Mic\", \"Listen\"),\n o(\"tts-voice-settings\", \"Voice settings\", \"AudioLines\", \"Listen\"),\n\n // Page rows: notes\n o(\"notes:close-tab\", \"Close tab\", \"X\", \"Page: notes\"),\n o(\"notes:close-others\", \"Close other tabs\", \"PanelTopClose\", \"Page: notes\"),\n o(\"notes:export-md\", \"Export as Markdown\", \"FileDown\", \"Page: notes\"),\n o(\"notes:share-clipboard\", \"Copy to clipboard\", \"ClipboardCopy\", \"Page: notes\"),\n o(\"notes:convert-artifacts\", \"Convert to artifacts\", \"Shapes\", \"Page: notes\"),\n o(\"notes:trash\", \"Move to Trash\", \"Trash2\", \"Page: notes\", { danger: true }),\n\n // Page rows: a record (quiz row, table row)\n o(\"row:open\", \"Open\", \"SquareArrowOutUpRight\", \"Page: record\"),\n o(\"row:open-tab\", \"Open in new tab\", \"ExternalLink\", \"Page: record\"),\n o(\"row:take\", \"Take\", \"Play\", \"Page: record\"),\n o(\"row:results\", \"Results\", \"ChartBar\", \"Page: record\"),\n o(\"row:manage\", \"Manage\", \"Settings2\", \"Page: record\"),\n o(\"row:restore\", \"Restore\", \"ArchiveRestore\", \"Page: record\"),\n\n // Page rows: chat message\n o(\"regenerate-latest\", \"Regenerate latest\", \"RotateCcw\", \"Page: chat message\", { ai: true }),\n o(\"fork-and-regenerate\", \"Fork and regenerate\", \"GitFork\", \"Page: chat message\", { ai: true }),\n o(\"feedback-up\", \"Good response\", \"ThumbsUp\", \"Page: chat message\"),\n o(\"feedback-down\", \"Bad response\", \"ThumbsDown\", \"Page: chat message\"),\n\n // Tools & admin\n o(\"cm:x:surface\", \"This page (location, context, agents)\", \"MapPin\", \"Tools & admin\"),\n o(\"cm:admin\", \"Admin tools\", \"Shield\", \"Tools & admin\"),\n o(\"feedback\", \"Send feedback\", \"MessageSquareWarning\", \"Tools & admin\"),\n o(\"keyboard-shortcuts\", \"Keyboard shortcuts\", \"Keyboard\", \"Tools & admin\", { status: \"proposed\" }),\n];\n\nexport const CATALOG_GROUPS: readonly CatalogGroup[] = [...new Set(CATALOG.map((c) => c.group))];\n\nexport function catalogOption(id: string): CatalogOption | undefined {\n return CATALOG.find((c) => c.id === id);\n}\n\n/** Ready-made pieces: dropping one inserts the whole block. */\nexport interface CatalogTemplate {\n id: string;\n label: string;\n icon: string;\n build: () => MenuNode;\n}\n\nlet seq = 0;\nconst tid = (p: string) => `${p}_t${Date.now().toString(36)}${(seq++).toString(36)}`;\n\nfunction itemFrom(id: string): MenuNode {\n const c = catalogOption(id);\n return {\n id: tid(\"i\"),\n kind: \"item\",\n catalogId: id,\n label: c?.label ?? id,\n icon: c?.icon ?? \"Circle\",\n ...(c?.shortcut ? { shortcut: c.shortcut } : {}),\n ...(c?.danger ? { danger: true } : {}),\n ...(c?.ai ? { ai: true } : {}),\n };\n}\n\nconst strip = (label: string, ids: string[]): MenuNode => ({\n id: tid(\"s\"),\n kind: \"section\",\n label,\n layout: \"row\",\n children: ids.map(itemFrom),\n});\n\nconst sub = (label: string, icon: string, ids: string[]): MenuNode => ({\n id: tid(\"m\"),\n kind: \"submenu\",\n label,\n icon,\n children: ids.map(itemFrom),\n});\n\nexport const TEMPLATES: readonly CatalogTemplate[] = [\n { id: \"strip-thing\", label: \"Icon strip — a thing\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:copy\", \"cm:share\", \"duplicate\", \"favorite\", \"save-as-file\", \"archive\"]) },\n { id: \"strip-edit\", label: \"Icon strip — editable text\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:cut\", \"cm:copy\", \"cm:paste\", \"cm:undo\", \"cm:redo\", \"cm:find\"]) },\n { id: \"strip-read\", label: \"Icon strip — read-only text\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:copy\", \"cm:speak\", \"cm:find\", \"cm:share\"]) },\n { id: \"sub-intelligence\", label: \"Intelligence ▸\", icon: \"Sparkles\", build: () => sub(\"Intelligence\", \"Sparkles\", [\"cm:chat\", \"cm:placement:ai-action\", \"cm:placement:bound-agent\", \"send-to-agent\"]) },\n { id: \"sub-save-share\", label: \"Save & share ▸\", icon: \"Share2\", build: () => sub(\"Save & share\", \"Share2\", [\"cm:copy-as\", \"save-as-file\", \"cm:convert\", \"share-webpage\", \"cm:share\"]) },\n { id: \"sub-organize\", label: \"Organize ▸\", icon: \"Tags\", build: () => sub(\"Organize\", \"Tags\", [\"cm:attach\", \"pin-message\", \"cm:view-history\", \"cm:compare\"]) },\n { id: \"sub-tools\", label: \"Tools ▸\", icon: \"Wrench\", build: () => sub(\"Tools\", \"Wrench\", [\"cm:speak\", \"cm:quick-actions\", \"feedback\", \"cm:x:surface\", \"cm:admin\"]) },\n];\n\n// ── placeholders ─────────────────────────────────────────────────────────────\n\n/** What a placeholder can hold. A catalog group holds that group's options the design has not placed. */\nexport interface SlotSource {\n id: string;\n label: string;\n /** The default placeholder wording (\"All other AI items\"). */\n phrase: string;\n icon: string;\n /** Filled by the live menu from data (agents, a page's own rows) — the preview cannot list them. */\n runtime?: boolean;\n}\n\nexport const SLOT_SOURCES: readonly SlotSource[] = [\n { id: \"any\", label: \"Everything not placed\", phrase: \"Everything else\", icon: \"Ellipsis\" },\n { id: \"agents\", label: \"Agents & shortcuts (library)\", phrase: \"All other agents\", icon: \"Bot\", runtime: true },\n { id: \"page-rows\", label: \"This page's own rows\", phrase: \"All of this page's actions\", icon: \"PanelTop\", runtime: true },\n ...CATALOG_GROUPS.map((g) => ({\n id: `group:${g}`,\n label: g,\n phrase: g === \"AI\" ? \"All other AI items\" : `All other ${g.toLowerCase()} options`,\n icon: CATALOG.find((c) => c.group === g)?.icon ?? \"Circle\",\n })),\n];\n\nexport function slotSource(id: string): SlotSource | undefined {\n return SLOT_SOURCES.find((s) => s.id === id);\n}\n\n/** The catalog options a placeholder stands for: its kind, minus every option the design already places. */\nexport function slotOptions(fills: string, placed: ReadonlySet<string>): CatalogOption[] {\n if (fills === \"agents\" || fills === \"page-rows\") return [];\n const pool = fills === \"any\" ? CATALOG : CATALOG.filter((c) => `group:${c.group}` === fills);\n return pool.filter((c) => !placed.has(c.id));\n}\n","// src/design/MenuPreview.tsx — @ai-matrx/context-menu: DRAWS A DESIGN AS THE MENU IT DESCRIBES.\n//\n// The same component draws the builder's live preview and the right-click test menu, so what the\n// designer sees is what opens. Icons come from the host (`renderIcon`), so this file has no icon set.\n\nimport { useMemo, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { slotOptions, slotSource } from \"./catalog\";\nimport { isContainer, placedCatalogIds, type MenuDesign, type MenuItemNode, type MenuNode, type MenuSlotNode, type MenuSubmenuNode } from \"./model\";\n\nexport interface MenuPreviewProps {\n design: MenuDesign;\n renderIcon: (name: string, className?: string) => ReactNode;\n /** The entry highlighted as \"selected in the builder\". */\n highlightId?: string | null;\n /** A click on any entry. */\n onSelectNode?: (id: string) => void;\n /** A click on an item (the menu's action). */\n onPick?: (item: MenuItemNode) => void;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction matches(node: MenuNode, q: string): boolean {\n if (!q) return true;\n if (node.kind === \"divider\") return false;\n if (node.kind === \"item\" || node.kind === \"slot\") return node.label.toLowerCase().includes(q);\n return node.label.toLowerCase().includes(q) || node.children.some((c) => matches(c, q));\n}\n\n/** While searching: one flat list of matching items, the way a command palette reads. */\nfunction flatten(nodes: readonly MenuNode[], q: string, out: MenuItemNode[] = []): MenuItemNode[] {\n for (const n of nodes) {\n if (n.kind === \"item\" && matches(n, q)) out.push(n);\n else if (isContainer(n)) flatten(n.children, q, out);\n }\n return out;\n}\n\nexport function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, className, style }: MenuPreviewProps) {\n const [query, setQuery] = useState(\"\");\n const q = query.trim().toLowerCase();\n const { look } = design;\n const results = useMemo(() => (q ? flatten(design.nodes, q) : null), [design.nodes, q]);\n const placed = useMemo(() => placedCatalogIds(design.nodes), [design.nodes]);\n const ctx: Ctx = { design, renderIcon, highlightId, onSelectNode, onPick, placed };\n\n return (\n <div\n role=\"menu\"\n data-density={look.density}\n className={`cm-menu ${className ?? \"\"}`}\n style={{ width: look.width, ...style }}\n >\n {look.search && (\n <div className=\"cm-search\">\n {renderIcon(\"Search\", \"cm-icon\")}\n {/* ui-exception: the menu's own filter row — this file IS the menu component */}\n <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder=\"Type to filter…\" aria-label=\"Filter menu\" />\n </div>\n )}\n {results ? (\n results.length === 0 ? (\n <div className=\"cm-empty\">No matches</div>\n ) : (\n results.map((n) => <Item key={n.id} node={n} ctx={ctx} />)\n )\n ) : design.nodes.length === 0 ? (\n <div className=\"cm-empty\">Empty menu — drag options in</div>\n ) : (\n <Nodes nodes={design.nodes} ctx={ctx} />\n )}\n </div>\n );\n}\n\ninterface Ctx {\n design: MenuDesign;\n renderIcon: MenuPreviewProps[\"renderIcon\"];\n highlightId: string | null | undefined;\n onSelectNode: MenuPreviewProps[\"onSelectNode\"];\n onPick: MenuPreviewProps[\"onPick\"];\n /** Catalog options the design places — a placeholder holds the rest. */\n placed: ReadonlySet<string>;\n}\n\nfunction Nodes({ nodes, ctx }: { nodes: readonly MenuNode[]; ctx: Ctx }) {\n return (\n <>\n {nodes.map((n) => {\n if (n.kind === \"divider\") return <div key={n.id} role=\"separator\" className=\"cm-divider\" />;\n if (n.kind === \"item\") return <Item key={n.id} node={n} ctx={ctx} />;\n if (n.kind === \"submenu\") return <Submenu key={n.id} node={n} ctx={ctx} />;\n if (n.kind === \"slot\") return <Slot key={n.id} node={n} ctx={ctx} />;\n return <Section key={n.id} node={n} ctx={ctx} />;\n })}\n </>\n );\n}\n\nfunction Section({ node, ctx }: { node: Extract<MenuNode, { kind: \"section\" }>; ctx: Ctx }) {\n const [open, setOpen] = useState(!node.collapsible);\n const layout = node.layout ?? \"list\";\n return (\n <div className={`cm-section ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`} data-layout={layout}>\n {node.label && (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n className=\"cm-section-label\"\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n if (node.collapsible) setOpen((o) => !o);\n }}\n >\n {node.label}\n {node.collapsible && <span className=\"cm-caret\">{open ? \"▾\" : \"▸\"}</span>}\n </button>\n )}\n {open && (\n <div className=\"cm-section-body\">\n {layout === \"list\" ? (\n <Nodes nodes={node.children} ctx={ctx} />\n ) : (\n node.children.map((c) =>\n c.kind === \"item\" ? <Tile key={c.id} node={c} ctx={ctx} /> : <Nodes key={c.id} nodes={[c]} ctx={ctx} />,\n )\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction Tile({ node, ctx }: { node: MenuItemNode; ctx: Ctx }) {\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role=\"menuitem\"\n title={node.label + (node.shortcut ? ` ${node.shortcut}` : \"\")}\n disabled={node.disabled}\n className={`cm-tile ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n ctx.onPick?.(node);\n }}\n >\n {ctx.renderIcon(node.icon ?? \"Circle\", \"cm-icon\")}\n </button>\n );\n}\n\nfunction Item({ node, ctx }: { node: MenuItemNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const [checked, setChecked] = useState(false);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role={node.toggle ? \"menuitemcheckbox\" : \"menuitem\"}\n aria-checked={node.toggle ? checked : undefined}\n disabled={node.disabled}\n className={`cm-item ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n if (node.toggle) setChecked((c) => !c);\n ctx.onPick?.(node);\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\">{node.toggle ? (checked ? ctx.renderIcon(\"Check\", \"cm-icon\") : null) : node.icon ? ctx.renderIcon(node.icon, \"cm-icon\") : null}</span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {look.showHints && node.hint && <span className=\"cm-hint\">{node.hint}</span>}\n </span>\n {look.showShortcuts && node.shortcut && <kbd className=\"cm-shortcut\">{node.shortcut}</kbd>}\n </button>\n );\n}\n\nfunction Submenu({ node, ctx }: { node: MenuSubmenuNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const [open, setOpen] = useState(false);\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n const show = (el: HTMLElement) => {\n setSide(flyoutSide(el, look.width));\n setOpen(true);\n };\n return (\n <div className=\"cm-sub\" onMouseEnter={(e) => show(e.currentTarget)} onMouseLeave={() => setOpen(false)}>\n {/* ui-exception: a menu row of the menu component itself */}\n <button\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n className={`cm-item ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n setOpen(true);\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\">{node.icon ? ctx.renderIcon(node.icon, \"cm-icon\") : null}</span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {look.showHints && node.hint && <span className=\"cm-hint\">{node.hint}</span>}\n </span>\n {ctx.renderIcon(\"ChevronRight\", \"cm-icon cm-chev\")}\n </button>\n {open && (\n <div role=\"menu\" className=\"cm-menu cm-flyout\" data-side={side} data-density={look.density} style={{ width: look.width }}>\n {node.children.length === 0 ? <div className=\"cm-empty\">Empty submenu</div> : <Nodes nodes={node.children} ctx={ctx} />}\n </div>\n )}\n </div>\n );\n}\n\ntype FlyoutSide = \"right\" | \"left\" | \"below\";\n\n/**\n * Where a submenu opens: right when it fits, else left, else just under its row (a narrow panel).\n * \"Fits\" is measured against the nearest `[data-menu-bounds]` box (a panel that clips), else the window.\n */\nfunction flyoutSide(row: HTMLElement, width: number): FlyoutSide {\n const r = row.getBoundingClientRect();\n const bounds = row.closest<HTMLElement>(\"[data-menu-bounds]\")?.getBoundingClientRect() ?? { left: 0, right: window.innerWidth };\n if (r.right + width + 8 <= bounds.right) return \"right\";\n if (r.left - width - 8 >= bounds.left) return \"left\";\n return \"below\";\n}\n\n/** A placeholder: a dashed row naming where the rest go; as a submenu it opens onto them. */\nfunction Slot({ node, ctx }: { node: MenuSlotNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const source = slotSource(node.fills);\n const options = slotOptions(node.fills, ctx.placed);\n const [open, setOpen] = useState(false);\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n const count = source?.runtime ? \"live\" : String(options.length);\n const row = (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup={node.shape === \"submenu\" ? \"menu\" : undefined}\n title={source ? `Placeholder: ${source.label}` : \"Placeholder\"}\n className={`cm-item cm-slot ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n if (node.shape === \"submenu\") setOpen(true);\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\">{ctx.renderIcon(node.icon ?? source?.icon ?? \"Ellipsis\", \"cm-icon\")}</span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n </span>\n <span className=\"cm-count\">{count}</span>\n {node.shape === \"submenu\" && ctx.renderIcon(\"ChevronRight\", \"cm-icon cm-chev\")}\n </button>\n );\n if (node.shape === \"items\") return row;\n return (\n <div\n className=\"cm-sub\"\n onMouseEnter={(e) => {\n setSide(flyoutSide(e.currentTarget, look.width));\n setOpen(true);\n }}\n onMouseLeave={() => setOpen(false)}\n >\n {row}\n {open && (\n <div role=\"menu\" className=\"cm-menu cm-flyout\" data-side={side} data-density={look.density} style={{ width: look.width }}>\n {source?.runtime ? (\n <div className=\"cm-runtime\">Filled at runtime: {source.label}</div>\n ) : options.length === 0 ? (\n <div className=\"cm-empty\">Nothing left — every option of this kind is placed</div>\n ) : (\n options.map((o) => (\n <Item key={o.id} node={{ id: `slot-${node.id}-${o.id}`, kind: \"item\", label: o.label, icon: o.icon, catalogId: o.id, ...(o.shortcut ? { shortcut: o.shortcut } : {}), ...(o.ai ? { ai: true } : {}), ...(o.danger ? { danger: true } : {}) }} ctx={ctx} />\n ))\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["o"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/design/model.ts","../src/design/catalog.ts","../src/design/MenuPreview.tsx"],"sourcesContent":["// @ai-matrx/context-menu — the menu design model, the option catalog, and the menu renderer.\n// The live context menu engine is moving here from matrx-frontend (features/context-menu-v3).\nexport * from \"./design/model\";\nexport * from \"./design/catalog\";\nexport { MenuPreview, type MenuPreviewProps } from \"./design/MenuPreview\";\n","// src/design/model.ts — @ai-matrx/context-menu: THE MENU DESIGN.\n//\n// A design is the whole menu a person drew in the builder: an ordered tree of items, sections,\n// submenus and dividers, plus the few presentation choices that change how it reads. It is plain\n// JSON (no functions, no React) so it saves as one record, travels in a URL or a chat, and is the\n// exact thing the real menu is later built from. Every edit is a pure function returning a new\n// design; nothing here mutates.\n\nexport type MenuNodeKind = \"item\" | \"section\" | \"submenu\" | \"divider\" | \"slot\" | \"search\";\n\n/**\n * A row's colour, from the design system's tokens: the role inks (primary … destructive) and the\n * named hues (the chip palette). Light and dark come with the tokens.\n */\nexport const MENU_TONES = [\n \"default\",\n \"primary\",\n \"success\",\n \"warning\",\n \"info\",\n \"destructive\",\n \"sky\",\n \"blue\",\n \"indigo\",\n \"violet\",\n \"fuchsia\",\n \"rose\",\n \"orange\",\n \"amber\",\n \"lime\",\n \"emerald\",\n \"teal\",\n \"cyan\",\n \"slate\",\n] as const;\nexport type MenuTone = (typeof MENU_TONES)[number];\n\n/**\n * What the live menu does with an entry it cannot offer right now (no editable text, not an admin…):\n * - disable: shown greyed out;\n * - hide: left out;\n * - required: never unavailable — the host must always provide it.\n */\nexport const UNAVAILABLE_MODES = [\"disable\", \"hide\", \"required\"] as const;\nexport type UnavailableMode = (typeof UNAVAILABLE_MODES)[number];\n\ninterface NodeBase {\n /** Stable within the design. */\n id: string;\n /** The catalog option this was dragged from, when it came from one. */\n catalogId?: string;\n /** A designer's note on this one entry (\"only on a table row\", \"merge with Copy\"). */\n note?: string;\n /** Extra words the menu's search matches (besides the label and hint). */\n keywords?: string[];\n /** What happens when the entry is unavailable. Absent = disable. */\n unavailable?: UnavailableMode;\n /** When it is unavailable, in words (\"no editable text\", \"not an org admin\"). */\n unavailableWhen?: string;\n}\n\nexport interface MenuItemNode extends NodeBase {\n kind: \"item\";\n label: string;\n /** A lucide icon name (`Sparkles`, `Copy`). */\n icon?: string;\n /** Shown right-aligned (`⌘C`). */\n shortcut?: string;\n /** One short line under the label. */\n hint?: string;\n /** Shown greyed out — the design says \"this exists here but is unavailable now\". */\n disabled?: boolean;\n /** Red, for actions that remove or discard. */\n danger?: boolean;\n /** A checkbox-style toggle item. */\n toggle?: boolean;\n /** A setting the person flips right from the menu, drawn as a switch. */\n switch?: boolean;\n /** A checkbox or switch starts on. */\n defaultOn?: boolean;\n /** Drawn as a highlighted, AI-flavoured item. */\n ai?: boolean;\n /** The row's colour (icon; the label too with `toneLabel`). */\n tone?: MenuTone;\n toneLabel?: boolean;\n}\n\nexport interface MenuSectionNode extends NodeBase {\n kind: \"section\";\n /** The small heading. Empty = an unlabelled group. */\n label: string;\n children: MenuNode[];\n /** Starts folded; a click on the heading opens it. */\n collapsible?: boolean;\n /** How the section's items are laid out. */\n layout?: \"list\" | \"grid\" | \"row\";\n}\n\nexport interface MenuSubmenuNode extends NodeBase {\n kind: \"submenu\";\n label: string;\n icon?: string;\n hint?: string;\n tone?: MenuTone;\n toneLabel?: boolean;\n children: MenuNode[];\n}\n\n/** THE MENU'S SEARCH BOX: filters every option of the menu (labels, hints, keywords) as you type. */\nexport interface MenuSearchNode extends NodeBase {\n kind: \"search\";\n placeholder: string;\n /** Takes the keyboard when the menu opens. */\n autofocus: boolean;\n}\n\nexport interface MenuDividerNode extends NodeBase {\n kind: \"divider\";\n}\n\n/**\n * A PLACEHOLDER: \"every other option of this kind goes here\". `shape: \"items\"` lays them out as rows\n * where the placeholder sits; `shape: \"submenu\"` gathers them into one submenu. `fills` names the\n * kind (a catalog group, the agent library, the page's own rows, or everything not placed).\n */\nexport interface MenuSlotNode extends NodeBase {\n kind: \"slot\";\n label: string;\n fills: string;\n /**\n * items: rows where it sits · submenu: one submenu · feature: THE FEATURE SECTION — a section header\n * (the label), the first `featureItems` options as rows, the rest in a nested \"More\" submenu.\n */\n shape: \"items\" | \"submenu\" | \"feature\";\n icon?: string;\n /** feature shape: how many options show before \"More\". Default 4. */\n featureItems?: number;\n}\n\nexport type MenuNode = MenuItemNode | MenuSectionNode | MenuSubmenuNode | MenuDividerNode | MenuSlotNode | MenuSearchNode;\nexport type MenuContainerNode = MenuSectionNode | MenuSubmenuNode;\n\n/** Where the menu opens; the builder previews each the way it appears there. */\nexport const MENU_SURFACES = [\n \"text-selection\",\n \"editable-field\",\n \"table-row\",\n \"page\",\n \"chat-message\",\n \"file\",\n \"anywhere\",\n] as const;\nexport type MenuSurface = (typeof MENU_SURFACES)[number];\n\nexport interface MenuLook {\n density: \"compact\" | \"comfortable\";\n width: number;\n showIcons: boolean;\n showShortcuts: boolean;\n showHints: boolean;\n /** A search box at the top of the menu. */\n search: boolean;\n}\n\nexport const DEFAULT_LOOK: MenuLook = {\n density: \"comfortable\",\n width: 280,\n showIcons: true,\n showShortcuts: true,\n showHints: false,\n search: false,\n};\n\nexport interface MenuDesign {\n /** The design's identity; every version shares it. */\n designId: string;\n name: string;\n surface: MenuSurface;\n look: MenuLook;\n nodes: MenuNode[];\n /** Free notes for whoever builds it. */\n notes: string;\n}\n\nexport const DESIGN_FORMAT = 1;\n\n// ── ids ──────────────────────────────────────────────────────────────────────\n\nexport function newId(prefix = \"n\"): string {\n const rnd =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID().slice(0, 8)\n : Math.random().toString(36).slice(2, 10);\n return `${prefix}_${rnd}`;\n}\n\nexport function emptyDesign(name = \"Untitled menu\"): MenuDesign {\n return { designId: newId(\"d\"), name, surface: \"anywhere\", look: { ...DEFAULT_LOOK }, nodes: [], notes: \"\" };\n}\n\nexport function isContainer(node: MenuNode): node is MenuContainerNode {\n return node.kind === \"section\" || node.kind === \"submenu\";\n}\n\n/** Every catalog option the design already places (so a placeholder holds only the rest). */\nexport function placedCatalogIds(nodes: readonly MenuNode[], out = new Set<string>()): Set<string> {\n for (const n of nodes) {\n if (n.catalogId) out.add(n.catalogId);\n if (isContainer(n)) placedCatalogIds(n.children, out);\n }\n return out;\n}\n\n/** How many times each catalog option appears in the design (a duplicate counts twice). */\nexport function catalogUseCounts(nodes: readonly MenuNode[], out = new Map<string, number>()): Map<string, number> {\n for (const n of nodes) {\n if (n.catalogId) out.set(n.catalogId, (out.get(n.catalogId) ?? 0) + 1);\n if (isContainer(n)) catalogUseCounts(n.children, out);\n }\n return out;\n}\n\n/** A deep copy with every id renewed — what a duplicate or a second drop of a template gets. */\nexport function cloneNode<N extends MenuNode>(node: N): N {\n const copy = { ...node, id: newId(node.kind[0]) } as N;\n if (isContainer(copy)) (copy as MenuContainerNode).children = (copy as MenuContainerNode).children.map(cloneNode);\n return copy;\n}\n\n// ── reading the tree ─────────────────────────────────────────────────────────\n\nexport interface Located {\n node: MenuNode;\n /** The container's id, or null at the top. */\n parentId: string | null;\n index: number;\n depth: number;\n}\n\nexport function locate(nodes: readonly MenuNode[], id: string, parentId: string | null = null, depth = 0): Located | null {\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i] as MenuNode;\n if (node.id === id) return { node, parentId, index: i, depth };\n if (isContainer(node)) {\n const inner = locate(node.children, id, node.id, depth + 1);\n if (inner) return inner;\n }\n }\n return null;\n}\n\nexport function contains(node: MenuNode, id: string): boolean {\n if (node.id === id) return true;\n return isContainer(node) && node.children.some((c) => contains(c, id));\n}\n\nexport function countItems(nodes: readonly MenuNode[]): number {\n let n = 0;\n for (const node of nodes) {\n if (node.kind === \"item\" || node.kind === \"slot\") n += 1;\n else if (isContainer(node)) n += countItems(node.children) + (node.kind === \"submenu\" ? 1 : 0);\n }\n return n;\n}\n\n// ── editing the tree (pure) ──────────────────────────────────────────────────\n\nfunction mapChildren(nodes: readonly MenuNode[], parentId: string | null, fn: (list: MenuNode[]) => MenuNode[]): MenuNode[] {\n if (parentId === null) return fn([...nodes]);\n return nodes.map((node) => {\n if (!isContainer(node)) return node;\n if (node.id === parentId) return { ...node, children: fn([...node.children]) };\n return { ...node, children: mapChildren(node.children, parentId, fn) };\n });\n}\n\nexport function insertNode(nodes: readonly MenuNode[], parentId: string | null, index: number, node: MenuNode): MenuNode[] {\n return mapChildren(nodes, parentId, (list) => {\n list.splice(Math.max(0, Math.min(index, list.length)), 0, node);\n return list;\n });\n}\n\nexport function removeNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n return nodes\n .filter((n) => n.id !== id)\n .map((n) => (isContainer(n) ? { ...n, children: removeNode(n.children, id) } : n));\n}\n\nexport function updateNode(nodes: readonly MenuNode[], id: string, patch: Partial<MenuNode>): MenuNode[] {\n return nodes.map((n) => {\n if (n.id === id) return { ...n, ...patch, id: n.id, kind: n.kind } as MenuNode;\n if (isContainer(n)) return { ...n, children: updateNode(n.children, id, patch) };\n return n;\n });\n}\n\n/**\n * Move `id` to `index` inside `parentId`. Refuses (returns the tree unchanged) a move into itself\n * or its own descendant. `index` is in the destination list as it reads BEFORE the move.\n */\nexport function canMove(nodes: readonly MenuNode[], id: string, parentId: string | null): boolean {\n const from = locate(nodes, id);\n return Boolean(from) && (parentId === null || !contains((from as Located).node, parentId));\n}\n\nexport function moveNode(nodes: readonly MenuNode[], id: string, parentId: string | null, index: number): MenuNode[] {\n const from = locate(nodes, id);\n // A refused move answers the SAME array, so a caller can tell \"nothing happened\" by identity.\n if (!from) return nodes as MenuNode[];\n if (parentId !== null && contains(from.node, parentId)) return nodes as MenuNode[];\n let target = index;\n if (from.parentId === parentId && from.index < index) target -= 1;\n return insertNode(removeNode(nodes, id), parentId, target, from.node);\n}\n\nexport function duplicateNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n const at = locate(nodes, id);\n if (!at) return [...nodes];\n return insertNode(nodes, at.parentId, at.index + 1, cloneNode(at.node));\n}\n\n/** Wrap a node into a new section (or submenu) in its place. */\nexport function wrapNode(nodes: readonly MenuNode[], id: string, kind: \"section\" | \"submenu\"): MenuNode[] {\n const at = locate(nodes, id);\n if (!at) return [...nodes];\n const wrapper: MenuContainerNode =\n kind === \"section\"\n ? { id: newId(\"s\"), kind: \"section\", label: \"New section\", children: [at.node] }\n : { id: newId(\"m\"), kind: \"submenu\", label: \"More\", icon: \"ChevronRight\", children: [at.node] };\n return insertNode(removeNode(nodes, id), at.parentId, at.index, wrapper);\n}\n\n/** Replace a container by its children. */\nexport function unwrapNode(nodes: readonly MenuNode[], id: string): MenuNode[] {\n const at = locate(nodes, id);\n if (!at || !isContainer(at.node)) return [...nodes];\n let out = removeNode(nodes, id);\n at.node.children.forEach((child, i) => {\n out = insertNode(out, at.parentId, at.index + i, child);\n });\n return out;\n}\n\n// ── reading a saved design defensively ──────────────────────────────────────\n\n/** A saved document back into a design; anything unreadable becomes an empty design, never a throw. */\nexport function parseDesign(raw: unknown): MenuDesign {\n let value: unknown = raw;\n if (typeof raw === \"string\") {\n try {\n value = JSON.parse(raw);\n } catch {\n return emptyDesign(\"Unreadable design\");\n }\n }\n const v = (value ?? {}) as Partial<MenuDesign> & { design?: MenuDesign };\n const d = v.design ?? v;\n return {\n designId: typeof d.designId === \"string\" ? d.designId : newId(\"d\"),\n name: typeof d.name === \"string\" ? d.name : \"Untitled menu\",\n surface: MENU_SURFACES.includes(d.surface as MenuSurface) ? (d.surface as MenuSurface) : \"anywhere\",\n look: { ...DEFAULT_LOOK, ...(d.look ?? {}) },\n nodes: Array.isArray(d.nodes) ? (d.nodes as MenuNode[]) : [],\n notes: typeof d.notes === \"string\" ? d.notes : \"\",\n };\n}\n\nexport function serializeDesign(design: MenuDesign): string {\n return JSON.stringify({ format: DESIGN_FORMAT, design });\n}\n","// src/design/catalog.ts — @ai-matrx/context-menu: EVERY OPTION A MENU CAN OFFER, as a palette.\n//\n// The builder's left column. Each entry is something the live menu shows somewhere today, taken\n// from the real menu's own lists in matrx-frontend (features/context-menu-v3):\n// - regroup/engine-rows.ts → the engine rows (`cm:*`)\n// - regroup/proposed-grouping.ts → the 13 \"grouped by what you get\" groups and their rules\n// - proposed/proposed-arrangement.ts → the three icon strips and the object-first submenus\n// - the page rows the demos show (notes, quiz row, table row, chat message)\n// Ids are the live menu's ids wherever one exists, so a saved design names the real row.\n// When the menu source moves into this package, this list is generated from it instead.\n\nimport type { MenuNode } from \"./model\";\n\nexport type CatalogGroup =\n | \"Clipboard\"\n | \"Edit\"\n | \"AI\"\n | \"Save & export\"\n | \"Share & publish\"\n | \"Organize\"\n | \"History & compare\"\n | \"Listen\"\n | \"Page: notes\"\n | \"Page: record\"\n | \"Page: chat message\"\n | \"Tools & admin\";\n\nexport interface CatalogOption {\n /** The live menu's id where one exists (`cm:copy`), else this catalog's own. */\n id: string;\n label: string;\n icon: string;\n group: CatalogGroup;\n shortcut?: string;\n hint?: string;\n danger?: boolean;\n ai?: boolean;\n /** \"Live\" = drawn by today's menu; \"Proposed\" = only in a proposal page so far. */\n status: \"live\" | \"proposed\";\n}\n\nconst o = (\n id: string,\n label: string,\n icon: string,\n group: CatalogGroup,\n extra: Partial<Omit<CatalogOption, \"id\" | \"label\" | \"icon\" | \"group\">> = {},\n): CatalogOption => ({ id, label, icon, group, status: \"live\", ...extra });\n\nexport const CATALOG: readonly CatalogOption[] = [\n // Clipboard — the verb strip\n o(\"cm:copy\", \"Copy\", \"Copy\", \"Clipboard\", { shortcut: \"⌘C\" }),\n o(\"cm:cut\", \"Cut\", \"Scissors\", \"Clipboard\", { shortcut: \"⌘X\" }),\n o(\"cm:paste\", \"Paste\", \"ClipboardPaste\", \"Clipboard\", { shortcut: \"⌘V\" }),\n o(\"cm:undo\", \"Undo\", \"Undo2\", \"Clipboard\", { shortcut: \"⌘Z\" }),\n o(\"cm:redo\", \"Redo\", \"Redo2\", \"Clipboard\", { shortcut: \"⇧⌘Z\" }),\n o(\"cm:find\", \"Find & Replace\", \"Search\", \"Clipboard\", { shortcut: \"⌘F\" }),\n o(\"cm:select-all\", \"Select All\", \"TextSelect\", \"Clipboard\", { shortcut: \"⌘A\" }),\n o(\"cm:copy-as\", \"Copy as…\", \"CopyPlus\", \"Clipboard\"),\n o(\"cm:json\", \"Copy as JSON\", \"Braces\", \"Clipboard\"),\n o(\"copy-html-page\", \"Copy as HTML page\", \"FileCode\", \"Clipboard\"),\n o(\"cm:insert-reference\", \"Insert / Copy reference…\", \"AtSign\", \"Clipboard\"),\n\n // Edit\n o(\"cm:save\", \"Save\", \"Save\", \"Edit\", { shortcut: \"⌘S\" }),\n o(\"duplicate\", \"Duplicate\", \"CopyPlus\", \"Edit\"),\n o(\"rename\", \"Rename\", \"PenLine\", \"Edit\"),\n o(\"edit\", \"Edit\", \"Pencil\", \"Edit\"),\n o(\"favorite\", \"Add to favorites\", \"Star\", \"Edit\"),\n o(\"archive\", \"Archive\", \"Archive\", \"Edit\", { danger: true }),\n o(\"cm:delete\", \"Delete\", \"Trash2\", \"Edit\", { danger: true }),\n\n // AI\n o(\"cm:chat\", \"Chat about this\", \"MessageSquare\", \"AI\", { ai: true }),\n o(\"cm:quick-actions\", \"Quick Actions\", \"Zap\", \"AI\", { ai: true }),\n o(\"cm:placement:ai-action\", \"AI Actions\", \"Sparkles\", \"AI\", { ai: true }),\n o(\"cm:placement:content-block\", \"Content blocks\", \"Blocks\", \"AI\", { ai: true }),\n o(\"cm:placement:organization-tool\", \"Org Items\", \"Building2\", \"AI\", { ai: true }),\n o(\"cm:placement:user-tool\", \"My Items\", \"User\", \"AI\", { ai: true }),\n o(\"cm:placement:quick-action\", \"Quick actions (placement)\", \"Zap\", \"AI\", { ai: true }),\n o(\"cm:placement:bound-agent\", \"Agents\", \"Bot\", \"AI\", { ai: true }),\n o(\"send-to-agent\", \"Send to agent…\", \"Send\", \"AI\", { ai: true }),\n o(\"continue-in-chat\", \"Continue in chat\", \"MessagesSquare\", \"AI\", { ai: true }),\n o(\"regenerate-response\", \"Regenerate\", \"RefreshCw\", \"AI\", { ai: true }),\n o(\"code-block-chart\", \"Make a chart\", \"ChartColumn\", \"AI\", { ai: true }),\n o(\"ai-improve\", \"Improve writing\", \"Wand2\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-summarize\", \"Summarize\", \"ListCollapse\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-explain\", \"Explain\", \"Lightbulb\", \"AI\", { ai: true, status: \"proposed\" }),\n o(\"ai-translate\", \"Translate…\", \"Languages\", \"AI\", { ai: true, status: \"proposed\" }),\n\n // Save & export\n o(\"cm:export\", \"Export\", \"FileOutput\", \"Save & export\"),\n o(\"cm:convert\", \"Convert to…\", \"ArrowRightLeft\", \"Save & export\"),\n o(\"save-as-file\", \"Save as file\", \"FileDown\", \"Save & export\"),\n o(\"download-pdf\", \"Download PDF\", \"FileText\", \"Save & export\"),\n o(\"download-docx\", \"Download Word\", \"FileType\", \"Save & export\"),\n o(\"download-html\", \"Download HTML\", \"FileCode2\", \"Save & export\"),\n o(\"print\", \"Print\", \"Printer\", \"Save & export\", { shortcut: \"⌘P\" }),\n\n // Share & publish\n o(\"cm:share\", \"Share…\", \"Share2\", \"Share & publish\"),\n o(\"share-link\", \"Copy share link\", \"Link\", \"Share & publish\"),\n o(\"send-google-doc\", \"Send to Google Docs\", \"FileUp\", \"Share & publish\"),\n o(\"email-to-me\", \"Email to me\", \"Mail\", \"Share & publish\"),\n o(\"html-preview\", \"Preview as web page\", \"Eye\", \"Share & publish\"),\n o(\"share-webpage\", \"Publish as web page\", \"Globe\", \"Share & publish\"),\n\n // Organize\n o(\"cm:attach\", \"Attach to…\", \"Paperclip\", \"Organize\"),\n o(\"set-context-value\", \"Set as context\", \"Pin\", \"Organize\"),\n o(\"pin-message\", \"Pin\", \"Pin\", \"Organize\"),\n o(\"notes-and-comments\", \"Notes & comments\", \"StickyNote\", \"Organize\"),\n o(\"move\", \"Move to folder…\", \"FolderInput\", \"Organize\"),\n o(\"tags\", \"Tags…\", \"Tags\", \"Organize\"),\n\n // History & compare\n o(\"cm:view-history\", \"View history\", \"History\", \"History & compare\"),\n o(\"edit-history\", \"Edit history\", \"GitCommitVertical\", \"History & compare\"),\n o(\"fork-at-message\", \"Fork from here\", \"GitBranch\", \"History & compare\"),\n o(\"cm:compare\", \"Compare…\", \"GitCompareArrows\", \"History & compare\"),\n o(\"compare-with-clipboard\", \"Compare with clipboard\", \"ClipboardList\", \"History & compare\"),\n o(\"set-compare-base\", \"Set as compare base\", \"Flag\", \"History & compare\"),\n\n // Listen\n o(\"cm:speak\", \"Read aloud\", \"Volume2\", \"Listen\"),\n o(\"cm:listen\", \"Dictate\", \"Mic\", \"Listen\"),\n o(\"tts-voice-settings\", \"Voice settings\", \"AudioLines\", \"Listen\"),\n\n // Page rows: notes\n o(\"notes:close-tab\", \"Close tab\", \"X\", \"Page: notes\"),\n o(\"notes:close-others\", \"Close other tabs\", \"PanelTopClose\", \"Page: notes\"),\n o(\"notes:export-md\", \"Export as Markdown\", \"FileDown\", \"Page: notes\"),\n o(\"notes:share-clipboard\", \"Copy to clipboard\", \"ClipboardCopy\", \"Page: notes\"),\n o(\"notes:convert-artifacts\", \"Convert to artifacts\", \"Shapes\", \"Page: notes\"),\n o(\"notes:trash\", \"Move to Trash\", \"Trash2\", \"Page: notes\", { danger: true }),\n\n // Page rows: a record (quiz row, table row)\n o(\"row:open\", \"Open\", \"SquareArrowOutUpRight\", \"Page: record\"),\n o(\"row:open-tab\", \"Open in new tab\", \"ExternalLink\", \"Page: record\"),\n o(\"row:take\", \"Take\", \"Play\", \"Page: record\"),\n o(\"row:results\", \"Results\", \"ChartBar\", \"Page: record\"),\n o(\"row:manage\", \"Manage\", \"Settings2\", \"Page: record\"),\n o(\"row:restore\", \"Restore\", \"ArchiveRestore\", \"Page: record\"),\n\n // Page rows: chat message\n o(\"regenerate-latest\", \"Regenerate latest\", \"RotateCcw\", \"Page: chat message\", { ai: true }),\n o(\"fork-and-regenerate\", \"Fork and regenerate\", \"GitFork\", \"Page: chat message\", { ai: true }),\n o(\"feedback-up\", \"Good response\", \"ThumbsUp\", \"Page: chat message\"),\n o(\"feedback-down\", \"Bad response\", \"ThumbsDown\", \"Page: chat message\"),\n\n // Tools & admin\n o(\"cm:x:surface\", \"This page (location, context, agents)\", \"MapPin\", \"Tools & admin\"),\n o(\"cm:admin\", \"Admin tools\", \"Shield\", \"Tools & admin\"),\n o(\"feedback\", \"Send feedback\", \"MessageSquareWarning\", \"Tools & admin\"),\n o(\"keyboard-shortcuts\", \"Keyboard shortcuts\", \"Keyboard\", \"Tools & admin\", { status: \"proposed\" }),\n];\n\nexport const CATALOG_GROUPS: readonly CatalogGroup[] = [...new Set(CATALOG.map((c) => c.group))];\n\nexport function catalogOption(id: string): CatalogOption | undefined {\n return CATALOG.find((c) => c.id === id);\n}\n\n/** Ready-made pieces: dropping one inserts the whole block. */\nexport interface CatalogTemplate {\n id: string;\n label: string;\n icon: string;\n build: () => MenuNode;\n}\n\nlet seq = 0;\nconst tid = (p: string) => `${p}_t${Date.now().toString(36)}${(seq++).toString(36)}`;\n\nfunction itemFrom(id: string): MenuNode {\n const c = catalogOption(id);\n return {\n id: tid(\"i\"),\n kind: \"item\",\n catalogId: id,\n label: c?.label ?? id,\n icon: c?.icon ?? \"Circle\",\n ...(c?.shortcut ? { shortcut: c.shortcut } : {}),\n ...(c?.danger ? { danger: true } : {}),\n ...(c?.ai ? { ai: true } : {}),\n };\n}\n\nconst strip = (label: string, ids: string[]): MenuNode => ({\n id: tid(\"s\"),\n kind: \"section\",\n label,\n layout: \"row\",\n children: ids.map(itemFrom),\n});\n\nconst sub = (label: string, icon: string, ids: string[]): MenuNode => ({\n id: tid(\"m\"),\n kind: \"submenu\",\n label,\n icon,\n children: ids.map(itemFrom),\n});\n\nexport const TEMPLATES: readonly CatalogTemplate[] = [\n { id: \"strip-thing\", label: \"Icon strip — a thing\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:copy\", \"cm:share\", \"duplicate\", \"favorite\", \"save-as-file\", \"archive\"]) },\n { id: \"strip-edit\", label: \"Icon strip — editable text\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:cut\", \"cm:copy\", \"cm:paste\", \"cm:undo\", \"cm:redo\", \"cm:find\"]) },\n { id: \"strip-read\", label: \"Icon strip — read-only text\", icon: \"Rows2\", build: () => strip(\"\", [\"cm:copy\", \"cm:speak\", \"cm:find\", \"cm:share\"]) },\n { id: \"sub-intelligence\", label: \"Intelligence ▸\", icon: \"Sparkles\", build: () => sub(\"Intelligence\", \"Sparkles\", [\"cm:chat\", \"cm:placement:ai-action\", \"cm:placement:bound-agent\", \"send-to-agent\"]) },\n { id: \"sub-save-share\", label: \"Save & share ▸\", icon: \"Share2\", build: () => sub(\"Save & share\", \"Share2\", [\"cm:copy-as\", \"save-as-file\", \"cm:convert\", \"share-webpage\", \"cm:share\"]) },\n { id: \"sub-organize\", label: \"Organize ▸\", icon: \"Tags\", build: () => sub(\"Organize\", \"Tags\", [\"cm:attach\", \"pin-message\", \"cm:view-history\", \"cm:compare\"]) },\n { id: \"sub-tools\", label: \"Tools ▸\", icon: \"Wrench\", build: () => sub(\"Tools\", \"Wrench\", [\"cm:speak\", \"cm:quick-actions\", \"feedback\", \"cm:x:surface\", \"cm:admin\"]) },\n];\n\n// ── placeholders ─────────────────────────────────────────────────────────────\n\n/** What a placeholder can hold. A catalog group holds that group's options the design has not placed. */\nexport interface SlotSource {\n id: string;\n label: string;\n /** The default placeholder wording (\"All other AI items\"). */\n phrase: string;\n icon: string;\n /** Filled by the live menu from data (agents, a page's own rows) — the preview cannot list them. */\n runtime?: boolean;\n}\n\nexport const SLOT_SOURCES: readonly SlotSource[] = [\n { id: \"any\", label: \"Everything not placed\", phrase: \"Everything else\", icon: \"Ellipsis\" },\n { id: \"agents\", label: \"Agents & shortcuts (library)\", phrase: \"All other agents\", icon: \"Bot\", runtime: true },\n { id: \"page-rows\", label: \"This page's own rows\", phrase: \"All of this page's actions\", icon: \"PanelTop\", runtime: true },\n ...CATALOG_GROUPS.map((g) => ({\n id: `group:${g}`,\n label: g,\n phrase: g === \"AI\" ? \"All other AI items\" : `All other ${g.toLowerCase()} options`,\n icon: CATALOG.find((c) => c.group === g)?.icon ?? \"Circle\",\n })),\n];\n\nexport function slotSource(id: string): SlotSource | undefined {\n return SLOT_SOURCES.find((s) => s.id === id);\n}\n\n/** The catalog options a placeholder stands for: its kind, minus every option the design already places. */\nexport function slotOptions(fills: string, placed: ReadonlySet<string>): CatalogOption[] {\n if (fills === \"agents\" || fills === \"page-rows\") return [];\n const pool = fills === \"any\" ? CATALOG : CATALOG.filter((c) => `group:${c.group}` === fills);\n return pool.filter((c) => !placed.has(c.id));\n}\n","// src/design/MenuPreview.tsx — @ai-matrx/context-menu: DRAWS A DESIGN AS THE MENU IT DESCRIBES.\n//\n// The same component draws the builder's live preview and the right-click test menu, so what the\n// designer sees is what opens. Icons come from the host (`renderIcon`), so this file has no icon set.\n// This file IS the menu component: its rows are the menu's own rows (hence the ui-exception marks).\n\nimport { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { slotOptions, slotSource } from \"./catalog\";\nimport {\n isContainer,\n placedCatalogIds,\n type MenuDesign,\n type MenuItemNode,\n type MenuNode,\n type MenuSearchNode,\n type MenuSlotNode,\n type MenuSubmenuNode,\n type MenuTone,\n} from \"./model\";\n\n/** Preview what the person sees when some entries are unavailable (each by its own rule). */\nexport type AvailabilityPreview = \"available\" | \"unavailable\";\n\nexport interface MenuPreviewProps {\n design: MenuDesign;\n renderIcon: (name: string, className?: string) => ReactNode;\n /** The entry highlighted as \"selected in the builder\". */\n highlightId?: string | null;\n /** A click on any entry. */\n onSelectNode?: (id: string) => void;\n /** A click on an item (the menu's action). */\n onPick?: (item: MenuItemNode) => void;\n /** \"unavailable\": every entry with an unavailable rule shows as that rule says. Default \"available\". */\n availability?: AvailabilityPreview;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface Ctx {\n design: MenuDesign;\n renderIcon: MenuPreviewProps[\"renderIcon\"];\n highlightId: string | null | undefined;\n onSelectNode: MenuPreviewProps[\"onSelectNode\"];\n onPick: MenuPreviewProps[\"onPick\"];\n /** Catalog options the design places — a placeholder holds the rest. */\n placed: ReadonlySet<string>;\n availability: AvailabilityPreview;\n query: string;\n setQuery: (q: string) => void;\n}\n\n// ── search ───────────────────────────────────────────────────────────────────\n\n/** The words an entry answers to: its label, its hint and its keywords. */\nfunction searchable(node: MenuNode): string {\n if (node.kind === \"divider\" || node.kind === \"search\") return \"\";\n const hint = node.kind === \"item\" || node.kind === \"submenu\" ? node.hint ?? \"\" : \"\";\n return [node.label, hint, ...(node.keywords ?? [])].join(\" \").toLowerCase();\n}\n\nexport interface Hit {\n node: MenuItemNode;\n /** Where it lives (\"Intelligence › AI Actions\"). */\n path: string;\n}\n\n/** While searching: every matching item, wherever it sits, with the submenus it is inside. */\nexport function searchMenu(nodes: readonly MenuNode[], q: string, trail: string[] = [], out: Hit[] = []): Hit[] {\n const words = q.split(/\\s+/).filter(Boolean);\n for (const n of nodes) {\n if (n.kind === \"item\") {\n const text = `${searchable(n)} ${trail.join(\" \").toLowerCase()}`;\n if (words.every((w) => text.includes(w))) out.push({ node: n, path: trail.join(\" › \") });\n } else if (isContainer(n)) {\n searchMenu(n.children, q, n.kind === \"submenu\" ? [...trail, n.label] : n.label ? [...trail, n.label] : trail, out);\n }\n }\n return out;\n}\n\n// ── the menu ─────────────────────────────────────────────────────────────────\n\nexport function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, availability = \"available\", className, style }: MenuPreviewProps) {\n const [query, setQuery] = useState(\"\");\n const q = query.trim().toLowerCase();\n const { look } = design;\n const placed = useMemo(() => placedCatalogIds(design.nodes), [design.nodes]);\n const ctx: Ctx = { design, renderIcon, highlightId, onSelectNode, onPick, placed, availability, query, setQuery };\n const searchAt = design.nodes.findIndex((n) => n.kind === \"search\");\n // The old \"search box at the top\" look switch still works when the design places no search box.\n const topSearch: MenuSearchNode | null =\n searchAt < 0 && look.search ? { id: \"look-search\", kind: \"search\", placeholder: \"Type to filter…\", autofocus: true } : null;\n const hits = useMemo(() => (q ? searchMenu(design.nodes, q) : null), [design.nodes, q]);\n\n // While searching: what sits above the search box stays (the icon strip), the rest becomes results.\n const above = searchAt >= 0 ? design.nodes.slice(0, searchAt) : [];\n return (\n <div role=\"menu\" data-density={look.density} className={`cm-menu ${className ?? \"\"}`} style={{ width: look.width, ...style }}>\n {topSearch && <SearchBox node={topSearch} ctx={ctx} />}\n {design.nodes.length === 0 && !topSearch ? (\n <div className=\"cm-empty\">Empty menu — drag options in</div>\n ) : hits ? (\n <>\n <Nodes nodes={above} ctx={ctx} />\n {searchAt >= 0 && <SearchBox node={design.nodes[searchAt] as MenuSearchNode} ctx={ctx} />}\n {hits.length === 0 ? (\n <div className=\"cm-empty\">No matches</div>\n ) : (\n hits.map((h) => <Item key={h.node.id} node={h.node} ctx={ctx} path={h.path} />)\n )}\n </>\n ) : (\n <Nodes nodes={design.nodes} ctx={ctx} />\n )}\n </div>\n );\n}\n\nfunction SearchBox({ node, ctx }: { node: MenuSearchNode; ctx: Ctx }) {\n const ref = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (node.autofocus) ref.current?.focus({ preventScroll: true });\n }, [node.autofocus]);\n return (\n <div className={`cm-search ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`} onClick={() => ctx.onSelectNode?.(node.id)}>\n {ctx.renderIcon(\"Search\", \"cm-icon\")}\n {/* ui-exception: the menu's own filter row — this file IS the menu component */}\n <input\n ref={ref}\n value={ctx.query}\n onChange={(e) => ctx.setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Escape\" && ctx.query) {\n e.stopPropagation();\n ctx.setQuery(\"\");\n }\n }}\n placeholder={node.placeholder || \"Type to filter…\"}\n aria-label=\"Filter menu\"\n />\n </div>\n );\n}\n\n/** Whether an entry shows, and whether it is greyed, under the availability being previewed. */\nfunction shown(node: MenuNode, ctx: Ctx): { hidden: boolean; greyed: boolean } {\n if (ctx.availability === \"available\" || !node.unavailableWhen) {\n return { hidden: false, greyed: node.kind === \"item\" && Boolean(node.disabled) };\n }\n const mode = node.unavailable ?? \"disable\";\n if (mode === \"hide\") return { hidden: true, greyed: false };\n if (mode === \"required\") return { hidden: false, greyed: false };\n return { hidden: false, greyed: true };\n}\n\nfunction Nodes({ nodes, ctx }: { nodes: readonly MenuNode[]; ctx: Ctx }) {\n return (\n <>\n {nodes.map((n) => {\n if (shown(n, ctx).hidden) return null;\n if (n.kind === \"divider\") return <div key={n.id} role=\"separator\" className=\"cm-divider\" />;\n if (n.kind === \"item\") return <Item key={n.id} node={n} ctx={ctx} />;\n if (n.kind === \"submenu\") return <Submenu key={n.id} node={n} ctx={ctx} />;\n if (n.kind === \"slot\") return n.shape === \"feature\" ? <FeatureSlot key={n.id} node={n} ctx={ctx} /> : <Slot key={n.id} node={n} ctx={ctx} />;\n if (n.kind === \"search\") return <SearchBox key={n.id} node={n} ctx={ctx} />;\n return <Section key={n.id} node={n} ctx={ctx} />;\n })}\n </>\n );\n}\n\nfunction toneAttrs(tone: MenuTone | undefined, toneLabel: boolean | undefined) {\n return tone && tone !== \"default\" ? { \"data-tone\": tone, ...(toneLabel ? { \"data-tone-label\": \"\" } : {}) } : {};\n}\n\nfunction Section({ node, ctx }: { node: Extract<MenuNode, { kind: \"section\" }>; ctx: Ctx }) {\n const [open, setOpen] = useState(!node.collapsible);\n const layout = node.layout ?? \"list\";\n return (\n <div className={`cm-section ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`} data-layout={layout}>\n {node.label && (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n className=\"cm-section-label\"\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n if (node.collapsible) setOpen((o) => !o);\n }}\n >\n {node.label}\n {node.collapsible && <span className=\"cm-caret\">{open ? \"▾\" : \"▸\"}</span>}\n </button>\n )}\n {open && (\n <div className=\"cm-section-body\">\n {layout === \"list\" ? (\n <Nodes nodes={node.children} ctx={ctx} />\n ) : (\n node.children.map((c) =>\n shown(c, ctx).hidden ? null : c.kind === \"item\" ? <Tile key={c.id} node={c} ctx={ctx} /> : <Nodes key={c.id} nodes={[c]} ctx={ctx} />,\n )\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction Tile({ node, ctx }: { node: MenuItemNode; ctx: Ctx }) {\n const { greyed } = shown(node, ctx);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role=\"menuitem\"\n title={node.label + (node.shortcut ? ` ${node.shortcut}` : \"\")}\n disabled={greyed}\n {...toneAttrs(node.tone, node.toneLabel)}\n className={`cm-tile ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n ctx.onPick?.(node);\n }}\n >\n {ctx.renderIcon(node.icon ?? \"Circle\", \"cm-icon\")}\n </button>\n );\n}\n\nfunction Item({ node, ctx, path }: { node: MenuItemNode; ctx: Ctx; path?: string }) {\n const { look } = ctx.design;\n const [checked, setChecked] = useState(Boolean(node.defaultOn));\n // A changed default shows at once (the designer flips \"On by default\" while looking at the row).\n useEffect(() => setChecked(Boolean(node.defaultOn)), [node.defaultOn]);\n const { greyed } = shown(node, ctx);\n const settable = node.toggle || node.switch;\n const hint = path || (look.showHints ? node.hint : undefined);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role={settable ? \"menuitemcheckbox\" : \"menuitem\"}\n aria-checked={settable ? checked : undefined}\n disabled={greyed}\n {...toneAttrs(node.tone, node.toneLabel)}\n className={`cm-item ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n if (settable) setChecked((c) => !c);\n ctx.onPick?.(node);\n }}\n >\n {look.showIcons && (\n <span className=\"cm-icon-slot\">\n {node.toggle ? (checked ? ctx.renderIcon(\"Check\", \"cm-icon\") : null) : node.icon ? ctx.renderIcon(node.icon, \"cm-icon\") : null}\n </span>\n )}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {hint && <span className=\"cm-hint\">{hint}</span>}\n </span>\n {look.showShortcuts && node.shortcut && !node.switch && <kbd className=\"cm-shortcut\">{node.shortcut}</kbd>}\n {node.switch && <span className=\"cm-switch\" data-on={checked ? \"\" : undefined} aria-hidden=\"true\" />}\n </button>\n );\n}\n\nfunction Submenu({ node, ctx }: { node: MenuSubmenuNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const [open, setOpen] = useState(false);\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n const { greyed } = shown(node, ctx);\n return (\n <div\n className=\"cm-sub\"\n onMouseEnter={(e) => {\n if (greyed) return;\n setSide(flyoutSide(e.currentTarget, look.width));\n setOpen(true);\n }}\n onMouseLeave={() => setOpen(false)}\n >\n {/* ui-exception: a menu row of the menu component itself */}\n <button\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n disabled={greyed}\n {...toneAttrs(node.tone, node.toneLabel)}\n className={`cm-item ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n setOpen(true);\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\">{node.icon ? ctx.renderIcon(node.icon, \"cm-icon\") : null}</span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {look.showHints && node.hint && <span className=\"cm-hint\">{node.hint}</span>}\n </span>\n {ctx.renderIcon(\"ChevronRight\", \"cm-icon cm-chev\")}\n </button>\n {open && (\n <div role=\"menu\" className=\"cm-menu cm-flyout\" data-side={side} data-density={look.density} style={{ width: look.width }}>\n {node.children.length === 0 ? <div className=\"cm-empty\">Empty submenu</div> : <Nodes nodes={node.children} ctx={ctx} />}\n </div>\n )}\n </div>\n );\n}\n\ntype FlyoutSide = \"right\" | \"left\" | \"below\";\n\n/**\n * Where a submenu opens: right when it fits, else left, else just under its row (a narrow panel).\n * \"Fits\" is measured against the nearest `[data-menu-bounds]` box (a panel that clips), else the window.\n */\nfunction flyoutSide(row: HTMLElement, width: number): FlyoutSide {\n const r = row.getBoundingClientRect();\n const bounds = row.closest<HTMLElement>(\"[data-menu-bounds]\")?.getBoundingClientRect() ?? { left: 0, right: window.innerWidth };\n if (r.right + width + 8 <= bounds.right) return \"right\";\n if (r.left - width - 8 >= bounds.left) return \"left\";\n return \"below\";\n}\n\n/** A dashed placeholder row (never a real option). */\nfunction SlotRow({ node, ctx, label, icon, count, more, onOpen }: { node: MenuSlotNode; ctx: Ctx; label: string; icon: string; count?: string; more?: boolean; onOpen?: () => void }) {\n const { look } = ctx.design;\n const source = slotSource(node.fills);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup={more ? \"menu\" : undefined}\n title={source ? `Placeholder: ${source.label}` : \"Placeholder\"}\n className={`cm-item cm-slot ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n ctx.onSelectNode?.(node.id);\n onOpen?.();\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\">{ctx.renderIcon(icon, \"cm-icon\")}</span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{label}</span>\n </span>\n {count && <span className=\"cm-count\">{count}</span>}\n {more && ctx.renderIcon(\"ChevronRight\", \"cm-icon cm-chev\")}\n </button>\n );\n}\n\n/** A placeholder: a dashed row naming where the rest go; as a submenu it opens onto them. */\nfunction Slot({ node, ctx }: { node: MenuSlotNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const source = slotSource(node.fills);\n const options = slotOptions(node.fills, ctx.placed);\n const [open, setOpen] = useState(false);\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n const icon = node.icon ?? source?.icon ?? \"Ellipsis\";\n const count = source?.runtime ? \"live\" : String(options.length);\n if (node.shape === \"items\") return <SlotRow node={node} ctx={ctx} label={node.label} icon={icon} count={count} />;\n return (\n <div\n className=\"cm-sub\"\n onMouseEnter={(e) => {\n setSide(flyoutSide(e.currentTarget, look.width));\n setOpen(true);\n }}\n onMouseLeave={() => setOpen(false)}\n >\n <SlotRow node={node} ctx={ctx} label={node.label} icon={icon} count={count} more onOpen={() => setOpen(true)} />\n {open && (\n <div role=\"menu\" className=\"cm-menu cm-flyout\" data-side={side} data-density={look.density} style={{ width: look.width }}>\n {source?.runtime ? (\n <div className=\"cm-runtime\">Filled at runtime: {source.label}</div>\n ) : options.length === 0 ? (\n <div className=\"cm-empty\">Nothing left — every option of this kind is placed</div>\n ) : (\n options.map((o) => (\n <Item\n key={o.id}\n node={{ id: `slot-${node.id}-${o.id}`, kind: \"item\", label: o.label, icon: o.icon, catalogId: o.id, ...(o.shortcut ? { shortcut: o.shortcut } : {}), ...(o.ai ? { ai: true } : {}), ...(o.danger ? { danger: true } : {}) }}\n ctx={ctx}\n />\n ))\n )}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * THE FEATURE SECTION placeholder: where the place the menu opens on puts its own options — a section\n * header (the placeholder's label), its first N options as rows, the rest in a nested \"More\" submenu.\n */\nfunction FeatureSlot({ node, ctx }: { node: MenuSlotNode; ctx: Ctx }) {\n const { look } = ctx.design;\n const n = Math.max(0, Math.min(12, node.featureItems ?? 4));\n const [open, setOpen] = useState(false);\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n return (\n <div className={`cm-section ${ctx.highlightId === node.id ? \"cm-hl\" : \"\"}`} data-layout=\"list\">\n {/* ui-exception: a menu row of the menu component itself */}\n <button type=\"button\" className=\"cm-section-label cm-slot-label\" onClick={() => ctx.onSelectNode?.(node.id)}>\n {node.label || \"This feature\"}\n </button>\n <div className=\"cm-section-body\">\n {Array.from({ length: n }, (_, i) => (\n <SlotRow key={i} node={node} ctx={ctx} label={`Feature option ${i + 1}`} icon=\"Circle\" />\n ))}\n <div\n className=\"cm-sub\"\n onMouseEnter={(e) => {\n setSide(flyoutSide(e.currentTarget, look.width));\n setOpen(true);\n }}\n onMouseLeave={() => setOpen(false)}\n >\n <SlotRow node={node} ctx={ctx} label=\"More\" icon=\"Ellipsis\" more onOpen={() => setOpen(true)} />\n {open && (\n <div role=\"menu\" className=\"cm-menu cm-flyout\" data-side={side} data-density={look.density} style={{ width: look.width }}>\n <div className=\"cm-runtime\">The rest of this feature's options, filled at runtime</div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["o"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as MenuNode, M as MenuDesign, b as MenuItemNode } from './model-
|
|
2
|
-
export { D as DEFAULT_LOOK, c as DESIGN_FORMAT, L as Located, d as MENU_SURFACES, e as
|
|
1
|
+
import { a as MenuNode, M as MenuDesign, b as MenuItemNode } from './model-C_7QZRE0.cjs';
|
|
2
|
+
export { D as DEFAULT_LOOK, c as DESIGN_FORMAT, L as Located, d as MENU_SURFACES, e as MENU_TONES, f as MenuContainerNode, g as MenuDividerNode, h as MenuLook, i as MenuNodeKind, j as MenuSearchNode, k as MenuSectionNode, l as MenuSlotNode, m as MenuSubmenuNode, n as MenuSurface, o as MenuTone, U as UNAVAILABLE_MODES, p as UnavailableMode, q as canMove, r as catalogUseCounts, s as cloneNode, t as contains, u as countItems, v as duplicateNode, w as emptyDesign, x as insertNode, y as isContainer, z as locate, A as moveNode, B as newId, C as parseDesign, E as placedCatalogIds, F as removeNode, G as serializeDesign, H as unwrapNode, I as updateNode, J as wrapNode } from './model-C_7QZRE0.cjs';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ReactNode, CSSProperties } from 'react';
|
|
5
5
|
|
|
@@ -43,6 +43,8 @@ declare function slotSource(id: string): SlotSource | undefined;
|
|
|
43
43
|
/** The catalog options a placeholder stands for: its kind, minus every option the design already places. */
|
|
44
44
|
declare function slotOptions(fills: string, placed: ReadonlySet<string>): CatalogOption[];
|
|
45
45
|
|
|
46
|
+
/** Preview what the person sees when some entries are unavailable (each by its own rule). */
|
|
47
|
+
type AvailabilityPreview = "available" | "unavailable";
|
|
46
48
|
interface MenuPreviewProps {
|
|
47
49
|
design: MenuDesign;
|
|
48
50
|
renderIcon: (name: string, className?: string) => ReactNode;
|
|
@@ -52,9 +54,11 @@ interface MenuPreviewProps {
|
|
|
52
54
|
onSelectNode?: (id: string) => void;
|
|
53
55
|
/** A click on an item (the menu's action). */
|
|
54
56
|
onPick?: (item: MenuItemNode) => void;
|
|
57
|
+
/** "unavailable": every entry with an unavailable rule shows as that rule says. Default "available". */
|
|
58
|
+
availability?: AvailabilityPreview;
|
|
55
59
|
className?: string;
|
|
56
60
|
style?: CSSProperties;
|
|
57
61
|
}
|
|
58
|
-
declare function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, className, style }: MenuPreviewProps): React.JSX.Element;
|
|
62
|
+
declare function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, availability, className, style }: MenuPreviewProps): React.JSX.Element;
|
|
59
63
|
|
|
60
64
|
export { CATALOG, CATALOG_GROUPS, type CatalogGroup, type CatalogOption, type CatalogTemplate, MenuDesign, MenuItemNode, MenuNode, MenuPreview, type MenuPreviewProps, SLOT_SOURCES, type SlotSource, TEMPLATES, catalogOption, slotOptions, slotSource };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as MenuNode, M as MenuDesign, b as MenuItemNode } from './model-
|
|
2
|
-
export { D as DEFAULT_LOOK, c as DESIGN_FORMAT, L as Located, d as MENU_SURFACES, e as
|
|
1
|
+
import { a as MenuNode, M as MenuDesign, b as MenuItemNode } from './model-C_7QZRE0.js';
|
|
2
|
+
export { D as DEFAULT_LOOK, c as DESIGN_FORMAT, L as Located, d as MENU_SURFACES, e as MENU_TONES, f as MenuContainerNode, g as MenuDividerNode, h as MenuLook, i as MenuNodeKind, j as MenuSearchNode, k as MenuSectionNode, l as MenuSlotNode, m as MenuSubmenuNode, n as MenuSurface, o as MenuTone, U as UNAVAILABLE_MODES, p as UnavailableMode, q as canMove, r as catalogUseCounts, s as cloneNode, t as contains, u as countItems, v as duplicateNode, w as emptyDesign, x as insertNode, y as isContainer, z as locate, A as moveNode, B as newId, C as parseDesign, E as placedCatalogIds, F as removeNode, G as serializeDesign, H as unwrapNode, I as updateNode, J as wrapNode } from './model-C_7QZRE0.js';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ReactNode, CSSProperties } from 'react';
|
|
5
5
|
|
|
@@ -43,6 +43,8 @@ declare function slotSource(id: string): SlotSource | undefined;
|
|
|
43
43
|
/** The catalog options a placeholder stands for: its kind, minus every option the design already places. */
|
|
44
44
|
declare function slotOptions(fills: string, placed: ReadonlySet<string>): CatalogOption[];
|
|
45
45
|
|
|
46
|
+
/** Preview what the person sees when some entries are unavailable (each by its own rule). */
|
|
47
|
+
type AvailabilityPreview = "available" | "unavailable";
|
|
46
48
|
interface MenuPreviewProps {
|
|
47
49
|
design: MenuDesign;
|
|
48
50
|
renderIcon: (name: string, className?: string) => ReactNode;
|
|
@@ -52,9 +54,11 @@ interface MenuPreviewProps {
|
|
|
52
54
|
onSelectNode?: (id: string) => void;
|
|
53
55
|
/** A click on an item (the menu's action). */
|
|
54
56
|
onPick?: (item: MenuItemNode) => void;
|
|
57
|
+
/** "unavailable": every entry with an unavailable rule shows as that rule says. Default "available". */
|
|
58
|
+
availability?: AvailabilityPreview;
|
|
55
59
|
className?: string;
|
|
56
60
|
style?: CSSProperties;
|
|
57
61
|
}
|
|
58
|
-
declare function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, className, style }: MenuPreviewProps): React.JSX.Element;
|
|
62
|
+
declare function MenuPreview({ design, renderIcon, highlightId, onSelectNode, onPick, availability, className, style }: MenuPreviewProps): React.JSX.Element;
|
|
59
63
|
|
|
60
64
|
export { CATALOG, CATALOG_GROUPS, type CatalogGroup, type CatalogOption, type CatalogTemplate, MenuDesign, MenuItemNode, MenuNode, MenuPreview, type MenuPreviewProps, SLOT_SOURCES, type SlotSource, TEMPLATES, catalogOption, slotOptions, slotSource };
|