@cntrl-site/sdk-nextjs 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/inspectionProfiles/Project_Default.xml +4 -9
- package/.idea/workspace.xml +427 -0
- package/cntrl-site-sdk-nextjs-0.11.0.tgz +0 -0
- package/cntrl-site-sdk-nextjs-0.12.0.tgz +0 -0
- 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 +3 -3
- 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/index.js +5 -4
- package/lib/provider/CntrlSdkContext.js +15 -0
- 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 +3 -3
- 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/index.ts +4 -3
- package/src/provider/CntrlSdkContext.ts +19 -1
- 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/cntrl-site-sdk-nextjs-0.10.2.tgz +0 -0
- package/lib/utils/castObject.js +0 -10
|
@@ -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
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { cntrlSdkContext } from './provider/defaultContext';
|
|
2
|
-
|
|
3
1
|
export * from '@cntrl-site/sdk';
|
|
4
2
|
|
|
5
3
|
export { RichTextConverter } from './utils/RichTextConverter/RichTextConverter';
|
|
@@ -17,7 +15,10 @@ export { LayoutStyle } from './components/LayoutStyle';
|
|
|
17
15
|
export { VimeoEmbedItem } from './components/items/VimeoEmbed';
|
|
18
16
|
export { YoutubeEmbedItem } from './components/items/YoutubeEmbed';
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
import { cntrlSdkContext as sdk } from './provider/defaultContext';
|
|
21
19
|
export { CntrlProvider } from './provider/CntrlProvider';
|
|
22
20
|
export type { CustomItemComponent } from './provider/CustomItemTypes';
|
|
23
21
|
export { useCntrlContext } from './provider/useCntrlContext';
|
|
22
|
+
export const customItems = sdk.customItems;
|
|
23
|
+
export const customSections = sdk.customSections;
|
|
24
|
+
export const cntrlSdkContext = sdk;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomItemRegistry } from './CustomItemRegistry';
|
|
2
|
-
import { TLayout, TTypePresets
|
|
2
|
+
import { TArticleSection, TLayout, TTypePresets } from '@cntrl-site/sdk';
|
|
3
3
|
import { CustomSectionRegistry } from './CustomSectionRegistry';
|
|
4
4
|
|
|
5
5
|
export class CntrlSdkContext {
|
|
@@ -10,6 +10,20 @@ export class CntrlSdkContext {
|
|
|
10
10
|
public readonly customSections: CustomSectionRegistry
|
|
11
11
|
) {}
|
|
12
12
|
|
|
13
|
+
async resolveSectionData(sections: TArticleSection[]): Promise<Record<string, any>> {
|
|
14
|
+
const resolvers = sections.map(section => {
|
|
15
|
+
const resolver = section.name ? this.customSections.getResolver(section.name) : undefined;
|
|
16
|
+
if (!resolver) return;
|
|
17
|
+
return {
|
|
18
|
+
name: section.name,
|
|
19
|
+
resolver
|
|
20
|
+
};
|
|
21
|
+
}).filter(isDefined);
|
|
22
|
+
return Object.fromEntries(
|
|
23
|
+
await Promise.all(resolvers.map(async ({ name, resolver }) => [name, await resolver()]))
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
setTypePresets(typePresets: TTypePresets) {
|
|
14
28
|
this._typePresets = typePresets;
|
|
15
29
|
}
|
|
@@ -26,3 +40,7 @@ export class CntrlSdkContext {
|
|
|
26
40
|
return this._typePresets;
|
|
27
41
|
}
|
|
28
42
|
}
|
|
43
|
+
|
|
44
|
+
function isDefined<T>(value: T): value is Exclude<T, undefined> {
|
|
45
|
+
return value !== undefined;
|
|
46
|
+
}
|
|
@@ -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;
|
|
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;
|