lib-pixelbuild 0.2.0 → 0.2.2

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 (59) hide show
  1. package/dist/builders/PageBuilder.js +7 -3
  2. package/dist/components/ButtonsComponent.d.ts +5 -0
  3. package/dist/components/ButtonsComponent.js +44 -0
  4. package/dist/components/CardComponent.js +31 -6
  5. package/dist/components/FormComponent.js +8 -4
  6. package/dist/components/{CarouselComponent.d.ts → ImageComponent.d.ts} +3 -2
  7. package/dist/components/ImageComponent.js +17 -0
  8. package/dist/components/ListComponent.js +5 -1
  9. package/dist/components/MapComponent.js +4 -4
  10. package/dist/components/SliderComponent.d.ts +1 -2
  11. package/dist/components/SliderComponent.js +175 -93
  12. package/dist/components/SocialIconsComponent.d.ts +3 -2
  13. package/dist/components/SocialIconsComponent.js +20 -15
  14. package/dist/components/TextComponent.js +3 -2
  15. package/dist/constants/ComponentEnum.d.ts +1 -0
  16. package/dist/constants/ComponentEnum.js +1 -0
  17. package/dist/elements/ButtonElement.js +19 -6
  18. package/dist/elements/ElementColWrapper.js +10 -1
  19. package/dist/elements/IconElement.js +5 -5
  20. package/dist/elements/IconMap.js +101 -28
  21. package/dist/elements/InputElement.js +4 -3
  22. package/dist/elements/TextElement.js +1 -1
  23. package/dist/factories/ButtonActionFactory.d.ts +3 -4
  24. package/dist/factories/ButtonActionFactory.js +2 -2
  25. package/dist/factories/ComponentFactory.js +6 -3
  26. package/dist/index.d.ts +5 -2
  27. package/dist/index.js +2 -0
  28. package/dist/layouts/Footer.js +1 -1
  29. package/dist/layouts/Header.js +29 -13
  30. package/dist/layouts/SiteLayout.d.ts +8 -1
  31. package/dist/layouts/SiteLayout.js +35 -3
  32. package/dist/renderers/SectionRenderer.js +26 -9
  33. package/dist/services/EmailService.d.ts +14 -5
  34. package/dist/services/EmailService.js +21 -22
  35. package/dist/stores/UseFormStore.d.ts +7 -2
  36. package/dist/stores/UseFormStore.js +8 -3
  37. package/dist/types/ElementType.d.ts +1 -0
  38. package/dist/types/EmailSettingsType.d.ts +5 -0
  39. package/dist/types/EmailSettingsType.js +1 -0
  40. package/dist/types/HeaderPropertiesType.d.ts +1 -0
  41. package/dist/types/MailBodyType.d.ts +2 -0
  42. package/dist/types/SocialPropertiesType.d.ts +3 -11
  43. package/dist/types/StylesType.d.ts +12 -0
  44. package/dist/types/WebsitePropertiesType.d.ts +2 -0
  45. package/dist/types/WebsiteType.d.ts +1 -0
  46. package/dist/utils/emailTemplate.d.ts +7 -0
  47. package/dist/utils/emailTemplate.js +66 -0
  48. package/dist/utils/fonts.d.ts +2 -0
  49. package/dist/utils/fonts.js +10 -0
  50. package/dist/utils/imageCustomization.d.ts +3 -0
  51. package/dist/utils/imageCustomization.js +11 -0
  52. package/dist/utils/responsiveProperties.d.ts +2 -0
  53. package/dist/utils/responsiveProperties.js +28 -0
  54. package/dist/utils/responsiveStyles.d.ts +6 -0
  55. package/dist/utils/responsiveStyles.js +82 -0
  56. package/package.json +2 -4
  57. package/dist/components/CarouselComponent.js +0 -6
  58. package/dist/layouts/Menu.d.ts +0 -5
  59. package/dist/layouts/Menu.js +0 -34
@@ -3,9 +3,10 @@ import { memo, useMemo } from 'react';
3
3
  import { Row, Container } from 'react-bootstrap';
4
4
  import { ElementFactory } from '../factories/ElementFactory.js';
5
5
  import { orderBySort } from '../utils/orderBySort.js';
6
+ import { resolveImageElement } from '../utils/imageCustomization.js';
6
7
  const elementFactory = new ElementFactory();
7
8
  const TextComponent = memo(function TextComponent({ component }) {
8
- const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
9
- return (_jsx(Container, { style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
9
+ const elements = useMemo(() => orderBySort(component.elements).map((element) => resolveImageElement(component, element)), [component.elements, component.properties]);
10
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
10
11
  });
11
12
  export { TextComponent };
@@ -13,5 +13,6 @@ export declare const ComponentTypeEnum: {
13
13
  readonly SocialIcons: "social-icons";
14
14
  readonly Map: "map";
15
15
  readonly List: "list";
16
+ readonly Buttons: "buttons";
16
17
  };
17
18
  export type ComponentTypeSlug = (typeof ComponentTypeEnum)[keyof typeof ComponentTypeEnum];
@@ -13,4 +13,5 @@ export const ComponentTypeEnum = {
13
13
  SocialIcons: 'social-icons',
14
14
  Map: 'map',
15
15
  List: 'list',
16
+ Buttons: 'buttons',
16
17
  };
@@ -4,6 +4,7 @@ import { Button, Spinner } from 'react-bootstrap';
4
4
  import { ElementColWrapper } from './ElementColWrapper.js';
5
5
  import { UseFormStore } from '../stores/UseFormStore.js';
6
6
  import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
7
+ import { ButtonActionEnum } from '../constants/ButtonActionEnum.js';
7
8
  import { getString, getNumber, getBoolean } from '../utils/propertyUtils.js';
8
9
  export function ButtonElement({ element, formId }) {
9
10
  const properties = element.properties;
@@ -22,7 +23,7 @@ export function ButtonElement({ element, formId }) {
22
23
  return () => unregisterElement(element.id);
23
24
  }, [element.id, properties.startHidden, registerElement, resolvedFormId, unregisterElement]);
24
25
  async function handleClick(event) {
25
- var _a;
26
+ var _a, _b, _c;
26
27
  if (!properties.path) {
27
28
  event.preventDefault();
28
29
  const form = event.currentTarget instanceof HTMLButtonElement ? event.currentTarget.form : null;
@@ -35,11 +36,21 @@ export function ButtonElement({ element, formId }) {
35
36
  if (hasErrors)
36
37
  return false;
37
38
  UseFormStore.getState().setElementState(element.id, { loading: true });
38
- const actionId = getNumber(properties, 'actionId');
39
+ const actionId = (_a = getNumber(properties, 'actionId')) !== null && _a !== void 0 ? _a : (properties.type === 'submit' ? ButtonActionEnum.SendMail : undefined);
39
40
  if (actionId) {
40
- await buttonActionFactory.build(actionId, formData);
41
+ const formConfig = resolvedFormId !== undefined ? (_b = UseFormStore.getState().forms[resolvedFormId]) === null || _b === void 0 ? void 0 : _b.email : undefined;
42
+ try {
43
+ await buttonActionFactory.build(actionId, formData, {
44
+ recipient: formConfig === null || formConfig === void 0 ? void 0 : formConfig.recipient,
45
+ subject: formConfig === null || formConfig === void 0 ? void 0 : formConfig.subject,
46
+ formId: resolvedFormId
47
+ });
48
+ }
49
+ catch (error) {
50
+ console.warn('Não foi possível enviar o formulário:', error);
51
+ }
41
52
  }
42
- const loadingTime = (_a = getNumber(properties, 'loadingTime')) !== null && _a !== void 0 ? _a : 0;
53
+ const loadingTime = (_c = getNumber(properties, 'loadingTime')) !== null && _c !== void 0 ? _c : 0;
43
54
  setTimeout(() => {
44
55
  if (getBoolean(properties, 'hideOnClick'))
45
56
  hideElement(element.id);
@@ -56,6 +67,8 @@ export function ButtonElement({ element, formId }) {
56
67
  if (hidden)
57
68
  return null;
58
69
  const buttonType = properties.type === 'button' || properties.type === 'submit' || properties.type === 'reset'
59
- ? properties.type : undefined;
60
- 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')), href: getString(properties, 'path'), target: properties.path ? '_blank' : 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')) }) }));
70
+ ? properties.type
71
+ : undefined;
72
+ 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')) }) }));
61
74
  }
@@ -1,5 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Col } from 'react-bootstrap';
3
3
  export function ElementColWrapper({ element, children }) {
4
- return (_jsx(Col, { xs: element.width.xs, sm: element.width.sm, md: element.width.md, lg: element.width.lg, xl: element.width.xl, style: element.styles, children: children }, element.id));
4
+ var _a;
5
+ const style = {};
6
+ if (element.fullBleed) {
7
+ style.paddingLeft = '0';
8
+ style.paddingRight = '0';
9
+ }
10
+ if ((_a = element.styles) === null || _a === void 0 ? void 0 : _a.textAlign) {
11
+ style.textAlign = element.styles.textAlign;
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));
5
14
  }
@@ -3,13 +3,13 @@ import { Suspense, useMemo } from 'react';
3
3
  import { iconMap } from './IconMap.js';
4
4
  import { ElementColWrapper } from './ElementColWrapper.js';
5
5
  function FallbackIcon({ name }) {
6
- const Icon = iconMap[name] || iconMap.FaQuestionCircle;
6
+ const Icon = iconMap[name] || iconMap.question;
7
7
  return _jsx(Icon, { size: "1em", "aria-label": name || 'Icon' });
8
8
  }
9
9
  export function IconElement({ element }) {
10
- var _a;
11
10
  const name = String(element.properties.name || '');
12
- const iconSize = ((_a = element.styles) === null || _a === void 0 ? void 0 : _a.fontSize) || '1.25rem';
13
- const Icon = useMemo(() => iconMap[name] || iconMap.FaQuestionCircle, [name]);
14
- return (_jsx(ElementColWrapper, { element: element, children: _jsx("span", { style: { fontSize: iconSize, display: 'inline-flex' }, children: _jsx(Suspense, { fallback: _jsx(FallbackIcon, { name: name }), children: _jsx(Icon, { size: "1em", style: element.styles, "aria-label": name || 'Icon' }) }) }) }));
11
+ const styles = element.styles || {};
12
+ const iconSize = styles.fontSize || '1.25rem';
13
+ const Icon = useMemo(() => iconMap[name] || iconMap.question, [name]);
14
+ return (_jsx(ElementColWrapper, { element: element, children: _jsx("span", { style: { fontSize: iconSize, display: 'inline-flex', color: styles.color }, children: _jsx(Suspense, { fallback: _jsx(FallbackIcon, { name: name }), children: _jsx(Icon, { size: "1em", color: styles.color, style: styles, "aria-label": name || 'Icon' }) }) }) }));
15
15
  }
@@ -1,30 +1,103 @@
1
- import { FaArrowRight, FaBars, FaCalendar, FaCheck, FaChevronLeft, FaChevronRight, FaClock, FaEnvelope, FaFacebookF, FaGlobe, FaHeart, FaHome, FaInfoCircle, FaInstagram, FaLink, FaMapMarkerAlt, FaPhone, FaQuestionCircle, FaQuoteLeft, FaSearch, FaShoppingCart, FaStar, FaTimes, FaTwitter, FaUser, FaWhatsapp, FaYoutube, } 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
- FaArrowRight,
4
- FaBars,
5
- FaCalendar,
6
- FaCheck,
7
- FaChevronLeft,
8
- FaChevronRight,
9
- FaClock,
10
- FaEnvelope,
11
- FaFacebookF,
12
- FaGlobe,
13
- FaHeart,
14
- FaHome,
15
- FaInfoCircle,
16
- FaInstagram,
17
- FaLink,
18
- FaMapMarkerAlt,
19
- FaPhone,
20
- FaQuestionCircle,
21
- FaQuoteLeft,
22
- FaSearch,
23
- FaShoppingCart,
24
- FaStar,
25
- FaTimes,
26
- FaTwitter,
27
- FaUser,
28
- FaWhatsapp,
29
- FaYoutube,
3
+ 'arrow-right': FaArrowRight,
4
+ 'arrow-left': FaArrowLeft,
5
+ 'arrow-up': FaArrowUp,
6
+ 'arrow-down': FaArrowDown,
7
+ 'chevron-right': FaChevronRight,
8
+ 'chevron-left': FaChevronLeft,
9
+ 'chevron-up': FaChevronUp,
10
+ 'chevron-down': FaChevronDown,
11
+ 'long-arrow-right': FaLongArrowAltRight,
12
+ 'long-arrow-left': FaLongArrowAltLeft,
13
+ bars: FaBars,
14
+ times: FaTimes,
15
+ check: FaCheck,
16
+ plus: FaPlus,
17
+ minus: FaMinus,
18
+ search: FaSearch,
19
+ home: FaHome,
20
+ user: FaUser,
21
+ users: FaUsers,
22
+ cog: FaCog,
23
+ info: FaInfoCircle,
24
+ question: FaQuestionCircle,
25
+ exclamation: FaExclamationTriangle,
26
+ 'check-circle': FaCheckCircle,
27
+ 'times-circle': FaTimesCircle,
28
+ 'external-link': FaExternalLinkAlt,
29
+ download: FaDownload,
30
+ upload: FaUpload,
31
+ sync: FaSync,
32
+ lock: FaLock,
33
+ unlock: FaUnlock,
34
+ eye: FaEye,
35
+ 'eye-slash': FaEyeSlash,
36
+ bell: FaBell,
37
+ star: FaStar,
38
+ heart: FaHeart,
39
+ list: FaList,
40
+ grid: FaTh,
41
+ 'grid-large': FaThLarge,
42
+ filter: FaFilter,
43
+ phone: FaPhone,
44
+ envelope: FaEnvelope,
45
+ 'envelope-open': FaEnvelopeOpen,
46
+ comment: FaComment,
47
+ comments: FaComments,
48
+ 'quote-left': FaQuoteLeft,
49
+ 'quote-right': FaQuoteRight,
50
+ 'paper-plane': FaPaperPlane,
51
+ facebook: FaFacebookF,
52
+ instagram: FaInstagram,
53
+ whatsapp: FaWhatsapp,
54
+ youtube: FaYoutube,
55
+ twitter: FaTwitter,
56
+ linkedin: FaLinkedinIn,
57
+ pinterest: FaPinterestP,
58
+ 'shopping-cart': FaShoppingCart,
59
+ 'shopping-bag': FaShoppingBag,
60
+ 'credit-card': FaCreditCard,
61
+ money: FaMoneyBillWave,
62
+ tag: FaTag,
63
+ tags: FaTags,
64
+ gift: FaGift,
65
+ truck: FaTruck,
66
+ 'map-marker': FaMapMarkerAlt,
67
+ map: FaMap,
68
+ 'map-pin': FaMapPin,
69
+ globe: FaGlobe,
70
+ compass: FaCompass,
71
+ 'location-arrow': FaLocationArrow,
72
+ clock: FaClock,
73
+ calendar: FaCalendar,
74
+ 'calendar-alt': FaCalendarAlt,
75
+ hourglass: FaHourglassHalf,
76
+ image: FaImage,
77
+ images: FaImages,
78
+ camera: FaCamera,
79
+ video: FaVideo,
80
+ film: FaFilm,
81
+ music: FaMusic,
82
+ headphones: FaHeadphones,
83
+ play: FaPlay,
84
+ briefcase: FaBriefcase,
85
+ building: FaBuilding,
86
+ 'chart-bar': FaChartBar,
87
+ 'chart-line': FaChartLine,
88
+ 'chart-pie': FaChartPie,
89
+ rocket: FaRocket,
90
+ lightbulb: FaLightbulb,
91
+ trophy: FaTrophy,
92
+ medal: FaMedal,
93
+ flag: FaFlag,
94
+ file: FaFile,
95
+ folder: FaFolder,
96
+ link: FaLink,
97
+ pencil: FaPencilAlt,
98
+ trash: FaTrashAlt,
99
+ copy: FaCopy,
100
+ cloud: FaCloud,
101
+ wifi: FaWifi,
102
+ mobile: FaMobileAlt,
30
103
  };
@@ -59,7 +59,8 @@ export function InputElement({ element, formId }) {
59
59
  const setCheckedValue = (checked, value) => {
60
60
  const store = UseFormStore.getState();
61
61
  if (checked && element.elementType === ElementTypeEnum.Radio && name && resolvedFormId !== undefined) {
62
- store.getElementsByForm(resolvedFormId)
62
+ store
63
+ .getElementsByForm(resolvedFormId)
63
64
  .filter((field) => field.id !== element.id && field.type === ElementTypeEnum.Radio && field.name === name)
64
65
  .forEach((field) => store.setElementState(field.id, { value: '' }));
65
66
  }
@@ -75,12 +76,12 @@ export function InputElement({ element, formId }) {
75
76
  const data = typeof option === 'object' && option !== null ? option : null;
76
77
  const value = String((_a = data === null || data === void 0 ? void 0 : data.value) !== null && _a !== void 0 ? _a : option);
77
78
  const text = String((_d = (_c = (_b = data === null || data === void 0 ? void 0 : data.label) !== null && _b !== void 0 ? _b : data === null || data === void 0 ? void 0 : data.text) !== null && _c !== void 0 ? _c : data === null || data === void 0 ? void 0 : data.title) !== null && _d !== void 0 ? _d : value);
78
- return _jsx("option", { value: value, children: text }, `${value}-${index}`);
79
+ return (_jsx("option", { value: value, children: text }, `${value}-${index}`));
79
80
  }) }));
80
81
  }
81
82
  if (element.elementType === ElementTypeEnum.Checkbox || element.elementType === ElementTypeEnum.Radio) {
82
83
  const value = getString(properties, 'value', 'on');
83
- 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 })] }));
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 }))] }));
84
85
  }
85
86
  if (element.elementType === ElementTypeEnum.File) {
86
87
  return (_jsx("div", { className: "alert alert-secondary", role: "status", style: element.styles, children: "File upload not available in this form." }));
@@ -7,7 +7,7 @@ export function TextElement({ element }) {
7
7
  if (element.elementType === 'title') {
8
8
  const tag = String(properties.tag || 'h2');
9
9
  const TitleTag = tag;
10
- return (_jsx(ElementColWrapper, { element: element, children: _jsx(TitleTag, { style: element.styles, children: text }) }));
10
+ return (_jsx(ElementColWrapper, { element: element, children: _jsx(TitleTag, { style: Object.assign({ margin: 0 }, element.styles), children: text }) }));
11
11
  }
12
12
  return (_jsx(ElementColWrapper, { element: element, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(text) }, style: element.styles }) }));
13
13
  }
@@ -1,10 +1,9 @@
1
- import { type EmailServiceConfig } from '../services/EmailService.js';
1
+ import { type EmailServiceConfig, type EmailSendOptions } from '../services/EmailService.js';
2
2
  import type { FormFieldsType } from '../types/FormFieldsType.js';
3
- import type { MailBodyType } from '../types/MailBodyType.js';
4
3
  declare class ButtonActionFactory {
5
4
  private emailService;
6
5
  configureEmail(config: EmailServiceConfig): void;
7
- build(actionId: number, data: FormFieldsType[]): Promise<MailBodyType | boolean>;
6
+ build(actionId: number, data: FormFieldsType[], options?: EmailSendOptions): Promise<boolean>;
8
7
  }
9
8
  export declare const buttonActionFactory: ButtonActionFactory;
10
- export type { EmailServiceConfig } from '../services/EmailService.js';
9
+ export type { EmailServiceConfig, EmailSendOptions } from '../services/EmailService.js';
@@ -7,13 +7,13 @@ class ButtonActionFactory {
7
7
  configureEmail(config) {
8
8
  this.emailService = new EmailService(config);
9
9
  }
10
- async build(actionId, data) {
10
+ async build(actionId, data, options) {
11
11
  switch (actionId) {
12
12
  case ButtonActionEnum.SendMail: {
13
13
  if (!this.emailService) {
14
14
  throw new Error('EmailService not configured. Call configureEmail() before using SendMail action.');
15
15
  }
16
- return this.emailService.sendMail(data);
16
+ return this.emailService.sendMail(data, options);
17
17
  }
18
18
  default:
19
19
  throw new Error('Invalid button action: ' + actionId);
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ComponentTypeEnum } from '../constants/ComponentEnum.js';
3
3
  import { TextComponent } from '../components/TextComponent.js';
4
+ import { ImageComponent } from '../components/ImageComponent.js';
4
5
  import { ListComponent } from '../components/ListComponent.js';
5
- import { CarouselComponent } from '../components/CarouselComponent.js';
6
6
  import { FormComponent } from '../components/FormComponent.js';
7
7
  import { SliderComponent } from '../components/SliderComponent.js';
8
8
  import { CardComponent } from '../components/CardComponent.js';
9
9
  import { MapComponent } from '../components/MapComponent.js';
10
+ import { ButtonsComponent } from '../components/ButtonsComponent.js';
10
11
  export class ComponentFactory {
11
12
  build(component, editionMode = false) {
12
13
  switch (component.componentType) {
@@ -14,6 +15,8 @@ export class ComponentFactory {
14
15
  case ComponentTypeEnum.TextWithImage:
15
16
  case ComponentTypeEnum.HeroBanner:
16
17
  return _jsx(TextComponent, { component: component }, component.id);
18
+ case ComponentTypeEnum.Image:
19
+ return _jsx(ImageComponent, { component: component }, component.id);
17
20
  case ComponentTypeEnum.List:
18
21
  return _jsx(ListComponent, { component: component }, component.id);
19
22
  case ComponentTypeEnum.Slider:
@@ -25,10 +28,10 @@ export class ComponentFactory {
25
28
  case ComponentTypeEnum.Card:
26
29
  case ComponentTypeEnum.Faq:
27
30
  return _jsx(CardComponent, { component: component }, component.id);
28
- case ComponentTypeEnum.Image:
29
- return _jsx(CarouselComponent, { component: component }, component.id);
30
31
  case ComponentTypeEnum.Map:
31
32
  return _jsx(MapComponent, { component: component }, component.id);
33
+ case ComponentTypeEnum.Buttons:
34
+ return _jsx(ButtonsComponent, { component: component }, component.id);
32
35
  default:
33
36
  throw new Error('Invalid component type: ' + component.componentType);
34
37
  }
package/dist/index.d.ts CHANGED
@@ -10,14 +10,17 @@ export type { PropertiesType } from './types/PropertiesType.js';
10
10
  export type { StylesType } from './types/StylesType.js';
11
11
  export { Header } from './layouts/Header.js';
12
12
  export { Footer } from './layouts/Footer.js';
13
- export { SiteLayout } from './layouts/SiteLayout.js';
13
+ export { SiteLayout, type EmailApiConfig } from './layouts/SiteLayout.js';
14
14
  export { PageBuilder } from './builders/PageBuilder.js';
15
15
  export { SectionRenderer } from './renderers/SectionRenderer.js';
16
16
  export { LoadingComponent } from './components/LoadingComponent.js';
17
17
  export { ComponentFactory } from './factories/ComponentFactory.js';
18
18
  export { ElementFactory } from './factories/ElementFactory.js';
19
+ export { iconMap } from './elements/IconMap.js';
19
20
  export { ComponentTypeEnum } from './constants/ComponentEnum.js';
20
21
  export { ElementTypeEnum } from './constants/ElementEnum.js';
22
+ export { ButtonActionEnum } from './constants/ButtonActionEnum.js';
21
23
  export { analyticsService } from './services/AnalyticsService.js';
22
24
  export { buttonActionFactory } from './factories/ButtonActionFactory.js';
23
- export type { EmailServiceConfig } from './services/EmailService.js';
25
+ export type { EmailServiceConfig, EmailSendOptions } from './services/EmailService.js';
26
+ export type { EmailSettingsType } from './types/EmailSettingsType.js';
package/dist/index.js CHANGED
@@ -6,7 +6,9 @@ export { SectionRenderer } from './renderers/SectionRenderer.js';
6
6
  export { LoadingComponent } from './components/LoadingComponent.js';
7
7
  export { ComponentFactory } from './factories/ComponentFactory.js';
8
8
  export { ElementFactory } from './factories/ElementFactory.js';
9
+ export { iconMap } from './elements/IconMap.js';
9
10
  export { ComponentTypeEnum } from './constants/ComponentEnum.js';
10
11
  export { ElementTypeEnum } from './constants/ElementEnum.js';
12
+ export { ButtonActionEnum } from './constants/ButtonActionEnum.js';
11
13
  export { analyticsService } from './services/AnalyticsService.js';
12
14
  export { buttonActionFactory } from './factories/ButtonActionFactory.js';
@@ -7,5 +7,5 @@ export function Footer({ website }) {
7
7
  const social = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.social;
8
8
  const footer = website.footer.properties;
9
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 })) }), _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
+ 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] })] })] }) }));
11
11
  }
@@ -5,11 +5,8 @@ import { Container, Navbar, Nav } from 'react-bootstrap';
5
5
  export function Header({ website, imageBaseUrl }) {
6
6
  const headerProperties = website.header.properties;
7
7
  const headerStyles = website.header.styles;
8
- const domain = (website.domain || '').replaceAll('.', '');
9
8
  const location = useLocation();
10
- const menuPages = useMemo(() => (website.pages || [])
11
- .filter((p) => p.menu === true)
12
- .sort((a, b) => (a.menuOrder || 0) - (b.menuOrder || 0)), [website.pages]);
9
+ const menuPages = useMemo(() => (website.pages || []).filter((p) => p.menu === true).sort((a, b) => (a.menuOrder || 0) - (b.menuOrder || 0)), [website.pages]);
13
10
  const isActive = useCallback((path) => {
14
11
  const currentPath = location.pathname;
15
12
  if (path === '/')
@@ -17,19 +14,38 @@ export function Header({ website, imageBaseUrl }) {
17
14
  return currentPath === path || currentPath.startsWith(path + '/');
18
15
  }, [location.pathname]);
19
16
  const showMenu = headerProperties.showMenu !== false && menuPages.length > 0;
20
- const logoUrl = useMemo(() => imageBaseUrl
21
- ? `${imageBaseUrl.replace(/\/+$/, '')}/${domain}/${website.logo}`
22
- : `https://noisdev-website-images.s3.sa-east-1.amazonaws.com/${domain}/${website.logo}`, [imageBaseUrl, domain, website.logo]);
23
- return (_jsx(Navbar, { expand: "lg", collapseOnSelect: true, className: "py-3", style: { backgroundColor: headerStyles.backgroundColor || undefined, width: '100%' }, children: _jsxs(Container, { fluid: headerStyles.fluid || undefined, children: [headerProperties.showLogo && (_jsx(Navbar.Brand, { style: { marginRight: showMenu ? 'auto' : 0, padding: 0 }, children: _jsx("img", { src: logoUrl, width: "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) => {
17
+ const logoUrl = useMemo(() => (imageBaseUrl && website.logo ? `${imageBaseUrl.replace(/\/+$/, '')}/${website.logo}` : undefined), [imageBaseUrl, website.logo]);
18
+ const logoAlign = headerProperties.logoAlign || 'center';
19
+ const menuLinkColor = headerStyles.menuLinkColor || headerStyles.color || undefined;
20
+ const menuActiveLinkColor = headerStyles.menuActiveLinkColor || headerStyles.menuLinkColor || headerStyles.color || undefined;
21
+ const brandStyle = { padding: 0 };
22
+ if (showMenu) {
23
+ if (logoAlign === 'right')
24
+ brandStyle.marginLeft = 'auto';
25
+ else if (logoAlign === 'center') {
26
+ brandStyle.marginRight = 'auto';
27
+ brandStyle.marginLeft = 'auto';
28
+ }
29
+ else {
30
+ brandStyle.marginRight = 'auto';
31
+ }
32
+ }
33
+ else if (logoAlign === 'center') {
34
+ brandStyle.margin = '0 auto';
35
+ }
36
+ else if (logoAlign === 'right') {
37
+ brandStyle.marginLeft = 'auto';
38
+ }
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) => {
24
40
  const active = isActive(p.path);
25
41
  return (_jsx(Nav.Link, { href: p.path, style: {
26
- color: active ? '#c0ad5b' : '#a4a4a4',
27
- fontSize: '0.9rem',
28
- letterSpacing: '0.05em',
29
- textTransform: 'uppercase',
42
+ color: active ? menuActiveLinkColor : menuLinkColor,
43
+ fontSize: headerStyles.menuFontSize || undefined,
44
+ letterSpacing: headerStyles.menuLetterSpacing || undefined,
45
+ textTransform: headerStyles.menuTextTransform || undefined,
30
46
  margin: '0 12px',
31
47
  paddingBottom: '4px',
32
- borderBottom: active ? '2px solid #c0ad5b' : '2px solid transparent',
48
+ borderBottom: active && menuActiveLinkColor ? `2px solid ${menuActiveLinkColor}` : '2px solid transparent',
33
49
  transition: 'color 0.3s, border-color 0.3s',
34
50
  }, children: p.title }, p.id));
35
51
  }) }) })] }))] }) }));
@@ -1,5 +1,12 @@
1
1
  import type { WebsiteType } from '../types/WebsiteType.js';
2
- export declare function SiteLayout({ website, imageBaseUrl }: {
2
+ export interface EmailApiConfig {
3
+ apiUrl?: string;
4
+ authToken?: string;
5
+ sender?: string;
6
+ senderName?: string;
7
+ }
8
+ export declare function SiteLayout({ website, imageBaseUrl, emailApi }: {
3
9
  readonly website: WebsiteType;
4
10
  readonly imageBaseUrl?: string;
11
+ readonly emailApi?: EmailApiConfig;
5
12
  }): import("react").JSX.Element;
@@ -1,7 +1,39 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
2
3
  import { Outlet } from 'react-router-dom';
4
+ import { Helmet } from 'react-helmet-async';
3
5
  import { Header } from './Header.js';
4
6
  import { Footer } from './Footer.js';
5
- export function SiteLayout({ website, imageBaseUrl }) {
6
- return (_jsxs("div", { id: "site-layout", style: { backgroundColor: website.styles.backgroundColor, color: website.styles.color }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] }));
7
+ import { buildFontFamily, buildGoogleFontsHref } from '../utils/fonts.js';
8
+ import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
9
+ export function SiteLayout({ website, imageBaseUrl, emailApi }) {
10
+ var _a, _b, _c, _d, _e, _f, _g, _h;
11
+ const fontFamily = buildFontFamily((_a = website.styles) === null || _a === void 0 ? void 0 : _a.fontFamily);
12
+ const fontHref = buildGoogleFontsHref((_b = website.styles) === null || _b === void 0 ? void 0 : _b.fontFamily);
13
+ useEffect(() => {
14
+ var _a, _b, _c, _d, _e, _f;
15
+ if (!(emailApi === null || emailApi === void 0 ? void 0 : emailApi.apiUrl) || !emailApi.authToken)
16
+ return;
17
+ buttonActionFactory.configureEmail({
18
+ apiUrl: emailApi.apiUrl,
19
+ authToken: emailApi.authToken,
20
+ websiteId: website.id,
21
+ sender: emailApi.sender || 'contato@pixelbuild.com.br',
22
+ senderName: emailApi.senderName || website.name,
23
+ defaultRecipient: (_b = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.email) === null || _b === void 0 ? void 0 : _b.recipient,
24
+ defaultRecipientName: (_d = (_c = website.properties) === null || _c === void 0 ? void 0 : _c.email) === null || _d === void 0 ? void 0 : _d.recipientName,
25
+ defaultSubject: (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.subject
26
+ });
27
+ }, [
28
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.apiUrl,
29
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.authToken,
30
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.sender,
31
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.senderName,
32
+ website.id,
33
+ website.name,
34
+ (_d = (_c = website.properties) === null || _c === void 0 ? void 0 : _c.email) === null || _d === void 0 ? void 0 : _d.recipient,
35
+ (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.recipientName,
36
+ (_h = (_g = website.properties) === null || _g === void 0 ? void 0 : _g.email) === null || _h === void 0 ? void 0 : _h.subject
37
+ ]);
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 })] })] }));
7
39
  }
@@ -1,8 +1,9 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
3
  import { Container, Row, Col } from 'react-bootstrap';
4
4
  import { ComponentFactory } from '../factories/ComponentFactory.js';
5
5
  import { orderBySort } from '../utils/orderBySort.js';
6
+ import { buildResponsiveCss } from '../utils/responsiveStyles.js';
6
7
  const componentFactory = new ComponentFactory();
7
8
  function colWidthValue(width, offset) {
8
9
  if (width === undefined && offset === undefined)
@@ -15,6 +16,20 @@ function colWidthValue(width, offset) {
15
16
  const ColumnContent = memo(function ColumnContent({ column, editionMode }) {
16
17
  const components = useMemo(() => orderBySort(column.components.filter((c) => c.enabled)), [column.components]);
17
18
  const childSections = useMemo(() => orderBySort(column.childSections), [column.childSections]);
19
+ if (editionMode && components.length === 0 && childSections.length === 0) {
20
+ return (_jsxs("div", { "data-pixelbuild-empty-column": column.id, style: {
21
+ minHeight: 80,
22
+ display: 'flex',
23
+ alignItems: 'center',
24
+ justifyContent: 'center',
25
+ gap: 6,
26
+ border: '1.5px dashed #c4d0dc',
27
+ color: '#94a3b8',
28
+ fontSize: 13,
29
+ cursor: 'pointer',
30
+ textAlign: 'center',
31
+ }, children: [_jsx("span", { style: { fontSize: 18, lineHeight: 1 }, children: "+" }), "Adicionar componente"] }));
32
+ }
18
33
  return (_jsxs(_Fragment, { children: [components.map((component) => componentFactory.build(component, editionMode)), childSections.map((childSection) => (_jsx(SectionContent, { section: childSection, editionMode: editionMode }, childSection.id)))] }));
19
34
  });
20
35
  function gridClass(id) {
@@ -22,9 +37,10 @@ function gridClass(id) {
22
37
  }
23
38
  const GridRenderer = memo(function GridRenderer({ section, editionMode }) {
24
39
  const grid = gridClass(section.id);
25
- const columns = useMemo(() => section.columns.filter((col) => col.components.some((c) => c.enabled) || col.childSections.length > 0), [section.columns]);
40
+ const columns = section.columns;
26
41
  const css = useMemo(() => {
27
- const rules = columns.map((column) => {
42
+ const rules = columns
43
+ .map((column) => {
28
44
  const properties = column.properties || {};
29
45
  const row = Math.max(0, Number(properties.row) || 0);
30
46
  const rowSpan = Math.max(1, Number(properties.rowSpan) || 1);
@@ -37,10 +53,11 @@ const GridRenderer = memo(function GridRenderer({ section, editionMode }) {
37
53
  `@media (min-width:576px){.${grid} .${columnClass}{grid-column:span ${sm}}}`,
38
54
  `@media (min-width:768px){.${grid} .${columnClass}{grid-column:span ${md};grid-row:${row + 1}/span ${rowSpan}}}`
39
55
  ].join('');
40
- }).join('');
56
+ })
57
+ .join('');
41
58
  return `.${grid}{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:1rem}${rules}`;
42
59
  }, [grid, columns]);
43
- return (_jsxs(_Fragment, { children: [_jsx("style", { children: css }), _jsx("div", { id: `section-${section.id}`, className: grid, style: section.sectionType === 'row' ? section.styles : undefined, children: columns.map((column) => (_jsx("div", { id: `column-${column.id}`, className: gridClass(column.id), style: column.styles, children: _jsx(ColumnContent, { column: column, editionMode: editionMode }) }, column.id))) })] }));
60
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: css }), _jsx("div", { id: `section-${section.id}`, "data-pb-section": section.sectionType === 'row' ? section.id : undefined, className: grid, style: section.sectionType === 'row' ? section.styles : undefined, children: columns.map((column) => (_jsx("div", { id: `column-${column.id}`, className: gridClass(column.id), style: column.styles, children: _jsx(ColumnContent, { column: column, editionMode: editionMode }) }, column.id))) })] }));
44
61
  });
45
62
  const SectionContent = memo(function SectionContent({ section, editionMode }) {
46
63
  const usesGrid = useMemo(() => section.columns.some((column) => { var _a, _b; return ((_a = column.properties) === null || _a === void 0 ? void 0 : _a.row) !== undefined || Number((_b = column.properties) === null || _b === void 0 ? void 0 : _b.rowSpan) > 1; }), [section.columns]);
@@ -48,13 +65,13 @@ const SectionContent = memo(function SectionContent({ section, editionMode }) {
48
65
  if (usesGrid) {
49
66
  return _jsx(GridRenderer, { section: section, editionMode: editionMode });
50
67
  }
51
- return (_jsx(Row, { id: `section-${section.id}`, style: section.sectionType === 'row' ? section.styles : undefined, children: section.columns.map((column) => (_jsx(ColumnRenderer, { column: column, editionMode: editionMode }, column.id))) }));
68
+ return (_jsx(Row, { id: `section-${section.id}`, "data-pb-section": section.sectionType === 'row' ? section.id : undefined, style: section.sectionType === 'row' ? section.styles : undefined, children: section.columns.map((column) => (_jsx(ColumnRenderer, { column: column, editionMode: editionMode }, column.id))) }));
52
69
  }, [usesGrid, section, editionMode]);
53
70
  if (section.sectionType === 'container-fluid') {
54
- return _jsx(Container, { fluid: true, style: section.styles, children: content });
71
+ return (_jsx(Container, { fluid: true, "data-pb-section": section.id, style: section.styles, children: content }));
55
72
  }
56
73
  if (section.sectionType === 'container') {
57
- return _jsx(Container, { style: section.styles, children: content });
74
+ return (_jsx(Container, { "data-pb-section": section.id, style: section.styles, children: content }));
58
75
  }
59
76
  return _jsx(Container, { fluid: true, children: content });
60
77
  });
@@ -66,6 +83,6 @@ const SectionRenderer = memo(function SectionRenderer({ sections, editionMode =
66
83
  if (sorted.length === 0) {
67
84
  return null;
68
85
  }
69
- return (_jsx(_Fragment, { children: sorted.map((section) => (_jsx(SectionContent, { section: section, editionMode: editionMode }, section.id))) }));
86
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: buildResponsiveCss(sorted) }), sorted.map((section) => (_jsx(SectionContent, { section: section, editionMode: editionMode }, section.id)))] }));
70
87
  });
71
88
  export { SectionRenderer };