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'
This commit is contained in:
@@ -254,9 +254,20 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly =
|
|||||||
const rawX = ghostRect.left - refRect.left;
|
const rawX = ghostRect.left - refRect.left;
|
||||||
const rawY = ghostRect.top - refRect.top;
|
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<string>(['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)
|
// Field dimensions in screen pixels (for clamping)
|
||||||
const fieldWpx = (144 / pageInfo.originalWidth) * renderedW;
|
const fieldWpx = (fieldW / pageInfo.originalWidth) * renderedW;
|
||||||
const fieldHpx = (36 / pageInfo.originalHeight) * renderedH;
|
const fieldHpx = (fieldH / pageInfo.originalHeight) * renderedH;
|
||||||
|
|
||||||
// Clamp so field stays within canvas bounds
|
// Clamp so field stays within canvas bounds
|
||||||
const clampedX = Math.max(0, Math.min(rawX, renderedW - fieldWpx));
|
const clampedX = Math.max(0, Math.min(rawX, renderedW - fieldWpx));
|
||||||
@@ -273,8 +284,9 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly =
|
|||||||
page: currentPage,
|
page: currentPage,
|
||||||
x: pdfX,
|
x: pdfX,
|
||||||
y: pdfY,
|
y: pdfY,
|
||||||
width: 144,
|
width: fieldW,
|
||||||
height: 36,
|
height: fieldH,
|
||||||
|
type: droppedType,
|
||||||
};
|
};
|
||||||
|
|
||||||
const next = [...fields, newField];
|
const next = [...fields, newField];
|
||||||
@@ -549,6 +561,12 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly =
|
|||||||
|
|
||||||
const isMoving = activeDragFieldId === field.id && activeDragType === 'move';
|
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
|
// Resize handle style factory
|
||||||
const resizeHandle = (corner: ResizeCorner) => {
|
const resizeHandle = (corner: ResizeCorner) => {
|
||||||
const cursors: Record<ResizeCorner, string> = {
|
const cursors: Record<ResizeCorner, string> = {
|
||||||
@@ -573,7 +591,7 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly =
|
|||||||
width: 10,
|
width: 10,
|
||||||
height: 10,
|
height: 10,
|
||||||
cursor: cursors[corner],
|
cursor: cursors[corner],
|
||||||
background: '#2563eb',
|
background: fieldColor,
|
||||||
zIndex: 12,
|
zIndex: 12,
|
||||||
pointerEvents: readOnly ? 'none' : 'all',
|
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
|
top: top - heightPx + canvasOffset.y, // top is y of bottom-left corner; shift up by height
|
||||||
width: widthPx,
|
width: widthPx,
|
||||||
height: heightPx,
|
height: heightPx,
|
||||||
border: '2px solid #2563eb',
|
border: `2px solid ${fieldColor}`,
|
||||||
background: readOnly ? 'rgba(37,99,235,0.05)' : 'rgba(37,99,235,0.1)',
|
background: readOnly ? `${fieldColor}0d` : `${fieldColor}1a`,
|
||||||
borderRadius: '2px',
|
borderRadius: '2px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
padding: '0 4px',
|
padding: '0 4px',
|
||||||
fontSize: '10px',
|
fontSize: '10px',
|
||||||
color: '#2563eb',
|
color: fieldColor,
|
||||||
// Raise above droppable overlay so the delete button is clickable
|
// Raise above droppable overlay so the delete button is clickable
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
pointerEvents: readOnly ? 'none' : 'all',
|
pointerEvents: readOnly ? 'none' : 'all',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
cursor: readOnly ? 'default' : (isMoving ? 'grabbing' : 'grab'),
|
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',
|
userSelect: 'none',
|
||||||
touchAction: 'none',
|
touchAction: 'none',
|
||||||
opacity: readOnly ? 0.6 : 1,
|
opacity: readOnly ? 0.6 : 1,
|
||||||
@@ -621,7 +639,7 @@ export function FieldPlacer({ docId, pageInfo, currentPage, children, readOnly =
|
|||||||
handleMoveStart(e, field.id);
|
handleMoveStart(e, field.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ pointerEvents: 'none' }}>Signature</span>
|
<span style={{ pointerEvents: 'none' }}>{fieldLabel}</span>
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<button
|
<button
|
||||||
data-no-move
|
data-no-move
|
||||||
|
|||||||
Reference in New Issue
Block a user