@1urso/generic-editor 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -210,7 +210,8 @@ The output of `onSave` is a JSON ready to be stored.
210
210
  "sortProp": "nome",
211
211
  "sortOrder": "asc",
212
212
  "newestPosition": "bottom",
213
- "scrollDirection": "down"
213
+ "scrollDirection": "down",
214
+ "containerHeight": 400 // Optional: Limits the list height (scrollable)
214
215
  }
215
216
  }
216
217
  ```
@@ -16,6 +16,7 @@ export interface IListSettings {
16
16
  sortOrder: 'asc' | 'desc';
17
17
  newestPosition?: 'top' | 'bottom';
18
18
  scrollDirection?: 'up' | 'down';
19
+ containerHeight?: number;
19
20
  }
20
21
  export interface IProp {
21
22
  name: string;
@@ -14329,167 +14329,219 @@ const Preview = () => {
14329
14329
  })
14330
14330
  });
14331
14331
  }, EditorSettings = () => {
14332
- let { state: s, updateListSettings: d, setCanvasHeight: w } = useEditor(), [k, F] = useState(""), [L, V] = useState("150");
14332
+ let { state: s, updateListSettings: d, setCanvasHeight: w } = useEditor(), [k, F] = useState(!1), [L, V] = useState(""), [U, K] = useState("asc"), [q, J] = useState("bottom"), [$, pA] = useState("down"), [mA, hA] = useState("150"), [gA, _A] = useState("");
14333
14333
  return useEffect(() => {
14334
- F(s.listSettings.sortProp || "__none__"), V(String(s.canvasHeight || 150));
14335
- }, [s.listSettings.sortProp, s.canvasHeight]), useEffect(() => {
14336
- let s = parseInt(L, 10);
14337
- !isNaN(s) && s > 0 && w(s);
14338
- }, [L, w]), /* @__PURE__ */ jsxs(s$2, { children: [/* @__PURE__ */ jsx(n$2, { children: /* @__PURE__ */ jsxs(o, {
14339
- variant: "soft",
14340
- color: "gray",
14341
- style: {
14342
- width: "100%",
14343
- justifyContent: "center",
14344
- cursor: "pointer"
14345
- },
14346
- children: [/* @__PURE__ */ jsx(GearIcon, {}), " Configurações"]
14347
- }) }), /* @__PURE__ */ jsxs(p$6, {
14348
- style: { maxWidth: 600 },
14349
- children: [
14350
- /* @__PURE__ */ jsx(g$2, { children: "Configurações do Editor" }),
14351
- /* @__PURE__ */ jsx(m, {
14352
- size: "2",
14353
- mb: "4",
14354
- children: "Configure o comportamento da lista."
14355
- }),
14356
- /* @__PURE__ */ jsx(p$1, {
14357
- pt: "3",
14358
- children: /* @__PURE__ */ jsxs(p, {
14359
- direction: "column",
14360
- gap: "3",
14361
- children: [
14362
- /* @__PURE__ */ jsx(p$2, {
14363
- size: "2",
14364
- weight: "bold",
14365
- children: "Ordenação"
14366
- }),
14367
- /* @__PURE__ */ jsxs(p, {
14368
- gap: "3",
14369
- align: "center",
14370
- children: [/* @__PURE__ */ jsxs(p$1, {
14371
- flexGrow: "1",
14372
- children: [/* @__PURE__ */ jsx(p$2, {
14373
- size: "1",
14374
- mb: "1",
14375
- as: "div",
14376
- children: "Propriedade para Ordenar (ex: data, id)"
14377
- }), /* @__PURE__ */ jsxs(C, {
14378
- value: k,
14379
- onValueChange: (s) => F(s),
14380
- children: [/* @__PURE__ */ jsx(u$2, {
14381
- style: { width: "100%" },
14382
- placeholder: "Selecione..."
14383
- }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14384
- value: "__none__",
14385
- children: "(Nenhum)"
14386
- }), s.availableProps.map((s) => /* @__PURE__ */ jsx(v$1, {
14387
- value: s.dataName,
14388
- children: s.name
14389
- }, s.dataName))] })]
14390
- })]
14391
- }), /* @__PURE__ */ jsxs(p$1, { children: [/* @__PURE__ */ jsx(p$2, {
14392
- size: "1",
14393
- mb: "1",
14394
- as: "div",
14395
- children: "Direção"
14396
- }), /* @__PURE__ */ jsxs(C, {
14397
- value: s.listSettings.sortOrder,
14398
- onValueChange: (s) => d({ sortOrder: s }),
14399
- children: [/* @__PURE__ */ jsx(u$2, {}), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14400
- value: "asc",
14401
- children: "Crescente (A-Z)"
14402
- }), /* @__PURE__ */ jsx(v$1, {
14403
- value: "desc",
14404
- children: "Decrescente (Z-A)"
14405
- })] })]
14406
- })] })]
14407
- }),
14408
- /* @__PURE__ */ jsxs(p, {
14409
- gap: "3",
14410
- align: "center",
14411
- children: [/* @__PURE__ */ jsxs(p$1, {
14412
- flexGrow: "1",
14413
- children: [/* @__PURE__ */ jsx(p$2, {
14414
- size: "1",
14415
- mb: "1",
14416
- as: "div",
14417
- children: "Posição do Recente"
14418
- }), /* @__PURE__ */ jsxs(C, {
14419
- value: s.listSettings.newestPosition || "bottom",
14420
- onValueChange: (s) => d({ newestPosition: s }),
14421
- children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14422
- value: "top",
14423
- children: "Topo (Início)"
14424
- }), /* @__PURE__ */ jsx(v$1, {
14425
- value: "bottom",
14426
- children: "Base (Final)"
14427
- })] })]
14428
- })]
14429
- }), /* @__PURE__ */ jsxs(p$1, {
14430
- flexGrow: "1",
14431
- children: [/* @__PURE__ */ jsx(p$2, {
14334
+ k && (V(s.listSettings.sortProp || "__none__"), K(s.listSettings.sortOrder || "asc"), J(s.listSettings.newestPosition || "bottom"), pA(s.listSettings.scrollDirection || "down"), _A(s.listSettings.containerHeight ? String(s.listSettings.containerHeight) : ""), hA(String(s.canvasHeight || 150)));
14335
+ }, [k]), useEffect(() => {
14336
+ if (!k) return;
14337
+ let d = parseInt(mA, 10);
14338
+ !isNaN(d) && d > 0 && s.canvasHeight !== d && w(d);
14339
+ }, [
14340
+ mA,
14341
+ k,
14342
+ w,
14343
+ s.canvasHeight
14344
+ ]), /* @__PURE__ */ jsxs(s$2, {
14345
+ open: k,
14346
+ onOpenChange: F,
14347
+ children: [/* @__PURE__ */ jsx(n$2, { children: /* @__PURE__ */ jsxs(o, {
14348
+ variant: "soft",
14349
+ color: "gray",
14350
+ style: {
14351
+ width: "100%",
14352
+ justifyContent: "center",
14353
+ cursor: "pointer"
14354
+ },
14355
+ children: [/* @__PURE__ */ jsx(GearIcon, {}), " Configurações"]
14356
+ }) }), /* @__PURE__ */ jsxs(p$6, {
14357
+ style: { maxWidth: 600 },
14358
+ children: [
14359
+ /* @__PURE__ */ jsx(g$2, { children: "Configurações do Editor" }),
14360
+ /* @__PURE__ */ jsx(m, {
14361
+ size: "2",
14362
+ mb: "4",
14363
+ children: "Configure o comportamento da lista."
14364
+ }),
14365
+ /* @__PURE__ */ jsx(p$1, {
14366
+ pt: "3",
14367
+ children: /* @__PURE__ */ jsxs(p, {
14368
+ direction: "column",
14369
+ gap: "3",
14370
+ children: [
14371
+ /* @__PURE__ */ jsx(p$2, {
14372
+ size: "2",
14373
+ weight: "bold",
14374
+ children: "Ordenação"
14375
+ }),
14376
+ /* @__PURE__ */ jsxs(p, {
14377
+ gap: "3",
14378
+ align: "center",
14379
+ children: [/* @__PURE__ */ jsxs(p$1, {
14380
+ flexGrow: "1",
14381
+ children: [/* @__PURE__ */ jsx(p$2, {
14382
+ size: "1",
14383
+ mb: "1",
14384
+ as: "div",
14385
+ children: "Propriedade para Ordenar (ex: data, id)"
14386
+ }), /* @__PURE__ */ jsxs(C, {
14387
+ value: L,
14388
+ onValueChange: (s) => V(s),
14389
+ children: [/* @__PURE__ */ jsx(u$2, {
14390
+ style: { width: "100%" },
14391
+ placeholder: "Selecione..."
14392
+ }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14393
+ value: "__none__",
14394
+ children: "(Nenhum)"
14395
+ }), s.availableProps.map((s) => /* @__PURE__ */ jsx(v$1, {
14396
+ value: s.dataName,
14397
+ children: s.name
14398
+ }, s.dataName))] })]
14399
+ })]
14400
+ }), /* @__PURE__ */ jsxs(p$1, { children: [/* @__PURE__ */ jsx(p$2, {
14432
14401
  size: "1",
14433
14402
  mb: "1",
14434
14403
  as: "div",
14435
- children: "Comportamento de Rolagem"
14404
+ children: "Direção"
14436
14405
  }), /* @__PURE__ */ jsxs(C, {
14437
- value: s.listSettings.scrollDirection || "down",
14438
- onValueChange: (s) => d({ scrollDirection: s }),
14439
- children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14440
- value: "down",
14441
- children: "Descer (Padrão)"
14406
+ value: U,
14407
+ onValueChange: (s) => K(s),
14408
+ children: [/* @__PURE__ */ jsx(u$2, {}), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14409
+ value: "asc",
14410
+ children: "Crescente (A-Z)"
14442
14411
  }), /* @__PURE__ */ jsx(v$1, {
14443
- value: "up",
14444
- children: "Subir (Chat)"
14412
+ value: "desc",
14413
+ children: "Decrescente (Z-A)"
14445
14414
  })] })]
14415
+ })] })]
14416
+ }),
14417
+ /* @__PURE__ */ jsxs(p, {
14418
+ gap: "3",
14419
+ align: "center",
14420
+ children: [/* @__PURE__ */ jsxs(p$1, {
14421
+ flexGrow: "1",
14422
+ children: [/* @__PURE__ */ jsx(p$2, {
14423
+ size: "1",
14424
+ mb: "1",
14425
+ as: "div",
14426
+ children: "Posição do Recente"
14427
+ }), /* @__PURE__ */ jsxs(C, {
14428
+ value: q,
14429
+ onValueChange: (s) => J(s),
14430
+ children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14431
+ value: "top",
14432
+ children: "Topo (Início)"
14433
+ }), /* @__PURE__ */ jsx(v$1, {
14434
+ value: "bottom",
14435
+ children: "Base (Final)"
14436
+ })] })]
14437
+ })]
14438
+ }), /* @__PURE__ */ jsxs(p$1, {
14439
+ flexGrow: "1",
14440
+ children: [/* @__PURE__ */ jsx(p$2, {
14441
+ size: "1",
14442
+ mb: "1",
14443
+ as: "div",
14444
+ children: "Comportamento de Rolagem"
14445
+ }), /* @__PURE__ */ jsxs(C, {
14446
+ value: $,
14447
+ onValueChange: (s) => pA(s),
14448
+ children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14449
+ value: "down",
14450
+ children: "Descer (Padrão)"
14451
+ }), /* @__PURE__ */ jsx(v$1, {
14452
+ value: "up",
14453
+ children: "Subir (Chat)"
14454
+ })] })]
14455
+ })]
14446
14456
  })]
14447
- })]
14448
- }),
14449
- /* @__PURE__ */ jsxs(p$1, { children: [
14457
+ }),
14450
14458
  /* @__PURE__ */ jsx(p$2, {
14451
- size: "1",
14452
- mb: "1",
14453
- as: "div",
14454
- children: "Altura do Item da Lista (px)"
14459
+ size: "2",
14460
+ weight: "bold",
14461
+ mt: "2",
14462
+ children: "Dimensões"
14455
14463
  }),
14456
- /* @__PURE__ */ jsx(u, {
14457
- type: "number",
14458
- min: "10",
14459
- value: L,
14460
- onChange: (s) => V(s.target.value)
14464
+ /* @__PURE__ */ jsxs(p, {
14465
+ gap: "3",
14466
+ align: "center",
14467
+ children: [/* @__PURE__ */ jsxs(p$1, {
14468
+ flexGrow: "1",
14469
+ children: [
14470
+ /* @__PURE__ */ jsx(p$2, {
14471
+ size: "1",
14472
+ mb: "1",
14473
+ as: "div",
14474
+ children: "Altura do Item (Template) (px)"
14475
+ }),
14476
+ /* @__PURE__ */ jsx(u, {
14477
+ type: "number",
14478
+ min: "10",
14479
+ value: mA,
14480
+ onChange: (s) => hA(s.target.value)
14481
+ }),
14482
+ /* @__PURE__ */ jsx(p$2, {
14483
+ size: "1",
14484
+ color: "gray",
14485
+ children: "Altura de cada item individual na lista."
14486
+ })
14487
+ ]
14488
+ }), /* @__PURE__ */ jsxs(p$1, {
14489
+ flexGrow: "1",
14490
+ children: [
14491
+ /* @__PURE__ */ jsx(p$2, {
14492
+ size: "1",
14493
+ mb: "1",
14494
+ as: "div",
14495
+ children: "Altura da Lista (Container) (px)"
14496
+ }),
14497
+ /* @__PURE__ */ jsx(u, {
14498
+ type: "number",
14499
+ min: "0",
14500
+ placeholder: "Auto (100%)",
14501
+ value: gA,
14502
+ onChange: (s) => _A(s.target.value)
14503
+ }),
14504
+ /* @__PURE__ */ jsx(p$2, {
14505
+ size: "1",
14506
+ color: "gray",
14507
+ children: "Altura total da lista. Se exceder, rola. Vazio = 100%."
14508
+ })
14509
+ ]
14510
+ })]
14461
14511
  }),
14462
14512
  /* @__PURE__ */ jsx(p$2, {
14463
14513
  size: "1",
14464
14514
  color: "gray",
14465
- children: "Define a altura visual de cada item na lista para referência."
14515
+ children: "Essa propriedade será usada para ordenar os itens no modo lista."
14466
14516
  })
14467
- ] }),
14468
- /* @__PURE__ */ jsx(p$2, {
14469
- size: "1",
14470
- color: "gray",
14471
- children: "Essa propriedade será usada para ordenar os itens no modo lista."
14472
- })
14473
- ]
14517
+ ]
14518
+ })
14519
+ }),
14520
+ /* @__PURE__ */ jsxs(p, {
14521
+ gap: "3",
14522
+ mt: "4",
14523
+ justify: "end",
14524
+ children: [/* @__PURE__ */ jsx(D$1, { children: /* @__PURE__ */ jsx(o, {
14525
+ variant: "soft",
14526
+ color: "gray",
14527
+ children: "Cancelar"
14528
+ }) }), /* @__PURE__ */ jsx(D$1, { children: /* @__PURE__ */ jsx(o, {
14529
+ onClick: () => {
14530
+ let s = parseInt(gA, 10);
14531
+ d({
14532
+ sortProp: L === "__none__" ? "" : L,
14533
+ sortOrder: U,
14534
+ newestPosition: q,
14535
+ scrollDirection: $,
14536
+ containerHeight: !isNaN(s) && s > 0 ? s : void 0
14537
+ }), F(!1);
14538
+ },
14539
+ children: "Salvar Alterações"
14540
+ }) })]
14474
14541
  })
14475
- }),
14476
- /* @__PURE__ */ jsxs(p, {
14477
- gap: "3",
14478
- mt: "4",
14479
- justify: "end",
14480
- children: [/* @__PURE__ */ jsx(D$1, { children: /* @__PURE__ */ jsx(o, {
14481
- variant: "soft",
14482
- color: "gray",
14483
- children: "Cancelar"
14484
- }) }), /* @__PURE__ */ jsx(D$1, { children: /* @__PURE__ */ jsx(o, {
14485
- onClick: () => {
14486
- d({ sortProp: k === "__none__" ? "" : k });
14487
- },
14488
- children: "Salvar Alterações"
14489
- }) })]
14490
- })
14491
- ]
14492
- })] });
14542
+ ]
14543
+ })]
14544
+ });
14493
14545
  };
14494
14546
  var EditorContent = ({ layout: s, initialState: w, onSave: k, theme: F = "light" }) => {
14495
14547
  let [L, V] = useState(!0), [U, K] = useState(!0), { addElement: q, loadState: J, state: X } = useEditor();
@@ -14747,5 +14799,5 @@ const GenericEditor = (s) => /* @__PURE__ */ jsx(EditorProvider, {
14747
14799
  availableProps: s.layout.props,
14748
14800
  theme: s.theme,
14749
14801
  children: /* @__PURE__ */ jsx(EditorContent, { ...s })
14750
- }), generateHTML = (s, d, w = {}) => Function("elements", "data", "options", getRendererCode() + "\nreturn renderTemplate(elements, data, options);")(s, d, w), getRendererCode = () => "\n/**\n * Render Template\n * @param {Array} elements - The JSON configuration of elements\n * @param {Object|Array} data - The data object to inject (Object for single, Array for list)\n * @param {Object} options - { isList: boolean, listSettings: { sortProp: string, sortOrder: 'asc'|'desc', newestPosition: 'top'|'bottom', scrollDirection: 'up'|'down' }, canvasHeight: number }\n * @returns {string} - The generated HTML string\n */\nfunction renderTemplate(elements, data, options = {}) {\n const { isList, listSettings, canvasHeight } = options;\n\n const camelToKebab = (string) => {\n return string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();\n };\n\n const styleObjectToString = (style) => {\n if (!style) return '';\n const pxProps = ['width', 'height', 'top', 'left', 'right', 'bottom', 'fontSize', 'borderRadius', 'padding', 'margin', 'borderWidth'];\n \n return Object.entries(style)\n .map(([key, value]) => {\n if (value === undefined || value === null) return '';\n const cssKey = camelToKebab(key);\n const cssValue = (typeof value === 'number' && pxProps.includes(key)) ? value + 'px' : value;\n return `${cssKey}: ${cssValue}`;\n })\n .filter(Boolean)\n .join('; ');\n };\n\n const renderItem = (itemData, index = 0, offsetY = 0) => {\n return elements.map(element => {\n let content = element.content;\n let imgSrc = '';\n\n if (element.type === 'text') {\n content = content.replace(/\\{\\{(.*?)\\}\\}/g, (match, key) => {\n const val = itemData[key.trim()];\n return val !== undefined && val !== null ? String(val) : match;\n });\n } else if (element.type === 'image') {\n if (element.dataBinding) {\n const val = itemData[element.dataBinding];\n if (val !== undefined && val !== null) {\n imgSrc = String(val);\n } else {\n imgSrc = content;\n }\n } else {\n imgSrc = content.replace(/\\{\\{(.*?)\\}\\}/g, (match, key) => {\n const val = itemData[key.trim()];\n return val !== undefined && val !== null ? String(val) : match;\n });\n }\n }\n\n const baseStyle = {\n position: 'absolute',\n left: element.x,\n top: element.y + offsetY,\n width: element.width,\n height: element.height,\n transform: element.rotation ? `rotate(${element.rotation}deg)` : undefined,\n overflow: 'hidden',\n ...element.style\n };\n \n // Fix: remove padding if it's not explicitly set, or handle it for text\n if (element.type === 'text' && !baseStyle.padding) {\n // baseStyle.padding = '8px'; // Removed default padding to respect resize box\n }\n \n const styleString = styleObjectToString(baseStyle);\n\n if (element.type === 'text') {\n return `<div style=\"${styleString}\">${content}</div>`;\n } else if (element.type === 'image') {\n const imgStyle = styleObjectToString({\n width: '100%',\n height: '100%',\n objectFit: element.style?.objectFit || 'cover',\n display: 'block'\n });\n return `<div style=\"${styleString}\"><img src=\"${imgSrc}\" alt=\"Element\" style=\"${imgStyle}\" /></div>`;\n } else if (element.type === 'box') {\n return `<div style=\"${styleString}\"></div>`;\n }\n return '';\n }).join('\\n');\n };\n\n if (isList && Array.isArray(data)) {\n // Calculate item height\n const itemHeight = canvasHeight || Math.max(...elements.map(el => el.y + el.height));\n\n // Sort data\n let listData = [...data];\n if (listSettings && listSettings.sortProp) {\n const prop = listSettings.sortProp;\n const order = listSettings.sortOrder === 'asc' ? 1 : -1;\n listData.sort((a, b) => {\n const valA = a[prop];\n const valB = b[prop];\n if (valA < valB) return -1 * order;\n if (valA > valB) return 1 * order;\n return 0;\n });\n }\n \n // Handle newest position\n if (listSettings && listSettings.newestPosition === 'top') {\n listData.reverse();\n }\n\n // Generate HTML for all items\n const itemsHtml = listData.map((item, index) => {\n const itemHtml = renderItem(item, index, 0); \n const itemContainerStyle = styleObjectToString({\n position: 'relative',\n height: itemHeight,\n width: '100%',\n marginBottom: 0\n });\n \n return `<div class=\"list-item\" style=\"${itemContainerStyle}\">${itemHtml}</div>`;\n }).join('\\n');\n\n // Animation Styles based on settings\n const scrollDirection = (listSettings && listSettings.scrollDirection) || 'down';\n \n const justify = (listSettings && listSettings.newestPosition === 'top') ? 'flex-start' : 'flex-end';\n\n const animationCss = `\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .list-wrapper {\n display: flex;\n flex-direction: column;\n justify-content: ${justify};\n height: 100%;\n width: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n box-sizing: border-box;\n padding: 10px;\n }\n .list-item {\n flex-shrink: 0;\n animation: slideIn 0.3s ease-out;\n margin-bottom: 10px;\n width: 100%;\n position: relative;\n }\n `;\n\n return `\n <style>${animationCss}</style>\n <div class=\"list-wrapper\">\n ${itemsHtml}\n </div>\n `;\n }\n\n // Single Item\n const contentHtml = renderItem(data);\n return `<div style=\"position: relative; width: 100%; height: 100%; overflow: hidden;\">${contentHtml}</div>`;\n}\n";
14802
+ }), generateHTML = (s, d, w = {}) => Function("elements", "data", "options", getRendererCode() + "\nreturn renderTemplate(elements, data, options);")(s, d, w), getRendererCode = () => "\n/**\n * Render Template\n * @param {Array} elements - The JSON configuration of elements\n * @param {Object|Array} data - The data object to inject (Object for single, Array for list)\n * @param {Object} options - { isList: boolean, listSettings: { sortProp: string, sortOrder: 'asc'|'desc', newestPosition: 'top'|'bottom', scrollDirection: 'up'|'down' }, canvasHeight: number }\n * @returns {string} - The generated HTML string\n */\nfunction renderTemplate(elements, data, options = {}) {\n const { isList, listSettings, canvasHeight } = options;\n\n const camelToKebab = (string) => {\n return string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();\n };\n\n const styleObjectToString = (style) => {\n if (!style) return '';\n const pxProps = ['width', 'height', 'top', 'left', 'right', 'bottom', 'fontSize', 'borderRadius', 'padding', 'margin', 'borderWidth'];\n \n return Object.entries(style)\n .map(([key, value]) => {\n if (value === undefined || value === null) return '';\n const cssKey = camelToKebab(key);\n const cssValue = (typeof value === 'number' && pxProps.includes(key)) ? value + 'px' : value;\n return `${cssKey}: ${cssValue}`;\n })\n .filter(Boolean)\n .join('; ');\n };\n\n const renderItem = (itemData, index = 0, offsetY = 0) => {\n return elements.map(element => {\n let content = element.content;\n let imgSrc = '';\n\n if (element.type === 'text') {\n content = content.replace(/\\{\\{(.*?)\\}\\}/g, (match, key) => {\n const val = itemData[key.trim()];\n return val !== undefined && val !== null ? String(val) : match;\n });\n } else if (element.type === 'image') {\n if (element.dataBinding) {\n const val = itemData[element.dataBinding];\n if (val !== undefined && val !== null) {\n imgSrc = String(val);\n } else {\n imgSrc = content;\n }\n } else {\n imgSrc = content.replace(/\\{\\{(.*?)\\}\\}/g, (match, key) => {\n const val = itemData[key.trim()];\n return val !== undefined && val !== null ? String(val) : match;\n });\n }\n }\n\n const baseStyle = {\n position: 'absolute',\n left: element.x,\n top: element.y + offsetY,\n width: element.width,\n height: element.height,\n transform: element.rotation ? `rotate(${element.rotation}deg)` : undefined,\n overflow: 'hidden',\n ...element.style\n };\n \n // Fix: remove padding if it's not explicitly set, or handle it for text\n if (element.type === 'text' && !baseStyle.padding) {\n // baseStyle.padding = '8px'; // Removed default padding to respect resize box\n }\n \n const styleString = styleObjectToString(baseStyle);\n\n if (element.type === 'text') {\n return `<div style=\"${styleString}\">${content}</div>`;\n } else if (element.type === 'image') {\n const imgStyle = styleObjectToString({\n width: '100%',\n height: '100%',\n objectFit: element.style?.objectFit || 'cover',\n display: 'block'\n });\n return `<div style=\"${styleString}\"><img src=\"${imgSrc}\" alt=\"Element\" style=\"${imgStyle}\" /></div>`;\n } else if (element.type === 'box') {\n return `<div style=\"${styleString}\"></div>`;\n }\n return '';\n }).join('\\n');\n };\n\n if (isList && Array.isArray(data)) {\n // Calculate item height\n const itemHeight = canvasHeight || Math.max(...elements.map(el => el.y + el.height));\n\n // Sort data\n let listData = [...data];\n if (listSettings && listSettings.sortProp) {\n const prop = listSettings.sortProp;\n const order = listSettings.sortOrder === 'asc' ? 1 : -1;\n listData.sort((a, b) => {\n const valA = a[prop];\n const valB = b[prop];\n if (valA < valB) return -1 * order;\n if (valA > valB) return 1 * order;\n return 0;\n });\n }\n \n // Handle newest position\n if (listSettings && listSettings.newestPosition === 'top') {\n listData.reverse();\n }\n\n // Generate HTML for all items\n const itemsHtml = listData.map((item, index) => {\n const itemHtml = renderItem(item, index, 0); \n const itemContainerStyle = styleObjectToString({\n position: 'relative',\n height: itemHeight,\n width: '100%',\n marginBottom: 0\n });\n \n return `<div class=\"list-item\" style=\"${itemContainerStyle}\">${itemHtml}</div>`;\n }).join('\\n');\n\n // Animation Styles based on settings\n const scrollDirection = (listSettings && listSettings.scrollDirection) || 'down';\n const containerHeight = (listSettings && listSettings.containerHeight) ? listSettings.containerHeight + 'px' : '100%';\n \n const justify = (listSettings && listSettings.newestPosition === 'top') ? 'flex-start' : 'flex-end';\n\n const animationCss = `\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .list-wrapper {\n display: flex;\n flex-direction: column;\n justify-content: ${justify};\n height: ${containerHeight};\n width: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n box-sizing: border-box;\n padding: 10px;\n }\n .list-item {\n flex-shrink: 0;\n animation: slideIn 0.3s ease-out;\n margin-bottom: 10px;\n width: 100%;\n position: relative;\n }\n `;\n \n const scrollScript = scrollDirection === 'up' \n ? `<script>\n document.addEventListener('DOMContentLoaded', () => {\n const wrapper = document.querySelector('.list-wrapper');\n if(wrapper) wrapper.scrollTop = wrapper.scrollHeight;\n });\n <\/script>`\n : '';\n\n return `\n <style>${animationCss}</style>\n <div class=\"list-wrapper\">\n ${itemsHtml}\n </div>\n ${scrollScript}\n `;\n }\n\n // Single Item\n const contentHtml = renderItem(data);\n return `<div style=\"position: relative; width: 100%; height: 100%; overflow: hidden;\">${contentHtml}</div>`;\n}\n";
14751
14803
  export { GenericEditor as EditorContent, generateHTML };