@cntrl-site/sdk-nextjs 1.1.5 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.idea/modules.xml +8 -0
  2. package/.idea/sdk-nextjs.iml +12 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/cntrl-site-sdk-nextjs-1.2.0.tgz +0 -0
  5. package/lib/components/Article.js +2 -2
  6. package/lib/components/{Section.js → Section/Section.js} +2 -2
  7. package/lib/components/{useSectionHeightMap.js → Section/useSectionHeightMap.js} +1 -1
  8. package/lib/components/items/{CodeEmbedItem.js → CodeEmbedItem/CodeEmbedItem.js} +2 -2
  9. package/lib/components/items/{useCodeEmbedItem.js → CodeEmbedItem/useCodeEmbedItem.js} +2 -2
  10. package/lib/components/items/CompoundItem/CompoundChild.js +95 -0
  11. package/lib/components/items/CompoundItem/CompoundItem.js +52 -0
  12. package/lib/components/items/CompoundItem/useCompoundItem.js +17 -0
  13. package/lib/components/items/{CustomItem.js → CustomItem/CustomItem.js} +2 -2
  14. package/lib/components/items/{VimeoEmbed.js → EmbedVideoItem/VimeoEmbed.js} +4 -4
  15. package/lib/components/items/{YoutubeEmbed.js → EmbedVideoItem/YoutubeEmbed.js} +5 -5
  16. package/lib/components/items/{useEmbedVideoItem.js → EmbedVideoItem/useEmbedVideoItem.js} +2 -2
  17. package/lib/components/items/{ImageItem.js → FileItem/ImageItem.js} +6 -6
  18. package/lib/components/items/{VideoItem.js → FileItem/VideoItem.js} +5 -5
  19. package/lib/components/items/{useFileItem.js → FileItem/useFileItem.js} +2 -2
  20. package/lib/components/items/{GroupItem.js → GroupItem/GroupItem.js} +5 -5
  21. package/lib/components/items/{useGroupItem.js → GroupItem/useGroupItem.js} +2 -2
  22. package/lib/components/{Item.js → items/Item.js} +39 -85
  23. package/lib/components/items/{RectangleItem.js → RectangleItem/RectangleItem.js} +3 -3
  24. package/lib/components/items/{useRectangleItem.js → RectangleItem/useRectangleItem.js} +2 -2
  25. package/lib/components/items/{RichTextItem.js → RichTextItem/RichTextItem.js} +7 -7
  26. package/lib/components/items/{useRichTextItem.js → RichTextItem/useRichTextItem.js} +2 -2
  27. package/lib/components/items/RichTextWrapper.js +10 -0
  28. package/lib/components/items/itemsMap.js +26 -0
  29. package/lib/components/{useItemAngle.js → items/useItemAngle.js} +1 -1
  30. package/lib/components/items/useItemArea.js +22 -0
  31. package/lib/components/items/useItemPointerEvents.js +14 -0
  32. package/lib/components/{useItemScale.js → items/useItemScale.js} +2 -2
  33. package/lib/components/items/useItemTriggers.js +17 -0
  34. package/lib/components/items/useSizing.js +23 -0
  35. package/lib/index.js +8 -8
  36. package/lib/interactions/InteractionsRegistry.js +6 -6
  37. package/lib/utils/RichTextConverter/RichTextConverter.js +1 -1
  38. package/lib/utils/getCompoundBondaryStyles.js +61 -0
  39. package/lib/utils/isItemType.js +7 -0
  40. package/package.json +2 -2
  41. package/src/components/Article.tsx +2 -2
  42. package/src/components/{Section.tsx → Section/Section.tsx} +2 -2
  43. package/src/components/{useSectionColor.ts → Section/useSectionColor.ts} +1 -1
  44. package/src/components/{useSectionHeightMap.ts → Section/useSectionHeightMap.ts} +1 -1
  45. package/src/components/items/{CodeEmbedItem.tsx → CodeEmbedItem/CodeEmbedItem.tsx} +2 -2
  46. package/src/components/items/{useCodeEmbedItem.ts → CodeEmbedItem/useCodeEmbedItem.ts} +2 -2
  47. package/src/components/items/CompoundItem/CompoundChild.tsx +130 -0
  48. package/src/components/items/CompoundItem/CompoundItem.tsx +70 -0
  49. package/src/components/items/CompoundItem/useCompoundItem.ts +21 -0
  50. package/src/components/items/{CustomItem.tsx → CustomItem/CustomItem.tsx} +2 -2
  51. package/src/components/items/{VimeoEmbed.tsx → EmbedVideoItem/VimeoEmbed.tsx} +5 -5
  52. package/src/components/items/{YoutubeEmbed.tsx → EmbedVideoItem/YoutubeEmbed.tsx} +6 -6
  53. package/src/components/items/{useEmbedVideoItem.ts → EmbedVideoItem/useEmbedVideoItem.ts} +2 -2
  54. package/src/components/items/{ImageItem.tsx → FileItem/ImageItem.tsx} +6 -6
  55. package/src/components/items/{VideoItem.tsx → FileItem/VideoItem.tsx} +5 -5
  56. package/src/components/items/{useFileItem.ts → FileItem/useFileItem.ts} +2 -2
  57. package/src/components/items/{GroupItem.tsx → GroupItem/GroupItem.tsx} +4 -5
  58. package/src/components/items/{useGroupItem.ts → GroupItem/useGroupItem.ts} +2 -2
  59. package/src/components/{Item.tsx → items/Item.tsx} +36 -105
  60. package/src/components/items/{RectangleItem.tsx → RectangleItem/RectangleItem.tsx} +3 -3
  61. package/src/components/items/{useRectangleItem.ts → RectangleItem/useRectangleItem.ts} +2 -2
  62. package/src/components/items/{RichTextItem.tsx → RichTextItem/RichTextItem.tsx} +7 -7
  63. package/src/components/items/{useRichTextItem.ts → RichTextItem/useRichTextItem.ts} +2 -2
  64. package/src/components/items/RichTextWrapper.tsx +15 -0
  65. package/src/components/items/itemsMap.ts +26 -0
  66. package/src/components/{useItemAngle.ts → items/useItemAngle.ts} +1 -1
  67. package/src/components/items/useItemArea.ts +35 -0
  68. package/src/components/items/useItemPointerEvents.ts +10 -0
  69. package/src/components/{useItemScale.ts → items/useItemScale.ts} +2 -2
  70. package/src/components/items/useItemTriggers.ts +15 -0
  71. package/src/components/items/useSizing.ts +25 -0
  72. package/src/index.ts +8 -8
  73. package/src/interactions/InteractionsRegistry.ts +6 -5
  74. package/src/utils/RichTextConverter/RichTextConverter.tsx +1 -1
  75. package/src/utils/getCompoundBondaryStyles.ts +62 -0
  76. package/src/utils/isItemType.ts +6 -0
  77. package/lib/components/useItemDimensions.js +0 -12
  78. package/lib/components/useItemPosition.js +0 -30
  79. package/src/components/useItemDimensions.ts +0 -16
  80. package/src/components/useItemPosition.ts +0 -37
  81. /package/lib/components/{LinkWrapper.js → items/LinkWrapper.js} +0 -0
  82. /package/src/components/{LinkWrapper.tsx → items/LinkWrapper.tsx} +0 -0
@@ -1,9 +1,9 @@
1
1
  import { getLayoutStyles, CodeEmbedItem as TCodeEmbedItem, AreaAnchor } from '@cntrl-site/sdk';
2
2
  import { FC, useEffect, useId, useState } from 'react';
3
- import { useCntrlContext } from '../../provider/useCntrlContext';
3
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
4
4
  import { ItemProps } from '../Item';
5
5
  import JSXStyle from 'styled-jsx/style';
6
- import { useRegisterResize } from "../../common/useRegisterResize";
6
+ import { useRegisterResize } from "../../../common/useRegisterResize";
7
7
  import { useItemAngle } from '../useItemAngle';
8
8
  import { LinkWrapper } from '../LinkWrapper';
9
9
  import { useCodeEmbedItem } from './useCodeEmbedItem';
@@ -1,6 +1,6 @@
1
1
  import { CodeEmbedItem, AreaAnchor, KeyframeType } from '@cntrl-site/sdk';
2
- import { useLayoutContext } from '../useLayoutContext';
3
- import { useKeyframeValue } from '../../common/useKeyframeValue';
2
+ import { useLayoutContext } from '../../useLayoutContext';
3
+ import { useKeyframeValue } from '../../../common/useKeyframeValue';
4
4
 
5
5
  export const useCodeEmbedItem = (item: CodeEmbedItem, sectionId: string) => {
6
6
  const layoutId = useLayoutContext();
@@ -0,0 +1,130 @@
1
+ import React, {
2
+ FC,
3
+ useEffect,
4
+ useId,
5
+ useRef,
6
+ } from 'react';
7
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
8
+ import { useLayoutContext } from '../../useLayoutContext';
9
+ import { useExemplary } from '../../../common/useExemplary';
10
+ import { useItemScale } from '../useItemScale';
11
+ import { useItemInteractionCtrl } from '../../../interactions/useItemInteractionCtrl';
12
+ import { ArticleItemType, getLayoutStyles, ItemAny, AreaAnchor } from '@cntrl-site/sdk';
13
+ import JSXStyle from 'styled-jsx/style';
14
+ import { ScaleAnchorMap } from '../../../utils/ScaleAnchorMap';
15
+ import { isItemType } from '../../../utils/isItemType';
16
+ import { RichTextWrapper } from '../RichTextWrapper';
17
+ import { itemsMap } from '../itemsMap';
18
+ import {
19
+ getCompoundHeight,
20
+ getCompoundLeft,
21
+ getCompoundTop, getCompoundTransform,
22
+ getCompoundWidth
23
+ } from '../../../utils/getCompoundBondaryStyles';
24
+ import { useItemTriggers } from '../useItemTriggers';
25
+ import { parseSizing, useSizing } from '../useSizing';
26
+ import { useItemPointerEvents } from '../useItemPointerEvents';
27
+ import { useItemArea } from '../useItemArea';
28
+
29
+ interface ChildItemProps {
30
+ item: ItemAny;
31
+ sectionId: string;
32
+ isParentVisible?: boolean;
33
+ }
34
+
35
+ const noop = () => null;
36
+
37
+ export const CompoundChild: FC<ChildItemProps> = ({ item, sectionId, isParentVisible = true }) => {
38
+ const id = useId();
39
+ const { layouts } = useCntrlContext();
40
+ const layout = useLayoutContext();
41
+ const exemplary = useExemplary();
42
+ const { handleVisibilityChange, allowPointerEvents } = useItemPointerEvents(isParentVisible);
43
+ const itemScale = useItemScale(item, sectionId);
44
+ const interactionCtrl = useItemInteractionCtrl(item.id);
45
+ const triggers = useItemTriggers(interactionCtrl);
46
+ const stateProps = interactionCtrl?.getState(['top', 'left', 'width', 'height', 'scale']);
47
+ const compoundSettings = layout && item.compoundSettings ? item.compoundSettings[layout] : undefined;
48
+ const { width, height, top, left } = useItemArea(item, sectionId, {
49
+ top: stateProps?.styles?.top as number,
50
+ left: stateProps?.styles?.left as number,
51
+ width: stateProps?.styles?.width as number,
52
+ height: stateProps?.styles?.height as number
53
+ });
54
+ const isInitialRef = useRef(true);
55
+ const sizingAxis = useSizing(item);
56
+ const ItemComponent = itemsMap[item.type] || noop;
57
+
58
+ useEffect(() => {
59
+ isInitialRef.current = false;
60
+ }, []);
61
+
62
+ const transformOrigin = compoundSettings ? ScaleAnchorMap[compoundSettings.positionAnchor] : 'top left';
63
+ const isRichText = isItemType(item, ArticleItemType.RichText);
64
+ const scale = stateProps?.styles?.scale ?? itemScale;
65
+ const hasClickTriggers = interactionCtrl?.getHasTrigger(item.id, 'click') ?? false;
66
+ if (!item.compoundSettings) return null;
67
+ const layoutValues: Record<string, any>[] = [item.area, item.hidden, item.compoundSettings];
68
+ if (item.layoutParams) {
69
+ layoutValues.push(item.layoutParams);
70
+ }
71
+ return (
72
+ <div
73
+ className={`item-${item.id}`}
74
+ onTransitionEnd={(e) => {
75
+ e.stopPropagation();
76
+ interactionCtrl?.handleTransitionEnd?.(e.propertyName);
77
+ }}
78
+ style={{
79
+ ...(top && compoundSettings ? { top: getCompoundTop(compoundSettings, top) } : {}),
80
+ ...(left && compoundSettings ? { left: getCompoundLeft(compoundSettings, left) } : {}),
81
+ ...(width && compoundSettings
82
+ ? { width: `${sizingAxis.x === 'manual'
83
+ ? getCompoundWidth(compoundSettings, width, isRichText, exemplary)
84
+ : 'max-content'}` }
85
+ : {}),
86
+ ...(height && compoundSettings
87
+ ? { height: `${sizingAxis.y === 'manual'
88
+ ? getCompoundHeight(compoundSettings, height)
89
+ : 'unset'}` }
90
+ : {}),
91
+ ...(scale && compoundSettings ? { transform: `scale(${scale}) ${getCompoundTransform(compoundSettings)}` } : {}),
92
+ transition: stateProps?.transition ?? 'none',
93
+ cursor: hasClickTriggers ? 'pointer' : 'unset',
94
+ pointerEvents: allowPointerEvents ? 'auto' : 'none'
95
+ }}
96
+ {...triggers}
97
+ >
98
+ <RichTextWrapper isRichText={isRichText} transformOrigin={transformOrigin}>
99
+ <ItemComponent
100
+ item={item}
101
+ sectionId={sectionId}
102
+ interactionCtrl={interactionCtrl}
103
+ onVisibilityChange={handleVisibilityChange}
104
+ />
105
+ </RichTextWrapper>
106
+ <JSXStyle id={id}>{`
107
+ ${getLayoutStyles(layouts, layoutValues, ([area, hidden, compoundSettings, layoutParams]) => {
108
+ const sizingAxis = parseSizing(layoutParams.sizing);
109
+ const scaleAnchor = area.scaleAnchor as AreaAnchor;
110
+ return (`
111
+ .item-${item.id} {
112
+ position: absolute;
113
+ top: ${getCompoundTop(compoundSettings, area.top)};
114
+ left: ${getCompoundLeft(compoundSettings, area.left)};
115
+ transition: opacity 0.2s linear 0.1s;
116
+ display: ${hidden ? 'none' : 'block'};
117
+ width: ${sizingAxis.x === 'manual'
118
+ ? `${getCompoundWidth(compoundSettings, area.width, isRichText)}`
119
+ : 'max-content'};
120
+ height: ${sizingAxis.y === 'manual' ? `${getCompoundHeight(compoundSettings, area.height)}` : 'unset'};
121
+ transform-origin: ${ScaleAnchorMap[scaleAnchor]};
122
+ transform: scale(${area.scale}) ${getCompoundTransform(compoundSettings)};
123
+ z-index: ${area.zIndex};
124
+ }
125
+ `);
126
+ })}
127
+ `}</JSXStyle>
128
+ </div>
129
+ );
130
+ };
@@ -0,0 +1,70 @@
1
+ import React, { FC, useEffect, useId, useState } from 'react';
2
+ import { useItemAngle } from '../useItemAngle';
3
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
4
+ import { useRegisterResize } from '../../../common/useRegisterResize';
5
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
6
+ import { LinkWrapper } from '../LinkWrapper';
7
+ import { ItemProps } from '../Item';
8
+ import JSXStyle from 'styled-jsx/style';
9
+ import { getLayoutStyles } from '@cntrl-site/sdk';
10
+ import { CompoundItem as TCompoundItem } from '@cntrl-site/sdk';
11
+ import { CompoundChild } from './CompoundChild';
12
+ import { useCompoundItem } from './useCompoundItem';
13
+
14
+ export const CompoundItem: FC<ItemProps<TCompoundItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
15
+ const id = useId();
16
+ const { items } = item;
17
+ const itemAngle = useItemAngle(item, sectionId);
18
+ const { layouts } = useCntrlContext();
19
+ const { opacity: itemOpacity } = useCompoundItem(item, sectionId);
20
+ const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
21
+ const [ref, setRef] = useState<HTMLDivElement | null>(null);
22
+ useRegisterResize(ref, onResize);
23
+ const stateParams = interactionCtrl?.getState(['opacity', 'angle']);
24
+ const angle = getStyleFromItemStateAndParams(stateParams?.styles?.angle, itemAngle);
25
+ const opacity = getStyleFromItemStateAndParams(stateParams?.styles?.opacity, itemOpacity);
26
+ const isInteractive = opacity !== 0 && opacity !== undefined;
27
+ useEffect(() => {
28
+ onVisibilityChange?.(isInteractive);
29
+ }, [isInteractive, onVisibilityChange]);
30
+ return (
31
+ <LinkWrapper url={item.link?.url} target={item.link?.target}>
32
+ <>
33
+ <div
34
+ className={`compound-${item.id}`}
35
+ ref={setRef}
36
+ style={{
37
+ ...(opacity !== undefined ? { opacity } : {}),
38
+ ...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
39
+ transition: stateParams?.transition ?? 'none'
40
+ }}
41
+ >
42
+ {items && items.map(item => (
43
+ <CompoundChild
44
+ item={item}
45
+ key={item.id}
46
+ sectionId={sectionId}
47
+ isParentVisible={isInteractive}
48
+ />
49
+ ))}
50
+ </div>
51
+ <JSXStyle id={id}>{`
52
+ .compound-${item.id} {
53
+ position: absolute;
54
+ width: 100%;
55
+ height: 100%;
56
+ box-sizing: border-box;
57
+ }
58
+ ${getLayoutStyles(layouts, layoutValues, ([area, layoutParams]) => {
59
+ return (`
60
+ .compound-${item.id} {
61
+ opacity: ${layoutParams.opacity};
62
+ transform: rotate(${area.angle}deg);
63
+ }
64
+ `);
65
+ })}
66
+ `}</JSXStyle>
67
+ </>
68
+ </LinkWrapper>
69
+ );
70
+ };
@@ -0,0 +1,21 @@
1
+ import { CompoundItem, KeyframeType } from '@cntrl-site/sdk';
2
+ import { useLayoutContext } from '../../useLayoutContext';
3
+ import { useKeyframeValue } from '../../../common/useKeyframeValue';
4
+
5
+ export function useCompoundItem(item: CompoundItem, sectionId: string) {
6
+ const layoutId = useLayoutContext();
7
+ const opacity = useKeyframeValue(
8
+ item,
9
+ KeyframeType.Opacity,
10
+ (item, layoutId) => {
11
+ if (!layoutId) return;
12
+ const layoutParams = item.layoutParams[layoutId];
13
+ return 'opacity' in layoutParams ? layoutParams.opacity : 1;
14
+ },
15
+ (animator, scroll, value) => value !== undefined ? animator.getOpacity({ opacity: value }, scroll).opacity : undefined,
16
+ sectionId,
17
+ [layoutId]
18
+ );
19
+
20
+ return { opacity };
21
+ }
@@ -1,9 +1,9 @@
1
1
  import { getLayoutStyles, CustomItem as TCustomItem } from '@cntrl-site/sdk';
2
2
  import { FC, useState } from 'react';
3
- import { useCntrlContext } from '../../provider/useCntrlContext';
3
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
4
4
  import { ItemProps } from '../Item';
5
5
  import JSXStyle from 'styled-jsx/style';
6
- import { useRegisterResize } from '../../common/useRegisterResize';
6
+ import { useRegisterResize } from '../../../common/useRegisterResize';
7
7
  import { useItemAngle } from '../useItemAngle';
8
8
 
9
9
  export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, sectionId, interactionCtrl }) => {
@@ -1,16 +1,16 @@
1
1
  import type { VimeoEmbedItem as TVimeoEmbedItem } from '@cntrl-site/sdk';
2
+ import { getLayoutStyles } from '@cntrl-site/sdk';
2
3
  import type { FC } from 'react';
3
4
  import type { ItemProps } from '../Item';
4
- import { getLayoutStyles } from '@cntrl-site/sdk';
5
5
  import Player from '@vimeo/player';
6
6
  import { useEffect, useId, useMemo, useState } from 'react';
7
7
  import JSXStyle from 'styled-jsx/style';
8
- import { useRegisterResize } from '../../common/useRegisterResize';
9
- import { useCntrlContext } from '../../provider/useCntrlContext';
10
- import { getStyleFromItemStateAndParams } from '../../utils/getStyleFromItemStateAndParams';
11
- import { LinkWrapper } from '../LinkWrapper';
12
8
  import { useItemAngle } from '../useItemAngle';
9
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
10
+ import { useRegisterResize } from "../../../common/useRegisterResize";
11
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
13
12
  import { useEmbedVideoItem } from './useEmbedVideoItem';
13
+ import { LinkWrapper } from '../LinkWrapper';
14
14
 
15
15
  export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
16
16
  const id = useId();
@@ -2,15 +2,15 @@ import { FC, useEffect, useId, useState } from 'react';
2
2
  import JSXStyle from 'styled-jsx/style';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
- import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
5
+ import { getYoutubeId } from '../../../utils/getValidYoutubeUrl';
6
6
  import { useEmbedVideoItem } from './useEmbedVideoItem';
7
7
  import { useItemAngle } from '../useItemAngle';
8
8
  import { getLayoutStyles, YoutubeEmbedItem as TYoutubeEmbedItem } from '@cntrl-site/sdk';
9
- import { useCntrlContext } from '../../provider/useCntrlContext';
10
- import { useYouTubeIframeApi } from '../../utils/Youtube/useYouTubeIframeApi';
11
- import { YTPlayer } from '../../utils/Youtube/YoutubeIframeApi';
12
- import { useRegisterResize } from "../../common/useRegisterResize";
13
- import { getStyleFromItemStateAndParams } from '../../utils/getStyleFromItemStateAndParams';
9
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
10
+ import { useYouTubeIframeApi } from '../../../utils/Youtube/useYouTubeIframeApi';
11
+ import { YTPlayer } from '../../../utils/Youtube/YoutubeIframeApi';
12
+ import { useRegisterResize } from "../../../common/useRegisterResize";
13
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
14
14
 
15
15
  export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
16
16
  const id = useId();
@@ -1,6 +1,6 @@
1
1
  import { KeyframeType, VimeoEmbedItem, YoutubeEmbedItem } from '@cntrl-site/sdk';
2
- import { useKeyframeValue } from '../../common/useKeyframeValue';
3
- import { useLayoutContext } from '../useLayoutContext';
2
+ import { useKeyframeValue } from '../../../common/useKeyframeValue';
3
+ import { useLayoutContext } from '../../useLayoutContext';
4
4
 
5
5
  export const useEmbedVideoItem = (item: VimeoEmbedItem | YoutubeEmbedItem, sectionId: string) => {
6
6
  const layoutId = useLayoutContext();
@@ -6,12 +6,12 @@ import { ItemProps } from '../Item';
6
6
  import { LinkWrapper } from '../LinkWrapper';
7
7
  import { useFileItem } from './useFileItem';
8
8
  import { useItemAngle } from '../useItemAngle';
9
- import { useCntrlContext } from '../../provider/useCntrlContext';
10
- import { useRegisterResize } from "../../common/useRegisterResize";
11
- import { useImageFx } from '../../utils/effects/useImageFx';
12
- import { useElementRect } from '../../utils/useElementRect';
13
- import { useLayoutContext } from '../useLayoutContext';
14
- import { getStyleFromItemStateAndParams } from '../../utils/getStyleFromItemStateAndParams';
9
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
10
+ import { useRegisterResize } from "../../../common/useRegisterResize";
11
+ import { useImageFx } from '../../../utils/effects/useImageFx';
12
+ import { useElementRect } from '../../../utils/useElementRect';
13
+ import { useLayoutContext } from '../../useLayoutContext';
14
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
15
15
 
16
16
  const baseVariables = `precision mediump float;
17
17
  uniform sampler2D u_image;
@@ -6,11 +6,11 @@ import { ItemProps } from '../Item';
6
6
  import { LinkWrapper } from '../LinkWrapper';
7
7
  import { useFileItem } from './useFileItem';
8
8
  import { useItemAngle } from '../useItemAngle';
9
- import { useCntrlContext } from '../../provider/useCntrlContext';
10
- import { useRegisterResize } from "../../common/useRegisterResize";
11
- import { useLayoutContext } from '../useLayoutContext';
12
- import { ScrollPlaybackVideo } from '../ScrollPlaybackVideo';
13
- import { getStyleFromItemStateAndParams } from '../../utils/getStyleFromItemStateAndParams';
9
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
10
+ import { useRegisterResize } from "../../../common/useRegisterResize";
11
+ import { useLayoutContext } from '../../useLayoutContext';
12
+ import { ScrollPlaybackVideo } from '../../ScrollPlaybackVideo';
13
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
14
14
 
15
15
  export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
16
16
  const id = useId();
@@ -1,6 +1,6 @@
1
1
  import { ImageItem, KeyframeType, VideoItem } from '@cntrl-site/sdk';
2
- import { useKeyframeValue } from '../../common/useKeyframeValue';
3
- import { useLayoutContext } from '../useLayoutContext';
2
+ import { useKeyframeValue } from '../../../common/useKeyframeValue';
3
+ import { useLayoutContext } from '../../useLayoutContext';
4
4
 
5
5
  const DEFAULT_COLOR = 'rgba(0, 0, 0, 1)';
6
6
  export const useFileItem = (item: ImageItem | VideoItem, sectionId: string) => {
@@ -3,13 +3,13 @@ import { Item, ItemProps } from '../Item';
3
3
  import JSXStyle from 'styled-jsx/style';
4
4
  import { getLayoutStyles, GroupItem as TGroupItem } from '@cntrl-site/sdk';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
- import { useRegisterResize } from '../../common/useRegisterResize';
7
- import { useCntrlContext } from '../../provider/useCntrlContext';
6
+ import { useRegisterResize } from '../../../common/useRegisterResize';
7
+ import { useCntrlContext } from '../../../provider/useCntrlContext';
8
8
  import { useItemAngle } from '../useItemAngle';
9
9
  import { useGroupItem } from './useGroupItem';
10
- import { getStyleFromItemStateAndParams } from '../../utils/getStyleFromItemStateAndParams';
10
+ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
11
11
 
12
- export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize, articleHeight, interactionCtrl, onVisibilityChange }) => {
12
+ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
13
13
  const id = useId();
14
14
  const { items } = item;
15
15
  const itemAngle = useItemAngle(item, sectionId);
@@ -42,7 +42,6 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
42
42
  item={item}
43
43
  key={item.id}
44
44
  sectionId={sectionId}
45
- articleHeight={articleHeight}
46
45
  isParentVisible={isInteractive}
47
46
  isInGroup
48
47
  />
@@ -1,6 +1,6 @@
1
- import { useKeyframeValue } from '../../common/useKeyframeValue';
1
+ import { useKeyframeValue } from '../../../common/useKeyframeValue';
2
2
  import { GroupItem, KeyframeType } from '@cntrl-site/sdk';
3
- import { useLayoutContext } from '../useLayoutContext';
3
+ import { useLayoutContext } from '../../useLayoutContext';
4
4
 
5
5
  export function useGroupItem(item: GroupItem, sectionId: string) {
6
6
  const layoutId = useLayoutContext();
@@ -1,10 +1,6 @@
1
- import {
2
- ComponentType,
1
+ import React, {
3
2
  FC,
4
- PropsWithChildren,
5
- useCallback,
6
3
  useContext,
7
- useEffect,
8
4
  useId,
9
5
  useMemo,
10
6
  useRef,
@@ -15,39 +11,34 @@ import {
15
11
  AnchorSide,
16
12
  ArticleItemType,
17
13
  getLayoutStyles,
18
- Item as TItem,
19
14
  ItemAny,
20
15
  PositionType
21
16
  } from '@cntrl-site/sdk';
22
- import { RectangleItem } from './items/RectangleItem';
23
- import { ImageItem } from './items/ImageItem';
24
- import { VideoItem } from './items/VideoItem';
25
- import { RichTextItem } from './items/RichTextItem';
26
- import { VimeoEmbedItem } from './items/VimeoEmbed';
27
- import { YoutubeEmbedItem } from './items/YoutubeEmbed';
28
- import { CustomItem } from './items/CustomItem';
29
- import { useCntrlContext } from '../provider/useCntrlContext';
30
- import { useItemPosition } from './useItemPosition';
31
- import { useItemDimensions } from './useItemDimensions';
17
+ import { useCntrlContext } from '../../provider/useCntrlContext';
32
18
  import { useItemScale } from './useItemScale';
33
- import { ScaleAnchorMap } from '../utils/ScaleAnchorMap';
34
- import { useSectionHeightData } from './useSectionHeightMap';
35
- import { getItemTopStyle } from '../utils/getItemTopStyle';
36
- import { useStickyItemTop } from './items/useStickyItemTop';
37
- import { getAnchoredItemTop } from '../utils/getAnchoredItemTop';
38
- import { useLayoutContext } from './useLayoutContext';
39
- import { ArticleRectContext } from "../provider/ArticleRectContext";
40
- import { useExemplary } from "../common/useExemplary";
41
- import { GroupItem } from './items/GroupItem';
42
- import { CodeEmbedItem } from './items/CodeEmbedItem';
19
+ import { ScaleAnchorMap } from '../../utils/ScaleAnchorMap';
20
+ import { useSectionHeightData } from '../Section/useSectionHeightMap';
21
+ import { getItemTopStyle } from '../../utils/getItemTopStyle';
22
+ import { useStickyItemTop } from './useStickyItemTop';
23
+ import { getAnchoredItemTop } from '../../utils/getAnchoredItemTop';
24
+ import { useLayoutContext } from '../useLayoutContext';
25
+ import { ArticleRectContext } from "../../provider/ArticleRectContext";
26
+ import { useExemplary } from "../../common/useExemplary";
43
27
  import { AreaAnchor } from '@cntrl-site/sdk/src/types/article/ItemArea';
44
- import { KeyframesContext } from '../provider/KeyframesContext';
45
- import { useItemInteractionCtrl } from '../interactions/useItemInteractionCtrl';
28
+ import { KeyframesContext } from '../../provider/KeyframesContext';
29
+ import { useItemInteractionCtrl } from '../../interactions/useItemInteractionCtrl';
30
+ import { isItemType } from '../../utils/isItemType';
31
+ import { RichTextWrapper } from './RichTextWrapper';
32
+ import { itemsMap } from './itemsMap';
33
+ import { useItemTriggers } from './useItemTriggers';
34
+ import { parseSizing, useSizing } from './useSizing';
35
+ import { useItemPointerEvents } from './useItemPointerEvents';
36
+ import { useItemArea } from './useItemArea';
46
37
 
47
38
  export interface ItemProps<I extends ItemAny> {
48
39
  item: I;
49
40
  sectionId: string;
50
- articleHeight: number;
41
+ articleHeight?: number;
51
42
  onResize?: (height: number) => void;
52
43
  interactionCtrl?: ReturnType<typeof useItemInteractionCtrl>;
53
44
  onVisibilityChange: (isVisible: boolean) => void;
@@ -56,41 +47,16 @@ export interface ItemProps<I extends ItemAny> {
56
47
  export interface ItemWrapperProps {
57
48
  item: ItemAny;
58
49
  sectionId: string;
59
- articleHeight: number;
50
+ articleHeight?: number;
60
51
  isInGroup?: boolean;
61
52
  isParentVisible?: boolean;
62
53
  }
63
54
 
64
- const itemsMap: Record<ArticleItemType, ComponentType<ItemProps<any>>> = {
65
- [ArticleItemType.Rectangle]: RectangleItem,
66
- [ArticleItemType.Image]: ImageItem,
67
- [ArticleItemType.Video]: VideoItem,
68
- [ArticleItemType.RichText]: RichTextItem,
69
- [ArticleItemType.YoutubeEmbed]: YoutubeEmbedItem,
70
- [ArticleItemType.VimeoEmbed]: VimeoEmbedItem,
71
- [ArticleItemType.Custom]: CustomItem,
72
- [ArticleItemType.Group]: GroupItem,
73
- [ArticleItemType.CodeEmbed]: CodeEmbedItem
74
- };
75
-
76
- interface RTWrapperProps {
77
- isRichText: boolean;
78
- }
79
-
80
55
  const stickyFix = `
81
56
  -webkit-transform: translate3d(0, 0, 0);
82
57
  transform: translate3d(0, 0, 0);
83
58
  `;
84
59
 
85
- const RichTextWrapper: FC<PropsWithChildren<RTWrapperProps>> = ({ isRichText, children }) => {
86
- if (!isRichText) return <>{children}</>;
87
- return (
88
- <div style={{ transformOrigin: 'top left', transform: 'scale(var(--layout-deviation))' }}>
89
- {children}
90
- </div>
91
- );
92
- };
93
-
94
60
  const noop = () => null;
95
61
 
96
62
  export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false }) => {
@@ -103,38 +69,36 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
103
69
  const { layouts } = useCntrlContext();
104
70
  const layout = useLayoutContext();
105
71
  const exemplary = useExemplary();
106
- const [allowPointerEvents, setAllowPointerEvents] = useState<boolean>(isParentVisible);
72
+ const { handleVisibilityChange, allowPointerEvents } = useItemPointerEvents(isParentVisible);
107
73
  const [wrapperHeight, setWrapperHeight] = useState<undefined | number>(undefined);
108
74
  const [itemHeight, setItemHeight] = useState<undefined | number>(undefined);
109
75
  const itemScale = useItemScale(item, sectionId);
110
76
  const interactionCtrl = useItemInteractionCtrl(item.id);
77
+ const triggers = useItemTriggers(interactionCtrl);
111
78
  const wrapperStateProps = interactionCtrl?.getState(['top', 'left']);
112
- const innerStateProps = interactionCtrl?.getState(['width', 'height', 'scale']);
113
- const position = useItemPosition(item, sectionId, {
79
+ const innerStateProps = interactionCtrl?.getState(['width', 'height', 'scale', 'top', 'left']);
80
+ const { width, height, top, left } = useItemArea(item, sectionId, {
114
81
  top: wrapperStateProps?.styles?.top as number,
115
82
  left: wrapperStateProps?.styles?.left as number,
83
+ width: innerStateProps?.styles?.width as number,
84
+ height: innerStateProps?.styles?.height as number
116
85
  });
117
86
  const sectionHeight = useSectionHeightData(sectionId);
118
87
  const stickyTop = useStickyItemTop(item, sectionHeight, sectionId);
119
- const dimensions = useItemDimensions(item, sectionId);
120
88
  const layoutValues: Record<string, any>[] = [item.area, item.hidden];
121
- const isInitialRef = useRef(true);
122
89
  layoutValues.push(item.sticky);
123
90
  layoutValues.push(sectionHeight);
124
91
  if (item.layoutParams) {
125
92
  layoutValues.push(item.layoutParams);
126
93
  }
127
- const sizing = layout && isItemType(item, ArticleItemType.RichText)
128
- ? item.layoutParams[layout].sizing
129
- : undefined;
130
- const sizingAxis = parseSizing(sizing);
94
+ const sizingAxis = useSizing(item);
131
95
  const ItemComponent = itemsMap[item.type] || noop;
132
96
  const sectionTop = rectObserver ? rectObserver.getSectionTop(sectionId) : 0;
133
97
 
134
98
  const handleItemResize = (height: number) => {
135
99
  if (!layout) return;
136
100
  const sticky = item.sticky[layout];
137
- if (!sticky || stickyTop === undefined) {
101
+ if (!sticky || stickyTop === undefined || !articleHeight) {
138
102
  setWrapperHeight(undefined);
139
103
  return;
140
104
  }
@@ -148,18 +112,10 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
148
112
  setWrapperHeight(wrapperHeight);
149
113
  };
150
114
 
151
- const handleVisibilityChange = useCallback((isVisible: boolean) => {
152
- if (!isParentVisible) return;
153
- setAllowPointerEvents(isVisible);
154
- }, [isParentVisible]);
155
-
156
- useEffect(() => {
157
- isInitialRef.current = false;
158
- }, []);
159
-
160
115
  const isRichText = isItemType(item, ArticleItemType.RichText);
161
- const width = (innerStateProps?.styles?.width ?? dimensions?.width) as number | undefined;
162
- const height = (innerStateProps?.styles?.height ?? dimensions?.height) as number | undefined;
116
+ const anchorSide = layout ? item.area[layout].anchorSide : AnchorSide.Top;
117
+ const positionType = layout ? item.area[layout].positionType : PositionType.ScreenBased;
118
+ const isScreenBasedBottom = positionType === PositionType.ScreenBased && anchorSide === AnchorSide.Bottom;
163
119
  const scale = innerStateProps?.styles?.scale ?? itemScale;
164
120
  const hasClickTriggers = interactionCtrl?.getHasTrigger(item.id, 'click') ?? false;
165
121
  return (
@@ -171,9 +127,9 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
171
127
  interactionCtrl?.handleTransitionEnd?.(e.propertyName);
172
128
  }}
173
129
  style={{
174
- ...(position ? { top: position.top } : {}),
175
- ...(position ? { left: position.left } : {}),
176
- ...(position ? { bottom: position.bottom } : {}),
130
+ ...(top ? { top: isScreenBasedBottom ? 'unset' : getItemTopStyle(top, anchorSide) } : {}),
131
+ ...(left ? { left: `${left * 100}vw` } : {}),
132
+ ...(top ? { bottom: isScreenBasedBottom ? `${-top * 100}vw` : 'unset' } : {}),
177
133
  ...(wrapperHeight !== undefined ? { height: `${wrapperHeight * 100}vw` } : {}),
178
134
  transition: wrapperStateProps?.transition ?? 'none'
179
135
  }}
@@ -191,15 +147,6 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
191
147
  <div
192
148
  className={`item-${item.id}-inner`}
193
149
  ref={itemInnerRef}
194
- onClick={() => {
195
- interactionCtrl?.sendTrigger('click');
196
- }}
197
- onMouseEnter={() => {
198
- interactionCtrl?.sendTrigger('hover-in');
199
- }}
200
- onMouseLeave={() => {
201
- interactionCtrl?.sendTrigger('hover-out');
202
- }}
203
150
  style={{
204
151
  ...((width && height) ? {
205
152
  width: `${sizingAxis.x === 'manual'
@@ -213,6 +160,7 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
213
160
  cursor: hasClickTriggers ? 'pointer' : 'unset',
214
161
  pointerEvents: allowPointerEvents ? 'auto' : 'none'
215
162
  }}
163
+ {...triggers}
216
164
  >
217
165
  <ItemComponent
218
166
  item={item}
@@ -262,20 +210,3 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
262
210
  </div>
263
211
  );
264
212
  };
265
-
266
- function parseSizing(sizing: string = 'manual'): Axis {
267
- const axisSizing = sizing.split(' ');
268
- return {
269
- y: axisSizing[0],
270
- x: axisSizing[1] ? axisSizing[1] : axisSizing[0]
271
- } as Axis;
272
- }
273
-
274
- export function isItemType<T extends ArticleItemType>(item: ItemAny, itemType: T): item is TItem<T> {
275
- return item.type === itemType;
276
- }
277
-
278
- interface Axis {
279
- x: 'manual' | 'auto';
280
- y: 'manual' | 'auto';
281
- }