react-id-card-generator 1.0.14 → 1.0.16

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.
@@ -30,7 +30,52 @@ const IDCardGenerator = ({ template, data, side = 'front', scale = 1, className
30
30
  // Render a single field
31
31
  const renderField = (field) => {
32
32
  const posStyle = styleUtils.positionToStyle(field.position);
33
- const fieldStyle = styleUtils.fieldStyleToCSS(field.style);
33
+ let fieldStyle = styleUtils.fieldStyleToCSS(field.style);
34
+ // Determine flex direction and alignment for text fields
35
+ let flexDirection = 'column';
36
+ if (field.type === 'text' && field.style?.labelPosition === 'left')
37
+ flexDirection = 'row';
38
+ // Map verticalAlign and textAlign to flex properties
39
+ let justifyContent = 'flex-start';
40
+ let alignItems = 'flex-start';
41
+ if (field.type === 'text') {
42
+ const textAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';
43
+ const verticalAlign = field.style?.verticalAlign || 'top';
44
+ if (flexDirection === 'column') {
45
+ // For column: verticalAlign controls justifyContent (vertical), textAlign controls alignItems (horizontal)
46
+ if (verticalAlign === 'middle')
47
+ justifyContent = 'center';
48
+ else if (verticalAlign === 'bottom')
49
+ justifyContent = 'flex-end';
50
+ else
51
+ justifyContent = 'flex-start';
52
+ if (textAlign === 'center')
53
+ alignItems = 'center';
54
+ else if (textAlign === 'right')
55
+ alignItems = 'flex-end';
56
+ else
57
+ alignItems = 'flex-start';
58
+ }
59
+ else {
60
+ // For row: verticalAlign controls alignItems (vertical)
61
+ if (verticalAlign === 'middle')
62
+ alignItems = 'center';
63
+ else if (verticalAlign === 'bottom')
64
+ alignItems = 'flex-end';
65
+ else
66
+ alignItems = 'flex-start';
67
+ }
68
+ }
69
+ // Remove fontSize for label fields so text field font size does not affect them
70
+ if (field.type === 'label' && fieldStyle.fontSize) {
71
+ const { fontSize, ...rest } = fieldStyle;
72
+ fieldStyle = rest;
73
+ }
74
+ // Remove textTransform from container for text and label fields - applied directly to spans
75
+ if ((field.type === 'text' || field.type === 'label') && fieldStyle.textTransform) {
76
+ const { textTransform, ...rest } = fieldStyle;
77
+ fieldStyle = rest;
78
+ }
34
79
  const combinedStyle = {
35
80
  ...posStyle,
36
81
  ...fieldStyle,
@@ -38,6 +83,10 @@ const IDCardGenerator = ({ template, data, side = 'front', scale = 1, className
38
83
  boxSizing: 'border-box',
39
84
  overflow: 'hidden',
40
85
  cursor: editable ? 'pointer' : 'default',
86
+ display: field.type === 'text' ? 'flex' : undefined,
87
+ flexDirection: field.type === 'text' ? flexDirection : undefined,
88
+ justifyContent: field.type === 'text' ? justifyContent : undefined,
89
+ alignItems: field.type === 'text' ? alignItems : undefined,
41
90
  };
42
91
  const handleClick = (e) => {
43
92
  if (onFieldClick) {
@@ -47,21 +96,90 @@ const IDCardGenerator = ({ template, data, side = 'front', scale = 1, className
47
96
  };
48
97
  const value = getFieldValue(field, data);
49
98
  switch (field.type) {
50
- case 'text':
51
- return (jsxRuntime.jsxs("div", { id: field.id, style: combinedStyle, onClick: handleClick, className: "idcard-field idcard-field-text", children: [field.label && (jsxRuntime.jsx("span", { className: "idcard-field-label", style: { fontSize: '0.8em', display: 'block' }, children: field.label })), jsxRuntime.jsx("span", { className: "idcard-field-value", children: String(value || field.placeholder || '') })] }, field.id));
52
- case 'label':
53
- return (jsxRuntime.jsx("div", { id: field.id, style: combinedStyle, onClick: handleClick, className: "idcard-field idcard-field-label", children: field.staticText || field.label || '' }, field.id));
99
+ case 'text': {
100
+ // Label style properties
101
+ let labelFontSize = field.style?.labelFontSize;
102
+ if (!labelFontSize || labelFontSize === '0.75em') {
103
+ labelFontSize = '12px';
104
+ }
105
+ else if (!labelFontSize.endsWith('px')) {
106
+ const num = parseFloat(labelFontSize);
107
+ if (!isNaN(num))
108
+ labelFontSize = num + 'px';
109
+ else
110
+ labelFontSize = '12px';
111
+ }
112
+ const labelFontWeight = field.style?.labelFontWeight || 'normal';
113
+ const labelColor = field.style?.labelColor || '#666666';
114
+ const labelTextTransform = field.style?.labelTextTransform || 'none';
115
+ const labelTextAlign = field.style?.labelTextAlign || 'left';
116
+ // Text/value style properties (separate from label)
117
+ const textFontSize = field.style?.textFontSize || field.style?.fontSize || '1em';
118
+ const textFontWeight = field.style?.textFontWeight || field.style?.fontWeight || 'normal';
119
+ const textColor = field.style?.textColor || field.style?.color || '#000000';
120
+ const textTextTransform = field.style?.textTransform || 'none';
121
+ const textTextAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';
122
+ // For row layout (label on left), use individual span alignment
123
+ if (field.style?.labelPosition === 'left') {
124
+ let labelAlignSelf = 'flex-start';
125
+ if (field.style?.labelVerticalAlign === 'middle')
126
+ labelAlignSelf = 'center';
127
+ else if (field.style?.labelVerticalAlign === 'bottom')
128
+ labelAlignSelf = 'flex-end';
129
+ let textAlignSelf = 'flex-start';
130
+ if (field.style?.textVerticalAlign === 'middle')
131
+ textAlignSelf = 'center';
132
+ else if (field.style?.textVerticalAlign === 'bottom')
133
+ textAlignSelf = 'flex-end';
134
+ const labelStyle = {
135
+ fontSize: labelFontSize,
136
+ fontWeight: labelFontWeight,
137
+ color: labelColor,
138
+ opacity: 0.7,
139
+ marginRight: 8,
140
+ alignSelf: labelAlignSelf,
141
+ whiteSpace: 'nowrap',
142
+ textTransform: labelTextTransform
143
+ };
144
+ const textStyle = {
145
+ textTransform: textTextTransform,
146
+ fontSize: textFontSize,
147
+ fontWeight: textFontWeight,
148
+ color: textColor,
149
+ alignSelf: textAlignSelf
150
+ };
151
+ return (jsxRuntime.jsxs("div", { id: field.id, style: combinedStyle, onClick: handleClick, className: "idcard-field idcard-field-text", children: [field.label && (jsxRuntime.jsx("span", { className: "idcard-field-label", style: labelStyle, children: field.label })), jsxRuntime.jsx("span", { style: { width: '100%', textAlign: textTextAlign }, children: jsxRuntime.jsx("span", { className: "idcard-field-value", style: textStyle, children: String(value || field.placeholder || '') }) })] }, field.id));
152
+ }
153
+ else {
154
+ // For column layout (label on top), let container alignment handle positioning
155
+ const labelStyle = {
156
+ fontSize: labelFontSize,
157
+ fontWeight: labelFontWeight,
158
+ color: labelColor,
159
+ opacity: 0.7,
160
+ textTransform: labelTextTransform,
161
+ width: '100%',
162
+ textAlign: labelTextAlign
163
+ };
164
+ const textStyle = {
165
+ textTransform: textTextTransform,
166
+ fontSize: textFontSize,
167
+ fontWeight: textFontWeight,
168
+ color: textColor,
169
+ width: '100%',
170
+ textAlign: textTextAlign
171
+ };
172
+ return (jsxRuntime.jsxs("div", { id: field.id, style: combinedStyle, onClick: handleClick, className: "idcard-field idcard-field-text", children: [field.label && (jsxRuntime.jsx("span", { className: "idcard-field-label", style: labelStyle, children: field.label })), jsxRuntime.jsx("span", { className: "idcard-field-value", style: textStyle, children: String(value || field.placeholder || '') })] }, field.id));
173
+ }
174
+ }
175
+ case 'label': {
176
+ const labelTextTransform = field.style?.labelTextTransform || 'none';
177
+ return (jsxRuntime.jsx("div", { id: field.id, style: combinedStyle, onClick: handleClick, className: "idcard-field idcard-field-label", children: jsxRuntime.jsx("span", { style: { textTransform: labelTextTransform }, children: field.staticText || field.label || '' }) }, field.id));
178
+ }
54
179
  case 'image':
55
- return (jsxRuntime.jsx("div", { id: field.id, style: {
56
- ...combinedStyle,
57
- display: 'flex',
58
- alignItems: 'center',
59
- justifyContent: 'center',
60
- }, onClick: handleClick, className: "idcard-field idcard-field-image", children: value ? (jsxRuntime.jsx("img", { src: String(value), alt: field.label || 'Image', style: {
180
+ return (jsxRuntime.jsx("div", { id: field.id, style: combinedStyle, onClick: handleClick, children: value ? (jsxRuntime.jsx("img", { src: String(value), alt: field.label || 'Image', style: {
61
181
  width: '100%',
62
- height: '100%',
63
- objectFit: 'cover',
64
- objectPosition: 'center top',
182
+ display: 'block',
65
183
  } })) : (jsxRuntime.jsx("div", { style: {
66
184
  width: '100%',
67
185
  height: '100%',
@@ -79,10 +197,7 @@ const IDCardGenerator = ({ template, data, side = 'front', scale = 1, className
79
197
  return (jsxRuntime.jsx("div", { id: field.id, style: {
80
198
  ...combinedStyle,
81
199
  backgroundColor: '#fff',
82
- display: 'flex',
83
- alignItems: 'center',
84
- justifyContent: 'center',
85
- }, onClick: handleClick, className: "idcard-field idcard-field-qrcode", children: qrDataUrl ? (jsxRuntime.jsx("img", { src: qrDataUrl, alt: "QR Code", style: { width: '100%', height: '100%', objectFit: 'contain' } })) : (jsxRuntime.jsx("div", { style: {
200
+ }, onClick: handleClick, className: "idcard-field idcard-field-qrcode", children: qrDataUrl ? (jsxRuntime.jsx("img", { src: qrDataUrl, alt: "QR Code", style: { width: '100%', height: '100%' } })) : (jsxRuntime.jsx("div", { style: {
86
201
  width: '100%',
87
202
  height: '100%',
88
203
  backgroundColor: '#f0f0f0',
@@ -98,22 +213,19 @@ const IDCardGenerator = ({ template, data, side = 'front', scale = 1, className
98
213
  };
99
214
  // Card container style
100
215
  const cardStyle = {
101
- width: template.cardSize.width * scale,
102
- height: template.cardSize.height * scale,
216
+ width: Math.round(template.cardSize.width),
217
+ height: Math.round(template.cardSize.height),
103
218
  position: 'relative',
104
219
  overflow: 'hidden',
105
220
  backgroundColor: '#fff',
106
- transform: `scale(${scale})`,
107
- transformOrigin: 'top left',
108
221
  ...style,
109
222
  };
110
223
  return (jsxRuntime.jsxs("div", { id: side === 'front' ? 'idcardfront' : 'idcardback', className: `idcard-container idcard-${side} ${className}`, style: cardStyle, children: [backgroundImage && (jsxRuntime.jsx("img", { src: backgroundImage, alt: `${side} background`, style: {
111
224
  position: 'absolute',
112
225
  top: 0,
113
226
  left: 0,
114
- width: '100%',
115
- height: '100%',
116
- objectFit: 'cover',
227
+ width: `${Math.round(template.cardSize.width)}px`,
228
+ height: `${Math.round(template.cardSize.height)}px`,
117
229
  zIndex: 0,
118
230
  } })), fieldsToRender.map(renderField)] }));
119
231
  };
@@ -1 +1 @@
1
- {"version":3,"file":"IDCardGenerator.js","sources":["../../../src/components/IDCardGenerator.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\r\nimport type { IDCardGeneratorProps, FieldMapping, IDCardData, IDCardTemplate } from '../types';\r\nimport { fieldStyleToCSS, positionToStyle } from '../utils/styleUtils';\r\nimport { generateQrCodeFromFields } from '../core/qrUtils';\r\n\r\n/**\r\n * IDCardGenerator - Renders a completed ID card\r\n * \r\n * Takes a template and user data, then renders the filled card.\r\n * This is the component used to display actual ID cards for individual users.\r\n * \r\n * Example:\r\n * ```tsx\r\n * <IDCardGenerator \r\n * template={myTemplate}\r\n * data={{ name: 'John Doe', photo: '...' }}\r\n * side=\"front\"\r\n * />\r\n * ```\r\n */\r\nexport const IDCardGenerator: React.FC<IDCardGeneratorProps> = ({\r\n template,\r\n data,\r\n side = 'front',\r\n scale = 1,\r\n className = '',\r\n style = {},\r\n onFieldClick,\r\n editable = false,\r\n}: IDCardGeneratorProps) => {\r\n // Get fields for the current side only\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 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 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 ? 'pointer' : 'default',\r\n };\r\n\r\n const handleClick = (e: React.MouseEvent) => {\r\n if (onFieldClick) {\r\n e.stopPropagation();\r\n onFieldClick(field);\r\n }\r\n };\r\n\r\n const value = getFieldValue(field, data);\r\n\r\n switch (field.type) {\r\n case 'text':\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-text\"\r\n >\r\n {field.label && (\r\n <span className=\"idcard-field-label\" style={{ fontSize: '0.8em', display: 'block' }}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span className=\"idcard-field-value\">{String(value || field.placeholder || '')}</span>\r\n </div>\r\n );\r\n\r\n case 'label':\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-label\"\r\n >\r\n {field.staticText || field.label || ''}\r\n </div>\r\n );\r\n\r\n case 'image':\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={{\r\n ...combinedStyle,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n }}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-image\"\r\n >\r\n {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 }}\r\n >\r\n {field.label || 'Photo'}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n\r\n case 'qrcode':\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, Math.min(field.position.width, field.position.height) * 2)\r\n : '';\r\n\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={{\r\n ...combinedStyle,\r\n backgroundColor: '#fff',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n }}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-qrcode\"\r\n >\r\n {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 }}\r\n >\r\n QR Code\r\n </div>\r\n )}\r\n </div>\r\n );\r\n\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n // Card container style\r\n const cardStyle: React.CSSProperties = {\r\n width: template.cardSize.width * scale,\r\n height: template.cardSize.height * scale,\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: '#fff',\r\n transform: `scale(${scale})`,\r\n transformOrigin: 'top left',\r\n ...style,\r\n };\r\n\r\n return (\r\n <div\r\n id={side === 'front' ? 'idcardfront' : 'idcardback'}\r\n className={`idcard-container idcard-${side} ${className}`}\r\n style={cardStyle}\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 }}\r\n />\r\n )}\r\n\r\n {/* Fields */}\r\n {fieldsToRender.map(renderField)}\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Get field value from data based on field configuration\r\n */\r\nfunction getFieldValue(field: FieldMapping, data: IDCardData): string | number | undefined {\r\n if (field.type === 'label') {\r\n return field.staticText;\r\n }\r\n\r\n const value = data[field.fieldKey];\r\n\r\n // Handle array values (like department)\r\n if (Array.isArray(value)) {\r\n return value[0];\r\n }\r\n\r\n return value as string | number | undefined;\r\n}\r\n\r\n"],"names":["useMemo","positionToStyle","fieldStyleToCSS","_jsxs","_jsx","generateQrCodeFromFields"],"mappings":";;;;;;;AAKA;;;;;;;;;;;;;;AAcG;AACI,MAAM,eAAe,GAAmC,CAAC,EAC9D,QAAQ,EACR,IAAI,EACJ,IAAI,GAAG,OAAO,EACd,KAAK,GAAG,CAAC,EACT,SAAS,GAAG,EAAE,EACd,KAAK,GAAG,EAAE,EACV,YAAY,EACZ,QAAQ,GAAG,KAAK,GACK,KAAI;;AAEzB,IAAA,MAAM,cAAc,GAAGA,aAAO,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,WAAW,GAAG,CAAC,KAAmB,KAAI;QAC1C,MAAM,QAAQ,GAAGC,0BAAe,CAAC,KAAK,CAAC,QAAQ,CAAC;QAChD,MAAM,UAAU,GAAGC,0BAAe,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/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,SAAS,GAAG,SAAS;SACzC;AAED,QAAA,MAAM,WAAW,GAAG,CAAC,CAAmB,KAAI;YAC1C,IAAI,YAAY,EAAE;gBAChB,CAAC,CAAC,eAAe,EAAE;gBACnB,YAAY,CAAC,KAAK,CAAC;YACrB;AACF,QAAA,CAAC;QAED,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC;AAExC,QAAA,QAAQ,KAAK,CAAC,IAAI;AAChB,YAAA,KAAK,MAAM;AACT,gBAAA,QACEC,eAAA,CAAA,KAAA,EAAA,EAEE,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,gCAAgC,EAAA,QAAA,EAAA,CAEzC,KAAK,CAAC,KAAK,KACVC,cAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,oBAAoB,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAChF,KAAK,CAAC,KAAK,EAAA,CACP,CACR,EACDA,cAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,oBAAoB,EAAA,QAAA,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,EAAA,CAAQ,KAXjF,KAAK,CAAC,EAAE,CAYT;AAGV,YAAA,KAAK,OAAO;AACV,gBAAA,QACEA,cAAA,CAAA,KAAA,EAAA,EAEE,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,iCAAiC,YAE1C,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,IANjC,KAAK,CAAC,EAAE,CAOT;AAGV,YAAA,KAAK,OAAO;gBACV,QACEA,wBAEE,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,KAAK,EAAE;AACL,wBAAA,GAAG,aAAa;AAChB,wBAAA,OAAO,EAAE,MAAM;AACf,wBAAA,UAAU,EAAE,QAAQ;AACpB,wBAAA,cAAc,EAAE,QAAQ;AACzB,qBAAA,EACD,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAE1C,KAAK,IACJA,cAAA,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,KAEFA,cAAA,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;AACd,yBAAA,EAAA,QAAA,EAEA,KAAK,CAAC,KAAK,IAAI,OAAO,EAAA,CACnB,CACP,EAAA,EArCI,KAAK,CAAC,EAAE,CAsCT;AAGV,YAAA,KAAK,QAAQ;AACX,gBAAA,MAAM,SAAS,GAAG,KAAK,CAAC;sBACpBC,gCAAwB,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;sBACxG,EAAE;gBAEN,QACED,wBAEE,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,KAAK,EAAE;AACL,wBAAA,GAAG,aAAa;AAChB,wBAAA,eAAe,EAAE,MAAM;AACvB,wBAAA,OAAO,EAAE,MAAM;AACf,wBAAA,UAAU,EAAE,QAAQ;AACpB,wBAAA,cAAc,EAAE,QAAQ;qBACzB,EACD,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,kCAAkC,YAE3C,SAAS,IACRA,wBACE,GAAG,EAAE,SAAS,EACd,GAAG,EAAC,SAAS,EACb,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAC9D,KAEFA,cAAA,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;AACd,yBAAA,EAAA,QAAA,EAAA,SAAA,EAAA,CAGG,CACP,EAAA,EAjCI,KAAK,CAAC,EAAE,CAkCT;AAGV,YAAA;AACE,gBAAA,OAAO,IAAI;;AAEjB,IAAA,CAAC;;AAGD,IAAA,MAAM,SAAS,GAAwB;AACrC,QAAA,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAK;AACtC,QAAA,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,KAAK;AACxC,QAAA,QAAQ,EAAE,UAAU;AACpB,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,eAAe,EAAE,MAAM;QACvB,SAAS,EAAE,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA,CAAG;AAC5B,QAAA,eAAe,EAAE,UAAU;AAC3B,QAAA,GAAG,KAAK;KACT;AAED,IAAA,QACED,eAAA,CAAA,KAAA,EAAA,EACE,EAAE,EAAE,IAAI,KAAK,OAAO,GAAG,aAAa,GAAG,YAAY,EACnD,SAAS,EAAE,2BAA2B,IAAI,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,EACzD,KAAK,EAAE,SAAS,aAGf,eAAe,KACdC,cAAA,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;iBACV,EAAA,CACD,CACH,EAGA,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA,EAAA,CAC5B;AAEV;AAEA;;AAEG;AACH,SAAS,aAAa,CAAC,KAAmB,EAAE,IAAgB,EAAA;AAC1D,IAAA,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;QAC1B,OAAO,KAAK,CAAC,UAAU;IACzB;IAEA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;;AAGlC,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACxB,QAAA,OAAO,KAAK,CAAC,CAAC,CAAC;IACjB;AAEA,IAAA,OAAO,KAAoC;AAC7C;;;;"}
1
+ {"version":3,"file":"IDCardGenerator.js","sources":["../../../src/components/IDCardGenerator.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\r\nimport type { IDCardGeneratorProps, FieldMapping, IDCardData, IDCardTemplate } from '../types';\r\nimport { fieldStyleToCSS, positionToStyle } from '../utils/styleUtils';\r\nimport { generateQrCodeFromFields } from '../core/qrUtils';\r\n\r\n/**\r\n * IDCardGenerator - Renders a completed ID card\r\n * \r\n * Takes a template and user data, then renders the filled card.\r\n * This is the component used to display actual ID cards for individual users.\r\n * \r\n * Example:\r\n * ```tsx\r\n * <IDCardGenerator \r\n * template={myTemplate}\r\n * data={{ name: 'John Doe', photo: '...' }}\r\n * side=\"front\"\r\n * />\r\n * ```\r\n */\r\nexport const IDCardGenerator: React.FC<IDCardGeneratorProps> = ({\r\n template,\r\n data,\r\n side = 'front',\r\n scale = 1,\r\n className = '',\r\n style = {},\r\n onFieldClick,\r\n editable = false,\r\n}: IDCardGeneratorProps) => {\r\n // Get fields for the current side only\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 a single field\r\n const renderField = (field: FieldMapping) => {\r\n const posStyle = positionToStyle(field.position);\r\n let fieldStyle = fieldStyleToCSS(field.style);\r\n \r\n // Determine flex direction and alignment for text fields\r\n let flexDirection: 'column' | 'row' = 'column';\r\n if (field.type === 'text' && field.style?.labelPosition === 'left') flexDirection = 'row';\r\n\r\n // Map verticalAlign and textAlign to flex properties\r\n let justifyContent: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n let alignItems: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n if (field.type === 'text') {\r\n const textAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n const verticalAlign = field.style?.verticalAlign || 'top';\r\n \r\n if (flexDirection === 'column') {\r\n // For column: verticalAlign controls justifyContent (vertical), textAlign controls alignItems (horizontal)\r\n if (verticalAlign === 'middle') justifyContent = 'center';\r\n else if (verticalAlign === 'bottom') justifyContent = 'flex-end';\r\n else justifyContent = 'flex-start';\r\n \r\n if (textAlign === 'center') alignItems = 'center';\r\n else if (textAlign === 'right') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n } else {\r\n // For row: verticalAlign controls alignItems (vertical)\r\n if (verticalAlign === 'middle') alignItems = 'center';\r\n else if (verticalAlign === 'bottom') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n }\r\n }\r\n\r\n // Remove fontSize for label fields so text field font size does not affect them\r\n if (field.type === 'label' && fieldStyle.fontSize) {\r\n const { fontSize, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\r\n\r\n // Remove textTransform from container for text and label fields - applied directly to spans\r\n if ((field.type === 'text' || field.type === 'label') && fieldStyle.textTransform) {\r\n const { textTransform, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\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 ? 'pointer' : 'default',\r\n display: field.type === 'text' ? 'flex' : undefined,\r\n flexDirection: field.type === 'text' ? flexDirection : undefined,\r\n justifyContent: field.type === 'text' ? justifyContent : undefined,\r\n alignItems: field.type === 'text' ? alignItems : undefined,\r\n };\r\n\r\n const handleClick = (e: React.MouseEvent) => {\r\n if (onFieldClick) {\r\n e.stopPropagation();\r\n onFieldClick(field);\r\n }\r\n };\r\n\r\n const value = getFieldValue(field, data);\r\n\r\n switch (field.type) {\r\n case 'text': {\r\n // Label style properties\r\n let labelFontSize = field.style?.labelFontSize;\r\n if (!labelFontSize || labelFontSize === '0.75em') {\r\n labelFontSize = '12px';\r\n } else if (!labelFontSize.endsWith('px')) {\r\n const num = parseFloat(labelFontSize);\r\n if (!isNaN(num)) labelFontSize = num + 'px';\r\n else labelFontSize = '12px';\r\n }\r\n const labelFontWeight = field.style?.labelFontWeight || 'normal';\r\n const labelColor = field.style?.labelColor || '#666666';\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n const labelTextAlign = field.style?.labelTextAlign || 'left';\r\n \r\n // Text/value style properties (separate from label)\r\n const textFontSize = field.style?.textFontSize || field.style?.fontSize || '1em';\r\n const textFontWeight = field.style?.textFontWeight || field.style?.fontWeight || 'normal';\r\n const textColor = field.style?.textColor || field.style?.color || '#000000';\r\n const textTextTransform = field.style?.textTransform || 'none';\r\n const textTextAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n \r\n // For row layout (label on left), use individual span alignment\r\n if (field.style?.labelPosition === 'left') {\r\n let labelAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.labelVerticalAlign === 'middle') labelAlignSelf = 'center';\r\n else if (field.style?.labelVerticalAlign === 'bottom') labelAlignSelf = 'flex-end';\r\n \r\n let textAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.textVerticalAlign === 'middle') textAlignSelf = 'center';\r\n else if (field.style?.textVerticalAlign === 'bottom') textAlignSelf = 'flex-end';\r\n \r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n marginRight: 8, \r\n alignSelf: labelAlignSelf, \r\n whiteSpace: 'nowrap', \r\n textTransform: labelTextTransform \r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor, \r\n alignSelf: textAlignSelf\r\n };\r\n \r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-text\"\r\n >\r\n {field.label && (\r\n <span className=\"idcard-field-label\" style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span style={{ width: '100%', textAlign: textTextAlign }}>\r\n <span className=\"idcard-field-value\" style={textStyle}>{String(value || field.placeholder || '')}</span>\r\n </span>\r\n </div>\r\n );\r\n } else {\r\n // For column layout (label on top), let container alignment handle positioning\r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n textTransform: labelTextTransform,\r\n width: '100%',\r\n textAlign: labelTextAlign\r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor,\r\n width: '100%',\r\n textAlign: textTextAlign\r\n };\r\n \r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-text\"\r\n >\r\n {field.label && (\r\n <span className=\"idcard-field-label\" style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span className=\"idcard-field-value\" style={textStyle}>{String(value || field.placeholder || '')}</span>\r\n </div>\r\n );\r\n }\r\n }\r\n\r\n case 'label': {\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-label\"\r\n >\r\n <span style={{ textTransform: labelTextTransform }}>{field.staticText || field.label || ''}</span>\r\n </div>\r\n );\r\n }\r\n\r\n case 'image':\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={combinedStyle}\r\n onClick={handleClick}\r\n >\r\n {value ? (\r\n <img\r\n src={String(value)}\r\n alt={field.label || 'Image'}\r\n style={{\r\n width: '100%',\r\n display: 'block',\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 }}\r\n >\r\n {field.label || 'Photo'}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n\r\n case 'qrcode':\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, Math.min(field.position.width, field.position.height) * 2)\r\n : '';\r\n\r\n return (\r\n <div\r\n key={field.id}\r\n id={field.id}\r\n style={{\r\n ...combinedStyle,\r\n backgroundColor: '#fff',\r\n }}\r\n onClick={handleClick}\r\n className=\"idcard-field idcard-field-qrcode\"\r\n >\r\n {qrDataUrl ? (\r\n <img\r\n src={qrDataUrl}\r\n alt=\"QR Code\"\r\n style={{ width: '100%', height: '100%' }}\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 }}\r\n >\r\n QR Code\r\n </div>\r\n )}\r\n </div>\r\n );\r\n\r\n default:\r\n return null;\r\n }\r\n };\r\n\r\n // Card container style\r\n const cardStyle: React.CSSProperties = {\r\n width: Math.round(template.cardSize.width),\r\n height: Math.round(template.cardSize.height),\r\n position: 'relative',\r\n overflow: 'hidden',\r\n backgroundColor: '#fff',\r\n ...style,\r\n };\r\n\r\n return (\r\n <div\r\n id={side === 'front' ? 'idcardfront' : 'idcardback'}\r\n className={`idcard-container idcard-${side} ${className}`}\r\n style={cardStyle}\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: `${Math.round(template.cardSize.width)}px`,\r\n height: `${Math.round(template.cardSize.height)}px`,\r\n zIndex: 0,\r\n }}\r\n />\r\n )}\r\n\r\n {/* Fields */}\r\n {fieldsToRender.map(renderField)}\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Get field value from data based on field configuration\r\n */\r\nfunction getFieldValue(field: FieldMapping, data: IDCardData): string | number | undefined {\r\n if (field.type === 'label') {\r\n return field.staticText;\r\n }\r\n\r\n const value = data[field.fieldKey];\r\n\r\n // Handle array values (like department)\r\n if (Array.isArray(value)) {\r\n return value[0];\r\n }\r\n\r\n return value as string | number | undefined;\r\n}\r\n\r\n"],"names":["useMemo","positionToStyle","fieldStyleToCSS","_jsxs","_jsx","generateQrCodeFromFields"],"mappings":"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"}
@@ -205,9 +205,7 @@ const IDCardPreview = ({ template, data, side, scale = 1, showGrid = false, onFi
205
205
  case 'image':
206
206
  return value ? (jsxRuntime.jsx("img", { src: String(value), alt: field.label || 'Image', style: {
207
207
  width: '100%',
208
- height: '100%',
209
- objectFit: 'cover',
210
- objectPosition: 'center top',
208
+ display: 'block',
211
209
  } })) : (jsxRuntime.jsxs("div", { style: {
212
210
  width: '100%',
213
211
  height: '100%',
@@ -228,7 +226,7 @@ const IDCardPreview = ({ template, data, side, scale = 1, showGrid = false, onFi
228
226
  const qrDataUrl = field.qrFields
229
227
  ? qrUtils.generateQrCodeFromFields(data, field.qrFields, qrSize)
230
228
  : '';
231
- return qrDataUrl ? (jsxRuntime.jsx("img", { src: qrDataUrl, alt: "QR Code", style: { width: '100%', height: '100%', objectFit: 'contain', display: 'block', pointerEvents: 'none' } })) : (jsxRuntime.jsx("div", { style: {
229
+ return qrDataUrl ? (jsxRuntime.jsx("img", { src: qrDataUrl, alt: "QR Code", style: { width: '100%', height: '100%', display: 'block', pointerEvents: 'none' } })) : (jsxRuntime.jsx("div", { style: {
232
230
  width: '100%',
233
231
  height: '100%',
234
232
  backgroundColor: '#f0f0f0',
@@ -247,14 +245,12 @@ const IDCardPreview = ({ template, data, side, scale = 1, showGrid = false, onFi
247
245
  };
248
246
  // Card container style
249
247
  const cardStyle = {
250
- width: template.cardSize.width,
251
- height: template.cardSize.height,
248
+ width: Math.round(template.cardSize.width),
249
+ height: Math.round(template.cardSize.height),
252
250
  position: 'relative',
253
251
  overflow: 'hidden',
254
252
  backgroundColor: backgroundImage ? 'transparent' : '#f5f5f5',
255
253
  border: '1px solid #ddd',
256
- transform: `scale(${scale})`,
257
- transformOrigin: 'top left',
258
254
  };
259
255
  // Grid overlay style
260
256
  const gridStyle = {
@@ -277,9 +273,8 @@ const IDCardPreview = ({ template, data, side, scale = 1, showGrid = false, onFi
277
273
  position: 'absolute',
278
274
  top: 0,
279
275
  left: 0,
280
- width: '100%',
281
- height: '100%',
282
- objectFit: 'cover',
276
+ width: `${Math.round(template.cardSize.width)}px`,
277
+ height: `${Math.round(template.cardSize.height)}px`,
283
278
  zIndex: 0,
284
279
  pointerEvents: 'none',
285
280
  } })), fieldsToRender.map(renderField), showGrid && jsxRuntime.jsx("div", { style: gridStyle }), !backgroundImage && fieldsToRender.length === 0 && (jsxRuntime.jsxs("div", { style: {
@@ -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 let fieldStyle = fieldStyleToCSS(field.style);\r\n const isSelected = field.id === selectedFieldId;\r\n\r\n // Determine flex direction and alignment for text fields\r\n let flexDirection: 'column' | 'row' = 'column';\r\n if (field.type === 'text' && field.style?.labelPosition === 'left') flexDirection = 'row';\r\n\r\n // Map verticalAlign and textAlign to flex properties\r\n let justifyContent: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n let alignItems: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n if (field.type === 'text') {\r\n const textAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n const verticalAlign = field.style?.verticalAlign || 'top';\r\n \r\n if (flexDirection === 'column') {\r\n // For column: verticalAlign controls justifyContent (vertical), textAlign controls alignItems (horizontal)\r\n if (verticalAlign === 'middle') justifyContent = 'center';\r\n else if (verticalAlign === 'bottom') justifyContent = 'flex-end';\r\n else justifyContent = 'flex-start';\r\n \r\n if (textAlign === 'center') alignItems = 'center';\r\n else if (textAlign === 'right') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n } else {\r\n // For row: verticalAlign controls alignItems (vertical)\r\n if (verticalAlign === 'middle') alignItems = 'center';\r\n else if (verticalAlign === 'bottom') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n // justifyContent can be left as default for row\r\n }\r\n }\r\n\r\n // Remove fontSize for label fields so text field font size does not affect them\r\n if (field.type === 'label' && fieldStyle.fontSize) {\r\n const { fontSize, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\r\n\r\n // Remove textTransform from container for text and label fields - applied directly to spans\r\n if ((field.type === 'text' || field.type === 'label') && fieldStyle.textTransform) {\r\n const { textTransform, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\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 display: field.type === 'text' ? 'flex' : undefined,\r\n flexDirection: field.type === 'text' ? flexDirection : undefined,\r\n justifyContent: field.type === 'text' ? justifyContent : undefined,\r\n alignItems: field.type === 'text' ? alignItems : undefined,\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\r\n switch (field.type) {\r\n case 'text': {\r\n // Label style properties\r\n // Always use px for label font size, default 12px\r\n let labelFontSize = field.style?.labelFontSize;\r\n if (!labelFontSize || labelFontSize === '0.75em') {\r\n labelFontSize = '12px';\r\n } else if (!labelFontSize.endsWith('px')) {\r\n const num = parseFloat(labelFontSize);\r\n if (!isNaN(num)) labelFontSize = num + 'px';\r\n else labelFontSize = '12px';\r\n }\r\n const labelFontWeight = field.style?.labelFontWeight || 'normal';\r\n const labelColor = field.style?.labelColor || '#666666';\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n const labelTextAlign = field.style?.labelTextAlign || 'left';\r\n \r\n // Text/value style properties (separate from label)\r\n const textFontSize = field.style?.textFontSize || field.style?.fontSize || '1em';\r\n const textFontWeight = field.style?.textFontWeight || field.style?.fontWeight || 'normal';\r\n const textColor = field.style?.textColor || field.style?.color || '#000000';\r\n const textTextTransform = field.style?.textTransform || 'none';\r\n const textTextAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n \r\n // For row layout (label on left), use individual span alignment\r\n if (field.style?.labelPosition === 'left') {\r\n let labelAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.labelVerticalAlign === 'middle') labelAlignSelf = 'center';\r\n else if (field.style?.labelVerticalAlign === 'bottom') labelAlignSelf = 'flex-end';\r\n \r\n let textAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.textVerticalAlign === 'middle') textAlignSelf = 'center';\r\n else if (field.style?.textVerticalAlign === 'bottom') textAlignSelf = 'flex-end';\r\n \r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n marginRight: 8, \r\n alignSelf: labelAlignSelf, \r\n whiteSpace: 'nowrap', \r\n textTransform: labelTextTransform \r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor, \r\n alignSelf: textAlignSelf\r\n };\r\n \r\n return (\r\n <>\r\n {field.label && (\r\n <span style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span style={{ width: '100%', textAlign: textTextAlign }}>\r\n <span style={textStyle}>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </span>\r\n </>\r\n );\r\n } else {\r\n // For column layout (label on top), let container alignment handle positioning\r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n textTransform: labelTextTransform,\r\n width: '100%',\r\n textAlign: labelTextAlign\r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor,\r\n width: '100%',\r\n textAlign: textTextAlign\r\n };\r\n \r\n return (\r\n <>\r\n {field.label && (\r\n <span style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span style={textStyle}>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </>\r\n );\r\n }\r\n }\r\n\r\n case 'label': {\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n return <span style={{ textTransform: labelTextTransform }}>{field.staticText || field.label || 'Label'}</span>;\r\n }\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 // Use the field's rendered width/height (in px) for QR code size\r\n const qrWidth = Math.max(32, Math.round(field.position.width));\r\n const qrHeight = Math.max(32, Math.round(field.position.height));\r\n // Always generate QR code at the field's current size for smooth scaling\r\n const qrSize = Math.max(qrWidth, qrHeight);\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, qrSize)\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', display: 'block', pointerEvents: 'none' }}\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":["useMemo","_jsx","positionToStyle","fieldStyleToCSS","_jsxs","_Fragment","generateQrCodeFromFields"],"mappings":"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"}
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 let fieldStyle = fieldStyleToCSS(field.style);\r\n const isSelected = field.id === selectedFieldId;\r\n\r\n // Determine flex direction and alignment for text fields\r\n let flexDirection: 'column' | 'row' = 'column';\r\n if (field.type === 'text' && field.style?.labelPosition === 'left') flexDirection = 'row';\r\n\r\n // Map verticalAlign and textAlign to flex properties\r\n let justifyContent: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n let alignItems: 'flex-start' | 'center' | 'flex-end' = 'flex-start';\r\n if (field.type === 'text') {\r\n const textAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n const verticalAlign = field.style?.verticalAlign || 'top';\r\n \r\n if (flexDirection === 'column') {\r\n // For column: verticalAlign controls justifyContent (vertical), textAlign controls alignItems (horizontal)\r\n if (verticalAlign === 'middle') justifyContent = 'center';\r\n else if (verticalAlign === 'bottom') justifyContent = 'flex-end';\r\n else justifyContent = 'flex-start';\r\n \r\n if (textAlign === 'center') alignItems = 'center';\r\n else if (textAlign === 'right') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n } else {\r\n // For row: verticalAlign controls alignItems (vertical)\r\n if (verticalAlign === 'middle') alignItems = 'center';\r\n else if (verticalAlign === 'bottom') alignItems = 'flex-end';\r\n else alignItems = 'flex-start';\r\n // justifyContent can be left as default for row\r\n }\r\n }\r\n\r\n // Remove fontSize for label fields so text field font size does not affect them\r\n if (field.type === 'label' && fieldStyle.fontSize) {\r\n const { fontSize, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\r\n\r\n // Remove textTransform from container for text and label fields - applied directly to spans\r\n if ((field.type === 'text' || field.type === 'label') && fieldStyle.textTransform) {\r\n const { textTransform, ...rest } = fieldStyle;\r\n fieldStyle = rest;\r\n }\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 display: field.type === 'text' ? 'flex' : undefined,\r\n flexDirection: field.type === 'text' ? flexDirection : undefined,\r\n justifyContent: field.type === 'text' ? justifyContent : undefined,\r\n alignItems: field.type === 'text' ? alignItems : undefined,\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\r\n switch (field.type) {\r\n case 'text': {\r\n // Label style properties\r\n // Always use px for label font size, default 12px\r\n let labelFontSize = field.style?.labelFontSize;\r\n if (!labelFontSize || labelFontSize === '0.75em') {\r\n labelFontSize = '12px';\r\n } else if (!labelFontSize.endsWith('px')) {\r\n const num = parseFloat(labelFontSize);\r\n if (!isNaN(num)) labelFontSize = num + 'px';\r\n else labelFontSize = '12px';\r\n }\r\n const labelFontWeight = field.style?.labelFontWeight || 'normal';\r\n const labelColor = field.style?.labelColor || '#666666';\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n const labelTextAlign = field.style?.labelTextAlign || 'left';\r\n \r\n // Text/value style properties (separate from label)\r\n const textFontSize = field.style?.textFontSize || field.style?.fontSize || '1em';\r\n const textFontWeight = field.style?.textFontWeight || field.style?.fontWeight || 'normal';\r\n const textColor = field.style?.textColor || field.style?.color || '#000000';\r\n const textTextTransform = field.style?.textTransform || 'none';\r\n const textTextAlign = field.style?.textTextAlign || field.style?.textAlign || 'left';\r\n \r\n // For row layout (label on left), use individual span alignment\r\n if (field.style?.labelPosition === 'left') {\r\n let labelAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.labelVerticalAlign === 'middle') labelAlignSelf = 'center';\r\n else if (field.style?.labelVerticalAlign === 'bottom') labelAlignSelf = 'flex-end';\r\n \r\n let textAlignSelf: React.CSSProperties['alignSelf'] = 'flex-start';\r\n if (field.style?.textVerticalAlign === 'middle') textAlignSelf = 'center';\r\n else if (field.style?.textVerticalAlign === 'bottom') textAlignSelf = 'flex-end';\r\n \r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n marginRight: 8, \r\n alignSelf: labelAlignSelf, \r\n whiteSpace: 'nowrap', \r\n textTransform: labelTextTransform \r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor, \r\n alignSelf: textAlignSelf\r\n };\r\n \r\n return (\r\n <>\r\n {field.label && (\r\n <span style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span style={{ width: '100%', textAlign: textTextAlign }}>\r\n <span style={textStyle}>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </span>\r\n </>\r\n );\r\n } else {\r\n // For column layout (label on top), let container alignment handle positioning\r\n const labelStyle: React.CSSProperties = { \r\n fontSize: labelFontSize, \r\n fontWeight: labelFontWeight, \r\n color: labelColor, \r\n opacity: 0.7, \r\n textTransform: labelTextTransform,\r\n width: '100%',\r\n textAlign: labelTextAlign\r\n };\r\n \r\n const textStyle: React.CSSProperties = { \r\n textTransform: textTextTransform, \r\n fontSize: textFontSize, \r\n fontWeight: textFontWeight, \r\n color: textColor,\r\n width: '100%',\r\n textAlign: textTextAlign\r\n };\r\n \r\n return (\r\n <>\r\n {field.label && (\r\n <span style={labelStyle}>\r\n {field.label}\r\n </span>\r\n )}\r\n <span style={textStyle}>{String(value || field.placeholder || field.fieldKey)}</span>\r\n </>\r\n );\r\n }\r\n }\r\n\r\n case 'label': {\r\n const labelTextTransform = field.style?.labelTextTransform || 'none';\r\n return <span style={{ textTransform: labelTextTransform }}>{field.staticText || field.label || 'Label'}</span>;\r\n }\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 display: 'block',\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 // Use the field's rendered width/height (in px) for QR code size\r\n const qrWidth = Math.max(32, Math.round(field.position.width));\r\n const qrHeight = Math.max(32, Math.round(field.position.height));\r\n // Always generate QR code at the field's current size for smooth scaling\r\n const qrSize = Math.max(qrWidth, qrHeight);\r\n const qrDataUrl = field.qrFields\r\n ? generateQrCodeFromFields(data, field.qrFields, qrSize)\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%', display: 'block', pointerEvents: 'none' }}\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: Math.round(template.cardSize.width),\r\n height: Math.round(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 };\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: `${Math.round(template.cardSize.width)}px`,\r\n height: `${Math.round(template.cardSize.height)}px`,\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":["useMemo","_jsx","positionToStyle","fieldStyleToCSS","_jsxs","_Fragment","generateQrCodeFromFields"],"mappings":"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"}
@@ -6,55 +6,29 @@ var qrUtils = require('./qrUtils.js');
6
6
 
7
7
  // High-quality canvas rendering defaults
8
8
  const defaultCanvasOptions = {
9
- scale: 10, // 10x resolution for crisp output
10
- dpi: 1200,
9
+ scale: 2, // 2x resolution for good quality without precision issues
11
10
  imageTimeout: 15000,
12
11
  letterRendering: true,
13
12
  logging: false,
14
13
  useCORS: true, // Allow cross-origin images
15
14
  allowTaint: true, // Allow cross-origin images to taint canvas
16
- backgroundColor: null,
15
+ backgroundColor: '#ffffff', // White background to prevent black screen
17
16
  foreignObjectRendering: false, // Disable foreign object rendering for better compatibility
18
17
  };
19
18
  /**
20
19
  * Capture a DOM element as a high-resolution canvas
21
20
  * Uses html2canvas to convert the element to an image
21
+ * Captures the element directly as rendered on screen to preserve exact positioning
22
22
  * @returns Canvas and the original element, or null if not found
23
23
  */
24
- async function captureElement(elementId, scale = 10) {
24
+ async function captureElement(elementId, scale = 2) {
25
25
  const element = document.getElementById(elementId);
26
26
  if (!element)
27
27
  return null;
28
28
  // Get actual rendered dimensions
29
29
  const rect = element.getBoundingClientRect();
30
- // Clone the element to avoid modifying the original
31
- const clone = element.cloneNode(true);
32
- // Create a wrapper to ensure proper positioning
33
- const wrapper = document.createElement('div');
34
- wrapper.style.cssText = `
35
- position: fixed;
36
- left: -99999px;
37
- top: 0;
38
- width: ${rect.width}px;
39
- height: ${rect.height}px;
40
- overflow: visible;
41
- background: transparent;
42
- `;
43
- // Copy computed styles to clone - maintain relative positioning for child elements
44
- // Don't set left/top to '0' as it can interfere with absolutely positioned children
45
- clone.style.position = 'relative';
46
- clone.style.margin = '0';
47
- clone.style.transform = 'none';
48
- clone.style.transformOrigin = 'top left';
49
- clone.style.width = `${rect.width}px`;
50
- clone.style.height = `${rect.height}px`;
51
- // Remove any inherited left/top that might shift content
52
- clone.style.removeProperty('left');
53
- clone.style.removeProperty('top');
54
- wrapper.appendChild(clone);
55
- document.body.appendChild(wrapper);
56
- // Wait for images to load in clone
57
- const images = clone.querySelectorAll('img');
30
+ // Wait for images to load
31
+ const images = element.querySelectorAll('img');
58
32
  await Promise.all(Array.from(images).map((img) => new Promise((resolve) => {
59
33
  if (img.complete) {
60
34
  resolve();
@@ -65,21 +39,17 @@ async function captureElement(elementId, scale = 10) {
65
39
  }
66
40
  })));
67
41
  // Small delay to ensure styles are applied
68
- await new Promise((resolve) => setTimeout(resolve, 50));
69
- const canvas = await html2canvas(clone, {
42
+ await new Promise((resolve) => setTimeout(resolve, 100));
43
+ // Capture the element directly as it appears on screen
44
+ // This preserves all styling exactly as rendered
45
+ const canvas = await html2canvas(element, {
70
46
  ...defaultCanvasOptions,
71
47
  scale,
72
48
  width: rect.width,
73
49
  height: rect.height,
74
- x: 0,
75
- y: 0,
76
- scrollX: 0,
77
- scrollY: 0,
78
- windowWidth: rect.width,
79
- windowHeight: rect.height,
50
+ windowWidth: element.scrollWidth,
51
+ windowHeight: element.scrollHeight,
80
52
  });
81
- // Clean up
82
- document.body.removeChild(wrapper);
83
53
  return { canvas, element };
84
54
  }
85
55
  /**
@@ -123,8 +93,8 @@ async function downloadIDCardAsPDF(options) {
123
93
  const imgData = canvas.toDataURL('image/jpeg', 1.0);
124
94
  // Use getBoundingClientRect for accurate dimensions
125
95
  const rect = element.getBoundingClientRect();
126
- const pdfWidth = rect.width * 0.264583; // Convert px to mm
127
- const pdfHeight = rect.height * 0.264583;
96
+ const pdfWidth = rect.width; // Convert px to mm
97
+ const pdfHeight = rect.height;
128
98
  const orientation = pdfWidth >= pdfHeight ? 'landscape' : 'portrait';
129
99
  if (i === 0) {
130
100
  pdf = new jsPDF({
@@ -157,7 +127,7 @@ async function downloadIDCardAsPDF(options) {
157
127
  */
158
128
  async function downloadIDCardAsImage(options) {
159
129
  try {
160
- const { frontElementId = 'idcardfront', filename = 'ID_Card', data, qrElementId, qrFields, format = 'png', scale = 10, quality = 1.0, } = options;
130
+ const { frontElementId = 'idcardfront', filename = 'ID_Card', data, qrElementId, qrFields, format = 'png', scale = 2, quality = 1.0, } = options;
161
131
  // Generate QR code if needed
162
132
  if (qrElementId && data && qrFields && qrFields.length > 0) {
163
133
  const qrData = {};