lib-pixelbuild 0.2.2 → 0.3.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.
Files changed (72) hide show
  1. package/dist/builders/PageBuilder.js +42 -29
  2. package/dist/components/ButtonsComponent.js +6 -5
  3. package/dist/components/CardComponent.js +13 -7
  4. package/dist/components/FormComponent.js +3 -2
  5. package/dist/components/IconComponent.d.ts +5 -0
  6. package/dist/components/IconComponent.js +12 -0
  7. package/dist/components/ImageComponent.js +4 -3
  8. package/dist/components/ListComponent.js +1 -2
  9. package/dist/components/LoadingComponent.js +2 -2
  10. package/dist/components/MapComponent.js +10 -11
  11. package/dist/components/SliderComponent.d.ts +1 -1
  12. package/dist/components/SliderComponent.js +8 -10
  13. package/dist/components/SocialIconsComponent.js +3 -4
  14. package/dist/components/TextComponent.js +3 -2
  15. package/dist/components/VideoComponent.d.ts +4 -0
  16. package/dist/components/VideoComponent.js +34 -0
  17. package/dist/constants/ComponentEnum.d.ts +1 -0
  18. package/dist/constants/ComponentEnum.js +1 -0
  19. package/dist/designSystem/baseCss.d.ts +8 -0
  20. package/dist/designSystem/baseCss.js +406 -0
  21. package/dist/designSystem/buildSiteCss.d.ts +8 -0
  22. package/dist/designSystem/buildSiteCss.js +11 -0
  23. package/dist/designSystem/index.d.ts +6 -0
  24. package/dist/designSystem/index.js +5 -0
  25. package/dist/designSystem/theme.d.ts +9 -0
  26. package/dist/designSystem/theme.js +11 -0
  27. package/dist/designSystem/themeVars.d.ts +8 -0
  28. package/dist/designSystem/themeVars.js +9 -0
  29. package/dist/designSystem/tokens.d.ts +82 -0
  30. package/dist/designSystem/tokens.js +144 -0
  31. package/dist/elements/AlertElement.js +4 -4
  32. package/dist/elements/ButtonElement.js +5 -3
  33. package/dist/elements/ElementColWrapper.js +2 -2
  34. package/dist/elements/IconMap.js +2 -2
  35. package/dist/elements/InputElement.js +10 -9
  36. package/dist/elements/TextElement.js +4 -0
  37. package/dist/factories/ComponentFactory.d.ts +2 -1
  38. package/dist/factories/ComponentFactory.js +28 -11
  39. package/dist/index.d.ts +16 -3
  40. package/dist/index.js +14 -1
  41. package/dist/layouts/Footer.js +16 -5
  42. package/dist/layouts/Header.js +20 -10
  43. package/dist/layouts/SiteLayout.js +3 -2
  44. package/dist/renderers/BlockRenderer.d.ts +8 -0
  45. package/dist/renderers/BlockRenderer.js +68 -0
  46. package/dist/types/{SectionColumnType.d.ts → BlockType.d.ts} +2 -6
  47. package/dist/types/ComponentType.d.ts +3 -0
  48. package/dist/types/PageType.d.ts +2 -2
  49. package/dist/types/WebsiteType.d.ts +5 -0
  50. package/dist/ui/PbAlert.d.ts +10 -0
  51. package/dist/ui/PbAlert.js +8 -0
  52. package/dist/ui/PbButton.d.ts +20 -0
  53. package/dist/ui/PbButton.js +20 -0
  54. package/dist/ui/PbCol.d.ts +14 -0
  55. package/dist/ui/PbCol.js +43 -0
  56. package/dist/ui/PbContainer.d.ts +7 -0
  57. package/dist/ui/PbContainer.js +17 -0
  58. package/dist/ui/PbRow.d.ts +7 -0
  59. package/dist/ui/PbRow.js +17 -0
  60. package/dist/ui/PbSpinner.d.ts +3 -0
  61. package/dist/ui/PbSpinner.js +5 -0
  62. package/dist/ui/index.d.ts +6 -0
  63. package/dist/ui/index.js +6 -0
  64. package/dist/utils/imageCustomization.js +1 -3
  65. package/dist/utils/responsiveStyles.d.ts +2 -2
  66. package/dist/utils/responsiveStyles.js +10 -19
  67. package/package.json +1 -6
  68. package/dist/renderers/SectionRenderer.d.ts +0 -6
  69. package/dist/renderers/SectionRenderer.js +0 -88
  70. package/dist/types/SectionType.d.ts +0 -10
  71. package/dist/types/SectionType.js +0 -1
  72. /package/dist/types/{SectionColumnType.js → BlockType.js} +0 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Design System tokens.
3
+ *
4
+ * Fontes de verdade para cores, tipografia, espaçamento, raio e sombra do site
5
+ * público. Cada token é exposto como uma variável CSS `--pb-*` e os componentes
6
+ * do `lib-pixelbuild` consomem via `var(--pb-*, <fallback>)`, de forma que um
7
+ * site sem design system configurado continua com aparência padrão.
8
+ */
9
+ /**
10
+ * Valores padrão. Mantidos neutros e modernos para que um site sem
11
+ * personalização não tenha cara de "framework genérico".
12
+ */
13
+ export const defaultTokens = {
14
+ colors: {
15
+ primary: '#F58220',
16
+ secondary: '#64748B',
17
+ success: '#16A34A',
18
+ danger: '#DC2626',
19
+ warning: '#F59E0B',
20
+ info: '#0EA5E9',
21
+ light: '#F8FAFC',
22
+ dark: '#0F172A',
23
+ background: '#FFFFFF',
24
+ surface: '#FFFFFF',
25
+ text: '#1F2937',
26
+ heading: '#111827',
27
+ muted: '#6B7280',
28
+ border: '#E5E7EB'
29
+ },
30
+ typography: {
31
+ fontFamily: "'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
32
+ fontSizeBase: '16px',
33
+ fontWeightNormal: '400',
34
+ fontWeightBold: '700',
35
+ lineHeight: '1.6'
36
+ },
37
+ spacing: {
38
+ none: '0',
39
+ xs: '4px',
40
+ sm: '8px',
41
+ md: '16px',
42
+ lg: '24px',
43
+ xl: '32px',
44
+ xxl: '48px'
45
+ },
46
+ radius: {
47
+ none: '0',
48
+ sm: '4px',
49
+ md: '8px',
50
+ lg: '12px',
51
+ full: '9999px'
52
+ },
53
+ shadow: {
54
+ none: 'none',
55
+ sm: '0 1px 2px rgba(0,0,0,0.05)',
56
+ md: '0 4px 12px rgba(0,0,0,0.08)',
57
+ lg: '0 8px 24px rgba(0,0,0,0.12)'
58
+ },
59
+ gutter: '1.5rem'
60
+ };
61
+ function mergePartial(base, partial) {
62
+ if (!partial)
63
+ return base;
64
+ const result = Object.assign({}, base);
65
+ for (const key of Object.keys(partial)) {
66
+ const value = partial[key];
67
+ if (value === undefined)
68
+ continue;
69
+ const baseValue = base[key];
70
+ if (typeof baseValue === 'object' && baseValue !== null && typeof value === 'object' && value !== null) {
71
+ ;
72
+ result[key] = Object.assign(Object.assign({}, baseValue), value);
73
+ }
74
+ else {
75
+ ;
76
+ result[key] = value;
77
+ }
78
+ }
79
+ return result;
80
+ }
81
+ export function mergeTokens(base, partial) {
82
+ const merged = mergePartial(base, partial || {});
83
+ return merged;
84
+ }
85
+ /** Mapeia os tokens para pares `--pb-*` → valor. */
86
+ export function tokenToCssVars(tokens) {
87
+ const { colors, typography, spacing, radius, shadow } = tokens;
88
+ return {
89
+ '--pb-color-primary': colors.primary,
90
+ '--pb-color-secondary': colors.secondary,
91
+ '--pb-color-success': colors.success,
92
+ '--pb-color-danger': colors.danger,
93
+ '--pb-color-warning': colors.warning,
94
+ '--pb-color-info': colors.info,
95
+ '--pb-color-light': colors.light,
96
+ '--pb-color-dark': colors.dark,
97
+ '--pb-color-background': colors.background,
98
+ '--pb-color-surface': colors.surface,
99
+ '--pb-color-text': colors.text,
100
+ '--pb-color-heading': colors.heading,
101
+ '--pb-color-muted': colors.muted,
102
+ '--pb-color-border': colors.border,
103
+ '--pb-font-family': typography.fontFamily,
104
+ '--pb-font-size-base': typography.fontSizeBase,
105
+ '--pb-font-weight-normal': typography.fontWeightNormal,
106
+ '--pb-font-weight-bold': typography.fontWeightBold,
107
+ '--pb-line-height': typography.lineHeight,
108
+ '--pb-space-none': spacing.none,
109
+ '--pb-space-xs': spacing.xs,
110
+ '--pb-space-sm': spacing.sm,
111
+ '--pb-space-md': spacing.md,
112
+ '--pb-space-lg': spacing.lg,
113
+ '--pb-space-xl': spacing.xl,
114
+ '--pb-space-xxl': spacing.xxl,
115
+ '--pb-radius-none': radius.none,
116
+ '--pb-radius-sm': radius.sm,
117
+ '--pb-radius-md': radius.md,
118
+ '--pb-radius-lg': radius.lg,
119
+ '--pb-radius-full': radius.full,
120
+ '--pb-shadow-none': shadow.none,
121
+ '--pb-shadow-sm': shadow.sm,
122
+ '--pb-shadow-md': shadow.md,
123
+ '--pb-shadow-lg': shadow.lg,
124
+ '--pb-gutter': tokens.gutter
125
+ };
126
+ }
127
+ /** Gera o bloco `:root { --pb-*: ... }` a partir dos tokens (com defaults). */
128
+ export function buildTokenCss(tokens) {
129
+ const merged = mergeTokens(defaultTokens, tokens);
130
+ const vars = tokenToCssVars(merged);
131
+ const lines = Object.entries(vars)
132
+ .map(([key, value]) => ` ${key}: ${value};`)
133
+ .join('\n');
134
+ return `:root {\n${lines}\n}`;
135
+ }
136
+ /**
137
+ * Retorna o mapa de variáveis `--pb-*` (com defaults mesclados) para aplicação
138
+ * inline em um elemento raiz — permite que a troca de token reflita em tempo
139
+ * real no preview sem reinjetar o `<head>`.
140
+ */
141
+ export function buildThemeVars(designSystem) {
142
+ const merged = mergeTokens(defaultTokens, designSystem);
143
+ return tokenToCssVars(merged);
144
+ }
@@ -1,6 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect } from 'react';
3
- import { Alert } from 'react-bootstrap';
3
+ import { PbAlert } from '../ui/PbAlert.js';
4
4
  import { UseFormStore } from '../stores/UseFormStore.js';
5
5
  import { ElementColWrapper } from './ElementColWrapper.js';
6
6
  import { getString, getNumber, getBoolean } from '../utils/propertyUtils.js';
@@ -16,8 +16,8 @@ export function AlertElement({ element, formId }) {
16
16
  hidden: getBoolean(properties, 'startHidden')
17
17
  });
18
18
  return () => unregisterElement(element.id);
19
- }, [element.id, properties.startHidden, registerElement, resolvedFormId, unregisterElement]);
19
+ }, [element.id, properties.startHidden, registerElement, unregisterElement, resolvedFormId]);
20
20
  if (hidden)
21
21
  return null;
22
- return (_jsx(ElementColWrapper, { element: element, children: _jsxs(Alert, { variant: getString(properties, 'type', 'info'), style: element.styles, children: [_jsx(Alert.Heading, { children: getString(properties, 'title') }), _jsx("p", { className: "mb-0", children: getString(properties, 'message') })] }) }));
22
+ return (_jsx(ElementColWrapper, { element: element, children: _jsx(PbAlert, { variant: getString(properties, 'type', 'info'), style: element.styles, title: getString(properties, 'title'), children: _jsx("p", { className: "pb-mb-0", children: getString(properties, 'message') }) }) }));
23
23
  }
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from 'react';
3
- import { Button, Spinner } from 'react-bootstrap';
4
3
  import { ElementColWrapper } from './ElementColWrapper.js';
4
+ import { PbButton } from '../ui/PbButton.js';
5
+ import { PbSpinner } from '../ui/PbSpinner.js';
5
6
  import { UseFormStore } from '../stores/UseFormStore.js';
6
7
  import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
7
8
  import { ButtonActionEnum } from '../constants/ButtonActionEnum.js';
@@ -21,7 +22,7 @@ export function ButtonElement({ element, formId }) {
21
22
  hidden: getBoolean(properties, 'startHidden')
22
23
  });
23
24
  return () => unregisterElement(element.id);
24
- }, [element.id, properties.startHidden, registerElement, resolvedFormId, unregisterElement]);
25
+ }, [element.id, properties.startHidden, registerElement, unregisterElement, resolvedFormId]);
25
26
  async function handleClick(event) {
26
27
  var _a, _b, _c;
27
28
  if (!properties.path) {
@@ -70,5 +71,6 @@ export function ButtonElement({ element, formId }) {
70
71
  ? properties.type
71
72
  : undefined;
72
73
  const size = getString(properties, 'size');
73
- return (_jsx(ElementColWrapper, { element: element, children: _jsx(Button, { as: properties.path ? 'a' : 'button', type: buttonType, variant: getString(properties, 'variant', buttonType ? 'primary' : getString(properties, 'type', 'primary')), size: size === 'sm' || size === 'lg' ? size : undefined, href: getString(properties, 'path'), target: properties.path ? getString(properties, 'target', '_self') : undefined, rel: properties.path ? 'noopener noreferrer' : undefined, disabled: loading, onClick: handleClick, style: element.styles, children: loading ? (_jsxs(_Fragment, { children: [_jsx("output", { "aria-busy": "true", children: _jsx(Spinner, { as: "span", animation: "border", size: "sm", "aria-hidden": "true" }) }), ' ' + getString(properties, 'message')] })) : (getString(properties, 'text') || getString(properties, 'title')) }) }));
74
+ const variant = getString(properties, 'variant', buttonType ? 'primary' : getString(properties, 'type', 'primary'));
75
+ return (_jsx(ElementColWrapper, { element: element, children: _jsx(PbButton, { href: getString(properties, 'path') || undefined, target: properties.path ? getString(properties, 'target', '_self') : undefined, type: buttonType, variant: variant, size: size === 'sm' || size === 'lg' ? size : undefined, disabled: loading, onClick: handleClick, style: element.styles, children: loading ? (_jsxs(_Fragment, { children: [_jsx("output", { "aria-busy": "true", children: _jsx(PbSpinner, { size: "sm" }) }), ' ' + getString(properties, 'message')] })) : (getString(properties, 'text') || getString(properties, 'title')) }) }));
74
76
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Col } from 'react-bootstrap';
2
+ import { PbCol } from '../ui/PbCol.js';
3
3
  export function ElementColWrapper({ element, children }) {
4
4
  var _a;
5
5
  const style = {};
@@ -10,5 +10,5 @@ export function ElementColWrapper({ element, children }) {
10
10
  if ((_a = element.styles) === null || _a === void 0 ? void 0 : _a.textAlign) {
11
11
  style.textAlign = element.styles.textAlign;
12
12
  }
13
- return (_jsx(Col, { "data-pb-element": element.id, xs: element.width.xs, sm: element.width.sm, md: element.width.md, lg: element.width.lg, xl: element.width.xl, style: style, children: children }, element.id));
13
+ return (_jsx(PbCol, { colId: element.id, width: element.width, offset: element.offset, style: style, "data-pb-element": element.id, children: children }));
14
14
  }
@@ -1,4 +1,4 @@
1
- import { FaArrowRight, FaArrowLeft, FaArrowUp, FaArrowDown, FaChevronRight, FaChevronLeft, FaChevronUp, FaChevronDown, FaLongArrowAltRight, FaLongArrowAltLeft, FaBars, FaTimes, FaCheck, FaPlus, FaMinus, FaSearch, FaHome, FaUser, FaUsers, FaCog, FaInfoCircle, FaQuestionCircle, FaExclamationTriangle, FaCheckCircle, FaTimesCircle, FaExternalLinkAlt, FaDownload, FaUpload, FaSync, FaLock, FaUnlock, FaEye, FaEyeSlash, FaBell, FaStar, FaHeart, FaList, FaTh, FaThLarge, FaFilter, FaPhone, FaEnvelope, FaEnvelopeOpen, FaComment, FaComments, FaQuoteLeft, FaQuoteRight, FaPaperPlane, FaFacebookF, FaInstagram, FaWhatsapp, FaYoutube, FaTwitter, FaLinkedinIn, FaPinterestP, FaShoppingCart, FaShoppingBag, FaCreditCard, FaMoneyBillWave, FaTag, FaTags, FaGift, FaTruck, FaMapMarkerAlt, FaMap, FaMapPin, FaGlobe, FaCompass, FaLocationArrow, FaClock, FaCalendar, FaCalendarAlt, FaHourglassHalf, FaImage, FaImages, FaCamera, FaVideo, FaFilm, FaMusic, FaHeadphones, FaPlay, FaBriefcase, FaBuilding, FaChartBar, FaChartLine, FaChartPie, FaRocket, FaLightbulb, FaTrophy, FaMedal, FaFlag, FaFile, FaFolder, FaLink, FaPencilAlt, FaTrashAlt, FaCopy, FaCloud, FaWifi, FaMobileAlt, } from 'react-icons/fa';
1
+ import { FaArrowRight, FaArrowLeft, FaArrowUp, FaArrowDown, FaChevronRight, FaChevronLeft, FaChevronUp, FaChevronDown, FaLongArrowAltRight, FaLongArrowAltLeft, FaBars, FaTimes, FaCheck, FaPlus, FaMinus, FaSearch, FaHome, FaUser, FaUsers, FaCog, FaInfoCircle, FaQuestionCircle, FaExclamationTriangle, FaCheckCircle, FaTimesCircle, FaExternalLinkAlt, FaDownload, FaUpload, FaSync, FaLock, FaUnlock, FaEye, FaEyeSlash, FaBell, FaStar, FaHeart, FaList, FaTh, FaThLarge, FaFilter, FaPhone, FaEnvelope, FaEnvelopeOpen, FaComment, FaComments, FaQuoteLeft, FaQuoteRight, FaPaperPlane, FaFacebookF, FaInstagram, FaWhatsapp, FaYoutube, FaTwitter, FaLinkedinIn, FaPinterestP, FaShoppingCart, FaShoppingBag, FaCreditCard, FaMoneyBillWave, FaTag, FaTags, FaGift, FaTruck, FaMapMarkerAlt, FaMap, FaMapPin, FaGlobe, FaCompass, FaLocationArrow, FaClock, FaCalendar, FaCalendarAlt, FaHourglassHalf, FaImage, FaImages, FaCamera, FaVideo, FaFilm, FaMusic, FaHeadphones, FaPlay, FaBriefcase, FaBuilding, FaChartBar, FaChartLine, FaChartPie, FaRocket, FaLightbulb, FaTrophy, FaMedal, FaFlag, FaFile, FaFolder, FaLink, FaPencilAlt, FaTrashAlt, FaCopy, FaCloud, FaWifi, FaMobileAlt } from 'react-icons/fa';
2
2
  export const iconMap = {
3
3
  'arrow-right': FaArrowRight,
4
4
  'arrow-left': FaArrowLeft,
@@ -99,5 +99,5 @@ export const iconMap = {
99
99
  copy: FaCopy,
100
100
  cloud: FaCloud,
101
101
  wifi: FaWifi,
102
- mobile: FaMobileAlt,
102
+ mobile: FaMobileAlt
103
103
  };
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from 'react';
3
- import { Form } from 'react-bootstrap';
4
3
  import { IMaskInput } from 'react-imask';
5
4
  import { ElementColWrapper } from './ElementColWrapper.js';
6
5
  import { UseFormStore } from '../stores/UseFormStore.js';
@@ -66,12 +65,14 @@ export function InputElement({ element, formId }) {
66
65
  }
67
66
  store.setElementState(element.id, { value: checked ? value : '' });
68
67
  };
68
+ const isCheck = element.elementType === ElementTypeEnum.Checkbox || element.elementType === ElementTypeEnum.Radio;
69
69
  const renderControl = () => {
70
+ const baseClass = error ? 'pb-form-control-invalid' : '';
70
71
  if (element.elementType === ElementTypeEnum.Textarea) {
71
- return (_jsx("textarea", { defaultValue: getString(properties, 'value'), rows: getNumber(properties, 'rows') || 4, onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `form-control${error ? ' is-invalid' : ''}`, style: element.styles }));
72
+ return (_jsx("textarea", { defaultValue: getString(properties, 'value'), rows: getNumber(properties, 'rows') || 4, onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `pb-form-textarea ${baseClass}`.trim(), style: element.styles }));
72
73
  }
73
74
  if (element.elementType === ElementTypeEnum.Select) {
74
- return (_jsx("select", { defaultValue: getString(properties, 'value'), onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, className: `form-select${error ? ' is-invalid' : ''}`, style: element.styles, children: options.map((option, index) => {
75
+ return (_jsx("select", { defaultValue: getString(properties, 'value'), onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, className: `pb-form-select ${baseClass}`.trim(), style: element.styles, children: options.map((option, index) => {
75
76
  var _a, _b, _c, _d;
76
77
  const data = typeof option === 'object' && option !== null ? option : null;
77
78
  const value = String((_a = data === null || data === void 0 ? void 0 : data.value) !== null && _a !== void 0 ? _a : option);
@@ -79,17 +80,17 @@ export function InputElement({ element, formId }) {
79
80
  return (_jsx("option", { value: value, children: text }, `${value}-${index}`));
80
81
  }) }));
81
82
  }
82
- if (element.elementType === ElementTypeEnum.Checkbox || element.elementType === ElementTypeEnum.Radio) {
83
+ if (isCheck) {
83
84
  const value = getString(properties, 'value', 'on');
84
- return (_jsxs("div", { className: "form-check", children: [_jsx("input", { id: controlId, type: element.elementType, defaultChecked: getBoolean(properties, 'checked'), value: value, onChange: (e) => setCheckedValue(e.target.checked, value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, className: `form-check-input${error ? ' is-invalid' : ''}`, style: element.styles }), label && (_jsx("label", { className: "form-check-label", htmlFor: controlId, children: label }))] }));
85
+ return (_jsxs("div", { className: "pb-form-check", children: [_jsx("input", { id: controlId, type: element.elementType, defaultChecked: getBoolean(properties, 'checked'), value: value, onChange: (e) => setCheckedValue(e.target.checked, value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, className: `pb-form-check-input${error ? ' pb-form-check-invalid' : ''}`, style: element.styles }), label && (_jsx("label", { className: "pb-form-check-label", htmlFor: controlId, children: label }))] }));
85
86
  }
86
87
  if (element.elementType === ElementTypeEnum.File) {
87
- return (_jsx("div", { className: "alert alert-secondary", role: "status", style: element.styles, children: "File upload not available in this form." }));
88
+ return (_jsx("div", { className: "pb-alert pb-alert-secondary", role: "status", style: element.styles, children: "File upload not available in this form." }));
88
89
  }
89
90
  if (hasMask) {
90
- return (_jsx(IMaskInput, { mask: getString(properties, 'mask'), defaultValue: getString(properties, 'value'), onAccept: handleAccept, onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `form-control${error ? ' is-invalid' : ''}`, style: element.styles }));
91
+ return (_jsx(IMaskInput, { mask: getString(properties, 'mask'), defaultValue: getString(properties, 'value'), onAccept: handleAccept, onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `pb-form-control ${baseClass}`.trim(), style: element.styles }));
91
92
  }
92
- return (_jsx("input", { type: getString(properties, 'type', 'text'), defaultValue: getString(properties, 'value'), onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `form-control${error ? ' is-invalid' : ''}`, style: element.styles }));
93
+ return (_jsx("input", { type: getString(properties, 'type', 'text'), defaultValue: getString(properties, 'value'), onChange: (e) => setValue(e.target.value), onBlur: handleBlur, required: getBoolean(properties, 'required'), name: name, placeholder: getString(properties, 'placeholder'), className: `pb-form-control ${baseClass}`.trim(), style: element.styles }));
93
94
  };
94
- return (_jsx(ElementColWrapper, { element: element, children: _jsxs(Form.Group, { className: "mb-3", controlId: controlId, children: [label && element.elementType !== ElementTypeEnum.Checkbox && element.elementType !== ElementTypeEnum.Radio && (_jsx(Form.Label, { children: label })), renderControl(), error && (_jsx("div", { className: "invalid-feedback", style: { display: 'block' }, children: errorMessage }))] }) }));
95
+ return (_jsx(ElementColWrapper, { element: element, children: _jsxs("div", { className: "pb-form-group", id: controlId, children: [label && !isCheck && (_jsx("label", { className: "pb-form-label", htmlFor: controlId, children: label })), renderControl(), error && (_jsx("div", { className: "pb-invalid-feedback", role: "alert", children: errorMessage }))] }) }));
95
96
  }
@@ -4,10 +4,14 @@ import { ElementColWrapper } from './ElementColWrapper.js';
4
4
  export function TextElement({ element }) {
5
5
  const properties = element.properties;
6
6
  const text = String(properties.text || properties.title || properties.message || '');
7
+ const isSimple = properties.editorType === 'simple';
7
8
  if (element.elementType === 'title') {
8
9
  const tag = String(properties.tag || 'h2');
9
10
  const TitleTag = tag;
10
11
  return (_jsx(ElementColWrapper, { element: element, children: _jsx(TitleTag, { style: Object.assign({ margin: 0 }, element.styles), children: text }) }));
11
12
  }
13
+ if (isSimple) {
14
+ return (_jsx(ElementColWrapper, { element: element, children: _jsx("div", { style: Object.assign({ whiteSpace: 'pre-wrap' }, element.styles), children: text }) }));
15
+ }
12
16
  return (_jsx(ElementColWrapper, { element: element, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(text) }, style: element.styles }) }));
13
17
  }
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { ComponentType } from '../types/ComponentType.js';
3
+ import type { ComponentDefaults } from '../types/WebsiteType.js';
3
4
  export declare class ComponentFactory {
4
- build(component: ComponentType, editionMode?: boolean): React.ReactElement | null;
5
+ build(component: ComponentType, editionMode?: boolean, defaults?: ComponentDefaults): React.ReactElement | null;
5
6
  }
@@ -8,32 +8,49 @@ import { SliderComponent } from '../components/SliderComponent.js';
8
8
  import { CardComponent } from '../components/CardComponent.js';
9
9
  import { MapComponent } from '../components/MapComponent.js';
10
10
  import { ButtonsComponent } from '../components/ButtonsComponent.js';
11
+ import { IconComponent } from '../components/IconComponent.js';
12
+ import { VideoComponent } from '../components/VideoComponent.js';
13
+ /**
14
+ * Aplica os estilos padrão do design system (`componentDefaults`) antes dos
15
+ * estilos da instância — o override da instância prevalece.
16
+ */
17
+ function applyDefaults(component, defaults) {
18
+ const typeDefaults = defaults === null || defaults === void 0 ? void 0 : defaults[component.componentType];
19
+ if (!typeDefaults || Object.keys(typeDefaults).length === 0)
20
+ return component;
21
+ return Object.assign(Object.assign({}, component), { styles: Object.assign(Object.assign({}, typeDefaults), component.styles) });
22
+ }
11
23
  export class ComponentFactory {
12
- build(component, editionMode = false) {
13
- switch (component.componentType) {
24
+ build(component, editionMode = false, defaults) {
25
+ const resolved = applyDefaults(component, defaults);
26
+ switch (resolved.componentType) {
14
27
  case ComponentTypeEnum.Text:
15
28
  case ComponentTypeEnum.TextWithImage:
16
29
  case ComponentTypeEnum.HeroBanner:
17
- return _jsx(TextComponent, { component: component }, component.id);
30
+ return _jsx(TextComponent, { component: resolved }, resolved.id);
18
31
  case ComponentTypeEnum.Image:
19
- return _jsx(ImageComponent, { component: component }, component.id);
32
+ return _jsx(ImageComponent, { component: resolved }, resolved.id);
20
33
  case ComponentTypeEnum.List:
21
- return _jsx(ListComponent, { component: component }, component.id);
34
+ return _jsx(ListComponent, { component: resolved }, resolved.id);
22
35
  case ComponentTypeEnum.Slider:
23
36
  case ComponentTypeEnum.Gallery:
24
37
  case ComponentTypeEnum.Testimonials:
25
- return _jsx(SliderComponent, { component: component, editionMode: editionMode }, component.id);
38
+ return _jsx(SliderComponent, { component: resolved, editionMode: editionMode }, resolved.id);
26
39
  case ComponentTypeEnum.Form:
27
- return _jsx(FormComponent, { component: component }, component.id);
40
+ return _jsx(FormComponent, { component: resolved }, resolved.id);
28
41
  case ComponentTypeEnum.Card:
29
42
  case ComponentTypeEnum.Faq:
30
- return _jsx(CardComponent, { component: component }, component.id);
43
+ return _jsx(CardComponent, { component: resolved }, resolved.id);
31
44
  case ComponentTypeEnum.Map:
32
- return _jsx(MapComponent, { component: component }, component.id);
45
+ return _jsx(MapComponent, { component: resolved }, resolved.id);
33
46
  case ComponentTypeEnum.Buttons:
34
- return _jsx(ButtonsComponent, { component: component }, component.id);
47
+ return _jsx(ButtonsComponent, { component: resolved }, resolved.id);
48
+ case ComponentTypeEnum.Icon:
49
+ return _jsx(IconComponent, { component: resolved }, resolved.id);
50
+ case ComponentTypeEnum.Video:
51
+ return _jsx(VideoComponent, { component: resolved }, resolved.id);
35
52
  default:
36
- throw new Error('Invalid component type: ' + component.componentType);
53
+ throw new Error('Invalid component type: ' + resolved.componentType);
37
54
  }
38
55
  }
39
56
  }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  export type { RawWebsiteType } from './types/RawWebsiteType.js';
2
2
  export type { WebsiteType } from './types/WebsiteType.js';
3
3
  export type { PageType } from './types/PageType.js';
4
- export type { SectionType } from './types/SectionType.js';
5
- export type { SectionColumnType } from './types/SectionColumnType.js';
4
+ export type { BlockType } from './types/BlockType.js';
6
5
  export type { ColumnWidthType } from './types/ColumnWidthType.js';
7
6
  export type { ComponentType } from './types/ComponentType.js';
8
7
  export type { ElementType } from './types/ElementType.js';
@@ -12,7 +11,9 @@ export { Header } from './layouts/Header.js';
12
11
  export { Footer } from './layouts/Footer.js';
13
12
  export { SiteLayout, type EmailApiConfig } from './layouts/SiteLayout.js';
14
13
  export { PageBuilder } from './builders/PageBuilder.js';
15
- export { SectionRenderer } from './renderers/SectionRenderer.js';
14
+ export { BlockRenderer } from './renderers/BlockRenderer.js';
15
+ export { IconComponent } from './components/IconComponent.js';
16
+ export { VideoComponent } from './components/VideoComponent.js';
16
17
  export { LoadingComponent } from './components/LoadingComponent.js';
17
18
  export { ComponentFactory } from './factories/ComponentFactory.js';
18
19
  export { ElementFactory } from './factories/ElementFactory.js';
@@ -24,3 +25,15 @@ export { analyticsService } from './services/AnalyticsService.js';
24
25
  export { buttonActionFactory } from './factories/ButtonActionFactory.js';
25
26
  export type { EmailServiceConfig, EmailSendOptions } from './services/EmailService.js';
26
27
  export type { EmailSettingsType } from './types/EmailSettingsType.js';
28
+ export type { DesignTokens, DesignColors, DesignTypography, DesignSpacing, DesignRadius, DesignShadow, PartialDesignTokens, DeepPartial } from './designSystem/tokens.js';
29
+ export { defaultTokens, mergeTokens, tokenToCssVars, buildTokenCss, buildThemeVars } from './designSystem/tokens.js';
30
+ export { baseCss } from './designSystem/baseCss.js';
31
+ export { buildSiteCss } from './designSystem/buildSiteCss.js';
32
+ export { themeVarsStyle } from './designSystem/themeVars.js';
33
+ export { ThemeStyle } from './designSystem/theme.js';
34
+ export { PbContainer } from './ui/PbContainer.js';
35
+ export { PbRow } from './ui/PbRow.js';
36
+ export { PbCol } from './ui/PbCol.js';
37
+ export { PbButton } from './ui/PbButton.js';
38
+ export { PbSpinner } from './ui/PbSpinner.js';
39
+ export { PbAlert } from './ui/PbAlert.js';
package/dist/index.js CHANGED
@@ -2,7 +2,9 @@ export { Header } from './layouts/Header.js';
2
2
  export { Footer } from './layouts/Footer.js';
3
3
  export { SiteLayout } from './layouts/SiteLayout.js';
4
4
  export { PageBuilder } from './builders/PageBuilder.js';
5
- export { SectionRenderer } from './renderers/SectionRenderer.js';
5
+ export { BlockRenderer } from './renderers/BlockRenderer.js';
6
+ export { IconComponent } from './components/IconComponent.js';
7
+ export { VideoComponent } from './components/VideoComponent.js';
6
8
  export { LoadingComponent } from './components/LoadingComponent.js';
7
9
  export { ComponentFactory } from './factories/ComponentFactory.js';
8
10
  export { ElementFactory } from './factories/ElementFactory.js';
@@ -12,3 +14,14 @@ export { ElementTypeEnum } from './constants/ElementEnum.js';
12
14
  export { ButtonActionEnum } from './constants/ButtonActionEnum.js';
13
15
  export { analyticsService } from './services/AnalyticsService.js';
14
16
  export { buttonActionFactory } from './factories/ButtonActionFactory.js';
17
+ export { defaultTokens, mergeTokens, tokenToCssVars, buildTokenCss, buildThemeVars } from './designSystem/tokens.js';
18
+ export { baseCss } from './designSystem/baseCss.js';
19
+ export { buildSiteCss } from './designSystem/buildSiteCss.js';
20
+ export { themeVarsStyle } from './designSystem/themeVars.js';
21
+ export { ThemeStyle } from './designSystem/theme.js';
22
+ export { PbContainer } from './ui/PbContainer.js';
23
+ export { PbRow } from './ui/PbRow.js';
24
+ export { PbCol } from './ui/PbCol.js';
25
+ export { PbButton } from './ui/PbButton.js';
26
+ export { PbSpinner } from './ui/PbSpinner.js';
27
+ export { PbAlert } from './ui/PbAlert.js';
@@ -1,11 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import DOMPurify from 'dompurify';
3
- import { Container, Row, Col } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
5
+ import { PbCol } from '../ui/PbCol.js';
4
6
  import { SocialIconsComponent } from '../components/SocialIconsComponent.js';
5
7
  export function Footer({ website }) {
6
- var _a;
8
+ var _a, _b, _c, _d, _e, _f;
7
9
  const social = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.social;
8
- const footer = website.footer.properties;
9
- const styles = website.footer.styles;
10
- return (_jsx(Container, { fluid: styles.fluid || undefined, style: { backgroundColor: styles.backgroundColor }, children: _jsxs(Row, { id: 'footer', style: styles, children: [_jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex justify-content-center", style: { marginBottom: '30px' }, children: social && (_jsx(SocialIconsComponent, { social: social, color: styles.socialIconColor || styles.color })) }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex flex-column align-items-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text1) } }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex flex-column align-items-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text2) } }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex justify-content-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text3) } }), _jsxs(Col, { xs: 12, sm: 12, md: 12, lg: 12, children: [_jsx("hr", { className: "footer-divider" }), _jsxs("p", { className: "text-center mb-0", children: ["\u00A9 ", new Date().getFullYear(), " ", website.name] })] })] }) }));
10
+ const footerProps = ((_b = website.footer) === null || _b === void 0 ? void 0 : _b.properties) || {};
11
+ const styles = ((_c = website.footer) === null || _c === void 0 ? void 0 : _c.styles) || {};
12
+ const fluid = styles.fluid || undefined;
13
+ const baseStyle = Object.assign({}, styles);
14
+ delete baseStyle.fluid;
15
+ delete baseStyle.responsive;
16
+ const textStyle = {
17
+ display: 'flex',
18
+ flexDirection: 'column',
19
+ alignItems: 'center'
20
+ };
21
+ return (_jsx(PbContainer, { fluid: fluid || undefined, children: _jsx("footer", { id: "footer", className: "pb-footer", style: { backgroundColor: styles.backgroundColor }, children: _jsxs(PbRow, { children: [_jsx(PbCol, { width: { xs: 12 }, style: { marginBottom: '30px' }, children: social && _jsx(SocialIconsComponent, { social: social, color: styles.socialIconColor || styles.color }) }), _jsx(PbCol, { width: { xs: 12 }, style: textStyle, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize((_d = footerProps.text1) !== null && _d !== void 0 ? _d : '') } }) }), _jsx(PbCol, { width: { xs: 12 }, style: textStyle, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize((_e = footerProps.text2) !== null && _e !== void 0 ? _e : '') } }) }), _jsx(PbCol, { width: { xs: 12 }, style: { display: 'flex', justifyContent: 'center' }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize((_f = footerProps.text3) !== null && _f !== void 0 ? _f : '') } }) }), _jsxs(PbCol, { width: { xs: 12 }, children: [_jsx("hr", { className: "pb-footer-divider" }), _jsxs("p", { className: "pb-text-center pb-mb-0", style: baseStyle, children: ["\u00A9 ", new Date().getFullYear(), " ", website.name] })] })] }) }) }));
11
22
  }
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useCallback } from 'react';
2
+ import { useMemo, useCallback, useState } from 'react';
3
3
  import { useLocation } from 'react-router-dom';
4
- import { Container, Navbar, Nav } from 'react-bootstrap';
4
+ import { PbContainer } from '../ui/PbContainer.js';
5
5
  export function Header({ website, imageBaseUrl }) {
6
- const headerProperties = website.header.properties;
7
- const headerStyles = website.header.styles;
6
+ var _a, _b;
7
+ const headerProperties = ((_a = website.header) === null || _a === void 0 ? void 0 : _a.properties) || {};
8
+ const headerStyles = ((_b = website.header) === null || _b === void 0 ? void 0 : _b.styles) || {};
8
9
  const location = useLocation();
10
+ const [menuOpen, setMenuOpen] = useState(false);
9
11
  const menuPages = useMemo(() => (website.pages || []).filter((p) => p.menu === true).sort((a, b) => (a.menuOrder || 0) - (b.menuOrder || 0)), [website.pages]);
10
12
  const isActive = useCallback((path) => {
11
13
  const currentPath = location.pathname;
@@ -18,6 +20,7 @@ export function Header({ website, imageBaseUrl }) {
18
20
  const logoAlign = headerProperties.logoAlign || 'center';
19
21
  const menuLinkColor = headerStyles.menuLinkColor || headerStyles.color || undefined;
20
22
  const menuActiveLinkColor = headerStyles.menuActiveLinkColor || headerStyles.menuLinkColor || headerStyles.color || undefined;
23
+ const textAlign = headerStyles.textAlign || 'left';
21
24
  const brandStyle = { padding: 0 };
22
25
  if (showMenu) {
23
26
  if (logoAlign === 'right')
@@ -36,17 +39,24 @@ export function Header({ website, imageBaseUrl }) {
36
39
  else if (logoAlign === 'right') {
37
40
  brandStyle.marginLeft = 'auto';
38
41
  }
39
- return (_jsx(Navbar, { expand: "lg", collapseOnSelect: true, className: "py-3", style: { backgroundColor: headerStyles.backgroundColor || undefined, color: headerStyles.color || undefined, width: '100%' }, children: _jsxs(Container, { fluid: headerStyles.fluid || undefined, style: { textAlign: headerStyles.textAlign || undefined }, children: [headerProperties.showLogo && logoUrl && (_jsx(Navbar.Brand, { style: brandStyle, children: _jsx("img", { src: logoUrl, width: headerProperties.logoWidth || 200, className: "d-inline-block align-top", alt: "Logo" }) })), showMenu && (_jsxs(_Fragment, { children: [_jsx(Navbar.Toggle, { "aria-controls": "header-navbar-nav" }), _jsx(Navbar.Collapse, { id: "header-navbar-nav", children: _jsx(Nav, { className: `mx-auto ${headerProperties.showLogo ? '' : 'w-100 justify-content-center'}`, children: menuPages.map((p) => {
42
+ const innerStyle = { textAlign };
43
+ if (textAlign === 'center')
44
+ innerStyle.justifyContent = 'center';
45
+ else if (textAlign === 'right')
46
+ innerStyle.justifyContent = 'flex-end';
47
+ const closeMenu = useCallback(() => setMenuOpen(false), []);
48
+ return (_jsx("header", { className: "pb-header", style: {
49
+ backgroundColor: headerStyles.backgroundColor || undefined,
50
+ color: headerStyles.color || undefined
51
+ }, children: _jsx(PbContainer, { fluid: headerStyles.fluid || undefined, children: _jsxs("div", { className: "pb-header-inner", style: innerStyle, children: [headerProperties.showLogo && logoUrl && (_jsx("a", { className: "pb-brand", href: "/", style: brandStyle, "aria-label": "P\u00E1gina inicial", children: _jsx("img", { src: logoUrl, width: Number(headerProperties.logoWidth) || 200, alt: "Logo" }) })), showMenu && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "pb-nav-toggle", "aria-label": menuOpen ? 'Fechar menu' : 'Abrir menu', "aria-expanded": menuOpen, onClick: () => setMenuOpen((open) => !open), children: "\u2630" }), _jsx("nav", { className: `pb-nav${menuOpen ? ' pb-nav-open' : ''}`, "aria-label": "Menu principal", children: menuPages.map((p) => {
40
52
  const active = isActive(p.path);
41
- return (_jsx(Nav.Link, { href: p.path, style: {
53
+ return (_jsx("a", { href: p.path, onClick: closeMenu, className: `pb-nav-link${active ? ' pb-nav-link-active' : ''}`, style: {
42
54
  color: active ? menuActiveLinkColor : menuLinkColor,
43
55
  fontSize: headerStyles.menuFontSize || undefined,
44
56
  letterSpacing: headerStyles.menuLetterSpacing || undefined,
45
57
  textTransform: headerStyles.menuTextTransform || undefined,
46
58
  margin: '0 12px',
47
- paddingBottom: '4px',
48
- borderBottom: active && menuActiveLinkColor ? `2px solid ${menuActiveLinkColor}` : '2px solid transparent',
49
- transition: 'color 0.3s, border-color 0.3s',
59
+ paddingBottom: '4px'
50
60
  }, children: p.title }, p.id));
51
- }) }) })] }))] }) }));
61
+ }) })] }))] }) }) }));
52
62
  }
@@ -4,10 +4,11 @@ import { Outlet } from 'react-router-dom';
4
4
  import { Helmet } from 'react-helmet-async';
5
5
  import { Header } from './Header.js';
6
6
  import { Footer } from './Footer.js';
7
+ import { ThemeStyle } from '../designSystem/theme.js';
7
8
  import { buildFontFamily, buildGoogleFontsHref } from '../utils/fonts.js';
8
9
  import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
9
10
  export function SiteLayout({ website, imageBaseUrl, emailApi }) {
10
- var _a, _b, _c, _d, _e, _f, _g, _h;
11
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
11
12
  const fontFamily = buildFontFamily((_a = website.styles) === null || _a === void 0 ? void 0 : _a.fontFamily);
12
13
  const fontHref = buildGoogleFontsHref((_b = website.styles) === null || _b === void 0 ? void 0 : _b.fontFamily);
13
14
  useEffect(() => {
@@ -35,5 +36,5 @@ export function SiteLayout({ website, imageBaseUrl, emailApi }) {
35
36
  (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.recipientName,
36
37
  (_h = (_g = website.properties) === null || _g === void 0 ? void 0 : _g.email) === null || _h === void 0 ? void 0 : _h.subject
37
38
  ]);
38
- return (_jsxs(_Fragment, { children: [fontHref && (_jsxs(Helmet, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" }), _jsx("link", { href: fontHref, rel: "stylesheet" })] })), _jsxs("div", { id: "site-layout", style: { backgroundColor: website.styles.backgroundColor, color: website.styles.color, fontFamily }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] })] }));
39
+ return (_jsxs(_Fragment, { children: [_jsx(ThemeStyle, { designSystem: website.designSystem }), fontHref && (_jsxs(Helmet, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" }), _jsx("link", { href: fontHref, rel: "stylesheet" })] })), _jsxs("div", { id: "site-layout", className: "pb-root", style: { backgroundColor: (_j = website.styles) === null || _j === void 0 ? void 0 : _j.backgroundColor, color: (_k = website.styles) === null || _k === void 0 ? void 0 : _k.color, fontFamily }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] })] }));
39
40
  }
@@ -0,0 +1,8 @@
1
+ import type { BlockType } from '../types/BlockType.js';
2
+ import type { ComponentDefaults } from '../types/WebsiteType.js';
3
+ declare const BlockRenderer: import("react").NamedExoticComponent<{
4
+ readonly blocks: BlockType[];
5
+ readonly editionMode?: boolean;
6
+ readonly componentDefaults?: ComponentDefaults;
7
+ }>;
8
+ export { BlockRenderer };
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { ComponentFactory } from '../factories/ComponentFactory.js';
5
+ import { orderBySort } from '../utils/orderBySort.js';
6
+ import { buildResponsiveCss } from '../utils/responsiveStyles.js';
7
+ const componentFactory = new ComponentFactory();
8
+ function gridClass(id) {
9
+ return `pixelbuild-grid-${String(id).replace(/[^a-zA-Z0-9_-]/g, '_')}`;
10
+ }
11
+ const BlockGrid = memo(function BlockGrid({ block, editionMode, componentDefaults }) {
12
+ const grid = gridClass(block.id);
13
+ const components = orderBySort(block.components);
14
+ const css = useMemo(() => {
15
+ const rules = components
16
+ .map((component) => {
17
+ var _a, _b, _c;
18
+ const properties = component.properties || {};
19
+ const row = Math.max(0, Number(properties.row) || 0);
20
+ const rowSpan = Math.max(1, Number(properties.rowSpan) || 1);
21
+ const xs = ((_a = component.width) === null || _a === void 0 ? void 0 : _a.xs) || 12;
22
+ const sm = ((_b = component.width) === null || _b === void 0 ? void 0 : _b.sm) || xs;
23
+ const md = ((_c = component.width) === null || _c === void 0 ? void 0 : _c.md) || sm;
24
+ const cls = gridClass(component.id);
25
+ return [
26
+ `.${grid} .${cls}{grid-column:span ${xs};grid-row:auto;min-width:0}`,
27
+ `@media (min-width:576px){.${grid} .${cls}{grid-column:span ${sm}}}`,
28
+ `@media (min-width:768px){.${grid} .${cls}{grid-column:span ${md};grid-row:${row + 1}/span ${rowSpan}}}`
29
+ ].join('');
30
+ })
31
+ .join('');
32
+ return `.${grid}{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pb-gutter,1rem)}${rules}`;
33
+ }, [grid, components]);
34
+ if (editionMode && components.length === 0) {
35
+ return (_jsxs("div", { "data-pixelbuild-empty-block": block.id, style: {
36
+ minHeight: 80,
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ justifyContent: 'center',
40
+ gap: 6,
41
+ border: '1.5px dashed #c4d0dc',
42
+ color: '#94a3b8',
43
+ fontSize: 13,
44
+ cursor: 'pointer',
45
+ textAlign: 'center',
46
+ borderRadius: 8
47
+ }, children: [_jsx("span", { style: { fontSize: 18, lineHeight: 1 }, children: "+" }), "Adicionar componente"] }));
48
+ }
49
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: css }), _jsx("div", { className: grid, children: components.map((component) => (_jsx("div", { className: gridClass(component.id), children: componentFactory.build(component, editionMode, componentDefaults) }, component.id))) })] }));
50
+ });
51
+ const BlockContent = memo(function BlockContent({ block, editionMode, componentDefaults }) {
52
+ const content = useMemo(() => _jsx(BlockGrid, { block: block, editionMode: editionMode, componentDefaults: componentDefaults }), [block, editionMode, componentDefaults]);
53
+ if (block.sectionType === 'container-fluid') {
54
+ return (_jsx(PbContainer, { fluid: true, "data-pb-block": block.id, style: block.styles, children: content }));
55
+ }
56
+ if (block.sectionType === 'container') {
57
+ return (_jsx(PbContainer, { "data-pb-block": block.id, style: block.styles, children: content }));
58
+ }
59
+ return _jsx(PbContainer, { fluid: true, children: content });
60
+ });
61
+ const BlockRenderer = memo(function BlockRenderer({ blocks, editionMode = false, componentDefaults }) {
62
+ const sorted = useMemo(() => orderBySort(blocks || []), [blocks]);
63
+ if (sorted.length === 0) {
64
+ return null;
65
+ }
66
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: buildResponsiveCss(sorted) }), sorted.map((block) => (_jsx(BlockContent, { block: block, editionMode: editionMode, componentDefaults: componentDefaults }, block.id)))] }));
67
+ });
68
+ export { BlockRenderer };