@cntrl-site/sdk-nextjs 0.8.5 → 0.8.7

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.
Binary file
Binary file
@@ -12,12 +12,13 @@ const VimeoEmbed_1 = require("./items/VimeoEmbed");
12
12
  const YoutubeEmbed_1 = require("./items/YoutubeEmbed");
13
13
  const CustomItem_1 = require("./items/CustomItem");
14
14
  const useCntrlContext_1 = require("../provider/useCntrlContext");
15
- const useItemAngle_1 = require("./useItemAngle");
16
15
  const useItemPosition_1 = require("./useItemPosition");
17
16
  const useItemDimensions_1 = require("./useItemDimensions");
18
17
  const useItemSticky_1 = require("./items/useItemSticky");
19
18
  const castObject_1 = require("../utils/castObject");
20
19
  const useCurrentLayout_1 = require("../common/useCurrentLayout");
20
+ const useItemScale_1 = require("./useItemScale");
21
+ const ScaleAnchorMap_1 = require("../utils/ScaleAnchorMap");
21
22
  const itemsMap = {
22
23
  [sdk_1.ArticleItemType.Rectangle]: RectangleItem_1.RectangleItem,
23
24
  [sdk_1.ArticleItemType.Image]: ImageItem_1.ImageItem,
@@ -30,7 +31,7 @@ const itemsMap = {
30
31
  const noop = () => null;
31
32
  const Item = ({ item }) => {
32
33
  const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
33
- const angle = (0, useItemAngle_1.useItemAngle)(item);
34
+ const { scale, scaleAnchor } = (0, useItemScale_1.useItemScale)(item);
34
35
  const position = (0, useItemPosition_1.useItemPosition)(item);
35
36
  const layout = (0, useCurrentLayout_1.useCurrentLayout)();
36
37
  const [ref, setRef] = (0, react_1.useState)(null);
@@ -57,7 +58,8 @@ const Item = ({ item }) => {
57
58
  setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
58
59
  }, [ref]);
59
60
  const styles = {
60
- transform: `rotate(${angle}deg)`,
61
+ transform: `scale(${scale})`,
62
+ transformOrigin: ScaleAnchorMap_1.ScaleAnchorMap[scaleAnchor],
61
63
  left: `${position.left * 100}vw`,
62
64
  width: `${sizingAxis.x === sdk_1.ArticleItemSizingType.Manual ? `${width * 100}vw` : 'max-content'}`,
63
65
  height: `${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${height * 100}vw` : 'unset'}`,
@@ -75,7 +77,8 @@ const Item = ({ item }) => {
75
77
  width: ${sizingAxis.x === sdk_1.ArticleItemSizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
76
78
  height: ${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${area.height * 100}vw` : 'unset'};
77
79
  z-index: ${area.zIndex};
78
- transform: rotate(${area.angle}deg);
80
+ transform: scale(${scale});
81
+ transform-origin: ${ScaleAnchorMap_1.ScaleAnchorMap[scaleAnchor]};
79
82
  }
80
83
  `);
81
84
  })}
@@ -6,14 +6,17 @@ const react_1 = require("react");
6
6
  const sdk_1 = require("@cntrl-site/sdk");
7
7
  const LinkWrapper_1 = require("../LinkWrapper");
8
8
  const useFileItem_1 = require("./useFileItem");
9
+ const useItemAngle_1 = require("../useItemAngle");
9
10
  const ImageItem = ({ item }) => {
10
11
  const { radius, strokeWidth, opacity, strokeColor } = (0, useFileItem_1.useFileItem)(item);
12
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
11
13
  const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
12
14
  return ((0, jsx_runtime_1.jsx)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `image-wrapper-${item.id}`, style: {
13
15
  borderRadius: `${radius * 100}vw`,
14
16
  borderWidth: `${strokeWidth * 100}vw`,
15
17
  opacity: `${opacity}`,
16
- borderColor: `${borderColor}`
18
+ borderColor: `${borderColor}`,
19
+ transform: `rotate(${angle}deg)`
17
20
  }, children: (0, jsx_runtime_1.jsx)("img", { className: "image", src: item.commonParams.url }) }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
18
21
  .image-wrapper-${item.id} {
19
22
  position: absolute;
@@ -6,15 +6,18 @@ const react_1 = require("react");
6
6
  const sdk_1 = require("@cntrl-site/sdk");
7
7
  const LinkWrapper_1 = require("../LinkWrapper");
8
8
  const useRectangleItem_1 = require("./useRectangleItem");
9
+ const useItemAngle_1 = require("../useItemAngle");
9
10
  const RectangleItem = ({ item }) => {
10
11
  const { fillColor, radius, strokeWidth, strokeColor } = (0, useRectangleItem_1.useRectangleItem)(item);
12
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
11
13
  const backgroundColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(fillColor).toCss(), [fillColor]);
12
14
  const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
13
15
  return ((0, jsx_runtime_1.jsx)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `rectangle-${item.id}`, style: {
14
16
  backgroundColor: `${backgroundColor}`,
15
17
  borderRadius: `${radius * 100}vw`,
16
18
  borderWidth: `${strokeWidth * 100}vw`,
17
- borderColor: `${borderColor}`
19
+ borderColor: `${borderColor}`,
20
+ transform: `rotate(${angle}deg)`
18
21
  } }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
19
22
  .rectangle-${item.id} {
20
23
  position: absolute;
@@ -8,9 +8,13 @@ const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  //@ts-ignore
9
9
  const style_1 = __importDefault(require("styled-jsx/style"));
10
10
  const useRichTextItem_1 = require("./useRichTextItem");
11
+ const useItemAngle_1 = require("../useItemAngle");
11
12
  const RichTextItem = ({ item }) => {
12
13
  const [content, styles, preset] = (0, useRichTextItem_1.useRichTextItem)(item);
14
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
13
15
  const className = preset ? `cntrl-preset-${preset.id}` : undefined;
14
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: className, children: content }), (0, jsx_runtime_1.jsx)(style_1.default, { id: item.id, children: styles })] }));
16
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: className, style: {
17
+ transform: `rotate(${angle}deg)`
18
+ }, children: content }), (0, jsx_runtime_1.jsx)(style_1.default, { id: item.id, children: styles })] }));
15
19
  };
16
20
  exports.RichTextItem = RichTextItem;
@@ -6,14 +6,17 @@ const react_1 = require("react");
6
6
  const sdk_1 = require("@cntrl-site/sdk");
7
7
  const LinkWrapper_1 = require("../LinkWrapper");
8
8
  const useFileItem_1 = require("./useFileItem");
9
+ const useItemAngle_1 = require("../useItemAngle");
9
10
  const VideoItem = ({ item }) => {
10
11
  const { radius, strokeWidth, strokeColor, opacity } = (0, useFileItem_1.useFileItem)(item);
12
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
11
13
  const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
12
14
  return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: [(0, jsx_runtime_1.jsx)("div", { className: `video-wrapper-${item.id}`, style: {
13
15
  borderRadius: `${radius * 100}vw`,
14
16
  borderWidth: `${strokeWidth * 100}vw`,
15
17
  opacity: `${opacity}`,
16
- borderColor: `${borderColor}`
18
+ borderColor: `${borderColor}`,
19
+ transform: `rotate(${angle}deg)`
17
20
  }, children: (0, jsx_runtime_1.jsx)("video", { autoPlay: true, muted: true, loop: true, playsInline: true, className: "video", children: (0, jsx_runtime_1.jsx)("source", { src: item.commonParams.url }) }) }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
18
21
  .video-wrapper-${item.id} {
19
22
  position: absolute;
@@ -4,8 +4,10 @@ exports.VimeoEmbedItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const LinkWrapper_1 = require("../LinkWrapper");
6
6
  const useEmbedVideoItem_1 = require("./useEmbedVideoItem");
7
+ const useItemAngle_1 = require("../useItemAngle");
7
8
  const VimeoEmbedItem = ({ item }) => {
8
9
  const { radius } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item);
10
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
9
11
  const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
10
12
  const getValidVimeoUrl = (url) => {
11
13
  const validURL = new URL(url);
@@ -22,16 +24,14 @@ const VimeoEmbedItem = ({ item }) => {
22
24
  };
23
25
  const validUrl = getValidVimeoUrl(url);
24
26
  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: {
25
- borderRadius: `${radius * 100}vw`
27
+ borderRadius: `${radius * 100}vw`,
28
+ transform: `rotate(${angle}deg)`
26
29
  }, 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", { jsx: true, children: `
27
30
  .embed-video-wrapper-${item.id} {
28
31
  position: absolute;
29
32
  overflow: hidden;
30
33
  width: 100%;
31
34
  height: 100%;
32
- top: 50%;
33
- left: 50%;
34
- transform: translate(-50%, -50%);
35
35
  }
36
36
  .embedVideo {
37
37
  width: 100%;
@@ -5,9 +5,11 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const LinkWrapper_1 = require("../LinkWrapper");
6
6
  const getValidYoutubeUrl_1 = require("../../utils/getValidYoutubeUrl");
7
7
  const useEmbedVideoItem_1 = require("./useEmbedVideoItem");
8
+ const useItemAngle_1 = require("../useItemAngle");
8
9
  const YoutubeEmbedItem = ({ item }) => {
9
10
  const { autoplay, controls, url } = item.commonParams;
10
11
  const { radius } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item);
12
+ const angle = (0, useItemAngle_1.useItemAngle)(item);
11
13
  const getValidYoutubeUrl = (url) => {
12
14
  const newUrl = new URL(url);
13
15
  const id = (0, getValidYoutubeUrl_1.getYoutubeId)(newUrl);
@@ -19,16 +21,14 @@ const YoutubeEmbedItem = ({ item }) => {
19
21
  };
20
22
  const validUrl = getValidYoutubeUrl(url);
21
23
  return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: [(0, jsx_runtime_1.jsx)("div", { className: `embed-youtube-video-wrapper-${item.id}`, style: {
22
- borderRadius: `${radius * 100}vw`
24
+ borderRadius: `${radius * 100}vw`,
25
+ transform: `rotate(${angle}deg)`
23
26
  }, children: (0, jsx_runtime_1.jsx)("iframe", { className: "embedYoutubeVideo", src: validUrl || '', allow: "accelerometer; autoplay; allowfullscreen;", allowFullScreen: true }) }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
24
27
  .embed-youtube-video-wrapper-${item.id} {
25
28
  position: absolute;
26
29
  overflow: hidden;
27
30
  width: 100%;
28
31
  height: 100%;
29
- top: 50%;
30
- left: 50%;
31
- transform: translate(-50%, -50%);
32
32
  }
33
33
  .embedYoutubeVideo {
34
34
  width: 100%;
@@ -11,7 +11,7 @@ const useItemSticky = (top, parentOffsetTop, item) => {
11
11
  const [adjustedTop, setAdjustedTop] = (0, react_1.useState)(top);
12
12
  const articleRectObserver = (0, react_1.useContext)(ArticleRectContext_1.ArticleRectContext);
13
13
  const layoutId = (0, useCurrentLayout_1.useCurrentLayout)();
14
- const sticky = (0, react_1.useMemo)(() => item.layoutParams[layoutId].sticky, [layoutId]);
14
+ const sticky = (0, react_1.useMemo)(() => item.sticky[layoutId], [layoutId]);
15
15
  const stickyManager = (0, react_1.useMemo)(() => new StickyManager_1.StickyManager(sticky), [sticky]);
16
16
  const handleSticky = (0, react_1.useCallback)((scroll) => {
17
17
  setIsFixed(stickyManager.getIsSticky(scroll));
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useItemScale = void 0;
4
+ const useKeyframeValue_1 = require("../common/useKeyframeValue");
5
+ const useCurrentLayout_1 = require("../common/useCurrentLayout");
6
+ const useItemScale = (item) => {
7
+ const layout = (0, useCurrentLayout_1.useCurrentLayout)();
8
+ const { scale } = (0, useKeyframeValue_1.useKeyframeValue)(item, (item, layoutId) => ({ scale: layoutId ? item.area[layoutId].scale : 1 }), (animator, scroll, value) => animator.getScale(value, scroll));
9
+ const scaleAnchor = item.area[layout].scaleAnchor;
10
+ return { scale, scaleAnchor };
11
+ };
12
+ exports.useItemScale = useItemScale;
@@ -138,6 +138,21 @@ class Animator {
138
138
  opacity: rangeMap(pos, start.position, end.position, start.value.opacity, end.value.opacity, true)
139
139
  };
140
140
  }
141
+ getScale(values, pos) {
142
+ const keyframes = this.keyframesMap[sdk_1.KeyframeType.Scale];
143
+ if (!keyframes || !keyframes.length)
144
+ return values;
145
+ if (keyframes.length === 1) {
146
+ const [keyframe] = keyframes;
147
+ return {
148
+ scale: keyframe.value.scale
149
+ };
150
+ }
151
+ const { start, end } = this.getStartEnd(pos, keyframes);
152
+ return {
153
+ scale: rangeMap(pos, start.position, end.position, start.value.scale, end.value.scale, true)
154
+ };
155
+ }
141
156
  getStartEnd(position, keyframes) {
142
157
  const index = (0, binSearchInsertAt_1.binSearchInsertAt)(keyframes, { position }, compare);
143
158
  const end = index === keyframes.length ? index - 1 : index;
@@ -168,7 +183,8 @@ function createKeyframesMap() {
168
183
  [sdk_1.KeyframeType.Color]: [],
169
184
  [sdk_1.KeyframeType.Rotation]: [],
170
185
  [sdk_1.KeyframeType.BorderColor]: [],
171
- [sdk_1.KeyframeType.Opacity]: []
186
+ [sdk_1.KeyframeType.Opacity]: [],
187
+ [sdk_1.KeyframeType.Scale]: []
172
188
  };
173
189
  }
174
190
  function rangeMap(n, start1, stop1, start2, stop2, withinBounds = false) {
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScaleAnchorMap = void 0;
4
+ const sdk_1 = require("@cntrl-site/sdk");
5
+ exports.ScaleAnchorMap = {
6
+ [sdk_1.ScaleAnchor.TopLeft]: 'top left',
7
+ [sdk_1.ScaleAnchor.TopCenter]: 'top center',
8
+ [sdk_1.ScaleAnchor.TopRight]: 'top right',
9
+ [sdk_1.ScaleAnchor.MiddleLeft]: 'center left',
10
+ [sdk_1.ScaleAnchor.MiddleCenter]: 'center',
11
+ [sdk_1.ScaleAnchor.MiddleRight]: 'center right',
12
+ [sdk_1.ScaleAnchor.BottomLeft]: 'bottom left',
13
+ [sdk_1.ScaleAnchor.BottomCenter]: 'bottom center',
14
+ [sdk_1.ScaleAnchor.BottomRight]: 'bottom right'
15
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "SDK for Next.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/index.js",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "homepage": "https://github.com/cntrl-site/sdk-nextjs#readme",
23
23
  "dependencies": {
24
- "@cntrl-site/sdk": "^0.7.0",
24
+ "@cntrl-site/sdk": "^0.7.2",
25
25
  "html-react-parser": "^3.0.1",
26
26
  "styled-jsx": "^5.0.2"
27
27
  },
@@ -14,12 +14,13 @@ import { VimeoEmbedItem } from './items/VimeoEmbed';
14
14
  import { YoutubeEmbedItem } from './items/YoutubeEmbed';
15
15
  import { CustomItem } from './items/CustomItem';
16
16
  import { useCntrlContext } from '../provider/useCntrlContext';
17
- import { useItemAngle } from './useItemAngle';
18
17
  import { useItemPosition } from './useItemPosition';
19
18
  import { useItemDimensions } from './useItemDimensions';
20
19
  import { getItemTopStyle, useItemSticky } from './items/useItemSticky';
21
20
  import { castObject } from '../utils/castObject';
22
21
  import { useCurrentLayout } from '../common/useCurrentLayout';
22
+ import { useItemScale } from './useItemScale';
23
+ import { ScaleAnchorMap } from '../utils/ScaleAnchorMap';
23
24
 
24
25
  export interface ItemProps<I extends TArticleItemAny> {
25
26
  item: I;
@@ -39,7 +40,7 @@ const noop = () => null;
39
40
 
40
41
  export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
41
42
  const { layouts } = useCntrlContext();
42
- const angle = useItemAngle(item);
43
+ const { scale, scaleAnchor } = useItemScale(item);
43
44
  const position = useItemPosition(item);
44
45
  const layout = useCurrentLayout();
45
46
  const [ref, setRef] = useState<HTMLDivElement | null>(null);
@@ -69,7 +70,8 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
69
70
  }, [ref]);
70
71
 
71
72
  const styles = {
72
- transform: `rotate(${angle}deg)`,
73
+ transform: `scale(${scale})`,
74
+ transformOrigin: ScaleAnchorMap[scaleAnchor],
73
75
  left: `${position.left * 100}vw`,
74
76
  width: `${sizingAxis.x === SizingType.Manual ? `${width * 100}vw` : 'max-content'}`,
75
77
  height: `${sizingAxis.y === SizingType.Manual ? `${height * 100}vw` : 'unset'}`,
@@ -96,7 +98,8 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
96
98
  width: ${sizingAxis.x === SizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
97
99
  height: ${sizingAxis.y === SizingType.Manual ? `${area.height * 100}vw` : 'unset'};
98
100
  z-index: ${area.zIndex};
99
- transform: rotate(${area.angle}deg);
101
+ transform: scale(${scale});
102
+ transform-origin: ${ScaleAnchorMap[scaleAnchor]};
100
103
  }
101
104
  `);
102
105
  })}
@@ -3,9 +3,11 @@ import { CntrlColor, TImageItem } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useFileItem } from './useFileItem';
6
+ import { useItemAngle } from '../useItemAngle';
6
7
 
7
8
  export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
8
9
  const { radius, strokeWidth, opacity, strokeColor } = useFileItem(item);
10
+ const angle = useItemAngle(item);
9
11
  const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
10
12
  return (
11
13
  <LinkWrapper url={item.link?.url}>
@@ -15,7 +17,8 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
15
17
  borderRadius: `${radius * 100}vw`,
16
18
  borderWidth: `${strokeWidth * 100}vw`,
17
19
  opacity: `${opacity}`,
18
- borderColor: `${borderColor}`
20
+ borderColor: `${borderColor}`,
21
+ transform: `rotate(${angle}deg)`
19
22
  }}
20
23
  >
21
24
  <img className="image" src={item.commonParams.url} />
@@ -3,9 +3,11 @@ import { TRectangleItem, CntrlColor } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useRectangleItem } from './useRectangleItem';
6
+ import { useItemAngle } from '../useItemAngle';
6
7
 
7
8
  export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item }) => {
8
9
  const { fillColor, radius, strokeWidth, strokeColor } = useRectangleItem(item);
10
+ const angle = useItemAngle(item);
9
11
  const backgroundColor = useMemo(() => CntrlColor.parse(fillColor).toCss(), [fillColor]);
10
12
  const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
11
13
 
@@ -17,7 +19,8 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item }) => {
17
19
  backgroundColor: `${backgroundColor}`,
18
20
  borderRadius: `${radius * 100}vw`,
19
21
  borderWidth: `${strokeWidth * 100}vw`,
20
- borderColor: `${borderColor}`
22
+ borderColor: `${borderColor}`,
23
+ transform: `rotate(${angle}deg)`
21
24
  }}
22
25
  />
23
26
  <style jsx>{`
@@ -4,13 +4,22 @@ import { TRichTextItem } from '@cntrl-site/sdk';
4
4
  import JSXStyle from 'styled-jsx/style';
5
5
  import { ItemProps } from '../Item';
6
6
  import { useRichTextItem } from './useRichTextItem';
7
+ import { useItemAngle } from '../useItemAngle';
7
8
 
8
9
  export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item }) => {
9
10
  const [content, styles, preset] = useRichTextItem(item);
11
+ const angle = useItemAngle(item);
10
12
  const className = preset ? `cntrl-preset-${preset.id}` : undefined;
11
13
  return (
12
14
  <>
13
- <div className={className}>{content}</div>
15
+ <div
16
+ className={className}
17
+ style={{
18
+ transform: `rotate(${angle}deg)`
19
+ }}
20
+ >
21
+ {content}
22
+ </div>
14
23
  <JSXStyle id={item.id}>
15
24
  {styles}
16
25
  </JSXStyle>
@@ -3,9 +3,11 @@ import { CntrlColor, TVideoItem } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useFileItem } from './useFileItem';
6
+ import { useItemAngle } from '../useItemAngle';
6
7
 
7
8
  export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
8
9
  const { radius, strokeWidth, strokeColor, opacity } = useFileItem(item);
10
+ const angle = useItemAngle(item);
9
11
  const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
10
12
  return (
11
13
  <LinkWrapper url={item.link?.url}>
@@ -14,7 +16,8 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
14
16
  borderRadius: `${radius * 100}vw`,
15
17
  borderWidth: `${strokeWidth * 100}vw`,
16
18
  opacity: `${opacity}`,
17
- borderColor: `${borderColor}`
19
+ borderColor: `${borderColor}`,
20
+ transform: `rotate(${angle}deg)`
18
21
  }}
19
22
  >
20
23
  <video autoPlay muted loop playsInline className="video">
@@ -3,9 +3,11 @@ import { TVimeoEmbedItem } from '@cntrl-site/core';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useEmbedVideoItem } from './useEmbedVideoItem';
6
+ import { useItemAngle } from '../useItemAngle';
6
7
 
7
8
  export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
8
9
  const { radius } = useEmbedVideoItem(item);
10
+ const angle = useItemAngle(item);
9
11
  const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
10
12
  const getValidVimeoUrl = (url: string): string => {
11
13
  const validURL = new URL(url);
@@ -27,7 +29,8 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
27
29
  <LinkWrapper url={item.link?.url}>
28
30
  <div className={`embed-video-wrapper-${item.id}`}
29
31
  style={{
30
- borderRadius: `${radius * 100}vw`
32
+ borderRadius: `${radius * 100}vw`,
33
+ transform: `rotate(${angle}deg)`
31
34
  }}
32
35
  >
33
36
  <iframe
@@ -43,9 +46,6 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
43
46
  overflow: hidden;
44
47
  width: 100%;
45
48
  height: 100%;
46
- top: 50%;
47
- left: 50%;
48
- transform: translate(-50%, -50%);
49
49
  }
50
50
  .embedVideo {
51
51
  width: 100%;
@@ -4,10 +4,12 @@ import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
6
6
  import { useEmbedVideoItem } from './useEmbedVideoItem';
7
+ import { useItemAngle } from '../useItemAngle';
7
8
 
8
9
  export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) => {
9
10
  const { autoplay, controls, url } = item.commonParams;
10
11
  const { radius } = useEmbedVideoItem(item);
12
+ const angle = useItemAngle(item);
11
13
 
12
14
  const getValidYoutubeUrl = (url: string): string => {
13
15
  const newUrl = new URL(url);
@@ -25,7 +27,8 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) =>
25
27
  <LinkWrapper url={item.link?.url}>
26
28
  <div className={`embed-youtube-video-wrapper-${item.id}`}
27
29
  style={{
28
- borderRadius: `${radius * 100}vw`
30
+ borderRadius: `${radius * 100}vw`,
31
+ transform: `rotate(${angle}deg)`
29
32
  }}
30
33
  >
31
34
  <iframe
@@ -41,9 +44,6 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) =>
41
44
  overflow: hidden;
42
45
  width: 100%;
43
46
  height: 100%;
44
- top: 50%;
45
- left: 50%;
46
- transform: translate(-50%, -50%);
47
47
  }
48
48
  .embedYoutubeVideo {
49
49
  width: 100%;
@@ -9,7 +9,7 @@ export const useItemSticky = (top: number, parentOffsetTop: number, item: TArtic
9
9
  const [adjustedTop, setAdjustedTop] = useState(top);
10
10
  const articleRectObserver = useContext(ArticleRectContext);
11
11
  const layoutId = useCurrentLayout();
12
- const sticky = useMemo(() => item.layoutParams[layoutId].sticky, [layoutId]);
12
+ const sticky = useMemo(() => item.sticky[layoutId], [layoutId]);
13
13
  const stickyManager = useMemo(() => new StickyManager(sticky), [sticky]);
14
14
 
15
15
  const handleSticky = useCallback((scroll: number) => {
@@ -0,0 +1,15 @@
1
+ import { TArticleItemAny } from '@cntrl-site/sdk';
2
+ import { useKeyframeValue } from '../common/useKeyframeValue';
3
+ import { useCurrentLayout } from '../common/useCurrentLayout';
4
+
5
+ export const useItemScale = (item: TArticleItemAny) => {
6
+ const layout = useCurrentLayout();
7
+ const { scale } = useKeyframeValue(
8
+ item,
9
+ (item, layoutId) => ({ scale: layoutId ? item.area[layoutId].scale : 1 }),
10
+ (animator, scroll, value) => animator.getScale(value, scroll)
11
+ );
12
+ const scaleAnchor = item.area[layout].scaleAnchor;
13
+
14
+ return { scale, scaleAnchor };
15
+ };
@@ -178,6 +178,24 @@ export class Animator {
178
178
  };
179
179
  }
180
180
 
181
+ getScale(
182
+ values: TKeyframeValueMap[KeyframeType.Scale],
183
+ pos: number
184
+ ): TKeyframeValueMap[KeyframeType.Scale] {
185
+ const keyframes = this.keyframesMap[KeyframeType.Scale];
186
+ if (!keyframes || !keyframes.length) return values;
187
+ if (keyframes.length === 1) {
188
+ const [keyframe] = keyframes;
189
+ return {
190
+ scale: keyframe.value.scale
191
+ };
192
+ }
193
+ const { start, end } = this.getStartEnd<KeyframeType.Scale>(pos, keyframes);
194
+ return {
195
+ scale: rangeMap(pos, start.position, end.position, start.value.scale, end.value.scale, true)
196
+ };
197
+ }
198
+
181
199
  getStartEnd<T extends KeyframeType>(position: number, keyframes: AnimationData<T>[]): PositionKeyframes<T> {
182
200
  const index = binSearchInsertAt(keyframes, { position }, compare);
183
201
  const end = index === keyframes.length ? index - 1 : index;
@@ -215,7 +233,8 @@ function createKeyframesMap(): KeyframesMap {
215
233
  [KeyframeType.Color]: [],
216
234
  [KeyframeType.Rotation]: [],
217
235
  [KeyframeType.BorderColor]: [],
218
- [KeyframeType.Opacity]: []
236
+ [KeyframeType.Opacity]: [],
237
+ [KeyframeType.Scale]: []
219
238
  };
220
239
  }
221
240
 
@@ -0,0 +1,13 @@
1
+ import { ScaleAnchor } from '@cntrl-site/sdk';
2
+
3
+ export const ScaleAnchorMap = {
4
+ [ScaleAnchor.TopLeft]: 'top left',
5
+ [ScaleAnchor.TopCenter]: 'top center',
6
+ [ScaleAnchor.TopRight]: 'top right',
7
+ [ScaleAnchor.MiddleLeft]: 'center left',
8
+ [ScaleAnchor.MiddleCenter]: 'center',
9
+ [ScaleAnchor.MiddleRight]: 'center right',
10
+ [ScaleAnchor.BottomLeft]: 'bottom left',
11
+ [ScaleAnchor.BottomCenter]: 'bottom center',
12
+ [ScaleAnchor.BottomRight]: 'bottom right'
13
+ };
@@ -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>
Binary file