react-id-card-generator 1.1.0 → 1.1.1

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.
@@ -16,6 +16,16 @@ const defaultFieldTypes = [
16
16
  { type: 'qrcode', label: 'QR Code', icon: '📱' },
17
17
  { type: 'table', label: 'Table', icon: '▦' },
18
18
  ];
19
+ const getPhotoRadiusSliderValue = (borderRadius) => {
20
+ if (typeof borderRadius !== 'string') {
21
+ return 0;
22
+ }
23
+ const parsed = Number.parseFloat(borderRadius);
24
+ if (!Number.isFinite(parsed)) {
25
+ return 0;
26
+ }
27
+ return Math.max(0, Math.min(200, Math.round(parsed)));
28
+ };
19
29
  /**
20
30
  * IDCardDesigner - Visual drag-and-drop template builder
21
31
  *
@@ -383,11 +393,15 @@ const IDCardDesigner = ({ initialTemplate, onSave, onCancel, className = '', sty
383
393
  }, [selectedFieldId, removeField]);
384
394
  // Keyboard shortcuts
385
395
  react.useEffect(() => {
396
+ const handleLineHeightInputFocus = () => {
397
+ };
398
+ const handleLineHeightInputBlur = () => {
399
+ };
386
400
  // Listen for focus/blur on line height input
387
401
  const lhInput = document.getElementById('line-height-input');
388
402
  if (lhInput) {
389
- lhInput.addEventListener('focus', () => { });
390
- lhInput.addEventListener('blur', () => { });
403
+ lhInput.addEventListener('focus', handleLineHeightInputFocus);
404
+ lhInput.addEventListener('blur', handleLineHeightInputBlur);
391
405
  }
392
406
  const handleKeyDown = (e) => {
393
407
  if (selectedFieldId) {
@@ -437,7 +451,13 @@ const IDCardDesigner = ({ initialTemplate, onSave, onCancel, className = '', sty
437
451
  }
438
452
  };
439
453
  document.addEventListener('keydown', handleKeyDown);
440
- return () => document.removeEventListener('keydown', handleKeyDown);
454
+ return () => {
455
+ document.removeEventListener('keydown', handleKeyDown);
456
+ if (lhInput) {
457
+ lhInput.removeEventListener('focus', handleLineHeightInputFocus);
458
+ lhInput.removeEventListener('blur', handleLineHeightInputBlur);
459
+ }
460
+ };
441
461
  }, [selectedFieldId, handleDeleteField, template.fields, template.cardSize, updateField]);
442
462
  return (jsxRuntime.jsxs("div", { className: `idcard-designer ${className}`, style: style, children: [jsxRuntime.jsxs("div", { className: "designer-header", children: [jsxRuntime.jsx("input", { type: "text", value: templateName, onChange: (e) => setTemplateName(e.target.value), className: "template-name-input", placeholder: "Template Name" }), jsxRuntime.jsxs("div", { className: "header-actions", children: [onCancel && (jsxRuntime.jsx("button", { type: "button", onClick: onCancel, className: "btn btn-secondary", children: "Cancel" })), jsxRuntime.jsx("button", { type: "button", onClick: handleSave, className: "btn btn-primary", disabled: !isValid, children: "Save Template" })] })] }), jsxRuntime.jsxs("div", { className: "designer-body", children: [jsxRuntime.jsxs("div", { className: "designer-sidebar left-sidebar", children: [jsxRuntime.jsx("h3", { children: "Add Fields" }), jsxRuntime.jsx("div", { className: "field-types", children: defaultFieldTypes.map((fieldType) => (jsxRuntime.jsxs("button", { type: "button", onClick: () => handleAddField(fieldType.type), className: "field-type-btn", children: [jsxRuntime.jsx("span", { className: "field-icon", children: fieldType.icon }), jsxRuntime.jsx("span", { className: "field-label", children: fieldType.label })] }, fieldType.type))) }), jsxRuntime.jsx("h3", { children: "Card Settings" }), jsxRuntime.jsxs("div", { className: "card-settings", children: [jsxRuntime.jsxs("div", { className: "setting-group", children: [jsxRuntime.jsx("label", { children: "Orientation" }), jsxRuntime.jsxs("div", { className: "btn-group", children: [jsxRuntime.jsx("button", { type: "button", className: `btn ${template.orientation === 'landscape' ? 'active' : ''}`, onClick: () => handleOrientationChange('landscape'), children: "Landscape" }), jsxRuntime.jsx("button", { type: "button", className: `btn ${template.orientation === 'portrait' ? 'active' : ''}`, onClick: () => handleOrientationChange('portrait'), children: "Portrait" })] })] }), jsxRuntime.jsxs("div", { className: "setting-group", children: [jsxRuntime.jsx("label", { children: "Card Sides" }), jsxRuntime.jsxs("div", { className: "btn-group", children: [jsxRuntime.jsx("button", { type: "button", className: `btn ${template.sides === 'single' ? 'active' : ''}`, onClick: () => handleSidesChange('single'), children: "Single" }), jsxRuntime.jsx("button", { type: "button", className: `btn ${template.sides === 'double' ? 'active' : ''}`, onClick: () => handleSidesChange('double'), children: "Double" })] })] }), jsxRuntime.jsxs("div", { className: "setting-group", children: [jsxRuntime.jsx("label", { children: "Card Size (px)" }), jsxRuntime.jsxs("div", { className: "size-inputs", children: [jsxRuntime.jsx("input", { type: "number", value: template.cardSize.width, onChange: (e) => setCardSize({ ...template.cardSize, width: Number(e.target.value) }), placeholder: "Width" }), jsxRuntime.jsx("span", { children: "\u00D7" }), jsxRuntime.jsx("input", { type: "number", value: template.cardSize.height, onChange: (e) => setCardSize({ ...template.cardSize, height: Number(e.target.value) }), placeholder: "Height" })] })] })] }), jsxRuntime.jsx("h3", { children: "Background" }), jsxRuntime.jsxs("div", { className: "background-upload", children: [jsxRuntime.jsx("input", { type: "file", accept: "image/*", onChange: handleBackgroundUpload, id: "bg-upload", className: "file-input" }), jsxRuntime.jsxs("label", { htmlFor: "bg-upload", className: "btn btn-outline", children: ["Upload ", activeSide, " Background"] }), template.backgrounds[activeSide] && (jsxRuntime.jsx("button", { type: "button", className: "btn btn-danger btn-sm", onClick: () => setBackground(activeSide, ''), children: "Remove" }))] })] }), jsxRuntime.jsxs("div", { className: "designer-preview", children: [jsxRuntime.jsxs("div", { className: "side-tabs", children: [jsxRuntime.jsx("button", { type: "button", className: `tab ${activeSide === 'front' ? 'active' : ''}`, onClick: () => setActiveSide('front'), children: "Front" }), template.sides === 'double' && (jsxRuntime.jsx("button", { type: "button", className: `tab ${activeSide === 'back' ? 'active' : ''}`, onClick: () => setActiveSide('back'), children: "Back" })), jsxRuntime.jsxs("label", { className: "grid-toggle", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: showGrid, onChange: (e) => setShowGrid(e.target.checked) }), "Show Grid"] })] }), jsxRuntime.jsx("div", { ref: previewContainerRef, className: "preview-wrapper", onMouseDown: handleMouseDown, children: jsxRuntime.jsx(IDCardPreview.IDCardPreview, { template: template, data: sampleData, side: activeSide, showGrid: showGrid, onFieldSelect: handleFieldSelect, selectedFieldId: selectedFieldId, editable: true }) }), jsxRuntime.jsxs("div", { className: "fields-list", children: [jsxRuntime.jsxs("h4", { children: ["Fields on ", activeSide, " side:"] }), template.fields
443
463
  .filter((f) => f.side === activeSide)
@@ -489,7 +509,7 @@ const IDCardDesigner = ({ initialTemplate, onSave, onCancel, className = '', sty
489
509
  ? [...currentFields, field.fieldKey]
490
510
  : currentFields.filter(f => f !== field.fieldKey);
491
511
  handleFieldPropertyUpdate('qrFields', newFields);
492
- }, style: { marginRight: '6px' } }), field.label || field.fieldKey] }, field.fieldKey))) })] })), selectedField.type !== 'text' && selectedField.type !== 'table' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h4", { children: "Style" }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Font Size" }), jsxRuntime.jsx("input", { type: "text", value: selectedField.style?.fontSize || '12px', onChange: (e) => handleFieldPropertyUpdate('style.fontSize', e.target.value) })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Font Weight" }), jsxRuntime.jsxs("select", { value: selectedField.style?.fontWeight || 'normal', onChange: (e) => handleFieldPropertyUpdate('style.fontWeight', e.target.value), children: [jsxRuntime.jsx("option", { value: "normal", children: "Normal" }), jsxRuntime.jsx("option", { value: "bold", children: "Bold" }), jsxRuntime.jsx("option", { value: "100", children: "100" }), jsxRuntime.jsx("option", { value: "200", children: "200" }), jsxRuntime.jsx("option", { value: "300", children: "300" }), jsxRuntime.jsx("option", { value: "400", children: "400" }), jsxRuntime.jsx("option", { value: "500", children: "500" }), jsxRuntime.jsx("option", { value: "600", children: "600" }), jsxRuntime.jsx("option", { value: "700", children: "700" }), jsxRuntime.jsx("option", { value: "800", children: "800" }), jsxRuntime.jsx("option", { value: "900", children: "900" })] })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Color" }), jsxRuntime.jsx("input", { type: "color", value: selectedField.style?.color || '#000000', onChange: (e) => handleFieldPropertyUpdate('style.color', e.target.value) })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Align" }), jsxRuntime.jsxs("select", { value: selectedField.style?.textAlign || 'left', onChange: (e) => handleFieldPropertyUpdate('style.textAlign', e.target.value), children: [jsxRuntime.jsx("option", { value: "left", children: "Left" }), jsxRuntime.jsx("option", { value: "center", children: "Center" }), jsxRuntime.jsx("option", { value: "right", children: "Right" })] })] }), selectedField.type === 'label' && (jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Transform" }), jsxRuntime.jsxs("select", { value: selectedField.style?.labelTextTransform || 'none', onChange: (e) => handleFieldPropertyUpdate('style.labelTextTransform', e.target.value), children: [jsxRuntime.jsx("option", { value: "none", children: "None" }), jsxRuntime.jsx("option", { value: "uppercase", children: "UPPERCASE" }), jsxRuntime.jsx("option", { value: "lowercase", children: "lowercase" }), jsxRuntime.jsx("option", { value: "capitalize", children: "Capitalize" })] })] }))] }), selectedField.type === 'qrcode' ? (jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Background Color" }), jsxRuntime.jsx("div", { style: {
512
+ }, style: { marginRight: '6px' } }), field.label || field.fieldKey] }, field.fieldKey))) })] })), selectedField.type === 'image' && (jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { htmlFor: `photo-radius-input-${selectedField.id}`, children: "Photo Radius" }), jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [jsxRuntime.jsx("input", { type: "range", min: "0", max: "200", value: getPhotoRadiusSliderValue(selectedField.style?.borderRadius), onChange: (e) => handleFieldPropertyUpdate('style.borderRadius', `${e.target.value}px`), "aria-label": "Photo radius slider", style: { flex: 1 } }), jsxRuntime.jsx("input", { id: `photo-radius-input-${selectedField.id}`, type: "text", value: selectedField.style?.borderRadius || '0px', onChange: (e) => handleFieldPropertyUpdate('style.borderRadius', e.target.value.trim() || '0px'), style: { width: 72 } })] }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 8, marginTop: 8 }, children: [jsxRuntime.jsx("button", { type: "button", className: "btn btn-outline btn-sm", onClick: () => handleFieldPropertyUpdate('style.borderRadius', '0px'), children: "Square" }), jsxRuntime.jsx("button", { type: "button", className: "btn btn-outline btn-sm", onClick: () => handleFieldPropertyUpdate('style.borderRadius', '50%'), children: "Circle" })] })] })), selectedField.type !== 'text' && selectedField.type !== 'table' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h4", { children: "Style" }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Font Size" }), jsxRuntime.jsx("input", { type: "text", value: selectedField.style?.fontSize || '12px', onChange: (e) => handleFieldPropertyUpdate('style.fontSize', e.target.value) })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Font Weight" }), jsxRuntime.jsxs("select", { value: selectedField.style?.fontWeight || 'normal', onChange: (e) => handleFieldPropertyUpdate('style.fontWeight', e.target.value), children: [jsxRuntime.jsx("option", { value: "normal", children: "Normal" }), jsxRuntime.jsx("option", { value: "bold", children: "Bold" }), jsxRuntime.jsx("option", { value: "100", children: "100" }), jsxRuntime.jsx("option", { value: "200", children: "200" }), jsxRuntime.jsx("option", { value: "300", children: "300" }), jsxRuntime.jsx("option", { value: "400", children: "400" }), jsxRuntime.jsx("option", { value: "500", children: "500" }), jsxRuntime.jsx("option", { value: "600", children: "600" }), jsxRuntime.jsx("option", { value: "700", children: "700" }), jsxRuntime.jsx("option", { value: "800", children: "800" }), jsxRuntime.jsx("option", { value: "900", children: "900" })] })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Color" }), jsxRuntime.jsx("input", { type: "color", value: selectedField.style?.color || '#000000', onChange: (e) => handleFieldPropertyUpdate('style.color', e.target.value) })] }), jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Align" }), jsxRuntime.jsxs("select", { value: selectedField.style?.textAlign || 'left', onChange: (e) => handleFieldPropertyUpdate('style.textAlign', e.target.value), children: [jsxRuntime.jsx("option", { value: "left", children: "Left" }), jsxRuntime.jsx("option", { value: "center", children: "Center" }), jsxRuntime.jsx("option", { value: "right", children: "Right" })] })] }), selectedField.type === 'label' && (jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Text Transform" }), jsxRuntime.jsxs("select", { value: selectedField.style?.labelTextTransform || 'none', onChange: (e) => handleFieldPropertyUpdate('style.labelTextTransform', e.target.value), children: [jsxRuntime.jsx("option", { value: "none", children: "None" }), jsxRuntime.jsx("option", { value: "uppercase", children: "UPPERCASE" }), jsxRuntime.jsx("option", { value: "lowercase", children: "lowercase" }), jsxRuntime.jsx("option", { value: "capitalize", children: "Capitalize" })] })] }))] }), selectedField.type === 'qrcode' ? (jsxRuntime.jsxs("div", { className: "property-group", children: [jsxRuntime.jsx("label", { children: "Background Color" }), jsxRuntime.jsx("div", { style: {
493
513
  padding: '8px 10px',
494
514
  border: '1px solid #ddd',
495
515
  borderRadius: '4px',