@livepreso/content-react 1.0.1 → 1.1.0

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.
@@ -19,8 +19,8 @@
19
19
  "content/content-react/lib/hooks/use-shared-state.js": "0d160ddf3e5dec37849f72f4ec2a1d7aac680159",
20
20
  "content/content-react/lib/hooks/use-subslides.js": "508ac21b01a4ece811ebc2db9c6a41ef6071e326",
21
21
  "content/content-react/lib/hooks/use-transitions.js": "c9cdf3e8af82b8f8a51e99ee670334cc5c7c42c1",
22
- "content/content-react/package.json": "1bed2af8c66bfa4ad2540e0e001cea26109435eb",
23
- "content/content-react/.rush/temp/shrinkwrap-deps.json": "b1ad1f22903e0092d2fa7647b96a86692d3accaf"
22
+ "content/content-react/package.json": "829ec6db57241917d8f143d522ff22d62d4dbcc0",
23
+ "content/content-react/.rush/temp/shrinkwrap-deps.json": "597fd3e1925904d69b27c3bc319a49733033c2b1"
24
24
  },
25
25
  "arguments": ""
26
26
  }
@@ -61,7 +61,7 @@
61
61
  "/concat-map@0.0.1": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
62
62
  "/convert-source-map@2.0.0": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
63
63
  "/cross-spawn@7.0.6": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
64
- "/debug@4.3.7(supports-color@5.5.0)": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
64
+ "/debug@4.3.7(supports-color@8.1.1)": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
65
65
  "/deep-is@0.1.4": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
66
66
  "/electron-to-chromium@1.5.65": "sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==",
67
67
  "/escalade@3.2.0": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
@@ -86,7 +86,6 @@
86
86
  "/glob-parent@6.0.2": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
87
87
  "/globals@11.12.0": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
88
88
  "/globals@14.0.0": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
89
- "/has-flag@3.0.0": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
90
89
  "/has-flag@4.0.0": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
91
90
  "/ignore@5.3.2": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
92
91
  "/import-fresh@3.3.0": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
@@ -134,8 +133,8 @@
134
133
  "/shebang-command@2.0.0": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
135
134
  "/shebang-regex@3.0.0": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
136
135
  "/strip-json-comments@3.1.1": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
137
- "/supports-color@5.5.0": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
138
136
  "/supports-color@7.2.0": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
137
+ "/supports-color@8.1.1": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
139
138
  "/type-check@0.4.0": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
140
139
  "/ulog@2.0.0-beta.19": "sha512-27YIp4dUwaJQTh7ovk60wWjBMVV/AXMZhSVftkU7HMjaPc1t8wO5u6hVVUyBTyGKrLxYmR0v34Iihq8mE26LUg==",
141
140
  "/update-browserslist-db@1.1.1(browserslist@4.24.2)": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
package/CHANGELOG.json CHANGED
@@ -1,6 +1,38 @@
1
1
  {
2
2
  "name": "@livepreso/content-react",
3
3
  "entries": [
4
+ {
5
+ "version": "1.1.0",
6
+ "tag": "@livepreso/content-react_v1.1.0",
7
+ "date": "Tue, 08 Jul 2025 01:48:30 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Add support for getting/setting cmsvals (and user templates)"
12
+ }
13
+ ],
14
+ "patch": [
15
+ {
16
+ "comment": "User templates temp key correctly regexed"
17
+ },
18
+ {
19
+ "comment": "useSlideContext always updates state on context change"
20
+ }
21
+ ]
22
+ }
23
+ },
24
+ {
25
+ "version": "1.0.2",
26
+ "tag": "@livepreso/content-react_v1.0.2",
27
+ "date": "Wed, 25 Jun 2025 23:57:00 GMT",
28
+ "comments": {
29
+ "patch": [
30
+ {
31
+ "comment": "Deal with alphanumeric ids for temp keys"
32
+ }
33
+ ]
34
+ }
35
+ },
4
36
  {
5
37
  "version": "1.0.1",
6
38
  "tag": "@livepreso/content-react_v1.0.1",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # Change Log - @livepreso/content-react
2
2
 
3
- This log was last generated on Thu, 12 Jun 2025 03:07:46 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 08 Jul 2025 01:48:30 GMT and should not be manually modified.
4
+
5
+ ## 1.1.0
6
+ Tue, 08 Jul 2025 01:48:30 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Add support for getting/setting cmsvals (and user templates)
11
+
12
+ ### Patches
13
+
14
+ - User templates temp key correctly regexed
15
+ - useSlideContext always updates state on context change
16
+
17
+ ## 1.0.2
18
+ Wed, 25 Jun 2025 23:57:00 GMT
19
+
20
+ ### Patches
21
+
22
+ - Deal with alphanumeric ids for temp keys
4
23
 
5
24
  ## 1.0.1
6
25
  Thu, 12 Jun 2025 03:07:46 GMT
@@ -0,0 +1,4 @@
1
+ Config file "/Users/laurenrui/Development/livepreso/content/content-react/config/rush-project.json" does not exist. Attempting to load via rig.
2
+
3
+ No rig found for "/Users/laurenrui/Development/livepreso/content/content-react"
4
+
package/eslint.config.mjs CHANGED
@@ -8,5 +8,8 @@ export default [
8
8
  Bridge: true,
9
9
  },
10
10
  },
11
+ rules: {
12
+ "no-console": "off",
13
+ },
11
14
  },
12
15
  ];
package/index.js CHANGED
@@ -57,30 +57,29 @@ export class App extends AppBase {
57
57
 
58
58
  defaultRenderer(Slide, article) {
59
59
  const el = article.get(0);
60
+ const id = el.id;
60
61
 
61
- if (window.__deck_roots__[el.id]) {
62
- this.unmountRoot(el.id);
62
+ if (window.__deck_roots__[id]) {
63
+ this.unmountRoot(id);
63
64
  }
64
65
 
65
66
  const root = createRoot(el);
66
67
 
67
- window.__deck_roots__[el.id] = root;
68
+ window.__deck_roots__[id] = root;
69
+
70
+ function slideClosed() {
71
+ root.unmount();
72
+ delete window.__deck_roots__[id];
73
+ article.off("slide:closed", slideClosed);
74
+ }
75
+
76
+ article.on("slide:closed", slideClosed);
68
77
 
69
78
  const RootApp = this.rootApp(Slide);
70
79
  const AppComponent = () => {
71
80
  // TODO: Refactor this to be a prop
72
81
  const slideState = useRootSlide(article);
73
82
 
74
- useEffect(() => {
75
- function slideClosed() {
76
- root.unmount();
77
- delete window.__deck_roots__[el.id];
78
- article.off("slide:closed", slideClosed);
79
- }
80
-
81
- article.on("slide:closed", slideClosed);
82
- }, []);
83
-
84
83
  return (
85
84
  <SlideContext.Provider value={slideState}>
86
85
  {!slideState.transitions.exited && (
@@ -4,7 +4,7 @@ import { CompanywideJSONContext } from "../contexts.js";
4
4
  import set from "lodash.set";
5
5
  import unescape from "lodash.unescape";
6
6
  import { useEditableInitialState } from "../hooks/use-editable-initial-state.js";
7
- import { useSlide } from "../hooks/use-slide.js";
7
+ import { useSlide } from "../hooks/slide.js";
8
8
  import { getCWEJSONKey, testCWEJSONExists } from "../utils.js";
9
9
 
10
10
  /**
@@ -0,0 +1,10 @@
1
+ import { useTransitions } from "../hooks";
2
+ import { createPortal } from "react-dom";
3
+
4
+ export function OverlayPortal({ children }) {
5
+ const { entered, exiting, exited } = useTransitions();
6
+ if ((!entered && !exiting) || exited) {
7
+ return;
8
+ }
9
+ return createPortal(children, window.Bridge.UI.overlay);
10
+ }
@@ -2,3 +2,4 @@ export * from "./Subslide.js";
2
2
  export * from "./Subslides.js";
3
3
  export * from "./ScrollableArea.js";
4
4
  export * from "./CompanywideJSON.js";
5
+ export * from "./OverlayPortal.js";
package/lib/contexts.js CHANGED
@@ -6,6 +6,7 @@ export const SlideContext = React.createContext({
6
6
  slideKey: null,
7
7
  isCurrentSlide: false,
8
8
  isUserTemplate: false,
9
+ isUserTemplateLibrary: false,
9
10
  isPMTemplate: false,
10
11
  });
11
12
 
@@ -0,0 +1,126 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useTransitions } from "./use-transitions";
3
+ import { useSlideContext } from "./use-slide-context.js";
4
+ import { useSlide, useSlideModel } from "./slide.js";
5
+ import { useModes } from "./use-modes.js";
6
+
7
+ function useUserTemplateCMS(name) {
8
+ const { slideID, presentationKey, isUserTemplate, isUserTemplateLibrary } =
9
+ useSlide();
10
+
11
+ let contextKey;
12
+
13
+ if (isUserTemplate) {
14
+ contextKey = `_userTemplateCMSvals.${slideID}--${name}-${presentationKey}`;
15
+ } else if (isUserTemplateLibrary) {
16
+ contextKey = `_userTemplateCMSvals.${presentationKey}--${name}`;
17
+ }
18
+
19
+ const [obj, setValue] = useSlideContext(
20
+ contextKey,
21
+ { mime: "text/plain", value: null },
22
+ { enabled: !!contextKey },
23
+ );
24
+
25
+ return [
26
+ obj?.value ?? null,
27
+ contextKey
28
+ ? (value) => setValue({ value, mime: "text/plain" })
29
+ : () => {
30
+ console.warn("Not a user template, can't set value");
31
+ },
32
+ ];
33
+ }
34
+
35
+ function useDefaultCMSValueFromPresomanager(name, { slidePath = null } = {}) {
36
+ const { isPresomanager } = useModes();
37
+ const model = useSlideModel({ slidePath });
38
+
39
+ let key;
40
+ if (model.autoAdjunctID) {
41
+ key = `${name}-autoadjunct-${model.autoAdjunctID}`;
42
+ } else {
43
+ key = name;
44
+ }
45
+
46
+ const [cmsVals] = useSlideContext(
47
+ "_cmsVals",
48
+ { mime: "text/plain", value: null },
49
+ // TODO: Presets? Previews?
50
+ { enabled: !isPresomanager },
51
+ );
52
+
53
+ return cmsVals?.find?.((c) => c.key === key)?.value ?? null;
54
+ }
55
+
56
+ export function useCMSVal(name, { enabled = true, slidePath = null } = {}) {
57
+ const { entered, entering } = useTransitions();
58
+ const { isPresomanager } = useModes();
59
+ const { isUserTemplate, isUserTemplateLibrary } = useSlide();
60
+ const [userTemplateValue, setUserTemplateValue] = useUserTemplateCMS(name);
61
+ const defaultFromPM = useDefaultCMSValueFromPresomanager(name, { slidePath });
62
+
63
+ // We need to make sure we aren't trying to call this bridge command
64
+ // (which can be specific to this slide) while it's being removed,
65
+ // otherwise we might throw warnings about missing cmsval keys.
66
+ const isActiveSlide = entered || entering;
67
+
68
+ const getCmsVal = useCallback(() => {
69
+ if (!enabled || !name || !isActiveSlide) {
70
+ return undefined;
71
+ }
72
+
73
+ if (isUserTemplate || isUserTemplateLibrary) {
74
+ return userTemplateValue;
75
+ }
76
+
77
+ if (!isPresomanager) {
78
+ return defaultFromPM;
79
+ }
80
+
81
+ return Bridge.CMSVals.get(name, { slidePath });
82
+ }, [
83
+ enabled,
84
+ name,
85
+ defaultFromPM,
86
+ isUserTemplate,
87
+ isUserTemplateLibrary,
88
+ isActiveSlide,
89
+ isPresomanager,
90
+ ]);
91
+
92
+ const [value, setCMSValue] = useState(getCmsVal());
93
+
94
+ function updateCMSVal(value) {
95
+ if (isUserTemplate) {
96
+ setUserTemplateValue(value);
97
+ } else {
98
+ Bridge.CMSVals.set(name, value, { slidePath });
99
+ }
100
+ setCMSValue(value);
101
+ }
102
+
103
+ useEffect(() => {
104
+ if (!enabled || !isActiveSlide) {
105
+ return;
106
+ }
107
+
108
+ function onCMSValChanged(key, newValue) {
109
+ const fullKey = Bridge.CMSVals.getFullKey(name, { slidePath });
110
+
111
+ if (key !== fullKey) {
112
+ return;
113
+ }
114
+
115
+ setCMSValue(newValue);
116
+ }
117
+
118
+ Bridge.presenter.getPresentation().on("cmsValChanged", onCMSValChanged);
119
+
120
+ return () => {
121
+ Bridge.presenter.getPresentation().off("cmsValChanged", onCMSValChanged);
122
+ };
123
+ }, [enabled, name, getCmsVal]);
124
+
125
+ return [value, updateCMSVal];
126
+ }
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useState } from "react";
2
2
 
3
3
  import { useModes } from "./use-modes";
4
- import { useSlide } from "./use-slide";
4
+ import { useSlide } from "./slide";
5
5
  import { useEditableFieldKey } from "./use-editable-field-key";
6
6
  import { getCWEData, getUserTemplateData } from "../utils";
7
7
 
@@ -41,11 +41,6 @@ export function useCWEEditableInfo(id) {
41
41
 
42
42
  function updateValue() {
43
43
  const newValue = getValue();
44
-
45
- if (value === newValue) {
46
- return;
47
- }
48
-
49
44
  setValue(newValue);
50
45
  }
51
46
 
@@ -4,11 +4,16 @@ export { useAsyncReference } from "./use-async-reference.js";
4
4
  export { useModes } from "./use-modes.js";
5
5
  export { useSlideContext } from "./use-slide-context.js";
6
6
  export { useCompanywide } from "./use-companywide.js";
7
- export { useSlide } from "./use-slide.js";
7
+ export { useSlideModel, useSlide } from "./slide.js";
8
8
  export { useTransitions } from "./use-transitions.js";
9
9
  export { useSubslides } from "./use-subslides.js";
10
10
  export { useSlideDone } from "./use-slide-done.js";
11
11
  export { useEditableFieldKey } from "./use-editable-field-key.js";
12
12
  export { useEditableInitialState } from "./use-editable-initial-state.js";
13
- export { usePrepEditableInfo, usePrepEditableValue } from "./prep-editable.js";
13
+ export {
14
+ usePrepEditable,
15
+ usePrepEditableInfo,
16
+ usePrepEditableValue,
17
+ } from "./prep-editable.js";
14
18
  export { useCWEEditableInfo, useCWEEditableValue } from "./cwe-editable.js";
19
+ export { useCMSVal } from "./cmsvals.js";
@@ -1,9 +1,37 @@
1
- import { useCallback, useEffect, useState } from "react";
2
-
3
1
  import { useModes } from "./use-modes";
4
- import { useSlide } from "./use-slide";
2
+ import { useSlide } from "./slide";
3
+ import { useSlideContext } from "./use-slide-context";
5
4
  import { useEditableFieldKey } from "./use-editable-field-key";
6
5
 
6
+ /**
7
+ * Get and set values for use by templates, in a way that it will magically
8
+ * work with user templates especially. Values get placed in a special part
9
+ * of the context to allow the user template magic to work, and this is the
10
+ * function to use to make that seamless.
11
+ */
12
+ export function usePrepEditable(editableKey) {
13
+ const { isPresomanager } = useModes();
14
+ const { slideID, isUserTemplateLibrary } = useSlide();
15
+
16
+ const key = useEditableFieldKey(editableKey, { isPrep: true });
17
+
18
+ const prepKey = `${slideID}--${key}`;
19
+ const keyPath = `_editableContent.${prepKey}`;
20
+
21
+ const [obj, setObj] = useSlideContext(
22
+ keyPath,
23
+ {
24
+ mime: "text/plain",
25
+ value: null,
26
+ },
27
+ {
28
+ enabled: !isPresomanager || isUserTemplateLibrary,
29
+ },
30
+ );
31
+
32
+ return [obj?.value ?? null, (value) => setObj({ mime: "text/plain", value })];
33
+ }
34
+
7
35
  /**
8
36
  * Returns information about a prep editable on the current slide.
9
37
  *
@@ -12,7 +40,7 @@ import { useEditableFieldKey } from "./use-editable-field-key";
12
40
  *
13
41
  * Example:
14
42
  *
15
- * usePrepEditable("test");
43
+ * usePrepEditableInfo("test");
16
44
  * => {
17
45
  * key: "test",
18
46
  * value: "User edited text",
@@ -20,49 +48,13 @@ import { useEditableFieldKey } from "./use-editable-field-key";
20
48
  * }
21
49
  */
22
50
  export function usePrepEditableInfo(id) {
23
- const { isPresomanager } = useModes();
24
- const { slideID } = useSlide();
25
-
26
51
  const key = useEditableFieldKey(id, { isPrep: true });
27
-
28
- const prepKey = `${slideID}--${key}`;
29
- const keyPath = `_editableContent.${prepKey}.value`;
30
-
31
- const getValue = useCallback(() => {
32
- return Bridge.Context.get(keyPath, null);
33
- }, [keyPath]);
34
-
35
- const [value, setValue] = useState(getValue());
36
-
37
- function updateValue() {
38
- const newValue = getValue();
39
-
40
- if (value === newValue) {
41
- return;
42
- }
43
-
44
- setValue(newValue);
45
- }
46
-
47
- useEffect(() => {
48
- if (isPresomanager) return;
49
-
50
- function onContextChange() {
51
- updateValue();
52
- }
53
-
54
- Bridge.presenter.getPresentation().on("change:context", onContextChange);
55
-
56
- return () => {
57
- Bridge.presenter.getPresentation().off("change:context", onContextChange);
58
- };
59
- }, [isPresomanager, value, getValue]);
52
+ const [value] = usePrepEditable(id);
60
53
 
61
54
  return {
62
55
  key,
63
56
  value: value,
64
57
  hasValue: value !== null,
65
- updateValue,
66
58
  };
67
59
  }
68
60
 
@@ -70,5 +62,6 @@ export function usePrepEditableInfo(id) {
70
62
  * Returns the current value of a prep editable on the current slide.
71
63
  */
72
64
  export function usePrepEditableValue(id, defaultValue = null) {
73
- return usePrepEditableInfo(id).value ?? defaultValue;
65
+ const [value] = usePrepEditable(id);
66
+ return value ?? defaultValue;
74
67
  }
@@ -1,3 +1,4 @@
1
+ import { useMemo } from "react";
1
2
  import { SlideContext } from "../contexts.js";
2
3
  import { useContext } from "react";
3
4
 
@@ -13,6 +14,7 @@ export function useSlide() {
13
14
  currentSubslide,
14
15
  transitions,
15
16
  isUserTemplate,
17
+ isUserTemplateLibrary,
16
18
  isPMTemplate,
17
19
  } = useContext(SlideContext);
18
20
 
@@ -27,6 +29,19 @@ export function useSlide() {
27
29
  totalSubslides,
28
30
  transitions,
29
31
  isUserTemplate,
32
+ isUserTemplateLibrary,
30
33
  isPMTemplate,
31
34
  };
32
35
  }
36
+
37
+ export function useSlideModel({ slidePath = null } = {}) {
38
+ const { slideID } = useSlide();
39
+
40
+ return useMemo(() => {
41
+ const presentation = Bridge.presenter.getPresentation();
42
+ if (slidePath) {
43
+ return presentation.search(slidePath);
44
+ }
45
+ return presentation.current;
46
+ }, [slidePath, slideID]);
47
+ }
@@ -1,4 +1,4 @@
1
- import { useSlide } from "./use-slide.js";
1
+ import { useSlide } from "./slide.js";
2
2
  import { getPMTemplateFieldKey, getUserTemplateFieldKey } from "../utils.js";
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { useSlide } from "./use-slide.js";
1
+ import { useSlide } from "./slide.js";
2
2
  import { useEditableFieldKey } from "./use-editable-field-key.js";
3
3
  import { getCWEData, getUserTemplateData } from "../utils.js";
4
4
 
@@ -12,10 +12,11 @@ export function useModes() {
12
12
  const isPreview = bodyClasses.includes("preview");
13
13
  const isPresent = bodyClasses.includes("present");
14
14
  const isReview = bodyClasses.includes("review");
15
- // Editing user templates in prep results in both the 'preview' and 'edit-mode'
16
- // classes being added to the body. In order to detect if we are truly on the
17
- // PresoManager page in the app, we need to ignore the 'preview' class.
18
- const isPresomanager = bodyClasses.includes("edit-mode") && !isPreview;
15
+ const isPresomanager =
16
+ // Editing user templates in prep results in both the 'preview' and 'edit-mode'
17
+ // classes being added to the body. In order to detect if we are truly on the
18
+ // PresoManager page in the app, we need to ignore the 'preview' class.
19
+ bodyClasses.includes("edit-mode") && !isPreview;
19
20
  const isEmptyPreview = bodyClasses.includes("empty-preview");
20
21
  const isRemote = isOnline && isClient && !isShareOnline;
21
22
  const isCdk = typeof window.__cdk_version__ !== "undefined";
@@ -115,26 +115,32 @@ export function useRootSlide(article) {
115
115
  const slideEntered = updateState("entered");
116
116
  const slideExiting = updateState("exiting");
117
117
  const slideExited = updateState("exited");
118
-
119
- article.off();
120
- article.on("slide:entering", slideEntering);
121
- article.on("slide:entered", slideEntered);
122
- article.on("slide:exiting", slideExiting);
123
- article.on("slide:exited", slideExited);
124
- article.on("slide:closed", () => {
118
+ const slideClosed = () => {
125
119
  doneRegister.current.promises = [];
126
- });
127
- article.on("slideready", (e, done) => {
120
+ };
121
+ const slideReady = (e, done) => {
128
122
  Promise.all(doneRegister.current.promises).then(() => {
129
123
  done();
130
124
  });
131
125
 
132
126
  setSlideReady(true);
133
127
  slideEntered(e);
134
- });
128
+ };
129
+
130
+ article.on("slide:entering", slideEntering);
131
+ article.on("slide:entered", slideEntered);
132
+ article.on("slide:exiting", slideExiting);
133
+ article.on("slide:exited", slideExited);
134
+ article.on("slide:closed", slideClosed);
135
+ article.on("slideready", slideReady);
135
136
 
136
137
  return () => {
137
- article.off();
138
+ article.off("slide:entering", slideEntering);
139
+ article.off("slide:entered", slideEntered);
140
+ article.off("slide:exiting", slideExiting);
141
+ article.off("slide:exited", slideExited);
142
+ article.off("slide:closed", slideClosed);
143
+ article.off("slideready", slideReady);
138
144
  };
139
145
  }, [slideReady]);
140
146
 
@@ -161,6 +167,8 @@ export function useRootSlide(article) {
161
167
  doneRegister,
162
168
  rootElement: article.get(0),
163
169
  isUserTemplate: slideID.startsWith("adjunct-template-slide"),
170
+ isUserTemplateLibrary:
171
+ slideID.startsWith("template-") && !slideID.startsWith("template-slide"),
164
172
  isPMTemplate: slideID.startsWith("template-slide"),
165
173
 
166
174
  registerSubslide: () => setTotalSubslides(totalSubslides.current + 1),
@@ -3,28 +3,24 @@ import { useEffect, useState, useCallback } from "react";
3
3
  import { useModes } from "./use-modes";
4
4
 
5
5
  import isPlainObject from "lodash.isplainobject";
6
- import isEqual from "lodash.isequal";
7
6
 
8
- function getValueFromContext(context, path, defaultValue) {
9
- if (path) {
10
- return Bridge.Context.get(path, defaultValue);
11
- }
12
-
13
- return context;
14
- }
15
-
16
- export function useSlideContext(contextPath = null, defaultValue = null) {
7
+ export function useSlideContext(
8
+ contextPath = null,
9
+ defaultValue = null,
10
+ { enabled = true } = {},
11
+ ) {
17
12
  let persist = false;
18
13
  let path = contextPath;
19
14
 
20
15
  const { isPresomanager } = useModes();
21
16
 
17
+ // useCallback to prevent useEffect from re-rendering
22
18
  const getValue = useCallback(() => {
23
- return getValueFromContext(
24
- window.Bridge.Context.getDict(),
25
- path,
26
- defaultValue,
27
- );
19
+ if (path) {
20
+ return window.Bridge.Context.get(path, defaultValue);
21
+ }
22
+
23
+ return window.Bridge.Context.getDict();
28
24
  }, [path, defaultValue]);
29
25
 
30
26
  const [context, setContextState] = useState(getValue);
@@ -37,6 +33,10 @@ export function useSlideContext(contextPath = null, defaultValue = null) {
37
33
  }
38
34
 
39
35
  function setContext(key, data) {
36
+ if (!enabled) {
37
+ return;
38
+ }
39
+
40
40
  let setPath = key;
41
41
  let setData = data;
42
42
 
@@ -53,11 +53,10 @@ export function useSlideContext(contextPath = null, defaultValue = null) {
53
53
  }
54
54
 
55
55
  useEffect(() => {
56
- if (isPresomanager) return;
56
+ if (isPresomanager || !enabled) return;
57
57
 
58
58
  function onContextChange() {
59
59
  const newValue = getValue();
60
- if (isEqual(context, newValue)) return;
61
60
  setContextState(newValue);
62
61
  }
63
62
 
@@ -66,7 +65,7 @@ export function useSlideContext(contextPath = null, defaultValue = null) {
66
65
  return () => {
67
66
  Bridge.presenter.getPresentation().off("change:context", onContextChange);
68
67
  };
69
- }, [isPresomanager, context, getValue]);
68
+ }, [enabled, isPresomanager, context, getValue]);
70
69
 
71
70
  return [context, setContext];
72
71
  }
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useCallback } from "react";
2
- import { useSlide } from "./use-slide";
2
+ import { useSlide } from "./slide";
3
3
 
4
4
  export function useSlideDone() {
5
5
  const { doneRegister } = useSlide();
@@ -1,5 +1,5 @@
1
1
  import { useEffect } from "react";
2
- import { useSlide } from "./use-slide";
2
+ import { useSlide } from "./slide";
3
3
 
4
4
  export function useSlideReady(fn) {
5
5
  const { isSlideReady } = useSlide();
@@ -1,7 +1,7 @@
1
1
  import { SlideContext, SubslideContext } from "../contexts.js";
2
2
 
3
3
  import { useContext } from "react";
4
- import { useSlide } from "./use-slide";
4
+ import { useSlide } from "./slide.js";
5
5
 
6
6
  export function useSubslides() {
7
7
  const context = useContext(SubslideContext);
@@ -3,12 +3,14 @@ import { useContext } from "react";
3
3
  import { useModes } from "./index.js";
4
4
 
5
5
  export function useTransitions() {
6
- const { isScreenshot } = useModes();
7
- const { entering, exiting, entered } = useContext(SlideContext).transitions;
6
+ const { isScreenshot } = useModes();
7
+ const { entering, exiting, exited, entered } =
8
+ useContext(SlideContext).transitions;
8
9
 
9
- return {
10
- entering: isScreenshot ? false : entering,
11
- exiting: isScreenshot ? false : exiting,
12
- entered: isScreenshot ? true : entered,
13
- };
10
+ return {
11
+ entering: isScreenshot ? false : entering,
12
+ exiting: isScreenshot ? false : exiting,
13
+ entered: isScreenshot ? true : entered,
14
+ exited,
15
+ };
14
16
  }
package/lib/utils.js CHANGED
@@ -52,8 +52,8 @@ export function testCWEJSONExists({
52
52
  * Results are used when composing field keys for PM templates
53
53
  * and user templates, eg. getPMTemplateFieldKey() and getUserTemplateFieldKey().
54
54
  */
55
- function getSlideNumericID(slideID) {
56
- const numericRegex = /-(\d+)(?:-temp)*$/;
55
+ function getSlideID(slideID) {
56
+ const numericRegex = /-(\d\w+)(?:-temp)*$/;
57
57
  return slideID.match(numericRegex)?.[1];
58
58
  }
59
59
 
@@ -72,7 +72,7 @@ function getSlideNumericID(slideID) {
72
72
  * @returns {string} - The constructed field key for the PM template.
73
73
  */
74
74
  export function getPMTemplateFieldKey(key, slideID) {
75
- const slideNumericID = getSlideNumericID(slideID);
75
+ const slideNumericID = getSlideID(slideID);
76
76
  // example: image_plus_text_columns-options-autoadjunct-767-temp
77
77
  const isUnsavedTemplate = slideID.indexOf("-temp") > -1;
78
78
  const templateFieldKey = `${key}-autoadjunct-${slideNumericID}`;
@@ -99,11 +99,15 @@ export function getPMTemplateFieldKey(key, slideID) {
99
99
  * @returns {string} - The constructed field key for the user template.
100
100
  */
101
101
  export function getUserTemplateFieldKey(key, slideID) {
102
- const slideNumericID = getSlideNumericID(slideID);
102
+ const numericRegex = /-(\d+)(?:-temp)*$/;
103
+ const slideNumericID = slideID.match(numericRegex)?.[1];
104
+
103
105
  const isUnsavedTemplate = slideID.indexOf("-tempkey") > -1;
104
106
 
105
107
  if (isUnsavedTemplate) {
106
- return `${key}-tempkey-${slideNumericID}`;
108
+ const numericRegex = /tempkey-((?:[\d\w])+)/;
109
+ const tempID = slideID.match(numericRegex)?.[1];
110
+ return `${key}-tempkey-${tempID}`;
107
111
  }
108
112
 
109
113
  return `${key}-adjunct-${slideNumericID}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livepreso/content-react",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -1,26 +0,0 @@
1
- {
2
- "files": {
3
- "content/content-react/.rush/temp/shrinkwrap-deps.json": "4645c4e5204fbf6e4b13573ceeacb3c093ff7a90",
4
- "content/content-react/.eslintrc.js": "6245fc28bbe1102d1b4c2a1db96a508e6221f6bd",
5
- "content/content-react/.stylelintrc": "5c129c044fdf8b0dfd92da7860ea25f60bcde085",
6
- "content/content-react/CHANGELOG.json": "001e63a228a710a99d8534c5bc38ddf662946eed",
7
- "content/content-react/CHANGELOG.md": "b5932d45a8c6fcebf4267435c93a9d98a153242e",
8
- "content/content-react/index.js": "826cec91ed8d4b018b33a847b4df6a3e8631d220",
9
- "content/content-react/lib/components/ScrollableArea.js": "ee97a6ce605c2071f879382d1f347fe4fed83ee4",
10
- "content/content-react/lib/components/ScrollableArea.module.scss": "74543f283eb2db0b67d70ffe0d068e03a1131573",
11
- "content/content-react/lib/components/Subslide.js": "ddec8751b9a86d0cc5f587ec31d7d426f42648c5",
12
- "content/content-react/lib/components/Subslides.js": "764d5901525bab61b8f72dc4fe399a356b185e12",
13
- "content/content-react/lib/components/index.js": "f233f0e270fc648dc9c8ae2abfa93bd9e8ccdc01",
14
- "content/content-react/lib/contexts.js": "59a0173397a32c788c0d61ee317741fe0a9c9bee",
15
- "content/content-react/lib/hooks/index.js": "6fcf567354b94f0ab3fb0e2c4bf502cd5a81429e",
16
- "content/content-react/lib/hooks/use-async-reference.js": "23e3eeff2b87b530d40129a049996a5fe76e34c6",
17
- "content/content-react/lib/hooks/use-context.js": "3f697379e6ee9790ba6b4ae96ad6d6c2ba20a669",
18
- "content/content-react/lib/hooks/use-modes.js": "ad8e27b3659b0fcf6fbe79333ccec86d690ed983",
19
- "content/content-react/lib/hooks/use-root-slide.js": "98ce55032605df9507467b32f7969355318330f4",
20
- "content/content-react/lib/hooks/use-shared-state.js": "0d160ddf3e5dec37849f72f4ec2a1d7aac680159",
21
- "content/content-react/lib/hooks/use-subslides.js": "508ac21b01a4ece811ebc2db9c6a41ef6071e326",
22
- "content/content-react/lib/hooks/use-transitions.js": "c9cdf3e8af82b8f8a51e99ee670334cc5c7c42c1",
23
- "content/content-react/package.json": "1bed2af8c66bfa4ad2540e0e001cea26109435eb"
24
- },
25
- "arguments": ""
26
- }