@cntrl-site/sdk-nextjs 1.8.9-alpha.10 → 1.8.9-alpha.12

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.
@@ -2,9 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LinkWrapper = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';
6
5
  const LinkWrapper = ({ url, children, target }) => {
7
- const validUrl = url && prependBasePath(buildValidUrl(url));
6
+ const validUrl = url && buildValidUrl(url);
8
7
  const targetParams = target === '_blank' ? { target, rel: 'noreferrer' } : {};
9
8
  return url ? ((0, jsx_runtime_1.jsx)("a", Object.assign({ href: validUrl }, targetParams, { children: children }))) : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children }));
10
9
  };
@@ -26,10 +25,3 @@ function buildValidUrl(url) {
26
25
  return url;
27
26
  return `//${url}`;
28
27
  }
29
- function prependBasePath(url) {
30
- // Only prepend for internal links (starting with '/')
31
- if (url && url.startsWith('/') && basePath && !url.startsWith(basePath)) {
32
- return `${basePath}${url}`;
33
- }
34
- return url;
35
- }
@@ -93,6 +93,8 @@ class InteractionsRegistry {
93
93
  for (const interaction of this.interactions) {
94
94
  const { triggers } = interaction;
95
95
  for (const trigger of triggers) {
96
+ if (!('itemId' in trigger))
97
+ continue;
96
98
  if (trigger.itemId !== itemId)
97
99
  continue;
98
100
  if (activeStates.includes(trigger.from)) {
@@ -102,12 +104,107 @@ class InteractionsRegistry {
102
104
  }
103
105
  return available;
104
106
  }
105
- notifyTrigger(itemId, triggerType) {
107
+ notifyLoad() {
106
108
  var _a, _b;
107
109
  const timestamp = Date.now();
108
110
  for (const interaction of this.interactions) {
109
111
  const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
110
- const matchingTrigger = interaction.triggers.find((trigger) => trigger.itemId === itemId
112
+ const matchingTrigger = interaction.triggers.find(trigger => 'position' in trigger && trigger.position === 0 && trigger.from === currentStateId);
113
+ if (!matchingTrigger)
114
+ continue;
115
+ const activeStateId = this.getActiveInteractionState(interaction.id);
116
+ const isNewStateActive = matchingTrigger.to === activeStateId;
117
+ this.setCurrentStateForInteraction(interaction.id, matchingTrigger.to);
118
+ const transitioningItems = (_a = this.stateItemsIdsMap[activeStateId]) !== null && _a !== void 0 ? _a : [];
119
+ const state = interaction.states.find((state) => state.id === matchingTrigger.to);
120
+ const actions = (_b = state === null || state === void 0 ? void 0 : state.actions) !== null && _b !== void 0 ? _b : [];
121
+ for (const action of actions) {
122
+ const ctrl = this.ctrls.get(action.itemId);
123
+ if (!ctrl)
124
+ continue;
125
+ ctrl.receiveAction(action.type);
126
+ }
127
+ this.itemsStages = this.itemsStages.map((stage) => {
128
+ if (stage.interactionId !== interaction.id)
129
+ return stage;
130
+ return {
131
+ itemId: stage.itemId,
132
+ interactionId: stage.interactionId,
133
+ type: 'transitioning',
134
+ from: stage.type === 'transitioning' ? stage.to : stage.stateId,
135
+ to: matchingTrigger.to,
136
+ direction: isNewStateActive ? 'in' : 'out',
137
+ updated: timestamp
138
+ };
139
+ });
140
+ const itemsToNotify = new Set(transitioningItems);
141
+ for (const trigger of interaction.triggers) {
142
+ if (!('itemId' in trigger))
143
+ continue;
144
+ itemsToNotify.add(trigger.itemId);
145
+ }
146
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
147
+ this.notifyTransitionStartForItems(transitioningItems, activeStateId);
148
+ }
149
+ }
150
+ notifyScrollTrigger(position) {
151
+ var _a, _b;
152
+ const timestamp = Date.now();
153
+ for (const interaction of this.interactions) {
154
+ const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
155
+ const matchingTrigger = interaction.triggers.find((trigger) => {
156
+ if (!('position' in trigger) || trigger.position === 0)
157
+ return false;
158
+ const isScrollingDown = trigger.position < position;
159
+ const relevantState = isScrollingDown ? trigger.from : trigger.to;
160
+ return relevantState === currentStateId;
161
+ });
162
+ if (!matchingTrigger || !('position' in matchingTrigger))
163
+ continue;
164
+ const activeStateId = this.getActiveInteractionState(interaction.id);
165
+ const targetStateId = matchingTrigger.position > position ? matchingTrigger.from : matchingTrigger.to;
166
+ const isNewStateActive = targetStateId === activeStateId;
167
+ this.setCurrentStateForInteraction(interaction.id, targetStateId !== null && targetStateId !== void 0 ? targetStateId : activeStateId);
168
+ const transitioningItems = (_a = this.stateItemsIdsMap[activeStateId]) !== null && _a !== void 0 ? _a : [];
169
+ const state = interaction.states.find((state) => state.id === targetStateId);
170
+ const actions = (_b = state === null || state === void 0 ? void 0 : state.actions) !== null && _b !== void 0 ? _b : [];
171
+ for (const action of actions) {
172
+ const ctrl = this.ctrls.get(action.itemId);
173
+ if (!ctrl)
174
+ continue;
175
+ ctrl.receiveAction(action.type);
176
+ }
177
+ const itemsStages = this.itemsStages.map((stage) => {
178
+ if (stage.interactionId !== interaction.id)
179
+ return stage;
180
+ return {
181
+ itemId: stage.itemId,
182
+ interactionId: stage.interactionId,
183
+ type: 'transitioning',
184
+ from: stage.type === 'transitioning' ? stage.to : stage.stateId,
185
+ to: targetStateId,
186
+ direction: isNewStateActive ? 'in' : 'out',
187
+ updated: timestamp
188
+ };
189
+ });
190
+ this.itemsStages = itemsStages;
191
+ const itemsToNotify = new Set(transitioningItems);
192
+ for (const trigger of interaction.triggers) {
193
+ if (!('itemId' in trigger))
194
+ continue;
195
+ itemsToNotify.add(trigger.itemId);
196
+ }
197
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
198
+ this.notifyTransitionStartForItems(transitioningItems, activeStateId);
199
+ }
200
+ }
201
+ notifyItemTrigger(itemId, triggerType) {
202
+ var _a, _b;
203
+ const timestamp = Date.now();
204
+ for (const interaction of this.interactions) {
205
+ const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
206
+ const matchingTrigger = interaction.triggers.find((trigger) => 'itemId' in trigger
207
+ && trigger.itemId === itemId
111
208
  && trigger.from === currentStateId
112
209
  && trigger.type === triggerType);
113
210
  if (!matchingTrigger)
@@ -139,6 +236,8 @@ class InteractionsRegistry {
139
236
  });
140
237
  const itemsToNotify = new Set(transitioningItems);
141
238
  for (const trigger of interaction.triggers) {
239
+ if (!('itemId' in trigger))
240
+ continue;
142
241
  itemsToNotify.add(trigger.itemId);
143
242
  }
144
243
  this.notifyItemCtrlsChange(Array.from(itemsToNotify));
@@ -56,7 +56,7 @@ class ItemInteractionController {
56
56
  return triggers.has(triggerType);
57
57
  }
58
58
  sendTrigger(type) {
59
- this.registry.notifyTrigger(this.itemId, type);
59
+ this.registry.notifyItemTrigger(this.itemId, type);
60
60
  }
61
61
  receiveAction(type) {
62
62
  var _a;
@@ -5,14 +5,35 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const InteractionsRegistry_1 = require("../interactions/InteractionsRegistry");
7
7
  const useCurrentLayout_1 = require("../common/useCurrentLayout");
8
+ const ArticleRectContext_1 = require("./ArticleRectContext");
8
9
  exports.InteractionsContext = (0, react_1.createContext)(undefined);
9
10
  const InteractionsProvider = ({ article, children }) => {
10
11
  const { layoutId } = (0, useCurrentLayout_1.useCurrentLayout)();
12
+ const articleRectObserver = (0, react_1.useContext)(ArticleRectContext_1.ArticleRectContext);
11
13
  const registry = (0, react_1.useMemo)(() => {
12
14
  if (!layoutId)
13
15
  return;
14
16
  return new InteractionsRegistry_1.InteractionsRegistry(article, layoutId);
15
17
  }, [layoutId]);
18
+ (0, react_1.useEffect)(() => {
19
+ if (!registry || !articleRectObserver)
20
+ return;
21
+ const handleScroll = () => {
22
+ const scrollY = window.scrollY;
23
+ registry.notifyScrollTrigger(scrollY);
24
+ };
25
+ return articleRectObserver.on('scroll', handleScroll);
26
+ }, [registry, articleRectObserver]);
27
+ (0, react_1.useEffect)(() => {
28
+ if (!registry)
29
+ return;
30
+ registry.notifyLoad();
31
+ const handleLoad = () => {
32
+ registry.notifyLoad();
33
+ };
34
+ window.addEventListener('load', handleLoad);
35
+ return () => window.removeEventListener('load', handleLoad);
36
+ }, [registry]);
16
37
  return ((0, jsx_runtime_1.jsx)(exports.InteractionsContext.Provider, { value: registry, children: children }));
17
38
  };
18
39
  exports.InteractionsProvider = InteractionsProvider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "1.8.9-alpha.10",
3
+ "version": "1.8.9-alpha.12",
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.22.8",
34
+ "@cntrl-site/sdk": "^1.22.9-alpha.1",
35
35
  "@types/vimeo__player": "^2.18.0",
36
36
  "@vimeo/player": "^2.25.0",
37
37
  "html-react-parser": "^3.0.1",
@@ -24,7 +24,7 @@ export const ScrollPlaybackVideo: FC<Props> = ({ sectionId, src, playbackParams,
24
24
  const scrollPos = articleRectObserver.getSectionScroll(sectionId);
25
25
  const time = rangeMap(scrollPos, playbackParams.from, playbackParams.to, 0, 1, true);
26
26
  setTime(toFixed(time));
27
- })
27
+ });
28
28
  }, [playbackParams?.from, playbackParams?.to, time]);
29
29
 
30
30
  const scrollVideoManager = useMemo<ScrollPlaybackVideoManager | null>(() => {
@@ -1,7 +1,5 @@
1
1
  import React, { ReactElement, ReactNode } from 'react';
2
2
 
3
- const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';
4
-
5
3
  interface Props {
6
4
  url?: string;
7
5
  children: ReactElement | ReactNode[];
@@ -9,7 +7,7 @@ interface Props {
9
7
  }
10
8
 
11
9
  export const LinkWrapper: React.FC<Props> = ({ url, children, target }) => {
12
- const validUrl = url && prependBasePath(buildValidUrl(url));
10
+ const validUrl = url && buildValidUrl(url);
13
11
  const targetParams = target === '_blank' ? { target, rel: 'noreferrer' } : {};
14
12
  return url ? (
15
13
  <a
@@ -39,11 +37,3 @@ function buildValidUrl(url: string): string {
39
37
  if (protocolCheck) return url;
40
38
  return `//${url}`;
41
39
  }
42
-
43
- function prependBasePath(url: string): string {
44
- // Only prepend for internal links (starting with '/')
45
- if (url && url.startsWith('/') && basePath && !url.startsWith(basePath)) {
46
- return `${basePath}${url}`;
47
- }
48
- return url;
49
- }
@@ -3,7 +3,7 @@ import {
3
3
  Article,
4
4
  ArticleItemType,
5
5
  Interaction,
6
- InteractionTrigger,
6
+ InteractionItemTrigger,
7
7
  ItemAny,
8
8
  } from '@cntrl-site/sdk';
9
9
  import { isItemType } from '../utils/isItemType';
@@ -96,12 +96,13 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
96
96
  return itemStyles;
97
97
  }
98
98
 
99
- getItemAvailableTriggers(itemId: string): Set<InteractionTrigger['type']> {
100
- const available = new Set<InteractionTrigger['type']>();
99
+ getItemAvailableTriggers(itemId: string): Set<InteractionItemTrigger['type']> {
100
+ const available = new Set<InteractionItemTrigger['type']>();
101
101
  const activeStates = Object.values(this.interactionStateMap);
102
102
  for (const interaction of this.interactions) {
103
103
  const { triggers } = interaction;
104
104
  for (const trigger of triggers) {
105
+ if (!('itemId' in trigger)) continue;
105
106
  if (trigger.itemId !== itemId) continue;
106
107
  if (activeStates.includes(trigger.from)) {
107
108
  available.add(trigger.type);
@@ -111,12 +112,102 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
111
112
  return available;
112
113
  }
113
114
 
114
- notifyTrigger(itemId: string, triggerType: TriggerType): void {
115
+ notifyLoad() {
116
+ const timestamp = Date.now();
117
+ for (const interaction of this.interactions) {
118
+ const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
119
+ const matchingTrigger = interaction.triggers.find(trigger =>
120
+ 'position' in trigger && trigger.position === 0 && trigger.from === currentStateId
121
+ );
122
+ if (!matchingTrigger) continue;
123
+ const activeStateId = this.getActiveInteractionState(interaction.id);
124
+ const isNewStateActive = matchingTrigger.to === activeStateId;
125
+ this.setCurrentStateForInteraction(interaction.id, matchingTrigger.to);
126
+ const transitioningItems = this.stateItemsIdsMap[activeStateId] ?? [];
127
+ const state = interaction.states.find((state) => state.id === matchingTrigger.to);
128
+ const actions = state?.actions ?? [];
129
+ for (const action of actions) {
130
+ const ctrl = this.ctrls.get(action.itemId);
131
+ if (!ctrl) continue;
132
+ ctrl.receiveAction(action.type);
133
+ }
134
+
135
+ this.itemsStages = this.itemsStages.map((stage) => {
136
+ if (stage.interactionId !== interaction.id) return stage;
137
+ return {
138
+ itemId: stage.itemId,
139
+ interactionId: stage.interactionId,
140
+ type: 'transitioning',
141
+ from: stage.type === 'transitioning' ? stage.to : stage.stateId!,
142
+ to: matchingTrigger.to,
143
+ direction: isNewStateActive ? 'in' : 'out',
144
+ updated: timestamp
145
+ };
146
+ });
147
+
148
+ const itemsToNotify = new Set<ItemId>(transitioningItems);
149
+ for (const trigger of interaction.triggers) {
150
+ if (!('itemId' in trigger)) continue;
151
+ itemsToNotify.add(trigger.itemId);
152
+ }
153
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
154
+ this.notifyTransitionStartForItems(transitioningItems, activeStateId);
155
+ }
156
+ }
157
+
158
+ notifyScrollTrigger(position: number) {
159
+ const timestamp = Date.now();
160
+ for (const interaction of this.interactions) {
161
+ const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
162
+ const matchingTrigger = interaction.triggers.find((trigger) => {
163
+ if (!('position' in trigger) || trigger.position === 0) return false;
164
+ const isScrollingDown = trigger.position < position;
165
+ const relevantState = isScrollingDown ? trigger.from : trigger.to;
166
+ return relevantState === currentStateId;
167
+ });
168
+ if (!matchingTrigger || !('position' in matchingTrigger)) continue;
169
+ const activeStateId = this.getActiveInteractionState(interaction.id);
170
+ const targetStateId = matchingTrigger.position > position ? matchingTrigger.from : matchingTrigger.to;
171
+ const isNewStateActive = targetStateId === activeStateId;
172
+ this.setCurrentStateForInteraction(interaction.id, targetStateId ?? activeStateId);
173
+ const transitioningItems = this.stateItemsIdsMap[activeStateId] ?? [];
174
+ const state = interaction.states.find((state) => state.id === targetStateId);
175
+ const actions = state?.actions ?? [];
176
+ for (const action of actions) {
177
+ const ctrl = this.ctrls.get(action.itemId);
178
+ if (!ctrl) continue;
179
+ ctrl.receiveAction(action.type);
180
+ }
181
+ const itemsStages = this.itemsStages.map((stage) => {
182
+ if (stage.interactionId !== interaction.id) return stage;
183
+ return {
184
+ itemId: stage.itemId,
185
+ interactionId: stage.interactionId,
186
+ type: 'transitioning' as const,
187
+ from: stage.type === 'transitioning' ? stage.to : stage.stateId!,
188
+ to: targetStateId,
189
+ direction: isNewStateActive ? 'in' as const : 'out' as const,
190
+ updated: timestamp
191
+ };
192
+ });
193
+ this.itemsStages = itemsStages;
194
+ const itemsToNotify = new Set<ItemId>(transitioningItems);
195
+ for (const trigger of interaction.triggers) {
196
+ if (!('itemId' in trigger)) continue;
197
+ itemsToNotify.add(trigger.itemId);
198
+ }
199
+ this.notifyItemCtrlsChange(Array.from(itemsToNotify));
200
+ this.notifyTransitionStartForItems(transitioningItems, activeStateId);
201
+ }
202
+ }
203
+
204
+ notifyItemTrigger(itemId: string, triggerType: TriggerType): void {
115
205
  const timestamp = Date.now();
116
206
  for (const interaction of this.interactions) {
117
207
  const currentStateId = this.getCurrentStateByInteractionId(interaction.id);
118
208
  const matchingTrigger = interaction.triggers.find((trigger) =>
119
- trigger.itemId === itemId
209
+ 'itemId' in trigger
210
+ && trigger.itemId === itemId
120
211
  && trigger.from === currentStateId
121
212
  && trigger.type === triggerType
122
213
  );
@@ -146,6 +237,7 @@ export class InteractionsRegistry implements InteractionsRegistryPort {
146
237
  });
147
238
  const itemsToNotify = new Set<ItemId>(transitioningItems);
148
239
  for (const trigger of interaction.triggers) {
240
+ if (!('itemId' in trigger)) continue;
149
241
  itemsToNotify.add(trigger.itemId);
150
242
  }
151
243
  this.notifyItemCtrlsChange(Array.from(itemsToNotify));
@@ -269,7 +361,7 @@ type TransitioningStage = {
269
361
  type ActiveStage = { type: 'active'; itemId: string; interactionId: string; stateId?: string; isStartState: boolean; updated: number; };
270
362
  type InteractionStateMap = Record<InteractionId, StateId>;
271
363
  type StateItemsIdsMap = Record<StateId, ItemId[]>;
272
- type TriggerType = InteractionTrigger['type'];
364
+ type TriggerType = InteractionItemTrigger['type'];
273
365
  type InteractionId = string;
274
366
  type StateId = string;
275
367
  type ItemId = string;
@@ -1,11 +1,12 @@
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
+ import { InteractionItemTrigger } from '@cntrl-site/sdk';
5
5
 
6
6
  export class ItemInteractionController implements ItemInteractionCtrl {
7
7
  private transitionsInProgress: Set<string> = new Set();
8
8
  private actionReceiver: ((type: 'play' | 'pause') => void) | undefined;
9
+
9
10
  constructor(
10
11
  private itemId: string,
11
12
  private registry: InteractionsRegistryPort,
@@ -29,13 +30,13 @@ export class ItemInteractionController implements ItemInteractionCtrl {
29
30
  };
30
31
  }
31
32
 
32
- getHasTrigger(itemId: string, triggerType: InteractionTrigger['type']): boolean {
33
+ getHasTrigger(itemId: string, triggerType: InteractionItemTrigger['type']): boolean {
33
34
  const triggers = this.registry.getItemAvailableTriggers(itemId);
34
35
  return triggers.has(triggerType);
35
36
  }
36
37
 
37
38
  sendTrigger(type: 'click' | 'hover-in' | 'hover-out') {
38
- this.registry.notifyTrigger(this.itemId, type);
39
+ this.registry.notifyItemTrigger(this.itemId, type);
39
40
  }
40
41
 
41
42
  receiveAction(type: 'play' | 'pause') {
@@ -1,8 +1,8 @@
1
- import { ArticleItemType, InteractionTrigger, ItemState } from '@cntrl-site/sdk';
1
+ import { ArticleItemType, InteractionItemTrigger, 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
+ getHasTrigger(itemId: string, triggerType: InteractionItemTrigger['type']): boolean;
6
6
  sendTrigger(type: 'click' | 'hover-in' | 'hover-out'): void;
7
7
  handleTransitionEnd?: (styleKey: string) => void;
8
8
  handleTransitionStart?: (styleKeys: string[]) => void;
@@ -14,8 +14,8 @@ export interface ItemInteractionCtrl {
14
14
  export interface InteractionsRegistryPort {
15
15
  register(itemId: string, ctrl: ItemInteractionCtrl): void;
16
16
  getStatePropsForItem(itemId: string): StateProps;
17
- getItemAvailableTriggers(itemId: string): Set<InteractionTrigger['type']>;
18
- notifyTrigger(itemId: string, type: TriggerType): void;
17
+ getItemAvailableTriggers(itemId: string): Set<InteractionItemTrigger['type']>;
18
+ notifyItemTrigger(itemId: string, type: TriggerType): void;
19
19
  notifyTransitionEnd(itemId: string): void;
20
20
  }
21
21
 
@@ -1,7 +1,8 @@
1
- import { createContext, FC, PropsWithChildren, useContext, useMemo } from 'react';
1
+ import { createContext, FC, PropsWithChildren, useContext, useEffect, useMemo } from 'react';
2
2
  import { InteractionsRegistry } from '../interactions/InteractionsRegistry';
3
3
  import { Article } from '@cntrl-site/sdk';
4
4
  import { useCurrentLayout } from '../common/useCurrentLayout';
5
+ import { ArticleRectContext } from './ArticleRectContext';
5
6
 
6
7
  export const InteractionsContext = createContext<InteractionsRegistry | undefined>(undefined);
7
8
 
@@ -11,10 +12,32 @@ interface Props {
11
12
 
12
13
  export const InteractionsProvider: FC<PropsWithChildren<Props>> = ({ article, children }) => {
13
14
  const { layoutId } = useCurrentLayout();
15
+ const articleRectObserver = useContext(ArticleRectContext);
14
16
  const registry = useMemo(() => {
15
17
  if (!layoutId) return;
16
18
  return new InteractionsRegistry(article, layoutId);
17
19
  }, [layoutId]);
20
+
21
+ useEffect(() => {
22
+ if (!registry || !articleRectObserver) return;
23
+ const handleScroll = () => {
24
+ const scrollY = window.scrollY;
25
+ registry.notifyScrollTrigger(scrollY);
26
+ };
27
+ return articleRectObserver.on('scroll', handleScroll);
28
+ }, [registry, articleRectObserver]);
29
+
30
+ useEffect(() => {
31
+ if (!registry) return;
32
+ registry.notifyLoad();
33
+
34
+ const handleLoad = () => {
35
+ registry.notifyLoad();
36
+ };
37
+ window.addEventListener('load', handleLoad);
38
+ return () => window.removeEventListener('load', handleLoad);
39
+ }, [registry]);
40
+
18
41
  return (
19
42
  <InteractionsContext.Provider value={registry}>
20
43
  {children}