@zentto/studio 0.8.4 → 0.9.0

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.
@@ -1385,7 +1385,7 @@ let ZsPageDesigner = class ZsPageDesigner extends LitElement {
1385
1385
  if (field.type === 'heading')
1386
1386
  return field.label ?? 'Titulo';
1387
1387
  if (field.type === 'datagrid')
1388
- return this.renderLiveDataGrid(field);
1388
+ return '◫ ZenttoDataGrid';
1389
1389
  if (field.type === 'report')
1390
1390
  return '◫ ZenttoReportViewer';
1391
1391
  if (field.type === 'chart')
@@ -1406,34 +1406,6 @@ let ZsPageDesigner = class ZsPageDesigner extends LitElement {
1406
1406
  return '▸ Nodo 1\n ▸ Nodo 2';
1407
1407
  return field.placeholder ?? field.type;
1408
1408
  }
1409
- /** Render live datagrid inside canvas — props update in real time */
1410
- renderLiveDataGrid(field) {
1411
- const p = field.props ?? {};
1412
- const rawEp = p.endpoint || '';
1413
- // Build full URL: if relative path and we have apiBaseUrl, prepend it
1414
- const ep = rawEp && !rawEp.startsWith('http') && this.apiBaseUrl
1415
- ? `${this.apiBaseUrl.replace(/\/+$/, '')}${rawEp.startsWith('/') ? '' : '/'}${rawEp}`
1416
- : rawEp;
1417
- const headers = {};
1418
- if (this.apiToken) {
1419
- headers['Authorization'] = `Bearer ${this.apiToken}`;
1420
- if (this.apiCompany)
1421
- headers['x-empresa'] = this.apiCompany;
1422
- if (this.apiBranch)
1423
- headers['x-sucursal'] = this.apiBranch;
1424
- }
1425
- return html `
1426
- <zs-field-datagrid
1427
- .config="${field}"
1428
- .endpoint="${ep}"
1429
- .authToken="${this.apiToken}"
1430
- .authHeaders="${headers}"
1431
- .designMode="${true}"
1432
- .theme="${'light'}"
1433
- style="display:block;width:100%;min-height:200px;"
1434
- ></zs-field-datagrid>
1435
- `;
1436
- }
1437
1409
  // ─── Right Panel (Properties — Figma-quality) ──────
1438
1410
  renderRightPanel() {
1439
1411
  const field = this.selectedField;
@@ -1567,345 +1539,9 @@ let ZsPageDesigner = class ZsPageDesigner extends LitElement {
1567
1539
  ` : ''}
1568
1540
  ` : ''}
1569
1541
  </div>
1570
-
1571
- <!-- Type-specific props -->
1572
- ${this.renderTypeSpecificProps(field)}
1573
- </div>
1574
- `;
1575
- }
1576
- // ─── Type-Specific Property Panels ────────────────
1577
- renderTypeSpecificProps(field) {
1578
- switch (field.type) {
1579
- case 'datagrid': return this.renderDataGridProps(field);
1580
- case 'chart': return this.renderChartProps(field);
1581
- case 'report': return this.renderReportProps(field);
1582
- case 'select':
1583
- case 'multiselect':
1584
- case 'radio': return this.renderSelectProps(field);
1585
- case 'number':
1586
- case 'currency':
1587
- case 'percentage':
1588
- case 'slider':
1589
- case 'rating': return this.renderNumberProps(field);
1590
- case 'lookup': return this.renderLookupProps(field);
1591
- case 'chips':
1592
- case 'tags': return this.renderChipsProps(field);
1593
- case 'treeview': return this.renderTreeViewProps(field);
1594
- case 'date':
1595
- case 'time':
1596
- case 'datetime': return this.renderDateProps(field);
1597
- case 'file':
1598
- case 'image': return this.renderFileProps(field);
1599
- case 'signature': return this.renderSignatureProps(field);
1600
- default: return nothing;
1601
- }
1602
- }
1603
- setProp(field, key, value) {
1604
- if (!field.props)
1605
- field.props = {};
1606
- field.props[key] = value;
1607
- this.commitChange();
1608
- }
1609
- // ─── DataGrid Props ───────────────────────────────
1610
- renderDataGridProps(field) {
1611
- const p = field.props ?? {};
1612
- return html `
1613
- <div class="prop-section">
1614
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('grid-config')}">
1615
- <span class="collapse-icon ${this.collapsedSections.has('grid-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1616
- <h4>DataGrid Config</h4>
1617
- </div>
1618
- ${!this.collapsedSections.has('grid-config') ? html `
1619
- <div class="prop-info">◫ Conecta un endpoint y el grid cargara los datos en el canvas</div>
1620
- <div class="prop-row"><span class="prop-label">Altura</span><input class="prop-input" .value="${p.height ?? '400px'}" placeholder="400px" @change="${(e) => this.setProp(field, 'height', e.target.value)}" /></div>
1621
- <div class="prop-row"><span class="prop-label">Page Size</span><input class="prop-input" type="number" min="5" .value="${String(p.pageSize ?? 25)}" @change="${(e) => this.setProp(field, 'pageSize', parseInt(e.target.value) || 25)}" /></div>
1622
- <div class="prop-row"><span class="prop-label">Densidad</span>
1623
- <select class="prop-input" .value="${p.density ?? 'compact'}" @change="${(e) => this.setProp(field, 'density', e.target.value)}">
1624
- <option value="compact">Compacta</option>
1625
- <option value="standard">Estandar</option>
1626
- <option value="comfortable">Comoda</option>
1627
- </select>
1628
- </div>
1629
- <div class="prop-row"><span class="prop-label">Row Click</span>
1630
- <select class="prop-input" .value="${p.onRowClick ?? 'emit'}" @change="${(e) => this.setProp(field, 'onRowClick', e.target.value)}">
1631
- <option value="emit">Emitir evento</option>
1632
- <option value="navigate">Navegar</option>
1633
- <option value="select">Seleccionar</option>
1634
- <option value="detail">Detalle</option>
1635
- </select>
1636
- </div>
1637
- ${p.onRowClick === 'navigate' ? html `
1638
- <div class="prop-row"><span class="prop-label">Nav Segment</span><input class="prop-input" .value="${p.rowClickSegment ?? ''}" placeholder="/clientes/{id}" @change="${(e) => this.setProp(field, 'rowClickSegment', e.target.value)}" /></div>
1639
- ` : ''}
1640
- <div class="prop-divider"></div>
1641
- ${this.renderToggle('Toolbar', p.enableToolbar ?? true, (v) => this.setProp(field, 'enableToolbar', v))}
1642
- ${this.renderToggle('Busqueda', p.enableSearch ?? true, (v) => this.setProp(field, 'enableSearch', v))}
1643
- ${this.renderToggle('Exportar', p.enableExport ?? false, (v) => this.setProp(field, 'enableExport', v))}
1644
- ${this.renderToggle('Paginacion', p.enablePagination ?? true, (v) => this.setProp(field, 'enablePagination', v))}
1645
- ${this.renderToggle('Filtros Header', p.enableHeaderFilters ?? false, (v) => this.setProp(field, 'enableHeaderFilters', v))}
1646
- ${this.renderToggle('Clipboard', p.enableClipboard ?? false, (v) => this.setProp(field, 'enableClipboard', v))}
1647
- ${this.renderToggle('Seleccion Filas', p.enableRowSelection ?? false, (v) => this.setProp(field, 'enableRowSelection', v))}
1648
- ${this.renderToggle('Master-Detail', p.enableMasterDetail ?? false, (v) => this.setProp(field, 'enableMasterDetail', v))}
1649
- ${this.renderToggle('Totales', p.showTotals ?? false, (v) => this.setProp(field, 'showTotals', v))}
1650
- ${this.renderToggle('Context Menu', p.enableContextMenu ?? false, (v) => this.setProp(field, 'enableContextMenu', v))}
1651
- ${this.renderToggle('Find (Ctrl+F)', p.enableFind ?? false, (v) => this.setProp(field, 'enableFind', v))}
1652
- ${this.renderToggle('Status Bar', p.enableStatusBar ?? false, (v) => this.setProp(field, 'enableStatusBar', v))}
1653
- ${this.renderToggle('Filter Panel', p.enableFilterPanel ?? false, (v) => this.setProp(field, 'enableFilterPanel', v))}
1654
- ${this.renderToggle('Configurador', p.enableConfigurator ?? false, (v) => this.setProp(field, 'enableConfigurator', v))}
1655
- <div class="prop-divider"></div>
1656
- <div class="prop-row"><span class="prop-label">Moneda</span><input class="prop-input" .value="${p.defaultCurrency ?? ''}" placeholder="USD, VES, EUR..." @change="${(e) => this.setProp(field, 'defaultCurrency', e.target.value)}" /></div>
1657
- <div class="prop-row"><span class="prop-label">Archivo Export</span><input class="prop-input" .value="${p.exportFilename ?? ''}" placeholder="clientes" @change="${(e) => this.setProp(field, 'exportFilename', e.target.value)}" /></div>
1658
- <div class="prop-row"><span class="prop-label">Grid ID</span><input class="prop-input" style="font-family:'SF Mono','Consolas',monospace;font-size:10px;" .value="${p.gridId ?? ''}" placeholder="clientes-grid" @change="${(e) => this.setProp(field, 'gridId', e.target.value)}" /></div>
1659
- ` : ''}
1660
- </div>
1661
- `;
1662
- }
1663
- // ─── Chart Props ──────────────────────────────────
1664
- renderChartProps(field) {
1665
- const p = field.props ?? {};
1666
- return html `
1667
- <div class="prop-section">
1668
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('chart-config')}">
1669
- <span class="collapse-icon ${this.collapsedSections.has('chart-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1670
- <h4>Chart Config</h4>
1671
- </div>
1672
- ${!this.collapsedSections.has('chart-config') ? html `
1673
- <div class="prop-info">📊 Configuracion del grafico SVG</div>
1674
- <div class="prop-row"><span class="prop-label">Tipo</span>
1675
- <select class="prop-input" .value="${p.chartType ?? 'bar'}" @change="${(e) => this.setProp(field, 'chartType', e.target.value)}">
1676
- <option value="bar">Barras</option>
1677
- <option value="line">Lineas</option>
1678
- <option value="pie">Torta</option>
1679
- <option value="donut">Donut</option>
1680
- <option value="area">Area</option>
1681
- </select>
1682
- </div>
1683
- <div class="prop-row"><span class="prop-label">Titulo</span><input class="prop-input" .value="${p.chartTitle ?? ''}" placeholder="Ventas por Mes" @change="${(e) => this.setProp(field, 'chartTitle', e.target.value)}" /></div>
1684
- <div class="prop-row"><span class="prop-label">Label Field</span><input class="prop-input" .value="${p.labelField ?? ''}" placeholder="mes" @change="${(e) => this.setProp(field, 'labelField', e.target.value)}" /></div>
1685
- <div class="prop-row"><span class="prop-label">Value Field</span><input class="prop-input" .value="${p.valueField ?? ''}" placeholder="total" @change="${(e) => this.setProp(field, 'valueField', e.target.value)}" /></div>
1686
- <div class="prop-divider"></div>
1687
- <div class="prop-pos-grid">
1688
- <div class="prop-pos-cell">
1689
- <span class="prop-pos-label prop-pos-label--w">W</span>
1690
- <input type="number" min="100" .value="${String(p.width ?? 400)}" @change="${(e) => this.setProp(field, 'width', parseInt(e.target.value) || 400)}" />
1691
- </div>
1692
- <div class="prop-pos-cell">
1693
- <span class="prop-pos-label prop-pos-label--h">H</span>
1694
- <input type="number" min="100" .value="${String(p.height ?? 250)}" @change="${(e) => this.setProp(field, 'height', parseInt(e.target.value) || 250)}" />
1695
- </div>
1696
- </div>
1697
- <div class="prop-divider"></div>
1698
- ${this.renderToggle('Leyenda', p.showLegend ?? true, (v) => this.setProp(field, 'showLegend', v))}
1699
- ${this.renderToggle('Animacion', p.animated ?? false, (v) => this.setProp(field, 'animated', v))}
1700
- ` : ''}
1701
- </div>
1702
- `;
1703
- }
1704
- // ─── Report Props ─────────────────────────────────
1705
- renderReportProps(field) {
1706
- const p = field.props ?? {};
1707
- return html `
1708
- <div class="prop-section">
1709
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('report-config')}">
1710
- <span class="collapse-icon ${this.collapsedSections.has('report-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1711
- <h4>Report Config</h4>
1712
- </div>
1713
- ${!this.collapsedSections.has('report-config') ? html `
1714
- <div class="prop-info">📋 Configuracion de zentto-report</div>
1715
- <div class="prop-row"><span class="prop-label">Template ID</span><input class="prop-input" .value="${p.templateId ?? ''}" placeholder="invoice-template" @change="${(e) => this.setProp(field, 'templateId', e.target.value)}" /></div>
1716
- <div class="prop-row"><span class="prop-label">Zoom</span><input class="prop-input" type="number" min="25" max="300" step="25" .value="${String(p.zoom ?? 100)}" @change="${(e) => this.setProp(field, 'zoom', parseInt(e.target.value) || 100)}" /></div>
1717
- <div class="prop-row"><span class="prop-label">Altura</span><input class="prop-input" .value="${p.height ?? '500px'}" placeholder="500px" @change="${(e) => this.setProp(field, 'height', e.target.value)}" /></div>
1718
- <div class="prop-divider"></div>
1719
- ${this.renderToggle('Toolbar', p.showToolbar ?? true, (v) => this.setProp(field, 'showToolbar', v))}
1720
- ${this.renderToggle('Imprimir', p.showPrint ?? true, (v) => this.setProp(field, 'showPrint', v))}
1721
- ${this.renderToggle('Exportar PDF', p.showExportPdf ?? true, (v) => this.setProp(field, 'showExportPdf', v))}
1722
- ${this.renderToggle('Navegacion', p.showNavigation ?? true, (v) => this.setProp(field, 'showNavigation', v))}
1723
- ` : ''}
1724
- </div>
1725
- `;
1726
- }
1727
- // ─── Select/Radio Props ───────────────────────────
1728
- renderSelectProps(field) {
1729
- const p = field.props ?? {};
1730
- const options = p.options ?? [];
1731
- return html `
1732
- <div class="prop-section">
1733
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('select-config')}">
1734
- <span class="collapse-icon ${this.collapsedSections.has('select-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1735
- <h4>Opciones</h4>
1736
- </div>
1737
- ${!this.collapsedSections.has('select-config') ? html `
1738
- ${options.map((opt, i) => html `
1739
- <div style="display:flex;gap:3px;margin-bottom:3px;align-items:center;">
1740
- <input class="prop-input" style="flex:1;" .value="${opt.value}" placeholder="valor" @change="${(e) => { options[i].value = e.target.value; this.setProp(field, 'options', [...options]); }}" />
1741
- <input class="prop-input" style="flex:1;" .value="${opt.label}" placeholder="label" @change="${(e) => { options[i].label = e.target.value; this.setProp(field, 'options', [...options]); }}" />
1742
- <button style="border:none;background:none;cursor:pointer;color:#d32f2f;font-size:12px;padding:2px 4px;" @click="${() => { options.splice(i, 1); this.setProp(field, 'options', [...options]); }}">✕</button>
1743
- </div>
1744
- `)}
1745
- <button style="width:100%;padding:4px;border:1px dashed #ccc;border-radius:4px;background:none;cursor:pointer;font-size:10px;color:#888;font-family:inherit;margin-top:4px;"
1746
- @click="${() => { options.push({ value: '', label: '' }); this.setProp(field, 'options', [...options]); }}"
1747
- >+ Agregar opcion</button>
1748
- ${field.type === 'radio' ? html `
1749
- <div class="prop-divider"></div>
1750
- ${this.renderToggle('Horizontal', p.horizontal ?? false, (v) => this.setProp(field, 'horizontal', v))}
1751
- ` : ''}
1752
- ${field.type === 'multiselect' ? html `
1753
- <div class="prop-divider"></div>
1754
- ${this.renderToggle('Multiple', true, () => { })}
1755
- ` : ''}
1756
- ` : ''}
1757
- </div>
1758
- `;
1759
- }
1760
- // ─── Number/Currency/Slider/Rating Props ──────────
1761
- renderNumberProps(field) {
1762
- const p = field.props ?? {};
1763
- return html `
1764
- <div class="prop-section">
1765
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('number-config')}">
1766
- <span class="collapse-icon ${this.collapsedSections.has('number-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1767
- <h4>Numero Config</h4>
1768
- </div>
1769
- ${!this.collapsedSections.has('number-config') ? html `
1770
- ${field.type === 'currency' ? html `
1771
- <div class="prop-row"><span class="prop-label">Simbolo</span><input class="prop-input" .value="${p.currencySymbol ?? '$'}" @change="${(e) => this.setProp(field, 'currencySymbol', e.target.value)}" /></div>
1772
- ` : ''}
1773
- ${field.type === 'slider' || field.type === 'rating' ? html `
1774
- <div class="prop-pos-grid">
1775
- <div class="prop-pos-cell">
1776
- <span class="prop-pos-label prop-pos-label--x">Min</span>
1777
- <input type="number" .value="${String(p.min ?? 0)}" @change="${(e) => this.setProp(field, 'min', parseInt(e.target.value) || 0)}" />
1778
- </div>
1779
- <div class="prop-pos-cell">
1780
- <span class="prop-pos-label prop-pos-label--y">Max</span>
1781
- <input type="number" .value="${String(p.max ?? (field.type === 'rating' ? 5 : 100))}" @change="${(e) => this.setProp(field, 'max', parseInt(e.target.value) || 100)}" />
1782
- </div>
1783
- </div>
1784
- ${field.type === 'slider' ? html `
1785
- <div class="prop-row"><span class="prop-label">Step</span><input class="prop-input" type="number" min="1" .value="${String(p.step ?? 1)}" @change="${(e) => this.setProp(field, 'step', parseInt(e.target.value) || 1)}" /></div>
1786
- ` : ''}
1787
- ${field.type === 'rating' ? html `
1788
- <div class="prop-row"><span class="prop-label">Estrellas</span><input class="prop-input" type="number" min="3" max="10" .value="${String(p.maxRating ?? 5)}" @change="${(e) => this.setProp(field, 'maxRating', parseInt(e.target.value) || 5)}" /></div>
1789
- ` : ''}
1790
- ` : ''}
1791
- ` : ''}
1792
- </div>
1793
- `;
1794
- }
1795
- // ─── Lookup Props ─────────────────────────────────
1796
- renderLookupProps(field) {
1797
- const p = field.props ?? {};
1798
- return html `
1799
- <div class="prop-section">
1800
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('lookup-config')}">
1801
- <span class="collapse-icon ${this.collapsedSections.has('lookup-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1802
- <h4>Lookup Config</h4>
1803
- </div>
1804
- ${!this.collapsedSections.has('lookup-config') ? html `
1805
- <div class="prop-row"><span class="prop-label">Min Chars</span><input class="prop-input" type="number" min="1" .value="${String(p.minChars ?? 2)}" @change="${(e) => this.setProp(field, 'minChars', parseInt(e.target.value) || 2)}" /></div>
1806
- <div class="prop-row"><span class="prop-label">Debounce</span><input class="prop-input" type="number" min="100" step="100" .value="${String(p.debounceMs ?? 300)}" @change="${(e) => this.setProp(field, 'debounceMs', parseInt(e.target.value) || 300)}" /></div>
1807
- ` : ''}
1808
- </div>
1809
- `;
1810
- }
1811
- // ─── Chips/Tags Props ─────────────────────────────
1812
- renderChipsProps(field) {
1813
- const p = field.props ?? {};
1814
- return html `
1815
- <div class="prop-section">
1816
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('chips-config')}">
1817
- <span class="collapse-icon ${this.collapsedSections.has('chips-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1818
- <h4>Chips Config</h4>
1819
- </div>
1820
- ${!this.collapsedSections.has('chips-config') ? html `
1821
- <div class="prop-row"><span class="prop-label">Max Chips</span><input class="prop-input" type="number" min="0" .value="${String(p.maxChips ?? 0)}" @change="${(e) => this.setProp(field, 'maxChips', parseInt(e.target.value) || 0)}" /></div>
1822
- <div class="prop-row"><span class="prop-label">Color Mode</span>
1823
- <select class="prop-input" .value="${p.colorMode ?? 'default'}" @change="${(e) => this.setProp(field, 'colorMode', e.target.value)}">
1824
- <option value="default">Default</option>
1825
- <option value="primary">Primary</option>
1826
- <option value="success">Success</option>
1827
- <option value="auto">Auto (ciclo)</option>
1828
- </select>
1829
- </div>
1830
- ${this.renderToggle('Permitir custom', p.allowCustom ?? true, (v) => this.setProp(field, 'allowCustom', v))}
1831
- ${this.renderSelectProps(field)}
1832
- ` : ''}
1833
- </div>
1834
- `;
1835
- }
1836
- // ─── TreeView Props ───────────────────────────────
1837
- renderTreeViewProps(field) {
1838
- const p = field.props ?? {};
1839
- return html `
1840
- <div class="prop-section">
1841
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('tree-config')}">
1842
- <span class="collapse-icon ${this.collapsedSections.has('tree-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1843
- <h4>TreeView Config</h4>
1844
- </div>
1845
- ${!this.collapsedSections.has('tree-config') ? html `
1846
- ${this.renderToggle('Multi-select', p.multiSelect ?? false, (v) => this.setProp(field, 'multiSelect', v))}
1847
- ${this.renderToggle('Checkboxes', p.showCheckboxes ?? false, (v) => this.setProp(field, 'showCheckboxes', v))}
1848
- ${this.renderToggle('Buscador', p.searchable ?? false, (v) => this.setProp(field, 'searchable', v))}
1849
- ` : ''}
1850
- </div>
1851
- `;
1852
- }
1853
- // ─── Date Props ───────────────────────────────────
1854
- renderDateProps(field) {
1855
- const p = field.props ?? {};
1856
- return html `
1857
- <div class="prop-section">
1858
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('date-config')}">
1859
- <span class="collapse-icon ${this.collapsedSections.has('date-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1860
- <h4>Fecha Config</h4>
1861
- </div>
1862
- ${!this.collapsedSections.has('date-config') ? html `
1863
- <div class="prop-row"><span class="prop-label">Modo</span>
1864
- <select class="prop-input" .value="${p.mode ?? 'date'}" @change="${(e) => this.setProp(field, 'mode', e.target.value)}">
1865
- <option value="date">Fecha</option>
1866
- <option value="time">Hora</option>
1867
- <option value="datetime">Fecha y Hora</option>
1868
- </select>
1869
- </div>
1870
- <div class="prop-row"><span class="prop-label">Min</span><input class="prop-input" type="date" .value="${p.min ?? ''}" @change="${(e) => this.setProp(field, 'min', e.target.value)}" /></div>
1871
- <div class="prop-row"><span class="prop-label">Max</span><input class="prop-input" type="date" .value="${p.max ?? ''}" @change="${(e) => this.setProp(field, 'max', e.target.value)}" /></div>
1872
- ` : ''}
1873
- </div>
1874
- `;
1875
- }
1876
- // ─── File/Image Props ─────────────────────────────
1877
- renderFileProps(field) {
1878
- const p = field.props ?? {};
1879
- return html `
1880
- <div class="prop-section">
1881
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('file-config')}">
1882
- <span class="collapse-icon ${this.collapsedSections.has('file-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1883
- <h4>Archivo Config</h4>
1884
- </div>
1885
- ${!this.collapsedSections.has('file-config') ? html `
1886
- <div class="prop-row"><span class="prop-label">Accept</span><input class="prop-input" .value="${p.accept ?? ''}" placeholder="image/*,.pdf" @change="${(e) => this.setProp(field, 'accept', e.target.value)}" /></div>
1887
- ${this.renderToggle('Multiple', p.multiple ?? false, (v) => this.setProp(field, 'multiple', v))}
1888
- ` : ''}
1889
- </div>
1890
- `;
1891
- }
1892
- // ─── Signature Props ──────────────────────────────
1893
- renderSignatureProps(field) {
1894
- const p = field.props ?? {};
1895
- return html `
1896
- <div class="prop-section">
1897
- <div class="prop-section-header" data-section="layout" @click="${() => this.toggleSection('sig-config')}">
1898
- <span class="collapse-icon ${this.collapsedSections.has('sig-config') ? 'collapse-icon--collapsed' : ''}">▾</span>
1899
- <h4>Firma Config</h4>
1900
- </div>
1901
- ${!this.collapsedSections.has('sig-config') ? html `
1902
- <div class="prop-row"><span class="prop-label">Grosor</span><input class="prop-input" type="number" min="1" max="10" .value="${String(p.penWidth ?? 2)}" @change="${(e) => this.setProp(field, 'penWidth', parseInt(e.target.value) || 2)}" /></div>
1903
- <div class="prop-row"><span class="prop-label">Color</span><input class="prop-input" type="color" .value="${p.penColor ?? '#000000'}" @change="${(e) => this.setProp(field, 'penColor', e.target.value)}" /></div>
1904
- ` : ''}
1905
1542
  </div>
1906
1543
  `;
1907
1544
  }
1908
- // ─── Grid Configurator Modal ────────────────────
1909
1545
  renderFormProperties() {
1910
1546
  if (!this.schema)
1911
1547
  return nothing;