@cntrl-site/sdk-nextjs 1.9.78 → 1.9.79
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/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/modules.xml +8 -0
- package/.idea/sdk-nextjs.iml +12 -0
- package/.idea/vcs.xml +6 -0
- 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 +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 +12 -12
- 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 +52 -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 +66 -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,166 +1,166 @@
|
|
|
1
|
-
import { measureFont, Rect } from '@cntrl-site/sdk';
|
|
2
|
-
import { ItemGeometryController } from './ItemGeometryController';
|
|
3
|
-
import { domDfs } from '../utils/domDfs';
|
|
4
|
-
import { formatCSSNumber, parseCSSNumber } from '../utils/CSSNumeric';
|
|
5
|
-
|
|
6
|
-
export enum SizingType {
|
|
7
|
-
Auto = 'auto',
|
|
8
|
-
Manual = 'manual',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface RichTextGeometryOptions {
|
|
12
|
-
xSizing: SizingType;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type GeomtryRegistry = {
|
|
16
|
-
getControllerById: (itemId: string) => ItemGeometryController;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export class RichTextGeometryController implements ItemGeometryController {
|
|
20
|
-
private scale: number = 1;
|
|
21
|
-
private angle: number = 0;
|
|
22
|
-
private options!: RichTextGeometryOptions;
|
|
23
|
-
private parentId?: string;
|
|
24
|
-
private registry: GeomtryRegistry | undefined;
|
|
25
|
-
static parseCssValue(value: string) {
|
|
26
|
-
const parsedLs = Number.parseInt(value);
|
|
27
|
-
return Number.isNaN(parsedLs) ? 0 : parsedLs;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
private container: HTMLElement
|
|
32
|
-
) { }
|
|
33
|
-
|
|
34
|
-
setRegistry(registry: GeomtryRegistry) {
|
|
35
|
-
this.registry = registry;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
getBoundary(isRotatedBoundary?: boolean): Rect {
|
|
39
|
-
const rect = this.container.getBoundingClientRect();
|
|
40
|
-
if (isRotatedBoundary) {
|
|
41
|
-
return Rect.fromObject(rect);
|
|
42
|
-
}
|
|
43
|
-
const angle = this.getAngle();
|
|
44
|
-
if (angle === 0) return Rect.fromObject(rect);
|
|
45
|
-
const styles = getComputedStyle(this.container);
|
|
46
|
-
const ratio = Number.parseInt(styles.width) / Number.parseInt(styles.height);
|
|
47
|
-
return Rect.getOriginRectFromBoundary(rect, angle, ratio);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
getContentGuides(): [boundary: Rect, xs: number[], ys: number[]] {
|
|
51
|
-
const boundary = this.getBoundary();
|
|
52
|
-
const contentXs: Set<number> = new Set();
|
|
53
|
-
const { xSizing } = this.options;
|
|
54
|
-
const contentYs: Set<number> = new Set();
|
|
55
|
-
domDfs(Array.from(this.container.children), (el) => {
|
|
56
|
-
if (el.children.length !== 0) return;
|
|
57
|
-
const rects = el.getClientRects();
|
|
58
|
-
const styles = window.getComputedStyle(el);
|
|
59
|
-
const ls = RichTextGeometryController.parseCssValue(styles.letterSpacing);
|
|
60
|
-
const metrics = measureFont(this.getFontStr(styles), el.textContent?.trim() ?? '');
|
|
61
|
-
const {
|
|
62
|
-
capHeight,
|
|
63
|
-
baseline,
|
|
64
|
-
fontBoxHeight,
|
|
65
|
-
xHeight,
|
|
66
|
-
leftMargin,
|
|
67
|
-
rightMargin
|
|
68
|
-
} = metrics;
|
|
69
|
-
for (let i = 0; i <= rects.length - 1; i += 1) {
|
|
70
|
-
const rect = rects[i];
|
|
71
|
-
const halfLead = (rect.height - fontBoxHeight) / 2;
|
|
72
|
-
contentXs.add(rect.left + leftMargin - boundary.left);
|
|
73
|
-
contentXs.add(rect.right - rightMargin - ls - boundary.left);
|
|
74
|
-
contentYs.add(rect.top + halfLead + baseline - boundary.top); // baseline
|
|
75
|
-
if (i === 0) {
|
|
76
|
-
contentYs.add(rect.top + halfLead + baseline - capHeight - boundary.top); // cap height
|
|
77
|
-
}
|
|
78
|
-
if (rects.length === 1) {
|
|
79
|
-
contentYs.add(rect.top + halfLead + baseline - xHeight - boundary.top); // x-height
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
const left = xSizing === SizingType.Auto ? Math.min(...contentXs.values()) : 0;
|
|
84
|
-
const right = xSizing === SizingType.Auto ? Math.max(...contentXs.values()) : boundary.width;
|
|
85
|
-
const center = left + (right - left) / 2;
|
|
86
|
-
return [
|
|
87
|
-
boundary,
|
|
88
|
-
[left, center, right],
|
|
89
|
-
[...Array.from(contentYs.values(), y => y)]
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
setParentId(parentId?: string) {
|
|
94
|
-
this.parentId = parentId;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
getParentId(): string | undefined {
|
|
98
|
-
return this.parentId;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
setScale(scale: number) {
|
|
102
|
-
this.scale = scale;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
setAngle(angle: number) {
|
|
106
|
-
this.angle = angle;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
getContentBoundary(): Rect {
|
|
110
|
-
if (this.getAngle() !== 0) {
|
|
111
|
-
return this.getBoundary(true);
|
|
112
|
-
}
|
|
113
|
-
const [boundary, xs, ys] = this.getContentGuides();
|
|
114
|
-
const left = Math.min(...xs);
|
|
115
|
-
const right = Math.max(...xs);
|
|
116
|
-
|
|
117
|
-
const top = Math.min(...ys);
|
|
118
|
-
const bottom = Math.max(...ys);
|
|
119
|
-
const content = new Rect(
|
|
120
|
-
boundary.left + left,
|
|
121
|
-
boundary.top + top,
|
|
122
|
-
right - left,
|
|
123
|
-
bottom - top
|
|
124
|
-
);
|
|
125
|
-
return content;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private getFontStr(styles: CSSStyleDeclaration) {
|
|
129
|
-
const fontSize = parseCSSNumber(styles.fontSize);
|
|
130
|
-
const lineHeight = parseCSSNumber(styles.lineHeight);
|
|
131
|
-
const scaledFontSize = formatCSSNumber({
|
|
132
|
-
value: fontSize.value * this.getScale(),
|
|
133
|
-
unit: fontSize.unit
|
|
134
|
-
});
|
|
135
|
-
const scaledLineHeight = formatCSSNumber({
|
|
136
|
-
value: lineHeight.value * this.getScale(),
|
|
137
|
-
unit: lineHeight.unit
|
|
138
|
-
});
|
|
139
|
-
return `${scaledFontSize} / ${scaledLineHeight} ${styles.fontFamily}`;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
setOptions(options?: RichTextGeometryOptions) {
|
|
143
|
-
if (!options) return;
|
|
144
|
-
this.options = options;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
getAngle(): number {
|
|
148
|
-
return this.angle + this.getParentAngle();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
getScale() {
|
|
152
|
-
return this.scale * this.getParentScale();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
private getParentAngle() {
|
|
156
|
-
if (!this.registry || !this.parentId) return 0;
|
|
157
|
-
const parentController = this.registry.getControllerById(this.parentId);
|
|
158
|
-
return parentController.getAngle();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
getParentScale(): number {
|
|
162
|
-
if (!this.registry || !this.parentId) return 1;
|
|
163
|
-
const parentController = this.registry.getControllerById(this.parentId);
|
|
164
|
-
return parentController.getScale();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
1
|
+
import { measureFont, Rect } from '@cntrl-site/sdk';
|
|
2
|
+
import { ItemGeometryController } from './ItemGeometryController';
|
|
3
|
+
import { domDfs } from '../utils/domDfs';
|
|
4
|
+
import { formatCSSNumber, parseCSSNumber } from '../utils/CSSNumeric';
|
|
5
|
+
|
|
6
|
+
export enum SizingType {
|
|
7
|
+
Auto = 'auto',
|
|
8
|
+
Manual = 'manual',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface RichTextGeometryOptions {
|
|
12
|
+
xSizing: SizingType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type GeomtryRegistry = {
|
|
16
|
+
getControllerById: (itemId: string) => ItemGeometryController;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class RichTextGeometryController implements ItemGeometryController {
|
|
20
|
+
private scale: number = 1;
|
|
21
|
+
private angle: number = 0;
|
|
22
|
+
private options!: RichTextGeometryOptions;
|
|
23
|
+
private parentId?: string;
|
|
24
|
+
private registry: GeomtryRegistry | undefined;
|
|
25
|
+
static parseCssValue(value: string) {
|
|
26
|
+
const parsedLs = Number.parseInt(value);
|
|
27
|
+
return Number.isNaN(parsedLs) ? 0 : parsedLs;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
private container: HTMLElement
|
|
32
|
+
) { }
|
|
33
|
+
|
|
34
|
+
setRegistry(registry: GeomtryRegistry) {
|
|
35
|
+
this.registry = registry;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getBoundary(isRotatedBoundary?: boolean): Rect {
|
|
39
|
+
const rect = this.container.getBoundingClientRect();
|
|
40
|
+
if (isRotatedBoundary) {
|
|
41
|
+
return Rect.fromObject(rect);
|
|
42
|
+
}
|
|
43
|
+
const angle = this.getAngle();
|
|
44
|
+
if (angle === 0) return Rect.fromObject(rect);
|
|
45
|
+
const styles = getComputedStyle(this.container);
|
|
46
|
+
const ratio = Number.parseInt(styles.width) / Number.parseInt(styles.height);
|
|
47
|
+
return Rect.getOriginRectFromBoundary(rect, angle, ratio);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getContentGuides(): [boundary: Rect, xs: number[], ys: number[]] {
|
|
51
|
+
const boundary = this.getBoundary();
|
|
52
|
+
const contentXs: Set<number> = new Set();
|
|
53
|
+
const { xSizing } = this.options;
|
|
54
|
+
const contentYs: Set<number> = new Set();
|
|
55
|
+
domDfs(Array.from(this.container.children), (el) => {
|
|
56
|
+
if (el.children.length !== 0) return;
|
|
57
|
+
const rects = el.getClientRects();
|
|
58
|
+
const styles = window.getComputedStyle(el);
|
|
59
|
+
const ls = RichTextGeometryController.parseCssValue(styles.letterSpacing);
|
|
60
|
+
const metrics = measureFont(this.getFontStr(styles), el.textContent?.trim() ?? '');
|
|
61
|
+
const {
|
|
62
|
+
capHeight,
|
|
63
|
+
baseline,
|
|
64
|
+
fontBoxHeight,
|
|
65
|
+
xHeight,
|
|
66
|
+
leftMargin,
|
|
67
|
+
rightMargin
|
|
68
|
+
} = metrics;
|
|
69
|
+
for (let i = 0; i <= rects.length - 1; i += 1) {
|
|
70
|
+
const rect = rects[i];
|
|
71
|
+
const halfLead = (rect.height - fontBoxHeight) / 2;
|
|
72
|
+
contentXs.add(rect.left + leftMargin - boundary.left);
|
|
73
|
+
contentXs.add(rect.right - rightMargin - ls - boundary.left);
|
|
74
|
+
contentYs.add(rect.top + halfLead + baseline - boundary.top); // baseline
|
|
75
|
+
if (i === 0) {
|
|
76
|
+
contentYs.add(rect.top + halfLead + baseline - capHeight - boundary.top); // cap height
|
|
77
|
+
}
|
|
78
|
+
if (rects.length === 1) {
|
|
79
|
+
contentYs.add(rect.top + halfLead + baseline - xHeight - boundary.top); // x-height
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const left = xSizing === SizingType.Auto ? Math.min(...contentXs.values()) : 0;
|
|
84
|
+
const right = xSizing === SizingType.Auto ? Math.max(...contentXs.values()) : boundary.width;
|
|
85
|
+
const center = left + (right - left) / 2;
|
|
86
|
+
return [
|
|
87
|
+
boundary,
|
|
88
|
+
[left, center, right],
|
|
89
|
+
[...Array.from(contentYs.values(), y => y)]
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setParentId(parentId?: string) {
|
|
94
|
+
this.parentId = parentId;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getParentId(): string | undefined {
|
|
98
|
+
return this.parentId;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setScale(scale: number) {
|
|
102
|
+
this.scale = scale;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
setAngle(angle: number) {
|
|
106
|
+
this.angle = angle;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getContentBoundary(): Rect {
|
|
110
|
+
if (this.getAngle() !== 0) {
|
|
111
|
+
return this.getBoundary(true);
|
|
112
|
+
}
|
|
113
|
+
const [boundary, xs, ys] = this.getContentGuides();
|
|
114
|
+
const left = Math.min(...xs);
|
|
115
|
+
const right = Math.max(...xs);
|
|
116
|
+
|
|
117
|
+
const top = Math.min(...ys);
|
|
118
|
+
const bottom = Math.max(...ys);
|
|
119
|
+
const content = new Rect(
|
|
120
|
+
boundary.left + left,
|
|
121
|
+
boundary.top + top,
|
|
122
|
+
right - left,
|
|
123
|
+
bottom - top
|
|
124
|
+
);
|
|
125
|
+
return content;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private getFontStr(styles: CSSStyleDeclaration) {
|
|
129
|
+
const fontSize = parseCSSNumber(styles.fontSize);
|
|
130
|
+
const lineHeight = parseCSSNumber(styles.lineHeight);
|
|
131
|
+
const scaledFontSize = formatCSSNumber({
|
|
132
|
+
value: fontSize.value * this.getScale(),
|
|
133
|
+
unit: fontSize.unit
|
|
134
|
+
});
|
|
135
|
+
const scaledLineHeight = formatCSSNumber({
|
|
136
|
+
value: lineHeight.value * this.getScale(),
|
|
137
|
+
unit: lineHeight.unit
|
|
138
|
+
});
|
|
139
|
+
return `${scaledFontSize} / ${scaledLineHeight} ${styles.fontFamily}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
setOptions(options?: RichTextGeometryOptions) {
|
|
143
|
+
if (!options) return;
|
|
144
|
+
this.options = options;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
getAngle(): number {
|
|
148
|
+
return this.angle + this.getParentAngle();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
getScale() {
|
|
152
|
+
return this.scale * this.getParentScale();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private getParentAngle() {
|
|
156
|
+
if (!this.registry || !this.parentId) return 0;
|
|
157
|
+
const parentController = this.registry.getControllerById(this.parentId);
|
|
158
|
+
return parentController.getAngle();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getParentScale(): number {
|
|
162
|
+
if (!this.registry || !this.parentId) return 1;
|
|
163
|
+
const parentController = this.registry.getControllerById(this.parentId);
|
|
164
|
+
return parentController.getScale();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { useContext, useEffect, useMemo } from 'react';
|
|
2
|
-
import { GenericGeometryController } from './GenericGeometryController';
|
|
3
|
-
import { GeometryControllerCtor } from './ItemGeometryController';
|
|
4
|
-
import { ItemGeometryContext } from './ItemGeometryContext';
|
|
5
|
-
|
|
6
|
-
export function useItemGeometry<T extends GeometryControllerCtor = typeof GenericGeometryController>(
|
|
7
|
-
itemId: string,
|
|
8
|
-
element?: HTMLElement | null,
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
controllerCtor: T = GenericGeometryController,
|
|
11
|
-
options?: any
|
|
12
|
-
): InstanceType<T> | undefined {
|
|
13
|
-
const itemGeometryService = useContext(ItemGeometryContext);
|
|
14
|
-
const controller = useMemo(() => {
|
|
15
|
-
if (!element) return undefined;
|
|
16
|
-
return new controllerCtor(element);
|
|
17
|
-
}, [element, controllerCtor]);
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (!controller) return;
|
|
20
|
-
controller.setOptions(options);
|
|
21
|
-
return itemGeometryService.register(itemId, controller);
|
|
22
|
-
}, [itemGeometryService, itemId, controller]);
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
return controller;
|
|
25
|
-
}
|
|
1
|
+
import { useContext, useEffect, useMemo } from 'react';
|
|
2
|
+
import { GenericGeometryController } from './GenericGeometryController';
|
|
3
|
+
import { GeometryControllerCtor } from './ItemGeometryController';
|
|
4
|
+
import { ItemGeometryContext } from './ItemGeometryContext';
|
|
5
|
+
|
|
6
|
+
export function useItemGeometry<T extends GeometryControllerCtor = typeof GenericGeometryController>(
|
|
7
|
+
itemId: string,
|
|
8
|
+
element?: HTMLElement | null,
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
controllerCtor: T = GenericGeometryController,
|
|
11
|
+
options?: any
|
|
12
|
+
): InstanceType<T> | undefined {
|
|
13
|
+
const itemGeometryService = useContext(ItemGeometryContext);
|
|
14
|
+
const controller = useMemo(() => {
|
|
15
|
+
if (!element) return undefined;
|
|
16
|
+
return new controllerCtor(element);
|
|
17
|
+
}, [element, controllerCtor]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!controller) return;
|
|
20
|
+
controller.setOptions(options);
|
|
21
|
+
return itemGeometryService.register(itemId, controller);
|
|
22
|
+
}, [itemGeometryService, itemId, controller]);
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
return controller;
|
|
25
|
+
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
2
|
-
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { ArticleRectContext } from '../provider/ArticleRectContext';
|
|
4
|
-
|
|
5
|
-
interface LayoutData {
|
|
6
|
-
layoutId: string;
|
|
7
|
-
exemplary: number;
|
|
8
|
-
start: number;
|
|
9
|
-
end: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
type UseCurrentLayoutReturn = {
|
|
13
|
-
layoutId: string | undefined;
|
|
14
|
-
layoutDeviation: number;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export function useCurrentLayout(): UseCurrentLayoutReturn {
|
|
18
|
-
const { layouts } = useCntrlContext();
|
|
19
|
-
const articleRectObserver = useContext(ArticleRectContext);
|
|
20
|
-
const layoutRanges = useMemo(() => {
|
|
21
|
-
const sorted = layouts.slice().sort((la, lb) => la.startsWith - lb.startsWith);
|
|
22
|
-
return sorted.reduce<LayoutData[]>((acc, layout, i, layouts) => {
|
|
23
|
-
const next = layouts[i + 1];
|
|
24
|
-
return [
|
|
25
|
-
...acc,
|
|
26
|
-
{
|
|
27
|
-
layoutId: layout.id,
|
|
28
|
-
exemplary: layout.exemplary,
|
|
29
|
-
start: layout.startsWith,
|
|
30
|
-
end: next ? next.startsWith : Number.MAX_SAFE_INTEGER
|
|
31
|
-
}
|
|
32
|
-
];
|
|
33
|
-
}, []);
|
|
34
|
-
}, [layouts]);
|
|
35
|
-
const getCurrentLayout = useCallback((articleWidth: number) => {
|
|
36
|
-
const range = layoutRanges.find(l => articleWidth >= l.start && articleWidth < l.end);
|
|
37
|
-
return range;
|
|
38
|
-
}, [layoutRanges]);
|
|
39
|
-
const [layoutId, setLayoutId] = useState<string | undefined>(undefined);
|
|
40
|
-
const [deviation, setDeviation] = useState(1);
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!articleRectObserver) return;
|
|
43
|
-
return articleRectObserver.on('resize', () => {
|
|
44
|
-
const articleWidth = articleRectObserver.width;
|
|
45
|
-
const { layoutId, exemplary } = getCurrentLayout(articleWidth)!;
|
|
46
|
-
setLayoutId(layoutId);
|
|
47
|
-
setDeviation(articleWidth / exemplary);
|
|
48
|
-
});
|
|
49
|
-
}, [articleRectObserver, getCurrentLayout]);
|
|
50
|
-
|
|
51
|
-
return { layoutId, layoutDeviation: deviation };
|
|
52
|
-
}
|
|
1
|
+
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
2
|
+
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { ArticleRectContext } from '../provider/ArticleRectContext';
|
|
4
|
+
|
|
5
|
+
interface LayoutData {
|
|
6
|
+
layoutId: string;
|
|
7
|
+
exemplary: number;
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type UseCurrentLayoutReturn = {
|
|
13
|
+
layoutId: string | undefined;
|
|
14
|
+
layoutDeviation: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function useCurrentLayout(): UseCurrentLayoutReturn {
|
|
18
|
+
const { layouts } = useCntrlContext();
|
|
19
|
+
const articleRectObserver = useContext(ArticleRectContext);
|
|
20
|
+
const layoutRanges = useMemo(() => {
|
|
21
|
+
const sorted = layouts.slice().sort((la, lb) => la.startsWith - lb.startsWith);
|
|
22
|
+
return sorted.reduce<LayoutData[]>((acc, layout, i, layouts) => {
|
|
23
|
+
const next = layouts[i + 1];
|
|
24
|
+
return [
|
|
25
|
+
...acc,
|
|
26
|
+
{
|
|
27
|
+
layoutId: layout.id,
|
|
28
|
+
exemplary: layout.exemplary,
|
|
29
|
+
start: layout.startsWith,
|
|
30
|
+
end: next ? next.startsWith : Number.MAX_SAFE_INTEGER
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
}, []);
|
|
34
|
+
}, [layouts]);
|
|
35
|
+
const getCurrentLayout = useCallback((articleWidth: number) => {
|
|
36
|
+
const range = layoutRanges.find(l => articleWidth >= l.start && articleWidth < l.end);
|
|
37
|
+
return range;
|
|
38
|
+
}, [layoutRanges]);
|
|
39
|
+
const [layoutId, setLayoutId] = useState<string | undefined>(undefined);
|
|
40
|
+
const [deviation, setDeviation] = useState(1);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!articleRectObserver) return;
|
|
43
|
+
return articleRectObserver.on('resize', () => {
|
|
44
|
+
const articleWidth = articleRectObserver.width;
|
|
45
|
+
const { layoutId, exemplary } = getCurrentLayout(articleWidth)!;
|
|
46
|
+
setLayoutId(layoutId);
|
|
47
|
+
setDeviation(articleWidth / exemplary);
|
|
48
|
+
});
|
|
49
|
+
}, [articleRectObserver, getCurrentLayout]);
|
|
50
|
+
|
|
51
|
+
return { layoutId, layoutDeviation: deviation };
|
|
52
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useCntrlContext } from "../provider/useCntrlContext";
|
|
2
|
-
import { useLayoutContext } from "../components/useLayoutContext";
|
|
3
|
-
|
|
4
|
-
export const useExemplary = () => {
|
|
5
|
-
const { layouts } = useCntrlContext();
|
|
6
|
-
const layout = useLayoutContext();
|
|
7
|
-
const exemplary = layouts.find(l => l.id === layout)?.exemplary ?? 1;
|
|
8
|
-
return exemplary;
|
|
9
|
-
};
|
|
1
|
+
import { useCntrlContext } from "../provider/useCntrlContext";
|
|
2
|
+
import { useLayoutContext } from "../components/useLayoutContext";
|
|
3
|
+
|
|
4
|
+
export const useExemplary = () => {
|
|
5
|
+
const { layouts } = useCntrlContext();
|
|
6
|
+
const layout = useLayoutContext();
|
|
7
|
+
const exemplary = layouts.find(l => l.id === layout)?.exemplary ?? 1;
|
|
8
|
+
return exemplary;
|
|
9
|
+
};
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import { ImageItem, KeyframeType, VideoItem } from '@cntrl-site/sdk';
|
|
2
|
-
import { useKeyframeValue } from './useKeyframeValue';
|
|
3
|
-
import { useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
const baseVariables = `precision mediump float;
|
|
6
|
-
uniform sampler2D u_image;
|
|
7
|
-
uniform vec2 u_imgDimensions;
|
|
8
|
-
uniform float u_time;
|
|
9
|
-
uniform vec2 u_cursor;
|
|
10
|
-
varying vec2 v_texCoord;`;
|
|
11
|
-
|
|
12
|
-
export function useItemFXData(item: ImageItem | VideoItem, sectionId: string): FXData {
|
|
13
|
-
const { fragmentShader: shaderBody, FXControls, FXTextures } = item.commonParams;
|
|
14
|
-
const controls = FXControls ?? [];
|
|
15
|
-
const texturesUrls: string[] = useMemo(() => (FXTextures ?? []), [FXTextures]);
|
|
16
|
-
const controlsVariables = controls.map((c) => `uniform ${c.type} ${c.shaderParam};`)
|
|
17
|
-
.join('\n');
|
|
18
|
-
const patternsVariables = texturesUrls
|
|
19
|
-
.map((_, i) => `uniform sampler2D ${mediaEffectPatternUniformNames(i).tex};\nuniform vec2 ${mediaEffectPatternUniformNames(i).dim};`)
|
|
20
|
-
.join('\n');
|
|
21
|
-
const fragmentShader = `${baseVariables}\n${controlsVariables}\n${patternsVariables}\n${shaderBody}`;
|
|
22
|
-
const controlsValues = useKeyframeValue(
|
|
23
|
-
item,
|
|
24
|
-
KeyframeType.FXParams,
|
|
25
|
-
() => {
|
|
26
|
-
const defaultValue = controls.reduce<Record<string, ControlValue>>((acc, control) => {
|
|
27
|
-
if (Array.isArray(control.value)) {
|
|
28
|
-
acc[control.shaderParam] = control.value[0];
|
|
29
|
-
} else {
|
|
30
|
-
acc[control.shaderParam] = control.value;
|
|
31
|
-
}
|
|
32
|
-
return acc;
|
|
33
|
-
}, {});
|
|
34
|
-
return defaultValue;
|
|
35
|
-
},
|
|
36
|
-
(animator, scroll, value) => animator.getFXParams(value, scroll),
|
|
37
|
-
sectionId,
|
|
38
|
-
);
|
|
39
|
-
return {
|
|
40
|
-
fragmentShader,
|
|
41
|
-
controlsValues,
|
|
42
|
-
texturesUrls
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function mediaEffectPatternUniformNames(slotIndex: number): {
|
|
47
|
-
tex: string;
|
|
48
|
-
dim: string;
|
|
49
|
-
} {
|
|
50
|
-
if (slotIndex === 0) {
|
|
51
|
-
return { tex: 'u_pattern', dim: 'u_patternDimensions' };
|
|
52
|
-
}
|
|
53
|
-
const n = slotIndex + 1;
|
|
54
|
-
return { tex: `u_pattern${n}`, dim: `u_pattern${n}Dimensions` };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type FXData = {
|
|
58
|
-
fragmentShader: string;
|
|
59
|
-
controlsValues: Record<string, ControlValue>;
|
|
60
|
-
texturesUrls: string[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
type ControlValue = number;
|
|
1
|
+
import { ImageItem, KeyframeType, VideoItem } from '@cntrl-site/sdk';
|
|
2
|
+
import { useKeyframeValue } from './useKeyframeValue';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
const baseVariables = `precision mediump float;
|
|
6
|
+
uniform sampler2D u_image;
|
|
7
|
+
uniform vec2 u_imgDimensions;
|
|
8
|
+
uniform float u_time;
|
|
9
|
+
uniform vec2 u_cursor;
|
|
10
|
+
varying vec2 v_texCoord;`;
|
|
11
|
+
|
|
12
|
+
export function useItemFXData(item: ImageItem | VideoItem, sectionId: string): FXData {
|
|
13
|
+
const { fragmentShader: shaderBody, FXControls, FXTextures } = item.commonParams;
|
|
14
|
+
const controls = FXControls ?? [];
|
|
15
|
+
const texturesUrls: string[] = useMemo(() => (FXTextures ?? []), [FXTextures]);
|
|
16
|
+
const controlsVariables = controls.map((c) => `uniform ${c.type} ${c.shaderParam};`)
|
|
17
|
+
.join('\n');
|
|
18
|
+
const patternsVariables = texturesUrls
|
|
19
|
+
.map((_, i) => `uniform sampler2D ${mediaEffectPatternUniformNames(i).tex};\nuniform vec2 ${mediaEffectPatternUniformNames(i).dim};`)
|
|
20
|
+
.join('\n');
|
|
21
|
+
const fragmentShader = `${baseVariables}\n${controlsVariables}\n${patternsVariables}\n${shaderBody}`;
|
|
22
|
+
const controlsValues = useKeyframeValue(
|
|
23
|
+
item,
|
|
24
|
+
KeyframeType.FXParams,
|
|
25
|
+
() => {
|
|
26
|
+
const defaultValue = controls.reduce<Record<string, ControlValue>>((acc, control) => {
|
|
27
|
+
if (Array.isArray(control.value)) {
|
|
28
|
+
acc[control.shaderParam] = control.value[0];
|
|
29
|
+
} else {
|
|
30
|
+
acc[control.shaderParam] = control.value;
|
|
31
|
+
}
|
|
32
|
+
return acc;
|
|
33
|
+
}, {});
|
|
34
|
+
return defaultValue;
|
|
35
|
+
},
|
|
36
|
+
(animator, scroll, value) => animator.getFXParams(value, scroll),
|
|
37
|
+
sectionId,
|
|
38
|
+
);
|
|
39
|
+
return {
|
|
40
|
+
fragmentShader,
|
|
41
|
+
controlsValues,
|
|
42
|
+
texturesUrls
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function mediaEffectPatternUniformNames(slotIndex: number): {
|
|
47
|
+
tex: string;
|
|
48
|
+
dim: string;
|
|
49
|
+
} {
|
|
50
|
+
if (slotIndex === 0) {
|
|
51
|
+
return { tex: 'u_pattern', dim: 'u_patternDimensions' };
|
|
52
|
+
}
|
|
53
|
+
const n = slotIndex + 1;
|
|
54
|
+
return { tex: `u_pattern${n}`, dim: `u_pattern${n}Dimensions` };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type FXData = {
|
|
58
|
+
fragmentShader: string;
|
|
59
|
+
controlsValues: Record<string, ControlValue>;
|
|
60
|
+
texturesUrls: string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type ControlValue = number;
|