@1urso/generic-editor 0.1.12 → 0.1.14

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,13 +14329,13 @@ 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(""), [L, V] = useState("asc"), [U, K] = useState("bottom"), [q, J] = useState("down"), [$, pA] = useState("150"), [mA, hA] = 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);
14334
+ F(s.listSettings.sortProp || "__none__"), V(s.listSettings.sortOrder || "asc"), K(s.listSettings.newestPosition || "bottom"), J(s.listSettings.scrollDirection || "down"), hA(s.listSettings.containerHeight ? String(s.listSettings.containerHeight) : ""), pA(String(s.canvasHeight || 150));
14335
+ }, [s.listSettings, s.canvasHeight]), useEffect(() => {
14336
+ let s = parseInt($, 10);
14337
14337
  !isNaN(s) && s > 0 && w(s);
14338
- }, [L, w]), /* @__PURE__ */ jsxs(s$2, { children: [/* @__PURE__ */ jsx(n$2, { children: /* @__PURE__ */ jsxs(o, {
14338
+ }, [$, w]), /* @__PURE__ */ jsxs(s$2, { children: [/* @__PURE__ */ jsx(n$2, { children: /* @__PURE__ */ jsxs(o, {
14339
14339
  variant: "soft",
14340
14340
  color: "gray",
14341
14341
  style: {
@@ -14394,8 +14394,8 @@ const Preview = () => {
14394
14394
  as: "div",
14395
14395
  children: "Direção"
14396
14396
  }), /* @__PURE__ */ jsxs(C, {
14397
- value: s.listSettings.sortOrder,
14398
- onValueChange: (s) => d({ sortOrder: s }),
14397
+ value: L,
14398
+ onValueChange: (s) => V(s),
14399
14399
  children: [/* @__PURE__ */ jsx(u$2, {}), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14400
14400
  value: "asc",
14401
14401
  children: "Crescente (A-Z)"
@@ -14416,8 +14416,8 @@ const Preview = () => {
14416
14416
  as: "div",
14417
14417
  children: "Posição do Recente"
14418
14418
  }), /* @__PURE__ */ jsxs(C, {
14419
- value: s.listSettings.newestPosition || "bottom",
14420
- onValueChange: (s) => d({ newestPosition: s }),
14419
+ value: U,
14420
+ onValueChange: (s) => K(s),
14421
14421
  children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14422
14422
  value: "top",
14423
14423
  children: "Topo (Início)"
@@ -14434,8 +14434,8 @@ const Preview = () => {
14434
14434
  as: "div",
14435
14435
  children: "Comportamento de Rolagem"
14436
14436
  }), /* @__PURE__ */ jsxs(C, {
14437
- value: s.listSettings.scrollDirection || "down",
14438
- onValueChange: (s) => d({ scrollDirection: s }),
14437
+ value: q,
14438
+ onValueChange: (s) => J(s),
14439
14439
  children: [/* @__PURE__ */ jsx(u$2, { style: { width: "100%" } }), /* @__PURE__ */ jsxs(g, { children: [/* @__PURE__ */ jsx(v$1, {
14440
14440
  value: "down",
14441
14441
  children: "Descer (Padrão)"
@@ -14446,25 +14446,60 @@ const Preview = () => {
14446
14446
  })]
14447
14447
  })]
14448
14448
  }),
14449
- /* @__PURE__ */ jsxs(p$1, { children: [
14450
- /* @__PURE__ */ jsx(p$2, {
14451
- size: "1",
14452
- mb: "1",
14453
- as: "div",
14454
- children: "Altura do Item da Lista (px)"
14455
- }),
14456
- /* @__PURE__ */ jsx(u, {
14457
- type: "number",
14458
- min: "10",
14459
- value: L,
14460
- onChange: (s) => V(s.target.value)
14461
- }),
14462
- /* @__PURE__ */ jsx(p$2, {
14463
- size: "1",
14464
- color: "gray",
14465
- children: "Define a altura visual de cada item na lista para referência."
14466
- })
14467
- ] }),
14449
+ /* @__PURE__ */ jsx(p$2, {
14450
+ size: "2",
14451
+ weight: "bold",
14452
+ mt: "2",
14453
+ children: "Dimensões"
14454
+ }),
14455
+ /* @__PURE__ */ jsxs(p, {
14456
+ gap: "3",
14457
+ align: "center",
14458
+ children: [/* @__PURE__ */ jsxs(p$1, {
14459
+ flexGrow: "1",
14460
+ children: [
14461
+ /* @__PURE__ */ jsx(p$2, {
14462
+ size: "1",
14463
+ mb: "1",
14464
+ as: "div",
14465
+ children: "Altura do Item (Template) (px)"
14466
+ }),
14467
+ /* @__PURE__ */ jsx(u, {
14468
+ type: "number",
14469
+ min: "10",
14470
+ value: $,
14471
+ onChange: (s) => pA(s.target.value)
14472
+ }),
14473
+ /* @__PURE__ */ jsx(p$2, {
14474
+ size: "1",
14475
+ color: "gray",
14476
+ children: "Altura de cada item individual na lista."
14477
+ })
14478
+ ]
14479
+ }), /* @__PURE__ */ jsxs(p$1, {
14480
+ flexGrow: "1",
14481
+ children: [
14482
+ /* @__PURE__ */ jsx(p$2, {
14483
+ size: "1",
14484
+ mb: "1",
14485
+ as: "div",
14486
+ children: "Altura da Lista (Container) (px)"
14487
+ }),
14488
+ /* @__PURE__ */ jsx(u, {
14489
+ type: "number",
14490
+ min: "0",
14491
+ placeholder: "Auto (100%)",
14492
+ value: mA,
14493
+ onChange: (s) => hA(s.target.value)
14494
+ }),
14495
+ /* @__PURE__ */ jsx(p$2, {
14496
+ size: "1",
14497
+ color: "gray",
14498
+ children: "Altura total da lista. Se exceder, rola. Vazio = 100%."
14499
+ })
14500
+ ]
14501
+ })]
14502
+ }),
14468
14503
  /* @__PURE__ */ jsx(p$2, {
14469
14504
  size: "1",
14470
14505
  color: "gray",
@@ -14483,7 +14518,14 @@ const Preview = () => {
14483
14518
  children: "Cancelar"
14484
14519
  }) }), /* @__PURE__ */ jsx(D$1, { children: /* @__PURE__ */ jsx(o, {
14485
14520
  onClick: () => {
14486
- d({ sortProp: k === "__none__" ? "" : k });
14521
+ let s = parseInt(mA, 10);
14522
+ d({
14523
+ sortProp: k === "__none__" ? "" : k,
14524
+ sortOrder: L,
14525
+ newestPosition: U,
14526
+ scrollDirection: q,
14527
+ containerHeight: !isNaN(s) && s > 0 ? s : void 0
14528
+ });
14487
14529
  },
14488
14530
  children: "Salvar Alterações"
14489
14531
  }) })]
@@ -14590,7 +14632,8 @@ var EditorContent = ({ layout: s, initialState: w, onSave: k, theme: F = "light"
14590
14632
  isList: X.isList,
14591
14633
  mockData: X.mockData,
14592
14634
  singleMockData: X.singleMockData,
14593
- listSettings: X.listSettings
14635
+ listSettings: X.listSettings,
14636
+ canvasHeight: X.canvasHeight
14594
14637
  };
14595
14638
  k(JSON.stringify(s, null, 2));
14596
14639
  }
@@ -14746,5 +14789,5 @@ const GenericEditor = (s) => /* @__PURE__ */ jsx(EditorProvider, {
14746
14789
  availableProps: s.layout.props,
14747
14790
  theme: s.theme,
14748
14791
  children: /* @__PURE__ */ jsx(EditorContent, { ...s })
14749
- }), 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";
14792
+ }), 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 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";
14750
14793
  export { GenericEditor as EditorContent, generateHTML };