fix(exam): keep region shapes overlaid on PDF in setup canvas
Some checks failed
app-ci-deploy / test-build-deploy (push) Has been cancelled

Three z-order fixes in ExamTemplateSetupPage:

1. loadShapes: early-return before deletion when models is empty, so
   seed guide shapes aren't wiped for a fresh template that has no
   saved regions yet.

2. Incremental PDF loading (onPageReady): replace per-page sendToBack
   (unreliable when all shapes are moving — reorderToBack no-ops) with
   bringToFront on existing domain shapes after each page is added.

3. Final load sequence: call bringDomainShapesToFront after syncPdfPages
   + loadShapes to guarantee correct z-order regardless of how tldraw's
   fractional indexer placed newly created shapes. Also called from
   onMount for the same reason.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
CC Worker 2026-06-07 10:12:16 +00:00
parent 3389fdcb5b
commit 15a519748d

View File

@ -88,10 +88,15 @@ function modelFromTLShape(shape: TLShape): ExamCanvasShapeModel | null {
}
}
function bringDomainShapesToFront(editor: Editor) {
const ids = editor.getCurrentPageShapes().filter((s) => !!shapeTypeToKind(s.type)).map((s) => s.id)
if (ids.length) try { editor.bringToFront(ids as any) } catch { /* */ }
}
function loadShapes(editor: Editor, models: ExamCanvasShapeModel[]) {
if (!models.length) return
const existing = editor.getCurrentPageShapes().filter((s) => shapeTypeToKind(s.type)).map((s) => s.id)
if (existing.length) editor.deleteShapes(existing)
if (!models.length) return
editor.createShapes(models.map((m) => ({
id: createShapeId(m.id),
type: SHAPE_TYPES[m.kind],
@ -117,8 +122,7 @@ function syncPdfPages(editor: Editor, pages: PdfPageImage[]) {
props: { w: geometry.w, h: geometry.h, src: page.src, pageNumber: geometry.pageNumber },
} as any
}))
const ids = geometries.map((geometry) => createShapeId(PDF_PAGE_IDS_PREFIX + geometry.pageNumber))
try { editor.sendToBack(ids as any) } catch { /* tldraw 3 keeps creation order behind later region shapes */ }
// z-order is enforced by the caller via bringDomainShapesToFront
}
function seedGuide(editor: Editor) {
@ -170,7 +174,7 @@ const ExamTemplateSetupInner: React.FC = () => {
const shapeId = createShapeId(PDF_PAGE_IDS_PREFIX + newPage.pageNumber)
if (!ed.getCurrentPageShapes().find((s) => s.id === shapeId)) {
ed.createShapes([{ id: shapeId, type: PDF_PAGE_SHAPE_TYPE, x: geometry.x, y: geometry.y, isLocked: true, props: { w: geometry.w, h: geometry.h, src: newPage.src, pageNumber: newPage.pageNumber } } as any])
try { ed.sendToBack([shapeId as any]) } catch { /* */ }
bringDomainShapesToFront(ed)
}
}
setPdfStatus('ready')
@ -188,6 +192,7 @@ const ExamTemplateSetupInner: React.FC = () => {
if (editor) {
syncPdfPages(editor, pages)
loadShapes(editor, shapesFromTemplate(detail, geometries))
bringDomainShapesToFront(editor)
}
setDirty(false)
} catch (e) {
@ -256,6 +261,7 @@ const ExamTemplateSetupInner: React.FC = () => {
editor.user.updateUserPreferences({ colorScheme: theme.palette.mode === 'dark' ? 'dark' : 'light' })
editor.store.listen(() => setDirty(true), { scope: 'document' })
if (template) loadShapes(editor, shapesFromTemplate(template, pageGeometriesRef.current)); else seedGuide(editor)
bringDomainShapesToFront(editor)
}}
/>
</Box>