@cntrl-site/sdk-nextjs 0.11.1 → 0.12.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.
- package/lib/common/useKeyframeValue.js +10 -10
- package/lib/components/Article.js +1 -1
- package/lib/components/Item.js +6 -15
- package/lib/components/Section.js +4 -1
- package/lib/components/items/ImageItem.js +3 -3
- package/lib/components/items/RectangleItem.js +25 -13
- package/lib/components/items/RichTextItem.js +2 -2
- package/lib/components/items/VideoItem.js +3 -3
- package/lib/components/items/VimeoEmbed.js +3 -3
- package/lib/components/items/YoutubeEmbed.js +3 -3
- package/lib/components/items/useEmbedVideoItem.js +2 -2
- package/lib/components/items/useFileItem.js +5 -5
- package/lib/components/items/useItemSticky.js +5 -5
- package/lib/components/items/useRectangleItem.js +5 -5
- package/lib/components/useItemAngle.js +2 -2
- package/lib/components/useItemDimensions.js +2 -2
- package/lib/components/useItemPosition.js +2 -2
- package/lib/components/useItemScale.js +2 -2
- package/lib/utils/ArticleRectManager/ArticleRectObserver.js +36 -18
- package/lib/utils/ArticleRectManager/useArticleRectObserver.js +1 -1
- package/lib/utils/ArticleRectManager/useSectionRegistry.js +14 -0
- package/lib/utils/StickyManager/StickyManager.js +2 -2
- package/package.json +2 -2
- package/src/common/useKeyframeValue.ts +10 -9
- package/src/components/Article.tsx +1 -1
- package/src/components/Item.tsx +8 -17
- package/src/components/Section.tsx +5 -1
- package/src/components/items/ImageItem.tsx +3 -3
- package/src/components/items/RectangleItem.tsx +26 -14
- package/src/components/items/RichTextItem.tsx +2 -2
- package/src/components/items/VideoItem.tsx +3 -3
- package/src/components/items/VimeoEmbed.tsx +3 -3
- package/src/components/items/YoutubeEmbed.tsx +3 -3
- package/src/components/items/useEmbedVideoItem.ts +2 -1
- package/src/components/items/useFileItem.ts +7 -3
- package/src/components/items/useItemSticky.ts +5 -6
- package/src/components/items/useRectangleItem.ts +6 -2
- package/src/components/useItemAngle.ts +3 -2
- package/src/components/useItemDimensions.ts +2 -1
- package/src/components/useItemPosition.ts +2 -1
- package/src/components/useItemScale.ts +3 -2
- package/src/utils/ArticleRectManager/ArticleRectObserver.ts +32 -15
- package/src/utils/ArticleRectManager/useArticleRectObserver.ts +1 -1
- package/src/utils/ArticleRectManager/useSectionRegistry.ts +11 -0
- package/src/utils/StickyManager/StickyManager.ts +2 -2
- package/.idea/inspectionProfiles/Project_Default.xml +0 -15
- package/cntrl-site-sdk-nextjs-0.10.2.tgz +0 -0
- package/cntrl-site-sdk-nextjs-0.11.1.tgz +0 -0
- package/lib/utils/castObject.js +0 -10
|
@@ -24,7 +24,7 @@ export const Article: FC<Props> = ({ article, sectionData }) => {
|
|
|
24
24
|
return (
|
|
25
25
|
<Section section={section} key={section.id} data={data}>
|
|
26
26
|
{article.sections[i].items.map(item => (
|
|
27
|
-
<Item item={item} key={item.id} />
|
|
27
|
+
<Item item={item} key={item.id} sectionId={section.id} />
|
|
28
28
|
))}
|
|
29
29
|
</Section>
|
|
30
30
|
);
|
package/src/components/Item.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType, FC, useEffect, useId, useRef
|
|
1
|
+
import { ComponentType, FC, useEffect, useId, useRef } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import {
|
|
4
4
|
ArticleItemSizingType as SizingType,
|
|
@@ -18,13 +18,13 @@ import { useCntrlContext } from '../provider/useCntrlContext';
|
|
|
18
18
|
import { useItemPosition } from './useItemPosition';
|
|
19
19
|
import { useItemDimensions } from './useItemDimensions';
|
|
20
20
|
import { getItemTopStyle, useItemSticky } from './items/useItemSticky';
|
|
21
|
-
import { castObject } from '../utils/castObject';
|
|
22
21
|
import { useCurrentLayout } from '../common/useCurrentLayout';
|
|
23
22
|
import { useItemScale } from './useItemScale';
|
|
24
23
|
import { ScaleAnchorMap } from '../utils/ScaleAnchorMap';
|
|
25
24
|
|
|
26
25
|
export interface ItemProps<I extends TArticleItemAny> {
|
|
27
26
|
item: I;
|
|
27
|
+
sectionId: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const itemsMap: Record<ArticleItemType, ComponentType<ItemProps<any>>> = {
|
|
@@ -39,16 +39,14 @@ const itemsMap: Record<ArticleItemType, ComponentType<ItemProps<any>>> = {
|
|
|
39
39
|
|
|
40
40
|
const noop = () => null;
|
|
41
41
|
|
|
42
|
-
export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
|
|
42
|
+
export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, sectionId}) => {
|
|
43
43
|
const id = useId();
|
|
44
44
|
const { layouts } = useCntrlContext();
|
|
45
|
-
const { scale, scaleAnchor } = useItemScale(item);
|
|
46
|
-
const position = useItemPosition(item);
|
|
45
|
+
const { scale, scaleAnchor } = useItemScale(item, sectionId);
|
|
46
|
+
const position = useItemPosition(item, sectionId);
|
|
47
47
|
const layout = useCurrentLayout();
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const { top, isFixed } = useItemSticky(position.top, parentOffsetTop, item);
|
|
51
|
-
const { width, height } = useItemDimensions(item);
|
|
48
|
+
const { top, isFixed } = useItemSticky(position.top, item, sectionId);
|
|
49
|
+
const { width, height } = useItemDimensions(item, sectionId);
|
|
52
50
|
const layoutValues: Record<string, any>[] = [item.area];
|
|
53
51
|
const isInitialRef = useRef(true);
|
|
54
52
|
if (item.layoutParams) {
|
|
@@ -65,12 +63,6 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
|
|
|
65
63
|
isInitialRef.current = false;
|
|
66
64
|
}, []);
|
|
67
65
|
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (!ref) return;
|
|
70
|
-
const offsetParent = castObject(ref.offsetParent, HTMLElement);
|
|
71
|
-
setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
|
|
72
|
-
}, [ref]);
|
|
73
|
-
|
|
74
66
|
const styles = {
|
|
75
67
|
transform: `scale(${scale})`,
|
|
76
68
|
transformOrigin: ScaleAnchorMap[scaleAnchor],
|
|
@@ -84,10 +76,9 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
|
|
|
84
76
|
<div
|
|
85
77
|
suppressHydrationWarning={true}
|
|
86
78
|
className={`item-${item.id}`}
|
|
87
|
-
ref={setRef}
|
|
88
79
|
style={isInitialRef.current ? {} : { ...styles, position: isFixed ? 'fixed': 'absolute' } }
|
|
89
80
|
>
|
|
90
|
-
<ItemComponent item={item} />
|
|
81
|
+
<ItemComponent item={item} sectionId={sectionId} />
|
|
91
82
|
<JSXStyle id={id}>{`
|
|
92
83
|
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams]) => {
|
|
93
84
|
const sizingAxis = parseSizing(layoutParams.sizing);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC, ReactElement, useId } from 'react';
|
|
1
|
+
import { FC, ReactElement, useId, useRef } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import {
|
|
4
4
|
getLayoutMediaQuery,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '@cntrl-site/sdk';
|
|
10
10
|
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
11
11
|
import { useSectionColor } from './useSectionColor';
|
|
12
|
+
import { useSectionRegistry } from '../utils/ArticleRectManager/useSectionRegistry';
|
|
12
13
|
|
|
13
14
|
type SectionChild = ReactElement<any, any>;
|
|
14
15
|
|
|
@@ -20,9 +21,11 @@ interface Props {
|
|
|
20
21
|
|
|
21
22
|
export const Section: FC<Props> = ({ section, data, children }) => {
|
|
22
23
|
const id = useId();
|
|
24
|
+
const sectionRef = useRef<HTMLDivElement | null>(null);
|
|
23
25
|
const { layouts, customSections } = useCntrlContext();
|
|
24
26
|
const backgroundColor = useSectionColor(section.color);
|
|
25
27
|
const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
|
|
28
|
+
useSectionRegistry(section.id, sectionRef.current);
|
|
26
29
|
const getSectionVisibilityStyles = () => {
|
|
27
30
|
return layouts
|
|
28
31
|
.sort((a, b) => a.startsWith - b.startsWith)
|
|
@@ -48,6 +51,7 @@ export const Section: FC<Props> = ({ section, data, children }) => {
|
|
|
48
51
|
style={{
|
|
49
52
|
backgroundColor: backgroundColor
|
|
50
53
|
}}
|
|
54
|
+
ref={sectionRef}
|
|
51
55
|
>
|
|
52
56
|
{children}
|
|
53
57
|
</div>
|
|
@@ -6,10 +6,10 @@ import { LinkWrapper } from '../LinkWrapper';
|
|
|
6
6
|
import { useFileItem } from './useFileItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
8
|
|
|
9
|
-
export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
|
|
9
|
+
export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId }) => {
|
|
10
10
|
const id = useId();
|
|
11
|
-
const { radius, strokeWidth, opacity, strokeColor } = useFileItem(item);
|
|
12
|
-
const angle = useItemAngle(item);
|
|
11
|
+
const { radius, strokeWidth, opacity, strokeColor } = useFileItem(item, sectionId);
|
|
12
|
+
const angle = useItemAngle(item, sectionId);
|
|
13
13
|
const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
|
|
14
14
|
return (
|
|
15
15
|
<LinkWrapper url={item.link?.url}>
|
|
@@ -6,33 +6,45 @@ import { LinkWrapper } from '../LinkWrapper';
|
|
|
6
6
|
import { useRectangleItem } from './useRectangleItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
8
|
|
|
9
|
-
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item }) => {
|
|
9
|
+
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId }) => {
|
|
10
10
|
const id = useId();
|
|
11
|
-
const { fillColor, radius, strokeWidth, strokeColor } = useRectangleItem(item);
|
|
12
|
-
const angle = useItemAngle(item);
|
|
13
|
-
const backgroundColor = useMemo(() => CntrlColor.parse(fillColor)
|
|
14
|
-
const borderColor = useMemo(() => CntrlColor.parse(strokeColor)
|
|
11
|
+
const { fillColor, radius, strokeWidth, strokeColor } = useRectangleItem(item, sectionId);
|
|
12
|
+
const angle = useItemAngle(item, sectionId);
|
|
13
|
+
const backgroundColor = useMemo(() => CntrlColor.parse(fillColor), [fillColor]);
|
|
14
|
+
const borderColor = useMemo(() => CntrlColor.parse(strokeColor), [strokeColor]);
|
|
15
15
|
|
|
16
16
|
return (
|
|
17
17
|
<LinkWrapper url={item.link?.url}>
|
|
18
18
|
<>
|
|
19
|
-
<div
|
|
19
|
+
<div className={`rectangle-${item.id}`}
|
|
20
20
|
style={{
|
|
21
|
-
backgroundColor: `${backgroundColor}`,
|
|
21
|
+
backgroundColor: `${backgroundColor.toCss()}`,
|
|
22
22
|
borderRadius: `${radius * 100}vw`,
|
|
23
23
|
borderWidth: `${strokeWidth * 100}vw`,
|
|
24
|
-
borderColor: `${borderColor}`,
|
|
24
|
+
borderColor: `${borderColor.toCss()}`,
|
|
25
25
|
transform: `rotate(${angle}deg)`
|
|
26
26
|
}}
|
|
27
27
|
/>
|
|
28
28
|
<JSXStyle id={id}>{`
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
border-style: solid;
|
|
34
|
-
box-sizing: border-box;
|
|
29
|
+
@supports (color: oklch(42% 0.3 90 / 1)) {
|
|
30
|
+
.rectangle-${item.id} {
|
|
31
|
+
background-color: ${backgroundColor.fmt('oklch')};
|
|
32
|
+
border-color: ${borderColor.fmt('oklch')};
|
|
35
33
|
}
|
|
34
|
+
}
|
|
35
|
+
@supports not (color: oklch(42% 0.3 90 / 1)) {
|
|
36
|
+
.rectangle-${item.id} {
|
|
37
|
+
background-color: ${backgroundColor.fmt('rgba')};
|
|
38
|
+
border-color: ${borderColor.fmt('rgba')};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
.rectangle-${item.id} {
|
|
42
|
+
position: absolute;
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
45
|
+
border-style: solid;
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
}
|
|
36
48
|
`}</JSXStyle>
|
|
37
49
|
</>
|
|
38
50
|
</LinkWrapper>
|
|
@@ -5,9 +5,9 @@ import { ItemProps } from '../Item';
|
|
|
5
5
|
import { useRichTextItem } from './useRichTextItem';
|
|
6
6
|
import { useItemAngle } from '../useItemAngle';
|
|
7
7
|
|
|
8
|
-
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item }) => {
|
|
8
|
+
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId }) => {
|
|
9
9
|
const [content, styles, preset] = useRichTextItem(item);
|
|
10
|
-
const angle = useItemAngle(item);
|
|
10
|
+
const angle = useItemAngle(item, sectionId);
|
|
11
11
|
const className = preset ? `cntrl-preset-${preset.id}` : undefined;
|
|
12
12
|
return (
|
|
13
13
|
<>
|
|
@@ -6,10 +6,10 @@ import { LinkWrapper } from '../LinkWrapper';
|
|
|
6
6
|
import { useFileItem } from './useFileItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
8
|
|
|
9
|
-
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
|
|
9
|
+
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId }) => {
|
|
10
10
|
const id = useId();
|
|
11
|
-
const { radius, strokeWidth, strokeColor, opacity } = useFileItem(item);
|
|
12
|
-
const angle = useItemAngle(item);
|
|
11
|
+
const { radius, strokeWidth, strokeColor, opacity } = useFileItem(item, sectionId);
|
|
12
|
+
const angle = useItemAngle(item, sectionId);
|
|
13
13
|
const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
|
|
14
14
|
return (
|
|
15
15
|
<LinkWrapper url={item.link?.url}>
|
|
@@ -6,10 +6,10 @@ import { LinkWrapper } from '../LinkWrapper';
|
|
|
6
6
|
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
8
|
|
|
9
|
-
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
|
|
9
|
+
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId }) => {
|
|
10
10
|
const id = useId();
|
|
11
|
-
const { radius } = useEmbedVideoItem(item);
|
|
12
|
-
const angle = useItemAngle(item);
|
|
11
|
+
const { radius } = useEmbedVideoItem(item, sectionId);
|
|
12
|
+
const angle = useItemAngle(item, sectionId);
|
|
13
13
|
const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
|
|
14
14
|
const getValidVimeoUrl = (url: string): string => {
|
|
15
15
|
const validURL = new URL(url);
|
|
@@ -7,11 +7,11 @@ import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
|
|
|
7
7
|
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
8
8
|
import { useItemAngle } from '../useItemAngle';
|
|
9
9
|
|
|
10
|
-
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) => {
|
|
10
|
+
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, sectionId }) => {
|
|
11
11
|
const id = useId();
|
|
12
12
|
const { autoplay, controls, url } = item.commonParams;
|
|
13
|
-
const { radius } = useEmbedVideoItem(item);
|
|
14
|
-
const angle = useItemAngle(item);
|
|
13
|
+
const { radius } = useEmbedVideoItem(item, sectionId);
|
|
14
|
+
const angle = useItemAngle(item, sectionId);
|
|
15
15
|
|
|
16
16
|
const getValidYoutubeUrl = (url: string): string => {
|
|
17
17
|
const newUrl = new URL(url);
|
|
@@ -2,7 +2,7 @@ import { TVimeoEmbedItem, TYoutubeEmbedItem } from '@cntrl-site/core';
|
|
|
2
2
|
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
3
3
|
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
4
4
|
|
|
5
|
-
export const useEmbedVideoItem = (item: TVimeoEmbedItem | TYoutubeEmbedItem) => {
|
|
5
|
+
export const useEmbedVideoItem = (item: TVimeoEmbedItem | TYoutubeEmbedItem, sectionId: string) => {
|
|
6
6
|
const layoutId = useCurrentLayout();
|
|
7
7
|
const radius = useKeyframeValue(
|
|
8
8
|
item,
|
|
@@ -12,6 +12,7 @@ export const useEmbedVideoItem = (item: TVimeoEmbedItem | TYoutubeEmbedItem) =>
|
|
|
12
12
|
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
13
13
|
},
|
|
14
14
|
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
15
|
+
sectionId,
|
|
15
16
|
[layoutId]
|
|
16
17
|
);
|
|
17
18
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TImageItem, TVideoItem } from '@cntrl-site/sdk';
|
|
2
2
|
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
3
3
|
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
4
4
|
|
|
5
5
|
const defaultColor = 'rgba(0, 0, 0, 1)';
|
|
6
6
|
|
|
7
|
-
export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
7
|
+
export const useFileItem = (item: TImageItem | TVideoItem, sectionId: string) => {
|
|
8
8
|
const layoutId = useCurrentLayout();
|
|
9
9
|
const radius = useKeyframeValue(
|
|
10
10
|
item,
|
|
@@ -14,6 +14,7 @@ export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
|
14
14
|
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
15
15
|
},
|
|
16
16
|
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
17
|
+
sectionId,
|
|
17
18
|
[layoutId]
|
|
18
19
|
);
|
|
19
20
|
const strokeWidth = useKeyframeValue(
|
|
@@ -24,6 +25,7 @@ export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
|
24
25
|
return 'strokeWidth' in layoutParams ? layoutParams.strokeWidth : 0;
|
|
25
26
|
},
|
|
26
27
|
(animator, scroll, value) => animator.getBorderWidth({ borderWidth: value }, scroll).borderWidth,
|
|
28
|
+
sectionId,
|
|
27
29
|
[layoutId]
|
|
28
30
|
);
|
|
29
31
|
|
|
@@ -35,6 +37,7 @@ export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
|
35
37
|
return 'opacity' in layoutParams ? layoutParams.opacity : 0;
|
|
36
38
|
},
|
|
37
39
|
(animator, scroll, value) => animator.getOpacity({ opacity: value }, scroll).opacity,
|
|
40
|
+
sectionId,
|
|
38
41
|
[layoutId]
|
|
39
42
|
);
|
|
40
43
|
|
|
@@ -45,7 +48,8 @@ export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
|
45
48
|
const layoutParams = item.layoutParams[layoutId];
|
|
46
49
|
return 'strokeColor' in layoutParams ? layoutParams.strokeColor : defaultColor;
|
|
47
50
|
},
|
|
48
|
-
(animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color
|
|
51
|
+
(animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color,
|
|
52
|
+
sectionId
|
|
49
53
|
);
|
|
50
54
|
|
|
51
55
|
return { radius, strokeWidth, opacity, strokeColor };
|
|
@@ -4,7 +4,7 @@ import { StickyManager } from '../../utils/StickyManager/StickyManager';
|
|
|
4
4
|
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
5
5
|
import { ArticleRectContext } from '../../provider/ArticleRectContext';
|
|
6
6
|
|
|
7
|
-
export const useItemSticky = (top: number,
|
|
7
|
+
export const useItemSticky = (top: number, item: TArticleItemAny, sectionId: string) => {
|
|
8
8
|
const [isFixed, setIsFixed] = useState(false);
|
|
9
9
|
const [adjustedTop, setAdjustedTop] = useState(top);
|
|
10
10
|
const articleRectObserver = useContext(ArticleRectContext);
|
|
@@ -16,20 +16,19 @@ export const useItemSticky = (top: number, parentOffsetTop: number, item: TArtic
|
|
|
16
16
|
setIsFixed(stickyManager.getIsSticky(scroll));
|
|
17
17
|
setAdjustedTop(stickyManager.getPosition(
|
|
18
18
|
scroll,
|
|
19
|
-
top
|
|
20
|
-
parentOffsetTop
|
|
19
|
+
top
|
|
21
20
|
));
|
|
22
|
-
}, [top, stickyManager
|
|
21
|
+
}, [top, stickyManager]);
|
|
23
22
|
|
|
24
23
|
useEffect(() => {
|
|
25
24
|
if (!articleRectObserver) return;
|
|
26
|
-
handleSticky(articleRectObserver.
|
|
25
|
+
handleSticky(articleRectObserver.getSectionScroll(sectionId));
|
|
27
26
|
}, [handleSticky, articleRectObserver]);
|
|
28
27
|
|
|
29
28
|
useEffect(() => {
|
|
30
29
|
if (!articleRectObserver || !sticky) return;
|
|
31
30
|
return articleRectObserver.on('scroll', () => {
|
|
32
|
-
handleSticky(articleRectObserver.
|
|
31
|
+
handleSticky(articleRectObserver.getSectionScroll(sectionId));
|
|
33
32
|
});
|
|
34
33
|
}, [handleSticky, articleRectObserver, sticky]);
|
|
35
34
|
return {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TRectangleItem } from '@cntrl-site/sdk';
|
|
2
2
|
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
3
3
|
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
4
4
|
|
|
5
5
|
const defaultColor = 'rgba(0, 0, 0, 1)';
|
|
6
6
|
|
|
7
|
-
export const useRectangleItem = (item: TRectangleItem) => {
|
|
7
|
+
export const useRectangleItem = (item: TRectangleItem, sectionId: string) => {
|
|
8
8
|
const layoutId = useCurrentLayout();
|
|
9
9
|
const radius = useKeyframeValue(
|
|
10
10
|
item,
|
|
@@ -14,6 +14,7 @@ export const useRectangleItem = (item: TRectangleItem) => {
|
|
|
14
14
|
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
15
15
|
},
|
|
16
16
|
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
17
|
+
sectionId,
|
|
17
18
|
[layoutId]
|
|
18
19
|
);
|
|
19
20
|
const strokeWidth = useKeyframeValue(
|
|
@@ -24,6 +25,7 @@ export const useRectangleItem = (item: TRectangleItem) => {
|
|
|
24
25
|
return 'strokeWidth' in layoutParams ? layoutParams.strokeWidth : 0;
|
|
25
26
|
},
|
|
26
27
|
(animator, scroll, value) => animator.getBorderWidth({ borderWidth: value }, scroll).borderWidth,
|
|
28
|
+
sectionId,
|
|
27
29
|
[layoutId]
|
|
28
30
|
);
|
|
29
31
|
const fillColor = useKeyframeValue(
|
|
@@ -34,6 +36,7 @@ export const useRectangleItem = (item: TRectangleItem) => {
|
|
|
34
36
|
return 'fillColor' in layoutParams ? layoutParams.fillColor : defaultColor;
|
|
35
37
|
},
|
|
36
38
|
(animator, scroll, value) => animator.getColor({ color: value }, scroll).color,
|
|
39
|
+
sectionId,
|
|
37
40
|
[layoutId]
|
|
38
41
|
);
|
|
39
42
|
const strokeColor = useKeyframeValue(
|
|
@@ -44,6 +47,7 @@ export const useRectangleItem = (item: TRectangleItem) => {
|
|
|
44
47
|
return 'strokeColor' in layoutParams ? layoutParams.strokeColor : defaultColor;
|
|
45
48
|
},
|
|
46
49
|
(animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color,
|
|
50
|
+
sectionId,
|
|
47
51
|
[layoutId]
|
|
48
52
|
);
|
|
49
53
|
return { fillColor, strokeWidth, radius, strokeColor };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { TArticleItemAny } from '@cntrl-site/sdk';
|
|
2
2
|
import { useKeyframeValue } from '../common/useKeyframeValue';
|
|
3
3
|
|
|
4
|
-
export const useItemAngle = (item: TArticleItemAny) => {
|
|
4
|
+
export const useItemAngle = (item: TArticleItemAny, sectionId: string) => {
|
|
5
5
|
const { angle } = useKeyframeValue(
|
|
6
6
|
item,
|
|
7
7
|
(item, layoutId) => ({ angle: layoutId ? item.area[layoutId].angle : 0 }),
|
|
8
|
-
(animator, scroll, value) => animator.getRotation(value, scroll)
|
|
8
|
+
(animator, scroll, value) => animator.getRotation(value, scroll),
|
|
9
|
+
sectionId
|
|
9
10
|
);
|
|
10
11
|
return angle;
|
|
11
12
|
};
|
|
@@ -11,12 +11,13 @@ const defaultArea = {
|
|
|
11
11
|
zIndex: 0
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const useItemDimensions = (item: TArticleItemAny) => {
|
|
14
|
+
export const useItemDimensions = (item: TArticleItemAny, sectionId: string) => {
|
|
15
15
|
const layoutId = useCurrentLayout();
|
|
16
16
|
const { width, height } = useKeyframeValue<{ width: number; height: number }>(
|
|
17
17
|
item,
|
|
18
18
|
(item, layoutId) => layoutId ? item.area[layoutId] : defaultArea,
|
|
19
19
|
(animator, scroll, value) => animator.getDimensions(value, scroll),
|
|
20
|
+
sectionId,
|
|
20
21
|
[layoutId]
|
|
21
22
|
);
|
|
22
23
|
return { width, height };
|
|
@@ -2,12 +2,13 @@ import { TArticleItemAny } from '@cntrl-site/sdk';
|
|
|
2
2
|
import { useKeyframeValue } from '../common/useKeyframeValue';
|
|
3
3
|
import { useCurrentLayout } from '../common/useCurrentLayout';
|
|
4
4
|
|
|
5
|
-
export const useItemPosition = (item: TArticleItemAny) => {
|
|
5
|
+
export const useItemPosition = (item: TArticleItemAny, sectionId: string) => {
|
|
6
6
|
const layoutId = useCurrentLayout();
|
|
7
7
|
const { top, left } = useKeyframeValue<{ top: number; left: number }>(
|
|
8
8
|
item,
|
|
9
9
|
(item, layoutId) => item.area[layoutId],
|
|
10
10
|
(animator, scroll, value) => animator.getPositions(value, scroll),
|
|
11
|
+
sectionId,
|
|
11
12
|
[layoutId]
|
|
12
13
|
);
|
|
13
14
|
return { top, left };
|
|
@@ -2,12 +2,13 @@ import { TArticleItemAny } from '@cntrl-site/sdk';
|
|
|
2
2
|
import { useKeyframeValue } from '../common/useKeyframeValue';
|
|
3
3
|
import { useCurrentLayout } from '../common/useCurrentLayout';
|
|
4
4
|
|
|
5
|
-
export const useItemScale = (item: TArticleItemAny) => {
|
|
5
|
+
export const useItemScale = (item: TArticleItemAny, sectionId: string) => {
|
|
6
6
|
const layout = useCurrentLayout();
|
|
7
7
|
const { scale } = useKeyframeValue(
|
|
8
8
|
item,
|
|
9
9
|
(item, layoutId) => ({ scale: layoutId ? item.area[layoutId].scale : 1 }),
|
|
10
|
-
(animator, scroll, value) => animator.getScale(value, scroll)
|
|
10
|
+
(animator, scroll, value) => animator.getScale(value, scroll),
|
|
11
|
+
sectionId
|
|
11
12
|
);
|
|
12
13
|
const scaleAnchor = item.area[layout].scaleAnchor;
|
|
13
14
|
|
|
@@ -8,18 +8,27 @@ interface EventMap {
|
|
|
8
8
|
export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
9
9
|
private resizeObserver: ResizeObserver;
|
|
10
10
|
private articleWidth: number = 0;
|
|
11
|
+
private registry: Map<string, HTMLElement> = new Map();
|
|
11
12
|
private scrollPos: number = window.scrollY;
|
|
12
13
|
private animationFrame: number = NaN;
|
|
14
|
+
private parent: HTMLElement | undefined = undefined;
|
|
15
|
+
private sectionsScrollMap: Map<string, number> = new Map();
|
|
13
16
|
|
|
14
17
|
constructor() {
|
|
15
18
|
super();
|
|
16
|
-
this.resizeObserver = new ResizeObserver(this.handleResize);
|
|
19
|
+
this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
get scroll(): number {
|
|
20
23
|
return this.scrollPos;
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
getSectionScroll(sectionId: string): number {
|
|
27
|
+
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
28
|
+
if (sectionTop === undefined) return 0;
|
|
29
|
+
return - (sectionTop / this.articleWidth - this.scrollPos);
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
get width(): number {
|
|
24
33
|
return this.articleWidth;
|
|
25
34
|
}
|
|
@@ -28,8 +37,8 @@ export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
|
28
37
|
this.scrollPos = scroll;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
this.
|
|
40
|
+
init(parent: HTMLElement) {
|
|
41
|
+
this.parent = parent;
|
|
33
42
|
const onScroll = () => {
|
|
34
43
|
this.handleScroll(window.scrollY);
|
|
35
44
|
if (!isNaN(this.animationFrame)) return;
|
|
@@ -40,7 +49,7 @@ export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
|
40
49
|
};
|
|
41
50
|
window.addEventListener('scroll', onScroll);
|
|
42
51
|
return () => {
|
|
43
|
-
this.
|
|
52
|
+
this.parent = undefined;
|
|
44
53
|
window.removeEventListener('scroll', onScroll);
|
|
45
54
|
if (!isNaN(this.animationFrame)) {
|
|
46
55
|
window.cancelAnimationFrame(this.animationFrame);
|
|
@@ -49,22 +58,30 @@ export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
|
49
58
|
};
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
register(el: HTMLElement, sectionId: string) {
|
|
62
|
+
this.registry.set(sectionId, el);
|
|
63
|
+
this.resizeObserver.observe(el);
|
|
64
|
+
return () => {
|
|
65
|
+
this.registry.delete(sectionId);
|
|
66
|
+
this.resizeObserver.unobserve(el);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
52
70
|
private handleScroll = (scroll: number) => {
|
|
53
71
|
this.setScroll(scroll / this.articleWidth);
|
|
54
72
|
};
|
|
55
73
|
|
|
56
|
-
private handleResize
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!(element instanceof HTMLElement)) return;
|
|
61
|
-
this.notify(element);
|
|
74
|
+
private handleResize() {
|
|
75
|
+
if (!this.parent) return;
|
|
76
|
+
const parentBoundary = this.parent.getBoundingClientRect();
|
|
77
|
+
this.articleWidth = parentBoundary.width;
|
|
62
78
|
this.setScroll(window.scrollY / this.articleWidth);
|
|
63
79
|
this.emit('resize', undefined);
|
|
80
|
+
for (const sectionId of this.registry.keys()) {
|
|
81
|
+
const el = this.registry.get(sectionId);
|
|
82
|
+
if (!el) continue;
|
|
83
|
+
const rect = el.getBoundingClientRect();
|
|
84
|
+
this.sectionsScrollMap.set(sectionId, rect.top - parentBoundary.top);
|
|
85
|
+
}
|
|
64
86
|
};
|
|
65
|
-
|
|
66
|
-
private notify(el: HTMLElement) {
|
|
67
|
-
const elBoundary = el.getBoundingClientRect();
|
|
68
|
-
this.articleWidth = elBoundary.width;
|
|
69
|
-
}
|
|
70
87
|
}
|
|
@@ -10,7 +10,7 @@ export const useArticleRectObserver = (el?: HTMLElement | null) => {
|
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
if (!el || !articleRectObserver) return;
|
|
13
|
-
return articleRectObserver.
|
|
13
|
+
return articleRectObserver.init(el);
|
|
14
14
|
}, [el, articleRectObserver]);
|
|
15
15
|
|
|
16
16
|
return articleRectObserver;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { ArticleRectContext } from '../../provider/ArticleRectContext';
|
|
3
|
+
|
|
4
|
+
export const useSectionRegistry = ( sectionId: string, el?: HTMLElement | null) => {
|
|
5
|
+
const articleRectObserver = useContext(ArticleRectContext);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!el || !articleRectObserver) return;
|
|
9
|
+
return articleRectObserver.register(el, sectionId);
|
|
10
|
+
}, [el, articleRectObserver]);
|
|
11
|
+
};
|
|
@@ -10,10 +10,10 @@ export class StickyManager {
|
|
|
10
10
|
return (this.sticky.from <= scroll) && (!this.sticky.to || this.sticky.to >= scroll);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
getPosition(scroll: number, top: number
|
|
13
|
+
getPosition(scroll: number, top: number): number {
|
|
14
14
|
if (!this.sticky) return top;
|
|
15
15
|
if (this.getIsSticky(scroll)) {
|
|
16
|
-
return top - this.sticky.from
|
|
16
|
+
return top - this.sticky.from;
|
|
17
17
|
}
|
|
18
18
|
if (this.sticky.to !== undefined && this.sticky.to <= scroll) {
|
|
19
19
|
return top + this.sticky.to - this.sticky.from;
|
|
@@ -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
|
|
Binary file
|
package/lib/utils/castObject.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.castObject = void 0;
|
|
4
|
-
function castObject(value, ctor) {
|
|
5
|
-
if (value instanceof ctor) {
|
|
6
|
-
return value;
|
|
7
|
-
}
|
|
8
|
-
throw new TypeError(`passed value "${String(value)}" is not instance of ${ctor.name}`);
|
|
9
|
-
}
|
|
10
|
-
exports.castObject = castObject;
|