From 3de098fe4f3c4fadfdd616ce98c8f7f2cb967c77 Mon Sep 17 00:00:00 2001 From: Wassim SAMAD Date: Thu, 14 May 2026 12:09:10 -0400 Subject: [PATCH] Add Presentation + IconRef to NodeDefinition v1 surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds optional `presentation` field for tool palette metadata: sentence- case label, optional description, icon (iconify reference, inline SVG, or lazy React component), palette section override, sort order, and a `hidden` flag for container kinds that exist but should not appear in the palette. Consumer arrives in Phase 4 (auto-derived palette buttons) — defining the type now means Phase 2's `column` and `shelf` definitions ship with the field already populated, no later round-trip. Iconify is the encouraged form for built-ins and AI-authored nodes: matches the @iconify-react setup the editor app already uses, and AI emits a name string from a curated list (no asset upload step needed). Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/core/src/registry/index.ts | 2 ++ packages/core/src/registry/types.ts | 36 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/packages/core/src/registry/index.ts b/packages/core/src/registry/index.ts index 9d2e6505..ee5fc49b 100644 --- a/packages/core/src/registry/index.ts +++ b/packages/core/src/registry/index.ts @@ -10,6 +10,7 @@ export type { DragAction, EditorCtx, HostableConfig, + IconRef, Issue, LazyComponent, McpOverrides, @@ -22,6 +23,7 @@ export type { ParamField, ParamGroup, Plugin, + Presentation, Relations, RendererSource, RotatableConfig, diff --git a/packages/core/src/registry/types.ts b/packages/core/src/registry/types.ts index 8c8273f6..07738843 100644 --- a/packages/core/src/registry/types.ts +++ b/packages/core/src/registry/types.ts @@ -32,11 +32,47 @@ export type NodeDefinition> = { tool?: LazyComponent affordances?: Affordance>[] + presentation?: Presentation mcp?: McpOverrides } export type NodeCategory = 'site' | 'structure' | 'furnish' | 'analysis' | 'utility' +// ─── Presentation (tool palette + UI surface) ──────────────────────── + +/** + * UI metadata for surfacing a node kind in the tool palette and elsewhere. + * Phase 4 ships the consumer (auto-derived palette buttons); definitions can + * declare this from Phase 2 onward so the spike's `column` and `shelf` show up + * correctly the moment the palette consumes the registry. + */ +export type Presentation = { + /** Sentence-case label shown in palette buttons, breadcrumbs, etc. */ + label: string + /** Optional longer tooltip / help text. */ + description?: string + /** Icon for palette buttons and tree views. */ + icon: IconRef + /** Tool palette section. Defaults to `category` when omitted. */ + paletteSection?: 'site' | 'structure' | 'furnish' + /** Sort key within a palette section; lower numbers come first. */ + paletteOrder?: number + /** Set true for kinds that exist but should NOT appear in the palette + * (containers like `site`/`building`/`level`, internal nodes). */ + hidden?: boolean +} + +export type IconRef = + /** Iconify identifier, e.g. `lucide:square`. Matches the @iconify-react + * setup the editor app already uses for tool icons. */ + | { kind: 'iconify'; name: string } + /** Inline SVG path data. Use for asset packs or plugins that want a custom + * mark without contributing a React component. */ + | { kind: 'svg'; viewBox: string; path: string } + /** Custom React component, lazy-loaded. Use sparingly — adds a Suspense + * boundary per icon. */ + | { kind: 'component'; module: () => Promise<{ default: ComponentType }> } + export type LazyComponent = () => Promise<{ default: ComponentType }> export type RendererSource =