@cntrl-site/sdk-nextjs 1.0.18 → 1.0.19-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +15 -0
- package/jest.config.js +2 -2
- package/lib/components/Article.js +9 -8
- package/lib/components/Item.js +31 -13
- package/lib/components/items/CodeEmbedItem.js +9 -8
- package/lib/components/items/CustomItem.js +8 -7
- package/lib/components/items/GroupItem.js +9 -8
- package/lib/components/items/ImageItem.js +13 -12
- package/lib/components/items/RectangleItem.js +9 -8
- package/lib/components/items/RichTextItem.js +8 -7
- package/lib/components/items/VideoItem.js +13 -12
- package/lib/components/items/VimeoEmbed.js +16 -15
- package/lib/components/items/YoutubeEmbed.js +14 -13
- package/lib/components/useStatesClassNames.js +18 -0
- package/lib/provider/InteractionsContext.js +45 -0
- package/lib/utils/{HoverStyles/HoverStyles.js → StateStyles/StateStyles.js} +18 -16
- package/lib/utils/getStatesCSS.js +16 -0
- package/package.json +7 -4
- package/src/components/Article.tsx +31 -28
- package/src/components/ArticleWrapper.tsx +1 -2
- package/src/components/Item.tsx +35 -18
- package/src/components/items/CodeEmbedItem.tsx +10 -9
- package/src/components/items/CustomItem.tsx +10 -9
- package/src/components/items/GroupItem.tsx +10 -9
- package/src/components/items/ImageItem.tsx +16 -15
- package/src/components/items/RectangleItem.tsx +11 -10
- package/src/components/items/RichTextItem.tsx +15 -9
- package/src/components/items/VideoItem.tsx +16 -15
- package/src/components/items/VimeoEmbed.tsx +17 -16
- package/src/components/items/YoutubeEmbed.tsx +15 -15
- package/src/components/useStatesClassNames.ts +23 -0
- package/src/provider/InteractionsContext.test.tsx +97 -0
- package/src/provider/InteractionsContext.tsx +65 -0
- package/src/utils/{HoverStyles/HoverStyles.ts → StateStyles/StateStyles.ts} +22 -21
- package/src/utils/getStatesCSS.ts +21 -0
- package/cntrl-site-sdk-nextjs-1.0.17.tgz +0 -0
- package/cntrl-site-sdk-nextjs-1.0.18.tgz +0 -0
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLayoutStyles, CustomItem as TCustomItem } from '@cntrl-site/sdk';
|
|
2
2
|
import { FC, useState } from 'react';
|
|
3
3
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
4
4
|
import { ItemProps } from '../Item';
|
|
5
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
6
5
|
import JSXStyle from 'styled-jsx/style';
|
|
7
6
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
8
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
9
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
9
10
|
|
|
10
11
|
export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, sectionId }) => {
|
|
11
12
|
const sdk = useCntrlContext();
|
|
12
13
|
const { layouts } = useCntrlContext();
|
|
13
14
|
const angle = useItemAngle(item, sectionId);
|
|
14
15
|
const component = sdk.customItems.get(item.commonParams.name);
|
|
15
|
-
const layoutValues: Record<string, any>[] = [item.area, item.state
|
|
16
|
+
const layoutValues: Record<string, any>[] = [item.area, item.state];
|
|
16
17
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
17
18
|
useRegisterResize(ref, onResize);
|
|
19
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'custom-component');
|
|
18
20
|
if (!component) return null;
|
|
19
21
|
return (
|
|
20
22
|
<>
|
|
21
23
|
<div
|
|
22
|
-
className={`custom-component-${item.id}`}
|
|
24
|
+
className={`custom-component-${item.id} ${statesClassNames}`}
|
|
23
25
|
ref={setRef}
|
|
24
26
|
style={{
|
|
25
27
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
@@ -28,20 +30,19 @@ export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, section
|
|
|
28
30
|
{component({})}
|
|
29
31
|
</div>
|
|
30
32
|
<JSXStyle id={item.id}>
|
|
31
|
-
{`${getLayoutStyles(layouts, layoutValues, ([area,
|
|
33
|
+
{`${getLayoutStyles(layouts, layoutValues, ([area, stateParams]) => {
|
|
34
|
+
const statesCSS = getStatesCSS(item.id, 'custom-component', ['angle'], stateParams);
|
|
32
35
|
return (`
|
|
33
36
|
.custom-component-${item.id} {
|
|
34
37
|
transform: rotate(${area.angle}deg);
|
|
35
|
-
transition:
|
|
38
|
+
transition: all 0.2s ease;
|
|
36
39
|
height: 100%;
|
|
37
40
|
width: 100%;
|
|
38
41
|
position: absolute;
|
|
39
42
|
left: 0;
|
|
40
43
|
top: 0;
|
|
41
44
|
}
|
|
42
|
-
|
|
43
|
-
${getHoverStyles<ArticleItemType.Custom>(['angle'], hoverParams)};
|
|
44
|
-
}
|
|
45
|
+
${statesCSS}
|
|
45
46
|
`);
|
|
46
47
|
})}`}
|
|
47
48
|
</JSXStyle>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React, { FC, useId, useState } from 'react';
|
|
2
2
|
import { Item, ItemProps } from '../Item';
|
|
3
3
|
import JSXStyle from 'styled-jsx/style';
|
|
4
|
-
import {
|
|
5
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
4
|
+
import { getLayoutStyles, GroupItem as TGroupItem } from '@cntrl-site/sdk';
|
|
6
5
|
import { LinkWrapper } from '../LinkWrapper';
|
|
7
6
|
import { useRegisterResize } from '../../common/useRegisterResize';
|
|
8
7
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
9
8
|
import { useItemAngle } from '../useItemAngle';
|
|
10
9
|
import { useGroupItem } from './useGroupItem';
|
|
10
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
11
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
11
12
|
|
|
12
13
|
export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize, articleHeight }) => {
|
|
13
14
|
const id = useId();
|
|
@@ -15,7 +16,8 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
|
|
|
15
16
|
const angle = useItemAngle(item, sectionId);
|
|
16
17
|
const { layouts } = useCntrlContext();
|
|
17
18
|
const { opacity } = useGroupItem(item, sectionId);
|
|
18
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
19
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
20
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'group');
|
|
19
21
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
20
22
|
useRegisterResize(ref, onResize);
|
|
21
23
|
|
|
@@ -23,7 +25,7 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
|
|
|
23
25
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
24
26
|
<>
|
|
25
27
|
<div
|
|
26
|
-
className={`group-${item.id}`}
|
|
28
|
+
className={`group-${item.id} ${statesClassNames}`}
|
|
27
29
|
ref={setRef}
|
|
28
30
|
style={{
|
|
29
31
|
...(opacity !== undefined ? { opacity } : {}),
|
|
@@ -47,16 +49,15 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
|
|
|
47
49
|
height: 100%;
|
|
48
50
|
box-sizing: border-box;
|
|
49
51
|
}
|
|
50
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
52
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
53
|
+
const statesCSS = getStatesCSS(item.id, 'group', ['opacity', 'angle'], stateParams);
|
|
51
54
|
return (`
|
|
52
55
|
.group-${item.id} {
|
|
53
56
|
opacity: ${layoutParams.opacity};
|
|
54
57
|
transform: rotate(${area.angle}deg);
|
|
55
|
-
transition:
|
|
56
|
-
}
|
|
57
|
-
.group-${item.id}:hover {
|
|
58
|
-
${getHoverStyles<ArticleItemType.Group>(['opacity', 'angle'], hoverParams)};
|
|
58
|
+
transition: all 0.2s ease;
|
|
59
59
|
}
|
|
60
|
+
${statesCSS}
|
|
60
61
|
`);
|
|
61
62
|
})}
|
|
62
63
|
`}</JSXStyle>
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { FC, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import { CntrlColor } from '@cntrl-site/color';
|
|
4
|
-
import {
|
|
4
|
+
import { getLayoutStyles, ImageItem as TImageItem } from '@cntrl-site/sdk';
|
|
5
5
|
import { ItemProps } from '../Item';
|
|
6
6
|
import { LinkWrapper } from '../LinkWrapper';
|
|
7
7
|
import { useFileItem } from './useFileItem';
|
|
8
8
|
import { useItemAngle } from '../useItemAngle';
|
|
9
9
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
10
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
11
10
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
12
11
|
import { useImageFx } from '../../utils/effects/useImageFx';
|
|
13
12
|
import { useElementRect } from '../../utils/useElementRect';
|
|
14
13
|
import { useLayoutContext } from '../useLayoutContext';
|
|
14
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
15
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
15
16
|
|
|
16
17
|
const baseVariables = `precision mediump float;
|
|
17
18
|
uniform sampler2D u_image;
|
|
@@ -41,12 +42,14 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
41
42
|
acc[control.shaderParam] = control.value;
|
|
42
43
|
return acc;
|
|
43
44
|
}, {});
|
|
44
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
45
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
45
46
|
const fullShaderCode = `${baseVariables}\n${controlsVariables}\n${fragmentShader}`;
|
|
46
47
|
const area = layoutId ? item.area[layoutId] : null;
|
|
47
48
|
const exemplary = layouts?.find(l => l.id === layoutId)?.exemplary;
|
|
48
49
|
const width = area && exemplary ? area.width * exemplary : 0;
|
|
49
50
|
const height = area && exemplary ? area.height * exemplary : 0;
|
|
51
|
+
const statesWrapperClassNames = useStatesClassNames(item.id, item.state, 'image-wrapper');
|
|
52
|
+
const statesImgClassNames = useStatesClassNames(item.id, item.state, 'image');
|
|
50
53
|
useEffect(() => {
|
|
51
54
|
isInitialRef.current = false;
|
|
52
55
|
}, []);
|
|
@@ -74,7 +77,7 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
74
77
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
75
78
|
<>
|
|
76
79
|
<div
|
|
77
|
-
className={`image-wrapper-${item.id}`}
|
|
80
|
+
className={`image-wrapper-${item.id} ${statesWrapperClassNames}`}
|
|
78
81
|
ref={setRef}
|
|
79
82
|
style={{
|
|
80
83
|
...(opacity !== undefined ? { opacity } : {}),
|
|
@@ -86,14 +89,14 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
86
89
|
<canvas
|
|
87
90
|
style={inlineStyles}
|
|
88
91
|
ref={fxCanvas}
|
|
89
|
-
className={`img-canvas image-${item.id}`}
|
|
92
|
+
className={`img-canvas image-${item.id} ${statesImgClassNames}`}
|
|
90
93
|
width={rectWidth}
|
|
91
94
|
height={rectHeight}
|
|
92
95
|
/>
|
|
93
96
|
) : (
|
|
94
97
|
<img
|
|
95
98
|
alt=""
|
|
96
|
-
className={`image image-${item.id}`}
|
|
99
|
+
className={`image image-${item.id} ${statesImgClassNames}`}
|
|
97
100
|
style={inlineStyles}
|
|
98
101
|
src={item.commonParams.url}
|
|
99
102
|
/>
|
|
@@ -125,26 +128,24 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
125
128
|
border-width: 0;
|
|
126
129
|
box-sizing: border-box;
|
|
127
130
|
}
|
|
128
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
131
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
132
|
+
const wrapperStatesCSS = getStatesCSS(item.id, 'image-wrapper', ['angle', 'opacity', 'blur'], stateParams);
|
|
133
|
+
const imgStatesCSS = getStatesCSS(item.id, 'image', ['strokeWidth', 'radius', 'strokeColor'], stateParams);
|
|
129
134
|
return (`
|
|
130
135
|
.image-wrapper-${item.id} {
|
|
131
136
|
opacity: ${layoutParams.opacity};
|
|
132
137
|
transform: rotate(${area.angle}deg);
|
|
133
138
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
134
|
-
transition:
|
|
135
|
-
}
|
|
136
|
-
.image-wrapper-${item.id}:hover {
|
|
137
|
-
${getHoverStyles<ArticleItemType.Image>(['angle', 'opacity', 'blur'], hoverParams)};
|
|
139
|
+
transition: all 0.2s ease;
|
|
138
140
|
}
|
|
139
141
|
.image-${item.id} {
|
|
140
142
|
border-color: ${CntrlColor.parse(layoutParams.strokeColor).fmt('rgba')};
|
|
141
143
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
142
144
|
border-width: ${layoutParams.strokeWidth * 100}vw;
|
|
143
|
-
transition:
|
|
144
|
-
}
|
|
145
|
-
.image-wrapper-${item.id}:hover .image, .image-wrapper-${item.id}:hover .img-canvas {
|
|
146
|
-
${getHoverStyles<ArticleItemType.Image>(['strokeWidth', 'radius', 'strokeColor'], hoverParams)};
|
|
145
|
+
transition: all 0.2s ease;
|
|
147
146
|
}
|
|
147
|
+
${wrapperStatesCSS}
|
|
148
|
+
${imgStatesCSS}
|
|
148
149
|
`);
|
|
149
150
|
})}
|
|
150
151
|
`}</JSXStyle>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { FC,
|
|
1
|
+
import { FC, useId, useMemo, useState } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import { CntrlColor } from '@cntrl-site/color';
|
|
4
|
-
import { RectangleItem as TRectangleItem, getLayoutStyles
|
|
4
|
+
import { RectangleItem as TRectangleItem, getLayoutStyles } from '@cntrl-site/sdk';
|
|
5
5
|
import { ItemProps } from '../Item';
|
|
6
6
|
import { LinkWrapper } from '../LinkWrapper';
|
|
7
7
|
import { useRectangleItem } from './useRectangleItem';
|
|
8
8
|
import { useItemAngle } from '../useItemAngle';
|
|
9
9
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
10
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
11
10
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
11
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
12
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
12
13
|
|
|
13
14
|
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId, onResize }) => {
|
|
14
15
|
const id = useId();
|
|
@@ -17,8 +18,9 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
17
18
|
const angle = useItemAngle(item, sectionId);
|
|
18
19
|
const backgroundColor = useMemo(() => fillColor ? CntrlColor.parse(fillColor) : undefined, [fillColor]);
|
|
19
20
|
const borderColor = useMemo(() => strokeColor ? CntrlColor.parse(strokeColor) : undefined, [strokeColor]);
|
|
20
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
21
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
21
22
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
23
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'rectangle');
|
|
22
24
|
useRegisterResize(ref, onResize);
|
|
23
25
|
const backdropFilterValue = backdropBlur ? `blur(${backdropBlur * 100}vw)`: undefined;
|
|
24
26
|
|
|
@@ -26,7 +28,7 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
26
28
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
27
29
|
<>
|
|
28
30
|
<div
|
|
29
|
-
className={`rectangle-${item.id}`}
|
|
31
|
+
className={`rectangle-${item.id} ${statesClassNames}`}
|
|
30
32
|
ref={setRef}
|
|
31
33
|
style={{
|
|
32
34
|
...(backgroundColor ? { backgroundColor : `${backgroundColor.fmt('rgba')}` } : {}),
|
|
@@ -49,7 +51,8 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
49
51
|
border-style: solid;
|
|
50
52
|
box-sizing: border-box;
|
|
51
53
|
}
|
|
52
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
54
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, states]) => {
|
|
55
|
+
const statesCSS = getStatesCSS(item.id, 'rectangle', ['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor', 'blur', 'backdropBlur'], states);
|
|
53
56
|
return (`
|
|
54
57
|
.rectangle-${item.id} {
|
|
55
58
|
background-color: ${CntrlColor.parse(layoutParams.fillColor).fmt('rgba')};
|
|
@@ -60,11 +63,9 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
60
63
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
61
64
|
backdrop-filter: ${layoutParams.backdropFilter !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
62
65
|
-webkit-backdrop-filter: ${layoutParams.backdropFilter !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
63
|
-
transition:
|
|
64
|
-
}
|
|
65
|
-
.rectangle-${item.id}:hover {
|
|
66
|
-
${getHoverStyles<ArticleItemType.Rectangle>(['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor', 'blur', 'backdropBlur'], hoverParams)};
|
|
66
|
+
transition: all 0.2s ease;
|
|
67
67
|
}
|
|
68
|
+
${statesCSS}
|
|
68
69
|
`);
|
|
69
70
|
})}
|
|
70
71
|
`}</JSXStyle>
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { FC, useId, useMemo, useState } from 'react';
|
|
2
2
|
import { CntrlColor } from '@cntrl-site/color';
|
|
3
|
-
import {
|
|
3
|
+
import { getLayoutStyles, RichTextItem as TRichTextItem } from '@cntrl-site/sdk';
|
|
4
4
|
import JSXStyle from 'styled-jsx/style';
|
|
5
5
|
import { ItemProps } from '../Item';
|
|
6
6
|
import { useRichTextItem } from './useRichTextItem';
|
|
7
7
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
8
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
9
8
|
import { useRichTextItemValues } from './useRichTextItemValues';
|
|
10
9
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
11
10
|
import { getFontFamilyValue } from '../../utils/getFontFamilyValue';
|
|
12
11
|
import { useExemplary } from '../../common/useExemplary';
|
|
13
12
|
import { useItemAngle } from '../useItemAngle';
|
|
13
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
14
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
14
15
|
|
|
15
16
|
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, onResize }) => {
|
|
16
17
|
const [content, styles] = useRichTextItem(item);
|
|
@@ -20,15 +21,16 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
20
21
|
const angle = useItemAngle(item, sectionId);
|
|
21
22
|
const { blur, wordSpacing, letterSpacing, color, fontSize, lineHeight } = useRichTextItemValues(item, sectionId);
|
|
22
23
|
const textColor = useMemo(() => color ? CntrlColor.parse(color) : undefined, [color]);
|
|
23
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
24
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
24
25
|
const exemplary = useExemplary();
|
|
26
|
+
const stateClassNames = useStatesClassNames(item.id, item.state, 'rich-text-wrapper');
|
|
25
27
|
useRegisterResize(ref, onResize);
|
|
26
28
|
|
|
27
29
|
return (
|
|
28
30
|
<>
|
|
29
31
|
<div
|
|
30
32
|
ref={setRef}
|
|
31
|
-
className={`rich-text-wrapper-${item.id}`}
|
|
33
|
+
className={`rich-text-wrapper-${item.id} ${stateClassNames}`}
|
|
32
34
|
style={{
|
|
33
35
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
34
36
|
...(textColor ? { color: `${textColor.fmt('rgba')}` } : {}),
|
|
@@ -43,8 +45,14 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
43
45
|
</div>
|
|
44
46
|
<JSXStyle id={id}>
|
|
45
47
|
{styles}
|
|
46
|
-
{`${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
48
|
+
{`${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, states]) => {
|
|
47
49
|
const color = CntrlColor.parse(layoutParams.color);
|
|
50
|
+
const statesCSS = getStatesCSS(
|
|
51
|
+
item.id,
|
|
52
|
+
'rich-text-wrapper',
|
|
53
|
+
['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color'],
|
|
54
|
+
states
|
|
55
|
+
);
|
|
48
56
|
return (`
|
|
49
57
|
.rich-text-wrapper-${item.id} {
|
|
50
58
|
font-size: ${layoutParams.fontSize * 100}vw;
|
|
@@ -60,16 +68,14 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
60
68
|
transform: rotate(${area.angle}deg);
|
|
61
69
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
62
70
|
text-transform: ${layoutParams.textTransform};
|
|
63
|
-
transition:
|
|
64
|
-
}
|
|
65
|
-
.rich-text-wrapper-${item.id}:hover {
|
|
66
|
-
${getHoverStyles<ArticleItemType.RichText>(['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color'], hoverParams)};
|
|
71
|
+
transition: all 0.2s ease;
|
|
67
72
|
}
|
|
68
73
|
@supports not (color: oklch(42% 0.3 90 / 1)) {
|
|
69
74
|
.rich-text-wrapper-${item.id} {
|
|
70
75
|
color: ${color.fmt('rgba')};
|
|
71
76
|
}
|
|
72
77
|
}
|
|
78
|
+
${statesCSS}
|
|
73
79
|
`);
|
|
74
80
|
})}`}
|
|
75
81
|
</JSXStyle>
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { FC, useId, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import { CntrlColor } from '@cntrl-site/color';
|
|
4
|
-
import {
|
|
4
|
+
import { getLayoutStyles, VideoItem as TVideoItem } from '@cntrl-site/sdk';
|
|
5
5
|
import { ItemProps } from '../Item';
|
|
6
6
|
import { LinkWrapper } from '../LinkWrapper';
|
|
7
7
|
import { useFileItem } from './useFileItem';
|
|
8
8
|
import { useItemAngle } from '../useItemAngle';
|
|
9
9
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
10
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
11
10
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
12
11
|
import { useLayoutContext } from '../useLayoutContext';
|
|
13
12
|
import { ScrollPlaybackVideo } from '../ScrollPlaybackVideo';
|
|
13
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
14
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
14
15
|
|
|
15
16
|
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize }) => {
|
|
16
17
|
const id = useId();
|
|
@@ -22,7 +23,9 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
22
23
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
|
23
24
|
const layoutId = useLayoutContext();
|
|
24
25
|
const scrollPlayback = layoutId ? item.layoutParams[layoutId].scrollPlayback : null;
|
|
25
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
26
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
27
|
+
const statesWrapperClassNames = useStatesClassNames(item.id, item.state, 'video-wrapper');
|
|
28
|
+
const statesVideoClassNames = useStatesClassNames(item.id, item.state, 'video');
|
|
26
29
|
const hasScrollPlayback = scrollPlayback !== null;
|
|
27
30
|
useRegisterResize(ref, onResize);
|
|
28
31
|
const inlineStyles = {
|
|
@@ -34,7 +37,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
34
37
|
return (
|
|
35
38
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
36
39
|
<div
|
|
37
|
-
className={`video-wrapper-${item.id}`}
|
|
40
|
+
className={`video-wrapper-${item.id} ${statesWrapperClassNames}`}
|
|
38
41
|
ref={setRef}
|
|
39
42
|
style={{
|
|
40
43
|
...(opacity !== undefined ? { opacity } : {}),
|
|
@@ -48,7 +51,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
48
51
|
src={item.commonParams.url}
|
|
49
52
|
playbackParams={scrollPlayback}
|
|
50
53
|
style={inlineStyles}
|
|
51
|
-
className={`video video-playback-wrapper video-${item.id}`}
|
|
54
|
+
className={`video video-playback-wrapper video-${item.id} ${statesWrapperClassNames}`}
|
|
52
55
|
/>
|
|
53
56
|
) : (
|
|
54
57
|
<video
|
|
@@ -58,7 +61,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
58
61
|
muted
|
|
59
62
|
loop
|
|
60
63
|
playsInline
|
|
61
|
-
className={`video video-${item.id}`}
|
|
64
|
+
className={`video video-${item.id} ${statesVideoClassNames}`}
|
|
62
65
|
style={inlineStyles}
|
|
63
66
|
>
|
|
64
67
|
<source src={item.commonParams.url} />
|
|
@@ -92,26 +95,24 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
92
95
|
display: flex;
|
|
93
96
|
justify-content: center;
|
|
94
97
|
}
|
|
95
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
98
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
99
|
+
const wrapperStatesCSS = getStatesCSS(item.id, 'video-wrapper', ['angle', 'opacity', 'blur'], stateParams);
|
|
100
|
+
const videoStatesCSS = getStatesCSS(item.id, 'video', ['strokeWidth', 'radius', 'strokeColor'], stateParams);
|
|
96
101
|
return (`
|
|
97
102
|
.video-wrapper-${item.id} {
|
|
98
103
|
opacity: ${layoutParams.opacity};
|
|
99
104
|
transform: rotate(${area.angle}deg);
|
|
100
105
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
101
|
-
transition:
|
|
102
|
-
}
|
|
103
|
-
.video-wrapper-${item.id}:hover {
|
|
104
|
-
${getHoverStyles<ArticleItemType.Video>(['angle', 'opacity', 'blur'], hoverParams)};
|
|
106
|
+
transition: all 0.2s ease;
|
|
105
107
|
}
|
|
106
108
|
.video-${item.id} {
|
|
107
109
|
border-color: ${CntrlColor.parse(layoutParams.strokeColor).fmt('rgba')};
|
|
108
110
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
109
111
|
border-width: ${layoutParams.strokeWidth * 100}vw;
|
|
110
|
-
transition:
|
|
111
|
-
}
|
|
112
|
-
.video-wrapper-${item.id}:hover .video {
|
|
113
|
-
${getHoverStyles<ArticleItemType.Video>(['strokeWidth', 'radius', 'strokeColor'], hoverParams)};
|
|
112
|
+
transition: all 0.2s ease;
|
|
114
113
|
}
|
|
114
|
+
${wrapperStatesCSS}
|
|
115
|
+
${videoStatesCSS}
|
|
115
116
|
`);
|
|
116
117
|
})}
|
|
117
118
|
`}</JSXStyle>
|
|
@@ -5,10 +5,11 @@ import { ItemProps } from '../Item';
|
|
|
5
5
|
import { LinkWrapper } from '../LinkWrapper';
|
|
6
6
|
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
|
-
import {
|
|
8
|
+
import { getLayoutStyles, VimeoEmbedItem as TVimeoEmbedItem } from '@cntrl-site/sdk';
|
|
9
9
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
10
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
11
10
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
11
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
12
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
12
13
|
|
|
13
14
|
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId, onResize }) => {
|
|
14
15
|
const id = useId();
|
|
@@ -21,7 +22,9 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
21
22
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
22
23
|
const [imgRef, setImgRef] = useState<HTMLImageElement | null>(null);
|
|
23
24
|
const [isCoverVisible, setIsCoverVisible] = useState(false);
|
|
24
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
25
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
26
|
+
const wrapperClassNames = useStatesClassNames(item.id, item.state, 'embed-video-wrapper');
|
|
27
|
+
const videoClassNames = useStatesClassNames(item.id, item.state, 'embed-video');
|
|
25
28
|
useRegisterResize(ref, onResize);
|
|
26
29
|
const getValidVimeoUrl = (url: string): string => {
|
|
27
30
|
const validURL = new URL(url);
|
|
@@ -60,7 +63,7 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
60
63
|
return (
|
|
61
64
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
62
65
|
<div
|
|
63
|
-
className={`embed-video-wrapper-${item.id}`}
|
|
66
|
+
className={`embed-video-wrapper-${item.id} ${wrapperClassNames}`}
|
|
64
67
|
ref={setRef}
|
|
65
68
|
style={{
|
|
66
69
|
...(opacity !== undefined ? { opacity } : {}),
|
|
@@ -96,7 +99,7 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
96
99
|
)}
|
|
97
100
|
<iframe
|
|
98
101
|
ref={setIframeRef}
|
|
99
|
-
className=
|
|
102
|
+
className={`embed-video ${videoClassNames}`}
|
|
100
103
|
src={validUrl || ''}
|
|
101
104
|
allow="autoplay; fullscreen; picture-in-picture;"
|
|
102
105
|
allowFullScreen
|
|
@@ -111,31 +114,29 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
111
114
|
width: 100%;
|
|
112
115
|
height: 100%;
|
|
113
116
|
}
|
|
114
|
-
.
|
|
117
|
+
.embed-video {
|
|
115
118
|
width: 100%;
|
|
116
119
|
height: 100%;
|
|
117
120
|
z-index: 1;
|
|
118
121
|
border: none;
|
|
119
122
|
overflow: hidden;
|
|
120
123
|
}
|
|
121
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
124
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
125
|
+
const wrapperStatesCSS = getStatesCSS(item.id, 'embed-video-wrapper', ['angle', 'blur', 'opacity'], stateParams);
|
|
126
|
+
const videoStatesCSS = getStatesCSS(item.id, 'embed-video', ['radius'], stateParams);
|
|
122
127
|
return (`
|
|
123
128
|
.embed-video-wrapper-${item.id} {
|
|
124
129
|
opacity: ${layoutParams.opacity};
|
|
125
130
|
transform: rotate(${area.angle}deg);
|
|
126
131
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
127
|
-
transition:
|
|
132
|
+
transition: all 0.2s ease;
|
|
128
133
|
}
|
|
129
|
-
.embed-video-wrapper-${item.id}
|
|
130
|
-
${getHoverStyles<ArticleItemType.VimeoEmbed>(['angle', 'blur', 'opacity'], hoverParams)}
|
|
131
|
-
}
|
|
132
|
-
.embed-video-wrapper-${item.id} .embedVideo {
|
|
134
|
+
.embed-video-wrapper-${item.id} .embed-video {
|
|
133
135
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
134
|
-
transition:
|
|
135
|
-
}
|
|
136
|
-
.embed-video-wrapper-${item.id}:hover .embedVideo {
|
|
137
|
-
${getHoverStyles<ArticleItemType.VimeoEmbed>(['radius'], hoverParams)};
|
|
136
|
+
transition: all 0.2s ease;
|
|
138
137
|
}
|
|
138
|
+
${wrapperStatesCSS}
|
|
139
|
+
${videoStatesCSS}
|
|
139
140
|
`);
|
|
140
141
|
})}
|
|
141
142
|
`}</JSXStyle>
|
|
@@ -5,12 +5,13 @@ import { LinkWrapper } from '../LinkWrapper';
|
|
|
5
5
|
import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
|
|
6
6
|
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
|
-
import {
|
|
9
|
-
import { getHoverStyles, getTransitions } from '../../utils/HoverStyles/HoverStyles';
|
|
8
|
+
import { getLayoutStyles, YoutubeEmbedItem as TYoutubeEmbedItem } from '@cntrl-site/sdk';
|
|
10
9
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
11
10
|
import { useYouTubeIframeApi } from '../../utils/Youtube/useYouTubeIframeApi';
|
|
12
11
|
import { YTPlayer } from '../../utils/Youtube/YoutubeIframeApi';
|
|
13
12
|
import { useRegisterResize } from "../../common/useRegisterResize";
|
|
13
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
14
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
14
15
|
|
|
15
16
|
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, sectionId, onResize }) => {
|
|
16
17
|
const id = useId();
|
|
@@ -23,7 +24,9 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
23
24
|
const [player, setPlayer] = useState<YTPlayer | undefined>(undefined);
|
|
24
25
|
const [isCoverVisible, setIsCoverVisible] = useState(false);
|
|
25
26
|
const [imgRef, setImgRef] = useState<HTMLImageElement | null>(null);
|
|
26
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
27
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
28
|
+
const wrapperClassNames = useStatesClassNames(item.id, item.state, 'embed-youtube-video-wrapper');
|
|
29
|
+
const embedClassNames = useStatesClassNames(item.id, item.state, 'embed');
|
|
27
30
|
useRegisterResize(div, onResize);
|
|
28
31
|
|
|
29
32
|
useEffect(() => {
|
|
@@ -78,7 +81,7 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
78
81
|
return (
|
|
79
82
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
80
83
|
<div
|
|
81
|
-
className={`embed-youtube-video-wrapper-${item.id}`}
|
|
84
|
+
className={`embed-youtube-video-wrapper-${item.id} ${wrapperClassNames}`}
|
|
82
85
|
onMouseEnter={() => {
|
|
83
86
|
if (!player || play !== 'on-hover') return;
|
|
84
87
|
player.playVideo();
|
|
@@ -113,11 +116,10 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
113
116
|
/>
|
|
114
117
|
)}
|
|
115
118
|
<div
|
|
116
|
-
className={`embed-${item.id}`}
|
|
119
|
+
className={`embed-${item.id} ${embedClassNames}`}
|
|
117
120
|
ref={setDiv}
|
|
118
121
|
style={{
|
|
119
122
|
...(radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {}),
|
|
120
|
-
|
|
121
123
|
}}
|
|
122
124
|
/>
|
|
123
125
|
</div>
|
|
@@ -137,24 +139,22 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
137
139
|
z-index: 1;
|
|
138
140
|
border: none;
|
|
139
141
|
}
|
|
140
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
142
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
143
|
+
const wrapperStatesCSS = getStatesCSS(item.id, 'embed-youtube-video-wrapper', ['angle', 'blur', 'opacity'], stateParams);
|
|
144
|
+
const embedStatesCSS = getStatesCSS(item.id, 'embed', ['radius'], stateParams);
|
|
141
145
|
return (`
|
|
142
146
|
.embed-youtube-video-wrapper-${item.id} {
|
|
143
147
|
opacity: ${layoutParams.opacity};
|
|
144
148
|
transform: rotate(${area.angle}deg);
|
|
145
149
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
146
|
-
transition:
|
|
150
|
+
transition: all 0.2s ease;
|
|
147
151
|
}
|
|
148
152
|
.embed-youtube-video-wrapper-${item.id} .embed-${item.id} {
|
|
149
153
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
150
|
-
transition:
|
|
151
|
-
}
|
|
152
|
-
.embed-youtube-video-wrapper-${item.id}:hover {
|
|
153
|
-
${getHoverStyles<ArticleItemType.YoutubeEmbed>(['angle', 'blur', 'opacity'], hoverParams)};
|
|
154
|
-
}
|
|
155
|
-
.embed-youtube-video-wrapper-${item.id}:hover .embed-${item.id} {
|
|
156
|
-
${getHoverStyles<ArticleItemType.YoutubeEmbed>(['radius'], hoverParams)};
|
|
154
|
+
transition: all 0.2s ease;
|
|
157
155
|
}
|
|
156
|
+
${wrapperStatesCSS}
|
|
157
|
+
${embedStatesCSS}
|
|
158
158
|
`);
|
|
159
159
|
})}
|
|
160
160
|
`}</JSXStyle>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ItemStateParams } from '@cntrl-site/sdk';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { InteractionsContext } from '../provider/InteractionsContext';
|
|
4
|
+
import { useCurrentLayout } from '../common/useCurrentLayout';
|
|
5
|
+
|
|
6
|
+
export function useStatesClassNames(
|
|
7
|
+
itemId: string,
|
|
8
|
+
itemStates: Record<LayoutId, Record<StateId, ItemStateParams>>,
|
|
9
|
+
uniquePrefix: string, // unique in terms of item type, ie. rectangle, code-embed, group etc
|
|
10
|
+
): string {
|
|
11
|
+
const { interactionsStatesMap } = useContext(InteractionsContext);
|
|
12
|
+
const { layoutId } = useCurrentLayout();
|
|
13
|
+
const activeStates = Object.values(interactionsStatesMap);
|
|
14
|
+
const statesForLayout = layoutId ? itemStates[layoutId] : {};
|
|
15
|
+
const stateClassNames = Object.keys(statesForLayout ?? {})
|
|
16
|
+
.filter((stateId) => activeStates.includes(stateId))
|
|
17
|
+
.map((stateId) => `${uniquePrefix}-${itemId}-state-${stateId}`)
|
|
18
|
+
.join(' ');
|
|
19
|
+
return stateClassNames;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type StateId = string;
|
|
23
|
+
type LayoutId = string;
|