@cntrl-site/sdk-nextjs 1.9.78 → 1.9.80-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/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/useCurrentLayout.js +5 -3
- package/lib/common/useItemFXData.js +5 -5
- package/lib/components/Article.js +5 -5
- package/lib/components/LayoutStyle.js +4 -4
- package/lib/components/Section/Section.js +27 -27
- package/lib/components/StructuredBlockItem/StructuredBlockItem.js +13 -13
- package/lib/components/StructuredBlockItem/StructuredComponent/StructuredComponent.js +15 -13
- package/lib/components/StructuredContent/StructuredContent.js +11 -11
- package/lib/components/items/CodeEmbedItem/CodeEmbedItem.js +36 -36
- package/lib/components/items/ComponentItem/ComponentItem.js +13 -13
- 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 +24 -24
- package/lib/components/items/EmbedVideoItem/YoutubeEmbed.js +27 -27
- package/lib/components/items/FileItem/ImageItem.js +40 -40
- package/lib/components/items/FileItem/VideoItem.js +64 -64
- package/lib/components/items/GroupItem/GroupItem.js +14 -14
- package/lib/components/items/Item.js +30 -30
- package/lib/components/items/RectangleItem/RectangleItem.js +27 -27
- package/lib/components/items/RichTextItem/RichTextItem.js +22 -22
- package/lib/utils/RichTextConverter/RichTextConverter.js +21 -21
- package/package.json +62 -62
- package/src/ItemGeometry/CSSPropertyNameMap.ts +37 -37
- package/src/ItemGeometry/GenericGeometryController.ts +59 -59
- package/src/ItemGeometry/ItemGeometryContext.ts +4 -4
- package/src/ItemGeometry/ItemGeometryController.ts +22 -22
- package/src/ItemGeometry/ItemGeometryService.ts +34 -34
- package/src/ItemGeometry/RichTextGeometryController.ts +166 -166
- package/src/ItemGeometry/useItemGeometry.ts +25 -25
- package/src/common/useCurrentLayout.ts +53 -52
- package/src/common/useExemplary.ts +9 -9
- package/src/common/useItemFXData.ts +63 -63
- package/src/common/useKeyframeValue.ts +85 -85
- package/src/common/useRegisterResize.ts +16 -16
- package/src/components/Article.tsx +69 -69
- package/src/components/ArticleWrapper.tsx +21 -21
- package/src/components/Head.tsx +95 -95
- package/src/components/LayoutStyle.tsx +21 -21
- package/src/components/Page.tsx +47 -47
- package/src/components/ScrollPlaybackVideo.tsx +75 -75
- package/src/components/Section/Section.tsx +162 -162
- package/src/components/Section/SectionImage.tsx +48 -48
- package/src/components/Section/SectionVideo.tsx +144 -144
- package/src/components/Section/useSectionColor.ts +19 -19
- package/src/components/Section/useSectionHeightMap.ts +19 -19
- package/src/components/StructuredBlockItem/StructuredBlockItem.tsx +69 -69
- package/src/components/StructuredBlockItem/StructuredComponent/StructuredComponent.tsx +68 -66
- package/src/components/StructuredContent/StructuredContent.tsx +42 -42
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +148 -148
- package/src/components/items/CodeEmbedItem/useCodeEmbedItem.ts +36 -36
- package/src/components/items/ComponentItem/ComponentItem.tsx +85 -85
- package/src/components/items/ComponentItem/useComponentItem.ts +35 -35
- package/src/components/items/CompoundItem/CompoundChild.tsx +151 -151
- package/src/components/items/CompoundItem/CompoundItem.tsx +88 -88
- package/src/components/items/CompoundItem/useCompoundItem.ts +21 -21
- package/src/components/items/CustomItem/CustomItem.tsx +50 -50
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +217 -217
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +201 -201
- package/src/components/items/EmbedVideoItem/useEmbedVideoItem.ts +46 -46
- package/src/components/items/FileItem/ImageItem.tsx +166 -166
- package/src/components/items/FileItem/VideoItem.tsx +287 -287
- package/src/components/items/FileItem/useFileItem.ts +81 -81
- package/src/components/items/GroupItem/GroupItem.tsx +99 -99
- package/src/components/items/GroupItem/useGroupItem.ts +34 -34
- package/src/components/items/Item.tsx +268 -268
- package/src/components/items/LinkWrapper.tsx +39 -39
- package/src/components/items/RectangleItem/RectangleItem.tsx +177 -177
- package/src/components/items/RectangleItem/useRectangleItem.ts +89 -89
- package/src/components/items/RichTextItem/RichTextItem.tsx +113 -113
- package/src/components/items/RichTextItem/useRichTextItem.ts +12 -12
- package/src/components/items/RichTextWrapper.tsx +15 -15
- package/src/components/items/itemsMap.ts +28 -28
- 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 +66 -66
- 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 +25 -25
- package/src/interactions/InteractionsRegistry.ts +513 -513
- package/src/interactions/ItemInteractionCtrl.ts +78 -78
- 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 +113 -113
- 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.tsx +73 -73
- package/src/provider/Keyframes.ts +11 -11
- package/src/provider/KeyframesContext.ts +5 -5
- package/src/provider/LayoutContext.ts +3 -3
- package/src/provider/WebGLContextManagerContext.tsx +4 -4
- package/src/provider/defaultContext.ts +8 -8
- package/src/provider/useCntrlContext.ts +8 -8
- package/src/styled-jsx.d.ts +1 -1
- package/src/types/components-utils.d.ts +7 -7
- package/src/utils/Animator/Animator.ts +570 -570
- 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/CSSNumeric.ts +19 -19
- package/src/utils/EventEmitter.ts +41 -41
- package/src/utils/RichTextConverter/RichTextConverter.tsx +342 -342
- 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/areFillsVisible/areFillsVisible.test.ts +63 -63
- package/src/utils/areFillsVisible/areFillsVisible.ts +37 -37
- package/src/utils/binSearchInsertAt.ts +33 -33
- package/src/utils/castObject.ts +10 -10
- package/src/utils/checkOverflowClipSupport.ts +13 -13
- package/src/utils/domDfs.ts +11 -11
- package/src/utils/effects/useImageFx.ts +154 -154
- package/src/utils/effects/useVideoFx.ts +156 -156
- package/src/utils/evaluateComponentBundle.ts +83 -83
- package/src/utils/getAnchoredItemTop.ts +12 -12
- package/src/utils/getCompoundBoundaryStyles.ts +60 -60
- package/src/utils/getFill.ts +46 -46
- package/src/utils/getFontFamilyValue.ts +3 -3
- package/src/utils/getInvertedRanges.ts +43 -43
- package/src/utils/getItemTopStyle.ts +39 -39
- package/src/utils/getStyleFromItemStateAndParams.ts +8 -8
- package/src/utils/getValidYoutubeUrl.ts +29 -29
- package/src/utils/isItemType.ts +5 -5
- package/src/utils/rangeMap.ts +13 -13
- package/src/utils/useElementRect.ts +23 -23
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { MediaEffect, VideoTextureManager } from '@cntrl-site/effects';
|
|
3
|
-
import { rangeMap } from '../rangeMap';
|
|
4
|
-
import { WebglContextManagerContext } from '../../provider/WebGLContextManagerContext';
|
|
5
|
-
|
|
6
|
-
interface FxParams {
|
|
7
|
-
videoUrl?: string;
|
|
8
|
-
fragmentShader: string | null;
|
|
9
|
-
controls?: Record<string, number | [number, number]>;
|
|
10
|
-
texturesUrls: string[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function useVideoFx(
|
|
14
|
-
canvas: HTMLCanvasElement | null | undefined,
|
|
15
|
-
enabled: boolean,
|
|
16
|
-
{
|
|
17
|
-
videoUrl,
|
|
18
|
-
fragmentShader,
|
|
19
|
-
controls,
|
|
20
|
-
texturesUrls
|
|
21
|
-
}: FxParams,
|
|
22
|
-
width: number,
|
|
23
|
-
height: number
|
|
24
|
-
): boolean {
|
|
25
|
-
const [isFXAllowed, setIsFXAllowed] = useState(true);
|
|
26
|
-
const [isReady, setIsReady] = useState(false);
|
|
27
|
-
const active = enabled && isReady;
|
|
28
|
-
const webGLContextManager = useContext(WebglContextManagerContext);
|
|
29
|
-
const glRef = useRef<WebGL2RenderingContext | null>(null);
|
|
30
|
-
const isRenderingRef = useRef(false);
|
|
31
|
-
const frameRef = useRef<number>();
|
|
32
|
-
const videoTextureManager = useMemo(() => {
|
|
33
|
-
if (!videoUrl || !enabled) return;
|
|
34
|
-
const handlePlayError = () => {
|
|
35
|
-
setIsFXAllowed(false);
|
|
36
|
-
};
|
|
37
|
-
return new VideoTextureManager(videoUrl, handlePlayError);
|
|
38
|
-
}, [videoUrl, enabled]);
|
|
39
|
-
const videoFx = useMemo<MediaEffect | undefined>(() => {
|
|
40
|
-
if (!videoTextureManager) return;
|
|
41
|
-
return new MediaEffect(
|
|
42
|
-
videoTextureManager,
|
|
43
|
-
texturesUrls,
|
|
44
|
-
fragmentShader!,
|
|
45
|
-
{
|
|
46
|
-
time: 0,
|
|
47
|
-
cursor: [0, 0],
|
|
48
|
-
...controls
|
|
49
|
-
},
|
|
50
|
-
width,
|
|
51
|
-
height
|
|
52
|
-
);
|
|
53
|
-
}, [videoTextureManager, fragmentShader, width, height, texturesUrls]);
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
if (!videoTextureManager) return;
|
|
57
|
-
videoTextureManager.onReadyStatusChange(setIsReady);
|
|
58
|
-
}, [videoTextureManager]);
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (!canvas || !videoFx) return;
|
|
62
|
-
const handleMouseMove = (evt: MouseEvent) => {
|
|
63
|
-
const rect = canvas.getBoundingClientRect();
|
|
64
|
-
const x = rangeMap(evt.clientX, rect.left, rect.left + rect.width, 0, 1, true);
|
|
65
|
-
const y = rangeMap(evt.clientY, rect.top, rect.top + rect.height, 0, 1, true);
|
|
66
|
-
videoFx.setParam('cursor', [x, y]);
|
|
67
|
-
};
|
|
68
|
-
window.addEventListener('mousemove', handleMouseMove, { capture: true, passive: true });
|
|
69
|
-
return () => {
|
|
70
|
-
window.removeEventListener('mousemove', handleMouseMove);
|
|
71
|
-
};
|
|
72
|
-
}, [canvas, videoFx]);
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (!active || !canvas || !videoFx) return;
|
|
76
|
-
let time = 0;
|
|
77
|
-
|
|
78
|
-
const startRendering = () => {
|
|
79
|
-
if (isRenderingRef.current) return;
|
|
80
|
-
|
|
81
|
-
const gl = webGLContextManager.getContext(canvas);
|
|
82
|
-
if (!gl) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
glRef.current = gl;
|
|
87
|
-
isRenderingRef.current = true;
|
|
88
|
-
|
|
89
|
-
videoFx.prepare(gl);
|
|
90
|
-
|
|
91
|
-
const renderFrame = () => {
|
|
92
|
-
if (!isRenderingRef.current || !glRef.current) return;
|
|
93
|
-
|
|
94
|
-
time += 0.1;
|
|
95
|
-
|
|
96
|
-
webGLContextManager.updateContextSize(glRef.current, canvas.width, canvas.height);
|
|
97
|
-
|
|
98
|
-
videoFx.setViewport(Math.floor(canvas.width), Math.floor(canvas.height));
|
|
99
|
-
videoFx.setParam('time', time);
|
|
100
|
-
try {
|
|
101
|
-
videoFx.render(glRef.current);
|
|
102
|
-
} catch {
|
|
103
|
-
setIsFXAllowed(false);
|
|
104
|
-
}
|
|
105
|
-
webGLContextManager.renderToCanvas(glRef.current, canvas);
|
|
106
|
-
|
|
107
|
-
frameRef.current = requestAnimationFrame(renderFrame);
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
frameRef.current = requestAnimationFrame(renderFrame);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const stopRendering = () => {
|
|
114
|
-
if (!isRenderingRef.current) return;
|
|
115
|
-
|
|
116
|
-
if (frameRef.current) {
|
|
117
|
-
cancelAnimationFrame(frameRef.current);
|
|
118
|
-
frameRef.current = undefined;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (glRef.current) {
|
|
122
|
-
webGLContextManager.releaseContext(canvas);
|
|
123
|
-
glRef.current = null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const ctx = canvas.getContext('2d');
|
|
127
|
-
if (ctx) {
|
|
128
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
isRenderingRef.current = false;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const observer = new IntersectionObserver(
|
|
135
|
-
([entry]) => {
|
|
136
|
-
if (entry.isIntersecting) {
|
|
137
|
-
startRendering();
|
|
138
|
-
} else {
|
|
139
|
-
stopRendering();
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
threshold: 0,
|
|
144
|
-
rootMargin: '75px'
|
|
145
|
-
}
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
observer.observe(canvas);
|
|
149
|
-
|
|
150
|
-
return () => {
|
|
151
|
-
stopRendering();
|
|
152
|
-
observer.disconnect();
|
|
153
|
-
};
|
|
154
|
-
}, [canvas, videoFx, active]);
|
|
155
|
-
return isFXAllowed;
|
|
156
|
-
}
|
|
1
|
+
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { MediaEffect, VideoTextureManager } from '@cntrl-site/effects';
|
|
3
|
+
import { rangeMap } from '../rangeMap';
|
|
4
|
+
import { WebglContextManagerContext } from '../../provider/WebGLContextManagerContext';
|
|
5
|
+
|
|
6
|
+
interface FxParams {
|
|
7
|
+
videoUrl?: string;
|
|
8
|
+
fragmentShader: string | null;
|
|
9
|
+
controls?: Record<string, number | [number, number]>;
|
|
10
|
+
texturesUrls: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function useVideoFx(
|
|
14
|
+
canvas: HTMLCanvasElement | null | undefined,
|
|
15
|
+
enabled: boolean,
|
|
16
|
+
{
|
|
17
|
+
videoUrl,
|
|
18
|
+
fragmentShader,
|
|
19
|
+
controls,
|
|
20
|
+
texturesUrls
|
|
21
|
+
}: FxParams,
|
|
22
|
+
width: number,
|
|
23
|
+
height: number
|
|
24
|
+
): boolean {
|
|
25
|
+
const [isFXAllowed, setIsFXAllowed] = useState(true);
|
|
26
|
+
const [isReady, setIsReady] = useState(false);
|
|
27
|
+
const active = enabled && isReady;
|
|
28
|
+
const webGLContextManager = useContext(WebglContextManagerContext);
|
|
29
|
+
const glRef = useRef<WebGL2RenderingContext | null>(null);
|
|
30
|
+
const isRenderingRef = useRef(false);
|
|
31
|
+
const frameRef = useRef<number>();
|
|
32
|
+
const videoTextureManager = useMemo(() => {
|
|
33
|
+
if (!videoUrl || !enabled) return;
|
|
34
|
+
const handlePlayError = () => {
|
|
35
|
+
setIsFXAllowed(false);
|
|
36
|
+
};
|
|
37
|
+
return new VideoTextureManager(videoUrl, handlePlayError);
|
|
38
|
+
}, [videoUrl, enabled]);
|
|
39
|
+
const videoFx = useMemo<MediaEffect | undefined>(() => {
|
|
40
|
+
if (!videoTextureManager) return;
|
|
41
|
+
return new MediaEffect(
|
|
42
|
+
videoTextureManager,
|
|
43
|
+
texturesUrls,
|
|
44
|
+
fragmentShader!,
|
|
45
|
+
{
|
|
46
|
+
time: 0,
|
|
47
|
+
cursor: [0, 0],
|
|
48
|
+
...controls
|
|
49
|
+
},
|
|
50
|
+
width,
|
|
51
|
+
height
|
|
52
|
+
);
|
|
53
|
+
}, [videoTextureManager, fragmentShader, width, height, texturesUrls]);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!videoTextureManager) return;
|
|
57
|
+
videoTextureManager.onReadyStatusChange(setIsReady);
|
|
58
|
+
}, [videoTextureManager]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!canvas || !videoFx) return;
|
|
62
|
+
const handleMouseMove = (evt: MouseEvent) => {
|
|
63
|
+
const rect = canvas.getBoundingClientRect();
|
|
64
|
+
const x = rangeMap(evt.clientX, rect.left, rect.left + rect.width, 0, 1, true);
|
|
65
|
+
const y = rangeMap(evt.clientY, rect.top, rect.top + rect.height, 0, 1, true);
|
|
66
|
+
videoFx.setParam('cursor', [x, y]);
|
|
67
|
+
};
|
|
68
|
+
window.addEventListener('mousemove', handleMouseMove, { capture: true, passive: true });
|
|
69
|
+
return () => {
|
|
70
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
71
|
+
};
|
|
72
|
+
}, [canvas, videoFx]);
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!active || !canvas || !videoFx) return;
|
|
76
|
+
let time = 0;
|
|
77
|
+
|
|
78
|
+
const startRendering = () => {
|
|
79
|
+
if (isRenderingRef.current) return;
|
|
80
|
+
|
|
81
|
+
const gl = webGLContextManager.getContext(canvas);
|
|
82
|
+
if (!gl) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
glRef.current = gl;
|
|
87
|
+
isRenderingRef.current = true;
|
|
88
|
+
|
|
89
|
+
videoFx.prepare(gl);
|
|
90
|
+
|
|
91
|
+
const renderFrame = () => {
|
|
92
|
+
if (!isRenderingRef.current || !glRef.current) return;
|
|
93
|
+
|
|
94
|
+
time += 0.1;
|
|
95
|
+
|
|
96
|
+
webGLContextManager.updateContextSize(glRef.current, canvas.width, canvas.height);
|
|
97
|
+
|
|
98
|
+
videoFx.setViewport(Math.floor(canvas.width), Math.floor(canvas.height));
|
|
99
|
+
videoFx.setParam('time', time);
|
|
100
|
+
try {
|
|
101
|
+
videoFx.render(glRef.current);
|
|
102
|
+
} catch {
|
|
103
|
+
setIsFXAllowed(false);
|
|
104
|
+
}
|
|
105
|
+
webGLContextManager.renderToCanvas(glRef.current, canvas);
|
|
106
|
+
|
|
107
|
+
frameRef.current = requestAnimationFrame(renderFrame);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
frameRef.current = requestAnimationFrame(renderFrame);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const stopRendering = () => {
|
|
114
|
+
if (!isRenderingRef.current) return;
|
|
115
|
+
|
|
116
|
+
if (frameRef.current) {
|
|
117
|
+
cancelAnimationFrame(frameRef.current);
|
|
118
|
+
frameRef.current = undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (glRef.current) {
|
|
122
|
+
webGLContextManager.releaseContext(canvas);
|
|
123
|
+
glRef.current = null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const ctx = canvas.getContext('2d');
|
|
127
|
+
if (ctx) {
|
|
128
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
isRenderingRef.current = false;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const observer = new IntersectionObserver(
|
|
135
|
+
([entry]) => {
|
|
136
|
+
if (entry.isIntersecting) {
|
|
137
|
+
startRendering();
|
|
138
|
+
} else {
|
|
139
|
+
stopRendering();
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
threshold: 0,
|
|
144
|
+
rootMargin: '75px'
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
observer.observe(canvas);
|
|
149
|
+
|
|
150
|
+
return () => {
|
|
151
|
+
stopRendering();
|
|
152
|
+
observer.disconnect();
|
|
153
|
+
};
|
|
154
|
+
}, [canvas, videoFx, active]);
|
|
155
|
+
return isFXAllowed;
|
|
156
|
+
}
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
import * as jsxRuntime from 'react/jsx-runtime';
|
|
4
|
-
import { Component as TComponent } from '@cntrl-site/components';
|
|
5
|
-
import * as componentUtils from '@cntrl-site/components/utils';
|
|
6
|
-
|
|
7
|
-
let globalsInitialized = false;
|
|
8
|
-
|
|
9
|
-
function ensureGlobals() {
|
|
10
|
-
if (globalsInitialized) return;
|
|
11
|
-
(globalThis as any).__CNTRL_REACT__ = React;
|
|
12
|
-
(globalThis as any).__CNTRL_REACT_DOM__ = ReactDOM;
|
|
13
|
-
(globalThis as any).__CNTRL_JSX_RUNTIME__ = jsxRuntime;
|
|
14
|
-
(globalThis as any).__CNTRL_COMPONENT_UTILS__ = componentUtils;
|
|
15
|
-
globalsInitialized = true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function transformEsmToEvaluatable(code: string): string {
|
|
19
|
-
let transformed = code;
|
|
20
|
-
let hasDefault = false;
|
|
21
|
-
|
|
22
|
-
transformed = transformed.replace(
|
|
23
|
-
/export\s*\{\s*(\w+)\s+as\s+default\s*\}\s*;?/g,
|
|
24
|
-
(_, name) => { hasDefault = true; return `var __cntrl_default_export__ = ${name};`; }
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
transformed = transformed.replace(
|
|
28
|
-
/export\s+default\s+/g,
|
|
29
|
-
() => { hasDefault = true; return 'var __cntrl_default_export__ = '; }
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
transformed = transformed.replace(
|
|
33
|
-
/export\s*\{\s*([^}]*)\}\s*;?/g,
|
|
34
|
-
(_, names) => {
|
|
35
|
-
if (!hasDefault) {
|
|
36
|
-
const firstName = names.split(',')[0].trim().split(/\s+/)[0];
|
|
37
|
-
if (firstName) {
|
|
38
|
-
hasDefault = true;
|
|
39
|
-
return `var __cntrl_default_export__ = ${firstName};`;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return '';
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
return `${transformed}\nreturn __cntrl_default_export__;`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function evaluateComponentBundle(
|
|
50
|
-
bundleCode: string
|
|
51
|
-
): (props: any) => React.ReactElement {
|
|
52
|
-
ensureGlobals();
|
|
53
|
-
const evaluatable = transformEsmToEvaluatable(bundleCode);
|
|
54
|
-
const fn = new Function(evaluatable);
|
|
55
|
-
return fn();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const resolvedCache = new Map<string, (props: any) => React.ReactElement>();
|
|
59
|
-
|
|
60
|
-
export function resolveCustomComponents(
|
|
61
|
-
bundles: Record<string, string>,
|
|
62
|
-
schemas?: Record<string, Record<string, unknown>>
|
|
63
|
-
): Map<string, TComponent> {
|
|
64
|
-
const result = new Map<string, TComponent>();
|
|
65
|
-
for (const [id, code] of Object.entries(bundles)) {
|
|
66
|
-
try {
|
|
67
|
-
let element = resolvedCache.get(id);
|
|
68
|
-
if (!element) {
|
|
69
|
-
element = evaluateComponentBundle(code);
|
|
70
|
-
resolvedCache.set(id, element);
|
|
71
|
-
}
|
|
72
|
-
result.set(id, {
|
|
73
|
-
id,
|
|
74
|
-
name: id,
|
|
75
|
-
element,
|
|
76
|
-
schema: schemas?.[id] ?? {}
|
|
77
|
-
} as TComponent);
|
|
78
|
-
} catch (err) {
|
|
79
|
-
console.error(`Failed to evaluate custom component bundle "${id}":`, err);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return result;
|
|
83
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import * as jsxRuntime from 'react/jsx-runtime';
|
|
4
|
+
import { Component as TComponent } from '@cntrl-site/components';
|
|
5
|
+
import * as componentUtils from '@cntrl-site/components/utils';
|
|
6
|
+
|
|
7
|
+
let globalsInitialized = false;
|
|
8
|
+
|
|
9
|
+
function ensureGlobals() {
|
|
10
|
+
if (globalsInitialized) return;
|
|
11
|
+
(globalThis as any).__CNTRL_REACT__ = React;
|
|
12
|
+
(globalThis as any).__CNTRL_REACT_DOM__ = ReactDOM;
|
|
13
|
+
(globalThis as any).__CNTRL_JSX_RUNTIME__ = jsxRuntime;
|
|
14
|
+
(globalThis as any).__CNTRL_COMPONENT_UTILS__ = componentUtils;
|
|
15
|
+
globalsInitialized = true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function transformEsmToEvaluatable(code: string): string {
|
|
19
|
+
let transformed = code;
|
|
20
|
+
let hasDefault = false;
|
|
21
|
+
|
|
22
|
+
transformed = transformed.replace(
|
|
23
|
+
/export\s*\{\s*(\w+)\s+as\s+default\s*\}\s*;?/g,
|
|
24
|
+
(_, name) => { hasDefault = true; return `var __cntrl_default_export__ = ${name};`; }
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
transformed = transformed.replace(
|
|
28
|
+
/export\s+default\s+/g,
|
|
29
|
+
() => { hasDefault = true; return 'var __cntrl_default_export__ = '; }
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
transformed = transformed.replace(
|
|
33
|
+
/export\s*\{\s*([^}]*)\}\s*;?/g,
|
|
34
|
+
(_, names) => {
|
|
35
|
+
if (!hasDefault) {
|
|
36
|
+
const firstName = names.split(',')[0].trim().split(/\s+/)[0];
|
|
37
|
+
if (firstName) {
|
|
38
|
+
hasDefault = true;
|
|
39
|
+
return `var __cntrl_default_export__ = ${firstName};`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return `${transformed}\nreturn __cntrl_default_export__;`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function evaluateComponentBundle(
|
|
50
|
+
bundleCode: string
|
|
51
|
+
): (props: any) => React.ReactElement {
|
|
52
|
+
ensureGlobals();
|
|
53
|
+
const evaluatable = transformEsmToEvaluatable(bundleCode);
|
|
54
|
+
const fn = new Function(evaluatable);
|
|
55
|
+
return fn();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const resolvedCache = new Map<string, (props: any) => React.ReactElement>();
|
|
59
|
+
|
|
60
|
+
export function resolveCustomComponents(
|
|
61
|
+
bundles: Record<string, string>,
|
|
62
|
+
schemas?: Record<string, Record<string, unknown>>
|
|
63
|
+
): Map<string, TComponent> {
|
|
64
|
+
const result = new Map<string, TComponent>();
|
|
65
|
+
for (const [id, code] of Object.entries(bundles)) {
|
|
66
|
+
try {
|
|
67
|
+
let element = resolvedCache.get(id);
|
|
68
|
+
if (!element) {
|
|
69
|
+
element = evaluateComponentBundle(code);
|
|
70
|
+
resolvedCache.set(id, element);
|
|
71
|
+
}
|
|
72
|
+
result.set(id, {
|
|
73
|
+
id,
|
|
74
|
+
name: id,
|
|
75
|
+
element,
|
|
76
|
+
schema: schemas?.[id] ?? {}
|
|
77
|
+
} as TComponent);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(`Failed to evaluate custom component bundle "${id}":`, err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { AnchorSide } from '@cntrl-site/sdk';
|
|
2
|
-
|
|
3
|
-
export function getAnchoredItemTop(top: number, sectionHeight: string, anchorSide?: AnchorSide) {
|
|
4
|
-
const styleTop = `${top * 100}vw`;
|
|
5
|
-
switch (anchorSide) {
|
|
6
|
-
case AnchorSide.Center: return `calc(${styleTop} + ${sectionHeight} / 2)`;
|
|
7
|
-
case AnchorSide.Bottom: return `calc(${styleTop} + ${sectionHeight})`;
|
|
8
|
-
case AnchorSide.Top:
|
|
9
|
-
default:
|
|
10
|
-
return styleTop;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
1
|
+
import { AnchorSide } from '@cntrl-site/sdk';
|
|
2
|
+
|
|
3
|
+
export function getAnchoredItemTop(top: number, sectionHeight: string, anchorSide?: AnchorSide) {
|
|
4
|
+
const styleTop = `${top * 100}vw`;
|
|
5
|
+
switch (anchorSide) {
|
|
6
|
+
case AnchorSide.Center: return `calc(${styleTop} + ${sectionHeight} / 2)`;
|
|
7
|
+
case AnchorSide.Bottom: return `calc(${styleTop} + ${sectionHeight})`;
|
|
8
|
+
case AnchorSide.Top:
|
|
9
|
+
default:
|
|
10
|
+
return styleTop;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { AreaAnchor, DimensionMode } from '@cntrl-site/sdk';
|
|
2
|
-
|
|
3
|
-
const positionMatrix: Record<AreaAnchor, [number, number]> = {
|
|
4
|
-
[AreaAnchor.TopLeft]: [0, 0],
|
|
5
|
-
[AreaAnchor.TopCenter]: [0, 0.5],
|
|
6
|
-
[AreaAnchor.TopRight]: [0, 1],
|
|
7
|
-
[AreaAnchor.MiddleLeft]: [0.5, 0],
|
|
8
|
-
[AreaAnchor.MiddleCenter]: [0.5, 0.5],
|
|
9
|
-
[AreaAnchor.MiddleRight]: [0.5, 1],
|
|
10
|
-
[AreaAnchor.BottomLeft]: [1, 0],
|
|
11
|
-
[AreaAnchor.BottomCenter]: [1, 0.5],
|
|
12
|
-
[AreaAnchor.BottomRight]: [1, 1]
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export function getCompoundHeight(compoundSettings: CompoundSettings | undefined, height: number | undefined) {
|
|
16
|
-
if (height === undefined || !compoundSettings) return;
|
|
17
|
-
if (compoundSettings.heightMode === 'relative') {
|
|
18
|
-
return `${height * 100}%`;
|
|
19
|
-
}
|
|
20
|
-
return `${height * 100}vw`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function getCompoundWidth(compoundSettings: CompoundSettings | undefined, width: number | undefined, isRichText: boolean, exemplary?: number) {
|
|
24
|
-
if (width === undefined || !compoundSettings) return;
|
|
25
|
-
if (compoundSettings.widthMode === 'relative') {
|
|
26
|
-
return `${width * 100}%`;
|
|
27
|
-
}
|
|
28
|
-
return isRichText && exemplary ? `${width * exemplary}px` : `${width * 100}vw`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function getCompoundTop(compoundSettings: CompoundSettings | undefined, top: number | undefined) {
|
|
32
|
-
if (top === undefined || !compoundSettings) return;
|
|
33
|
-
if (compoundSettings.heightMode === 'relative') {
|
|
34
|
-
return `${top * 100}%`;
|
|
35
|
-
}
|
|
36
|
-
const [ky] = positionMatrix[compoundSettings.positionAnchor];
|
|
37
|
-
return `calc(${ky * 100}% + ${top * 100}vw)`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function getCompoundLeft(compoundSettings: CompoundSettings | undefined, left: number | undefined) {
|
|
41
|
-
if (left === undefined || !compoundSettings) return;
|
|
42
|
-
if (compoundSettings.widthMode === 'relative') {
|
|
43
|
-
return `${left * 100}%`;
|
|
44
|
-
}
|
|
45
|
-
const [_, kx] = positionMatrix[compoundSettings.positionAnchor];
|
|
46
|
-
return `calc(${kx * 100}% + ${left * 100}vw)`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function getCompoundTransform(compoundSettings: CompoundSettings | undefined) {
|
|
50
|
-
if (!compoundSettings) return 'unset';
|
|
51
|
-
const areaAnchor = compoundSettings.positionAnchor as AreaAnchor;
|
|
52
|
-
const [ky, kx] = positionMatrix[areaAnchor];
|
|
53
|
-
return `translate(${kx * (-100)}%, ${ky * (-100)}%)`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type CompoundSettings = {
|
|
57
|
-
positionAnchor: AreaAnchor;
|
|
58
|
-
widthMode: DimensionMode;
|
|
59
|
-
heightMode: DimensionMode;
|
|
60
|
-
};
|
|
1
|
+
import { AreaAnchor, DimensionMode } from '@cntrl-site/sdk';
|
|
2
|
+
|
|
3
|
+
const positionMatrix: Record<AreaAnchor, [number, number]> = {
|
|
4
|
+
[AreaAnchor.TopLeft]: [0, 0],
|
|
5
|
+
[AreaAnchor.TopCenter]: [0, 0.5],
|
|
6
|
+
[AreaAnchor.TopRight]: [0, 1],
|
|
7
|
+
[AreaAnchor.MiddleLeft]: [0.5, 0],
|
|
8
|
+
[AreaAnchor.MiddleCenter]: [0.5, 0.5],
|
|
9
|
+
[AreaAnchor.MiddleRight]: [0.5, 1],
|
|
10
|
+
[AreaAnchor.BottomLeft]: [1, 0],
|
|
11
|
+
[AreaAnchor.BottomCenter]: [1, 0.5],
|
|
12
|
+
[AreaAnchor.BottomRight]: [1, 1]
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function getCompoundHeight(compoundSettings: CompoundSettings | undefined, height: number | undefined) {
|
|
16
|
+
if (height === undefined || !compoundSettings) return;
|
|
17
|
+
if (compoundSettings.heightMode === 'relative') {
|
|
18
|
+
return `${height * 100}%`;
|
|
19
|
+
}
|
|
20
|
+
return `${height * 100}vw`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getCompoundWidth(compoundSettings: CompoundSettings | undefined, width: number | undefined, isRichText: boolean, exemplary?: number) {
|
|
24
|
+
if (width === undefined || !compoundSettings) return;
|
|
25
|
+
if (compoundSettings.widthMode === 'relative') {
|
|
26
|
+
return `${width * 100}%`;
|
|
27
|
+
}
|
|
28
|
+
return isRichText && exemplary ? `${width * exemplary}px` : `${width * 100}vw`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getCompoundTop(compoundSettings: CompoundSettings | undefined, top: number | undefined) {
|
|
32
|
+
if (top === undefined || !compoundSettings) return;
|
|
33
|
+
if (compoundSettings.heightMode === 'relative') {
|
|
34
|
+
return `${top * 100}%`;
|
|
35
|
+
}
|
|
36
|
+
const [ky] = positionMatrix[compoundSettings.positionAnchor];
|
|
37
|
+
return `calc(${ky * 100}% + ${top * 100}vw)`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getCompoundLeft(compoundSettings: CompoundSettings | undefined, left: number | undefined) {
|
|
41
|
+
if (left === undefined || !compoundSettings) return;
|
|
42
|
+
if (compoundSettings.widthMode === 'relative') {
|
|
43
|
+
return `${left * 100}%`;
|
|
44
|
+
}
|
|
45
|
+
const [_, kx] = positionMatrix[compoundSettings.positionAnchor];
|
|
46
|
+
return `calc(${kx * 100}% + ${left * 100}vw)`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getCompoundTransform(compoundSettings: CompoundSettings | undefined) {
|
|
50
|
+
if (!compoundSettings) return 'unset';
|
|
51
|
+
const areaAnchor = compoundSettings.positionAnchor as AreaAnchor;
|
|
52
|
+
const [ky, kx] = positionMatrix[areaAnchor];
|
|
53
|
+
return `translate(${kx * (-100)}%, ${ky * (-100)}%)`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type CompoundSettings = {
|
|
57
|
+
positionAnchor: AreaAnchor;
|
|
58
|
+
widthMode: DimensionMode;
|
|
59
|
+
heightMode: DimensionMode;
|
|
60
|
+
};
|