@cntrl-site/sdk-nextjs 0.12.9 → 0.13.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.
@@ -22,6 +22,8 @@ const useCurrentLayout_1 = require("../common/useCurrentLayout");
22
22
  const useItemScale_1 = require("./useItemScale");
23
23
  const ScaleAnchorMap_1 = require("../utils/ScaleAnchorMap");
24
24
  const useSectionHeightMap_1 = require("./useSectionHeightMap");
25
+ const HoverStyles_1 = require("../utils/HoverStyles/HoverStyles");
26
+ const getItemTopStyle_1 = require("../utils/getItemTopStyle");
25
27
  const itemsMap = {
26
28
  [sdk_1.ArticleItemType.Rectangle]: RectangleItem_1.RectangleItem,
27
29
  [sdk_1.ArticleItemType.Image]: ImageItem_1.ImageItem,
@@ -41,7 +43,7 @@ const Item = ({ item, sectionId }) => {
41
43
  const sectionHeight = (0, useSectionHeightMap_1.useSectionHeightData)(sectionId);
42
44
  const layout = (0, useCurrentLayout_1.useCurrentLayout)();
43
45
  const { width, height } = (0, useItemDimensions_1.useItemDimensions)(item, sectionId);
44
- const layoutValues = [item.area, item.hidden];
46
+ const layoutValues = [item.area, item.hidden, item.state.hover];
45
47
  const isInitialRef = (0, react_1.useRef)(true);
46
48
  layoutValues.push(item.sticky);
47
49
  layoutValues.push(sectionHeight);
@@ -72,11 +74,11 @@ const Item = ({ item, sectionId }) => {
72
74
  height: `${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${height * 100}vw` : 'unset'}`,
73
75
  };
74
76
  return ((0, jsx_runtime_1.jsxs)("div", { className: `item-wrapper-${item.id}`, style: { top, left, ...(wrapperHeight ? { height: `${wrapperHeight * 100}vw` } : {}) }, children: [(0, jsx_runtime_1.jsx)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, style: isInitialRef.current ? {} : styles, children: (0, jsx_runtime_1.jsx)(ItemComponent, { item: item, sectionId: sectionId, onResize: handleItemResize }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
75
- ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams]) => {
77
+ ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area, hidden, hoverParams, sticky, sectionHeight, layoutParams]) => {
76
78
  const sizingAxis = parseSizing(layoutParams.sizing);
77
79
  return (`
78
80
  .item-${item.id} {
79
- position: ${sticky ? 'sticky' : 'absolute'};xw
81
+ position: ${sticky ? 'sticky' : 'absolute'};
80
82
  width: ${sizingAxis.x === sdk_1.ArticleItemSizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
81
83
  height: ${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `w${area.height * 100}vw` : 'unset'};
82
84
  transform: scale(${scale});
@@ -84,7 +86,9 @@ const Item = ({ item, sectionId }) => {
84
86
  transform-origin: ${ScaleAnchorMap_1.ScaleAnchorMap[scaleAnchor]};
85
87
  pointer-events: auto;
86
88
  --webkit-backface-visibility: hidden;
89
+ cursor: ${hoverParams ? 'pointer' : 'default'};
87
90
  visibility: ${hidden ? 'hidden' : 'visible'};
91
+ transition: ${(0, HoverStyles_1.getTransitions)(['width', 'height', 'scale'], hoverParams)};
88
92
  }
89
93
  .item-wrapper-${item.id} {
90
94
  position: absolute;
@@ -92,9 +96,16 @@ const Item = ({ item, sectionId }) => {
92
96
  -webkit-transform: translate3d(0, 0, 0);
93
97
  transform: translate3d(0, 0, 0);
94
98
  pointer-events: none;
95
- top: ${(0, useItemPosition_1.getItemTopStyle)(area.top, area.anchorSide)};
99
+ top: ${(0, getItemTopStyle_1.getItemTopStyle)(area.top, area.anchorSide)};
96
100
  left: ${area.left * 100}vw;
97
101
  height: ${sticky ? `${getStickyItemWrapperHeight(sticky, area.height) * 100}vw` : 'unset'};
102
+ transition: ${(0, HoverStyles_1.getTransitions)(['left', 'top'], hoverParams)};
103
+ }
104
+ .item-${item.id}:hover {
105
+ ${(0, HoverStyles_1.getHoverStyles)(['width', 'height', 'scale'], hoverParams)}
106
+ }
107
+ .item-wrapper-${item.id}:hover {
108
+ ${(0, HoverStyles_1.getHoverStyles)(['left', 'top'], hoverParams, area.anchorSide)}
98
109
  }
99
110
  `);
100
111
  })}
@@ -1,12 +1,29 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.CustomItem = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const sdk_1 = require("@cntrl-site/sdk");
4
9
  const useCntrlContext_1 = require("../../provider/useCntrlContext");
10
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
11
+ const style_1 = __importDefault(require("styled-jsx/style"));
5
12
  const CustomItem = ({ item }) => {
6
13
  const sdk = (0, useCntrlContext_1.useCntrlContext)();
14
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
7
15
  const component = sdk.customItems.get(item.commonParams.name);
8
16
  if (!component)
9
17
  return null;
10
- return component({});
18
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `custom-component-${item.id}`, children: component({}) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: item.id, children: `${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
19
+ return (`
20
+ .custom-component-${item.id} {
21
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle'], hoverParams)};
22
+ }
23
+ .custom-component-${item.id}:hover {
24
+ ${(0, HoverStyles_1.getHoverStyles)(['angle'], hoverParams)}
25
+ }
26
+ `);
27
+ })}` })] }));
11
28
  };
12
29
  exports.CustomItem = CustomItem;
@@ -11,8 +11,11 @@ const sdk_1 = require("@cntrl-site/sdk");
11
11
  const LinkWrapper_1 = require("../LinkWrapper");
12
12
  const useFileItem_1 = require("./useFileItem");
13
13
  const useItemAngle_1 = require("../useItemAngle");
14
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
15
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
14
16
  const ImageItem = ({ item, sectionId }) => {
15
17
  const id = (0, react_1.useId)();
18
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
16
19
  const { radius, strokeWidth, opacity, strokeColor } = (0, useFileItem_1.useFileItem)(item, sectionId);
17
20
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
18
21
  const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor), [strokeColor]);
@@ -44,6 +47,16 @@ const ImageItem = ({ item, sectionId }) => {
44
47
  object-fit: cover;
45
48
  pointer-events: none;
46
49
  }
50
+ ${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
51
+ return (`
52
+ .image-wrapper-${item.id} {
53
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)};
54
+ }
55
+ .image-wrapper-${item.id}:hover {
56
+ ${(0, HoverStyles_1.getHoverStyles)(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)}
57
+ }
58
+ `);
59
+ })}
47
60
  ` })] }) }));
48
61
  };
49
62
  exports.ImageItem = ImageItem;
@@ -11,8 +11,11 @@ const sdk_1 = require("@cntrl-site/sdk");
11
11
  const LinkWrapper_1 = require("../LinkWrapper");
12
12
  const useRectangleItem_1 = require("./useRectangleItem");
13
13
  const useItemAngle_1 = require("../useItemAngle");
14
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
15
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
14
16
  const RectangleItem = ({ item, sectionId }) => {
15
17
  const id = (0, react_1.useId)();
18
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
16
19
  const { fillColor, radius, strokeWidth, strokeColor } = (0, useRectangleItem_1.useRectangleItem)(item, sectionId);
17
20
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
18
21
  const backgroundColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(fillColor), [fillColor]);
@@ -37,6 +40,16 @@ const RectangleItem = ({ item, sectionId }) => {
37
40
  border-style: solid;
38
41
  box-sizing: border-box;
39
42
  }
43
+ ${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
44
+ return (`
45
+ .rectangle-${item.id} {
46
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor'], hoverParams)};
47
+ }
48
+ .rectangle-${item.id}:hover {
49
+ ${(0, HoverStyles_1.getHoverStyles)(['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor'], hoverParams)}
50
+ }
51
+ `);
52
+ })}
40
53
  ` })] }) }));
41
54
  };
42
55
  exports.RectangleItem = RectangleItem;
@@ -6,13 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RichTextItem = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
+ const sdk_1 = require("@cntrl-site/sdk");
9
10
  const style_1 = __importDefault(require("styled-jsx/style"));
10
11
  const useRichTextItem_1 = require("./useRichTextItem");
11
12
  const useItemAngle_1 = require("../useItemAngle");
13
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
14
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
12
15
  const RichTextItem = ({ item, sectionId, onResize }) => {
13
16
  const [content, styles, preset] = (0, useRichTextItem_1.useRichTextItem)(item);
17
+ const id = (0, react_1.useId)();
14
18
  const [ref, setRef] = (0, react_1.useState)(null);
15
19
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
20
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
16
21
  const className = preset ? `cntrl-preset-${preset.id}` : undefined;
17
22
  (0, react_1.useEffect)(() => {
18
23
  if (!ref || !onResize)
@@ -26,8 +31,17 @@ const RichTextItem = ({ item, sectionId, onResize }) => {
26
31
  observer.unobserve(ref);
27
32
  };
28
33
  }, [ref, onResize]);
29
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: setRef, className: className, style: {
34
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: setRef, className: `${className} rich-text-wrapper-${item.id}`, style: {
30
35
  transform: `rotate(${angle}deg)`
31
- }, children: content }), (0, jsx_runtime_1.jsx)(style_1.default, { id: item.id, children: styles })] }));
36
+ }, children: content }), (0, jsx_runtime_1.jsxs)(style_1.default, { id: id, children: [styles, `${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
37
+ return (`
38
+ .rich-text-wrapper-${item.id} {
39
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle'], hoverParams)};
40
+ }
41
+ .rich-text-wrapper-${item.id}:hover {
42
+ ${(0, HoverStyles_1.getHoverStyles)(['angle'], hoverParams)}
43
+ }
44
+ `);
45
+ })}`] })] }));
32
46
  };
33
47
  exports.RichTextItem = RichTextItem;
@@ -11,8 +11,11 @@ const sdk_1 = require("@cntrl-site/sdk");
11
11
  const LinkWrapper_1 = require("../LinkWrapper");
12
12
  const useFileItem_1 = require("./useFileItem");
13
13
  const useItemAngle_1 = require("../useItemAngle");
14
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
15
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
14
16
  const VideoItem = ({ item, sectionId }) => {
15
17
  const id = (0, react_1.useId)();
18
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
16
19
  const { radius, strokeWidth, strokeColor, opacity } = (0, useFileItem_1.useFileItem)(item, sectionId);
17
20
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
18
21
  const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor), [strokeColor]);
@@ -45,6 +48,16 @@ const VideoItem = ({ item, sectionId }) => {
45
48
  object-fit: cover;
46
49
  pointer-events: none;
47
50
  }
51
+ ${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
52
+ return (`
53
+ .video-wrapper-${item.id} {
54
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)};
55
+ }
56
+ .video-wrapper-${item.id}:hover {
57
+ ${(0, HoverStyles_1.getHoverStyles)(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)}
58
+ }
59
+ `);
60
+ })}
48
61
  ` })] }));
49
62
  };
50
63
  exports.VideoItem = VideoItem;
@@ -6,19 +6,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.VimeoEmbedItem = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
+ const player_1 = __importDefault(require("@vimeo/player"));
9
10
  const style_1 = __importDefault(require("styled-jsx/style"));
10
11
  const LinkWrapper_1 = require("../LinkWrapper");
11
12
  const useEmbedVideoItem_1 = require("./useEmbedVideoItem");
12
13
  const useItemAngle_1 = require("../useItemAngle");
14
+ const sdk_1 = require("@cntrl-site/sdk");
15
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
16
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
17
+ const useCurrentLayout_1 = require("../../common/useCurrentLayout");
13
18
  const VimeoEmbedItem = ({ item, sectionId }) => {
14
19
  const id = (0, react_1.useId)();
20
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
21
+ const layout = (0, useCurrentLayout_1.useCurrentLayout)();
15
22
  const { radius } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item, sectionId);
23
+ const [iframeRef, setIframeRef] = (0, react_1.useState)(null);
24
+ const vimeoPlayer = (0, react_1.useMemo)(() => iframeRef ? new player_1.default(iframeRef) : undefined, [iframeRef]);
25
+ const isAutoPlayOnHover = (0, react_1.useMemo)(() => {
26
+ const layoutHoverStates = item.state.hover[layout];
27
+ if (!layoutHoverStates)
28
+ return false;
29
+ return layoutHoverStates.autoplay === true;
30
+ }, [layout, item]);
16
31
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
17
32
  const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
18
33
  const getValidVimeoUrl = (url) => {
19
34
  const validURL = new URL(url);
20
35
  validURL.searchParams.append('controls', String(controls));
21
- validURL.searchParams.append('autoplay', !controls ? 'true' : String(autoplay));
36
+ validURL.searchParams.append('autoplay', String(autoplay));
22
37
  validURL.searchParams.append('muted', String(muted));
23
38
  validURL.searchParams.append('loop', String(loop));
24
39
  validURL.searchParams.append('pip', String(pictureInPicture));
@@ -32,19 +47,37 @@ const VimeoEmbedItem = ({ item, sectionId }) => {
32
47
  return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: [(0, jsx_runtime_1.jsx)("div", { className: `embed-video-wrapper-${item.id}`, style: {
33
48
  borderRadius: `${radius * 100}vw`,
34
49
  transform: `rotate(${angle}deg)`
35
- }, children: (0, jsx_runtime_1.jsx)("iframe", { className: "embedVideo", src: validUrl || '', allow: "autoplay; fullscreen; picture-in-picture;", allowFullScreen: true }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
36
- .embed-video-wrapper-${item.id} {
37
- position: absolute;
38
- overflow: hidden;
39
- width: 100%;
40
- height: 100%;
41
- }
42
- .embedVideo {
43
- width: 100%;
44
- height: 100%;
45
- z-index: 1;
46
- border: none;
47
- }
48
- ` })] }));
50
+ }, onMouseEnter: () => {
51
+ if (!vimeoPlayer || !isAutoPlayOnHover)
52
+ return;
53
+ vimeoPlayer.play();
54
+ }, onMouseLeave: () => {
55
+ if (!vimeoPlayer || !isAutoPlayOnHover)
56
+ return;
57
+ vimeoPlayer.pause();
58
+ }, children: (0, jsx_runtime_1.jsx)("iframe", { ref: setIframeRef, className: "embedVideo", src: validUrl || '', allow: "autoplay; fullscreen; picture-in-picture;", allowFullScreen: true }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
59
+ .embed-video-wrapper-${item.id} {
60
+ position: absolute;
61
+ overflow: hidden;
62
+ width: 100%;
63
+ height: 100%;
64
+ }
65
+ .embedVideo {
66
+ width: 100%;
67
+ height: 100%;
68
+ z-index: 1;
69
+ border: none;
70
+ }
71
+ ${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
72
+ return (`
73
+ .embed-video-wrapper-${item.id} {
74
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle', 'radius'], hoverParams)};
75
+ }
76
+ .embed-video-wrapper-${item.id}:hover {
77
+ ${(0, HoverStyles_1.getHoverStyles)(['angle', 'radius'], hoverParams)}
78
+ }
79
+ `);
80
+ })}
81
+ ` })] }));
49
82
  };
50
83
  exports.VimeoEmbedItem = VimeoEmbedItem;
@@ -11,8 +11,12 @@ const LinkWrapper_1 = require("../LinkWrapper");
11
11
  const getValidYoutubeUrl_1 = require("../../utils/getValidYoutubeUrl");
12
12
  const useEmbedVideoItem_1 = require("./useEmbedVideoItem");
13
13
  const useItemAngle_1 = require("../useItemAngle");
14
+ const sdk_1 = require("@cntrl-site/sdk");
15
+ const HoverStyles_1 = require("../../utils/HoverStyles/HoverStyles");
16
+ const useCntrlContext_1 = require("../../provider/useCntrlContext");
14
17
  const YoutubeEmbedItem = ({ item, sectionId }) => {
15
18
  const id = (0, react_1.useId)();
19
+ const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
16
20
  const { autoplay, controls, url } = item.commonParams;
17
21
  const { radius } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item, sectionId);
18
22
  const angle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
@@ -21,7 +25,7 @@ const YoutubeEmbedItem = ({ item, sectionId }) => {
21
25
  const id = (0, getValidYoutubeUrl_1.getYoutubeId)(newUrl);
22
26
  const validUrl = new URL(`https://www.youtube.com/embed/${id}`);
23
27
  validUrl.searchParams.append('controls', `${Number(controls)}`);
24
- validUrl.searchParams.append('autoplay', !controls ? 'true' : `${Number(autoplay)}`);
28
+ validUrl.searchParams.append('autoplay', `${Number(autoplay)}`);
25
29
  validUrl.searchParams.append('mute', `${Number(autoplay)}`);
26
30
  return validUrl.href;
27
31
  };
@@ -42,6 +46,16 @@ const YoutubeEmbedItem = ({ item, sectionId }) => {
42
46
  z-index: 1;
43
47
  border: none;
44
48
  }
49
+ ${(0, sdk_1.getLayoutStyles)(layouts, [item.state.hover], ([hoverParams]) => {
50
+ return (`
51
+ .embed-youtube-video-wrapper-${item.id} {
52
+ transition: ${(0, HoverStyles_1.getTransitions)(['angle', 'radius'], hoverParams)};
53
+ }
54
+ .embed-youtube-video-wrapper-${item.id}:hover {
55
+ ${(0, HoverStyles_1.getHoverStyles)(['angle', 'radius'], hoverParams)}
56
+ }
57
+ `);
58
+ })}
45
59
  ` })] }));
46
60
  };
47
61
  exports.YoutubeEmbedItem = YoutubeEmbedItem;
@@ -1,29 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getItemTopStyle = exports.useItemPosition = void 0;
4
- const sdk_1 = require("@cntrl-site/sdk");
3
+ exports.useItemPosition = void 0;
5
4
  const useKeyframeValue_1 = require("../common/useKeyframeValue");
6
5
  const useCurrentLayout_1 = require("../common/useCurrentLayout");
6
+ const getItemTopStyle_1 = require("../utils/getItemTopStyle");
7
7
  const useItemPosition = (item, sectionId) => {
8
8
  const layoutId = (0, useCurrentLayout_1.useCurrentLayout)();
9
9
  const { top, left } = (0, useKeyframeValue_1.useKeyframeValue)(item, (item, layoutId) => item.area[layoutId], (animator, scroll, value) => animator.getPositions(value, scroll), sectionId, [layoutId]);
10
10
  return {
11
- top: getItemTopStyle(top, item.area[layoutId].anchorSide),
11
+ top: (0, getItemTopStyle_1.getItemTopStyle)(top, item.area[layoutId].anchorSide),
12
12
  left: `${left * 100}vw`
13
13
  };
14
14
  };
15
15
  exports.useItemPosition = useItemPosition;
16
- function getItemTopStyle(top, anchorSide) {
17
- const defaultValue = `${top * 100}vw`;
18
- if (!anchorSide)
19
- return defaultValue;
20
- switch (anchorSide) {
21
- case sdk_1.AnchorSide.Top:
22
- return defaultValue;
23
- case sdk_1.AnchorSide.Center:
24
- return `calc(50% + ${top * 100}vw)`;
25
- case sdk_1.AnchorSide.Bottom:
26
- return `calc(100% + ${top * 100}vw)`;
27
- }
28
- }
29
- exports.getItemTopStyle = getItemTopStyle;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getHoverStyles = exports.getTransitions = void 0;
4
+ const sdk_1 = require("@cntrl-site/sdk");
5
+ const getItemTopStyle_1 = require("../getItemTopStyle");
6
+ const hoverTransformationMap = {
7
+ 'width': (width) => `width: ${width * 100}vw !important;`,
8
+ 'height': (height) => `height: ${height * 100}vw !important;`,
9
+ 'top': (top, anchorSide) => `top: ${(0, getItemTopStyle_1.getItemTopStyle)(top, anchorSide)} !important;`,
10
+ 'left': (left) => `left: ${left * 100}vw !important;`,
11
+ 'scale': (scale) => `transform: scale(${scale}) !important;`,
12
+ 'angle': (angle) => `transform: rotate(${angle}deg) !important;`,
13
+ 'opacity': (opacity) => `opacity: ${opacity} !important;`,
14
+ 'radius': (radius) => `border-radius: ${radius * 100}vw !important;`,
15
+ 'strokeWidth': (strokeWidth) => `border-width: ${strokeWidth * 100}vw !important;`,
16
+ 'strokeColor': (strokeColor) => `border-color: ${sdk_1.CntrlColor.parse(strokeColor).toCss()} !important;`,
17
+ 'fillColor': (fillColor) => `background-color: ${sdk_1.CntrlColor.parse(fillColor).toCss()} !important;`,
18
+ };
19
+ const CSSPropertyNameMap = {
20
+ 'width': 'width',
21
+ 'height': 'height',
22
+ 'top': 'top',
23
+ 'left': 'left',
24
+ 'scale': 'transform',
25
+ 'angle': 'transform',
26
+ 'opacity': 'opacity',
27
+ 'radius': 'border-radius',
28
+ 'strokeWidth': 'border-width',
29
+ 'strokeColor': 'border-color',
30
+ 'fillColor': 'background-color'
31
+ };
32
+ function getTransitions(values, hover) {
33
+ if (!hover)
34
+ return 'unset';
35
+ const transitionValues = values.reduce((acc, valueName) => {
36
+ if (valueName in hover && hover[valueName] !== undefined) {
37
+ const hoverProperties = hover[valueName];
38
+ return [
39
+ ...acc,
40
+ `${CSSPropertyNameMap[valueName]} ${hoverProperties.duration}ms ${hoverProperties.timing} ${hoverProperties.delay}ms`
41
+ ];
42
+ }
43
+ return acc;
44
+ }, []);
45
+ if (!transitionValues.length)
46
+ return 'unset';
47
+ return transitionValues.join(', ');
48
+ }
49
+ exports.getTransitions = getTransitions;
50
+ function getHoverStyles(values, hover, anchorSide) {
51
+ if (!hover)
52
+ return '';
53
+ const hoverValues = values.reduce((acc, valueName) => {
54
+ if (valueName in hover && hover[valueName] !== undefined) {
55
+ const hoverProperties = hover[valueName];
56
+ return [
57
+ ...acc,
58
+ hoverTransformationMap[valueName](hoverProperties.value, anchorSide)
59
+ ];
60
+ }
61
+ return acc;
62
+ }, []);
63
+ if (!hoverValues.length)
64
+ return '';
65
+ return hoverValues.join('\n');
66
+ }
67
+ exports.getHoverStyles = getHoverStyles;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getItemTopStyle = void 0;
4
+ const sdk_1 = require("@cntrl-site/sdk");
5
+ function getItemTopStyle(top, anchorSide) {
6
+ const defaultValue = `${top * 100}vw`;
7
+ if (!anchorSide)
8
+ return defaultValue;
9
+ switch (anchorSide) {
10
+ case sdk_1.AnchorSide.Top:
11
+ return defaultValue;
12
+ case sdk_1.AnchorSide.Center:
13
+ return `calc(50% + ${top * 100}vw)`;
14
+ case sdk_1.AnchorSide.Bottom:
15
+ return `calc(100% + ${top * 100}vw)`;
16
+ }
17
+ }
18
+ exports.getItemTopStyle = getItemTopStyle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "0.12.9",
3
+ "version": "0.13.0",
4
4
  "description": "SDK for Next.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/index.ts",
@@ -21,7 +21,8 @@
21
21
  },
22
22
  "homepage": "https://github.com/cntrl-site/sdk-nextjs#readme",
23
23
  "dependencies": {
24
- "@cntrl-site/sdk": "^1.1.5",
24
+ "@cntrl-site/sdk": "^1.1.6",
25
+ "@vimeo/player": "^2.20.1",
25
26
  "html-react-parser": "^3.0.1",
26
27
  "styled-jsx": "^5.0.2"
27
28
  },
@@ -38,6 +39,7 @@
38
39
  "@types/jest": "^29.2.5",
39
40
  "@types/node": "^18.11.7",
40
41
  "@types/react": "^18.0.15",
42
+ "@types/vimeo__player": "^2.18.0",
41
43
  "jest": "^29.3.1",
42
44
  "ts-jest": "^29.0.3",
43
45
  "typescript": "^4.9.5"
@@ -18,12 +18,14 @@ import { VimeoEmbedItem } from './items/VimeoEmbed';
18
18
  import { YoutubeEmbedItem } from './items/YoutubeEmbed';
19
19
  import { CustomItem } from './items/CustomItem';
20
20
  import { useCntrlContext } from '../provider/useCntrlContext';
21
- import { getItemTopStyle, useItemPosition } from './useItemPosition';
21
+ import { useItemPosition } from './useItemPosition';
22
22
  import { useItemDimensions } from './useItemDimensions';
23
23
  import { useCurrentLayout } from '../common/useCurrentLayout';
24
24
  import { useItemScale } from './useItemScale';
25
25
  import { ScaleAnchorMap } from '../utils/ScaleAnchorMap';
26
26
  import { useSectionHeightData } from './useSectionHeightMap';
27
+ import { getHoverStyles, getTransitions } from '../utils/HoverStyles/HoverStyles';
28
+ import { getItemTopStyle } from '../utils/getItemTopStyle';
27
29
 
28
30
  export interface ItemProps<I extends TArticleItemAny> {
29
31
  item: I;
@@ -52,7 +54,7 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, sectionId}) => {
52
54
  const sectionHeight = useSectionHeightData(sectionId);
53
55
  const layout = useCurrentLayout();
54
56
  const { width, height } = useItemDimensions(item, sectionId);
55
- const layoutValues: Record<string, any>[] = [item.area, item.hidden];
57
+ const layoutValues: Record<string, any>[] = [item.area, item.hidden, item.state.hover];
56
58
  const isInitialRef = useRef(true);
57
59
  layoutValues.push(item.sticky);
58
60
  layoutValues.push(sectionHeight);
@@ -100,12 +102,11 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, sectionId}) => {
100
102
  <ItemComponent item={item} sectionId={sectionId} onResize={handleItemResize} />
101
103
  </div>
102
104
  <JSXStyle id={id}>{`
103
- ${getLayoutStyles(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams]) => {
105
+ ${getLayoutStyles(layouts, layoutValues, ([area, hidden, hoverParams, sticky, sectionHeight, layoutParams]) => {
104
106
  const sizingAxis = parseSizing(layoutParams.sizing);
105
-
106
107
  return (`
107
108
  .item-${item.id} {
108
- position: ${sticky ? 'sticky' : 'absolute'};xw
109
+ position: ${sticky ? 'sticky' : 'absolute'};
109
110
  width: ${sizingAxis.x === SizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
110
111
  height: ${sizingAxis.y === SizingType.Manual ? `w${area.height * 100}vw` : 'unset'};
111
112
  transform: scale(${scale});
@@ -113,7 +114,9 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, sectionId}) => {
113
114
  transform-origin: ${ScaleAnchorMap[scaleAnchor]};
114
115
  pointer-events: auto;
115
116
  --webkit-backface-visibility: hidden;
117
+ cursor: ${hoverParams ? 'pointer' : 'default'};
116
118
  visibility: ${hidden ? 'hidden' : 'visible'};
119
+ transition: ${getTransitions(['width', 'height', 'scale'], hoverParams)};
117
120
  }
118
121
  .item-wrapper-${item.id} {
119
122
  position: absolute;
@@ -124,6 +127,13 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, sectionId}) => {
124
127
  top: ${getItemTopStyle(area.top, area.anchorSide)};
125
128
  left: ${area.left * 100}vw;
126
129
  height: ${sticky ? `${getStickyItemWrapperHeight(sticky, area.height) * 100}vw` : 'unset'};
130
+ transition: ${getTransitions(['left', 'top'], hoverParams)};
131
+ }
132
+ .item-${item.id}:hover {
133
+ ${getHoverStyles(['width', 'height', 'scale'], hoverParams)}
134
+ }
135
+ .item-wrapper-${item.id}:hover {
136
+ ${getHoverStyles(['left', 'top'], hoverParams, area.anchorSide)}
127
137
  }
128
138
  `);
129
139
  })}
@@ -1,11 +1,29 @@
1
- import { TCustomItem } from '@cntrl-site/sdk';
1
+ import { ArticleItemType, getLayoutStyles, TCustomItem } from '@cntrl-site/sdk';
2
2
  import { FC } from 'react';
3
3
  import { useCntrlContext } from '../../provider/useCntrlContext';
4
4
  import { ItemProps } from '../Item';
5
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
6
+ import JSXStyle from 'styled-jsx/style';
5
7
 
6
8
  export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item }) => {
7
9
  const sdk = useCntrlContext();
10
+ const { layouts } = useCntrlContext();
8
11
  const component = sdk.customItems.get(item.commonParams.name);
9
12
  if (!component) return null;
10
- return component({});
13
+ return (
14
+ <>
15
+ <div className={`custom-component-${item.id}`}>{component({})}</div>
16
+ <JSXStyle id={item.id}>
17
+ {`${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
18
+ return (`
19
+ .custom-component-${item.id} {
20
+ transition: ${getTransitions<ArticleItemType.Custom>(['angle'], hoverParams)};
21
+ }
22
+ .custom-component-${item.id}:hover {
23
+ ${getHoverStyles<ArticleItemType.Custom>(['angle'], hoverParams)}
24
+ }
25
+ `);
26
+ })}`}
27
+ </JSXStyle>
28
+ </>);
11
29
  };
@@ -1,20 +1,24 @@
1
1
  import { FC, useId, useMemo } from 'react';
2
2
  import JSXStyle from 'styled-jsx/style';
3
- import { CntrlColor, TImageItem } from '@cntrl-site/sdk';
3
+ import { ArticleItemType, CntrlColor, getLayoutStyles, TImageItem } from '@cntrl-site/sdk';
4
4
  import { ItemProps } from '../Item';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
6
  import { useFileItem } from './useFileItem';
7
7
  import { useItemAngle } from '../useItemAngle';
8
+ import { useCntrlContext } from '../../provider/useCntrlContext';
9
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
8
10
 
9
11
  export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId }) => {
10
12
  const id = useId();
13
+ const { layouts } = useCntrlContext();
11
14
  const { radius, strokeWidth, opacity, strokeColor } = useFileItem(item, sectionId);
12
15
  const angle = useItemAngle(item, sectionId);
13
16
  const borderColor = useMemo(() => CntrlColor.parse(strokeColor), [strokeColor]);
14
17
  return (
15
18
  <LinkWrapper url={item.link?.url}>
16
19
  <>
17
- <div className={`image-wrapper-${item.id}`}
20
+ <div
21
+ className={`image-wrapper-${item.id}`}
18
22
  style={{
19
23
  borderRadius: `${radius * 100}vw`,
20
24
  borderWidth: `${strokeWidth * 100}vw`,
@@ -47,6 +51,16 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId }) => {
47
51
  object-fit: cover;
48
52
  pointer-events: none;
49
53
  }
54
+ ${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
55
+ return (`
56
+ .image-wrapper-${item.id} {
57
+ transition: ${getTransitions<ArticleItemType.Image>(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)};
58
+ }
59
+ .image-wrapper-${item.id}:hover {
60
+ ${getHoverStyles<ArticleItemType.Image>(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)}
61
+ }
62
+ `);
63
+ })}
50
64
  `}</JSXStyle>
51
65
  </>
52
66
  </LinkWrapper>
@@ -1,13 +1,16 @@
1
1
  import { FC, useId, useMemo } from 'react';
2
2
  import JSXStyle from 'styled-jsx/style';
3
- import { TRectangleItem, CntrlColor } from '@cntrl-site/sdk';
3
+ import { TRectangleItem, CntrlColor, getLayoutStyles, ArticleItemType } from '@cntrl-site/sdk';
4
4
  import { ItemProps } from '../Item';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
6
  import { useRectangleItem } from './useRectangleItem';
7
7
  import { useItemAngle } from '../useItemAngle';
8
+ import { useCntrlContext } from '../../provider/useCntrlContext';
9
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
8
10
 
9
11
  export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId }) => {
10
12
  const id = useId();
13
+ const { layouts } = useCntrlContext();
11
14
  const { fillColor, radius, strokeWidth, strokeColor } = useRectangleItem(item, sectionId);
12
15
  const angle = useItemAngle(item, sectionId);
13
16
  const backgroundColor = useMemo(() => CntrlColor.parse(fillColor), [fillColor]);
@@ -39,6 +42,16 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId }
39
42
  border-style: solid;
40
43
  box-sizing: border-box;
41
44
  }
45
+ ${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
46
+ return (`
47
+ .rectangle-${item.id} {
48
+ transition: ${getTransitions<ArticleItemType.Rectangle>(['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor'], hoverParams)};
49
+ }
50
+ .rectangle-${item.id}:hover {
51
+ ${getHoverStyles<ArticleItemType.Rectangle>(['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor'], hoverParams)}
52
+ }
53
+ `);
54
+ })}
42
55
  `}</JSXStyle>
43
56
  </>
44
57
  </LinkWrapper>
@@ -1,14 +1,18 @@
1
- import { FC, useEffect, useState } from 'react';
2
- import { TRichTextItem } from '@cntrl-site/sdk';
1
+ import { FC, useEffect, useId, useState } from 'react';
2
+ import { ArticleItemType, getLayoutStyles, TRichTextItem } from '@cntrl-site/sdk';
3
3
  import JSXStyle from 'styled-jsx/style';
4
4
  import { ItemProps } from '../Item';
5
5
  import { useRichTextItem } from './useRichTextItem';
6
6
  import { useItemAngle } from '../useItemAngle';
7
+ import { useCntrlContext } from '../../provider/useCntrlContext';
8
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
7
9
 
8
10
  export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, onResize }) => {
9
11
  const [content, styles, preset] = useRichTextItem(item);
12
+ const id = useId();
10
13
  const [ref, setRef] = useState<HTMLDivElement | null>(null);
11
14
  const angle = useItemAngle(item, sectionId);
15
+ const { layouts } = useCntrlContext();
12
16
  const className = preset ? `cntrl-preset-${preset.id}` : undefined;
13
17
 
14
18
  useEffect(() => {
@@ -27,15 +31,25 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
27
31
  <>
28
32
  <div
29
33
  ref={setRef}
30
- className={className}
34
+ className={`${className} rich-text-wrapper-${item.id}`}
31
35
  style={{
32
36
  transform: `rotate(${angle}deg)`
33
37
  }}
34
38
  >
35
39
  {content}
36
40
  </div>
37
- <JSXStyle id={item.id}>
41
+ <JSXStyle id={id}>
38
42
  {styles}
43
+ {`${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
44
+ return (`
45
+ .rich-text-wrapper-${item.id} {
46
+ transition: ${getTransitions<ArticleItemType.RichText>(['angle'], hoverParams)};
47
+ }
48
+ .rich-text-wrapper-${item.id}:hover {
49
+ ${getHoverStyles<ArticleItemType.RichText>(['angle'], hoverParams)}
50
+ }
51
+ `);
52
+ })}`}
39
53
  </JSXStyle>
40
54
  </>
41
55
  );
@@ -1,13 +1,16 @@
1
1
  import { FC, useId, useMemo } from 'react';
2
2
  import JSXStyle from 'styled-jsx/style';
3
- import { CntrlColor, TVideoItem } from '@cntrl-site/sdk';
3
+ import { ArticleItemType, CntrlColor, getLayoutStyles, TVideoItem } from '@cntrl-site/sdk';
4
4
  import { ItemProps } from '../Item';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
6
  import { useFileItem } from './useFileItem';
7
7
  import { useItemAngle } from '../useItemAngle';
8
+ import { useCntrlContext } from '../../provider/useCntrlContext';
9
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
8
10
 
9
11
  export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId }) => {
10
12
  const id = useId();
13
+ const { layouts } = useCntrlContext();
11
14
  const { radius, strokeWidth, strokeColor, opacity } = useFileItem(item, sectionId);
12
15
  const angle = useItemAngle(item, sectionId);
13
16
  const borderColor = useMemo(() => CntrlColor.parse(strokeColor), [strokeColor]);
@@ -50,6 +53,16 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId }) => {
50
53
  object-fit: cover;
51
54
  pointer-events: none;
52
55
  }
56
+ ${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
57
+ return (`
58
+ .video-wrapper-${item.id} {
59
+ transition: ${getTransitions<ArticleItemType.Video>(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)};
60
+ }
61
+ .video-wrapper-${item.id}:hover {
62
+ ${getHoverStyles<ArticleItemType.Video>(['angle', 'strokeWidth', 'radius', 'strokeColor', 'opacity'], hoverParams)}
63
+ }
64
+ `);
65
+ })}
53
66
  `}</JSXStyle>
54
67
  </LinkWrapper>
55
68
  );
@@ -1,20 +1,34 @@
1
- import { FC, useId } from 'react';
1
+ import { FC, useEffect, useId, useMemo, useRef, useState } from 'react';
2
+ import Player from '@vimeo/player';
2
3
  import JSXStyle from 'styled-jsx/style';
3
4
  import { TVimeoEmbedItem } from '@cntrl-site/core';
4
5
  import { ItemProps } from '../Item';
5
6
  import { LinkWrapper } from '../LinkWrapper';
6
7
  import { useEmbedVideoItem } from './useEmbedVideoItem';
7
8
  import { useItemAngle } from '../useItemAngle';
9
+ import { ArticleItemType, getLayoutStyles } from '@cntrl-site/sdk';
10
+ import { useCntrlContext } from '../../provider/useCntrlContext';
11
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
12
+ import { useCurrentLayout } from '../../common/useCurrentLayout';
8
13
 
9
14
  export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId }) => {
10
15
  const id = useId();
16
+ const { layouts } = useCntrlContext();
17
+ const layout = useCurrentLayout()
11
18
  const { radius } = useEmbedVideoItem(item, sectionId);
19
+ const [iframeRef, setIframeRef] = useState<HTMLIFrameElement | null>(null);
20
+ const vimeoPlayer = useMemo(() => iframeRef ? new Player(iframeRef) : undefined, [iframeRef]);
21
+ const isAutoPlayOnHover = useMemo(() => {
22
+ const layoutHoverStates = item.state.hover[layout];
23
+ if (!layoutHoverStates) return false;
24
+ return layoutHoverStates.autoplay === true;
25
+ }, [layout, item]);
12
26
  const angle = useItemAngle(item, sectionId);
13
27
  const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
14
28
  const getValidVimeoUrl = (url: string): string => {
15
29
  const validURL = new URL(url);
16
30
  validURL.searchParams.append('controls', String(controls));
17
- validURL.searchParams.append('autoplay', !controls ? 'true' : String(autoplay));
31
+ validURL.searchParams.append('autoplay', String(autoplay));
18
32
  validURL.searchParams.append('muted', String(muted));
19
33
  validURL.searchParams.append('loop', String(loop));
20
34
  validURL.searchParams.append('pip', String(pictureInPicture));
@@ -29,33 +43,52 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
29
43
 
30
44
  return (
31
45
  <LinkWrapper url={item.link?.url}>
32
- <div className={`embed-video-wrapper-${item.id}`}
33
- style={{
34
- borderRadius: `${radius * 100}vw`,
35
- transform: `rotate(${angle}deg)`
36
- }}
37
- >
38
- <iframe
39
- className="embedVideo"
40
- src={validUrl || ''}
41
- allow="autoplay; fullscreen; picture-in-picture;"
42
- allowFullScreen
43
- />
44
- </div>
45
- <JSXStyle id={id}>{`
46
- .embed-video-wrapper-${item.id} {
47
- position: absolute;
48
- overflow: hidden;
49
- width: 100%;
50
- height: 100%;
51
- }
52
- .embedVideo {
53
- width: 100%;
54
- height: 100%;
55
- z-index: 1;
56
- border: none;
57
- }
58
- `}</JSXStyle>
46
+ <div className={`embed-video-wrapper-${item.id}`}
47
+ style={{
48
+ borderRadius: `${radius * 100}vw`,
49
+ transform: `rotate(${angle}deg)`
50
+ }}
51
+ onMouseEnter={() => {
52
+ if (!vimeoPlayer || !isAutoPlayOnHover) return;
53
+ vimeoPlayer.play();
54
+ }}
55
+ onMouseLeave={() =>{
56
+ if (!vimeoPlayer || !isAutoPlayOnHover) return;
57
+ vimeoPlayer.pause();
58
+ }}
59
+ >
60
+ <iframe
61
+ ref={setIframeRef}
62
+ className="embedVideo"
63
+ src={validUrl || ''}
64
+ allow="autoplay; fullscreen; picture-in-picture;"
65
+ allowFullScreen
66
+ />
67
+ </div>
68
+ <JSXStyle id={id}>{`
69
+ .embed-video-wrapper-${item.id} {
70
+ position: absolute;
71
+ overflow: hidden;
72
+ width: 100%;
73
+ height: 100%;
74
+ }
75
+ .embedVideo {
76
+ width: 100%;
77
+ height: 100%;
78
+ z-index: 1;
79
+ border: none;
80
+ }
81
+ ${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
82
+ return (`
83
+ .embed-video-wrapper-${item.id} {
84
+ transition: ${getTransitions<ArticleItemType.VimeoEmbed>(['angle', 'radius'], hoverParams)};
85
+ }
86
+ .embed-video-wrapper-${item.id}:hover {
87
+ ${getHoverStyles<ArticleItemType.VimeoEmbed>(['angle', 'radius'], hoverParams)}
88
+ }
89
+ `);
90
+ })}
91
+ `}</JSXStyle>
59
92
  </LinkWrapper>
60
93
  );
61
94
  };
@@ -6,9 +6,13 @@ import { LinkWrapper } from '../LinkWrapper';
6
6
  import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
7
7
  import { useEmbedVideoItem } from './useEmbedVideoItem';
8
8
  import { useItemAngle } from '../useItemAngle';
9
+ import { ArticleItemType, getLayoutStyles } from '@cntrl-site/sdk';
10
+ import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
11
+ import { useCntrlContext } from '../../provider/useCntrlContext';
9
12
 
10
13
  export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, sectionId }) => {
11
14
  const id = useId();
15
+ const { layouts } = useCntrlContext();
12
16
  const { autoplay, controls, url } = item.commonParams;
13
17
  const { radius } = useEmbedVideoItem(item, sectionId);
14
18
  const angle = useItemAngle(item, sectionId);
@@ -18,7 +22,7 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
18
22
  const id = getYoutubeId(newUrl);
19
23
  const validUrl = new URL(`https://www.youtube.com/embed/${id}`);
20
24
  validUrl.searchParams.append('controls', `${ Number(controls) }`);
21
- validUrl.searchParams.append('autoplay', !controls ? 'true' : `${ Number(autoplay) }`);
25
+ validUrl.searchParams.append('autoplay', `${ Number(autoplay) }`);
22
26
  validUrl.searchParams.append('mute', `${ Number(autoplay) }`);
23
27
 
24
28
  return validUrl.href;
@@ -53,6 +57,16 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
53
57
  z-index: 1;
54
58
  border: none;
55
59
  }
60
+ ${getLayoutStyles(layouts, [item.state.hover], ([hoverParams]) => {
61
+ return (`
62
+ .embed-youtube-video-wrapper-${item.id} {
63
+ transition: ${getTransitions<ArticleItemType.YoutubeEmbed>(['angle', 'radius'], hoverParams)};
64
+ }
65
+ .embed-youtube-video-wrapper-${item.id}:hover {
66
+ ${getHoverStyles<ArticleItemType.YoutubeEmbed>(['angle', 'radius'], hoverParams)}
67
+ }
68
+ `);
69
+ })}
56
70
  `}</JSXStyle>
57
71
  </LinkWrapper>
58
72
  )
@@ -1,6 +1,7 @@
1
1
  import { AnchorSide, TArticleItemAny } from '@cntrl-site/sdk';
2
2
  import { useKeyframeValue } from '../common/useKeyframeValue';
3
3
  import { useCurrentLayout } from '../common/useCurrentLayout';
4
+ import { getItemTopStyle } from '../utils/getItemTopStyle';
4
5
 
5
6
  export const useItemPosition = (item: TArticleItemAny, sectionId: string) => {
6
7
  const layoutId = useCurrentLayout();
@@ -17,17 +18,4 @@ export const useItemPosition = (item: TArticleItemAny, sectionId: string) => {
17
18
  };
18
19
  };
19
20
 
20
- export function getItemTopStyle(top: number, anchorSide?: AnchorSide) {
21
- const defaultValue = `${top * 100}vw`;
22
- if (!anchorSide) return defaultValue;
23
- switch (anchorSide) {
24
- case AnchorSide.Top:
25
- return defaultValue;
26
- case AnchorSide.Center:
27
- return `calc(50% + ${top * 100}vw)`;
28
- case AnchorSide.Bottom:
29
- return `calc(100% + ${top * 100}vw)`;
30
- }
31
- }
32
-
33
21
 
@@ -0,0 +1,74 @@
1
+ import { THoverParams, ArticleItemType, CntrlColor, AnchorSide, TItemHoverState } from '@cntrl-site/sdk';
2
+ import { getItemTopStyle } from '../getItemTopStyle';
3
+
4
+ type UnionToIntersection<U> = (U extends any ? (arg: U) => void : never) extends (arg: infer I) => void ? I : never;
5
+ type HoverParamsGetter = (value: any, anchorSide?: AnchorSide) => string;
6
+ type ItemHoverParams = Omit<UnionToIntersection<TItemHoverState>, 'autoplay'>;
7
+
8
+ const hoverTransformationMap: Record<keyof ItemHoverParams, HoverParamsGetter> = {
9
+ 'width': (width: number) => `width: ${width * 100}vw !important;`,
10
+ 'height': (height: number) => `height: ${height * 100}vw !important;`,
11
+ 'top': (top: number, anchorSide?: AnchorSide) => `top: ${getItemTopStyle(top, anchorSide)} !important;`,
12
+ 'left': (left: number) => `left: ${left * 100}vw !important;`,
13
+ 'scale': (scale: number) => `transform: scale(${scale}) !important;`,
14
+ 'angle': (angle: number) => `transform: rotate(${angle}deg) !important;`,
15
+ 'opacity': (opacity: number) => `opacity: ${opacity} !important;`,
16
+ 'radius': (radius: number) => `border-radius: ${radius * 100}vw !important;`,
17
+ 'strokeWidth': (strokeWidth: number) => `border-width: ${strokeWidth * 100}vw !important;`,
18
+ 'strokeColor': (strokeColor: string) => `border-color: ${CntrlColor.parse(strokeColor).toCss()} !important;`,
19
+ 'fillColor': (fillColor: string) => `background-color: ${CntrlColor.parse(fillColor).toCss()} !important;`,
20
+ };
21
+
22
+ const CSSPropertyNameMap: Record<keyof ItemHoverParams, string> = {
23
+ 'width': 'width',
24
+ 'height': 'height',
25
+ 'top': 'top',
26
+ 'left': 'left',
27
+ 'scale': 'transform',
28
+ 'angle': 'transform',
29
+ 'opacity': 'opacity',
30
+ 'radius': 'border-radius',
31
+ 'strokeWidth': 'border-width',
32
+ 'strokeColor': 'border-color',
33
+ 'fillColor': 'background-color'
34
+ };
35
+
36
+ export function getTransitions<T extends ArticleItemType>(
37
+ values: Array<keyof ItemHoverParams>,
38
+ hover?: ItemHoverParams
39
+ ): string {
40
+ if (!hover) return 'unset';
41
+ const transitionValues = values.reduce<string[]>((acc, valueName) => {
42
+ if (valueName in hover && hover[valueName] !== undefined) {
43
+ const hoverProperties = hover[valueName] as THoverParams<string | number>;
44
+ return [
45
+ ...acc,
46
+ `${CSSPropertyNameMap[valueName]} ${hoverProperties!.duration}ms ${hoverProperties!.timing} ${hoverProperties!.delay}ms`
47
+ ];
48
+ }
49
+ return acc;
50
+ }, []);
51
+ if (!transitionValues.length) return 'unset';
52
+ return transitionValues.join(', ');
53
+ }
54
+
55
+ export function getHoverStyles<T extends ArticleItemType>(
56
+ values: Array<keyof ItemHoverParams>,
57
+ hover?: ItemHoverParams,
58
+ anchorSide?: AnchorSide
59
+ ): string {
60
+ if (!hover) return '';
61
+ const hoverValues = values.reduce<string[]>((acc, valueName) => {
62
+ if (valueName in hover && hover[valueName] !== undefined) {
63
+ const hoverProperties = hover[valueName] as THoverParams<string | number>;
64
+ return [
65
+ ...acc,
66
+ hoverTransformationMap[valueName](hoverProperties.value, anchorSide)
67
+ ];
68
+ }
69
+ return acc;
70
+ }, []);
71
+ if (!hoverValues.length) return '';
72
+ return hoverValues.join('\n');
73
+ }
74
+
@@ -0,0 +1,14 @@
1
+ import { AnchorSide } from '@cntrl-site/sdk';
2
+
3
+ export function getItemTopStyle(top: number, anchorSide?: AnchorSide) {
4
+ const defaultValue = `${top * 100}vw`;
5
+ if (!anchorSide) return defaultValue;
6
+ switch (anchorSide) {
7
+ case AnchorSide.Top:
8
+ return defaultValue;
9
+ case AnchorSide.Center:
10
+ return `calc(50% + ${top * 100}vw)`;
11
+ case AnchorSide.Bottom:
12
+ return `calc(100% + ${top * 100}vw)`;
13
+ }
14
+ }
@@ -1,15 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
5
- <option name="myValues">
6
- <value>
7
- <list size="1">
8
- <item index="0" class="java.lang.String" itemvalue="jsx" />
9
- </list>
10
- </value>
11
- </option>
12
- <option name="myCustomValuesEnabled" value="true" />
13
- </inspection_tool>
14
- </profile>
15
- </component>