From 1e92ca363a91c6c94232f19bebfd7845f87ac3d1 Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Sat, 21 Mar 2026 12:50:18 -0600 Subject: [PATCH] feat(10-01): update handleDragEnd and renderFields for typed field creation - handleDragEnd: determine droppedType from active.id with validTypes set guard - handleDragEnd: checkbox fields drop at 24x24pt; all other types drop at 144x36pt - handleDragEnd: newField now includes type property set to droppedType - renderFields: use getFieldType() + PALETTE_TOKENS lookup to get per-field color and label - renderFields: border, background, and text color are now driven by fieldColor - renderFields: resize handle corners use fieldColor instead of hardcoded blue - renderFields: span displays fieldLabel instead of hardcoded 'Signature' --- .../[docId]/_components/FieldPlacer.tsx | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx b/teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx index 96c8a21..c0f80e4 100644 --- a/teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx +++ b/teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx @@ -254,9 +254,20 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = const rawX = ghostRect.left - refRect.left; const rawY = ghostRect.top - refRect.top; + // Determine the field type from the dnd-kit active.id (token id IS the SignatureFieldType) + const validTypes = new Set(['client-signature', 'initials', 'text', 'checkbox', 'date', 'agent-signature']); + const droppedType: SignatureFieldType = validTypes.has(active.id as string) + ? (active.id as SignatureFieldType) + : 'client-signature'; + + // Checkbox fields are square (24x24pt). All other types: 144x36pt. + const isCheckbox = droppedType === 'checkbox'; + const fieldW = isCheckbox ? 24 : 144; + const fieldH = isCheckbox ? 24 : 36; + // Field dimensions in screen pixels (for clamping) - const fieldWpx = (144 / pageInfo.originalWidth) * renderedW; - const fieldHpx = (36 / pageInfo.originalHeight) * renderedH; + const fieldWpx = (fieldW / pageInfo.originalWidth) * renderedW; + const fieldHpx = (fieldH / pageInfo.originalHeight) * renderedH; // Clamp so field stays within canvas bounds const clampedX = Math.max(0, Math.min(rawX, renderedW - fieldWpx)); @@ -273,8 +284,9 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = page: currentPage, x: pdfX, y: pdfY, - width: 144, - height: 36, + width: fieldW, + height: fieldH, + type: droppedType, }; const next = [...fields, newField]; @@ -549,6 +561,12 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = const isMoving = activeDragFieldId === field.id && activeDragType === 'move'; + // Per-type color and label + const fieldType = getFieldType(field); + const tokenMeta = PALETTE_TOKENS.find((t) => t.id === fieldType); + const fieldColor = tokenMeta?.color ?? '#2563eb'; + const fieldLabel = tokenMeta?.label ?? 'Signature'; + // Resize handle style factory const resizeHandle = (corner: ResizeCorner) => { const cursors: Record = { @@ -573,7 +591,7 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = width: 10, height: 10, cursor: cursors[corner], - background: '#2563eb', + background: fieldColor, zIndex: 12, pointerEvents: readOnly ? 'none' : 'all', }} @@ -595,21 +613,21 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = top: top - heightPx + canvasOffset.y, // top is y of bottom-left corner; shift up by height width: widthPx, height: heightPx, - border: '2px solid #2563eb', - background: readOnly ? 'rgba(37,99,235,0.05)' : 'rgba(37,99,235,0.1)', + border: `2px solid ${fieldColor}`, + background: readOnly ? `${fieldColor}0d` : `${fieldColor}1a`, borderRadius: '2px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 4px', fontSize: '10px', - color: '#2563eb', + color: fieldColor, // Raise above droppable overlay so the delete button is clickable zIndex: 10, pointerEvents: readOnly ? 'none' : 'all', boxSizing: 'border-box', cursor: readOnly ? 'default' : (isMoving ? 'grabbing' : 'grab'), - boxShadow: isMoving ? '0 4px 12px rgba(37,99,235,0.35)' : undefined, + boxShadow: isMoving ? `0 4px 12px ${fieldColor}59` : undefined, userSelect: 'none', touchAction: 'none', opacity: readOnly ? 0.6 : 1, @@ -621,7 +639,7 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly = handleMoveStart(e, field.id); }} > - Signature + {fieldLabel} {!readOnly && (