@wix/site-service-interactions 1.0.7 → 1.0.9

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.
@@ -6,12 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createInteractionsScriptElement = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const interactionsScriptContent_1 = require("./interactionsScriptContent");
9
+ const reviveScriptElement_1 = require("./reviveScriptElement");
9
10
  const createInteractionsScriptElement = (config, isReducedMotion, pageId) => () => {
10
11
  const configId = `interactions-config-${pageId}`;
11
12
  const interactionsScriptContent = (0, interactionsScriptContent_1.getInteractionsScriptContent)(configId, isReducedMotion);
12
13
  return (react_1.default.createElement(react_1.default.Fragment, null,
13
14
  react_1.default.createElement("script", { type: "application/json", id: configId }, encodeURIComponent(JSON.stringify(config))),
14
- react_1.default.createElement("script", { type: "module", id: `interactions-loader-${pageId}` }, interactionsScriptContent)));
15
+ react_1.default.createElement("script", { type: "module", id: `interactions-loader-${pageId}`, ref: reviveScriptElement_1.reviveScriptElement }, interactionsScriptContent)));
15
16
  };
16
17
  exports.createInteractionsScriptElement = createInteractionsScriptElement;
17
18
  //# sourceMappingURL=InteractionsScriptElement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionsScriptElement.js","sourceRoot":"","sources":["../../../src/implementations/InteractionsScriptElement.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAGzB,2EAA0E;AAEnE,MAAM,+BAA+B,GACxC,CAAC,MAAsB,EAAE,eAAwB,EAAE,MAAc,EAAqB,EAAE,CACxF,GAAG,EAAE;IACD,MAAM,QAAQ,GAAG,uBAAuB,MAAM,EAAE,CAAA;IAChD,MAAM,yBAAyB,GAAG,IAAA,wDAA4B,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAEzF,OAAO,CACH;QACI,0CAAQ,IAAI,EAAC,kBAAkB,EAAC,EAAE,EAAE,QAAQ,IACvC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACtC;QACT,0CAAQ,IAAI,EAAC,QAAQ,EAAC,EAAE,EAAE,uBAAuB,MAAM,EAAE,IACpD,yBAAyB,CACrB,CACV,CACN,CAAA;AACL,CAAC,CAAA;AAhBQ,QAAA,+BAA+B,mCAgBvC"}
1
+ {"version":3,"file":"InteractionsScriptElement.js","sourceRoot":"","sources":["../../../src/implementations/InteractionsScriptElement.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAGzB,2EAA0E;AAC1E,+DAA2D;AAEpD,MAAM,+BAA+B,GACxC,CAAC,MAAsB,EAAE,eAAwB,EAAE,MAAc,EAAqB,EAAE,CACxF,GAAG,EAAE;IACD,MAAM,QAAQ,GAAG,uBAAuB,MAAM,EAAE,CAAA;IAChD,MAAM,yBAAyB,GAAG,IAAA,wDAA4B,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAEzF,OAAO,CACH;QACI,0CAAQ,IAAI,EAAC,kBAAkB,EAAC,EAAE,EAAE,QAAQ,IACvC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACtC;QAGT,0CAAQ,IAAI,EAAC,QAAQ,EAAC,EAAE,EAAE,uBAAuB,MAAM,EAAE,EAAE,GAAG,EAAE,yCAAmB,IAC9E,yBAAyB,CACrB,CACV,CACN,CAAA;AACL,CAAC,CAAA;AAlBQ,QAAA,+BAA+B,mCAkBvC"}
@@ -48,13 +48,13 @@ const coreInteractions = (config, getService) => {
48
48
  const { SSR } = getService(definition_3.RenderingContextDefinition);
49
49
  const isSSRExperimentOpen = isOpen('specs.thunderbolt.interactionsInSsr');
50
50
  if (isSSRExperimentOpen) {
51
- let didInitInteractInSsr = false;
52
- try {
53
- didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService);
54
- }
55
- catch (error) {
56
- console.warn('failed initializing Interact in SSR, falling back to client init:', error);
57
- }
51
+ // Emits the config and loader scripts. Works in both environments: SSR serves markup the
52
+ // parser executes, and on the client the loader's ref revives it into a script that runs —
53
+ // which is what pages rendered only on the client (password-protected / members-only,
54
+ // client-side navigation) need, since they never get a server-rendered document.
55
+ const didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService);
56
+ // Fall back to direct init on the client if the script element could not be set up
57
+ // (e.g. no pageId or no interactions).
58
58
  if (!didInitInteractInSsr && !SSR) {
59
59
  initInteract(config, isReducedMotion);
60
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"coreInteractions.js","sourceRoot":"","sources":["../../../src/implementations/coreInteractions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coreInteractions.js","sourceRoot":"","sources":["../../../src/implementations/coreInteractions.ts"],"names":[],"mappings":";;;AAAA,4CAAwC;AAExC,yEAA+E;AAC/E,yEAAgF;AAChF,+EAA2F;AAC3F,mEAAoE;AACpE,mGAA+G;AAE/G,2EAA6E;AAE7E,MAAM,YAAY,GAAG,CAAC,MAAsB,EAAE,eAAwB,EAAE,EAAE;IACtE,mBAAQ,CAAC,kBAAkB,GAAG,eAAe,CAAA;IAC7C,mBAAQ,CAAC,KAAK,CAAC;QACX,mBAAmB,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC;QAC1E,iBAAiB,EAAE,IAAI;QACvB,SAAS,EAAE;YACP,gBAAgB,EAAE,IAAI;SACzB;KACJ,CAAC,CAAA;IACF,mBAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC,CAAA;AAED,MAAM,oBAAoB,GAAG,CACzB,MAAsB,EACtB,eAAwB,EACxB,UAAyC,EAC3C,EAAE;IACA,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,CAAC,CAAA;IACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACnB,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,GAAG,UAAU,CAAC,4BAAe,CAAC,CAAA;IACnD,MAAM,MAAM,GAAG,WAAW,EAAE,EAAE,CAAA;IAE9B,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,KAAK,CAAA;IAChB,CAAC;IAED,MAAM,EAAE,eAAe,EAAE,GAAG,UAAU,CAAC,qDAAiC,CAAC,CAAA;IACzE,MAAM,gBAAgB,GAAG,IAAA,2DAA+B,EAAC,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,CAAA;IACzF,eAAe,CAAC,gBAAgB,CAAC,CAAA;IAEjC,OAAO,IAAI,CAAA;AACf,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAAC,YAA4C,EAAE,EAAE,CACzE,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE;IAC1C,mBAAmB;IACnB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACZ,qBAAqB;IACrB,sBAAsB;IACtB,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAI,CAAC,CAAC,CAAA;IAE3C,OAAO,GAAG,CAAA;AACd,CAAC,EAAE,IAAI,GAAG,EAAU,CAAC,CAAA;AAElB,MAAM,gBAAgB,GAAG,CAAC,MAAsB,EAAE,UAAyC,EAAE,EAAE;IAClG,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,UAAU,CAAC,iCAAoB,CAAC,CAAA;IAC3E,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,kCAAqB,CAAC,CAAA;IACpD,MAAM,EAAE,GAAG,EAAE,GAAG,UAAU,CAAC,uCAA0B,CAAC,CAAA;IAEtD,MAAM,mBAAmB,GAAG,MAAM,CAAC,qCAAqC,CAAC,CAAA;IACzE,IAAI,mBAAmB,EAAE,CAAC;QACtB,yFAAyF;QACzF,2FAA2F;QAC3F,sFAAsF;QACtF,iFAAiF;QACjF,MAAM,oBAAoB,GAAG,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,UAAU,CAAC,CAAA;QAEtF,mFAAmF;QACnF,uCAAuC;QACvC,IAAI,CAAC,oBAAoB,IAAI,CAAC,GAAG,EAAE,CAAC;YAChC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;QACzC,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACzC,CAAC;IAED,OAAO;QACH,gBAAgB,EAAE,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC;KAC7D,CAAA;AACL,CAAC,CAAA;AAzBY,QAAA,gBAAgB,oBAyB5B"}
@@ -4,25 +4,39 @@ exports.getInteractionsScriptContent = void 0;
4
4
  const getInteractionsScriptContent = (configId, isReducedMotion) => `
5
5
  await import(\`https://static.parastorage.com/services/interact/dist/interact.umd.min.js\`);
6
6
 
7
+ // Wix pages run an AMD loader (RequireJS) whose define wins the interact UMD wrapper, so the
8
+ // bundle registers itself as a named AMD module instead of assigning window.interact. Read the
9
+ // global first, and when it is absent pull the module back out of the AMD loader.
10
+ let interactModule = window.interact;
11
+ if (!interactModule?.Interact) {
12
+ if (typeof window.require === \`function\`) {
13
+ try {
14
+ interactModule = await new Promise(function (resolve, reject) {
15
+ window.require([\`interact\`], resolve, reject);
16
+ });
17
+ } catch (error) {
18
+ console.error(\`Failed loading Interact via the AMD loader\`, error);
19
+ }
20
+ }
21
+ }
22
+
23
+ const Interact = interactModule?.Interact;
7
24
  const configElement = document.getElementById(\`${configId}\`);
8
- if (configElement) {
9
- const Interact = window.interact?.Interact;
10
- if (!Interact) {
11
- console.error(\`Interact library is not loaded\`);
12
- } else {
13
- const config = JSON.parse(decodeURIComponent(configElement.textContent));
25
+ if (!Interact) {
26
+ console.error(\`Interact library is not loaded\`);
27
+ } else if (configElement) {
28
+ const config = JSON.parse(decodeURIComponent(configElement.textContent));
14
29
 
15
- Interact.forceReducedMotion = ${isReducedMotion};
16
- Interact.setup({
17
- scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
18
- allowA11yTriggers: true,
19
- viewEnter: {
20
- useSafeViewEnter: true,
21
- },
22
- });
30
+ Interact.forceReducedMotion = ${isReducedMotion};
31
+ Interact.setup({
32
+ scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
33
+ allowA11yTriggers: true,
34
+ viewEnter: {
35
+ useSafeViewEnter: true,
36
+ },
37
+ });
23
38
 
24
- Interact.create(config);
25
- }
39
+ Interact.create(config);
26
40
  }
27
41
  `;
28
42
  exports.getInteractionsScriptContent = getInteractionsScriptContent;
@@ -1 +1 @@
1
- {"version":3,"file":"interactionsScriptContent.js","sourceRoot":"","sources":["../../../src/implementations/interactionsScriptContent.ts"],"names":[],"mappings":";;;AAAO,MAAM,4BAA4B,GAAG,CAAC,QAAgB,EAAE,eAAwB,EAAE,EAAE,CAAC;;;sDAGtC,QAAQ;;;;;;;;4CAQlB,eAAe;;;;;;;;;;;;CAY1D,CAAA;AAvBY,QAAA,4BAA4B,gCAuBxC"}
1
+ {"version":3,"file":"interactionsScriptContent.js","sourceRoot":"","sources":["../../../src/implementations/interactionsScriptContent.ts"],"names":[],"mappings":";;;AAAO,MAAM,4BAA4B,GAAG,CAAC,QAAgB,EAAE,eAAwB,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;sDAoBtC,QAAQ;;;;;;wCAMtB,eAAe;;;;;;;;;;;CAWtD,CAAA;AArCY,QAAA,4BAA4B,gCAqCxC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Replaces a React-created <script> with an equivalent the browser will execute.
3
+ *
4
+ * React DOM creates every script through `div.innerHTML` — deliberately, so that scripts it renders
5
+ * on the client never run (see the `type === 'script'` branch of its `createElement`). That sets the
6
+ * HTML spec's "already started" flag, which is sticky: moving, re-inserting or re-connecting the
7
+ * element changes nothing, and the flag is even copied on `cloneNode`.
8
+ *
9
+ * An element from `document.createElement` has the flag clear and runs as soon as it is connected,
10
+ * so copying the source across is enough. Used as a ref, this runs only on the client — refs are
11
+ * never invoked during `renderToString` — while SSR keeps emitting markup the parser executes.
12
+ * One mechanism, no environment check.
13
+ *
14
+ * On a page that was server-rendered the parser has already run this source, so hydration reviving
15
+ * it runs it a second time. That create is inert: `interact-element` is defined, its elements are
16
+ * connected, and `connect()` returns early for them, so only the first instance serves a key.
17
+ */
18
+ export declare const reviveScriptElement: (rendered: HTMLScriptElement | null) => void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reviveScriptElement = void 0;
4
+ /**
5
+ * Replaces a React-created <script> with an equivalent the browser will execute.
6
+ *
7
+ * React DOM creates every script through `div.innerHTML` — deliberately, so that scripts it renders
8
+ * on the client never run (see the `type === 'script'` branch of its `createElement`). That sets the
9
+ * HTML spec's "already started" flag, which is sticky: moving, re-inserting or re-connecting the
10
+ * element changes nothing, and the flag is even copied on `cloneNode`.
11
+ *
12
+ * An element from `document.createElement` has the flag clear and runs as soon as it is connected,
13
+ * so copying the source across is enough. Used as a ref, this runs only on the client — refs are
14
+ * never invoked during `renderToString` — while SSR keeps emitting markup the parser executes.
15
+ * One mechanism, no environment check.
16
+ *
17
+ * On a page that was server-rendered the parser has already run this source, so hydration reviving
18
+ * it runs it a second time. That create is inert: `interact-element` is defined, its elements are
19
+ * connected, and `connect()` returns early for them, so only the first instance serves a key.
20
+ */
21
+ const reviveScriptElement = (rendered) => {
22
+ if (!rendered?.isConnected) {
23
+ return;
24
+ }
25
+ const executable = globalThis.document.createElement('script');
26
+ executable.type = rendered.type;
27
+ executable.id = rendered.id;
28
+ executable.textContent = rendered.textContent;
29
+ rendered.replaceWith(executable);
30
+ };
31
+ exports.reviveScriptElement = reviveScriptElement;
32
+ //# sourceMappingURL=reviveScriptElement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviveScriptElement.js","sourceRoot":"","sources":["../../../src/implementations/reviveScriptElement.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;GAgBG;AACI,MAAM,mBAAmB,GAAG,CAAC,QAAkC,EAAE,EAAE;IACtE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;QACzB,OAAM;IACV,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAC9D,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAA;IAC3B,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAA;IAE7C,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;AACpC,CAAC,CAAA;AAXY,QAAA,mBAAmB,uBAW/B"}
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
2
  import { getInteractionsScriptContent } from './interactionsScriptContent';
3
+ import { reviveScriptElement } from './reviveScriptElement';
3
4
  export const createInteractionsScriptElement = (config, isReducedMotion, pageId) => () => {
4
5
  const configId = `interactions-config-${pageId}`;
5
6
  const interactionsScriptContent = getInteractionsScriptContent(configId, isReducedMotion);
6
7
  return (React.createElement(React.Fragment, null,
7
8
  React.createElement("script", { type: "application/json", id: configId }, encodeURIComponent(JSON.stringify(config))),
8
- React.createElement("script", { type: "module", id: `interactions-loader-${pageId}` }, interactionsScriptContent)));
9
+ React.createElement("script", { type: "module", id: `interactions-loader-${pageId}`, ref: reviveScriptElement }, interactionsScriptContent)));
9
10
  };
10
11
  //# sourceMappingURL=InteractionsScriptElement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionsScriptElement.js","sourceRoot":"","sources":["../../src/implementations/InteractionsScriptElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAE1E,MAAM,CAAC,MAAM,+BAA+B,GACxC,CAAC,MAAsB,EAAE,eAAwB,EAAE,MAAc,EAAqB,EAAE,CACxF,GAAG,EAAE;IACD,MAAM,QAAQ,GAAG,uBAAuB,MAAM,EAAE,CAAA;IAChD,MAAM,yBAAyB,GAAG,4BAA4B,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAEzF,OAAO,CACH;QACI,gCAAQ,IAAI,EAAC,kBAAkB,EAAC,EAAE,EAAE,QAAQ,IACvC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACtC;QACT,gCAAQ,IAAI,EAAC,QAAQ,EAAC,EAAE,EAAE,uBAAuB,MAAM,EAAE,IACpD,yBAAyB,CACrB,CACV,CACN,CAAA;AACL,CAAC,CAAA"}
1
+ {"version":3,"file":"InteractionsScriptElement.js","sourceRoot":"","sources":["../../src/implementations/InteractionsScriptElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3D,MAAM,CAAC,MAAM,+BAA+B,GACxC,CAAC,MAAsB,EAAE,eAAwB,EAAE,MAAc,EAAqB,EAAE,CACxF,GAAG,EAAE;IACD,MAAM,QAAQ,GAAG,uBAAuB,MAAM,EAAE,CAAA;IAChD,MAAM,yBAAyB,GAAG,4BAA4B,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAEzF,OAAO,CACH;QACI,gCAAQ,IAAI,EAAC,kBAAkB,EAAC,EAAE,EAAE,QAAQ,IACvC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACtC;QAGT,gCAAQ,IAAI,EAAC,QAAQ,EAAC,EAAE,EAAE,uBAAuB,MAAM,EAAE,EAAE,GAAG,EAAE,mBAAmB,IAC9E,yBAAyB,CACrB,CACV,CACN,CAAA;AACL,CAAC,CAAA"}
@@ -45,13 +45,13 @@ export const coreInteractions = (config, getService) => {
45
45
  const { SSR } = getService(RenderingContextDefinition);
46
46
  const isSSRExperimentOpen = isOpen('specs.thunderbolt.interactionsInSsr');
47
47
  if (isSSRExperimentOpen) {
48
- let didInitInteractInSsr = false;
49
- try {
50
- didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService);
51
- }
52
- catch (error) {
53
- console.warn('failed initializing Interact in SSR, falling back to client init:', error);
54
- }
48
+ // Emits the config and loader scripts. Works in both environments: SSR serves markup the
49
+ // parser executes, and on the client the loader's ref revives it into a script that runs —
50
+ // which is what pages rendered only on the client (password-protected / members-only,
51
+ // client-side navigation) need, since they never get a server-rendered document.
52
+ const didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService);
53
+ // Fall back to direct init on the client if the script element could not be set up
54
+ // (e.g. no pageId or no interactions).
55
55
  if (!didInitInteractInSsr && !SSR) {
56
56
  initInteract(config, isReducedMotion);
57
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"coreInteractions.js","sourceRoot":"","sources":["../../src/implementations/coreInteractions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coreInteractions.js","sourceRoot":"","sources":["../../src/implementations/coreInteractions.ts"],"names":[],"mappings":"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"}
@@ -1,25 +1,39 @@
1
1
  export const getInteractionsScriptContent = (configId, isReducedMotion) => `
2
2
  await import(\`https://static.parastorage.com/services/interact/dist/interact.umd.min.js\`);
3
3
 
4
+ // Wix pages run an AMD loader (RequireJS) whose define wins the interact UMD wrapper, so the
5
+ // bundle registers itself as a named AMD module instead of assigning window.interact. Read the
6
+ // global first, and when it is absent pull the module back out of the AMD loader.
7
+ let interactModule = window.interact;
8
+ if (!interactModule?.Interact) {
9
+ if (typeof window.require === \`function\`) {
10
+ try {
11
+ interactModule = await new Promise(function (resolve, reject) {
12
+ window.require([\`interact\`], resolve, reject);
13
+ });
14
+ } catch (error) {
15
+ console.error(\`Failed loading Interact via the AMD loader\`, error);
16
+ }
17
+ }
18
+ }
19
+
20
+ const Interact = interactModule?.Interact;
4
21
  const configElement = document.getElementById(\`${configId}\`);
5
- if (configElement) {
6
- const Interact = window.interact?.Interact;
7
- if (!Interact) {
8
- console.error(\`Interact library is not loaded\`);
9
- } else {
10
- const config = JSON.parse(decodeURIComponent(configElement.textContent));
22
+ if (!Interact) {
23
+ console.error(\`Interact library is not loaded\`);
24
+ } else if (configElement) {
25
+ const config = JSON.parse(decodeURIComponent(configElement.textContent));
11
26
 
12
- Interact.forceReducedMotion = ${isReducedMotion};
13
- Interact.setup({
14
- scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
15
- allowA11yTriggers: true,
16
- viewEnter: {
17
- useSafeViewEnter: true,
18
- },
19
- });
27
+ Interact.forceReducedMotion = ${isReducedMotion};
28
+ Interact.setup({
29
+ scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
30
+ allowA11yTriggers: true,
31
+ viewEnter: {
32
+ useSafeViewEnter: true,
33
+ },
34
+ });
20
35
 
21
- Interact.create(config);
22
- }
36
+ Interact.create(config);
23
37
  }
24
38
  `;
25
39
  //# sourceMappingURL=interactionsScriptContent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactionsScriptContent.js","sourceRoot":"","sources":["../../src/implementations/interactionsScriptContent.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,QAAgB,EAAE,eAAwB,EAAE,EAAE,CAAC;;;sDAGtC,QAAQ;;;;;;;;4CAQlB,eAAe;;;;;;;;;;;;CAY1D,CAAA"}
1
+ {"version":3,"file":"interactionsScriptContent.js","sourceRoot":"","sources":["../../src/implementations/interactionsScriptContent.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,QAAgB,EAAE,eAAwB,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;sDAoBtC,QAAQ;;;;;;wCAMtB,eAAe;;;;;;;;;;;CAWtD,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Replaces a React-created <script> with an equivalent the browser will execute.
3
+ *
4
+ * React DOM creates every script through `div.innerHTML` — deliberately, so that scripts it renders
5
+ * on the client never run (see the `type === 'script'` branch of its `createElement`). That sets the
6
+ * HTML spec's "already started" flag, which is sticky: moving, re-inserting or re-connecting the
7
+ * element changes nothing, and the flag is even copied on `cloneNode`.
8
+ *
9
+ * An element from `document.createElement` has the flag clear and runs as soon as it is connected,
10
+ * so copying the source across is enough. Used as a ref, this runs only on the client — refs are
11
+ * never invoked during `renderToString` — while SSR keeps emitting markup the parser executes.
12
+ * One mechanism, no environment check.
13
+ *
14
+ * On a page that was server-rendered the parser has already run this source, so hydration reviving
15
+ * it runs it a second time. That create is inert: `interact-element` is defined, its elements are
16
+ * connected, and `connect()` returns early for them, so only the first instance serves a key.
17
+ */
18
+ export declare const reviveScriptElement: (rendered: HTMLScriptElement | null) => void;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Replaces a React-created <script> with an equivalent the browser will execute.
3
+ *
4
+ * React DOM creates every script through `div.innerHTML` — deliberately, so that scripts it renders
5
+ * on the client never run (see the `type === 'script'` branch of its `createElement`). That sets the
6
+ * HTML spec's "already started" flag, which is sticky: moving, re-inserting or re-connecting the
7
+ * element changes nothing, and the flag is even copied on `cloneNode`.
8
+ *
9
+ * An element from `document.createElement` has the flag clear and runs as soon as it is connected,
10
+ * so copying the source across is enough. Used as a ref, this runs only on the client — refs are
11
+ * never invoked during `renderToString` — while SSR keeps emitting markup the parser executes.
12
+ * One mechanism, no environment check.
13
+ *
14
+ * On a page that was server-rendered the parser has already run this source, so hydration reviving
15
+ * it runs it a second time. That create is inert: `interact-element` is defined, its elements are
16
+ * connected, and `connect()` returns early for them, so only the first instance serves a key.
17
+ */
18
+ export const reviveScriptElement = (rendered) => {
19
+ if (!rendered?.isConnected) {
20
+ return;
21
+ }
22
+ const executable = globalThis.document.createElement('script');
23
+ executable.type = rendered.type;
24
+ executable.id = rendered.id;
25
+ executable.textContent = rendered.textContent;
26
+ rendered.replaceWith(executable);
27
+ };
28
+ //# sourceMappingURL=reviveScriptElement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviveScriptElement.js","sourceRoot":"","sources":["../../src/implementations/reviveScriptElement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAkC,EAAE,EAAE;IACtE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;QACzB,OAAM;IACV,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAC9D,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAA;IAC3B,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAA;IAE7C,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;AACpC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/site-service-interactions",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "main": "cjs/build/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -90,5 +90,5 @@
90
90
  ]
91
91
  }
92
92
  },
93
- "falconPackageHash": "a05b213a75034a399556f8e0fcaab4a027182245d76e1541432d184e"
93
+ "falconPackageHash": "629f3f89a2fc1e079366d274ab06644e0a74eba7c695c37d6f234e61"
94
94
  }
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import type { FunctionComponent } from 'react'
3
3
  import type { InteractConfig } from '@wix/interact'
4
4
  import { getInteractionsScriptContent } from './interactionsScriptContent'
5
+ import { reviveScriptElement } from './reviveScriptElement'
5
6
 
6
7
  export const createInteractionsScriptElement =
7
8
  (config: InteractConfig, isReducedMotion: boolean, pageId: string): FunctionComponent =>
@@ -14,7 +15,9 @@ export const createInteractionsScriptElement =
14
15
  <script type="application/json" id={configId}>
15
16
  {encodeURIComponent(JSON.stringify(config))}
16
17
  </script>
17
- <script type="module" id={`interactions-loader-${pageId}`}>
18
+ {/* In SSR the parser creates this and runs it. On the client React creates a script
19
+ that can never execute, so the ref swaps in one that can. */}
20
+ <script type="module" id={`interactions-loader-${pageId}`} ref={reviveScriptElement}>
18
21
  {interactionsScriptContent}
19
22
  </script>
20
23
  </>
@@ -62,14 +62,14 @@ export const coreInteractions = (config: InteractConfig, getService: ServicesMan
62
62
 
63
63
  const isSSRExperimentOpen = isOpen('specs.thunderbolt.interactionsInSsr')
64
64
  if (isSSRExperimentOpen) {
65
- let didInitInteractInSsr = false
66
-
67
- try {
68
- didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService)
69
- } catch (error) {
70
- console.warn('failed initializing Interact in SSR, falling back to client init:', error)
71
- }
65
+ // Emits the config and loader scripts. Works in both environments: SSR serves markup the
66
+ // parser executes, and on the client the loader's ref revives it into a script that runs —
67
+ // which is what pages rendered only on the client (password-protected / members-only,
68
+ // client-side navigation) need, since they never get a server-rendered document.
69
+ const didInitInteractInSsr = tryInitInteractInSsr(config, isReducedMotion, getService)
72
70
 
71
+ // Fall back to direct init on the client if the script element could not be set up
72
+ // (e.g. no pageId or no interactions).
73
73
  if (!didInitInteractInSsr && !SSR) {
74
74
  initInteract(config, isReducedMotion)
75
75
  }
@@ -1,24 +1,38 @@
1
1
  export const getInteractionsScriptContent = (configId: string, isReducedMotion: boolean) => `
2
2
  await import(\`https://static.parastorage.com/services/interact/dist/interact.umd.min.js\`);
3
3
 
4
+ // Wix pages run an AMD loader (RequireJS) whose define wins the interact UMD wrapper, so the
5
+ // bundle registers itself as a named AMD module instead of assigning window.interact. Read the
6
+ // global first, and when it is absent pull the module back out of the AMD loader.
7
+ let interactModule = window.interact;
8
+ if (!interactModule?.Interact) {
9
+ if (typeof window.require === \`function\`) {
10
+ try {
11
+ interactModule = await new Promise(function (resolve, reject) {
12
+ window.require([\`interact\`], resolve, reject);
13
+ });
14
+ } catch (error) {
15
+ console.error(\`Failed loading Interact via the AMD loader\`, error);
16
+ }
17
+ }
18
+ }
19
+
20
+ const Interact = interactModule?.Interact;
4
21
  const configElement = document.getElementById(\`${configId}\`);
5
- if (configElement) {
6
- const Interact = window.interact?.Interact;
7
- if (!Interact) {
8
- console.error(\`Interact library is not loaded\`);
9
- } else {
10
- const config = JSON.parse(decodeURIComponent(configElement.textContent));
22
+ if (!Interact) {
23
+ console.error(\`Interact library is not loaded\`);
24
+ } else if (configElement) {
25
+ const config = JSON.parse(decodeURIComponent(configElement.textContent));
11
26
 
12
- Interact.forceReducedMotion = ${isReducedMotion};
13
- Interact.setup({
14
- scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
15
- allowA11yTriggers: true,
16
- viewEnter: {
17
- useSafeViewEnter: true,
18
- },
19
- });
27
+ Interact.forceReducedMotion = ${isReducedMotion};
28
+ Interact.setup({
29
+ scrollOptionsGetter: function(){ return document.getElementById(\`site-root\`) },
30
+ allowA11yTriggers: true,
31
+ viewEnter: {
32
+ useSafeViewEnter: true,
33
+ },
34
+ });
20
35
 
21
- Interact.create(config);
22
- }
36
+ Interact.create(config);
23
37
  }
24
38
  `
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Replaces a React-created <script> with an equivalent the browser will execute.
3
+ *
4
+ * React DOM creates every script through `div.innerHTML` — deliberately, so that scripts it renders
5
+ * on the client never run (see the `type === 'script'` branch of its `createElement`). That sets the
6
+ * HTML spec's "already started" flag, which is sticky: moving, re-inserting or re-connecting the
7
+ * element changes nothing, and the flag is even copied on `cloneNode`.
8
+ *
9
+ * An element from `document.createElement` has the flag clear and runs as soon as it is connected,
10
+ * so copying the source across is enough. Used as a ref, this runs only on the client — refs are
11
+ * never invoked during `renderToString` — while SSR keeps emitting markup the parser executes.
12
+ * One mechanism, no environment check.
13
+ *
14
+ * On a page that was server-rendered the parser has already run this source, so hydration reviving
15
+ * it runs it a second time. That create is inert: `interact-element` is defined, its elements are
16
+ * connected, and `connect()` returns early for them, so only the first instance serves a key.
17
+ */
18
+ export const reviveScriptElement = (rendered: HTMLScriptElement | null) => {
19
+ if (!rendered?.isConnected) {
20
+ return
21
+ }
22
+
23
+ const executable = globalThis.document.createElement('script')
24
+ executable.type = rendered.type
25
+ executable.id = rendered.id
26
+ executable.textContent = rendered.textContent
27
+
28
+ rendered.replaceWith(executable)
29
+ }