fix: gauntlet hardening — alignment regression tests, cleanup, DRY, docker labels
- test: 3 regression tests for textAlign/verticalAlign/containerId REST round-trip (Zod was silently stripping these fields before the schema fix) - fix: pendingTitleTimerRef cleanup on unmount (App.tsx) - fix: localStorage JSON.parse wrapped in try/catch to prevent crash (App.tsx) - refactor: extract seedKnownContainers() helper — 4 identical loops → 1 (App.tsx) - chore: remove unnecessary `as any` cast on subtitle element type (index.ts) - docs: test counts updated to 446 (README.md, CLAUDE.md) - chore: fix stale LABEL source URLs in Dockerfile and Dockerfile.canvas Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
87e8a8e314
commit
64ebfc6791
+21
-23
@@ -88,13 +88,26 @@ function App(): JSX.Element {
|
||||
const knownContainerIdsRef = useRef<Set<string>>(new Set())
|
||||
const CONTAINER_TYPES = new Set(['rectangle', 'ellipse', 'diamond'])
|
||||
|
||||
// Seed knownContainerIdsRef before updateScene to prevent re-injection on load/sync
|
||||
const seedKnownContainers = (elements: readonly { type: string; id: string }[]): void => {
|
||||
for (const el of elements) {
|
||||
if (CONTAINER_TYPES.has(el.type)) {
|
||||
knownContainerIdsRef.current.add(el.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom font size input state
|
||||
const [customFontSize, setCustomFontSize] = useState<string>('')
|
||||
|
||||
// Draggable widget state — default near top menu
|
||||
const [widgetPos, setWidgetPos] = useState<{x: number, y: number}>(() => {
|
||||
const saved = localStorage.getItem('font-widget-pos')
|
||||
return saved ? JSON.parse(saved) : { x: window.innerWidth * 0.55, y: 90 }
|
||||
try {
|
||||
const saved = localStorage.getItem('font-widget-pos')
|
||||
return saved ? JSON.parse(saved) : { x: window.innerWidth * 0.55, y: 90 }
|
||||
} catch {
|
||||
return { x: window.innerWidth * 0.55, y: 90 }
|
||||
}
|
||||
})
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
const dragOffset = useRef<{x: number, y: number}>({x: 0, y: 0})
|
||||
@@ -162,10 +175,11 @@ function App(): JSX.Element {
|
||||
})
|
||||
}
|
||||
|
||||
// Clean up debounce timer on unmount
|
||||
// Clean up timers on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)
|
||||
if (pendingTitleTimerRef.current) clearTimeout(pendingTitleTimerRef.current)
|
||||
}
|
||||
}, [])
|
||||
|
||||
@@ -310,11 +324,7 @@ function App(): JSX.Element {
|
||||
const finalElements = prepareElementsForScene(result.elements, convertToExcalidrawElements as any)
|
||||
|
||||
// Seed known containers BEFORE updateScene so onChange doesn't re-inject titles
|
||||
for (const el of finalElements) {
|
||||
if (CONTAINER_TYPES.has(el.type)) {
|
||||
knownContainerIdsRef.current.add(el.id)
|
||||
}
|
||||
}
|
||||
seedKnownContainers(finalElements)
|
||||
|
||||
excalidrawAPI?.updateScene({ elements: finalElements })
|
||||
|
||||
@@ -543,11 +553,7 @@ function App(): JSX.Element {
|
||||
if (Array.isArray(data.elements) && data.elements.length > 0) {
|
||||
const finalElements = prepareElementsForScene(data.elements, convertToExcalidrawElements as any)
|
||||
// Seed known containers before updateScene
|
||||
for (const el of finalElements) {
|
||||
if (CONTAINER_TYPES.has(el.type)) {
|
||||
knownContainerIdsRef.current.add(el.id)
|
||||
}
|
||||
}
|
||||
seedKnownContainers(finalElements)
|
||||
api.updateScene({
|
||||
elements: finalElements,
|
||||
captureUpdate: CaptureUpdateAction.NEVER
|
||||
@@ -593,11 +599,7 @@ function App(): JSX.Element {
|
||||
case 'initial_elements':
|
||||
if (data.elements && data.elements.length > 0) {
|
||||
const initFinalElements = prepareElementsForScene(data.elements, convertToExcalidrawElements as any)
|
||||
for (const el of initFinalElements) {
|
||||
if (CONTAINER_TYPES.has(el.type)) {
|
||||
knownContainerIdsRef.current.add(el.id)
|
||||
}
|
||||
}
|
||||
seedKnownContainers(initFinalElements)
|
||||
api.updateScene({
|
||||
elements: initFinalElements,
|
||||
captureUpdate: CaptureUpdateAction.NEVER
|
||||
@@ -1118,11 +1120,7 @@ function App(): JSX.Element {
|
||||
const result: ApiResponse = await elemRes.json()
|
||||
if (result.success && result.elements && result.elements.length > 0) {
|
||||
const switchedElements = prepareElementsForScene(result.elements, convertToExcalidrawElements as any)
|
||||
for (const el of switchedElements) {
|
||||
if (CONTAINER_TYPES.has(el.type)) {
|
||||
knownContainerIdsRef.current.add(el.id)
|
||||
}
|
||||
}
|
||||
seedKnownContainers(switchedElements)
|
||||
excalidrawAPI?.updateScene({ elements: switchedElements })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user