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
@@ -2,11 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Suspense, memo, useMemo } from 'react';
3
3
  import { Helmet } from 'react-helmet-async';
4
4
  import { SectionRenderer } from '../renderers/SectionRenderer.js';
5
+ import { buildResponsiveCssForStyles } from '../utils/responsiveStyles.js';
6
+ import { buildFontFamily } from '../utils/fonts.js';
5
7
  function mergeStyles(websiteStyles, pageStyles) {
6
8
  const merged = Object.assign({}, websiteStyles);
7
9
  for (const key of Object.keys(pageStyles)) {
8
10
  const val = pageStyles[key];
9
11
  if (val !== '' && val !== null && val !== undefined) {
12
+ ;
10
13
  merged[key] = val;
11
14
  }
12
15
  }
@@ -31,6 +34,7 @@ const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
31
34
  backgroundPosition: toCssValue(mergedStyles.backgroundPosition),
32
35
  width: toCssValue(mergedStyles.width),
33
36
  height: toCssValue(mergedStyles.height),
37
+ fontFamily: buildFontFamily(mergedStyles.fontFamily),
34
38
  fontSize: toCssValue(mergedStyles.fontSize),
35
39
  fontWeight: toCssValue(mergedStyles.fontWeight),
36
40
  textAlign: mergedStyles.textAlign,
@@ -41,8 +45,8 @@ const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
41
45
  marginTop: toCssValue(mergedStyles.marginTop),
42
46
  marginBottom: toCssValue(mergedStyles.marginBottom),
43
47
  borderRadius: toCssValue(mergedStyles.borderRadius),
44
- minHeight: page.sections.length === 0 ? '200px' : undefined,
45
- }), [mergedStyles, page.sections.length]);
46
- return (_jsxs(Suspense, { fallback: _jsx("div", { children: website.properties.loadingMessage }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, children: [_jsx(SectionRenderer, { sections: page.sections, editionMode: editionMode }), page.sections.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "No sections configured. Use the layout editor to add content." }))] })] }));
48
+ minHeight: '100vh'
49
+ }), [mergedStyles]);
50
+ return (_jsxs(Suspense, { fallback: _jsx("div", { children: website.properties.loadingMessage }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, "data-pb-page": true, children: [_jsx("style", { children: buildResponsiveCssForStyles('[data-pb-page]', page.styles) }), _jsx(SectionRenderer, { sections: page.sections, editionMode: editionMode }), page.sections.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "No sections configured. Use the layout editor to add content." }))] })] }));
47
51
  });
48
52
  export { PageBuilder };
@@ -0,0 +1,5 @@
1
+ import type { ComponentType } from '../types/ComponentType.js';
2
+ declare const ButtonsComponent: import("react").NamedExoticComponent<{
3
+ readonly component: ComponentType;
4
+ }>;
5
+ export { ButtonsComponent };
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { Button, Container } from 'react-bootstrap';
4
+ import { orderBySort } from '../utils/orderBySort.js';
5
+ import { getString, getNumber, getBoolean } from '../utils/propertyUtils.js';
6
+ const ALIGN_JUSTIFY = {
7
+ left: 'flex-start',
8
+ center: 'center',
9
+ right: 'flex-end',
10
+ };
11
+ const ButtonsComponent = memo(function ButtonsComponent({ component }) {
12
+ var _a, _b;
13
+ const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
14
+ const properties = component.properties || {};
15
+ const isColumn = getString(properties, 'layout', 'row') === 'column';
16
+ const gap = (_a = getNumber(properties, 'gap', 12)) !== null && _a !== void 0 ? _a : 12;
17
+ const fullWidth = getBoolean(properties, 'fullWidth', false);
18
+ const align = (_b = ALIGN_JUSTIFY[getString(properties, 'align', 'left')]) !== null && _b !== void 0 ? _b : 'flex-start';
19
+ const containerStyle = {
20
+ display: 'flex',
21
+ flexDirection: isColumn ? 'column' : 'row',
22
+ flexWrap: 'wrap',
23
+ gap: `${gap}px`,
24
+ };
25
+ if (isColumn)
26
+ containerStyle.alignItems = align;
27
+ else
28
+ containerStyle.justifyContent = align;
29
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx("div", { style: containerStyle, children: elements.map((element) => {
30
+ const props = element.properties || {};
31
+ const href = getString(props, 'path') || getString(props, 'href');
32
+ const text = getString(props, 'text') || getString(props, 'title');
33
+ const size = getString(props, 'size');
34
+ const style = Object.assign({}, element.styles);
35
+ if (fullWidth) {
36
+ if (isColumn)
37
+ style.width = '100%';
38
+ else
39
+ style.flex = '1 1 0%';
40
+ }
41
+ return (_jsx(Button, { "data-pb-element": element.id, as: href ? 'a' : 'button', variant: getString(props, 'variant', 'primary'), size: size === 'sm' || size === 'lg' ? size : undefined, href: href || undefined, target: href ? getString(props, 'target', '_self') : undefined, rel: href ? 'noopener noreferrer' : undefined, style: style, children: text }, element.id));
42
+ }) }) }));
43
+ });
44
+ export { ButtonsComponent };
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
3
  import { Row, Container } from 'react-bootstrap';
4
4
  import { ElementFactory } from '../factories/ElementFactory.js';
@@ -24,7 +24,13 @@ function applyCardStyles(element, props) {
24
24
  if (props.cardTextSize)
25
25
  overrides.fontSize = props.cardTextSize;
26
26
  }
27
- return Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, element.styles), overrides) });
27
+ return Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, element.styles), overrides), fullBleed: element.elementType === 'image' ? true : element.fullBleed });
28
+ }
29
+ function stripWidth(element) {
30
+ return Object.assign(Object.assign({}, element), { width: {} });
31
+ }
32
+ function centerStyles(element) {
33
+ return Object.assign(Object.assign({}, element), { width: {}, styles: Object.assign(Object.assign({}, element.styles), { textAlign: 'center' }) });
28
34
  }
29
35
  const CardComponent = memo(function CardComponent({ component }) {
30
36
  const { properties } = component;
@@ -38,7 +44,7 @@ const CardComponent = memo(function CardComponent({ component }) {
38
44
  cardTitleColor: properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
39
45
  cardTitleSize: properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
40
46
  cardTextColor: properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
41
- cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize,
47
+ cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize
42
48
  }), [
43
49
  properties === null || properties === void 0 ? void 0 : properties.cardElement1,
44
50
  properties === null || properties === void 0 ? void 0 : properties.cardElement2,
@@ -49,14 +55,14 @@ const CardComponent = memo(function CardComponent({ component }) {
49
55
  properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
50
56
  properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
51
57
  properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
52
- properties === null || properties === void 0 ? void 0 : properties.cardTextSize,
58
+ properties === null || properties === void 0 ? void 0 : properties.cardTextSize
53
59
  ]);
54
60
  const orderedElements = useMemo(() => {
55
61
  const cardOrder = [
56
62
  cardProps.cardElement1,
57
63
  cardProps.cardElement2,
58
64
  cardProps.cardElement3,
59
- cardProps.cardElement4,
65
+ cardProps.cardElement4
60
66
  ].filter((v) => typeof v === 'string' && v.length > 0);
61
67
  if (cardOrder.length > 0) {
62
68
  return cardOrder
@@ -64,8 +70,27 @@ const CardComponent = memo(function CardComponent({ component }) {
64
70
  .filter((el) => el !== undefined);
65
71
  }
66
72
  return orderBySort(component.elements);
67
- }, [cardProps.cardElement1, cardProps.cardElement2, cardProps.cardElement3, cardProps.cardElement4, component.elements]);
73
+ }, [
74
+ cardProps.cardElement1,
75
+ cardProps.cardElement2,
76
+ cardProps.cardElement3,
77
+ cardProps.cardElement4,
78
+ component.elements
79
+ ]);
68
80
  const elements = useMemo(() => orderedElements.map((el) => applyCardStyles(el, cardProps)), [orderedElements, cardProps]);
81
+ const layout = String((properties === null || properties === void 0 ? void 0 : properties.cardLayout) || 'stacked');
82
+ if (layout === 'icon-left' || layout === 'icon-right') {
83
+ const icon = elements.find((element) => element.elementType === 'icon');
84
+ const others = elements.filter((element) => element !== icon);
85
+ const iconBox = icon ? _jsx("div", { style: { flex: '0 0 auto' }, children: elementFactory.build(stripWidth(icon)) }) : null;
86
+ const contentBox = _jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: others.map((element) => elementFactory.build(stripWidth(element))) });
87
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }, children: [layout === 'icon-left' ? iconBox : contentBox, layout === 'icon-left' ? contentBox : iconBox] }) }));
88
+ }
89
+ if (layout === 'icon-top') {
90
+ const icon = elements.find((element) => element.elementType === 'icon');
91
+ const others = elements.filter((element) => element !== icon);
92
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { textAlign: 'center' }, children: [icon && _jsx("div", { style: { display: 'inline-block' }, children: elementFactory.build(centerStyles(icon)) }), _jsx("div", { children: others.map((element) => elementFactory.build(centerStyles(element))) })] }) }));
93
+ }
69
94
  return (_jsx(Container, { style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
70
95
  });
71
96
  export { CardComponent };
@@ -1,19 +1,23 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useEffect, useMemo } from 'react';
3
- import { Form, Row } from 'react-bootstrap';
3
+ import { Form, Row, Container } from 'react-bootstrap';
4
4
  import { UseFormStore } from '../stores/UseFormStore.js';
5
5
  import { ElementFactory } from '../factories/ElementFactory.js';
6
6
  import { orderBySort } from '../utils/orderBySort.js';
7
7
  const elementFactory = new ElementFactory();
8
8
  const FormComponent = memo(function FormComponent({ component }) {
9
9
  const registerForm = UseFormStore((state) => state.registerForm);
10
+ const properties = component.properties;
10
11
  useEffect(() => {
11
- registerForm(component.id);
12
- }, [registerForm, component.id]);
12
+ registerForm(component.id, {
13
+ recipient: typeof properties.recipient === 'string' ? properties.recipient : undefined,
14
+ subject: typeof properties.subject === 'string' ? properties.subject : undefined
15
+ });
16
+ }, [registerForm, component.id, properties.recipient, properties.subject]);
13
17
  const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
14
18
  const handleSubmit = (event) => {
15
19
  event.preventDefault();
16
20
  };
17
- return (_jsx(Form, { onSubmit: handleSubmit, children: _jsx(Row, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }));
21
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Form, { onSubmit: handleSubmit, children: _jsx(Row, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }) }));
18
22
  });
19
23
  export { FormComponent };
@@ -1,4 +1,5 @@
1
1
  import type { ComponentType } from '../types/ComponentType.js';
2
- export declare function CarouselComponent({ component }: {
2
+ declare const ImageComponent: import("react").NamedExoticComponent<{
3
3
  readonly component: ComponentType;
4
- }): import("react").JSX.Element;
4
+ }>;
5
+ export { ImageComponent };
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { Row, Container } from 'react-bootstrap';
4
+ import { ElementFactory } from '../factories/ElementFactory.js';
5
+ import { orderBySort } from '../utils/orderBySort.js';
6
+ import { resolveImageElement } from '../utils/imageCustomization.js';
7
+ import { getBoolean } from '../utils/propertyUtils.js';
8
+ const elementFactory = new ElementFactory();
9
+ const ImageComponent = memo(function ImageComponent({ component }) {
10
+ const fullBleed = getBoolean(component.properties, 'fullBleed', false);
11
+ const elements = useMemo(() => orderBySort(component.elements).map((element) => resolveImageElement(component, element)), [component.elements, component.properties]);
12
+ if (fullBleed) {
13
+ return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--bs-gutter-x, 1.5rem))', marginLeft: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)', marginRight: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)' }), children: elements.map((element) => elementFactory.build(Object.assign(Object.assign({}, element), { fullBleed: true }))) }));
14
+ }
15
+ return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
16
+ });
17
+ export { ImageComponent };
@@ -7,6 +7,10 @@ import { orderBySort } from '../utils/orderBySort.js';
7
7
  const elementFactory = new ElementFactory();
8
8
  const ListComponent = memo(function ListComponent({ component }) {
9
9
  const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
10
+ const properties = component.properties || {};
11
+ const itemFontSize = String(properties.itemFontSize || '22px');
12
+ const itemGap = String(properties.itemGap || '8px');
13
+ const itemAlign = String(properties.itemAlign || 'center');
10
14
  const items = useMemo(() => {
11
15
  const result = [];
12
16
  for (let i = 0; i < elements.length; i++) {
@@ -24,6 +28,6 @@ const ListComponent = memo(function ListComponent({ component }) {
24
28
  }
25
29
  return result;
26
30
  }, [elements]);
27
- return (_jsx(Col, { style: component.styles, children: _jsx("ul", { style: { listStyle: 'none' }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: '8px' }, children: [_jsx("span", { children: elementFactory.build(icon) }), _jsx("span", { style: { fontSize: '22px' }, children: text ? elementFactory.build(text) : null })] }, id))) }) }));
31
+ return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx("ul", { style: { listStyle: 'none' }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent: itemAlign, marginBottom: itemGap }, children: [_jsx("span", { children: elementFactory.build(icon) }), _jsx("span", { style: { fontSize: itemFontSize }, children: text ? elementFactory.build(text) : null })] }, id))) }) }));
28
32
  });
29
33
  export { ListComponent };
@@ -8,7 +8,7 @@ function isValidCoord(value) {
8
8
  return COORDS_PATTERN.test(value.trim()) && Math.abs(Number(value)) <= 180;
9
9
  }
10
10
  export function MapComponent({ component }) {
11
- const { lat, lng, zoom = 15, height = '400px' } = component.properties;
11
+ const { lat, lng, zoom = 15, height = '400px', placeholderBackgroundColor = '#e0e0e0', placeholderTextColor = '#666' } = component.properties;
12
12
  const src = useMemo(() => {
13
13
  if (!lat || !lng)
14
14
  return null;
@@ -19,14 +19,14 @@ export function MapComponent({ component }) {
19
19
  }
20
20
  return `https://maps.google.com/maps?q=${encodeURIComponent(`${latStr},${lngStr}`)}&z=${zoom}&output=embed`;
21
21
  }, [lat, lng, zoom]);
22
- return (_jsx(Col, { style: component.styles, children: _jsx(Row, { children: _jsx(Col, { children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
22
+ return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { children: _jsx(Col, { children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
23
23
  width: '100%',
24
24
  height,
25
- backgroundColor: '#e0e0e0',
25
+ backgroundColor: placeholderBackgroundColor,
26
26
  display: 'flex',
27
27
  alignItems: 'center',
28
28
  justifyContent: 'center',
29
29
  borderRadius: '4px',
30
- color: '#666',
30
+ color: placeholderTextColor
31
31
  }, children: "Map not configured" })) }) }) }));
32
32
  }
@@ -1,6 +1,5 @@
1
1
  import type { ComponentType } from '../types/ComponentType.js';
2
- import 'keen-slider/keen-slider.min.css';
3
- export declare function SliderComponent({ component, editionMode }: {
2
+ export declare function SliderComponent({ component, editionMode, }: {
4
3
  readonly component: ComponentType;
5
4
  readonly editionMode?: boolean;
6
5
  }): import("react").JSX.Element;
@@ -1,109 +1,191 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { useKeenSlider } from 'keen-slider/react.js';
2
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
4
3
  import { ElementFactory } from '../factories/ElementFactory.js';
5
4
  import { orderBySort } from '../utils/orderBySort.js';
6
- import 'keen-slider/keen-slider.min.css';
5
+ import { resolveResponsiveProperties, breakpointFromWidth } from '../utils/responsiveProperties.js';
7
6
  const elementFactory = new ElementFactory();
8
7
  function cleanComponentStyles(styles) {
9
8
  const exclude = new Set(['minHeight', 'display', 'alignItems', 'justifyContent', 'flexDirection']);
10
9
  return Object.fromEntries(Object.entries(styles).filter(([key]) => !exclude.has(key)));
11
10
  }
12
- function StaticSliderComponent({ component }) {
13
- const firstSlide = orderBySort(component.elements)[0];
14
- if (!firstSlide)
15
- return null;
16
- return (_jsx("div", { style: Object.assign({ position: 'relative', overflow: 'hidden' }, cleanComponentStyles(component.styles)), children: elementFactory.build(firstSlide) }));
11
+ function buildSlide(element, fixedHeight, sharedImageStyles, useSharedImages) {
12
+ const isImage = element.elementType === 'image' || element.elementType === 'video';
13
+ if (isImage) {
14
+ const base = fixedHeight ? { width: '100%', height: '100%', objectFit: 'cover' } : { width: '100%' };
15
+ const override = useSharedImages ? sharedImageStyles || {} : element.styles;
16
+ return elementFactory.build(Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, base), override) }));
17
+ }
18
+ return elementFactory.build(Object.assign(Object.assign({}, element), { styles: element.styles }));
17
19
  }
18
- function InteractiveSliderComponent({ component }) {
20
+ function resolveChromeColors(properties) {
21
+ return {
22
+ arrowBackground: String(properties.arrowBackground || 'rgba(0,0,0,0.45)'),
23
+ arrowColor: String(properties.arrowColor || '#fff'),
24
+ arrowSize: Number(properties.arrowSize) || 40,
25
+ dotActiveBackground: String(properties.dotActiveBackground || '#333'),
26
+ dotBackground: String(properties.dotBackground || 'rgba(0,0,0,0.15)'),
27
+ dotActiveColor: String(properties.dotActiveColor || '#fff'),
28
+ dotColor: String(properties.dotColor || '#666'),
29
+ dotSize: Number(properties.dotSize) || 28,
30
+ };
31
+ }
32
+ const ARROW_BASE_STYLE = {
33
+ position: 'absolute',
34
+ top: '50%',
35
+ transform: 'translateY(-50%)',
36
+ zIndex: 10,
37
+ borderRadius: '50%',
38
+ border: 'none',
39
+ fontSize: 18,
40
+ fontWeight: 700,
41
+ lineHeight: 1,
42
+ cursor: 'pointer',
43
+ display: 'flex',
44
+ alignItems: 'center',
45
+ justifyContent: 'center',
46
+ transition: 'background 0.2s',
47
+ };
48
+ function ArrowButton({ side, size, background, color, onClick, }) {
49
+ return (_jsx("button", { type: "button", "aria-label": side === 'left' ? 'Slide anterior' : 'Próximo slide', onClick: onClick, style: Object.assign(Object.assign({}, ARROW_BASE_STYLE), { [side]: 8, width: size, height: size, background, color }), children: _jsx("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "none", children: _jsx("path", { d: side === 'left' ? 'M8.5 1L1.5 8L8.5 15' : 'M1.5 1L8.5 8L1.5 15', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
50
+ }
51
+ function Dots({ count, current, size, activeBackground, background, activeColor, color, onGoTo, }) {
52
+ return (_jsx("div", { "aria-label": "Navega\u00E7\u00E3o do slider", style: { display: 'flex', justifyContent: 'center', gap: 6, marginTop: 12 }, children: Array.from({ length: count }).map((_, index) => (_jsx("button", { type: "button", "aria-label": `Ir para o slide ${index + 1}`, "aria-current": current === index ? 'true' : undefined, onClick: () => onGoTo(index), style: {
53
+ width: size,
54
+ height: size,
55
+ borderRadius: '50%',
56
+ border: 'none',
57
+ background: current === index ? activeBackground : background,
58
+ color: current === index ? activeColor : color,
59
+ fontSize: 12,
60
+ fontWeight: 600,
61
+ lineHeight: 1,
62
+ cursor: 'pointer',
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'center',
66
+ transition: 'all 0.2s',
67
+ }, children: index + 1 }, index))) }));
68
+ }
69
+ function useSliderWidth(ref) {
70
+ const [width, setWidth] = useState(0);
71
+ useLayoutEffect(() => {
72
+ const el = ref.current;
73
+ if (!el)
74
+ return;
75
+ const measure = () => setWidth(el.getBoundingClientRect().width);
76
+ measure();
77
+ const observer = new ResizeObserver(measure);
78
+ observer.observe(el);
79
+ return () => observer.disconnect();
80
+ }, [ref]);
81
+ return width;
82
+ }
83
+ export function SliderComponent({ component, editionMode = false, }) {
19
84
  const properties = component.properties || {};
20
85
  const slides = orderBySort(component.elements);
21
- const [currentSlide, setCurrentSlide] = useState(0);
22
- const [loaded, setLoaded] = useState(false);
23
- const [ref, instanceRef] = useKeenSlider({
24
- loop: slides.length > 1,
25
- mode: 'snap',
26
- slides: { perView: Number(properties.perView) || 1, spacing: 10 },
27
- created() {
28
- setLoaded(true);
29
- },
30
- slideChanged(slider) {
31
- setCurrentSlide(slider.track.details.rel);
32
- }
33
- });
86
+ const n = slides.length;
87
+ const containerRef = useRef(null);
88
+ const width = useSliderWidth(containerRef);
89
+ const breakpoint = breakpointFromWidth(width);
90
+ const resolved = useMemo(() => resolveResponsiveProperties(properties, breakpoint), [properties, breakpoint]);
91
+ const perView = Math.max(1, Number(resolved.perView) || 1);
92
+ const spacing = Number(resolved.spacing) > 0 ? Number(resolved.spacing) : 10;
93
+ const fixedHeight = Number(resolved.height) > 0 ? Number(resolved.height) : 0;
94
+ const loop = resolved.loop === undefined ? n > 1 : Boolean(resolved.loop);
95
+ const slideWidth = width > 0 ? (width - spacing * (perView - 1)) / perView : 0;
96
+ const slideStep = slideWidth + spacing;
97
+ const maxIndex = Math.max(0, n - perView);
98
+ const [index, setIndex] = useState(loop ? n : 0);
99
+ const [animate, setAnimate] = useState(false);
100
+ const [dragging, setDragging] = useState(false);
101
+ const dragRef = useRef(null);
102
+ const currentIndex = loop
103
+ ? ((Math.round(index) % n) + n) % n
104
+ : Math.min(Math.max(0, Math.round(index)), maxIndex);
34
105
  useEffect(() => {
35
- if (!properties.autoplay || slides.length < 2)
106
+ if (editionMode || !resolved.autoplay || n <= 1)
36
107
  return;
37
- const interval = Number(properties.interval) > 0 ? Number(properties.interval) : 5000;
38
- const timer = window.setInterval(() => { var _a; return (_a = instanceRef.current) === null || _a === void 0 ? void 0 : _a.moveToIdx(instanceRef.current.track.details.rel + 1); }, interval);
108
+ const interval = Number(resolved.interval) > 0 ? Number(resolved.interval) : 5000;
109
+ const timer = window.setInterval(() => {
110
+ setAnimate(true);
111
+ setIndex((prev) => prev + 1);
112
+ }, interval);
39
113
  return () => window.clearInterval(timer);
40
- }, [instanceRef, properties.autoplay, properties.interval, slides.length]);
41
- const fixedHeight = Number(properties.height) > 0 ? Number(properties.height) : 0;
42
- const perView = Number(properties.perView) || 1;
43
- const showArrows = Boolean(properties.showArrows) && loaded && slides.length > perView;
44
- const showDots = Boolean(properties.showDots) && loaded && slides.length > 1;
45
- return (_jsxs("div", { style: Object.assign({ position: 'relative' }, cleanComponentStyles(component.styles)), children: [_jsx("div", { ref: ref, className: "keen-slider", style: fixedHeight ? { height: fixedHeight } : undefined, children: slides.map((element) => (_jsx("div", { className: "keen-slider__slide", style: { overflow: 'hidden' }, children: elementFactory.build(Object.assign(Object.assign({}, element), { styles: element.elementType === 'image' || element.elementType === 'video'
46
- ? fixedHeight
47
- ? Object.assign({ width: '100%', height: '100%', objectFit: 'cover' }, element.styles) : Object.assign({ width: '100%' }, element.styles)
48
- : element.styles })) }, element.id))) }), showArrows && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Slide anterior", onClick: () => { var _a; return (_a = instanceRef.current) === null || _a === void 0 ? void 0 : _a.moveToIdx(instanceRef.current.track.details.rel - 1); }, style: {
49
- position: 'absolute',
50
- left: 8,
51
- top: '50%',
52
- transform: 'translateY(-50%)',
53
- zIndex: 10,
54
- width: 40,
55
- height: 40,
56
- borderRadius: '50%',
57
- border: 'none',
58
- background: 'rgba(0,0,0,0.45)',
59
- color: '#fff',
60
- fontSize: 18,
61
- fontWeight: 700,
62
- lineHeight: 1,
63
- cursor: 'pointer',
64
- display: 'flex',
65
- alignItems: 'center',
66
- justifyContent: 'center',
67
- transition: 'background 0.2s',
68
- }, children: _jsx("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "none", children: _jsx("path", { d: "M8.5 1L1.5 8L8.5 15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("button", { type: "button", "aria-label": "Proximo slide", onClick: () => { var _a; return (_a = instanceRef.current) === null || _a === void 0 ? void 0 : _a.moveToIdx(instanceRef.current.track.details.rel + 1); }, style: {
69
- position: 'absolute',
70
- right: 8,
71
- top: '50%',
72
- transform: 'translateY(-50%)',
73
- zIndex: 10,
74
- width: 40,
75
- height: 40,
76
- borderRadius: '50%',
77
- border: 'none',
78
- background: 'rgba(0,0,0,0.45)',
79
- color: '#fff',
80
- fontSize: 18,
81
- fontWeight: 700,
82
- lineHeight: 1,
83
- cursor: 'pointer',
84
- display: 'flex',
85
- alignItems: 'center',
86
- justifyContent: 'center',
87
- transition: 'background 0.2s',
88
- }, children: _jsx("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "none", children: _jsx("path", { d: "M1.5 1L8.5 8L1.5 15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })), showDots && (_jsx("div", { "aria-label": "Navegacao do slider", style: { display: 'flex', justifyContent: 'center', gap: 6, marginTop: 12 }, children: slides.map((element, index) => (_jsx("button", { type: "button", "aria-label": `Ir para o slide ${index + 1}`, "aria-current": currentSlide === index ? 'true' : undefined, onClick: () => { var _a; return (_a = instanceRef.current) === null || _a === void 0 ? void 0 : _a.moveToIdx(index); }, style: {
89
- width: 28,
90
- height: 28,
91
- borderRadius: '50%',
92
- border: 'none',
93
- background: currentSlide === index ? '#333' : 'rgba(0,0,0,0.15)',
94
- color: currentSlide === index ? '#fff' : '#666',
95
- fontSize: 12,
96
- fontWeight: 600,
97
- lineHeight: 1,
98
- cursor: 'pointer',
114
+ }, [editionMode, resolved.autoplay, resolved.interval, n]);
115
+ const snapToRange = (value) => {
116
+ if (!loop)
117
+ return value;
118
+ if (value >= 2 * n)
119
+ return value - n;
120
+ if (value < n)
121
+ return value + n;
122
+ return value;
123
+ };
124
+ const handleTransitionEnd = () => {
125
+ if (!loop || dragging)
126
+ return;
127
+ const snapped = snapToRange(index);
128
+ if (snapped !== index) {
129
+ setAnimate(false);
130
+ setIndex(snapped);
131
+ }
132
+ };
133
+ const goTo = (i) => {
134
+ const target = loop ? i : Math.min(Math.max(0, i), maxIndex);
135
+ setAnimate(true);
136
+ setIndex(target);
137
+ };
138
+ const goToDot = (i) => {
139
+ const target = loop ? n + i : Math.min(Math.max(0, i), maxIndex);
140
+ let delta = target - index;
141
+ if (loop) {
142
+ if (delta > n / 2)
143
+ delta -= n;
144
+ else if (delta < -n / 2)
145
+ delta += n;
146
+ }
147
+ setAnimate(true);
148
+ setIndex(index + delta);
149
+ };
150
+ const onPointerDown = (e) => {
151
+ if (n <= 1)
152
+ return;
153
+ dragRef.current = { startX: e.clientX, startIndex: index };
154
+ e.currentTarget.setPointerCapture(e.pointerId);
155
+ setDragging(true);
156
+ setAnimate(false);
157
+ };
158
+ const onPointerMove = (e) => {
159
+ const drag = dragRef.current;
160
+ if (!drag || slideStep <= 0)
161
+ return;
162
+ setIndex(drag.startIndex - (e.clientX - drag.startX) / slideStep);
163
+ };
164
+ const endDrag = () => {
165
+ if (!dragRef.current)
166
+ return;
167
+ dragRef.current = null;
168
+ setDragging(false);
169
+ setIndex((prev) => {
170
+ const rounded = Math.round(prev);
171
+ return loop ? snapToRange(rounded) : Math.min(Math.max(0, rounded), maxIndex);
172
+ });
173
+ setAnimate(true);
174
+ };
175
+ const translateX = -(index * slideStep);
176
+ const trackSlides = loop ? [...slides, ...slides, ...slides] : slides;
177
+ const showArrows = Boolean(resolved.showArrows) && n > perView;
178
+ const showDots = Boolean(resolved.showDots) && n > 1;
179
+ const chrome = resolveChromeColors(resolved);
180
+ const useSharedImages = resolved.imageCustomization !== 'separate';
181
+ const sharedImageStyles = resolved.imageStyles || {};
182
+ return (_jsxs("div", { ref: containerRef, "data-pb-component": component.id, style: Object.assign({ position: 'relative' }, cleanComponentStyles(component.styles)), children: [_jsx("div", { style: Object.assign({ overflow: 'hidden' }, (fixedHeight ? { height: fixedHeight } : {})), children: _jsx("div", { style: {
99
183
  display: 'flex',
100
- alignItems: 'center',
101
- justifyContent: 'center',
102
- transition: 'all 0.2s',
103
- }, children: index + 1 }, element.id))) }))] }));
104
- }
105
- export function SliderComponent({ component, editionMode = false }) {
106
- if (editionMode)
107
- return _jsx(StaticSliderComponent, { component: component });
108
- return _jsx(InteractiveSliderComponent, { component: component });
184
+ columnGap: spacing,
185
+ transform: `translateX(${translateX}px)`,
186
+ transition: animate && !dragging ? 'transform 0.3s ease' : 'none',
187
+ cursor: dragging ? 'grabbing' : n > 1 ? 'grab' : 'default',
188
+ touchAction: 'pan-y',
189
+ userSelect: 'none',
190
+ }, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onTransitionEnd: handleTransitionEnd, children: trackSlides.map((element, i) => (_jsx("div", { style: { width: slideWidth, flexShrink: 0, overflow: 'hidden' }, children: buildSlide(element, fixedHeight, sharedImageStyles, useSharedImages) }, `${element.id}-${i}`))) }) }), showArrows && (_jsxs(_Fragment, { children: [_jsx(ArrowButton, { side: "left", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index - 1) }), _jsx(ArrowButton, { side: "right", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index + 1) })] })), showDots && (_jsx(Dots, { count: n, current: currentIndex, size: chrome.dotSize, activeBackground: chrome.dotActiveBackground, background: chrome.dotBackground, activeColor: chrome.dotActiveColor, color: chrome.dotColor, onGoTo: goToDot }))] }));
109
191
  }
@@ -1,4 +1,5 @@
1
1
  import type { SocialPropertiesType } from '../types/SocialPropertiesType.js';
2
- export declare function SocialIconsComponent({ social }: {
3
- readonly social: SocialPropertiesType;
2
+ export declare function SocialIconsComponent({ social, color }: {
3
+ readonly social?: SocialPropertiesType;
4
+ readonly color?: string;
4
5
  }): import("react").JSX.Element;
@@ -1,19 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Row, Col } from 'react-bootstrap';
3
- import { FaFacebookF, FaInstagram, FaLink } from 'react-icons/fa';
4
- export function SocialIconsComponent({ social }) {
5
- var _a, _b, _c;
6
- const all = [];
7
- if ((_a = social.facebook) === null || _a === void 0 ? void 0 : _a.path) {
8
- all.push({ id: 'facebook', url: social.facebook.path, icon: FaFacebookF, description: 'Logo do Facebook' });
9
- }
10
- if ((_b = social.instagram) === null || _b === void 0 ? void 0 : _b.path) {
11
- all.push({ id: 'instagram', url: social.instagram.path, icon: FaInstagram, description: 'Logo do Instagram' });
12
- }
13
- if ((_c = social.linktree) === null || _c === void 0 ? void 0 : _c.path) {
14
- all.push({ id: 'linktree', url: social.linktree.path, icon: FaLink, description: 'Logo do Linktree' });
15
- }
16
- if (all.length === 0)
3
+ import { FaFacebookF, FaInstagram, FaTiktok, FaWhatsapp, FaYoutube, FaXTwitter, FaLinkedin, FaThreads, FaLink, } from 'react-icons/fa6';
4
+ const SOCIAL_ICONS = {
5
+ facebook: FaFacebookF,
6
+ instagram: FaInstagram,
7
+ tiktok: FaTiktok,
8
+ whatsapp: FaWhatsapp,
9
+ youtube: FaYoutube,
10
+ x: FaXTwitter,
11
+ twitter: FaXTwitter,
12
+ linkedin: FaLinkedin,
13
+ threads: FaThreads,
14
+ linktree: FaLink,
15
+ kwai: FaLink,
16
+ };
17
+ export function SocialIconsComponent({ social, color }) {
18
+ const entries = Object.entries(social || {})
19
+ .filter(([, value]) => Boolean(value === null || value === void 0 ? void 0 : value.path))
20
+ .map(([id, value]) => ({ id, url: (value === null || value === void 0 ? void 0 : value.path) || '', Icon: SOCIAL_ICONS[id] || FaLink }));
21
+ if (entries.length === 0)
17
22
  return null;
18
- return (_jsx(Row, { children: all.map((element) => (_jsx(Col, { className: "text-center social-icons", style: { color: '#FFCC00' }, children: _jsx("a", { href: element.url, target: "_blank", rel: "noopener noreferrer", "aria-label": element.description, children: _jsx(element.icon, {}) }) }, element.id))) }));
23
+ return (_jsx(Row, { children: entries.map(({ id, url, Icon }) => (_jsx(Col, { className: "text-center social-icons", style: { color }, children: _jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": id, children: _jsx(Icon, {}) }) }, id))) }));
19
24
  }