@cntrl-site/sdk-nextjs 1.4.4 → 1.5.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/lib/components/items/EmbedVideoItem/VimeoEmbed.js +14 -0
- package/lib/components/items/EmbedVideoItem/YoutubeEmbed.js +14 -0
- package/lib/interactions/InteractionsRegistry.js +9 -1
- package/lib/interactions/ItemInteractionCtrl.js +7 -0
- package/lib/utils/getValidYoutubeUrl.js +15 -6
- package/package.json +2 -2
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +14 -0
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +14 -0
- package/src/interactions/InteractionsRegistry.ts +8 -2
- package/src/interactions/ItemInteractionCtrl.ts +10 -1
- package/src/interactions/types.ts +2 -0
- package/src/utils/getValidYoutubeUrl.ts +14 -6
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/inspectionProfiles/Project_Default.xml +0 -15
- package/.idea/modules.xml +0 -8
- package/.idea/sdk-nextjs.iml +0 -12
- package/.idea/vcs.xml +0 -6
|
@@ -98,6 +98,20 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
|
|
|
98
98
|
vimeoPlayer.pause();
|
|
99
99
|
}
|
|
100
100
|
}, [isInteractive, onVisibilityChange, vimeoPlayer]);
|
|
101
|
+
(0, react_1.useEffect)(() => {
|
|
102
|
+
if (!vimeoPlayer || !interactionCtrl)
|
|
103
|
+
return;
|
|
104
|
+
interactionCtrl.setActionReceiver((type) => {
|
|
105
|
+
switch (type) {
|
|
106
|
+
case 'play':
|
|
107
|
+
vimeoPlayer.play();
|
|
108
|
+
break;
|
|
109
|
+
case 'pause':
|
|
110
|
+
vimeoPlayer.pause();
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}, [interactionCtrl, vimeoPlayer]);
|
|
101
115
|
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_e = item.link) === null || _e === void 0 ? void 0 : _e.url, target: (_f = item.link) === null || _f === void 0 ? void 0 : _f.target, children: [(0, jsx_runtime_1.jsxs)("div", { className: `embed-video-wrapper-${item.id}`, ref: setRef, style: Object.assign(Object.assign(Object.assign(Object.assign({}, (opacity !== undefined ? { opacity } : {})), (angle !== undefined ? { transform: `rotate(${angle}deg)` } : {})), (blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {})), { transition: (_g = wrapperStateParams === null || wrapperStateParams === void 0 ? void 0 : wrapperStateParams.transition) !== null && _g !== void 0 ? _g : 'none' }), onMouseEnter: () => {
|
|
102
116
|
if (!vimeoPlayer || play !== 'on-hover')
|
|
103
117
|
return;
|
|
@@ -96,6 +96,20 @@ const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibi
|
|
|
96
96
|
player.pauseVideo();
|
|
97
97
|
}
|
|
98
98
|
}, [isInteractive, onVisibilityChange, player]);
|
|
99
|
+
(0, react_1.useEffect)(() => {
|
|
100
|
+
if (!player || !interactionCtrl)
|
|
101
|
+
return;
|
|
102
|
+
interactionCtrl.setActionReceiver((type) => {
|
|
103
|
+
switch (type) {
|
|
104
|
+
case 'play':
|
|
105
|
+
player.playVideo();
|
|
106
|
+
break;
|
|
107
|
+
case 'pause':
|
|
108
|
+
player.pauseVideo();
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}, [interactionCtrl, player]);
|
|
99
113
|
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_e = item.link) === null || _e === void 0 ? void 0 : _e.url, target: (_f = item.link) === null || _f === void 0 ? void 0 : _f.target, children: [(0, jsx_runtime_1.jsxs)("div", { className: `embed-youtube-video-wrapper-${item.id}`, onMouseEnter: () => {
|
|
100
114
|
if (!player || play !== 'on-hover')
|
|
101
115
|
return;
|
|
@@ -109,7 +109,7 @@ class InteractionsRegistry {
|
|
|
109
109
|
return available;
|
|
110
110
|
}
|
|
111
111
|
notifyTrigger(itemId, triggerType) {
|
|
112
|
-
var _a;
|
|
112
|
+
var _a, _b;
|
|
113
113
|
const timestamp = Date.now();
|
|
114
114
|
for (const interaction of this.interactions) {
|
|
115
115
|
const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
|
|
@@ -122,6 +122,14 @@ class InteractionsRegistry {
|
|
|
122
122
|
const isNewStateActive = matchingTrigger.to === activeStateId;
|
|
123
123
|
this.setCurrentStateForInteraction(interaction.id, matchingTrigger.to);
|
|
124
124
|
const transitioningItems = (_a = this.stateItemsIdsMap[activeStateId]) !== null && _a !== void 0 ? _a : [];
|
|
125
|
+
const state = interaction.states.find((state) => state.id === matchingTrigger.to);
|
|
126
|
+
const actions = (_b = state === null || state === void 0 ? void 0 : state.actions) !== null && _b !== void 0 ? _b : [];
|
|
127
|
+
for (const action of actions) {
|
|
128
|
+
const ctrl = this.ctrls.get(action.itemId);
|
|
129
|
+
if (!ctrl)
|
|
130
|
+
continue;
|
|
131
|
+
ctrl.receiveAction(action.type);
|
|
132
|
+
}
|
|
125
133
|
this.itemsStages = this.itemsStages.map((stage) => {
|
|
126
134
|
if (stage.interactionId !== interaction.id)
|
|
127
135
|
return stage;
|
|
@@ -58,6 +58,13 @@ class ItemInteractionController {
|
|
|
58
58
|
sendTrigger(type) {
|
|
59
59
|
this.registry.notifyTrigger(this.itemId, type);
|
|
60
60
|
}
|
|
61
|
+
receiveAction(type) {
|
|
62
|
+
var _a;
|
|
63
|
+
(_a = this.actionReceiver) === null || _a === void 0 ? void 0 : _a.call(this, type);
|
|
64
|
+
}
|
|
65
|
+
setActionReceiver(action) {
|
|
66
|
+
this.actionReceiver = action;
|
|
67
|
+
}
|
|
61
68
|
receiveChange() {
|
|
62
69
|
this.onChange();
|
|
63
70
|
}
|
|
@@ -8,18 +8,27 @@ var Allowed;
|
|
|
8
8
|
})(Allowed || (Allowed = {}));
|
|
9
9
|
function getYoutubeId({ hostname, pathname, search }) {
|
|
10
10
|
if (hostname !== Allowed.Full && hostname !== Allowed.Tiny) {
|
|
11
|
-
throw new Error(`Cannot get valid
|
|
11
|
+
throw new Error(`Cannot get valid YouTube ID from "${hostname}" - address is not whitelisted`);
|
|
12
12
|
}
|
|
13
13
|
switch (hostname) {
|
|
14
14
|
case Allowed.Tiny:
|
|
15
15
|
return pathname.replace('/', '');
|
|
16
16
|
case Allowed.Full:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
if (pathname.startsWith('/shorts/')) {
|
|
18
|
+
const shortsId = pathname.split('/shorts/')[1];
|
|
19
|
+
if (!shortsId) {
|
|
20
|
+
throw new Error('Cannot get valid YouTube Shorts ID from the pathname.');
|
|
21
|
+
}
|
|
22
|
+
return shortsId;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const searchParams = new URLSearchParams(search);
|
|
26
|
+
const id = searchParams.get('v');
|
|
27
|
+
if (!id) {
|
|
28
|
+
throw new Error('Cannot get valid YouTube ID from search params.');
|
|
29
|
+
}
|
|
30
|
+
return id;
|
|
21
31
|
}
|
|
22
|
-
return id;
|
|
23
32
|
}
|
|
24
33
|
}
|
|
25
34
|
exports.getYoutubeId = getYoutubeId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cntrl-site/sdk-nextjs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "SDK for Next.js",
|
|
5
5
|
"author": "arsen@momdesign.nyc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@antfu/eslint-config": "^3.8.0",
|
|
32
32
|
"@cntrl-site/color": "^1.0.0",
|
|
33
33
|
"@cntrl-site/effects": "^1.3.2",
|
|
34
|
-
"@cntrl-site/sdk": "^1.
|
|
34
|
+
"@cntrl-site/sdk": "^1.17.0",
|
|
35
35
|
"@types/vimeo__player": "^2.18.0",
|
|
36
36
|
"@vimeo/player": "^2.25.0",
|
|
37
37
|
"html-react-parser": "^3.0.1",
|
|
@@ -92,6 +92,20 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
92
92
|
}
|
|
93
93
|
}, [isInteractive, onVisibilityChange, vimeoPlayer]);
|
|
94
94
|
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (!vimeoPlayer || !interactionCtrl) return;
|
|
97
|
+
interactionCtrl.setActionReceiver((type) => {
|
|
98
|
+
switch(type) {
|
|
99
|
+
case 'play':
|
|
100
|
+
vimeoPlayer.play();
|
|
101
|
+
break;
|
|
102
|
+
case 'pause':
|
|
103
|
+
vimeoPlayer.pause();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}, [interactionCtrl, vimeoPlayer]);
|
|
108
|
+
|
|
95
109
|
return (
|
|
96
110
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
97
111
|
<div
|
|
@@ -91,6 +91,20 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
91
91
|
}
|
|
92
92
|
}, [isInteractive, onVisibilityChange, player]);
|
|
93
93
|
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!player || !interactionCtrl) return;
|
|
96
|
+
interactionCtrl.setActionReceiver((type) => {
|
|
97
|
+
switch(type) {
|
|
98
|
+
case 'play':
|
|
99
|
+
player.playVideo();
|
|
100
|
+
break;
|
|
101
|
+
case 'pause':
|
|
102
|
+
player.pauseVideo();
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}, [interactionCtrl, player]);
|
|
107
|
+
|
|
94
108
|
return (
|
|
95
109
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
96
110
|
<div
|
|
@@ -121,6 +121,13 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
|
|
|
121
121
|
const isNewStateActive = matchingTrigger.to === activeStateId;
|
|
122
122
|
this.setCurrentStateForInteraction(interaction.id, matchingTrigger.to);
|
|
123
123
|
const transitioningItems = this.stateItemsIdsMap[activeStateId] ?? [];
|
|
124
|
+
const state = interaction.states.find((state) => state.id === matchingTrigger.to);
|
|
125
|
+
const actions = state?.actions ?? [];
|
|
126
|
+
for (const action of actions) {
|
|
127
|
+
const ctrl = this.ctrls.get(action.itemId);
|
|
128
|
+
if (!ctrl) continue;
|
|
129
|
+
ctrl.receiveAction(action.type);
|
|
130
|
+
}
|
|
124
131
|
this.itemsStages = this.itemsStages.map((stage) => {
|
|
125
132
|
if (stage.interactionId !== interaction.id) return stage;
|
|
126
133
|
return {
|
|
@@ -166,8 +173,7 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
|
|
|
166
173
|
});
|
|
167
174
|
this.ctrls.get(itemId)?.receiveChange();
|
|
168
175
|
}
|
|
169
|
-
|
|
170
|
-
|
|
176
|
+
|
|
171
177
|
private getCurrentStateByInteractionId(id: InteractionId): string {
|
|
172
178
|
let state;
|
|
173
179
|
for (const interactionId of Object.keys(this.interactionStateMap)) {
|
|
@@ -5,10 +5,11 @@ import { InteractionTrigger } from '@cntrl-site/sdk';
|
|
|
5
5
|
|
|
6
6
|
export class ItemInteractionController implements ItemInteractionCtrl {
|
|
7
7
|
private transitionsInProgress: Set<string> = new Set();
|
|
8
|
+
private actionReceiver: ((type: 'play' | 'pause') => void) | undefined;
|
|
8
9
|
constructor(
|
|
9
10
|
private itemId: string,
|
|
10
11
|
private registry: InteractionsRegistryPort,
|
|
11
|
-
private onChange: () => void
|
|
12
|
+
private onChange: () => void,
|
|
12
13
|
) {
|
|
13
14
|
this.registry.register(itemId, this);
|
|
14
15
|
}
|
|
@@ -37,6 +38,14 @@ export class ItemInteractionController implements ItemInteractionCtrl {
|
|
|
37
38
|
this.registry.notifyTrigger(this.itemId, type);
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
receiveAction(type: 'play' | 'pause') {
|
|
42
|
+
this.actionReceiver?.(type);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setActionReceiver(action: (type: 'play' | 'pause') => void) {
|
|
46
|
+
this.actionReceiver = action;
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
handleTransitionStart = (types: string[]) => {
|
|
41
50
|
this.transitionsInProgress.clear();
|
|
42
51
|
for (const type of types) {
|
|
@@ -7,6 +7,8 @@ export interface ItemInteractionCtrl {
|
|
|
7
7
|
handleTransitionEnd?: (styleKey: string) => void;
|
|
8
8
|
handleTransitionStart?: (styleKeys: string[]) => void;
|
|
9
9
|
receiveChange: () => void;
|
|
10
|
+
receiveAction: (type: 'play' | 'pause') => void;
|
|
11
|
+
setActionReceiver: (action: (type: 'play' | 'pause') => void) => void;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export interface InteractionsRegistryPort {
|
|
@@ -5,17 +5,25 @@ enum Allowed {
|
|
|
5
5
|
|
|
6
6
|
export function getYoutubeId({ hostname, pathname, search }: URL): string {
|
|
7
7
|
if (hostname !== Allowed.Full && hostname !== Allowed.Tiny) {
|
|
8
|
-
throw new Error(`Cannot get valid
|
|
8
|
+
throw new Error(`Cannot get valid YouTube ID from "${hostname}" - address is not whitelisted`);
|
|
9
9
|
}
|
|
10
10
|
switch (hostname) {
|
|
11
11
|
case Allowed.Tiny:
|
|
12
12
|
return pathname.replace('/', '');
|
|
13
13
|
case Allowed.Full:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
if (pathname.startsWith('/shorts/')) {
|
|
15
|
+
const shortsId = pathname.split('/shorts/')[1];
|
|
16
|
+
if (!shortsId) {
|
|
17
|
+
throw new Error('Cannot get valid YouTube Shorts ID from the pathname.');
|
|
18
|
+
}
|
|
19
|
+
return shortsId;
|
|
20
|
+
} else {
|
|
21
|
+
const searchParams = new URLSearchParams(search);
|
|
22
|
+
const id = searchParams.get('v');
|
|
23
|
+
if (!id) {
|
|
24
|
+
throw new Error('Cannot get valid YouTube ID from search params.');
|
|
25
|
+
}
|
|
26
|
+
return id;
|
|
18
27
|
}
|
|
19
|
-
return id;
|
|
20
28
|
}
|
|
21
29
|
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<component name="InspectionProjectProfileManager">
|
|
2
|
-
<profile version="1.0">
|
|
3
|
-
<option name="myName" value="Project Default" />
|
|
4
|
-
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
|
|
5
|
-
<option name="myValues">
|
|
6
|
-
<value>
|
|
7
|
-
<list size="1">
|
|
8
|
-
<item index="0" class="java.lang.String" itemvalue="jsx" />
|
|
9
|
-
</list>
|
|
10
|
-
</value>
|
|
11
|
-
</option>
|
|
12
|
-
<option name="myCustomValuesEnabled" value="true" />
|
|
13
|
-
</inspection_tool>
|
|
14
|
-
</profile>
|
|
15
|
-
</component>
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/sdk-nextjs.iml" filepath="$PROJECT_DIR$/.idea/sdk-nextjs.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/sdk-nextjs.iml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager">
|
|
4
|
-
<content url="file://$MODULE_DIR$">
|
|
5
|
-
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
6
|
-
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
7
|
-
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
8
|
-
</content>
|
|
9
|
-
<orderEntry type="inheritedJdk" />
|
|
10
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
-
</component>
|
|
12
|
-
</module>
|