T24: Use shared types, add 300ms debounce on Yjs updates in PropertiesPanel
This commit is contained in:
@@ -1,39 +1,8 @@
|
||||
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import type { CADLayer, CADProperties, CADElement } from '../../types/cad.types';
|
||||
import './PropertiesPanel.css';
|
||||
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
interface CADLayer {
|
||||
id: string;
|
||||
name: string;
|
||||
visible: boolean;
|
||||
locked: boolean;
|
||||
color?: string;
|
||||
lineType?: string;
|
||||
transparency?: number;
|
||||
sortOrder?: number;
|
||||
}
|
||||
|
||||
interface CADProperties {
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
strokeWidth?: number;
|
||||
rotation?: number;
|
||||
lineType?: 'solid' | 'dashed' | 'dotted';
|
||||
radius?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface CADElement {
|
||||
id: string;
|
||||
type: string;
|
||||
layerId: string;
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
properties: CADProperties;
|
||||
}
|
||||
// ─── Types (local-only, not duplicated from cad.types.ts) ─────────────────────
|
||||
|
||||
interface YjsDocumentLike {
|
||||
layers: {
|
||||
@@ -112,6 +81,18 @@ const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ canvasRef, yjsDocRef
|
||||
const [fabricObject, setFabricObject] = useState<FabricObjectLike | null>(null);
|
||||
const fabricCanvasRef = useRef<FabricCanvasLike | null>(null);
|
||||
|
||||
// Debounce timer for Yjs updates (300ms) — no new dependency needed
|
||||
const yjsDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Clear debounce timer on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (yjsDebounceRef.current) {
|
||||
clearTimeout(yjsDebounceRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// ── Sync layers from YjsDocument ──────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
const yjsDoc = yjsDocRef?.current;
|
||||
@@ -215,19 +196,26 @@ const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ canvasRef, yjsDocRef
|
||||
};
|
||||
}, [canvasRef, yjsDocRef]);
|
||||
|
||||
// ── Update handlers (Panel → Canvas + YjsDocument) ─────────────────────────
|
||||
// ── Update handlers (Panel → Canvas + YjsDocument) ──────────────────────────
|
||||
|
||||
const updateFabricAndYjs = useCallback(
|
||||
(updates: Partial<CADElement> & { properties?: Partial<CADProperties> }) => {
|
||||
if (!selectedElement) return;
|
||||
|
||||
// Update YjsDocument
|
||||
// Debounce Yjs write (300ms) — only write after user pauses typing
|
||||
if (yjsDebounceRef.current) {
|
||||
clearTimeout(yjsDebounceRef.current);
|
||||
}
|
||||
const elId = selectedElement.id;
|
||||
yjsDebounceRef.current = setTimeout(() => {
|
||||
const yjsDoc = yjsDocRef?.current;
|
||||
if (yjsDoc) {
|
||||
yjsDoc.updateElement(selectedElement.id, updates);
|
||||
yjsDoc.updateElement(elId, updates);
|
||||
}
|
||||
yjsDebounceRef.current = null;
|
||||
}, 300);
|
||||
|
||||
// Update fabric object directly
|
||||
// Update fabric object directly (immediate, no debounce)
|
||||
const fabricObj = fabricObject;
|
||||
const fabricCanvas = fabricCanvasRef.current;
|
||||
if (fabricObj && fabricCanvas) {
|
||||
@@ -251,7 +239,7 @@ const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ canvasRef, yjsDocRef
|
||||
fabricCanvas.renderAll();
|
||||
}
|
||||
|
||||
// Update local state
|
||||
// Update local state (immediate, no debounce)
|
||||
setSelectedElement((prev) => {
|
||||
if (!prev) return prev;
|
||||
return {
|
||||
@@ -264,7 +252,7 @@ const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ canvasRef, yjsDocRef
|
||||
[selectedElement, fabricObject, yjsDocRef]
|
||||
);
|
||||
|
||||
// ── Field change handlers ─────────────────────────────────────────────────
|
||||
// ── Field change handlers ──────────────────────────────────────────────────
|
||||
|
||||
const handleNumberChange = (field: 'x' | 'y' | 'width' | 'height', value: string) => {
|
||||
const n = clampNumber(value, -100000, 100000);
|
||||
@@ -297,7 +285,7 @@ const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ canvasRef, yjsDocRef
|
||||
updateFabricAndYjs({ layerId: value });
|
||||
};
|
||||
|
||||
// ── Render ────────────────────────────────────────────────────────────────
|
||||
// ── Render ──────────────────────────────────────────────────────────────────
|
||||
|
||||
if (!selectedElement) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user