editor: tool-defaults seeding + drawTool capability (fence presets) (#346)
* feat(editor): tool-defaults seeding + drawTool capability; fence consumes it Adds a generic, transient `useEditor.toolDefaults` slice keyed by tool, set via `setToolDefaults(tool, params)`. A draw tool's create path merges its entry when minting a node and clears it on deactivation, so a host app can prime the next-drawn node's parameters — placing a saved preset of a drawn kind, or a future "small / medium / large" dimension picker for wall / slab / ceiling. Marks the kind with `capabilities.drawTool` (helper `isDrawnViaTool`) so host apps know to route placement through `setToolDefaults(type) + setTool(type)` instead of cloning a finished instance. Wires fence end-to-end: it declares `drawTool: true`, its create path merges `toolDefaults.fence`, and the draft preview (bar geometry, cursor, HUD label heights) reflects the seeded height/thickness so the ghost matches what will be built. The tool clears its own defaults on unmount. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(editor): restore dropped useEditor import in fence tool The toolDefaults-seeding commit lost the `useEditor` import (formatter stripped it), shipping a runtime ReferenceError when FenceTool mounts. Re-add it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a144502c04
commit
b8d94a6436
@@ -17,6 +17,8 @@ export {
|
||||
discoverPlugins,
|
||||
getHostRefFields,
|
||||
getSelectableKinds,
|
||||
isDrawnViaTool,
|
||||
isDrawnViaToolKind,
|
||||
isPresettable,
|
||||
isPresettableKind,
|
||||
isRegistryMovable,
|
||||
|
||||
@@ -2,6 +2,8 @@ import { beforeEach, describe, expect, test } from 'bun:test'
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
getHostRefFields,
|
||||
isDrawnViaTool,
|
||||
isDrawnViaToolKind,
|
||||
isPresettable,
|
||||
isPresettableKind,
|
||||
loadPlugin,
|
||||
@@ -124,6 +126,28 @@ describe('getHostRefFields', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('isDrawnViaTool', () => {
|
||||
beforeEach(() => {
|
||||
nodeRegistry._reset()
|
||||
})
|
||||
|
||||
test('true when capability set', () => {
|
||||
const def = makeDefinition('fence', { capabilities: { drawTool: true } })
|
||||
expect(isDrawnViaTool(def)).toBe(true)
|
||||
})
|
||||
|
||||
test('false when unset or not exactly true', () => {
|
||||
expect(isDrawnViaTool(makeDefinition('column'))).toBe(false)
|
||||
expect(isDrawnViaTool(makeDefinition('off', { capabilities: { drawTool: false } }))).toBe(false)
|
||||
})
|
||||
|
||||
test('isDrawnViaToolKind looks up the registry', () => {
|
||||
registerNode(makeDefinition('fence', { capabilities: { drawTool: true } }))
|
||||
expect(isDrawnViaToolKind('fence')).toBe(true)
|
||||
expect(isDrawnViaToolKind('unknown')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('loadPlugin', () => {
|
||||
beforeEach(() => {
|
||||
nodeRegistry._reset()
|
||||
|
||||
@@ -174,6 +174,22 @@ export function getHostRefFields(def: AnyNodeDefinition): ReadonlyArray<string>
|
||||
return def.capabilities.hostRefFields ?? []
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether instances of this kind are created by drawing with a build tool
|
||||
* (tool id === node `type`) rather than dropping a finished instance. Read
|
||||
* by host apps to route preset placement of such kinds through
|
||||
* `setToolDefaults(type, params)` + `setTool(type)` — see
|
||||
* `def.capabilities.drawTool` docs.
|
||||
*/
|
||||
export function isDrawnViaTool(def: AnyNodeDefinition): boolean {
|
||||
return def.capabilities.drawTool === true
|
||||
}
|
||||
|
||||
export function isDrawnViaToolKind(kind: string): boolean {
|
||||
const def = nodeRegistry.get(kind)
|
||||
return def ? isDrawnViaTool(def) : false
|
||||
}
|
||||
|
||||
export async function loadPlugin(plugin: Plugin): Promise<void> {
|
||||
if (plugin.apiVersion !== HOST_API_VERSION) {
|
||||
throw new Error(
|
||||
|
||||
@@ -1008,6 +1008,20 @@ export type Capabilities = {
|
||||
* are non-leaf scene containers.
|
||||
*/
|
||||
presettable?: boolean
|
||||
/**
|
||||
* Instances of this kind are created by operating a build tool and
|
||||
* drawing on the grid (clicking points), rather than dropping a
|
||||
* finished instance. The tool id equals the node `type`. Host apps may
|
||||
* seed the tool's starting parameters via
|
||||
* `useEditor.setToolDefaults(type, params)` before activating it — the
|
||||
* tool's create path merges those defaults when minting the node and
|
||||
* clears its own entry on deactivation. Used so placing a saved preset
|
||||
* of a drawn kind contributes its build parameters (a fence's
|
||||
* height / style / post spacing) while the user draws the fresh span,
|
||||
* and so a future "small / medium / large" picker can prime the same
|
||||
* tool. Read via the `isDrawnViaTool(def)` helper. Default `false`.
|
||||
*/
|
||||
drawTool?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user