@cntrl-site/sdk-nextjs 1.1.1 → 1.1.3

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.
@@ -53,7 +53,7 @@ const RichTextWrapper = ({ isRichText, children }) => {
53
53
  };
54
54
  const noop = () => null;
55
55
  const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGroup = false }) => {
56
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
56
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
57
57
  const itemWrapperRef = (0, react_1.useRef)(null);
58
58
  const itemInnerRef = (0, react_1.useRef)(null);
59
59
  const rectObserver = (0, react_1.useContext)(ArticleRectContext_1.ArticleRectContext);
@@ -119,11 +119,12 @@ const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGrou
119
119
  const width = ((_d = (_c = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.styles) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : dimensions === null || dimensions === void 0 ? void 0 : dimensions.width);
120
120
  const height = ((_f = (_e = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.styles) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : dimensions === null || dimensions === void 0 ? void 0 : dimensions.height);
121
121
  const scale = (_h = (_g = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.styles) === null || _g === void 0 ? void 0 : _g.scale) !== null && _h !== void 0 ? _h : itemScale;
122
+ const hasClickTriggers = (_j = interactionCtrl === null || interactionCtrl === void 0 ? void 0 : interactionCtrl.getHasTrigger(item.id, 'click')) !== null && _j !== void 0 ? _j : false;
122
123
  return ((0, jsx_runtime_1.jsxs)("div", { className: `item-wrapper-${item.id}`, ref: itemWrapperRef, onTransitionEnd: (e) => {
123
124
  var _a;
124
125
  e.stopPropagation();
125
126
  (_a = interactionCtrl === null || interactionCtrl === void 0 ? void 0 : interactionCtrl.handleTransitionEnd) === null || _a === void 0 ? void 0 : _a.call(interactionCtrl, e.propertyName);
126
- }, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (position ? { top: position.top } : {})), (position ? { left: position.left } : {})), (position ? { bottom: position.bottom } : {})), (wrapperHeight !== undefined ? { height: `${wrapperHeight * 100}vw` } : {})), { transition: (_j = wrapperStateProps === null || wrapperStateProps === void 0 ? void 0 : wrapperStateProps.transition) !== null && _j !== void 0 ? _j : 'none' }), children: [(0, jsx_runtime_1.jsx)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, style: {
127
+ }, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (position ? { top: position.top } : {})), (position ? { left: position.left } : {})), (position ? { bottom: position.bottom } : {})), (wrapperHeight !== undefined ? { height: `${wrapperHeight * 100}vw` } : {})), { transition: (_k = wrapperStateProps === null || wrapperStateProps === void 0 ? void 0 : wrapperStateProps.transition) !== null && _k !== void 0 ? _k : 'none' }), children: [(0, jsx_runtime_1.jsx)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, style: {
127
128
  opacity: (keyframes.length !== 0 && !layout) ? 0 : 1,
128
129
  top: `${stickyTop * 100}vw`,
129
130
  height: isRichText && itemHeight ? `${itemHeight * 100}vw` : 'unset',
@@ -140,8 +141,8 @@ const Item = ({ item, sectionId, articleHeight, isParentVisible = true, isInGrou
140
141
  : `${width * 100}vw`
141
142
  : 'max-content'}`,
142
143
  height: `${sizingAxis.y === 'manual' ? `${height * 100}vw` : 'unset'}`
143
- } : {})), (scale !== undefined ? { transform: `scale(${scale})`, 'WebkitTransform': `scale(${scale})` } : {})), { transition: (_k = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.transition) !== null && _k !== void 0 ? _k : 'none', pointerEvents: allowPointerEvents ? 'auto' : 'none' }), children: (0, jsx_runtime_1.jsx)(ItemComponent, { item: item, sectionId: sectionId, onResize: handleItemResize, articleHeight: articleHeight, interactionCtrl: interactionCtrl, onVisibilityChange: handleVisibilityChange }) }) }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
144
- ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams], exemplary) => {
144
+ } : {})), (scale !== undefined ? { transform: `scale(${scale})`, 'WebkitTransform': `scale(${scale})` } : {})), { transition: (_l = innerStateProps === null || innerStateProps === void 0 ? void 0 : innerStateProps.transition) !== null && _l !== void 0 ? _l : 'none', cursor: hasClickTriggers ? 'pointer' : 'unset', pointerEvents: allowPointerEvents ? 'auto' : 'none' }), children: (0, jsx_runtime_1.jsx)(ItemComponent, { item: item, sectionId: sectionId, onResize: handleItemResize, articleHeight: articleHeight, interactionCtrl: interactionCtrl, onVisibilityChange: handleVisibilityChange }) }) }) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
145
+ ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams]) => {
145
146
  const sizingAxis = parseSizing(layoutParams.sizing);
146
147
  const isScreenBasedBottom = area.positionType === sdk_1.PositionType.ScreenBased && area.anchorSide === sdk_1.AnchorSide.Bottom;
147
148
  const scaleAnchor = area.scaleAnchor;
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
@@ -61,6 +70,18 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
61
70
  }
62
71
  });
63
72
  }, [vimeoPlayer, imgRef]);
73
+ const handleClick = () => __awaiter(void 0, void 0, void 0, function* () {
74
+ if (!vimeoPlayer)
75
+ return;
76
+ const isPaused = yield vimeoPlayer.getPaused();
77
+ if (isPaused) {
78
+ vimeoPlayer.play();
79
+ setIsCoverVisible(false);
80
+ }
81
+ else {
82
+ vimeoPlayer.pause();
83
+ }
84
+ });
64
85
  const onCoverClick = () => {
65
86
  if (!vimeoPlayer || !imgRef)
66
87
  return;
@@ -88,7 +109,13 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
88
109
  width: '100%',
89
110
  top: '0',
90
111
  left: '0'
91
- }, alt: "Cover img" })), (0, jsx_runtime_1.jsx)("iframe", { ref: setIframeRef, className: `embed-video`, src: validUrl || '', allow: "autoplay; fullscreen; picture-in-picture;", allowFullScreen: true, style: Object.assign(Object.assign({}, (radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {})), { transition: (_j = frameStateParams === null || frameStateParams === void 0 ? void 0 : frameStateParams.transition) !== null && _j !== void 0 ? _j : 'none' }) })] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
112
+ }, alt: "Cover img" })), (!item.commonParams.controls && play === 'on-click') && ((0, jsx_runtime_1.jsx)("div", { onClick: handleClick, style: {
113
+ position: 'absolute',
114
+ height: '100%',
115
+ width: '100%',
116
+ top: '0',
117
+ left: '0'
118
+ } })), (0, jsx_runtime_1.jsx)("iframe", { ref: setIframeRef, className: `embed-video`, src: validUrl || '', allow: "autoplay; fullscreen; picture-in-picture;", allowFullScreen: true, style: Object.assign(Object.assign({}, (radius !== undefined ? { borderRadius: `${radius * 100}vw` } : {})), { transition: (_j = frameStateParams === null || frameStateParams === void 0 ? void 0 : frameStateParams.transition) !== null && _j !== void 0 ? _j : 'none' }) })] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
92
119
  .embed-video-wrapper-${item.id} {
93
120
  position: absolute;
94
121
  width: 100%;
@@ -93,6 +93,21 @@ class InteractionsRegistry {
93
93
  }
94
94
  return itemStyles;
95
95
  }
96
+ getItemAvailableTriggers(itemId) {
97
+ const available = new Set();
98
+ const activeStates = Object.values(this.interactionStateMap);
99
+ for (const interaction of this.interactions) {
100
+ const { triggers } = interaction;
101
+ for (const trigger of triggers) {
102
+ if (trigger.itemId !== itemId)
103
+ continue;
104
+ if (activeStates.some((stateId) => trigger.from === stateId)) {
105
+ available.add(trigger.type);
106
+ }
107
+ }
108
+ }
109
+ return available;
110
+ }
96
111
  notifyTrigger(itemId, triggerType) {
97
112
  var _a;
98
113
  const timestamp = Date.now();
@@ -120,7 +135,11 @@ class InteractionsRegistry {
120
135
  updated: timestamp
121
136
  };
122
137
  });
123
- this.notifyItemCtrlsChange(transitioningItems);
138
+ const itemsToNotify = new Set(transitioningItems);
139
+ for (const trigger of interaction.triggers) {
140
+ itemsToNotify.add(trigger.itemId);
141
+ }
142
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
124
143
  this.notifyTransitionStartForItems(transitioningItems, activeStateId);
125
144
  }
126
145
  }
@@ -51,6 +51,10 @@ class ItemInteractionController {
51
51
  transition
52
52
  };
53
53
  }
54
+ getHasTrigger(itemId, triggerType) {
55
+ const triggers = this.registry.getItemAvailableTriggers(itemId);
56
+ return triggers.has(triggerType);
57
+ }
54
58
  sendTrigger(type) {
55
59
  this.registry.notifyTrigger(this.itemId, type);
56
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "SDK for Next.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/index.ts",
@@ -161,6 +161,7 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
161
161
  const width = (innerStateProps?.styles?.width ?? dimensions?.width) as number | undefined;
162
162
  const height = (innerStateProps?.styles?.height ?? dimensions?.height) as number | undefined;
163
163
  const scale = innerStateProps?.styles?.scale ?? itemScale;
164
+ const hasClickTriggers = interactionCtrl?.getHasTrigger(item.id, 'click') ?? false;
164
165
  return (
165
166
  <div
166
167
  className={`item-wrapper-${item.id}`}
@@ -209,6 +210,7 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
209
210
  height: `${sizingAxis.y === 'manual' ? `${height * 100}vw` : 'unset'}` } : {}),
210
211
  ...(scale !== undefined ? { transform: `scale(${scale})`, 'WebkitTransform': `scale(${scale})` } : {}),
211
212
  transition: innerStateProps?.transition ?? 'none',
213
+ cursor: hasClickTriggers ? 'pointer' : 'unset',
212
214
  pointerEvents: allowPointerEvents ? 'auto' : 'none'
213
215
  }}
214
216
  >
@@ -224,7 +226,7 @@ export const Item: FC<ItemWrapperProps> = ({ item, sectionId, articleHeight, isP
224
226
  </RichTextWrapper>
225
227
  </div>
226
228
  <JSXStyle id={id}>{`
227
- ${getLayoutStyles(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams], exemplary) => {
229
+ ${getLayoutStyles(layouts, layoutValues, ([area, hidden, sticky, sectionHeight, layoutParams]) => {
228
230
  const sizingAxis = parseSizing(layoutParams.sizing);
229
231
  const isScreenBasedBottom = area.positionType === PositionType.ScreenBased && area.anchorSide === AnchorSide.Bottom;
230
232
  const scaleAnchor = area.scaleAnchor as AreaAnchor;
@@ -61,6 +61,17 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
61
61
  });
62
62
  }, [vimeoPlayer, imgRef]);
63
63
 
64
+ const handleClick = async () => {
65
+ if (!vimeoPlayer) return;
66
+ const isPaused = await vimeoPlayer.getPaused();
67
+ if (isPaused) {
68
+ vimeoPlayer.play();
69
+ setIsCoverVisible(false);
70
+ } else {
71
+ vimeoPlayer.pause();
72
+ }
73
+ };
74
+
64
75
  const onCoverClick = () => {
65
76
  if (!vimeoPlayer || !imgRef) return;
66
77
  vimeoPlayer!.play();
@@ -109,6 +120,19 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
109
120
  alt="Cover img"
110
121
  />
111
122
  )}
123
+ {/* ↓ This is necessary to track clicks on an iframe. */}
124
+ {(!item.commonParams.controls && play === 'on-click') && (
125
+ <div
126
+ onClick={handleClick}
127
+ style={{
128
+ position: 'absolute',
129
+ height: '100%',
130
+ width: '100%',
131
+ top: '0',
132
+ left: '0'
133
+ }}
134
+ />
135
+ )}
112
136
  <iframe
113
137
  ref={setIframeRef}
114
138
  className={`embed-video`}
@@ -92,6 +92,21 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
92
92
  return itemStyles;
93
93
  }
94
94
 
95
+ getItemAvailableTriggers(itemId: string): Set<InteractionTrigger['type']> {
96
+ const available = new Set<InteractionTrigger['type']>();
97
+ const activeStates = Object.values(this.interactionStateMap);
98
+ for (const interaction of this.interactions) {
99
+ const { triggers } = interaction;
100
+ for (const trigger of triggers) {
101
+ if (trigger.itemId !== itemId) continue;
102
+ if (activeStates.some((stateId) => trigger.from === stateId)) {
103
+ available.add(trigger.type);
104
+ }
105
+ }
106
+ }
107
+ return available;
108
+ }
109
+
95
110
  notifyTrigger(itemId: string, triggerType: TriggerType): void {
96
111
  const timestamp = Date.now();
97
112
  for (const interaction of this.interactions) {
@@ -118,7 +133,11 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
118
133
  updated: timestamp
119
134
  };
120
135
  });
121
- this.notifyItemCtrlsChange(transitioningItems);
136
+ const itemsToNotify = new Set<ItemId>(transitioningItems);
137
+ for (const trigger of interaction.triggers) {
138
+ itemsToNotify.add(trigger.itemId);
139
+ }
140
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
122
141
  this.notifyTransitionStartForItems(transitioningItems, activeStateId);
123
142
  }
124
143
  }
@@ -1,6 +1,7 @@
1
1
  import { InteractionsRegistryPort, ItemInteractionCtrl } from './types';
2
2
  import { getTransition } from './getTransition';
3
3
  import { getStyleKeysFromCSSProperty } from './CSSPropertyNameMap';
4
+ import { InteractionTrigger } from '@cntrl-site/sdk';
4
5
 
5
6
  export class ItemInteractionController implements ItemInteractionCtrl {
6
7
  private transitionsInProgress: Set<string> = new Set();
@@ -27,6 +28,11 @@ export class ItemInteractionController implements ItemInteractionCtrl {
27
28
  };
28
29
  }
29
30
 
31
+ getHasTrigger(itemId: string, triggerType: InteractionTrigger['type']): boolean {
32
+ const triggers = this.registry.getItemAvailableTriggers(itemId);
33
+ return triggers.has(triggerType);
34
+ }
35
+
30
36
  sendTrigger(type: 'click' | 'hover-in' | 'hover-out') {
31
37
  this.registry.notifyTrigger(this.itemId, type);
32
38
  }
@@ -1,7 +1,8 @@
1
- import { ArticleItemType, ItemState } from '@cntrl-site/sdk';
1
+ import { ArticleItemType, InteractionTrigger, ItemState } from '@cntrl-site/sdk';
2
2
 
3
3
  export interface ItemInteractionCtrl {
4
4
  getState(keys: string[]): StateCSSInfo;
5
+ getHasTrigger(itemId: string, triggerType: InteractionTrigger['type']): boolean;
5
6
  sendTrigger(type: 'click' | 'hover-in' | 'hover-out'): void;
6
7
  handleTransitionEnd?: (styleKey: string) => void;
7
8
  handleTransitionStart?: (styleKeys: string[]) => void;
@@ -11,6 +12,7 @@ export interface ItemInteractionCtrl {
11
12
  export interface InteractionsRegistryPort {
12
13
  register(itemId: string, ctrl: ItemInteractionCtrl): void;
13
14
  getStatePropsForItem(itemId: string): StateProps;
15
+ getItemAvailableTriggers(itemId: string): Set<InteractionTrigger['type']>;
14
16
  notifyTrigger(itemId: string, type: TriggerType): void;
15
17
  notifyTransitionEnd(itemId: string): void;
16
18
  }