ai-chatbot/packages/editor/src/components/ui/helpers/registered-tool-helper.tsx
Wassim SAMAD f773e6b8c5 feat(editor): placement & interaction overhaul — FSM spine, bug tracks, perf
Implements plans/editor-placement-interaction-overhaul.md: an authoritative
interaction-scope state machine plus the catalogued placement/interaction
fixes, and split-view floor-plan performance.

- Interaction-scope spine (lib/interaction/* + store/use-interaction-scope),
  driven from central useEditor setters; overlay scoping (zone labels,
  context badges, floating action menu) reads resolveOverlayPolicy.
- Bug tracks A/B/D/E/F/G/H: handle/cutout raycast, footprint validity,
  auto-slab loop, ceiling hosting, B-key tool desync, 2D drop offset,
  per-frame jank.
- Snapping modes (grid/lines/angles/off) + contextual HUD chips; modifier
  model (Shift=cycle, Alt=free place, Ctrl=grid step).
- Item move now tracks the cursor 1:1 (was a laggy per-frame lerp); handle
  rig hides during a whole-node move; rotate gizmo advertises Shift=free
  rotation in the HUD and hides the move cross while rotating.
- Floor-plan perf: pause live reactivity while in 3D-only view; per-node
  geometry cache so only changed nodes rebuild on a drag; hoist wall miters
  to a once-per-pass ctx.levelData (O(N^2) -> O(N) on wall/opening drags).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:04:58 -04:00

39 lines
1.4 KiB
TypeScript

import type { ToolHint } from '@pascal-app/core'
import { ContextualHelperPanel } from './contextual-helper-panel'
/**
* Generic helper panel rendered from `def.toolHints` data. Matches the
* visual styling of the hand-written `<WallHelper>` / `<ItemHelper>` /
* etc. so registry-driven kinds get a consistent look without each kind
* writing its own component.
*
* Drops the need for per-kind helper files entirely — kinds declare
* their hints as static data in their `NodeDefinition`.
*/
export function RegisteredToolHelper({
hints,
shiftPressed = false,
}: {
hints: ToolHint[]
shiftPressed?: boolean
}) {
if (hints.length === 0) return null
return (
<ContextualHelperPanel
showSnapping
hints={hints.map((hint) => {
// Shift is a per-kind bypass for item / opening / zone / duct placement
// ("Free place", "Free angle", …) — those hints flip to a bypassed
// state while held. For wall / fence, Shift now cycles the snapping
// mode (no hold-to-bypass), so it must NOT show the bypass treatment.
const isBypassHint = hint.key === 'Shift' && hint.label !== 'Cycle snapping mode'
return {
keys: [hint.key],
label: shiftPressed && isBypassHint ? 'Guided constraints bypassed' : hint.label,
active: shiftPressed && isBypassHint,
}
})}
/>
)
}