@cntrl-site/sdk-nextjs 1.9.72 → 1.9.74-alpha.0

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.
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/sdk-nextjs.iml" filepath="$PROJECT_DIR$/.idea/sdk-nextjs.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
7
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
+ </content>
9
+ <orderEntry type="inheritedJdk" />
10
+ <orderEntry type="sourceFolder" forTests="false" />
11
+ </component>
12
+ </module>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -8,7 +8,6 @@ const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
9
  const style_1 = __importDefault(require("styled-jsx/style"));
10
10
  const Section_1 = require("./Section/Section");
11
- const Item_1 = require("./items/Item");
12
11
  const useArticleRectObserver_1 = require("../utils/ArticleRectManager/useArticleRectObserver");
13
12
  const ArticleRectContext_1 = require("../provider/ArticleRectContext");
14
13
  const ArticleWrapper_1 = require("./ArticleWrapper");
@@ -31,8 +30,8 @@ const Article = ({ article, sectionData }) => {
31
30
  const sectionsLength = article.sections.length;
32
31
  return ((0, jsx_runtime_1.jsx)(ArticleRectContext_1.ArticleRectContext.Provider, { value: articleRectObserver, children: (0, jsx_runtime_1.jsxs)(InteractionsContext_1.InteractionsProvider, { article: article, children: [(0, jsx_runtime_1.jsx)(ArticleWrapper_1.ArticleWrapper, { children: (0, jsx_runtime_1.jsxs)("div", { className: "article", ref: articleRef, children: [(0, jsx_runtime_1.jsx)(WebGLContextManagerContext_1.WebglContextManagerContext.Provider, { value: webglContextManager, children: article.sections.map((section, i) => {
33
32
  const data = section.name ? sectionData[section.name] : {};
34
- return ((0, jsx_runtime_1.jsx)(Section_1.Section, { section: section, data: data, zIndex: sectionsLength - i, children: article.sections[i].items.map(item => ((0, jsx_runtime_1.jsx)(Item_1.Item, { item: item, sectionId: section.id, articleHeight: articleHeight }, item.id))) }, section.id));
35
- }) }), (0, jsx_runtime_1.jsx)("div", { id: "component-portal" })] }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
33
+ return ((0, jsx_runtime_1.jsx)(Section_1.Section, { articleHeight: articleHeight, section: section, data: data, zIndex: sectionsLength - i }, section.id));
34
+ }) }), (0, jsx_runtime_1.jsx)("div", { id: "component-portal" }), (0, jsx_runtime_1.jsx)("div", { id: "grid-component-lightbox-portal" })] }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
36
35
  .article {
37
36
  position: relative;
38
37
  overflow: clip;
@@ -15,18 +15,24 @@ const useLayoutContext_1 = require("../useLayoutContext");
15
15
  const SectionVideo_1 = require("./SectionVideo");
16
16
  const SectionImage_1 = require("./SectionImage");
17
17
  const checkOverflowClipSupport_1 = require("../../utils/checkOverflowClipSupport");
18
+ const StructuredContent_1 = require("../StructuredContent/StructuredContent");
19
+ const Item_1 = require("../items/Item");
18
20
  const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
19
- const Section = ({ section, data, children, zIndex }) => {
21
+ const Section = ({ section, data, zIndex, articleHeight }) => {
20
22
  var _a;
21
23
  const reactId = (0, react_1.useId)();
22
24
  const id = `${reactId}-section-${section.id}`;
23
25
  const sectionRef = (0, react_1.useRef)(null);
24
26
  const { layouts, customSections } = (0, useCntrlContext_1.useCntrlContext)();
25
27
  const layout = (0, useLayoutContext_1.useLayoutContext)();
26
- const layoutValues = [section.height, section.color, (_a = section.media) !== null && _a !== void 0 ? _a : {}];
28
+ const [sectionHeight, setSectionHeight] = (0, react_1.useState)(0);
29
+ const layoutValues = [
30
+ section.minHeight,
31
+ section.color,
32
+ (_a = section.media) !== null && _a !== void 0 ? _a : {}
33
+ ];
27
34
  const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
28
35
  (0, useSectionRegistry_1.useSectionRegistry)(section.id, sectionRef.current);
29
- const sectionHeight = layout && section.height[layout] ? section.height[layout] : undefined;
30
36
  const layoutMedia = layout && section.media && section.media[layout] ? section.media[layout] : undefined;
31
37
  const media = (0, react_1.useMemo)(() => {
32
38
  if (layoutMedia && !(0, checkOverflowClipSupport_1.isOverflowClipSupported)()) {
@@ -48,19 +54,31 @@ const Section = ({ section, data, children, zIndex }) => {
48
54
  }`;
49
55
  }, '');
50
56
  };
57
+ (0, react_1.useEffect)(() => {
58
+ if (!sectionRef.current)
59
+ return;
60
+ const observer = new ResizeObserver((entries) => {
61
+ const [entry] = entries;
62
+ const height = entry.contentRect.height;
63
+ setSectionHeight(height);
64
+ });
65
+ observer.observe(sectionRef.current);
66
+ return () => observer.disconnect();
67
+ }, []);
68
+ const children = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(StructuredContent_1.StructuredContent, { section: section }), section.items.map(item => ((0, jsx_runtime_1.jsx)(Item_1.Item, { sectionHeight: sectionHeight, item: item, sectionId: section.id, articleHeight: articleHeight }, item.id)))] }));
51
69
  if (SectionComponent)
52
70
  return (0, jsx_runtime_1.jsx)("div", { ref: sectionRef, children: (0, jsx_runtime_1.jsx)(SectionComponent, { data: data, children: children }) });
53
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: `section-${section.id}`, id: section.name, ref: sectionRef, style: { zIndex }, children: [media && media.size !== 'none' && sectionRef.current && ((0, jsx_runtime_1.jsx)("div", { className: `section-background-overlay-${section.id}`, children: (0, jsx_runtime_1.jsxs)("div", { className: `section-background-wrapper-${section.id}`, style: Object.assign({ transform: media.position === 'fixed' ? 'translateY(-100vh)' : 'unset' }, (sectionHeight && { height: media.position === 'fixed' ? `calc(${getSectionHeight(sectionHeight)} + 200vh)` : getSectionHeight(sectionHeight) })), children: [media.type === 'video' && ((0, jsx_runtime_1.jsx)(SectionVideo_1.SectionVideo, { container: sectionRef.current, sectionId: section.id, media: media })), media.type === 'image' && ((0, jsx_runtime_1.jsx)(SectionImage_1.SectionImage, { media: media, sectionId: section.id }))] }, `section-background-wrapper-${section.id}`) })), children] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
71
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: `section-${section.id}`, id: section.name, ref: sectionRef, style: { zIndex }, children: [media && media.size !== 'none' && sectionRef.current && ((0, jsx_runtime_1.jsx)("div", { className: `section-background-overlay-${section.id}`, children: (0, jsx_runtime_1.jsxs)("div", { className: `section-background-wrapper-${section.id}`, style: Object.assign({ transform: media.position === 'fixed' ? 'translateY(-100vh)' : 'unset' }, (sectionHeight && { height: media.position === 'fixed' ? `calc(${sectionHeight}px + 200vh)` : `${sectionHeight}px` })), children: [media.type === 'video' && ((0, jsx_runtime_1.jsx)(SectionVideo_1.SectionVideo, { container: sectionRef.current, sectionId: section.id, media: media })), media.type === 'image' && ((0, jsx_runtime_1.jsx)(SectionImage_1.SectionImage, { media: media, sectionId: section.id }))] }, `section-background-wrapper-${section.id}`) })), children] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
54
72
  ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([height, color, media]) => (`
55
73
  .section-${section.id} {
56
- height: ${getSectionHeight(height)};
74
+ min-height: ${getSectionHeight(height)};
57
75
  position: relative;
58
76
  background-color: ${color_1.CntrlColor.parse(color !== null && color !== void 0 ? color : DEFAULT_COLOR).fmt('rgba')};
59
77
  }
60
78
  .section-background-overlay-${section.id} {
61
- height: ${getSectionHeight(height)};
79
+ height: 100%;
62
80
  width: 100%;
63
- position: relative;
81
+ position: absolute;
64
82
  overflow: clip;
65
83
  }
66
84
  .section-background-wrapper-${section.id} {
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StructuredBlockItem = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const sdk_1 = require("@cntrl-site/sdk");
9
+ const react_1 = require("react");
10
+ const style_1 = __importDefault(require("styled-jsx/style"));
11
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
12
+ const useSizing_1 = require("../items/useSizing");
13
+ const StructuredComponent_1 = require("./StructuredComponent/StructuredComponent");
14
+ const noop = () => null;
15
+ const itemsMap = {
16
+ [sdk_1.StructuredBlockType.Component]: StructuredComponent_1.StructuredComponent,
17
+ [sdk_1.StructuredBlockType.RichText]: noop,
18
+ [sdk_1.StructuredBlockType.Image]: noop,
19
+ [sdk_1.StructuredBlockType.VimeoEmbed]: noop,
20
+ [sdk_1.StructuredBlockType.YoutubeEmbed]: noop,
21
+ };
22
+ const StructuredBlockItem = ({ block, maxWidthMap }) => {
23
+ var _a;
24
+ const reactId = (0, react_1.useId)();
25
+ const id = `${reactId}-item-${block.id}`;
26
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
27
+ const layoutValues = [block.area, block.layoutParams, (_a = block.hidden) !== null && _a !== void 0 ? _a : {}, maxWidthMap];
28
+ const ItemComponent = itemsMap[block.type] || noop;
29
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `structured-block-item-${block.id}`, children: [(0, jsx_runtime_1.jsx)(ItemComponent, { block: block }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
30
+ ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area, layoutParams, hidden, maxWidth]) => {
31
+ var _a, _b;
32
+ const sizingAxis = (0, useSizing_1.parseSizing)(layoutParams.sizing);
33
+ return (`
34
+ .structured-block-item-${block.id} {
35
+ display: ${hidden ? 'none' : 'block'};
36
+ align-self: ${getAlignSelf((_a = area.alignment) !== null && _a !== void 0 ? _a : 'center')};
37
+ width: ${sizingAxis.x === 'manual' && area.width ? `${area.width * 100}vw` : maxWidth !== null && maxWidth !== void 0 ? maxWidth : 'max-content'};
38
+ height: ${sizingAxis.y === 'manual' && area.height ? `${area.height * 100}vw` : 'unset'};
39
+ padding-top: ${area.paddingTop ? `${area.paddingTop * 100}vw` : 'unset'};
40
+ outline: none;
41
+ left: ${((_b = area.horizontalOffset) !== null && _b !== void 0 ? _b : 0) * 100}vw;
42
+ position: relative;
43
+ }
44
+ `);
45
+ })}
46
+ ` })] }));
47
+ };
48
+ exports.StructuredBlockItem = StructuredBlockItem;
49
+ function getAlignSelf(alignment) {
50
+ switch (alignment) {
51
+ case 'left':
52
+ return 'start';
53
+ case 'right':
54
+ return 'end';
55
+ default:
56
+ return 'center';
57
+ }
58
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StructuredComponent = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const style_1 = __importDefault(require("styled-jsx/style"));
9
+ const sdk_1 = require("@cntrl-site/sdk");
10
+ const react_1 = require("react");
11
+ const useCntrlContext_1 = require("../../../provider/useCntrlContext");
12
+ const useLayoutContext_1 = require("../../useLayoutContext");
13
+ const useItemGeometry_1 = require("../../../ItemGeometry/useItemGeometry");
14
+ const StructuredComponent = ({ block }) => {
15
+ var _a, _b;
16
+ const sdk = (0, useCntrlContext_1.useCntrlContext)();
17
+ const { layouts } = sdk;
18
+ const layout = (0, useLayoutContext_1.useLayoutContext)();
19
+ const fallbackLayout = (_a = layouts[0]) === null || _a === void 0 ? void 0 : _a.id;
20
+ const effectiveLayout = layout !== null && layout !== void 0 ? layout : fallbackLayout;
21
+ const layoutValues = [block.layoutParams];
22
+ const component = sdk.getComponent(block.commonParams.componentId);
23
+ const [ref, setRef] = (0, react_1.useState)(null);
24
+ (0, useItemGeometry_1.useItemGeometry)(block.id, ref);
25
+ const Element = component ? component.element : undefined;
26
+ const layoutParameters = effectiveLayout ? (_b = block.layoutParams[effectiveLayout]) === null || _b === void 0 ? void 0 : _b.parameters : undefined;
27
+ const commonParameters = block.commonParams.parameters;
28
+ const parameters = layoutParameters ? Object.assign(Object.assign({}, layoutParameters), { settings: Object.assign(Object.assign({}, layoutParameters.settings), commonParameters === null || commonParameters === void 0 ? void 0 : commonParameters.settings) }) : undefined;
29
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `custom-component-${block.id}`, ref: setRef, children: parameters && Element && ((0, jsx_runtime_1.jsx)(Element, Object.assign({ metadata: {
30
+ itemId: block.id,
31
+ submitUrl: sdk.getSubmitUrl(commonParameters === null || commonParameters === void 0 ? void 0 : commonParameters.pluginConfigId)
32
+ }, portalId: "component-portal", content: block.commonParams.content }, parameters))) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: block.id, children: `
33
+ .custom-component-${block.id} {
34
+ width: 100%;
35
+ height: 100%;
36
+ pointer-events: auto;
37
+ }
38
+ ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([layoutParams]) => {
39
+ return (`
40
+ .custom-component-${block.id} {
41
+ opacity: ${layoutParams.opacity};
42
+ filter: blur(${layoutParams.blur}vw);
43
+ ${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
44
+ }
45
+ `);
46
+ })}` })] }));
47
+ };
48
+ exports.StructuredComponent = StructuredComponent;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StructuredContent = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const sdk_1 = require("@cntrl-site/sdk");
9
+ const react_1 = require("react");
10
+ const style_1 = __importDefault(require("styled-jsx/style"));
11
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
12
+ const StructuredBlockItem_1 = require("../StructuredBlockItem/StructuredBlockItem");
13
+ const StructuredContent = ({ section }) => {
14
+ const reactId = (0, react_1.useId)();
15
+ const id = `${reactId}-structured-content-${section.id}`;
16
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
17
+ const structuredContentLength = section.structuredContent.length;
18
+ const defaultWidthRecord = section.type === 'content-based' ? section.structuredContentSettings.defaultWidth : {};
19
+ const layoutValues = [section.structuredContentSettings.paddingBottom, defaultWidthRecord];
20
+ if (structuredContentLength === 0)
21
+ return null;
22
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `structured-content-${section.id}`, children: [section.structuredContent.map(block => ((0, jsx_runtime_1.jsx)(StructuredBlockItem_1.StructuredBlockItem, { block: block, maxWidthMap: defaultWidthRecord }, block.id))), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
23
+ ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([paddingBottom, defaultWidth]) => {
24
+ return (`
25
+ .structured-content-${section.id} {
26
+ padding-bottom: ${paddingBottom * 100}vw;
27
+ max-width: ${defaultWidth < 1 ? `${defaultWidth * 100}vw` : 'unset'};
28
+ display: flex;
29
+ flex-direction: column;
30
+ margin: 0 auto;
31
+ width: 100%;
32
+ }
33
+ `);
34
+ })}
35
+ ` })] }));
36
+ };
37
+ exports.StructuredContent = StructuredContent;
@@ -34,7 +34,7 @@ const stickyFix = `
34
34
  transform: translate3d(0, 0, 0);
35
35
  `;
36
36
  const noop = () => null;
37
- const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false }) => {
37
+ const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false, sectionHeight = 0 }) => {
38
38
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
39
39
  const itemWrapperRef = (0, react_1.useRef)(null);
40
40
  const itemInnerRef = (0, react_1.useRef)(null);
@@ -69,7 +69,6 @@ const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGrou
69
69
  height: (_e = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.styles) === null || _e === void 0 ? void 0 : _e.height
70
70
  });
71
71
  const sectionHeightLayoutMap = (0, useSectionHeightMap_1.useSectionHeightData)(sectionId);
72
- const sectionHeight = layout && sectionHeightLayoutMap[layout] ? sectionHeightLayoutMap[layout] : '0';
73
72
  const stickyTop = (0, useStickyItemTop_1.useStickyItemTop)(item, sectionId, (_f = wrapperStateProps === null || wrapperStateProps === void 0 ? void 0 : wrapperStateProps.styles) === null || _f === void 0 ? void 0 : _f.top);
74
73
  const layoutValues = [item.area, item.hidden];
75
74
  layoutValues.push(item.sticky);
@@ -131,7 +130,7 @@ const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGrou
131
130
  (_a = interactionCtrl === null || interactionCtrl === void 0 ? void 0 : interactionCtrl.handleTransitionEnd) === null || _a === void 0 ? void 0 : _a.call(interactionCtrl, e.propertyName);
132
131
  }, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (top !== undefined ? { top: isScreenBasedBottom ? 'unset' : isContainItem ? (0, getItemTopStyle_1.getPercentageBasedTopStyle)(top, height, anchorSide) : (0, getItemTopStyle_1.getItemTopStyle)(top, anchorSide) } : {})), (left !== undefined ? { left: `${left * 100}vw` } : {})), (top !== undefined ? { bottom: isScreenBasedBottom ? `${-top * 100}vw` : 'unset' } : {})), (wrapperHeight !== undefined ? { height: `${wrapperHeight * 100}vw` } : {})), { transition: (_k = wrapperStateProps === null || wrapperStateProps === void 0 ? void 0 : wrapperStateProps.transition) !== null && _k !== void 0 ? _k : 'none' }), (blendMode && { mixBlendMode: blendMode })), children: [(0, jsx_runtime_1.jsx)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, style: {
133
132
  opacity: (keyframes.length !== 0 && !layout) ? 0 : 1,
134
- top: sticky ? (0, getAnchoredItemTop_1.getAnchoredItemTop)(stickyTop, sectionHeight, anchorSide) : 0,
133
+ top: sticky ? (0, getAnchoredItemTop_1.getAnchoredItemTop)(stickyTop, `${sectionHeight}px`, anchorSide) : 0,
135
134
  height: isRichText && itemHeight !== undefined ? `${itemHeight * 100}vw` : 'unset'
136
135
  }, children: (0, jsx_runtime_1.jsx)(RichTextWrapper_1.RichTextWrapper, { isRichText: isRichText, children: (0, jsx_runtime_1.jsx)("div", Object.assign({ className: `item-${item.id}-inner`, ref: itemInnerRef, style: Object.assign(Object.assign(Object.assign({ top: `${position.y}px`, left: `${position.x}px` }, ((width !== undefined && height !== undefined)
137
136
  ? {
@@ -78,7 +78,7 @@ class CntrlSdkContext {
78
78
  }
79
79
  setSectionsHeight(sections) {
80
80
  for (const section of sections) {
81
- this.sectionHeightMap.set(section.id, section.height);
81
+ this.sectionHeightMap.set(section.id, section.minHeight);
82
82
  }
83
83
  }
84
84
  getSectionHeightData(sectionId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "1.9.72",
3
+ "version": "1.9.74-alpha.0",
4
4
  "description": "SDK for Next.js",
5
5
  "author": "arsen@momdesign.nyc",
6
6
  "license": "MIT",
@@ -31,9 +31,9 @@
31
31
  "dependencies": {
32
32
  "@antfu/eslint-config": "^3.8.0",
33
33
  "@cntrl-site/color": "^1.0.0",
34
- "@cntrl-site/components": "^1.0.9",
34
+ "@cntrl-site/components": "^1.0.13-alpha.0",
35
35
  "@cntrl-site/effects": "^1.4.2",
36
- "@cntrl-site/sdk": "^1.27.2",
36
+ "@cntrl-site/sdk": "^1.28.0",
37
37
  "@types/vimeo__player": "^2.18.0",
38
38
  "@vimeo/player": "^2.25.0",
39
39
  "html-react-parser": "^3.0.1",
@@ -9,6 +9,7 @@ import { ArticleWrapper } from './ArticleWrapper';
9
9
  import { InteractionsProvider } from '../provider/InteractionsContext';
10
10
  import { WebglContextManagerContext } from '../provider/WebGLContextManagerContext';
11
11
  import { WebGLContextManager } from '@cntrl-site/effects';
12
+ import { StructuredContent } from './StructuredContent/StructuredContent';
12
13
 
13
14
  interface Props {
14
15
  article: TArticle;
@@ -41,24 +42,17 @@ export const Article: FC<Props> = ({ article, sectionData }) => {
41
42
  const data = section.name ? sectionData[section.name] : {};
42
43
  return (
43
44
  <Section
45
+ articleHeight={articleHeight}
44
46
  section={section}
45
47
  key={section.id}
46
48
  data={data}
47
49
  zIndex={sectionsLength - i}
48
- >
49
- {article.sections[i].items.map(item => (
50
- <Item
51
- item={item}
52
- key={item.id}
53
- sectionId={section.id}
54
- articleHeight={articleHeight}
55
- />
56
- ))}
57
- </Section>
50
+ />
58
51
  );
59
52
  })}
60
53
  </WebglContextManagerContext.Provider>
61
54
  <div id="component-portal" />
55
+ <div id="grid-component-lightbox-portal" />
62
56
  </div>
63
57
  </ArticleWrapper>
64
58
  <JSXStyle id={id}>{`
@@ -1,4 +1,4 @@
1
- import React, { FC, ReactElement, useId, useRef, useMemo } from 'react';
1
+ import React, { FC, ReactElement, useId, useRef, useMemo, useState, useEffect, PropsWithChildren } from 'react';
2
2
  import JSXStyle from 'styled-jsx/style';
3
3
  import {
4
4
  getLayoutMediaQuery,
@@ -14,27 +14,33 @@ import { useLayoutContext } from '../useLayoutContext';
14
14
  import { SectionVideo } from './SectionVideo';
15
15
  import { SectionImage } from './SectionImage';
16
16
  import { isOverflowClipSupported } from '../../utils/checkOverflowClipSupport';
17
+ import { StructuredContent } from '../StructuredContent/StructuredContent';
18
+ import { Item } from '../items/Item';
17
19
 
18
- type SectionChild = ReactElement<any, any>;
19
20
  const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
20
21
 
21
22
  interface Props {
22
23
  section: TSection;
23
- children: SectionChild[];
24
24
  zIndex: number;
25
25
  data?: any;
26
+ articleHeight: number;
26
27
  }
27
28
 
28
- export const Section: FC<Props> = ({ section, data, children, zIndex }) => {
29
+ export const Section: FC<PropsWithChildren<Props>> = ({ section, data, zIndex, articleHeight }) => {
29
30
  const reactId = useId();
30
31
  const id = `${reactId}-section-${section.id}`;
31
32
  const sectionRef = useRef<HTMLDivElement | null>(null);
32
33
  const { layouts, customSections } = useCntrlContext();
33
34
  const layout = useLayoutContext();
34
- const layoutValues: Record<string, any>[] = [section.height, section.color, section.media ?? {}];
35
+ const [sectionHeight, setSectionHeight] = useState(0);
36
+ const layoutValues: Record<string, any>[] = [
37
+ section.minHeight,
38
+ section.color,
39
+ section.media ?? {}
40
+ ];
41
+
35
42
  const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
36
43
  useSectionRegistry(section.id, sectionRef.current);
37
- const sectionHeight = layout && section.height[layout] ? section.height[layout] : undefined;
38
44
  const layoutMedia = layout && section.media && section.media[layout] ? section.media[layout] : undefined;
39
45
 
40
46
  const media = useMemo(() => {
@@ -62,6 +68,32 @@ export const Section: FC<Props> = ({ section, data, children, zIndex }) => {
62
68
  }, '');
63
69
  };
64
70
 
71
+ useEffect(() => {
72
+ if (!sectionRef.current) return;
73
+ const observer = new ResizeObserver((entries) => {
74
+ const [entry] = entries;
75
+ const height = entry.contentRect.height;
76
+ setSectionHeight(height);
77
+ });
78
+ observer.observe(sectionRef.current);
79
+ return () => observer.disconnect();
80
+ }, []);
81
+
82
+ const children = (
83
+ <>
84
+ <StructuredContent section={section} />
85
+ {section.items.map(item => (
86
+ <Item
87
+ sectionHeight={sectionHeight}
88
+ item={item}
89
+ key={item.id}
90
+ sectionId={section.id}
91
+ articleHeight={articleHeight}
92
+ />
93
+ ))}
94
+ </>
95
+ );
96
+
65
97
  if (SectionComponent) return <div ref={sectionRef}><SectionComponent data={data}>{children}</SectionComponent></div>;
66
98
 
67
99
  return (
@@ -79,7 +111,7 @@ export const Section: FC<Props> = ({ section, data, children, zIndex }) => {
79
111
  className={`section-background-wrapper-${section.id}`}
80
112
  style={{
81
113
  transform: media.position === 'fixed' ? 'translateY(-100vh)' : 'unset',
82
- ...(sectionHeight && { height: media.position === 'fixed' ? `calc(${getSectionHeight(sectionHeight)} + 200vh)` : getSectionHeight(sectionHeight) })
114
+ ...(sectionHeight && { height: media.position === 'fixed' ? `calc(${sectionHeight}px + 200vh)` : `${sectionHeight}px` })
83
115
  }}
84
116
  >
85
117
  {media.type === 'video' && (
@@ -97,14 +129,14 @@ export const Section: FC<Props> = ({ section, data, children, zIndex }) => {
97
129
  ${
98
130
  getLayoutStyles(layouts, layoutValues, ([height, color, media]) => (`
99
131
  .section-${section.id} {
100
- height: ${getSectionHeight(height)};
132
+ min-height: ${getSectionHeight(height)};
101
133
  position: relative;
102
134
  background-color: ${CntrlColor.parse(color ?? DEFAULT_COLOR).fmt('rgba')};
103
135
  }
104
136
  .section-background-overlay-${section.id} {
105
- height: ${getSectionHeight(height)};
137
+ height: 100%;
106
138
  width: 100%;
107
- position: relative;
139
+ position: absolute;
108
140
  overflow: clip;
109
141
  }
110
142
  .section-background-wrapper-${section.id} {
@@ -0,0 +1,69 @@
1
+ import { getLayoutStyles, StructuredBlockAny, StructuredBlockType } from '@cntrl-site/sdk';
2
+ import { ComponentType, FC, useId } from 'react';
3
+ import JSXStyle from 'styled-jsx/style';
4
+ import { useCntrlContext } from '../../provider/useCntrlContext';
5
+ import { parseSizing } from '../items/useSizing';
6
+ import { StructuredComponent } from './StructuredComponent/StructuredComponent';
7
+
8
+ export interface StructuredBlockItemProps<I extends StructuredBlockAny> {
9
+ block: I;
10
+ }
11
+
12
+ interface Props {
13
+ block: StructuredBlockAny;
14
+ maxWidthMap: Record<string, number>;
15
+ }
16
+
17
+ const noop = () => null;
18
+
19
+ const itemsMap: Record<StructuredBlockType, ComponentType<StructuredBlockItemProps<any>>> = {
20
+ [StructuredBlockType.Component]: StructuredComponent,
21
+ [StructuredBlockType.RichText]: noop,
22
+ [StructuredBlockType.Image]: noop,
23
+ [StructuredBlockType.VimeoEmbed]: noop,
24
+ [StructuredBlockType.YoutubeEmbed]: noop,
25
+ };
26
+
27
+ export const StructuredBlockItem: FC<Props> = ({ block, maxWidthMap }) => {
28
+ const reactId = useId();
29
+ const id = `${reactId}-item-${block.id}`;
30
+ const { layouts } = useCntrlContext();
31
+ const layoutValues: Record<string, any>[] = [block.area, block.layoutParams, block.hidden ?? {}, maxWidthMap];
32
+ const ItemComponent = itemsMap[block.type] || noop;
33
+ return (
34
+ <div
35
+ className={`structured-block-item-${block.id}`}
36
+ >
37
+ <ItemComponent block={block} />
38
+ <JSXStyle id={id}>{`
39
+ ${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, hidden, maxWidth]) => {
40
+ const sizingAxis = parseSizing(layoutParams.sizing);
41
+ return (`
42
+ .structured-block-item-${block.id} {
43
+ display: ${hidden ? 'none' : 'block'};
44
+ align-self: ${getAlignSelf(area.alignment ?? 'center')};
45
+ width: ${sizingAxis.x === 'manual' && area.width ? `${area.width * 100}vw` : maxWidth ?? 'max-content'};
46
+ height: ${sizingAxis.y === 'manual' && area.height ? `${area.height * 100}vw` : 'unset'};
47
+ padding-top: ${area.paddingTop ? `${area.paddingTop * 100}vw` : 'unset'};
48
+ outline: none;
49
+ left: ${(area.horizontalOffset ?? 0) * 100}vw;
50
+ position: relative;
51
+ }
52
+ `);
53
+ })}
54
+ `}
55
+ </JSXStyle>
56
+ </div>
57
+ );
58
+ };
59
+
60
+ function getAlignSelf(alignment: 'left' | 'center' | 'right') {
61
+ switch (alignment) {
62
+ case 'left':
63
+ return 'start';
64
+ case 'right':
65
+ return 'end';
66
+ default:
67
+ return 'center';
68
+ }
69
+ }
@@ -0,0 +1,66 @@
1
+ import JSXStyle from 'styled-jsx/style';
2
+ import { StructuredBlock, StructuredBlockType, getLayoutStyles } from '@cntrl-site/sdk';
3
+ import { FC, useState } from 'react';
4
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
5
+ import { useLayoutContext } from '../../useLayoutContext';
6
+ import { useItemGeometry } from '../../../ItemGeometry/useItemGeometry';
7
+
8
+ interface Props {
9
+ block: StructuredBlock<StructuredBlockType.Component>;
10
+ }
11
+
12
+ export const StructuredComponent: FC<Props> = ({ block }) => {
13
+ const sdk = useCntrlContext();
14
+ const { layouts } = sdk;
15
+ const layout = useLayoutContext();
16
+ const fallbackLayout = layouts[0]?.id;
17
+ const effectiveLayout = layout ?? fallbackLayout;
18
+ const layoutValues: Record<string, any>[] = [block.layoutParams];
19
+ const component = sdk.getComponent(block.commonParams.componentId);
20
+ const [ref, setRef] = useState<HTMLDivElement | null>(null);
21
+ useItemGeometry(block.id, ref);
22
+ const Element = component ? component.element : undefined;
23
+ const layoutParameters = effectiveLayout ? block.layoutParams[effectiveLayout]?.parameters : undefined;
24
+ const commonParameters = block.commonParams.parameters;
25
+ const parameters = layoutParameters ? {
26
+ ...layoutParameters,
27
+ settings: { ...layoutParameters.settings, ...commonParameters?.settings }
28
+ } : undefined;
29
+
30
+ return (
31
+ <>
32
+ <div
33
+ className={`custom-component-${block.id}`}
34
+ ref={setRef}
35
+ >
36
+ {parameters && Element && (
37
+ <Element
38
+ metadata={{
39
+ itemId: block.id,
40
+ submitUrl: sdk.getSubmitUrl(commonParameters?.pluginConfigId)
41
+ }}
42
+ portalId="component-portal"
43
+ content={block.commonParams.content}
44
+ {...parameters}
45
+ />
46
+ )}
47
+ </div>
48
+ <JSXStyle id={block.id}>{`
49
+ .custom-component-${block.id} {
50
+ width: 100%;
51
+ height: 100%;
52
+ pointer-events: auto;
53
+ }
54
+ ${getLayoutStyles(layouts, layoutValues, ([layoutParams]) => {
55
+ return (`
56
+ .custom-component-${block.id} {
57
+ opacity: ${layoutParams.opacity};
58
+ filter: blur(${layoutParams.blur}vw);
59
+ ${layoutParams.blur !== 0 ? 'will-change: transform;' : ''}
60
+ }
61
+ `);
62
+ })}`}
63
+ </JSXStyle>
64
+ </>
65
+ );
66
+ };
@@ -0,0 +1,42 @@
1
+ import { getLayoutStyles, Section } from '@cntrl-site/sdk';
2
+ import { FC, useId } from 'react';
3
+ import JSXStyle from 'styled-jsx/style';
4
+ import { useCntrlContext } from '../../provider/useCntrlContext';
5
+ import { StructuredBlockItem } from '../StructuredBlockItem/StructuredBlockItem';
6
+
7
+ interface Props {
8
+ section: Section;
9
+ }
10
+
11
+ export const StructuredContent: FC<Props> = ({ section }) => {
12
+ const reactId = useId();
13
+ const id = `${reactId}-structured-content-${section.id}`;
14
+ const { layouts } = useCntrlContext();
15
+ const structuredContentLength = section.structuredContent.length;
16
+ const defaultWidthRecord = section.type === 'content-based' ? section.structuredContentSettings.defaultWidth : {};
17
+ const layoutValues: Record<string, any>[] = [section.structuredContentSettings.paddingBottom, defaultWidthRecord];
18
+ if (structuredContentLength === 0) return null;
19
+ return (
20
+ <div className={`structured-content-${section.id}`}>
21
+ {section.structuredContent.map(block => (
22
+ <StructuredBlockItem block={block} key={block.id} maxWidthMap={defaultWidthRecord} />
23
+ ))}
24
+ <JSXStyle id={id}>
25
+ {`
26
+ ${getLayoutStyles(layouts, layoutValues, ([paddingBottom, defaultWidth]) => {
27
+ return (`
28
+ .structured-content-${section.id} {
29
+ padding-bottom: ${paddingBottom * 100}vw;
30
+ max-width: ${defaultWidth < 1 ? `${defaultWidth * 100}vw` : 'unset'};
31
+ display: flex;
32
+ flex-direction: column;
33
+ margin: 0 auto;
34
+ width: 100%;
35
+ }
36
+ `);
37
+ })}
38
+ `}
39
+ </JSXStyle>
40
+ </div>
41
+ );
42
+ };
@@ -52,6 +52,7 @@ export interface ItemWrapperProps {
52
52
  item: ItemAny;
53
53
  sectionId: string;
54
54
  articleHeight?: number;
55
+ sectionHeight?: number;
55
56
  isInGroup?: boolean;
56
57
  isParentVisible?: boolean;
57
58
  }
@@ -63,7 +64,7 @@ const stickyFix = `
63
64
 
64
65
  const noop = () => null;
65
66
 
66
- export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false }) => {
67
+ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false, sectionHeight = 0 }) => {
67
68
  const itemWrapperRef = useRef<HTMLDivElement | null>(null);
68
69
  const itemInnerRef = useRef<HTMLDivElement | null>(null);
69
70
  const rectObserver = useContext(ArticleRectContext);
@@ -100,7 +101,6 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
100
101
  height: innerStateProps?.styles?.height as number
101
102
  });
102
103
  const sectionHeightLayoutMap = useSectionHeightData(sectionId);
103
- const sectionHeight = layout && sectionHeightLayoutMap[layout] ? sectionHeightLayoutMap[layout] : '0';
104
104
  const stickyTop = useStickyItemTop(item, sectionId, wrapperStateProps?.styles?.top as number);
105
105
  const layoutValues: Record<string, any>[] = [item.area, item.hidden];
106
106
  layoutValues.push(item.sticky);
@@ -177,7 +177,7 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
177
177
  className={`item-${item.id}`}
178
178
  style={{
179
179
  opacity: (keyframes.length !== 0 && !layout) ? 0 : 1,
180
- top: sticky ? getAnchoredItemTop(stickyTop, sectionHeight, anchorSide) : 0,
180
+ top: sticky ? getAnchoredItemTop(stickyTop, `${sectionHeight}px`, anchorSide) : 0,
181
181
  height: isRichText && itemHeight !== undefined ? `${itemHeight * 100}vw` : 'unset'
182
182
  }}
183
183
  >
@@ -5,9 +5,10 @@ import {
5
5
  Interaction,
6
6
  InteractionItemTrigger,
7
7
  ItemAny,
8
+ InteractionItemScrollTrigger,
9
+ InteractionScrollTrigger,
8
10
  } from '@cntrl-site/sdk';
9
11
  import { isItemType } from '../utils/isItemType';
10
- import { InteractionItemScrollTrigger, InteractionScrollTrigger } from '@cntrl-site/sdk/lib/types/article/Interaction';
11
12
  import { ItemGeometryService } from '../ItemGeometry/ItemGeometryService';
12
13
 
13
14
  export class InteractionsRegistry implements InteractionsRegistryPort {
@@ -86,7 +86,7 @@ export class CntrlSdkContext {
86
86
 
87
87
  setSectionsHeight(sections: Section[]) {
88
88
  for (const section of sections) {
89
- this.sectionHeightMap.set(section.id, section.height);
89
+ this.sectionHeightMap.set(section.id, section.minHeight);
90
90
  }
91
91
  }
92
92