@cntrl-site/sdk-nextjs 1.0.18 → 1.0.19-alpha.1
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 +33 -13
- package/lib/components/items/CodeEmbedItem.js +11 -8
- package/lib/components/items/CustomItem.js +10 -7
- package/lib/components/items/GroupItem.js +11 -8
- package/lib/components/items/ImageItem.js +21 -15
- package/lib/components/items/RectangleItem.js +11 -8
- package/lib/components/items/RichTextItem.js +10 -7
- package/lib/components/items/VideoItem.js +16 -12
- package/lib/components/items/VimeoEmbed.js +19 -15
- package/lib/components/items/YoutubeEmbed.js +18 -13
- package/lib/components/useStatesClassNames.js +18 -0
- package/lib/components/useStatesTransitions.js +89 -0
- package/lib/provider/InteractionsContext.js +45 -0
- package/lib/utils/{HoverStyles/HoverStyles.js → StateStyles/StateStyles.js} +36 -24
- 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 +38 -18
- package/src/components/items/CodeEmbedItem.tsx +12 -9
- package/src/components/items/CustomItem.tsx +12 -9
- package/src/components/items/GroupItem.tsx +12 -9
- package/src/components/items/ImageItem.tsx +26 -19
- package/src/components/items/RectangleItem.tsx +13 -10
- package/src/components/items/RichTextItem.tsx +17 -9
- package/src/components/items/VideoItem.tsx +19 -15
- package/src/components/items/VimeoEmbed.tsx +20 -16
- package/src/components/items/YoutubeEmbed.tsx +20 -16
- package/src/components/useStatesClassNames.ts +23 -0
- package/src/components/useStatesTransitions.ts +95 -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} +41 -27
- package/src/utils/getStatesCSS.ts +24 -0
- package/cntrl-site-sdk-nextjs-1.0.17.tgz +0 -0
- package/cntrl-site-sdk-nextjs-1.0.18.tgz +0 -0
package/src/components/Item.tsx
CHANGED
|
@@ -21,7 +21,6 @@ import { useItemDimensions } from './useItemDimensions';
|
|
|
21
21
|
import { useItemScale } from './useItemScale';
|
|
22
22
|
import { ScaleAnchorMap } from '../utils/ScaleAnchorMap';
|
|
23
23
|
import { useSectionHeightData } from './useSectionHeightMap';
|
|
24
|
-
import { getHoverStyles, getTransitions } from '../utils/HoverStyles/HoverStyles';
|
|
25
24
|
import { getItemTopStyle } from '../utils/getItemTopStyle';
|
|
26
25
|
import { useStickyItemTop } from './items/useStickyItemTop';
|
|
27
26
|
import { getAnchoredItemTop } from '../utils/getAnchoredItemTop';
|
|
@@ -32,6 +31,10 @@ import { GroupItem } from './items/GroupItem';
|
|
|
32
31
|
import { CodeEmbedItem } from './items/CodeEmbedItem';
|
|
33
32
|
import { AreaAnchor } from '@cntrl-site/sdk/src/types/article/ItemArea';
|
|
34
33
|
import { KeyframesContext } from '../provider/KeyframesContext';
|
|
34
|
+
import { InteractionsContext } from '../provider/InteractionsContext';
|
|
35
|
+
import { getStatesCSS } from '../utils/getStatesCSS';
|
|
36
|
+
import { useStatesClassNames } from './useStatesClassNames';
|
|
37
|
+
import { useStatesTransitions } from './useStatesTransitions';
|
|
35
38
|
|
|
36
39
|
export interface ItemProps<I extends ItemAny> {
|
|
37
40
|
item: I;
|
|
@@ -79,6 +82,7 @@ const noop = () => null;
|
|
|
79
82
|
|
|
80
83
|
export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isInGroup = false }) => {
|
|
81
84
|
const itemWrapperRef = useRef<HTMLDivElement | null>(null);
|
|
85
|
+
const itemInnerRef = useRef<HTMLDivElement | null>(null);
|
|
82
86
|
const rectObserver = useContext(ArticleRectContext);
|
|
83
87
|
const keyframesRepo = useContext(KeyframesContext);
|
|
84
88
|
const id = useId();
|
|
@@ -93,14 +97,14 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
93
97
|
const sectionHeight = useSectionHeightData(sectionId);
|
|
94
98
|
const stickyTop = useStickyItemTop(item, sectionHeight, sectionId);
|
|
95
99
|
const dimensions = useItemDimensions(item, sectionId);
|
|
96
|
-
const layoutValues: Record<string, any>[] = [item.area, item.hidden, item.state
|
|
100
|
+
const layoutValues: Record<string, any>[] = [item.area, item.hidden, item.state];
|
|
97
101
|
const isInitialRef = useRef(true);
|
|
102
|
+
const { transitionTo, getItemTrigger } = useContext(InteractionsContext);
|
|
98
103
|
layoutValues.push(item.sticky);
|
|
99
104
|
layoutValues.push(sectionHeight);
|
|
100
105
|
if (item.layoutParams) {
|
|
101
106
|
layoutValues.push(item.layoutParams);
|
|
102
107
|
}
|
|
103
|
-
|
|
104
108
|
const sizing = layout && isItemType(item, ArticleItemType.RichText)
|
|
105
109
|
? item.layoutParams[layout].sizing
|
|
106
110
|
: undefined;
|
|
@@ -130,9 +134,13 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
130
134
|
}, []);
|
|
131
135
|
|
|
132
136
|
const isRichText = isItemType(item, ArticleItemType.RichText);
|
|
137
|
+
const innerStatesClassNames = useStatesClassNames(item.id, item.state, 'item-inner');
|
|
138
|
+
const wrapperStatesClassNames = useStatesClassNames(item.id, item.state, 'item-wrapper');
|
|
139
|
+
useStatesTransitions(itemWrapperRef.current, item.state, ['top', 'left']);
|
|
140
|
+
useStatesTransitions(itemInnerRef.current, item.state, ['width', 'height', 'scale']);
|
|
133
141
|
return (
|
|
134
142
|
<div
|
|
135
|
-
className={`item-wrapper-${item.id}`}
|
|
143
|
+
className={`item-wrapper-${item.id} ${wrapperStatesClassNames}`}
|
|
136
144
|
ref={itemWrapperRef}
|
|
137
145
|
style={{
|
|
138
146
|
...(position ? { top: position.top } : {}),
|
|
@@ -152,7 +160,23 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
152
160
|
>
|
|
153
161
|
<RichTextWrapper isRichText={isRichText}>
|
|
154
162
|
<div
|
|
155
|
-
className={`item-${item.id}-inner`}
|
|
163
|
+
className={`item-${item.id}-inner ${innerStatesClassNames}`}
|
|
164
|
+
ref={itemInnerRef}
|
|
165
|
+
onClick={() => {
|
|
166
|
+
const trigger = getItemTrigger(item.id, 'click');
|
|
167
|
+
if (!trigger) return;
|
|
168
|
+
transitionTo(trigger.id, trigger.to);
|
|
169
|
+
}}
|
|
170
|
+
onMouseEnter={() => {
|
|
171
|
+
const trigger = getItemTrigger(item.id, 'hover-in');
|
|
172
|
+
if (!trigger) return;
|
|
173
|
+
transitionTo(trigger.id, trigger.to);
|
|
174
|
+
}}
|
|
175
|
+
onMouseLeave={() => {
|
|
176
|
+
const trigger = getItemTrigger(item.id, 'hover-out');
|
|
177
|
+
if (!trigger) return;
|
|
178
|
+
transitionTo(trigger.id, trigger.to);
|
|
179
|
+
}}
|
|
156
180
|
style={{
|
|
157
181
|
...(dimensions ? {
|
|
158
182
|
width: `${sizingAxis.x === 'manual'
|
|
@@ -169,10 +193,12 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
169
193
|
</RichTextWrapper>
|
|
170
194
|
</div>
|
|
171
195
|
<JSXStyle id={id}>{`
|
|
172
|
-
${getLayoutStyles(layouts, layoutValues, ([area, hidden,
|
|
196
|
+
${getLayoutStyles(layouts, layoutValues, ([area, hidden, states, sticky, sectionHeight, layoutParams], exemplary) => {
|
|
173
197
|
const sizingAxis = parseSizing(layoutParams.sizing);
|
|
174
198
|
const isScreenBasedBottom = area.positionType === PositionType.ScreenBased && area.anchorSide === AnchorSide.Bottom;
|
|
175
199
|
const scaleAnchor = area.scaleAnchor as AreaAnchor;
|
|
200
|
+
const statesInnerCSS = getStatesCSS(item.id, 'item-inner', ['width', 'height', 'scale'], states);
|
|
201
|
+
const statesWrapperCSS = getStatesCSS(item.id, 'item-wrapper', ['top', 'left'], states, area.anchorSide);
|
|
176
202
|
return (`
|
|
177
203
|
.item-${item.id} {
|
|
178
204
|
position: ${sticky ? 'sticky' : 'absolute'};
|
|
@@ -183,7 +209,6 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
183
209
|
height: fit-content;
|
|
184
210
|
}
|
|
185
211
|
.item-${item.id}-inner {
|
|
186
|
-
transition: ${getTransitions(['width', 'height', 'scale'], hoverParams)};
|
|
187
212
|
pointer-events: auto;
|
|
188
213
|
width: ${sizingAxis.x === 'manual'
|
|
189
214
|
? `${area.width * 100}vw`
|
|
@@ -200,14 +225,9 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isI
|
|
|
200
225
|
bottom: ${isScreenBasedBottom ? `${-area.top * 100}vw` : 'unset'};
|
|
201
226
|
top: ${isScreenBasedBottom ? 'unset' : getItemTopStyle(area.top, area.anchorSide)};
|
|
202
227
|
left: ${area.left * 100}vw;
|
|
203
|
-
transition: ${getTransitions(['left', 'top'], hoverParams)};
|
|
204
|
-
}
|
|
205
|
-
.item-${item.id}-inner:hover {
|
|
206
|
-
${getHoverStyles(['width', 'height', 'scale'], hoverParams)};
|
|
207
|
-
}
|
|
208
|
-
.item-wrapper-${item.id}:hover {
|
|
209
|
-
${getHoverStyles(['left', 'top'], hoverParams, area.anchorSide)};
|
|
210
228
|
}
|
|
229
|
+
${statesWrapperCSS}
|
|
230
|
+
${statesInnerCSS}
|
|
211
231
|
`);
|
|
212
232
|
})}
|
|
213
233
|
`}</JSXStyle>
|
|
@@ -223,11 +243,11 @@ function parseSizing(sizing: string = 'manual'): Axis {
|
|
|
223
243
|
} as Axis;
|
|
224
244
|
}
|
|
225
245
|
|
|
246
|
+
export function isItemType<T extends ArticleItemType>(item: ItemAny, itemType: T): item is TItem<T> {
|
|
247
|
+
return item.type === itemType;
|
|
248
|
+
}
|
|
249
|
+
|
|
226
250
|
interface Axis {
|
|
227
251
|
x: 'manual' | 'auto';
|
|
228
252
|
y: 'manual' | 'auto';
|
|
229
253
|
}
|
|
230
|
-
|
|
231
|
-
export function isItemType<T extends ArticleItemType>(item: ItemAny, itemType: T): item is TItem<T> {
|
|
232
|
-
return item.type === itemType;
|
|
233
|
-
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLayoutStyles, CodeEmbedItem as TCodeEmbedItem, AreaAnchor } from '@cntrl-site/sdk';
|
|
2
2
|
import { FC, useEffect, useId, 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';
|
|
9
8
|
import { LinkWrapper } from '../LinkWrapper';
|
|
10
9
|
import { useCodeEmbedItem } from './useCodeEmbedItem';
|
|
10
|
+
import { getStatesCSS } from '../../utils/getStatesCSS';
|
|
11
|
+
import { useStatesClassNames } from '../useStatesClassNames';
|
|
12
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
11
13
|
|
|
12
14
|
const stylesMap = {
|
|
13
15
|
[AreaAnchor.TopLeft]: {},
|
|
@@ -30,7 +32,9 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
30
32
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
31
33
|
useRegisterResize(ref, onResize);
|
|
32
34
|
const pos = stylesMap[anchor];
|
|
33
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
35
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
36
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'embed-wrapper');
|
|
37
|
+
useStatesTransitions(ref!, item.state, ['angle', 'blur', 'opacity']);
|
|
34
38
|
|
|
35
39
|
useEffect(() => {
|
|
36
40
|
if (!ref) return;
|
|
@@ -56,7 +60,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
56
60
|
return (
|
|
57
61
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
58
62
|
<div
|
|
59
|
-
className={`embed-wrapper-${item.id}`}
|
|
63
|
+
className={`embed-wrapper-${item.id} ${statesClassNames}`}
|
|
60
64
|
style={{
|
|
61
65
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
62
66
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
@@ -93,21 +97,20 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
93
97
|
z-index: 1;
|
|
94
98
|
border: none;
|
|
95
99
|
}
|
|
96
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
100
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams], exemplary) => {
|
|
101
|
+
const statesCSS = getStatesCSS(item.id, 'embed-wrapper', ['angle', 'blur', 'opacity'], stateParams);
|
|
97
102
|
return (`
|
|
98
103
|
.embed-wrapper-${item.id} {
|
|
99
104
|
opacity: ${layoutParams.opacity};
|
|
100
105
|
transform: rotate(${area.angle}deg);
|
|
101
106
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
102
|
-
transition:
|
|
107
|
+
transition: all 0.2s ease;
|
|
103
108
|
}
|
|
104
109
|
.embed-${item.id} {
|
|
105
110
|
width: ${item.commonParams.scale ? `${area.width * exemplary}px` : '100%'};
|
|
106
111
|
height: ${item.commonParams.scale ? `${area.height * exemplary}px` : '100%'};
|
|
107
112
|
}
|
|
108
|
-
|
|
109
|
-
${getHoverStyles<ArticleItemType.CodeEmbed>(['angle', 'blur', 'opacity'], hoverParams)}
|
|
110
|
-
}
|
|
113
|
+
${statesCSS}
|
|
111
114
|
`);
|
|
112
115
|
})}
|
|
113
116
|
`}</JSXStyle>
|
|
@@ -1,25 +1,29 @@
|
|
|
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';
|
|
10
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
9
11
|
|
|
10
12
|
export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, sectionId }) => {
|
|
11
13
|
const sdk = useCntrlContext();
|
|
12
14
|
const { layouts } = useCntrlContext();
|
|
13
15
|
const angle = useItemAngle(item, sectionId);
|
|
14
16
|
const component = sdk.customItems.get(item.commonParams.name);
|
|
15
|
-
const layoutValues: Record<string, any>[] = [item.area, item.state
|
|
17
|
+
const layoutValues: Record<string, any>[] = [item.area, item.state];
|
|
16
18
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
17
19
|
useRegisterResize(ref, onResize);
|
|
20
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'custom-component');
|
|
21
|
+
useStatesTransitions(ref, item.state, ['angle'])
|
|
18
22
|
if (!component) return null;
|
|
19
23
|
return (
|
|
20
24
|
<>
|
|
21
25
|
<div
|
|
22
|
-
className={`custom-component-${item.id}`}
|
|
26
|
+
className={`custom-component-${item.id} ${statesClassNames}`}
|
|
23
27
|
ref={setRef}
|
|
24
28
|
style={{
|
|
25
29
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
@@ -28,20 +32,19 @@ export const CustomItem: FC<ItemProps<TCustomItem>> = ({ item, onResize, section
|
|
|
28
32
|
{component({})}
|
|
29
33
|
</div>
|
|
30
34
|
<JSXStyle id={item.id}>
|
|
31
|
-
{`${getLayoutStyles(layouts, layoutValues, ([area,
|
|
35
|
+
{`${getLayoutStyles(layouts, layoutValues, ([area, stateParams]) => {
|
|
36
|
+
const statesCSS = getStatesCSS(item.id, 'custom-component', ['angle'], stateParams);
|
|
32
37
|
return (`
|
|
33
38
|
.custom-component-${item.id} {
|
|
34
39
|
transform: rotate(${area.angle}deg);
|
|
35
|
-
transition:
|
|
40
|
+
transition: all 0.2s ease;
|
|
36
41
|
height: 100%;
|
|
37
42
|
width: 100%;
|
|
38
43
|
position: absolute;
|
|
39
44
|
left: 0;
|
|
40
45
|
top: 0;
|
|
41
46
|
}
|
|
42
|
-
|
|
43
|
-
${getHoverStyles<ArticleItemType.Custom>(['angle'], hoverParams)};
|
|
44
|
-
}
|
|
47
|
+
${statesCSS}
|
|
45
48
|
`);
|
|
46
49
|
})}`}
|
|
47
50
|
</JSXStyle>
|
|
@@ -1,13 +1,15 @@
|
|
|
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';
|
|
12
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
11
13
|
|
|
12
14
|
export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize, articleHeight }) => {
|
|
13
15
|
const id = useId();
|
|
@@ -15,15 +17,17 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
|
|
|
15
17
|
const angle = useItemAngle(item, sectionId);
|
|
16
18
|
const { layouts } = useCntrlContext();
|
|
17
19
|
const { opacity } = useGroupItem(item, sectionId);
|
|
18
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
20
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
21
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'group');
|
|
19
22
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
20
23
|
useRegisterResize(ref, onResize);
|
|
24
|
+
useStatesTransitions(ref!, item.state, ['opacity', 'angle'])
|
|
21
25
|
|
|
22
26
|
return (
|
|
23
27
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
24
28
|
<>
|
|
25
29
|
<div
|
|
26
|
-
className={`group-${item.id}`}
|
|
30
|
+
className={`group-${item.id} ${statesClassNames}`}
|
|
27
31
|
ref={setRef}
|
|
28
32
|
style={{
|
|
29
33
|
...(opacity !== undefined ? { opacity } : {}),
|
|
@@ -47,16 +51,15 @@ export const GroupItem: FC<ItemProps<TGroupItem>> = ({ item, sectionId, onResize
|
|
|
47
51
|
height: 100%;
|
|
48
52
|
box-sizing: border-box;
|
|
49
53
|
}
|
|
50
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
54
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
55
|
+
const statesCSS = getStatesCSS(item.id, 'group', ['opacity', 'angle'], stateParams);
|
|
51
56
|
return (`
|
|
52
57
|
.group-${item.id} {
|
|
53
58
|
opacity: ${layoutParams.opacity};
|
|
54
59
|
transform: rotate(${area.angle}deg);
|
|
55
|
-
transition:
|
|
56
|
-
}
|
|
57
|
-
.group-${item.id}:hover {
|
|
58
|
-
${getHoverStyles<ArticleItemType.Group>(['opacity', 'angle'], hoverParams)};
|
|
60
|
+
transition: all 0.2s ease;
|
|
59
61
|
}
|
|
62
|
+
${statesCSS}
|
|
60
63
|
`);
|
|
61
64
|
})}
|
|
62
65
|
`}</JSXStyle>
|
|
@@ -1,17 +1,19 @@
|
|
|
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';
|
|
16
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
15
17
|
|
|
16
18
|
const baseVariables = `precision mediump float;
|
|
17
19
|
uniform sampler2D u_image;
|
|
@@ -29,8 +31,9 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
29
31
|
const { radius, strokeWidth, opacity, strokeColor, blur } = useFileItem(item, sectionId);
|
|
30
32
|
const angle = useItemAngle(item, sectionId);
|
|
31
33
|
const borderColor = useMemo(() => strokeColor ? CntrlColor.parse(strokeColor) : undefined, [strokeColor]);
|
|
32
|
-
const [
|
|
33
|
-
|
|
34
|
+
const [wrapperRef, setWrapperRef] = useState<HTMLDivElement | null>(null);
|
|
35
|
+
const [imgRef, setImgRef] = useState<HTMLImageElement | HTMLCanvasElement | null>(null);
|
|
36
|
+
useRegisterResize(wrapperRef, onResize);
|
|
34
37
|
const { url, hasGLEffect, fragmentShader, FXControls, FXCursor } = item.commonParams;
|
|
35
38
|
const fxCanvas = useRef<HTMLCanvasElement | null>(null);
|
|
36
39
|
const isInitialRef = useRef(true);
|
|
@@ -41,12 +44,17 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
41
44
|
acc[control.shaderParam] = control.value;
|
|
42
45
|
return acc;
|
|
43
46
|
}, {});
|
|
44
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
47
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
45
48
|
const fullShaderCode = `${baseVariables}\n${controlsVariables}\n${fragmentShader}`;
|
|
46
49
|
const area = layoutId ? item.area[layoutId] : null;
|
|
47
50
|
const exemplary = layouts?.find(l => l.id === layoutId)?.exemplary;
|
|
48
51
|
const width = area && exemplary ? area.width * exemplary : 0;
|
|
49
52
|
const height = area && exemplary ? area.height * exemplary : 0;
|
|
53
|
+
const statesWrapperClassNames = useStatesClassNames(item.id, item.state, 'image-wrapper');
|
|
54
|
+
const statesImgClassNames = useStatesClassNames(item.id, item.state, 'image');
|
|
55
|
+
useStatesTransitions(wrapperRef, item.state, ['angle', 'opacity', 'blur']);
|
|
56
|
+
useStatesTransitions(imgRef, item.state, ['strokeWidth', 'radius', 'strokeColor']);
|
|
57
|
+
useStatesTransitions(fxCanvas.current, item.state, ['strokeWidth', 'radius', 'strokeColor']);
|
|
50
58
|
useEffect(() => {
|
|
51
59
|
isInitialRef.current = false;
|
|
52
60
|
}, []);
|
|
@@ -62,7 +70,7 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
62
70
|
width,
|
|
63
71
|
height
|
|
64
72
|
);
|
|
65
|
-
const rect = useElementRect(
|
|
73
|
+
const rect = useElementRect(wrapperRef);
|
|
66
74
|
const rectWidth = Math.floor(rect?.width ?? 0);
|
|
67
75
|
const rectHeight = Math.floor(rect?.height ?? 0);
|
|
68
76
|
const inlineStyles = {
|
|
@@ -74,8 +82,8 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
74
82
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
75
83
|
<>
|
|
76
84
|
<div
|
|
77
|
-
className={`image-wrapper-${item.id}`}
|
|
78
|
-
ref={
|
|
85
|
+
className={`image-wrapper-${item.id} ${statesWrapperClassNames}`}
|
|
86
|
+
ref={setWrapperRef}
|
|
79
87
|
style={{
|
|
80
88
|
...(opacity !== undefined ? { opacity } : {}),
|
|
81
89
|
...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}),
|
|
@@ -86,15 +94,16 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
86
94
|
<canvas
|
|
87
95
|
style={inlineStyles}
|
|
88
96
|
ref={fxCanvas}
|
|
89
|
-
className={`img-canvas image-${item.id}`}
|
|
97
|
+
className={`img-canvas image-${item.id} ${statesImgClassNames}`}
|
|
90
98
|
width={rectWidth}
|
|
91
99
|
height={rectHeight}
|
|
92
100
|
/>
|
|
93
101
|
) : (
|
|
94
102
|
<img
|
|
95
103
|
alt=""
|
|
96
|
-
className={`image image-${item.id}`}
|
|
104
|
+
className={`image image-${item.id} ${statesImgClassNames}`}
|
|
97
105
|
style={inlineStyles}
|
|
106
|
+
ref={setImgRef}
|
|
98
107
|
src={item.commonParams.url}
|
|
99
108
|
/>
|
|
100
109
|
)}
|
|
@@ -125,26 +134,24 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, sectionId, onResize
|
|
|
125
134
|
border-width: 0;
|
|
126
135
|
box-sizing: border-box;
|
|
127
136
|
}
|
|
128
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
137
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, stateParams]) => {
|
|
138
|
+
const wrapperStatesCSS = getStatesCSS(item.id, 'image-wrapper', ['angle', 'opacity', 'blur'], stateParams);
|
|
139
|
+
const imgStatesCSS = getStatesCSS(item.id, 'image', ['strokeWidth', 'radius', 'strokeColor'], stateParams);
|
|
129
140
|
return (`
|
|
130
141
|
.image-wrapper-${item.id} {
|
|
131
142
|
opacity: ${layoutParams.opacity};
|
|
132
143
|
transform: rotate(${area.angle}deg);
|
|
133
144
|
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)};
|
|
145
|
+
transition: all 0.2s ease;
|
|
138
146
|
}
|
|
139
147
|
.image-${item.id} {
|
|
140
148
|
border-color: ${CntrlColor.parse(layoutParams.strokeColor).fmt('rgba')};
|
|
141
149
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
142
150
|
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)};
|
|
151
|
+
transition: all 0.2s ease;
|
|
147
152
|
}
|
|
153
|
+
${wrapperStatesCSS}
|
|
154
|
+
${imgStatesCSS}
|
|
148
155
|
`);
|
|
149
156
|
})}
|
|
150
157
|
`}</JSXStyle>
|
|
@@ -1,14 +1,16 @@
|
|
|
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';
|
|
13
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
12
14
|
|
|
13
15
|
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId, onResize }) => {
|
|
14
16
|
const id = useId();
|
|
@@ -17,16 +19,18 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
17
19
|
const angle = useItemAngle(item, sectionId);
|
|
18
20
|
const backgroundColor = useMemo(() => fillColor ? CntrlColor.parse(fillColor) : undefined, [fillColor]);
|
|
19
21
|
const borderColor = useMemo(() => strokeColor ? CntrlColor.parse(strokeColor) : undefined, [strokeColor]);
|
|
20
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
22
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
21
23
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
24
|
+
const statesClassNames = useStatesClassNames(item.id, item.state, 'rectangle');
|
|
22
25
|
useRegisterResize(ref, onResize);
|
|
23
26
|
const backdropFilterValue = backdropBlur ? `blur(${backdropBlur * 100}vw)`: undefined;
|
|
27
|
+
useStatesTransitions(ref, item.state, ['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor', 'blur', 'backdropBlur']);
|
|
24
28
|
|
|
25
29
|
return (
|
|
26
30
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
27
31
|
<>
|
|
28
32
|
<div
|
|
29
|
-
className={`rectangle-${item.id}`}
|
|
33
|
+
className={`rectangle-${item.id} ${statesClassNames}`}
|
|
30
34
|
ref={setRef}
|
|
31
35
|
style={{
|
|
32
36
|
...(backgroundColor ? { backgroundColor : `${backgroundColor.fmt('rgba')}` } : {}),
|
|
@@ -49,7 +53,8 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
49
53
|
border-style: solid;
|
|
50
54
|
box-sizing: border-box;
|
|
51
55
|
}
|
|
52
|
-
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
56
|
+
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, states]) => {
|
|
57
|
+
const statesCSS = getStatesCSS(item.id, 'rectangle', ['angle', 'fillColor', 'strokeWidth', 'radius', 'strokeColor', 'blur', 'backdropBlur'], states);
|
|
53
58
|
return (`
|
|
54
59
|
.rectangle-${item.id} {
|
|
55
60
|
background-color: ${CntrlColor.parse(layoutParams.fillColor).fmt('rgba')};
|
|
@@ -60,11 +65,9 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, sectionId,
|
|
|
60
65
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
61
66
|
backdrop-filter: ${layoutParams.backdropFilter !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
62
67
|
-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)};
|
|
68
|
+
transition: all 0.2s ease;
|
|
67
69
|
}
|
|
70
|
+
${statesCSS}
|
|
68
71
|
`);
|
|
69
72
|
})}
|
|
70
73
|
`}</JSXStyle>
|
|
@@ -1,16 +1,18 @@
|
|
|
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';
|
|
15
|
+
import { useStatesTransitions } from '../useStatesTransitions';
|
|
14
16
|
|
|
15
17
|
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, onResize }) => {
|
|
16
18
|
const [content, styles] = useRichTextItem(item);
|
|
@@ -20,15 +22,17 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
20
22
|
const angle = useItemAngle(item, sectionId);
|
|
21
23
|
const { blur, wordSpacing, letterSpacing, color, fontSize, lineHeight } = useRichTextItemValues(item, sectionId);
|
|
22
24
|
const textColor = useMemo(() => color ? CntrlColor.parse(color) : undefined, [color]);
|
|
23
|
-
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state
|
|
25
|
+
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams, item.state];
|
|
24
26
|
const exemplary = useExemplary();
|
|
27
|
+
const stateClassNames = useStatesClassNames(item.id, item.state, 'rich-text-wrapper');
|
|
25
28
|
useRegisterResize(ref, onResize);
|
|
29
|
+
useStatesTransitions(ref, item.state, ['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color']);
|
|
26
30
|
|
|
27
31
|
return (
|
|
28
32
|
<>
|
|
29
33
|
<div
|
|
30
34
|
ref={setRef}
|
|
31
|
-
className={`rich-text-wrapper-${item.id}`}
|
|
35
|
+
className={`rich-text-wrapper-${item.id} ${stateClassNames}`}
|
|
32
36
|
style={{
|
|
33
37
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
34
38
|
...(textColor ? { color: `${textColor.fmt('rgba')}` } : {}),
|
|
@@ -43,8 +47,14 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
43
47
|
</div>
|
|
44
48
|
<JSXStyle id={id}>
|
|
45
49
|
{styles}
|
|
46
|
-
{`${getLayoutStyles(layouts, layoutValues, ([area, layoutParams,
|
|
50
|
+
{`${getLayoutStyles(layouts, layoutValues, ([area, layoutParams, states]) => {
|
|
47
51
|
const color = CntrlColor.parse(layoutParams.color);
|
|
52
|
+
const statesCSS = getStatesCSS(
|
|
53
|
+
item.id,
|
|
54
|
+
'rich-text-wrapper',
|
|
55
|
+
['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color'],
|
|
56
|
+
states
|
|
57
|
+
);
|
|
48
58
|
return (`
|
|
49
59
|
.rich-text-wrapper-${item.id} {
|
|
50
60
|
font-size: ${layoutParams.fontSize * 100}vw;
|
|
@@ -60,16 +70,14 @@ export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item, sectionId, on
|
|
|
60
70
|
transform: rotate(${area.angle}deg);
|
|
61
71
|
filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'};
|
|
62
72
|
text-transform: ${layoutParams.textTransform};
|
|
63
|
-
transition:
|
|
64
|
-
}
|
|
65
|
-
.rich-text-wrapper-${item.id}:hover {
|
|
66
|
-
${getHoverStyles<ArticleItemType.RichText>(['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color'], hoverParams)};
|
|
73
|
+
transition: all 0.2s ease;
|
|
67
74
|
}
|
|
68
75
|
@supports not (color: oklch(42% 0.3 90 / 1)) {
|
|
69
76
|
.rich-text-wrapper-${item.id} {
|
|
70
77
|
color: ${color.fmt('rgba')};
|
|
71
78
|
}
|
|
72
79
|
}
|
|
80
|
+
${statesCSS}
|
|
73
81
|
`);
|
|
74
82
|
})}`}
|
|
75
83
|
</JSXStyle>
|