refactor: replace workspace engine and drag/pointer logic with a new layout system and physics model.refactor: replace the workspace engine and drag/pointer logic with a new layout system.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
export interface LayoutItem {
|
||||
id: string;
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
rotation: number;
|
||||
width: number;
|
||||
height: number;
|
||||
ref: HTMLElement;
|
||||
}
|
||||
|
||||
export class LayoutStore {
|
||||
items = new Map<string, LayoutItem>();
|
||||
zCounter = 100;
|
||||
|
||||
register(id: string, ref: HTMLElement, initialData: Partial<LayoutItem>) {
|
||||
const existing = this.items.get(id);
|
||||
this.items.set(id, {
|
||||
id,
|
||||
ref,
|
||||
x: existing?.x ?? 0,
|
||||
y: existing?.y ?? 0,
|
||||
z: existing?.z ?? 0,
|
||||
rotation: existing?.rotation ?? 0,
|
||||
width: 200,
|
||||
height: 200,
|
||||
...initialData
|
||||
});
|
||||
}
|
||||
|
||||
initialize(id: string, ref: HTMLElement, config: {
|
||||
x?: number;
|
||||
y?: number;
|
||||
rotation?: number;
|
||||
z: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}) {
|
||||
if (this.items.has(id)) {
|
||||
// Update ref if it changed
|
||||
const item = this.items.get(id)!;
|
||||
if (item.ref !== ref) {
|
||||
item.ref = ref;
|
||||
this.update(id, {}); // Re-apply styles
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply defaults if not provided
|
||||
const x = config.x ?? Math.random() * 500;
|
||||
const y = config.y ?? Math.random() * 500;
|
||||
const rotation = config.rotation ?? (Math.random() * 10 - 5);
|
||||
|
||||
this.register(id, ref, {
|
||||
...config,
|
||||
x,
|
||||
y,
|
||||
rotation
|
||||
});
|
||||
|
||||
// Apply immediately
|
||||
this.update(id, {});
|
||||
}
|
||||
|
||||
unregister(id: string) {
|
||||
this.items.delete(id);
|
||||
}
|
||||
|
||||
// Fast Update: Updates internal state AND applies CSS transform immediately
|
||||
update(id: string, updates: Partial<LayoutItem>) {
|
||||
const item = this.items.get(id);
|
||||
if (!item) return;
|
||||
|
||||
Object.assign(item, updates);
|
||||
if (updates.z) this.zCounter = Math.max(this.zCounter, updates.z);
|
||||
|
||||
// Direct DOM manipulation (The "Engine" part)
|
||||
if (item.ref) {
|
||||
item.ref.style.transform =
|
||||
`translate3d(${item.x}px, ${item.y}px, 0) rotate(${item.rotation}deg)`;
|
||||
item.ref.style.zIndex = String(item.z);
|
||||
}
|
||||
}
|
||||
|
||||
bringToFront(id: string) {
|
||||
this.update(id, { z: ++this.zCounter });
|
||||
}
|
||||
|
||||
getSnapshot() {
|
||||
// Return serializable data for persistence
|
||||
return Array.from(this.items.values()).map(({ ref: _ref, ...data }) => data);
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton or Context-provided instance
|
||||
export const globalLayout = new LayoutStore();
|
||||
Reference in New Issue
Block a user