react-id-card-generator 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/IDCardDesigner.js +14 -7
- package/dist/cjs/components/IDCardDesigner.js.map +1 -1
- package/dist/cjs/components/IDCardGenerator.js +0 -3
- package/dist/cjs/components/IDCardGenerator.js.map +1 -1
- package/dist/cjs/components/IDCardPreview.js +0 -3
- package/dist/cjs/components/IDCardPreview.js.map +1 -1
- package/dist/cjs/core/exportUtils.js +2 -2
- package/dist/cjs/core/exportUtils.js.map +1 -1
- package/dist/cjs/hooks/useIDCardTemplate.js +41 -12
- package/dist/cjs/hooks/useIDCardTemplate.js.map +1 -1
- package/dist/cjs/utils/deepCleanUndefined.js +21 -0
- package/dist/cjs/utils/deepCleanUndefined.js.map +1 -0
- package/dist/esm/components/IDCardDesigner.js +15 -5
- package/dist/esm/components/IDCardDesigner.js.map +1 -1
- package/dist/esm/components/IDCardGenerator.js +1 -1
- package/dist/esm/components/IDCardGenerator.js.map +1 -1
- package/dist/esm/components/IDCardPreview.js +1 -1
- package/dist/esm/components/IDCardPreview.js.map +1 -1
- package/dist/esm/core/exportUtils.js +1 -1
- package/dist/esm/hooks/useIDCardTemplate.js +41 -12
- package/dist/esm/hooks/useIDCardTemplate.js.map +1 -1
- package/dist/esm/utils/deepCleanUndefined.js +19 -0
- package/dist/esm/utils/deepCleanUndefined.js.map +1 -0
- package/dist/types/components/IDCardDesigner.d.ts +0 -1
- package/dist/types/components/IDCardGenerator.d.ts +0 -1
- package/dist/types/components/IDCardPreview.d.ts +0 -1
- package/dist/types/utils/deepCleanUndefined.d.ts +1 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IDCardPreview.js","sources":["../../../src/components/IDCardPreview.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\r\nimport type { IDCardPreviewProps, FieldMapping } from '../types';\r\nimport { fieldStyleToCSS, positionToStyle } from '../utils/styleUtils';\r\nimport { generateQrCodeFromFields } from '../core/qrUtils';\r\n\r\n/**\r\n * IDCardPreview - Interactive card preview component\r\n * \r\n * Renders an ID card with:\r\n * - Field selection and highlighting\r\n * - Resize handles for selected fields\r\n * - Grid overlay for alignment\r\n * - Dynamic field rendering based on type\r\n * \r\n * Used inside the designer for visual editing\r\n */\r\nexport const IDCardPreview: React.FC<IDCardPreviewProps> = ({\r\n template,\r\n data,\r\n side,\r\n scale = 1,\r\n showGrid = false,\r\n onFieldSelect,\r\n selectedFieldId,\r\n editable = true,\r\n onFieldUpdate,\r\n}: IDCardPreviewProps) => {\r\n // Get only fields that belong to the current side\r\n const fieldsToRender = useMemo(() => {\r\n return template.fields.filter((field: FieldMapping) => field.side === side);\r\n }, [template.fields, side]);\r\n\r\n // Get background for current side\r\n const backgroundImage = side === 'front' ? template.backgrounds.front : template.backgrounds.back;\r\n\r\n // Render resize handles for selected field\r\n const renderResizeHandles = (field: FieldMapping) => {\r\n if (field.id !== selectedFieldId || !editable) return null;\r\n\r\n const handles = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];\r\n const handleStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n width: '8px',\r\n height: '8px',\r\n backgroundColor: '#2196F3',\r\n border: '1px solid #fff',\r\n borderRadius: '2px',\r\n zIndex: 1000,\r\n };\r\n\r\n const positions: Record<string, React.CSSProperties> = {\r\n n: { top: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 'n-resize' },\r\n s: { bottom: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 's-resize' },\r\n e: { right: '-4px', top: '50%', transform: 'translateY(-50%)', cursor: 'e-resize' },\r\n w: { left: '-4px', top: '50%', transform: 'translateY(-50%)', cursor: 'w-resize' },\r\n ne: { top: '-4px', right: '-4px', cursor: 'ne-resize' },\r\n nw: { top: '-4px', left: '-4px', cursor: 'nw-resize' },\r\n se: { bottom: '-4px', right: '-4px', cursor: 'se-resize' },\r\n sw: { bottom: '-4px', left: '-4px', cursor: 'sw-resize' },\r\n };\r\n\r\n return handles.map((handle) => (\r\n <div\r\n key={handle}\r\n className={`resize-handle resize-handle-${handle}`}\r\n style={{ ...handleStyle, ...positions[handle] }}\r\n data-handle={handle}\r\n />\r\n ));\r\n };\r\n\r\n // Render a single field\r\n const renderField = (field: FieldMapping) => {\r\n const posStyle = positionToStyle(field.position);\r\n const fieldStyle = fieldStyleToCSS(field.style);\r\n const isSelected = field.id === selectedFieldId;\r\n\r\n const combinedStyle: React.CSSProperties = {\r\n ...posStyle,\r\n ...fieldStyle,\r\n zIndex: field.zIndex || 1,\r\n boxSizing: 'border-box',\r\n overflow: 'hidden',\r\n cursor: editable ? 'move' : 'default',\r\n outline: isSelected ? '2px solid #2196F3' : 'none',\r\n outlineOffset: '1px',\r\n };\r\n\r\n const handleClick = (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n onFieldSelect?.(field);\r\n };\r\n\r\n const value = data[field.fieldKey];\r\n\r\n const content = (() => {\r\n switch (field.type) {\r\n case 'text':\r\n return (\r\n <>\r\n {field.label && (\r\n <span style={{ fontSize: '0.75em', display: 'block', opacity: 0.7 }}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </>\r\n );\r\n\r\n case 'label':\r\n return <span>{field.staticText || field.label || 'Label'}</span>;\r\n\r\n case 'image':\r\n return value ? (\r\n <img\r\n src={String(value)}\r\n alt={field.label || 'Image'}\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover',\r\n objectPosition: 'center top',\r\n }}\r\n />\r\n ) : (\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n backgroundColor: '#e0e0e0',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '10px',\r\n color: '#666',\r\n flexDirection: 'column',\r\n }}\r\n >\r\n <span>📷</span>\r\n <span>{field.label || 'Photo'}</span>\r\n </div>\r\n );\r\n\r\n case 'qrcode':\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, 200)\r\n : '';\r\n\r\n return qrDataUrl ? (\r\n <img\r\n src={qrDataUrl}\r\n alt=\"QR Code\"\r\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\r\n />\r\n ) : (\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n backgroundColor: '#f0f0f0',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '10px',\r\n color: '#666',\r\n border: '1px dashed #ccc',\r\n }}\r\n >\r\n QR Code\r\n </div>\r\n );\r\n\r\n default:\r\n return null;\r\n }\r\n })();\r\n\r\n return (\r\n <div\r\n key={field.id}\r\n id={`preview-${field.id}`}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className={`preview-field preview-field-${field.type} ${isSelected ? 'selected' : ''}`}\r\n >\r\n {content}\r\n {renderResizeHandles(field)}\r\n </div>\r\n );\r\n };\r\n\r\n // Card container style\r\n const cardStyle: React.CSSProperties = {\r\n width: template.cardSize.width,\r\n height: template.cardSize.height,\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: backgroundImage ? 'transparent' : '#f5f5f5',\r\n border: '1px solid #ddd',\r\n transform: `scale(${scale})`,\r\n transformOrigin: 'top left',\r\n };\r\n\r\n // Grid overlay style\r\n const gridStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n backgroundImage: showGrid\r\n ? 'linear-gradient(to right, rgba(0,0,0,0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.05) 1px, transparent 1px)'\r\n : 'none',\r\n backgroundSize: '10px 10px',\r\n pointerEvents: 'none',\r\n zIndex: 999,\r\n };\r\n\r\n const handleContainerClick = () => {\r\n onFieldSelect?.(null);\r\n };\r\n\r\n return (\r\n <div\r\n className=\"idcard-preview-container\"\r\n style={cardStyle}\r\n onClick={handleContainerClick}\r\n >\r\n {/* Background */}\r\n {backgroundImage && (\r\n <img\r\n src={backgroundImage}\r\n alt={`${side} background`}\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover',\r\n zIndex: 0,\r\n pointerEvents: 'none',\r\n }}\r\n />\r\n )}\r\n\r\n {/* Fields */}\r\n {fieldsToRender.map(renderField)}\r\n\r\n {/* Grid overlay */}\r\n {showGrid && <div style={gridStyle} />}\r\n\r\n {/* Empty state */}\r\n {!backgroundImage && fieldsToRender.length === 0 && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '50%',\r\n left: '50%',\r\n transform: 'translate(-50%, -50%)',\r\n textAlign: 'center',\r\n color: '#999',\r\n fontSize: '14px',\r\n }}\r\n >\r\n <p>Upload a background image</p>\r\n <p>and add fields to get started</p>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default IDCardPreview;\r\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;AAKA;;;;;;;;;;AAUG;AACI,MAAM,aAAa,GAAiC,CAAC,EAC1D,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,KAAK,GAAG,CAAC,EACT,QAAQ,GAAG,KAAK,EAChB,aAAa,EACb,eAAe,EACf,QAAQ,GAAG,IAAI,EACf,aAAa,GACM,KAAI;;AAEvB,IAAA,MAAM,cAAc,GAAG,OAAO,CAAC,MAAK;AAClC,QAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAmB,KAAK,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;IAC7E,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;;IAG3B,MAAM,eAAe,GAAG,IAAI,KAAK,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI;;AAGjG,IAAA,MAAM,mBAAmB,GAAG,CAAC,KAAmB,KAAI;AAClD,QAAA,IAAI,KAAK,CAAC,EAAE,KAAK,eAAe,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,IAAI;AAE1D,QAAA,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;AAC5D,QAAA,MAAM,WAAW,GAAwB;AACvC,YAAA,QAAQ,EAAE,UAAU;AACpB,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,MAAM,EAAE,KAAK;AACb,YAAA,eAAe,EAAE,SAAS;AAC1B,YAAA,MAAM,EAAE,gBAAgB;AACxB,YAAA,YAAY,EAAE,KAAK;AACnB,YAAA,MAAM,EAAE,IAAI;SACb;AAED,QAAA,MAAM,SAAS,GAAwC;AACrD,YAAA,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE;AAClF,YAAA,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE;AACrF,YAAA,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE;AACnF,YAAA,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE;AAClF,YAAA,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;AACvD,YAAA,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;AACtD,YAAA,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;AAC1D,YAAA,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;SAC1D;AAED,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,MACxBA,aAEE,SAAS,EAAE,CAAA,4BAAA,EAA+B,MAAM,EAAE,EAClD,KAAK,EAAE,EAAE,GAAG,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,EAAA,aAAA,EAClC,MAAM,EAAA,EAHd,MAAM,CAIX,CACH,CAAC;AACJ,IAAA,CAAC;;AAGD,IAAA,MAAM,WAAW,GAAG,CAAC,KAAmB,KAAI;QAC1C,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC;QAChD,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/C,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,EAAE,KAAK,eAAe;AAE/C,QAAA,MAAM,aAAa,GAAwB;AACzC,YAAA,GAAG,QAAQ;AACX,YAAA,GAAG,UAAU;AACb,YAAA,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC;AACzB,YAAA,SAAS,EAAE,YAAY;AACvB,YAAA,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS;YACrC,OAAO,EAAE,UAAU,GAAG,mBAAmB,GAAG,MAAM;AAClD,YAAA,aAAa,EAAE,KAAK;SACrB;AAED,QAAA,MAAM,WAAW,GAAG,CAAC,CAAmB,KAAI;YAC1C,CAAC,CAAC,eAAe,EAAE;AACnB,YAAA,aAAa,GAAG,KAAK,CAAC;AACxB,QAAA,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;AAElC,QAAA,MAAM,OAAO,GAAG,CAAC,MAAK;AACpB,YAAA,QAAQ,KAAK,CAAC,IAAI;AAChB,gBAAA,KAAK,MAAM;oBACT,QACEC,4BACG,KAAK,CAAC,KAAK,KACVD,cAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,YAChE,KAAK,CAAC,KAAK,EAAA,CACP,CACR,EACDA,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAO,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAA,CAAQ,CAAA,EAAA,CAClE;AAGP,gBAAA,KAAK,OAAO;oBACV,OAAOA,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAO,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,EAAA,CAAQ;AAElE,gBAAA,KAAK,OAAO;oBACV,OAAO,KAAK,IACVA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,EAClB,GAAG,EAAE,KAAK,CAAC,KAAK,IAAI,OAAO,EAC3B,KAAK,EAAE;AACL,4BAAA,KAAK,EAAE,MAAM;AACb,4BAAA,MAAM,EAAE,MAAM;AACd,4BAAA,SAAS,EAAE,OAAO;AAClB,4BAAA,cAAc,EAAE,YAAY;AAC7B,yBAAA,EAAA,CACD,KAEFC,IAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAE;AACL,4BAAA,KAAK,EAAE,MAAM;AACb,4BAAA,MAAM,EAAE,MAAM;AACd,4BAAA,eAAe,EAAE,SAAS;AAC1B,4BAAA,OAAO,EAAE,MAAM;AACf,4BAAA,UAAU,EAAE,QAAQ;AACpB,4BAAA,cAAc,EAAE,QAAQ;AACxB,4BAAA,QAAQ,EAAE,MAAM;AAChB,4BAAA,KAAK,EAAE,MAAM;AACb,4BAAA,aAAa,EAAE,QAAQ;yBACxB,EAAA,QAAA,EAAA,CAEDD,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAA,cAAA,EAAA,CAAe,EACfA,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAO,KAAK,CAAC,KAAK,IAAI,OAAO,EAAA,CAAQ,CAAA,EAAA,CACjC,CACP;AAEH,gBAAA,KAAK,QAAQ;AACX,oBAAA,MAAM,SAAS,GAAG,KAAK,CAAC;0BACpB,wBAAwB,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG;0BAClD,EAAE;AAEN,oBAAA,OAAO,SAAS,IACdA,aACE,GAAG,EAAE,SAAS,EACd,GAAG,EAAC,SAAS,EACb,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,EAAA,CAC9D,KAEFA,GAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAE;AACL,4BAAA,KAAK,EAAE,MAAM;AACb,4BAAA,MAAM,EAAE,MAAM;AACd,4BAAA,eAAe,EAAE,SAAS;AAC1B,4BAAA,OAAO,EAAE,MAAM;AACf,4BAAA,UAAU,EAAE,QAAQ;AACpB,4BAAA,cAAc,EAAE,QAAQ;AACxB,4BAAA,QAAQ,EAAE,MAAM;AAChB,4BAAA,KAAK,EAAE,MAAM;AACb,4BAAA,MAAM,EAAE,iBAAiB;AAC1B,yBAAA,EAAA,QAAA,EAAA,SAAA,EAAA,CAGG,CACP;AAEH,gBAAA;AACE,oBAAA,OAAO,IAAI;;QAEjB,CAAC,GAAG;QAEJ,QACEC,cAEE,EAAE,EAAE,WAAW,KAAK,CAAC,EAAE,CAAA,CAAE,EACzB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,CAAA,4BAAA,EAA+B,KAAK,CAAC,IAAI,IAAI,UAAU,GAAG,UAAU,GAAG,EAAE,CAAA,CAAE,EAAA,QAAA,EAAA,CAErF,OAAO,EACP,mBAAmB,CAAC,KAAK,CAAC,CAAA,EAAA,EAPtB,KAAK,CAAC,EAAE,CAQT;AAEV,IAAA,CAAC;;AAGD,IAAA,MAAM,SAAS,GAAwB;AACrC,QAAA,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK;AAC9B,QAAA,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;AAChC,QAAA,QAAQ,EAAE,UAAU;AACpB,QAAA,QAAQ,EAAE,QAAQ;QAClB,eAAe,EAAE,eAAe,GAAG,aAAa,GAAG,SAAS;AAC5D,QAAA,MAAM,EAAE,gBAAgB;QACxB,SAAS,EAAE,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA,CAAG;AAC5B,QAAA,eAAe,EAAE,UAAU;KAC5B;;AAGD,IAAA,MAAM,SAAS,GAAwB;AACrC,QAAA,QAAQ,EAAE,UAAU;AACpB,QAAA,GAAG,EAAE,CAAC;AACN,QAAA,IAAI,EAAE,CAAC;AACP,QAAA,KAAK,EAAE,MAAM;AACb,QAAA,MAAM,EAAE,MAAM;AACd,QAAA,eAAe,EAAE;AACf,cAAE;AACF,cAAE,MAAM;AACV,QAAA,cAAc,EAAE,WAAW;AAC3B,QAAA,aAAa,EAAE,MAAM;AACrB,QAAA,MAAM,EAAE,GAAG;KACZ;IAED,MAAM,oBAAoB,GAAG,MAAK;AAChC,QAAA,aAAa,GAAG,IAAI,CAAC;AACvB,IAAA,CAAC;AAED,IAAA,QACEA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,0BAA0B,EACpC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,oBAAoB,EAAA,QAAA,EAAA,CAG5B,eAAe,KACdD,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,CAAA,EAAG,IAAI,CAAA,WAAA,CAAa,EACzB,KAAK,EAAE;AACL,oBAAA,QAAQ,EAAE,UAAU;AACpB,oBAAA,GAAG,EAAE,CAAC;AACN,oBAAA,IAAI,EAAE,CAAC;AACP,oBAAA,KAAK,EAAE,MAAM;AACb,oBAAA,MAAM,EAAE,MAAM;AACd,oBAAA,SAAS,EAAE,OAAO;AAClB,oBAAA,MAAM,EAAE,CAAC;AACT,oBAAA,aAAa,EAAE,MAAM;AACtB,iBAAA,EAAA,CACD,CACH,EAGA,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAG/B,QAAQ,IAAIA,GAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAE,SAAS,EAAA,CAAI,EAGrC,CAAC,eAAe,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,KAC9CC,IAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAE;AACL,oBAAA,QAAQ,EAAE,UAAU;AACpB,oBAAA,GAAG,EAAE,KAAK;AACV,oBAAA,IAAI,EAAE,KAAK;AACX,oBAAA,SAAS,EAAE,uBAAuB;AAClC,oBAAA,SAAS,EAAE,QAAQ;AACnB,oBAAA,KAAK,EAAE,MAAM;AACb,oBAAA,QAAQ,EAAE,MAAM;AACjB,iBAAA,EAAA,QAAA,EAAA,CAEDD,mDAAgC,EAChCA,GAAA,CAAA,GAAA,EAAA,EAAA,QAAA,EAAA,+BAAA,EAAA,CAAoC,IAChC,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
|
|
1
|
+
{"version":3,"file":"IDCardPreview.js","sources":["../../../src/components/IDCardPreview.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\r\nimport type { IDCardPreviewProps, FieldMapping } from '../types';\r\nimport { fieldStyleToCSS, positionToStyle } from '../utils/styleUtils';\r\nimport { generateQrCodeFromFields } from '../core/qrUtils';\r\n\r\n/**\r\n * IDCardPreview - Interactive card preview component\r\n * \r\n * Renders an ID card with:\r\n * - Field selection and highlighting\r\n * - Resize handles for selected fields\r\n * - Grid overlay for alignment\r\n * - Dynamic field rendering based on type\r\n * \r\n * Used inside the designer for visual editing\r\n */\r\nexport const IDCardPreview: React.FC<IDCardPreviewProps> = ({\r\n template,\r\n data,\r\n side,\r\n scale = 1,\r\n showGrid = false,\r\n onFieldSelect,\r\n selectedFieldId,\r\n editable = true,\r\n onFieldUpdate,\r\n}: IDCardPreviewProps) => {\r\n // Get only fields that belong to the current side\r\n const fieldsToRender = useMemo(() => {\r\n return template.fields.filter((field: FieldMapping) => field.side === side);\r\n }, [template.fields, side]);\r\n\r\n // Get background for current side\r\n const backgroundImage = side === 'front' ? template.backgrounds.front : template.backgrounds.back;\r\n\r\n // Render resize handles for selected field\r\n const renderResizeHandles = (field: FieldMapping) => {\r\n if (field.id !== selectedFieldId || !editable) return null;\r\n\r\n const handles = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'];\r\n const handleStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n width: '8px',\r\n height: '8px',\r\n backgroundColor: '#2196F3',\r\n border: '1px solid #fff',\r\n borderRadius: '2px',\r\n zIndex: 1000,\r\n };\r\n\r\n const positions: Record<string, React.CSSProperties> = {\r\n n: { top: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 'n-resize' },\r\n s: { bottom: '-4px', left: '50%', transform: 'translateX(-50%)', cursor: 's-resize' },\r\n e: { right: '-4px', top: '50%', transform: 'translateY(-50%)', cursor: 'e-resize' },\r\n w: { left: '-4px', top: '50%', transform: 'translateY(-50%)', cursor: 'w-resize' },\r\n ne: { top: '-4px', right: '-4px', cursor: 'ne-resize' },\r\n nw: { top: '-4px', left: '-4px', cursor: 'nw-resize' },\r\n se: { bottom: '-4px', right: '-4px', cursor: 'se-resize' },\r\n sw: { bottom: '-4px', left: '-4px', cursor: 'sw-resize' },\r\n };\r\n\r\n return handles.map((handle) => (\r\n <div\r\n key={handle}\r\n className={`resize-handle resize-handle-${handle}`}\r\n style={{ ...handleStyle, ...positions[handle] }}\r\n data-handle={handle}\r\n />\r\n ));\r\n };\r\n\r\n // Render a single field\r\n const renderField = (field: FieldMapping) => {\r\n const posStyle = positionToStyle(field.position);\r\n const fieldStyle = fieldStyleToCSS(field.style);\r\n const isSelected = field.id === selectedFieldId;\r\n\r\n const combinedStyle: React.CSSProperties = {\r\n ...posStyle,\r\n ...fieldStyle,\r\n zIndex: field.zIndex || 1,\r\n boxSizing: 'border-box',\r\n overflow: 'hidden',\r\n cursor: editable ? 'move' : 'default',\r\n outline: isSelected ? '2px solid #2196F3' : 'none',\r\n outlineOffset: '1px',\r\n };\r\n\r\n const handleClick = (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n onFieldSelect?.(field);\r\n };\r\n\r\n const value = data[field.fieldKey];\r\n\r\n const content = (() => {\r\n switch (field.type) {\r\n case 'text':\r\n return (\r\n <>\r\n {field.label && (\r\n <span style={{ fontSize: '0.75em', display: 'block', opacity: 0.7 }}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </>\r\n );\r\n\r\n case 'label':\r\n return <span>{field.staticText || field.label || 'Label'}</span>;\r\n\r\n case 'image':\r\n return value ? (\r\n <img\r\n src={String(value)}\r\n alt={field.label || 'Image'}\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover',\r\n objectPosition: 'center top',\r\n }}\r\n />\r\n ) : (\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n backgroundColor: '#e0e0e0',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '10px',\r\n color: '#666',\r\n flexDirection: 'column',\r\n }}\r\n >\r\n <span>📷</span>\r\n <span>{field.label || 'Photo'}</span>\r\n </div>\r\n );\r\n\r\n case 'qrcode':\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, 200)\r\n : '';\r\n\r\n return qrDataUrl ? (\r\n <img\r\n src={qrDataUrl}\r\n alt=\"QR Code\"\r\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\r\n />\r\n ) : (\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n backgroundColor: '#f0f0f0',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '10px',\r\n color: '#666',\r\n border: '1px dashed #ccc',\r\n }}\r\n >\r\n QR Code\r\n </div>\r\n );\r\n\r\n default:\r\n return null;\r\n }\r\n })();\r\n\r\n return (\r\n <div\r\n key={field.id}\r\n id={`preview-${field.id}`}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className={`preview-field preview-field-${field.type} ${isSelected ? 'selected' : ''}`}\r\n >\r\n {content}\r\n {renderResizeHandles(field)}\r\n </div>\r\n );\r\n };\r\n\r\n // Card container style\r\n const cardStyle: React.CSSProperties = {\r\n width: template.cardSize.width,\r\n height: template.cardSize.height,\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: backgroundImage ? 'transparent' : '#f5f5f5',\r\n border: '1px solid #ddd',\r\n transform: `scale(${scale})`,\r\n transformOrigin: 'top left',\r\n };\r\n\r\n // Grid overlay style\r\n const gridStyle: React.CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n backgroundImage: showGrid\r\n ? 'linear-gradient(to right, rgba(0,0,0,0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.05) 1px, transparent 1px)'\r\n : 'none',\r\n backgroundSize: '10px 10px',\r\n pointerEvents: 'none',\r\n zIndex: 999,\r\n };\r\n\r\n const handleContainerClick = () => {\r\n onFieldSelect?.(null);\r\n };\r\n\r\n return (\r\n <div\r\n className=\"idcard-preview-container\"\r\n style={cardStyle}\r\n onClick={handleContainerClick}\r\n >\r\n {/* Background */}\r\n {backgroundImage && (\r\n <img\r\n src={backgroundImage}\r\n alt={`${side} background`}\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover',\r\n zIndex: 0,\r\n pointerEvents: 'none',\r\n }}\r\n />\r\n )}\r\n\r\n {/* Fields */}\r\n {fieldsToRender.map(renderField)}\r\n\r\n {/* Grid overlay */}\r\n {showGrid && <div style={gridStyle} />}\r\n\r\n {/* Empty state */}\r\n {!backgroundImage && fieldsToRender.length === 0 && (\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: '50%',\r\n left: '50%',\r\n transform: 'translate(-50%, -50%)',\r\n textAlign: 'center',\r\n color: '#999',\r\n fontSize: '14px',\r\n }}\r\n >\r\n <p>Upload a background image</p>\r\n <p>and add fields to get started</p>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -29,25 +29,42 @@ function useIDCardTemplate(initialTemplate) {
|
|
|
29
29
|
}, []);
|
|
30
30
|
// Update specific properties of a field
|
|
31
31
|
const updateField = useCallback((fieldId, updates) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
if (!fieldId || !updates)
|
|
33
|
+
return;
|
|
34
|
+
setTemplateState((prev) => {
|
|
35
|
+
const fieldExists = prev.fields.some((field) => field?.id === fieldId);
|
|
36
|
+
if (!fieldExists)
|
|
37
|
+
return prev;
|
|
38
|
+
return {
|
|
39
|
+
...prev,
|
|
40
|
+
updatedAt: new Date().toISOString(),
|
|
41
|
+
fields: prev.fields.map((field) => field?.id === fieldId ? { ...field, ...updates } : field).filter(Boolean),
|
|
42
|
+
};
|
|
43
|
+
});
|
|
37
44
|
}, []);
|
|
38
45
|
// Add a new field to the template
|
|
39
46
|
const addField = useCallback((field) => {
|
|
47
|
+
if (!field || !field.type || !field.position) {
|
|
48
|
+
console.warn('Invalid field object provided to addField:', field);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const validField = {
|
|
52
|
+
...field,
|
|
53
|
+
id: field.id || generateId('field'),
|
|
54
|
+
};
|
|
40
55
|
setTemplateState((prev) => ({
|
|
41
56
|
...prev,
|
|
42
57
|
updatedAt: new Date().toISOString(),
|
|
43
|
-
fields: [...prev.fields
|
|
58
|
+
fields: [...prev.fields.filter(Boolean), validField],
|
|
44
59
|
}));
|
|
45
60
|
}, []);
|
|
46
61
|
const removeField = useCallback((fieldId) => {
|
|
62
|
+
if (!fieldId)
|
|
63
|
+
return;
|
|
47
64
|
setTemplateState((prev) => ({
|
|
48
65
|
...prev,
|
|
49
66
|
updatedAt: new Date().toISOString(),
|
|
50
|
-
fields: prev.fields.filter((field) => field.id !== fieldId),
|
|
67
|
+
fields: prev.fields.filter((field) => field?.id && field.id !== fieldId),
|
|
51
68
|
}));
|
|
52
69
|
}, []);
|
|
53
70
|
const setBackground = useCallback((side, imageData) => {
|
|
@@ -94,9 +111,11 @@ function useIDCardTemplate(initialTemplate) {
|
|
|
94
111
|
}));
|
|
95
112
|
}, []);
|
|
96
113
|
const duplicateField = useCallback((fieldId) => {
|
|
114
|
+
if (!fieldId)
|
|
115
|
+
return;
|
|
97
116
|
setTemplateState((prev) => {
|
|
98
|
-
const field = prev.fields.find((f) => f
|
|
99
|
-
if (!field)
|
|
117
|
+
const field = prev.fields.find((f) => f?.id === fieldId);
|
|
118
|
+
if (!field || !field.position)
|
|
100
119
|
return prev;
|
|
101
120
|
const newField = {
|
|
102
121
|
...field,
|
|
@@ -110,15 +129,17 @@ function useIDCardTemplate(initialTemplate) {
|
|
|
110
129
|
return {
|
|
111
130
|
...prev,
|
|
112
131
|
updatedAt: new Date().toISOString(),
|
|
113
|
-
fields: [...prev.fields, newField],
|
|
132
|
+
fields: [...prev.fields.filter(Boolean), newField],
|
|
114
133
|
};
|
|
115
134
|
});
|
|
116
135
|
}, []);
|
|
117
136
|
const moveFieldToSide = useCallback((fieldId, side) => {
|
|
137
|
+
if (!fieldId || !side)
|
|
138
|
+
return;
|
|
118
139
|
setTemplateState((prev) => ({
|
|
119
140
|
...prev,
|
|
120
141
|
updatedAt: new Date().toISOString(),
|
|
121
|
-
fields: prev.fields.map((field) => field
|
|
142
|
+
fields: prev.fields.map((field) => field?.id === fieldId ? { ...field, side } : field).filter(Boolean),
|
|
122
143
|
}));
|
|
123
144
|
}, []);
|
|
124
145
|
const reset = useCallback(() => {
|
|
@@ -131,8 +152,16 @@ function useIDCardTemplate(initialTemplate) {
|
|
|
131
152
|
validationErrors: errors.map((e) => `${e.field}: ${e.message}`),
|
|
132
153
|
};
|
|
133
154
|
}, [template]);
|
|
155
|
+
// Ensure template always has valid fields array
|
|
156
|
+
const safeTemplate = useMemo(() => ({
|
|
157
|
+
...template,
|
|
158
|
+
fields: template.fields.filter((field) => Boolean(field) &&
|
|
159
|
+
Boolean(field.id) &&
|
|
160
|
+
Boolean(field.type) &&
|
|
161
|
+
Boolean(field.position)),
|
|
162
|
+
}), [template]);
|
|
134
163
|
return {
|
|
135
|
-
template,
|
|
164
|
+
template: safeTemplate,
|
|
136
165
|
setTemplate,
|
|
137
166
|
updateField,
|
|
138
167
|
addField,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useIDCardTemplate.js","sources":["../../../src/hooks/useIDCardTemplate.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\r\nimport type {\r\n IDCardTemplate,\r\n FieldMapping,\r\n CardSize,\r\n CardOrientation,\r\n CardSides,\r\n UseIDCardTemplateReturn,\r\n} from '../types';\r\nimport { createDefaultTemplate, generateId } from '../storage/templateStorage';\r\nimport { validateTemplate } from '../utils/validators';\r\n\r\n/**\r\n * Hook for managing ID card template state\r\n * Provides methods for updating fields, backgrounds, and card properties\r\n * Automatically updates the template's updatedAt timestamp on changes\r\n * \r\n * @param initialTemplate - Optional existing template to start with\r\n * @returns Template state and helper methods\r\n */\r\nexport function useIDCardTemplate(\r\n initialTemplate?: Partial<IDCardTemplate>\r\n): UseIDCardTemplateReturn {\r\n const [template, setTemplateState] = useState<IDCardTemplate>(() => {\r\n if (initialTemplate) {\r\n return {\r\n ...createDefaultTemplate(),\r\n ...initialTemplate,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n }\r\n return createDefaultTemplate();\r\n });\r\n\r\n const setTemplate = useCallback((newTemplate: IDCardTemplate) => {\r\n setTemplateState({\r\n ...newTemplate,\r\n updatedAt: new Date().toISOString(),\r\n });\r\n }, []);\r\n\r\n // Update specific properties of a field\r\n const updateField = useCallback((fieldId: string, updates: Partial<FieldMapping>) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.map((field: FieldMapping) =>\r\n field.id === fieldId ? { ...field, ...updates } : field\r\n ),\r\n }));\r\n }, []);\r\n\r\n // Add a new field to the template\r\n const addField = useCallback((field: FieldMapping) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: [...prev.fields, { ...field, id: field.id || generateId('field') }],\r\n }));\r\n }, []);\r\n\r\n const removeField = useCallback((fieldId: string) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.filter((field: FieldMapping) => field.id !== fieldId),\r\n }));\r\n }, []);\r\n\r\n const setBackground = useCallback((side: 'front' | 'back', imageData: string) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n backgrounds: {\r\n ...prev.backgrounds,\r\n [side]: imageData,\r\n },\r\n }));\r\n }, []);\r\n\r\n const setCardSize = useCallback((size: CardSize) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n cardSize: size,\r\n }));\r\n }, []);\r\n\r\n const setOrientation = useCallback((orientation: CardOrientation) => {\r\n setTemplateState((prev: IDCardTemplate) => {\r\n // Swap dimensions if orientation changes\r\n const shouldSwap =\r\n (orientation === 'portrait' && prev.cardSize.width > prev.cardSize.height) ||\r\n (orientation === 'landscape' && prev.cardSize.height > prev.cardSize.width);\r\n\r\n return {\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n orientation,\r\n cardSize: shouldSwap\r\n ? {\r\n ...prev.cardSize,\r\n width: prev.cardSize.height,\r\n height: prev.cardSize.width,\r\n }\r\n : prev.cardSize,\r\n };\r\n });\r\n }, []);\r\n\r\n const setSides = useCallback((sides: CardSides) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n sides,\r\n }));\r\n }, []);\r\n\r\n const duplicateField = useCallback((fieldId: string) => {\r\n setTemplateState((prev: IDCardTemplate) => {\r\n const field = prev.fields.find((f: FieldMapping) => f.id === fieldId);\r\n if (!field) return prev;\r\n\r\n const newField: FieldMapping = {\r\n ...field,\r\n id: generateId('field'),\r\n position: {\r\n ...field.position,\r\n x: field.position.x + 10,\r\n y: field.position.y + 10,\r\n },\r\n };\r\n\r\n return {\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: [...prev.fields, newField],\r\n };\r\n });\r\n }, []);\r\n\r\n const moveFieldToSide = useCallback((fieldId: string, side: 'front' | 'back') => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.map((field: FieldMapping) =>\r\n field.id === fieldId ? { ...field, side } : field\r\n ),\r\n }));\r\n }, []);\r\n\r\n const reset = useCallback(() => {\r\n setTemplateState(createDefaultTemplate());\r\n }, []);\r\n\r\n const validationResult = useMemo(() => {\r\n const errors = validateTemplate(template);\r\n return {\r\n isValid: errors.length === 0,\r\n validationErrors: errors.map((e) => `${e.field}: ${e.message}`),\r\n };\r\n }, [template]);\r\n\r\n return {\r\n template,\r\n setTemplate,\r\n updateField,\r\n addField,\r\n removeField,\r\n setBackground,\r\n setCardSize,\r\n setOrientation,\r\n setSides,\r\n duplicateField,\r\n moveFieldToSide,\r\n reset,\r\n isValid: validationResult.isValid,\r\n validationErrors: validationResult.validationErrors,\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useIDCardTemplate.js","sources":["../../../src/hooks/useIDCardTemplate.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\r\nimport type {\r\n IDCardTemplate,\r\n FieldMapping,\r\n CardSize,\r\n CardOrientation,\r\n CardSides,\r\n UseIDCardTemplateReturn,\r\n} from '../types';\r\nimport { createDefaultTemplate, generateId } from '../storage/templateStorage';\r\nimport { validateTemplate } from '../utils/validators';\r\n\r\n/**\r\n * Hook for managing ID card template state\r\n * Provides methods for updating fields, backgrounds, and card properties\r\n * Automatically updates the template's updatedAt timestamp on changes\r\n * \r\n * @param initialTemplate - Optional existing template to start with\r\n * @returns Template state and helper methods\r\n */\r\nexport function useIDCardTemplate(\r\n initialTemplate?: Partial<IDCardTemplate>\r\n): UseIDCardTemplateReturn {\r\n const [template, setTemplateState] = useState<IDCardTemplate>(() => {\r\n if (initialTemplate) {\r\n return {\r\n ...createDefaultTemplate(),\r\n ...initialTemplate,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n }\r\n return createDefaultTemplate();\r\n });\r\n\r\n const setTemplate = useCallback((newTemplate: IDCardTemplate) => {\r\n setTemplateState({\r\n ...newTemplate,\r\n updatedAt: new Date().toISOString(),\r\n });\r\n }, []);\r\n\r\n // Update specific properties of a field\r\n const updateField = useCallback((fieldId: string, updates: Partial<FieldMapping>) => {\r\n if (!fieldId || !updates) return;\r\n \r\n setTemplateState((prev: IDCardTemplate) => {\r\n const fieldExists = prev.fields.some((field: FieldMapping) => field?.id === fieldId);\r\n if (!fieldExists) return prev;\r\n \r\n return {\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.map((field: FieldMapping) =>\r\n field?.id === fieldId ? { ...field, ...updates } : field\r\n ).filter(Boolean),\r\n };\r\n });\r\n }, []);\r\n\r\n // Add a new field to the template\r\n const addField = useCallback((field: FieldMapping) => {\r\n if (!field || !field.type || !field.position) {\r\n console.warn('Invalid field object provided to addField:', field);\r\n return;\r\n }\r\n \r\n const validField = {\r\n ...field,\r\n id: field.id || generateId('field'),\r\n };\r\n \r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: [...prev.fields.filter(Boolean), validField],\r\n }));\r\n }, []);\r\n\r\n const removeField = useCallback((fieldId: string) => {\r\n if (!fieldId) return;\r\n \r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.filter((field: FieldMapping) => field?.id && field.id !== fieldId),\r\n }));\r\n }, []);\r\n\r\n const setBackground = useCallback((side: 'front' | 'back', imageData: string) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n backgrounds: {\r\n ...prev.backgrounds,\r\n [side]: imageData,\r\n },\r\n }));\r\n }, []);\r\n\r\n const setCardSize = useCallback((size: CardSize) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n cardSize: size,\r\n }));\r\n }, []);\r\n\r\n const setOrientation = useCallback((orientation: CardOrientation) => {\r\n setTemplateState((prev: IDCardTemplate) => {\r\n // Swap dimensions if orientation changes\r\n const shouldSwap =\r\n (orientation === 'portrait' && prev.cardSize.width > prev.cardSize.height) ||\r\n (orientation === 'landscape' && prev.cardSize.height > prev.cardSize.width);\r\n\r\n return {\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n orientation,\r\n cardSize: shouldSwap\r\n ? {\r\n ...prev.cardSize,\r\n width: prev.cardSize.height,\r\n height: prev.cardSize.width,\r\n }\r\n : prev.cardSize,\r\n };\r\n });\r\n }, []);\r\n\r\n const setSides = useCallback((sides: CardSides) => {\r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n sides,\r\n }));\r\n }, []);\r\n\r\n const duplicateField = useCallback((fieldId: string) => {\r\n if (!fieldId) return;\r\n \r\n setTemplateState((prev: IDCardTemplate) => {\r\n const field = prev.fields.find((f: FieldMapping) => f?.id === fieldId);\r\n if (!field || !field.position) return prev;\r\n\r\n const newField: FieldMapping = {\r\n ...field,\r\n id: generateId('field'),\r\n position: {\r\n ...field.position,\r\n x: field.position.x + 10,\r\n y: field.position.y + 10,\r\n },\r\n };\r\n\r\n return {\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: [...prev.fields.filter(Boolean), newField],\r\n };\r\n });\r\n }, []);\r\n\r\n const moveFieldToSide = useCallback((fieldId: string, side: 'front' | 'back') => {\r\n if (!fieldId || !side) return;\r\n \r\n setTemplateState((prev: IDCardTemplate) => ({\r\n ...prev,\r\n updatedAt: new Date().toISOString(),\r\n fields: prev.fields.map((field: FieldMapping) =>\r\n field?.id === fieldId ? { ...field, side } : field\r\n ).filter(Boolean),\r\n }));\r\n }, []);\r\n\r\n const reset = useCallback(() => {\r\n setTemplateState(createDefaultTemplate());\r\n }, []);\r\n\r\n const validationResult = useMemo(() => {\r\n const errors = validateTemplate(template);\r\n return {\r\n isValid: errors.length === 0,\r\n validationErrors: errors.map((e) => `${e.field}: ${e.message}`),\r\n };\r\n }, [template]);\r\n\r\n // Ensure template always has valid fields array\r\n const safeTemplate = useMemo(() => ({\r\n ...template,\r\n fields: template.fields.filter((field): field is FieldMapping => \r\n Boolean(field) && \r\n Boolean(field.id) && \r\n Boolean(field.type) && \r\n Boolean(field.position)\r\n ),\r\n }), [template]);\r\n\r\n return {\r\n template: safeTemplate,\r\n setTemplate,\r\n updateField,\r\n addField,\r\n removeField,\r\n setBackground,\r\n setCardSize,\r\n setOrientation,\r\n setSides,\r\n duplicateField,\r\n moveFieldToSide,\r\n reset,\r\n isValid: validationResult.isValid,\r\n validationErrors: validationResult.validationErrors,\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Recursively removes all properties with value undefined from an object or array.
|
|
2
|
+
function deepCleanUndefined(obj) {
|
|
3
|
+
if (Array.isArray(obj)) {
|
|
4
|
+
return obj.map(deepCleanUndefined).filter(v => v !== undefined);
|
|
5
|
+
}
|
|
6
|
+
else if (obj && typeof obj === 'object') {
|
|
7
|
+
const cleaned = {};
|
|
8
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
9
|
+
if (value !== undefined) {
|
|
10
|
+
cleaned[key] = deepCleanUndefined(value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return cleaned;
|
|
14
|
+
}
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { deepCleanUndefined };
|
|
19
|
+
//# sourceMappingURL=deepCleanUndefined.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepCleanUndefined.js","sources":["../../../src/utils/deepCleanUndefined.ts"],"sourcesContent":["// Recursively removes all properties with value undefined from an object or array.\r\nexport function deepCleanUndefined<T>(obj: T): T {\r\n if (Array.isArray(obj)) {\r\n return obj.map(deepCleanUndefined).filter(v => v !== undefined) as unknown as T;\r\n } else if (obj && typeof obj === 'object') {\r\n const cleaned: any = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (value !== undefined) {\r\n cleaned[key] = deepCleanUndefined(value);\r\n }\r\n }\r\n return cleaned;\r\n }\r\n return obj;\r\n}\r\n"],"names":[],"mappings":"AAAA;AACM,SAAU,kBAAkB,CAAI,GAAM,EAAA;AAC1C,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACtB,QAAA,OAAO,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS,CAAiB;IACjF;AAAO,SAAA,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACzC,MAAM,OAAO,GAAQ,EAAE;AACvB,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AAC9C,YAAA,IAAI,KAAK,KAAK,SAAS,EAAE;gBACvB,OAAO,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC;YAC1C;QACF;AACA,QAAA,OAAO,OAAO;IAChB;AACA,IAAA,OAAO,GAAG;AACZ;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function deepCleanUndefined<T>(obj: T): T;
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-id-card-generator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A flexible React library for designing, configuring, and generating ID cards with drag-and-drop field positioning",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"module": "dist/esm/index.js",
|
|
7
8
|
"types": "dist/types/index.d.ts",
|
|
8
9
|
"exports": {
|