Wrap legacy systems in LegacySystem + mount RegisteredSystems (shim 3/4)
Two additions plus a viewer JSX rewire: - legacy-system.tsx: <LegacySystem kind="..."> wrapper that renders its children only when nodeRegistry.has(kind) is false. Lets one wrapper cover all legacy systems for a kind (door has DoorSystem and DoorAnimationSystem — both belong to 'door' so they yield together). - registered-systems.tsx: <RegisteredSystems /> iterates the registry, filters entries that contribute a system, sorts by system.priority (default 5; e.g. wall mitering at 8 runs after door cuts at 3), mounts each via React.lazy. Today empty registry = renders nothing. - viewer/index.tsx: every existing per-kind system is wrapped in LegacySystem. RegisteredSystems is mounted alongside. With the registry empty (Phase 0), every LegacySystem passes through unchanged and RegisteredSystems is a no-op — zero behavior change. Once a kind registers in Phase 2+, its legacy systems yield and its registry-contributed system runs in their place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0fd7af216c
commit
7dd3ffed3f
@@ -12,8 +12,8 @@ import { DoorSystem } from '../../systems/door/door-system'
|
|||||||
import { ElevatorInteractionSystem } from '../../systems/elevator/elevator-interaction-system'
|
import { ElevatorInteractionSystem } from '../../systems/elevator/elevator-interaction-system'
|
||||||
import { FenceSystem } from '../../systems/fence/fence-system'
|
import { FenceSystem } from '../../systems/fence/fence-system'
|
||||||
import { GuideSystem } from '../../systems/guide/guide-system'
|
import { GuideSystem } from '../../systems/guide/guide-system'
|
||||||
import { ItemLightSystem } from '../../systems/item-light/item-light-system'
|
|
||||||
import { ItemSystem } from '../../systems/item/item-system'
|
import { ItemSystem } from '../../systems/item/item-system'
|
||||||
|
import { ItemLightSystem } from '../../systems/item-light/item-light-system'
|
||||||
import { LevelSystem } from '../../systems/level/level-system'
|
import { LevelSystem } from '../../systems/level/level-system'
|
||||||
import { RoofSystem } from '../../systems/roof/roof-system'
|
import { RoofSystem } from '../../systems/roof/roof-system'
|
||||||
import { ScanSystem } from '../../systems/scan/scan-system'
|
import { ScanSystem } from '../../systems/scan/scan-system'
|
||||||
@@ -27,9 +27,11 @@ import { ZoneSystem } from '../../systems/zone/zone-system'
|
|||||||
import { ErrorBoundary } from '../error-boundary'
|
import { ErrorBoundary } from '../error-boundary'
|
||||||
import { SceneRenderer } from '../renderers/scene-renderer'
|
import { SceneRenderer } from '../renderers/scene-renderer'
|
||||||
import FrameLimiter from './frame-limiter'
|
import FrameLimiter from './frame-limiter'
|
||||||
|
import { LegacySystem } from './legacy-system'
|
||||||
import { Lights } from './lights'
|
import { Lights } from './lights'
|
||||||
import { PerfMonitor } from './perf-monitor'
|
import { PerfMonitor } from './perf-monitor'
|
||||||
import PostProcessing, { DEFAULT_HOVER_STYLES, type HoverStyles } from './post-processing'
|
import PostProcessing, { DEFAULT_HOVER_STYLES, type HoverStyles } from './post-processing'
|
||||||
|
import { RegisteredSystems } from './registered-systems'
|
||||||
import { SceneBvh } from './scene-bvh'
|
import { SceneBvh } from './scene-bvh'
|
||||||
import { SelectionManager } from './selection-manager'
|
import { SelectionManager } from './selection-manager'
|
||||||
import { ViewerCamera } from './viewer-camera'
|
import { ViewerCamera } from './viewer-camera'
|
||||||
@@ -223,30 +225,76 @@ const Viewer: React.FC<ViewerProps> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Default Systems */}
|
{/* Default Systems */}
|
||||||
<LevelSystem />
|
<LegacySystem kind="level">
|
||||||
<GuideSystem />
|
<LevelSystem />
|
||||||
<ScanSystem />
|
</LegacySystem>
|
||||||
<WallCutout />
|
<LegacySystem kind="guide">
|
||||||
|
<GuideSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="scan">
|
||||||
|
<ScanSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="wall">
|
||||||
|
<WallCutout />
|
||||||
|
</LegacySystem>
|
||||||
{/* Core systems */}
|
{/* Core systems */}
|
||||||
<CeilingSystem />
|
<LegacySystem kind="ceiling">
|
||||||
<DoorAnimationSystem />
|
<CeilingSystem />
|
||||||
<ElevatorRuntimeSystem />
|
</LegacySystem>
|
||||||
<ElevatorInteractionSystem />
|
<LegacySystem kind="door">
|
||||||
<ElevatorOpeningSystem />
|
<DoorAnimationSystem />
|
||||||
<WindowAnimationSystem />
|
</LegacySystem>
|
||||||
<DoorSystem />
|
<LegacySystem kind="elevator">
|
||||||
<FenceSystem />
|
<ElevatorRuntimeSystem />
|
||||||
<ItemSystem />
|
</LegacySystem>
|
||||||
<RoofSystem />
|
<LegacySystem kind="elevator">
|
||||||
<SlabSystem />
|
<ElevatorInteractionSystem />
|
||||||
<StairSystem />
|
</LegacySystem>
|
||||||
<WallSystem />
|
<LegacySystem kind="elevator">
|
||||||
<WindowSystem />
|
<ElevatorOpeningSystem />
|
||||||
<ZoneSystem />
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="window">
|
||||||
|
<WindowAnimationSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="door">
|
||||||
|
<DoorSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="fence">
|
||||||
|
<FenceSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="item">
|
||||||
|
<ItemSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="roof">
|
||||||
|
<RoofSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="slab">
|
||||||
|
<SlabSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="stair">
|
||||||
|
<StairSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="wall">
|
||||||
|
<WallSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="window">
|
||||||
|
<WindowSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
<LegacySystem kind="zone">
|
||||||
|
<ZoneSystem />
|
||||||
|
</LegacySystem>
|
||||||
|
{/* Mounts systems contributed by registry-backed kinds. Today the
|
||||||
|
registry is empty so this renders nothing. Once kinds register
|
||||||
|
(Phase 2+), each kind's registered system runs here and its
|
||||||
|
legacy counterpart above short-circuits via the LegacySystem
|
||||||
|
wrapper (which checks nodeRegistry.has). */}
|
||||||
|
<RegisteredSystems />
|
||||||
<PostProcessing hoverStyles={hoverStyles} />
|
<PostProcessing hoverStyles={hoverStyles} />
|
||||||
{/* <DebugRenderer /> */}
|
{/* <DebugRenderer /> */}
|
||||||
|
|
||||||
<ItemLightSystem />
|
<LegacySystem kind="item">
|
||||||
|
<ItemLightSystem />
|
||||||
|
</LegacySystem>
|
||||||
{selectionManager === 'default' && <SelectionManager />}
|
{selectionManager === 'default' && <SelectionManager />}
|
||||||
{(perf || PERF_OVERLAY_ENABLED) && <PerfMonitor />}
|
{(perf || PERF_OVERLAY_ENABLED) && <PerfMonitor />}
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { nodeRegistry } from '@pascal-app/core'
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a legacy per-kind system component so it short-circuits the moment a
|
||||||
|
* NodeDefinition for the same kind appears in the registry. Lets us migrate
|
||||||
|
* one kind at a time without editing each legacy system file individually.
|
||||||
|
*
|
||||||
|
* Multiple legacy systems can belong to the same kind (e.g. door has both
|
||||||
|
* `<DoorSystem>` and `<DoorAnimationSystem>`) — wrap them together so they
|
||||||
|
* yield as a unit when the kind registers.
|
||||||
|
*
|
||||||
|
* Removed in Phase 6 alongside the legacy systems themselves.
|
||||||
|
*/
|
||||||
|
export function LegacySystem({ kind, children }: { kind: string; children: ReactNode }) {
|
||||||
|
if (nodeRegistry.has(kind)) return null
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { type AnyNodeDefinition, nodeRegistry } from '@pascal-app/core'
|
||||||
|
import { type ComponentType, lazy, Suspense, useMemo } from 'react'
|
||||||
|
|
||||||
|
const DEFAULT_PRIORITY = 5
|
||||||
|
|
||||||
|
// Cache lazy components keyed by the module-loader function so React.lazy
|
||||||
|
// isn't re-invoked across renders.
|
||||||
|
const lazyCache = new WeakMap<() => Promise<unknown>, ComponentType>()
|
||||||
|
|
||||||
|
function loadSystem(def: AnyNodeDefinition): ComponentType | null {
|
||||||
|
if (!def.system) return null
|
||||||
|
const cached = lazyCache.get(def.system.module)
|
||||||
|
if (cached) return cached
|
||||||
|
const Comp = lazy(def.system.module as () => Promise<{ default: ComponentType }>)
|
||||||
|
lazyCache.set(def.system.module, Comp)
|
||||||
|
return Comp
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mounts every registered node kind's system component, ordered by
|
||||||
|
* `system.priority` (default {@link DEFAULT_PRIORITY}).
|
||||||
|
*
|
||||||
|
* Today the registry is empty so this component mounts nothing — coexists
|
||||||
|
* with legacy `*-System` components in `<Viewer>`. Once kinds register via
|
||||||
|
* `@pascal-app/nodes`, each kind's registry-driven system takes over and
|
||||||
|
* its legacy counterpart short-circuits via the `nodeRegistry.has(kind)`
|
||||||
|
* guard added to each legacy system.
|
||||||
|
*/
|
||||||
|
export function RegisteredSystems() {
|
||||||
|
const entries = useMemo(() => {
|
||||||
|
return Array.from(nodeRegistry.entries())
|
||||||
|
.filter(([, def]) => def.system != null)
|
||||||
|
.sort(([, a], [, b]) => {
|
||||||
|
const pa = a.system?.priority ?? DEFAULT_PRIORITY
|
||||||
|
const pb = b.system?.priority ?? DEFAULT_PRIORITY
|
||||||
|
return pa - pb
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (entries.length === 0) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
{entries.map(([kind, def]) => {
|
||||||
|
const Comp = loadSystem(def)
|
||||||
|
if (!Comp) return null
|
||||||
|
return <Comp key={`registered-system:${kind}`} />
|
||||||
|
})}
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user