@cntrl-site/sdk-nextjs 1.6.11 → 1.6.12
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/LICENSE +21 -21
- package/README.md +4 -4
- package/TODO.md +1 -1
- package/eslint.config.mjs +35 -35
- package/jest.config.js +6 -6
- package/lib/common/useItemFXData.js +7 -7
- package/lib/components/Article.js +5 -5
- package/lib/components/LayoutStyle.js +4 -4
- package/lib/components/Section/Section.js +14 -14
- package/lib/components/items/CodeEmbedItem/CodeEmbedItem.js +40 -29
- package/lib/components/items/CompoundItem/CompoundChild.js +20 -20
- package/lib/components/items/CompoundItem/CompoundItem.js +14 -14
- package/lib/components/items/CustomItem/CustomItem.js +9 -9
- package/lib/components/items/EmbedVideoItem/VimeoEmbed.js +23 -23
- package/lib/components/items/EmbedVideoItem/YoutubeEmbed.js +26 -26
- package/lib/components/items/FileItem/ImageItem.js +38 -38
- package/lib/components/items/FileItem/VideoItem.js +45 -45
- package/lib/components/items/GroupItem/GroupItem.js +13 -13
- package/lib/components/items/Item.js +30 -30
- package/lib/components/items/RectangleItem/RectangleItem.js +20 -20
- package/lib/components/items/RichTextItem/RichTextItem.js +21 -21
- package/lib/provider/CntrlSdkContext.js +8 -0
- package/lib/utils/RichTextConverter/RichTextConverter.js +21 -21
- package/package.json +57 -57
- package/src/common/useCurrentLayout.ts +52 -52
- package/src/common/useExemplary.ts +9 -9
- package/src/common/useItemFXData.ts +47 -47
- package/src/common/useKeyframeValue.ts +85 -85
- package/src/common/useRegisterResize.ts +17 -17
- package/src/components/Article.tsx +66 -66
- package/src/components/ArticleWrapper.tsx +21 -21
- package/src/components/Head.tsx +56 -56
- package/src/components/LayoutStyle.tsx +21 -21
- package/src/components/Page.tsx +33 -33
- package/src/components/ScrollPlaybackVideo.tsx +56 -56
- package/src/components/Section/Section.tsx +77 -77
- package/src/components/Section/useSectionColor.ts +19 -19
- package/src/components/Section/useSectionHeightMap.ts +19 -19
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +132 -120
- package/src/components/items/CodeEmbedItem/useCodeEmbedItem.ts +36 -36
- package/src/components/items/CompoundItem/CompoundChild.tsx +150 -150
- package/src/components/items/CompoundItem/CompoundItem.tsx +71 -71
- package/src/components/items/CompoundItem/useCompoundItem.ts +21 -21
- package/src/components/items/CustomItem/CustomItem.tsx +47 -47
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +202 -202
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +187 -187
- package/src/components/items/EmbedVideoItem/useEmbedVideoItem.ts +46 -46
- package/src/components/items/FileItem/ImageItem.tsx +156 -156
- package/src/components/items/FileItem/VideoItem.tsx +185 -185
- package/src/components/items/FileItem/useFileItem.ts +73 -73
- package/src/components/items/GroupItem/GroupItem.tsx +79 -79
- package/src/components/items/GroupItem/useGroupItem.ts +34 -34
- package/src/components/items/Item.tsx +251 -251
- package/src/components/items/LinkWrapper.tsx +39 -39
- package/src/components/items/RectangleItem/RectangleItem.tsx +95 -95
- package/src/components/items/RectangleItem/useRectangleItem.ts +82 -82
- package/src/components/items/RichTextItem/RichTextItem.tsx +105 -105
- package/src/components/items/RichTextItem/useRichTextItem.ts +12 -12
- package/src/components/items/RichTextWrapper.tsx +15 -15
- package/src/components/items/itemsMap.ts +26 -26
- package/src/components/items/useDraggable.ts +252 -252
- package/src/components/items/useItemAngle.ts +13 -13
- package/src/components/items/useItemArea.ts +35 -35
- package/src/components/items/useItemPointerEvents.ts +23 -23
- package/src/components/items/useItemScale.ts +17 -17
- package/src/components/items/useItemTriggers.ts +15 -15
- package/src/components/items/useRichTextItemValues.ts +65 -65
- package/src/components/items/useSizing.ts +25 -25
- package/src/components/items/useStickyItemTop.ts +21 -21
- package/src/components/useLayoutContext.ts +7 -7
- package/src/index.ts +24 -24
- package/src/interactions/CSSPropertyNameMap.ts +38 -38
- package/src/interactions/InteractionsRegistry.ts +275 -275
- package/src/interactions/ItemInteractionCtrl.ts +77 -77
- package/src/interactions/getTransition.ts +27 -27
- package/src/interactions/types.ts +36 -36
- package/src/interactions/useItemInteractionCtrl.ts +18 -18
- package/src/provider/ArticleRectContext.ts +4 -4
- package/src/provider/CntrlContext.ts +5 -5
- package/src/provider/CntrlProvider.tsx +11 -11
- package/src/provider/CntrlSdkContext.ts +69 -59
- package/src/provider/CustomItemRegistry.ts +14 -14
- package/src/provider/CustomItemTypes.ts +3 -3
- package/src/provider/CustomSectionRegistry.ts +25 -25
- package/src/provider/InteractionsContext.old.tsx +65 -65
- package/src/provider/InteractionsContext.test.tsx +97 -97
- package/src/provider/InteractionsContext.tsx +28 -28
- package/src/provider/Keyframes.ts +11 -11
- package/src/provider/KeyframesContext.ts +5 -5
- package/src/provider/LayoutContext.ts +3 -3
- package/src/provider/defaultContext.ts +8 -8
- package/src/provider/useCntrlContext.ts +8 -8
- package/src/styled-jsx.d.ts +1 -1
- package/src/utils/Animator/Animator.ts +371 -371
- package/src/utils/ArticleRectManager/ArticleRectObserver.ts +93 -93
- package/src/utils/ArticleRectManager/useArticleRectObserver.ts +17 -17
- package/src/utils/ArticleRectManager/useSectionRegistry.ts +11 -11
- package/src/utils/EventEmitter.ts +41 -41
- package/src/utils/RichTextConverter/RichTextConverter.tsx +326 -326
- package/src/utils/ScaleAnchorMap.ts +13 -13
- package/src/utils/StickyManager/StickyManager.ts +23 -23
- package/src/utils/Youtube/YouTubeIframeApiLoader.ts +58 -58
- package/src/utils/Youtube/YoutubeIframeApi.ts +101 -101
- package/src/utils/Youtube/useYouTubeIframeApi.ts +12 -12
- package/src/utils/binSearchInsertAt.ts +33 -33
- package/src/utils/castObject.ts +10 -10
- package/src/utils/effects/useImageFx.ts +113 -113
- package/src/utils/effects/useVideoFx.ts +116 -116
- package/src/utils/getAnchoredItemTop.ts +12 -12
- package/src/utils/getCompoundBondaryStyles.ts +62 -62
- package/src/utils/getFontFamilyValue.ts +3 -3
- package/src/utils/getInvertedRanges.ts +43 -43
- package/src/utils/getItemTopStyle.ts +14 -14
- package/src/utils/getStyleFromItemStateAndParams.ts +8 -8
- package/src/utils/getValidYoutubeUrl.ts +29 -29
- package/src/utils/isItemType.ts +6 -6
- package/src/utils/rangeMap.ts +13 -13
- package/src/utils/useElementRect.ts +23 -23
- package/.idea/modules.xml +0 -8
- package/.idea/sdk-nextjs.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/cntrl-site-sdk-nextjs-1.6.11-alpha.0.tgz +0 -0
package/src/components/Head.tsx
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
2
|
-
import HTMLReactParser, { domToReact } from 'html-react-parser';
|
|
3
|
-
import Head from 'next/head';
|
|
4
|
-
import { FontFaceGenerator, Meta, Project } from '@cntrl-site/sdk';
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
project: Project;
|
|
8
|
-
meta: Meta;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const CNTRLHead: FC<Props> = ({ meta, project }) => {
|
|
12
|
-
const googleFonts: ReturnType<typeof domToReact> = HTMLReactParser(project.fonts.google);
|
|
13
|
-
const adobeFonts: ReturnType<typeof domToReact> = HTMLReactParser(project.fonts.adobe);
|
|
14
|
-
const parsedFonts = {
|
|
15
|
-
...(typeof googleFonts === 'object' ? googleFonts : {}),
|
|
16
|
-
...(typeof adobeFonts === 'object' ? adobeFonts : {})
|
|
17
|
-
};
|
|
18
|
-
const customFonts = project.fonts.custom;
|
|
19
|
-
const htmlHead = HTMLReactParser(project.html.head);
|
|
20
|
-
const ffGenerator = new FontFaceGenerator(customFonts);
|
|
21
|
-
const links = Object.values(parsedFonts as ReturnType<typeof domToReact>).map((value) => {
|
|
22
|
-
if (!value) return;
|
|
23
|
-
const rel = value?.rel || value.props?.rel;
|
|
24
|
-
const href = value?.href || value.props?.href;
|
|
25
|
-
if (!rel || !href) return;
|
|
26
|
-
return (
|
|
27
|
-
<link key={`link-${rel}-${href}`} rel={rel} href={href} />
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
return (
|
|
31
|
-
<Head>
|
|
32
|
-
<title>{meta.title}</title>
|
|
33
|
-
<meta name="description" content={meta.description}/>
|
|
34
|
-
<meta name="keywords" content={meta.keywords}/>
|
|
35
|
-
<meta name="og:title" content={meta.title}/>
|
|
36
|
-
<meta name="og:image" content={meta.opengraphThumbnail}/>
|
|
37
|
-
<meta name="og:description" content={meta.description}/>
|
|
38
|
-
<meta name="twitter:title" content={meta.title}/>
|
|
39
|
-
<meta name="twitter:image" content={meta.opengraphThumbnail}/>
|
|
40
|
-
<meta name="twitter:description" content={meta.description}/>
|
|
41
|
-
<meta property="twitter:card" content="summary_large_image"/>
|
|
42
|
-
<meta name="generator" content="https://cntrl.site"/>
|
|
43
|
-
<link rel="icon" href={meta.favicon}/>
|
|
44
|
-
{customFonts.length > 0 && (
|
|
45
|
-
<style
|
|
46
|
-
dangerouslySetInnerHTML={{
|
|
47
|
-
__html: ffGenerator.generate()
|
|
48
|
-
}}
|
|
49
|
-
/>
|
|
50
|
-
)}
|
|
51
|
-
{links}
|
|
52
|
-
{htmlHead}
|
|
53
|
-
|
|
54
|
-
</Head>
|
|
55
|
-
);
|
|
56
|
-
};
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import HTMLReactParser, { domToReact } from 'html-react-parser';
|
|
3
|
+
import Head from 'next/head';
|
|
4
|
+
import { FontFaceGenerator, Meta, Project } from '@cntrl-site/sdk';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
project: Project;
|
|
8
|
+
meta: Meta;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const CNTRLHead: FC<Props> = ({ meta, project }) => {
|
|
12
|
+
const googleFonts: ReturnType<typeof domToReact> = HTMLReactParser(project.fonts.google);
|
|
13
|
+
const adobeFonts: ReturnType<typeof domToReact> = HTMLReactParser(project.fonts.adobe);
|
|
14
|
+
const parsedFonts = {
|
|
15
|
+
...(typeof googleFonts === 'object' ? googleFonts : {}),
|
|
16
|
+
...(typeof adobeFonts === 'object' ? adobeFonts : {})
|
|
17
|
+
};
|
|
18
|
+
const customFonts = project.fonts.custom;
|
|
19
|
+
const htmlHead = HTMLReactParser(project.html.head);
|
|
20
|
+
const ffGenerator = new FontFaceGenerator(customFonts);
|
|
21
|
+
const links = Object.values(parsedFonts as ReturnType<typeof domToReact>).map((value) => {
|
|
22
|
+
if (!value) return;
|
|
23
|
+
const rel = value?.rel || value.props?.rel;
|
|
24
|
+
const href = value?.href || value.props?.href;
|
|
25
|
+
if (!rel || !href) return;
|
|
26
|
+
return (
|
|
27
|
+
<link key={`link-${rel}-${href}`} rel={rel} href={href} />
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
return (
|
|
31
|
+
<Head>
|
|
32
|
+
<title>{meta.title}</title>
|
|
33
|
+
<meta name="description" content={meta.description}/>
|
|
34
|
+
<meta name="keywords" content={meta.keywords}/>
|
|
35
|
+
<meta name="og:title" content={meta.title}/>
|
|
36
|
+
<meta name="og:image" content={meta.opengraphThumbnail}/>
|
|
37
|
+
<meta name="og:description" content={meta.description}/>
|
|
38
|
+
<meta name="twitter:title" content={meta.title}/>
|
|
39
|
+
<meta name="twitter:image" content={meta.opengraphThumbnail}/>
|
|
40
|
+
<meta name="twitter:description" content={meta.description}/>
|
|
41
|
+
<meta property="twitter:card" content="summary_large_image"/>
|
|
42
|
+
<meta name="generator" content="https://cntrl.site"/>
|
|
43
|
+
<link rel="icon" href={meta.favicon}/>
|
|
44
|
+
{customFonts.length > 0 && (
|
|
45
|
+
<style
|
|
46
|
+
dangerouslySetInnerHTML={{
|
|
47
|
+
__html: ffGenerator.generate()
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
{links}
|
|
52
|
+
{htmlHead}
|
|
53
|
+
|
|
54
|
+
</Head>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
2
|
-
import { getLayoutMediaQuery, Layout } from '@cntrl-site/sdk';
|
|
3
|
-
import JSXStyle from 'styled-jsx/style';
|
|
4
|
-
|
|
5
|
-
export interface LayoutStyleProps {
|
|
6
|
-
id: string;
|
|
7
|
-
layouts: Layout[];
|
|
8
|
-
layoutId: string;
|
|
9
|
-
children?: (layout: Layout) => string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const LayoutStyle: FC<LayoutStyleProps> = ({ id, layouts, layoutId, children }) => {
|
|
13
|
-
const layout = layouts.find(l => l.id === layoutId)!;
|
|
14
|
-
return (
|
|
15
|
-
<JSXStyle id={id}>{`
|
|
16
|
-
${getLayoutMediaQuery(layoutId, layouts)} {
|
|
17
|
-
${children?.(layout)}
|
|
18
|
-
}
|
|
19
|
-
`}</JSXStyle>
|
|
20
|
-
);
|
|
21
|
-
};
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { getLayoutMediaQuery, Layout } from '@cntrl-site/sdk';
|
|
3
|
+
import JSXStyle from 'styled-jsx/style';
|
|
4
|
+
|
|
5
|
+
export interface LayoutStyleProps {
|
|
6
|
+
id: string;
|
|
7
|
+
layouts: Layout[];
|
|
8
|
+
layoutId: string;
|
|
9
|
+
children?: (layout: Layout) => string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const LayoutStyle: FC<LayoutStyleProps> = ({ id, layouts, layoutId, children }) => {
|
|
13
|
+
const layout = layouts.find(l => l.id === layoutId)!;
|
|
14
|
+
return (
|
|
15
|
+
<JSXStyle id={id}>{`
|
|
16
|
+
${getLayoutMediaQuery(layoutId, layouts)} {
|
|
17
|
+
${children?.(layout)}
|
|
18
|
+
}
|
|
19
|
+
`}</JSXStyle>
|
|
20
|
+
);
|
|
21
|
+
};
|
package/src/components/Page.tsx
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import React, { FC, useMemo } from 'react';
|
|
2
|
-
import HTMLReactParser from 'html-react-parser';
|
|
3
|
-
import { Article as TArticle, Project, Meta, KeyframeAny } from '@cntrl-site/sdk';
|
|
4
|
-
import { Article } from './Article';
|
|
5
|
-
import { KeyframesContext } from '../provider/KeyframesContext';
|
|
6
|
-
import { CNTRLHead } from './Head';
|
|
7
|
-
import { Keyframes } from '../provider/Keyframes';
|
|
8
|
-
|
|
9
|
-
export interface PageProps {
|
|
10
|
-
article: TArticle;
|
|
11
|
-
project: Project;
|
|
12
|
-
meta: Meta;
|
|
13
|
-
keyframes: KeyframeAny[];
|
|
14
|
-
sectionData: Record<SectionName, any>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const Page: FC<PageProps> = ({ article, project, meta, keyframes, sectionData }) => {
|
|
18
|
-
const afterBodyOpen = HTMLReactParser(project.html.afterBodyOpen);
|
|
19
|
-
const beforeBodyClose = HTMLReactParser(project.html.beforeBodyClose);
|
|
20
|
-
const keyframesRepo = useMemo(() => new Keyframes(keyframes), [keyframes]);
|
|
21
|
-
return (
|
|
22
|
-
<>
|
|
23
|
-
<CNTRLHead project={project} meta={meta} />
|
|
24
|
-
{afterBodyOpen}
|
|
25
|
-
<KeyframesContext.Provider value={keyframesRepo}>
|
|
26
|
-
<Article article={article} sectionData={sectionData} />
|
|
27
|
-
</KeyframesContext.Provider>
|
|
28
|
-
{beforeBodyClose}
|
|
29
|
-
</>
|
|
30
|
-
);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
type SectionName = string;
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
2
|
+
import HTMLReactParser from 'html-react-parser';
|
|
3
|
+
import { Article as TArticle, Project, Meta, KeyframeAny } from '@cntrl-site/sdk';
|
|
4
|
+
import { Article } from './Article';
|
|
5
|
+
import { KeyframesContext } from '../provider/KeyframesContext';
|
|
6
|
+
import { CNTRLHead } from './Head';
|
|
7
|
+
import { Keyframes } from '../provider/Keyframes';
|
|
8
|
+
|
|
9
|
+
export interface PageProps {
|
|
10
|
+
article: TArticle;
|
|
11
|
+
project: Project;
|
|
12
|
+
meta: Meta;
|
|
13
|
+
keyframes: KeyframeAny[];
|
|
14
|
+
sectionData: Record<SectionName, any>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const Page: FC<PageProps> = ({ article, project, meta, keyframes, sectionData }) => {
|
|
18
|
+
const afterBodyOpen = HTMLReactParser(project.html.afterBodyOpen);
|
|
19
|
+
const beforeBodyClose = HTMLReactParser(project.html.beforeBodyClose);
|
|
20
|
+
const keyframesRepo = useMemo(() => new Keyframes(keyframes), [keyframes]);
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<CNTRLHead project={project} meta={meta} />
|
|
24
|
+
{afterBodyOpen}
|
|
25
|
+
<KeyframesContext.Provider value={keyframesRepo}>
|
|
26
|
+
<Article article={article} sectionData={sectionData} />
|
|
27
|
+
</KeyframesContext.Provider>
|
|
28
|
+
{beforeBodyClose}
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type SectionName = string;
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import React, { FC, useContext, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { rangeMap } from '../utils/rangeMap';
|
|
3
|
-
import { ArticleRectContext } from '../provider/ArticleRectContext';
|
|
4
|
-
import { ScrollPlaybackVideoManager } from '@cntrl-site/sdk';
|
|
5
|
-
|
|
6
|
-
type PlaybackParams = { from: number, to: number };
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
sectionId: string;
|
|
10
|
-
src: string;
|
|
11
|
-
playbackParams: PlaybackParams | null;
|
|
12
|
-
style?: React.CSSProperties;
|
|
13
|
-
className: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const ScrollPlaybackVideo: FC<Props> = ({ sectionId, src, playbackParams, style, className}) => {
|
|
17
|
-
const [containerElement, setContainerElement] = useState<HTMLDivElement | null>(null);
|
|
18
|
-
const [time, setTime] = useState(0);
|
|
19
|
-
const articleRectObserver = useContext(ArticleRectContext);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (!playbackParams || !articleRectObserver) return;
|
|
23
|
-
return articleRectObserver.on('scroll', () => {
|
|
24
|
-
const scrollPos = articleRectObserver.getSectionScroll(sectionId);
|
|
25
|
-
const time = rangeMap(scrollPos, playbackParams.from, playbackParams.to, 0, 1, true);
|
|
26
|
-
setTime(toFixed(time));
|
|
27
|
-
})
|
|
28
|
-
}, [playbackParams?.from, playbackParams?.to, time]);
|
|
29
|
-
|
|
30
|
-
const scrollVideoManager = useMemo<ScrollPlaybackVideoManager | null>(() => {
|
|
31
|
-
if (!containerElement) return null;
|
|
32
|
-
const manager = new ScrollPlaybackVideoManager({
|
|
33
|
-
src,
|
|
34
|
-
videoContainer: containerElement
|
|
35
|
-
});
|
|
36
|
-
return manager;
|
|
37
|
-
}, [containerElement, src]);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
return () => {
|
|
41
|
-
scrollVideoManager?.destroy();
|
|
42
|
-
};
|
|
43
|
-
}, [scrollVideoManager]);
|
|
44
|
-
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (scrollVideoManager && time >= 0 && time <= 1) {
|
|
47
|
-
scrollVideoManager.setTargetTimePercent(time);
|
|
48
|
-
}
|
|
49
|
-
}, [time, scrollVideoManager]);
|
|
50
|
-
|
|
51
|
-
return <div className={className} style={style} ref={setContainerElement} />;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
function toFixed(num: number) {
|
|
55
|
-
return Number(num.toFixed(3));
|
|
56
|
-
}
|
|
1
|
+
import React, { FC, useContext, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { rangeMap } from '../utils/rangeMap';
|
|
3
|
+
import { ArticleRectContext } from '../provider/ArticleRectContext';
|
|
4
|
+
import { ScrollPlaybackVideoManager } from '@cntrl-site/sdk';
|
|
5
|
+
|
|
6
|
+
type PlaybackParams = { from: number, to: number };
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
sectionId: string;
|
|
10
|
+
src: string;
|
|
11
|
+
playbackParams: PlaybackParams | null;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
className: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ScrollPlaybackVideo: FC<Props> = ({ sectionId, src, playbackParams, style, className}) => {
|
|
17
|
+
const [containerElement, setContainerElement] = useState<HTMLDivElement | null>(null);
|
|
18
|
+
const [time, setTime] = useState(0);
|
|
19
|
+
const articleRectObserver = useContext(ArticleRectContext);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!playbackParams || !articleRectObserver) return;
|
|
23
|
+
return articleRectObserver.on('scroll', () => {
|
|
24
|
+
const scrollPos = articleRectObserver.getSectionScroll(sectionId);
|
|
25
|
+
const time = rangeMap(scrollPos, playbackParams.from, playbackParams.to, 0, 1, true);
|
|
26
|
+
setTime(toFixed(time));
|
|
27
|
+
})
|
|
28
|
+
}, [playbackParams?.from, playbackParams?.to, time]);
|
|
29
|
+
|
|
30
|
+
const scrollVideoManager = useMemo<ScrollPlaybackVideoManager | null>(() => {
|
|
31
|
+
if (!containerElement) return null;
|
|
32
|
+
const manager = new ScrollPlaybackVideoManager({
|
|
33
|
+
src,
|
|
34
|
+
videoContainer: containerElement
|
|
35
|
+
});
|
|
36
|
+
return manager;
|
|
37
|
+
}, [containerElement, src]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
return () => {
|
|
41
|
+
scrollVideoManager?.destroy();
|
|
42
|
+
};
|
|
43
|
+
}, [scrollVideoManager]);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (scrollVideoManager && time >= 0 && time <= 1) {
|
|
47
|
+
scrollVideoManager.setTargetTimePercent(time);
|
|
48
|
+
}
|
|
49
|
+
}, [time, scrollVideoManager]);
|
|
50
|
+
|
|
51
|
+
return <div className={className} style={style} ref={setContainerElement} />;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function toFixed(num: number) {
|
|
55
|
+
return Number(num.toFixed(3));
|
|
56
|
+
}
|
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
import { FC, ReactElement, useId, useRef } from 'react';
|
|
2
|
-
import JSXStyle from 'styled-jsx/style';
|
|
3
|
-
import {
|
|
4
|
-
getLayoutMediaQuery,
|
|
5
|
-
getLayoutStyles,
|
|
6
|
-
Section as TSection,
|
|
7
|
-
SectionHeight,
|
|
8
|
-
SectionHeightMode
|
|
9
|
-
} from '@cntrl-site/sdk';
|
|
10
|
-
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
11
|
-
import { useSectionRegistry } from '../../utils/ArticleRectManager/useSectionRegistry';
|
|
12
|
-
import { CntrlColor } from '@cntrl-site/color';
|
|
13
|
-
|
|
14
|
-
type SectionChild = ReactElement<any, any>;
|
|
15
|
-
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
16
|
-
|
|
17
|
-
interface Props {
|
|
18
|
-
section: TSection;
|
|
19
|
-
children: SectionChild[];
|
|
20
|
-
data?: any;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const Section: FC<Props> = ({ section, data, children }) => {
|
|
24
|
-
const id = useId();
|
|
25
|
-
const sectionRef = useRef<HTMLDivElement | null>(null);
|
|
26
|
-
const { layouts, customSections } = useCntrlContext();
|
|
27
|
-
const layoutValues: Record<string, any>[] = [section.height, section.color];
|
|
28
|
-
const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
|
|
29
|
-
useSectionRegistry(section.id, sectionRef.current);
|
|
30
|
-
const getSectionVisibilityStyles = () => {
|
|
31
|
-
return layouts
|
|
32
|
-
.sort((a, b) => a.startsWith - b.startsWith)
|
|
33
|
-
.reduce((acc, layout) => {
|
|
34
|
-
const isHidden = section.hidden[layout.id];
|
|
35
|
-
return `
|
|
36
|
-
${acc}
|
|
37
|
-
${getLayoutMediaQuery(layout.id, layouts)} {
|
|
38
|
-
.section-${section.id} {
|
|
39
|
-
display: ${isHidden ? 'none': 'block'};
|
|
40
|
-
}
|
|
41
|
-
}`;
|
|
42
|
-
}, '');
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
if (SectionComponent) return <div ref={sectionRef}><SectionComponent data={data}>{children}</SectionComponent></div>;
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<>
|
|
49
|
-
<div
|
|
50
|
-
className={`section-${section.id}`}
|
|
51
|
-
id={section.name}
|
|
52
|
-
ref={sectionRef}
|
|
53
|
-
>
|
|
54
|
-
{children}
|
|
55
|
-
</div>
|
|
56
|
-
<JSXStyle id={id}>{`
|
|
57
|
-
${
|
|
58
|
-
getLayoutStyles(layouts, layoutValues, ([height, color]) => (`
|
|
59
|
-
.section-${section.id} {
|
|
60
|
-
height: ${getSectionHeight(height)};
|
|
61
|
-
position: relative;
|
|
62
|
-
background-color: ${CntrlColor.parse(color ?? DEFAULT_COLOR).fmt('rgba')};
|
|
63
|
-
}`
|
|
64
|
-
))
|
|
65
|
-
}
|
|
66
|
-
${getSectionVisibilityStyles()}
|
|
67
|
-
`}</JSXStyle>
|
|
68
|
-
</>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export function getSectionHeight(heightData: SectionHeight): string {
|
|
73
|
-
const { units, vhUnits, mode } = heightData;
|
|
74
|
-
if (mode === SectionHeightMode.ViewportHeightUnits) return `${vhUnits}vh`;
|
|
75
|
-
if (mode === SectionHeightMode.ControlUnits) return `${units * 100}vw`;
|
|
76
|
-
return '0';
|
|
77
|
-
}
|
|
1
|
+
import { FC, ReactElement, useId, useRef } from 'react';
|
|
2
|
+
import JSXStyle from 'styled-jsx/style';
|
|
3
|
+
import {
|
|
4
|
+
getLayoutMediaQuery,
|
|
5
|
+
getLayoutStyles,
|
|
6
|
+
Section as TSection,
|
|
7
|
+
SectionHeight,
|
|
8
|
+
SectionHeightMode
|
|
9
|
+
} from '@cntrl-site/sdk';
|
|
10
|
+
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
11
|
+
import { useSectionRegistry } from '../../utils/ArticleRectManager/useSectionRegistry';
|
|
12
|
+
import { CntrlColor } from '@cntrl-site/color';
|
|
13
|
+
|
|
14
|
+
type SectionChild = ReactElement<any, any>;
|
|
15
|
+
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
section: TSection;
|
|
19
|
+
children: SectionChild[];
|
|
20
|
+
data?: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Section: FC<Props> = ({ section, data, children }) => {
|
|
24
|
+
const id = useId();
|
|
25
|
+
const sectionRef = useRef<HTMLDivElement | null>(null);
|
|
26
|
+
const { layouts, customSections } = useCntrlContext();
|
|
27
|
+
const layoutValues: Record<string, any>[] = [section.height, section.color];
|
|
28
|
+
const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
|
|
29
|
+
useSectionRegistry(section.id, sectionRef.current);
|
|
30
|
+
const getSectionVisibilityStyles = () => {
|
|
31
|
+
return layouts
|
|
32
|
+
.sort((a, b) => a.startsWith - b.startsWith)
|
|
33
|
+
.reduce((acc, layout) => {
|
|
34
|
+
const isHidden = section.hidden[layout.id];
|
|
35
|
+
return `
|
|
36
|
+
${acc}
|
|
37
|
+
${getLayoutMediaQuery(layout.id, layouts)} {
|
|
38
|
+
.section-${section.id} {
|
|
39
|
+
display: ${isHidden ? 'none': 'block'};
|
|
40
|
+
}
|
|
41
|
+
}`;
|
|
42
|
+
}, '');
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
if (SectionComponent) return <div ref={sectionRef}><SectionComponent data={data}>{children}</SectionComponent></div>;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<>
|
|
49
|
+
<div
|
|
50
|
+
className={`section-${section.id}`}
|
|
51
|
+
id={section.name}
|
|
52
|
+
ref={sectionRef}
|
|
53
|
+
>
|
|
54
|
+
{children}
|
|
55
|
+
</div>
|
|
56
|
+
<JSXStyle id={id}>{`
|
|
57
|
+
${
|
|
58
|
+
getLayoutStyles(layouts, layoutValues, ([height, color]) => (`
|
|
59
|
+
.section-${section.id} {
|
|
60
|
+
height: ${getSectionHeight(height)};
|
|
61
|
+
position: relative;
|
|
62
|
+
background-color: ${CntrlColor.parse(color ?? DEFAULT_COLOR).fmt('rgba')};
|
|
63
|
+
}`
|
|
64
|
+
))
|
|
65
|
+
}
|
|
66
|
+
${getSectionVisibilityStyles()}
|
|
67
|
+
`}</JSXStyle>
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export function getSectionHeight(heightData: SectionHeight): string {
|
|
73
|
+
const { units, vhUnits, mode } = heightData;
|
|
74
|
+
if (mode === SectionHeightMode.ViewportHeightUnits) return `${vhUnits}vh`;
|
|
75
|
+
if (mode === SectionHeightMode.ControlUnits) return `${units * 100}vw`;
|
|
76
|
+
return '0';
|
|
77
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { CntrlColor } from '@cntrl-site/color';
|
|
3
|
-
import { useLayoutContext } from '../useLayoutContext';
|
|
4
|
-
|
|
5
|
-
type LayoutIdentifier = string;
|
|
6
|
-
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
7
|
-
|
|
8
|
-
export const useSectionColor = (colorData: Record<LayoutIdentifier, string | null>): CntrlColor => {
|
|
9
|
-
const layoutId = useLayoutContext();
|
|
10
|
-
return useMemo(() => {
|
|
11
|
-
if (!layoutId) return CntrlColor.parse(DEFAULT_COLOR);
|
|
12
|
-
const layoutColor = colorData[layoutId];
|
|
13
|
-
return CntrlColor.parse(
|
|
14
|
-
!layoutColor
|
|
15
|
-
? DEFAULT_COLOR
|
|
16
|
-
: layoutColor
|
|
17
|
-
);
|
|
18
|
-
}, [layoutId]);
|
|
19
|
-
};
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { CntrlColor } from '@cntrl-site/color';
|
|
3
|
+
import { useLayoutContext } from '../useLayoutContext';
|
|
4
|
+
|
|
5
|
+
type LayoutIdentifier = string;
|
|
6
|
+
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
7
|
+
|
|
8
|
+
export const useSectionColor = (colorData: Record<LayoutIdentifier, string | null>): CntrlColor => {
|
|
9
|
+
const layoutId = useLayoutContext();
|
|
10
|
+
return useMemo(() => {
|
|
11
|
+
if (!layoutId) return CntrlColor.parse(DEFAULT_COLOR);
|
|
12
|
+
const layoutColor = colorData[layoutId];
|
|
13
|
+
return CntrlColor.parse(
|
|
14
|
+
!layoutColor
|
|
15
|
+
? DEFAULT_COLOR
|
|
16
|
+
: layoutColor
|
|
17
|
+
);
|
|
18
|
+
}, [layoutId]);
|
|
19
|
+
};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { useContext } from 'react';
|
|
2
|
-
import { CntrlContext } from '../../provider/CntrlContext';
|
|
3
|
-
import { Layout, SectionHeight } from '@cntrl-site/sdk';
|
|
4
|
-
import { getSectionHeight } from './Section';
|
|
5
|
-
|
|
6
|
-
export const useSectionHeightData = (sectionId: string): Record<string, string> => {
|
|
7
|
-
const sectionHeightContext = useContext(CntrlContext);
|
|
8
|
-
const layouts = sectionHeightContext.layouts;
|
|
9
|
-
const sectionHeightData = sectionHeightContext.getSectionHeightData(sectionId);
|
|
10
|
-
return sectionHeightData ? getSectionHeightMap(sectionHeightData) : getDefaultHeightData(layouts);
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function getSectionHeightMap(sectionHeight: Record<string, SectionHeight>): Record<string, string> {
|
|
14
|
-
return Object.fromEntries(Object.entries(sectionHeight).map(([sectionId, heightData]) => [sectionId, getSectionHeight(heightData)]));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function getDefaultHeightData(layouts: Layout[]) {
|
|
18
|
-
return layouts.reduce((acc, layout) => ({...acc, [layout.id]: '0'}), {});
|
|
19
|
-
}
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { CntrlContext } from '../../provider/CntrlContext';
|
|
3
|
+
import { Layout, SectionHeight } from '@cntrl-site/sdk';
|
|
4
|
+
import { getSectionHeight } from './Section';
|
|
5
|
+
|
|
6
|
+
export const useSectionHeightData = (sectionId: string): Record<string, string> => {
|
|
7
|
+
const sectionHeightContext = useContext(CntrlContext);
|
|
8
|
+
const layouts = sectionHeightContext.layouts;
|
|
9
|
+
const sectionHeightData = sectionHeightContext.getSectionHeightData(sectionId);
|
|
10
|
+
return sectionHeightData ? getSectionHeightMap(sectionHeightData) : getDefaultHeightData(layouts);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function getSectionHeightMap(sectionHeight: Record<string, SectionHeight>): Record<string, string> {
|
|
14
|
+
return Object.fromEntries(Object.entries(sectionHeight).map(([sectionId, heightData]) => [sectionId, getSectionHeight(heightData)]));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getDefaultHeightData(layouts: Layout[]) {
|
|
18
|
+
return layouts.reduce((acc, layout) => ({...acc, [layout.id]: '0'}), {});
|
|
19
|
+
}
|