@nascentdigital/funnel-editor-contentful 4.6.7 → 5.0.2

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.
Files changed (129) hide show
  1. package/dist/Editor.d.ts +6 -1
  2. package/dist/Editor.js +17 -1
  3. package/dist/EditorApp.js +11 -9
  4. package/dist/EditorPageRouter.d.ts +1 -0
  5. package/dist/EditorPageRouter.js +40 -0
  6. package/dist/EntryEditor.js +43 -1
  7. package/dist/EntrySidebar.js +18 -1
  8. package/dist/asset/index.d.ts +1 -0
  9. package/dist/{page/hooks → asset}/index.js +1 -1
  10. package/dist/asset/repository/AssetRepository.d.ts +10 -0
  11. package/dist/asset/repository/AssetRepository.js +33 -0
  12. package/dist/asset/repository/index.d.ts +1 -0
  13. package/dist/{core/api → asset/repository}/index.js +1 -3
  14. package/dist/collection/controller/ContentfulCollectionController.d.ts +41 -0
  15. package/dist/collection/controller/ContentfulCollectionController.js +278 -0
  16. package/dist/collection/controller/ContentfulCollectionControllerContainer.d.ts +5 -0
  17. package/dist/collection/controller/ContentfulCollectionControllerContainer.js +28 -0
  18. package/dist/collection/controller/index.d.ts +3 -0
  19. package/dist/collection/controller/index.js +19 -0
  20. package/dist/collection/controller/useContentfulCollectionController.d.ts +2 -0
  21. package/dist/collection/controller/useContentfulCollectionController.js +8 -0
  22. package/dist/collection/domain/Collection.d.ts +108 -0
  23. package/dist/collection/domain/Collection.js +386 -0
  24. package/dist/collection/domain/index.d.ts +1 -0
  25. package/dist/collection/domain/index.js +17 -0
  26. package/dist/collection/index.d.ts +3 -0
  27. package/dist/collection/index.js +19 -0
  28. package/dist/collection/repository/CollectionRepository.d.ts +49 -0
  29. package/dist/collection/repository/CollectionRepository.js +210 -0
  30. package/dist/collection/repository/index.d.ts +1 -0
  31. package/dist/collection/repository/index.js +17 -0
  32. package/dist/collection/screens/CollectionEditor.d.ts +1 -0
  33. package/dist/collection/screens/CollectionEditor.js +59 -0
  34. package/dist/collection/screens/index.d.ts +1 -0
  35. package/dist/collection/screens/index.js +17 -0
  36. package/dist/core/bridge/AppBridgeContainer.d.ts +9 -0
  37. package/dist/core/bridge/AppBridgeContainer.js +55 -0
  38. package/dist/core/bridge/AppBridgeContext.d.ts +8 -0
  39. package/dist/core/bridge/AppBridgeContext.js +11 -0
  40. package/dist/core/bridge/AppMessage.d.ts +19 -0
  41. package/dist/core/bridge/AppMessage.js +19 -0
  42. package/dist/core/bridge/index.d.ts +4 -0
  43. package/dist/core/bridge/index.js +20 -0
  44. package/dist/core/bridge/useAppBridge.d.ts +8 -0
  45. package/dist/core/bridge/useAppBridge.js +24 -0
  46. package/dist/core/client/ContentfulClientContainer.d.ts +8 -0
  47. package/dist/core/client/ContentfulClientContainer.js +43 -0
  48. package/dist/core/client/ContentfulClientContext.d.ts +8 -0
  49. package/dist/core/client/ContentfulClientContext.js +8 -0
  50. package/dist/core/client/index.d.ts +3 -0
  51. package/dist/core/client/index.js +19 -0
  52. package/dist/core/client/useContentfulClient.d.ts +4 -0
  53. package/dist/core/client/useContentfulClient.js +24 -0
  54. package/dist/core/contentful/Contentful.d.ts +33 -0
  55. package/dist/core/contentful/Contentful.js +67 -0
  56. package/dist/core/contentful/ContentfulAsset.d.ts +23 -0
  57. package/dist/core/contentful/ContentfulAsset.js +89 -0
  58. package/dist/core/contentful/ContentfulCollection.d.ts +29 -0
  59. package/dist/core/contentful/ContentfulCollection.js +97 -0
  60. package/dist/core/contentful/ContentfulPage.d.ts +31 -0
  61. package/dist/core/contentful/ContentfulPage.js +84 -0
  62. package/dist/core/contentful/ContentfulRefs.d.ts +16 -0
  63. package/dist/core/contentful/ContentfulRefs.js +152 -0
  64. package/dist/core/contentful/index.d.ts +5 -0
  65. package/dist/core/contentful/index.js +21 -0
  66. package/dist/core/index.d.ts +3 -2
  67. package/dist/core/index.js +3 -2
  68. package/dist/core/repository/CollectionSerializer.d.ts +9 -0
  69. package/dist/core/repository/CollectionSerializer.js +41 -0
  70. package/dist/core/repository/LocalCollectionRepository.d.ts +27 -0
  71. package/dist/core/repository/LocalCollectionRepository.js +143 -0
  72. package/dist/core/repository/LocalPageRepository.d.ts +16 -0
  73. package/dist/core/repository/LocalPageRepository.js +153 -0
  74. package/dist/core/repository/PageSerializer.d.ts +3 -3
  75. package/dist/core/repository/PageSerializer.js +18 -14
  76. package/dist/core/repository/RemoteCollectionRepository.d.ts +19 -0
  77. package/dist/core/repository/RemoteCollectionRepository.js +236 -0
  78. package/dist/core/repository/RemotePageRepository.d.ts +14 -0
  79. package/dist/core/repository/RemotePageRepository.js +113 -0
  80. package/dist/core/repository/index.d.ts +4 -1
  81. package/dist/core/repository/index.js +4 -1
  82. package/dist/explore/components/Header.d.ts +26 -0
  83. package/dist/explore/components/Header.js +31 -0
  84. package/dist/explore/components/index.d.ts +1 -0
  85. package/dist/explore/components/index.js +17 -0
  86. package/dist/explore/index.d.ts +1 -0
  87. package/dist/explore/index.js +17 -0
  88. package/dist/explore/screens/Dashboard.d.ts +1 -0
  89. package/dist/explore/screens/Dashboard.js +22 -0
  90. package/dist/explore/screens/PageExplorer.d.ts +1 -0
  91. package/dist/explore/screens/PageExplorer.js +9 -0
  92. package/dist/explore/screens/SiteExplorer.d.ts +1 -0
  93. package/dist/explore/screens/SiteExplorer.js +24 -0
  94. package/dist/explore/screens/index.d.ts +3 -0
  95. package/dist/explore/screens/index.js +19 -0
  96. package/dist/page/{hooks/PageController.d.ts → controller/ContentfulPageController.d.ts} +17 -6
  97. package/dist/page/controller/ContentfulPageController.js +277 -0
  98. package/dist/page/controller/ContentfulPageControllerContainer.d.ts +5 -0
  99. package/dist/page/controller/ContentfulPageControllerContainer.js +28 -0
  100. package/dist/page/controller/index.d.ts +3 -0
  101. package/dist/page/controller/index.js +19 -0
  102. package/dist/page/controller/useContentfulPageController.d.ts +2 -0
  103. package/dist/page/controller/useContentfulPageController.js +8 -0
  104. package/dist/{core → page}/domain/Page.d.ts +71 -10
  105. package/dist/page/domain/Page.js +631 -0
  106. package/dist/page/index.d.ts +3 -0
  107. package/dist/page/index.js +3 -0
  108. package/dist/page/repository/PageRepository.d.ts +45 -0
  109. package/dist/page/repository/PageRepository.js +224 -0
  110. package/dist/page/repository/index.d.ts +1 -0
  111. package/dist/page/repository/index.js +17 -0
  112. package/dist/page/screens/PageEditor.js +29 -15
  113. package/package.json +10 -4
  114. package/dist/core/api/EditorApiClient.d.ts +0 -7
  115. package/dist/core/api/EditorApiClient.js +0 -29
  116. package/dist/core/api/EditorApiContainer.d.ts +0 -5
  117. package/dist/core/api/EditorApiContainer.js +0 -16
  118. package/dist/core/api/EditorApiContext.d.ts +0 -7
  119. package/dist/core/api/EditorApiContext.js +0 -6
  120. package/dist/core/api/index.d.ts +0 -3
  121. package/dist/core/api/useEditorApi.d.ts +0 -2
  122. package/dist/core/api/useEditorApi.js +0 -12
  123. package/dist/core/domain/Page.js +0 -180
  124. package/dist/core/repository/PageRepository.d.ts +0 -12
  125. package/dist/core/repository/PageRepository.js +0 -23
  126. package/dist/page/hooks/PageController.js +0 -107
  127. package/dist/page/hooks/index.d.ts +0 -1
  128. /package/dist/{core → page}/domain/index.d.ts +0 -0
  129. /package/dist/{core → page}/domain/index.js +0 -0
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.PageRepository = void 0;
15
+ const contentful_1 = require("@nascentdigital/funnel-cms/contentful");
16
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
17
+ const components_1 = require("@nascentdigital/funnel-editor/components");
18
+ const domain_1 = require("../domain");
19
+ // repository
20
+ class PageRepository {
21
+ constructor(args) {
22
+ // initialize instance
23
+ this.sdk = args.sdk;
24
+ this.contentfulClient = args.contentfulClient;
25
+ }
26
+ async search(args) {
27
+ throw new funnel_core_1.NotImplementedError();
28
+ }
29
+ async getOverview({ region }) {
30
+ // get overviews
31
+ const overview = await this.contentfulClient.pages.getOverview({
32
+ brand: funnel_core_1.AppConfig.brand(),
33
+ region,
34
+ version: 'draft'
35
+ });
36
+ // enrich with templates and flip to array
37
+ const templates = Object.values(funnel_core_1.Schema.Site.current().regions[region]);
38
+ return templates.map(template => {
39
+ var _a, _b;
40
+ // extract static page overview
41
+ const { type } = template;
42
+ if (template.variant === 'static') {
43
+ return new components_1.StaticPageOverview(Object.assign({ template,
44
+ type, refs: {} }, ((_a = overview.static.find(page => page.type === type)) !== null && _a !== void 0 ? _a : {})));
45
+ }
46
+ // or dynamic one
47
+ else {
48
+ return new components_1.DynamicPageOverview(Object.assign({ template,
49
+ type, count: 0 }, ((_b = overview.dynamic.find(page => page.type === type)) !== null && _b !== void 0 ? _b : {})));
50
+ }
51
+ });
52
+ }
53
+ async create(args) {
54
+ throw new funnel_core_1.NotImplementedError();
55
+ }
56
+ async createLanguage(args) {
57
+ throw new funnel_core_1.NotImplementedError();
58
+ }
59
+ async load(sys) {
60
+ // throw if entry isn't a page (it should be in this case)
61
+ const { sdk, contentfulClient } = this;
62
+ const { entry } = sdk;
63
+ sys = sys !== null && sys !== void 0 ? sys : entry.getSys();
64
+ const { id: entryId, contentType: { sys: { id: entryType } } } = sys;
65
+ if (entryType !== contentful_1.ContentfulPageData.contentType) {
66
+ throw new funnel_core_1.ArgumentError(`Cannot load Page from entry that isn't of "${contentful_1.ContentfulPageData.contentType}" type`);
67
+ }
68
+ // throw if page doesn't have a group id
69
+ const pageId = entryId;
70
+ const type = entry.fields.type.getValue();
71
+ const groupId = entry.fields.groupId.getValue();
72
+ const brand = entry.fields.brand.getValue();
73
+ const region = entry.fields.region.getValue();
74
+ const language = funnel_core_1.Language.tryParse(entry.fields.language.getValue());
75
+ if (!groupId || !type || !brand || !region || !language) {
76
+ throw new funnel_core_1.ArgumentError(`Page "${pageId}" is not configured (missing required fields)`);
77
+ }
78
+ // fetch remote data (throw if not found)
79
+ const _a = await contentfulClient.pages.getGroup({ groupId, type, brand, region, language, version: 'draft' }), _b = _a.group, { instances: pages } = _b, group = __rest(_b, ["instances"]), { page: pageResult } = _a;
80
+ if (!pageResult) {
81
+ throw new funnel_core_1.NotFoundError(`Unable to resolve Page with id "${pageId}"`);
82
+ }
83
+ console.debug('[PageRepository/load] loaded page data:', { group, pages, pageResult });
84
+ // get entry data + remote references
85
+ const { data: _remote } = pageResult, references = __rest(pageResult, ["data"]);
86
+ const data = entryToPageData(entry);
87
+ // return page model from data
88
+ const page = domain_1.Page.fromSchemaData(Object.assign({ data }, references));
89
+ return {
90
+ pageSummary: new components_1.PageSummary(Object.assign(Object.assign({ template: page.template }, group), { pages })),
91
+ page,
92
+ sys
93
+ };
94
+ }
95
+ async save(page) {
96
+ // serialize page updates (or skip if there are no changes)
97
+ const savables = [];
98
+ const updateArgs = domain_1.Page.toUpdates(page, savables);
99
+ if (updateArgs.updates.length === 0) {
100
+ return page;
101
+ }
102
+ // start all updates
103
+ page.onSaveStart();
104
+ savables.forEach(savable => savable.onSaveStart());
105
+ // update entry if page is local
106
+ let updatedOn;
107
+ const { sdk } = this;
108
+ const { entry } = sdk;
109
+ const { id: entryId, contentType: { sys: { id: entryType } } } = entry.getSys();
110
+ if (entryType === contentful_1.ContentfulPageData.contentType && page.id === entryId) {
111
+ console.debug('[PageRepository/save] saving local entry', { entry, page });
112
+ // save updates to entry
113
+ await saveEntryUpdates({ entry, updates: updateArgs.updates });
114
+ // capture updated timestamp
115
+ updatedOn = new Date(entry.getSys().updatedAt).getTime();
116
+ }
117
+ // or update remotely
118
+ else {
119
+ console.debug('[PageRepository/save] saving remote entry', page);
120
+ // push updates remotely
121
+ const result = await this.contentfulClient.pages.update(updateArgs);
122
+ // capture update timestamp
123
+ updatedOn = result.updatedOn;
124
+ // swap to new page (if update returned new data)
125
+ if (result.page) {
126
+ console.debug('[PageRepository/save] switching to new page data', result.page);
127
+ page = domain_1.Page.fromSchemaData(result.page);
128
+ }
129
+ }
130
+ console.debug('[PageRepository/save] finalizing save');
131
+ // complete updates
132
+ savables.forEach(savable => savable.onSaveComplete());
133
+ page.onSaveComplete(updatedOn);
134
+ console.debug('[PageRepository/save] save complete', page);
135
+ // return page
136
+ return page;
137
+ }
138
+ async sync({ page, sys }) {
139
+ // skip if entity version and updated sys are same
140
+ const { sdk } = this;
141
+ const { entry } = sdk;
142
+ const entrySys = entry.getSys();
143
+ if (sys.version === entrySys.version) {
144
+ console.debug('[ContentfulPageRepository/sync] ignoring unchanged entity');
145
+ return { page, sys };
146
+ }
147
+ // force reload if entry references changed
148
+ const entryReferences = entry.fields.references.getValue();
149
+ const entryRefs = new Set(entryReferences.map(link => `${link.sys.linkType}.${link.sys.id}`));
150
+ const { references: pageReferences } = page;
151
+ const pageRefs = new Set(pageReferences.map(link => `${link.sys.linkType}.${link.sys.id}`));
152
+ if (!pageRefs.isSupersetOf(entryRefs)) {
153
+ console.debug('[ContentfulPageRepository/sync] references changed - triggering reload');
154
+ return this.load(sys);
155
+ }
156
+ console.debug('[ContentfulPageRepository/sync] reusing stable references - merging entity');
157
+ // or load page data, but use old references in store
158
+ const data = entryToPageData(entry);
159
+ const references = {
160
+ files: page.assets.reduce((files, file) => {
161
+ files[file.value.id] = file;
162
+ return files;
163
+ }, {}),
164
+ collections: page.collections.reduce((collections, collection) => {
165
+ collections[collection.id] = collection;
166
+ return collections;
167
+ }, {}),
168
+ pages: page.pages.reduce((pages, page) => {
169
+ pages[page.id] = page;
170
+ return pages;
171
+ }, {})
172
+ };
173
+ // create new page (use existing sys)
174
+ return {
175
+ page: domain_1.Page.fromSchemaData(Object.assign({ data }, references)),
176
+ sys
177
+ };
178
+ }
179
+ async unpublish(page) {
180
+ throw new funnel_core_1.NotImplementedError();
181
+ }
182
+ }
183
+ exports.PageRepository = PageRepository;
184
+ // helpers
185
+ function entryToPageData(entry) {
186
+ // throw if it's not a page
187
+ const entryType = entry.getSys().contentType.sys.id;
188
+ if (entryType !== contentful_1.ContentfulPageData.contentType) {
189
+ throw new funnel_core_1.ArgumentError(`Expected entry to be "${contentful_1.ContentfulPageData.contentType}", but found "${entryType}"`);
190
+ }
191
+ // serialize entry (this is the latest data)
192
+ const entryData = contentful_1.ContentfulData.fromEntryData(entry);
193
+ return contentful_1.ContentfulPageData.deserialize(entryData);
194
+ }
195
+ async function saveEntryUpdates({ entry, updates }) {
196
+ var _a;
197
+ // serialize entry (this is the latest data)
198
+ const pageData = entryToPageData(entry);
199
+ // create model and apply updates
200
+ const pageModel = new funnel_core_1.Schema.PageModel(pageData);
201
+ pageModel.update(updates);
202
+ pageModel.sync();
203
+ // resolve references
204
+ const references = contentful_1.ContentfulData.findReferences([pageData.discover, pageData.preview, pageData.content]);
205
+ // update fields
206
+ const { fields } = entry;
207
+ await Promise.all([
208
+ // required updates
209
+ fields.name.setValue(pageData.name),
210
+ fields.slug.setValue(pageData.slug),
211
+ fields.url.setValue(pageData.url),
212
+ fields.state.setValue(pageData.state),
213
+ fields.errors.setValue(pageData.errors),
214
+ fields.references.setValue(references),
215
+ // TODO: save only fields that changed
216
+ // conditional updates
217
+ fields.tags.setValue((_a = pageData.tags) !== null && _a !== void 0 ? _a : []),
218
+ fields.preview.setValue(pageData.preview),
219
+ fields.discover.setValue(pageData.discover),
220
+ fields.content.setValue(pageData.content)
221
+ ]);
222
+ // save entry
223
+ await entry.save();
224
+ }
@@ -0,0 +1 @@
1
+ export * from './PageRepository';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./PageRepository"), exports);
@@ -2,34 +2,48 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PageEditor = PageEditor;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
5
6
  const components_1 = require("@nascentdigital/funnel-editor/components");
6
7
  const react_1 = require("react");
7
8
  const core_1 = require("../../core");
8
- const hooks_1 = require("../hooks");
9
+ const controller_1 = require("../controller");
9
10
  // component
10
11
  function PageEditor() {
11
12
  // hooks
12
- const editorApi = (0, core_1.useEditorApi)();
13
- const { controller, controllerContext } = (0, react_1.useMemo)(() => {
14
- const controller = new hooks_1.PageController({ editorApi });
15
- return {
16
- controller,
17
- controllerContext: { controller }
18
- };
19
- }, [editorApi]);
13
+ const splash = (0, components_1.useSplash)();
14
+ const bridge = (0, core_1.useAppBridge)();
15
+ const controller = (0, controller_1.useContentfulPageController)();
20
16
  const { page } = controller;
21
17
  const pageContext = (0, react_1.useMemo)(() => ({ page }), [page]);
22
18
  const [itemId, setItemId] = (0, react_1.useState)();
23
19
  const selectedItem = (0, react_1.useMemo)(() => page === null || page === void 0 ? void 0 : page.coerceItem(itemId), [page, itemId]);
24
- // sync with controller
25
- (0, components_1.usePageController)(controller);
20
+ const { ready } = controller;
26
21
  // load
27
22
  (0, react_1.useEffect)(() => {
28
- controller.load().catch(console.error);
29
- }, [controller]);
30
- const onSelectItem = (item) => setItemId(item.identifier);
23
+ controller.load().catch(e => {
24
+ // transform error
25
+ const error = funnel_core_1.IsometricErrorUtils.coerceError(e);
26
+ // TODO: come up with an appropriate message
27
+ const message = error.message;
28
+ // show error via splash
29
+ splash.showError({ message, onRetry: () => controller.reload() });
30
+ });
31
+ }, [splash, controller]);
32
+ // dismiss splash when ready
33
+ (0, react_1.useEffect)(() => {
34
+ if (ready) {
35
+ splash.dismiss();
36
+ }
37
+ else {
38
+ splash.showLoading('Fetching content');
39
+ }
40
+ }, [splash, ready]);
41
+ const onSelectItem = (item) => {
42
+ setItemId(item.identifier);
43
+ bridge.sendMessage(core_1.AppBlockNavMessage.create(item.identifier));
44
+ };
31
45
  // render
32
- return ((0, jsx_runtime_1.jsx)(components_1.PageControllerContext.Provider, { value: controllerContext, children: (0, jsx_runtime_1.jsx)(components_1.PageContext.Provider, { value: pageContext, children: (0, jsx_runtime_1.jsx)(components_1.AssetStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)(components_1.CollectionStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)(components_1.PageRefStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)("div", { className: "bg-background flex h-dvh w-dvw flex-col", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex-1", children: (0, jsx_runtime_1.jsxs)("div", { className: "absolute inset-0 flex", children: [(0, jsx_runtime_1.jsx)("section", { className: "scrollbar-thin w-[220px] shrink-0 overflow-y-scroll lg:w-[240px] xl:w-[280px]", children: (0, jsx_runtime_1.jsx)(components_1.PageNav, { selectedItem: selectedItem, onSelectItem: onSelectItem }) }), (0, jsx_runtime_1.jsx)("section", { className: "mx-auto h-full max-h-full max-w-[1000px] flex-1", children: renderContent({ controller, page, selectedItem, onSelectItem }) })] }) }) }) }) }) }) }) }));
46
+ return ((0, jsx_runtime_1.jsx)(components_1.PageContext.Provider, { value: pageContext, children: (0, jsx_runtime_1.jsx)(components_1.AssetStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)(components_1.CollectionStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)(components_1.PageRefStoreContext.Provider, { value: page, children: (0, jsx_runtime_1.jsx)("div", { className: "bg-background flex h-dvh w-dvw flex-col", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex-1", children: (0, jsx_runtime_1.jsxs)("div", { className: "absolute inset-0 flex", children: [(0, jsx_runtime_1.jsx)("section", { className: "scrollbar-thin w-[220px] shrink-0 overflow-y-scroll lg:w-[240px] xl:w-[280px]", tabIndex: -1, children: (0, jsx_runtime_1.jsx)(components_1.PageNav, { selectedItem: selectedItem, onSelectItem: onSelectItem }) }), (0, jsx_runtime_1.jsx)("section", { className: "mx-auto h-full max-h-full max-w-[1000px] flex-1", children: renderContent({ controller, page, selectedItem, onSelectItem }) })] }) }) }) }) }) }) }));
33
47
  }
34
48
  function renderContent({ controller, page, selectedItem, onSelectItem }) {
35
49
  // show loader if not ready
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nascentdigital/funnel-editor-contentful",
3
- "version": "4.6.7",
3
+ "version": "5.0.2",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "restricted"
@@ -37,9 +37,15 @@
37
37
  "react-dom": "^19"
38
38
  },
39
39
  "dependencies": {
40
- "@contentful/app-sdk": "^4.69.0",
40
+ "@contentful/app-sdk": "^4",
41
41
  "@contentful/react-apps-toolkit": "^2.0.1",
42
- "@nascentdigital/funnel-editor": "^4.6.7"
42
+ "@nascentdigital/funnel-cms": "^5.0.2",
43
+ "@nascentdigital/funnel-editor": "^5.0.2",
44
+ "react-dom": "^19",
45
+ "react-router": "^8",
46
+ "react-router-dom": "^7",
47
+ "rxjs": "^7",
48
+ "uuid": "^11"
43
49
  },
44
50
  "devDependencies": {
45
51
  "@types/node": "^22",
@@ -53,5 +59,5 @@
53
59
  "ts-jest": "^29",
54
60
  "type-fest": "^4"
55
61
  },
56
- "gitHead": "b17e33b4400391b3984e61225c572f097c4c26c9"
62
+ "gitHead": "24d9690cf813052f6561c3ccef11c7cf69ad7f7c"
57
63
  }
@@ -1,7 +0,0 @@
1
- import { EditorAppSDK } from '@contentful/app-sdk';
2
- import { PageClient } from '@nascentdigital/funnel-cms';
3
- export declare class EditorApiClient {
4
- readonly sdk: EditorAppSDK;
5
- constructor(sdk: EditorAppSDK);
6
- currentPageGroup(): Promise<PageClient.GetGroup.Result>;
7
- }
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EditorApiClient = void 0;
4
- // class
5
- class EditorApiClient {
6
- constructor(sdk) {
7
- this.sdk = sdk;
8
- }
9
- async currentPageGroup() {
10
- const entry = this.sdk.entry;
11
- const { type, content } = entry.fields;
12
- return {
13
- group: {},
14
- page: {
15
- data: {
16
- id: entry.getSys().id,
17
- type: 'home', // type.getValue(),
18
- region: 'ca',
19
- language: 'en',
20
- content: content.getValue(),
21
- },
22
- files: {},
23
- pages: {},
24
- collections: {},
25
- },
26
- };
27
- }
28
- }
29
- exports.EditorApiClient = EditorApiClient;
@@ -1,5 +0,0 @@
1
- import { PropsWithChildren } from 'react';
2
- export declare function EditorApiContainer({ children }: EditorApiContainer.Props): import("react/jsx-runtime").JSX.Element;
3
- export declare namespace EditorApiContainer {
4
- type Props = PropsWithChildren;
5
- }
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EditorApiContainer = EditorApiContainer;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_apps_toolkit_1 = require("@contentful/react-apps-toolkit");
6
- const react_1 = require("react");
7
- const EditorApiClient_1 = require("./EditorApiClient");
8
- const EditorApiContext_1 = require("./EditorApiContext");
9
- // container
10
- function EditorApiContainer({ children }) {
11
- // bind context
12
- const sdk = (0, react_apps_toolkit_1.useSDK)();
13
- const context = (0, react_1.useMemo)(() => ({ client: new EditorApiClient_1.EditorApiClient(sdk) }), [sdk]);
14
- // render
15
- return ((0, jsx_runtime_1.jsx)(EditorApiContext_1.EditorApiContext.Provider, { value: context, children: children }));
16
- }
@@ -1,7 +0,0 @@
1
- import { EditorApiClient } from './EditorApiClient';
2
- export declare const EditorApiContext: import("react").Context<EditorApiContext.Type>;
3
- export declare namespace EditorApiContext {
4
- type Type = {
5
- client: EditorApiClient;
6
- };
7
- }
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EditorApiContext = void 0;
4
- const react_1 = require("react");
5
- // context
6
- exports.EditorApiContext = (0, react_1.createContext)({});
@@ -1,3 +0,0 @@
1
- export * from './EditorApiClient';
2
- export * from './EditorApiContainer';
3
- export * from './useEditorApi';
@@ -1,2 +0,0 @@
1
- import { EditorApiClient } from './EditorApiClient';
2
- export declare function useEditorApi(): EditorApiClient;
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useEditorApi = useEditorApi;
4
- const react_1 = require("react");
5
- const EditorApiContext_1 = require("./EditorApiContext");
6
- // hook
7
- function useEditorApi() {
8
- // bind context
9
- const { client } = (0, react_1.useContext)(EditorApiContext_1.EditorApiContext);
10
- // return client
11
- return client;
12
- }
@@ -1,180 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Page = void 0;
4
- const funnel_core_1 = require("@nascentdigital/funnel-core");
5
- const components_1 = require("@nascentdigital/funnel-editor/components");
6
- const rxjs_1 = require("rxjs");
7
- // class
8
- class Page {
9
- constructor(args) {
10
- var _a, _b, _c;
11
- // initialize instance variables
12
- this.id = args.id;
13
- this.template = args.template;
14
- this.eventBus = args.eventBus;
15
- this.groupId = args.groupId;
16
- this.brand = args.brand;
17
- this.language = args.language;
18
- this.region = args.region;
19
- this.url = args.url;
20
- this.publishedOn = args.publishedOn;
21
- this.createdOn = args.createdOn;
22
- this.updatedOn = args.updatedOn;
23
- this.settings = new components_1.PageSettings(this);
24
- this._content = args.content;
25
- this._initialSlug = this._slug = args.slug;
26
- this._assets = (_a = args.files) !== null && _a !== void 0 ? _a : [];
27
- this._pages = (_b = args.pages) !== null && _b !== void 0 ? _b : [];
28
- this._collections = (_c = args.collections) !== null && _c !== void 0 ? _c : [];
29
- this._initialTags = new Set(args.tags);
30
- this._tags = new Set(args.tags);
31
- this._syncing = false;
32
- // bind content
33
- this._content.forEach((item) => item.bind({ parent: this, area: 'content' }));
34
- }
35
- get events$() {
36
- return this.eventBus.events$;
37
- }
38
- get stable$() {
39
- return this.eventBus.events$.pipe((0, rxjs_1.map)(() => !this._syncing && !this.modified), (0, rxjs_1.distinctUntilChanged)());
40
- }
41
- get modified() {
42
- return false;
43
- }
44
- get published() {
45
- return this.publishedOn !== undefined;
46
- }
47
- get syncing() {
48
- return this._syncing;
49
- }
50
- get hasSlug() {
51
- return this.template.variant === 'dynamic';
52
- }
53
- get slug() {
54
- return this._slug;
55
- }
56
- get discover() {
57
- return [];
58
- }
59
- get content() {
60
- return this._content;
61
- }
62
- get blocks() {
63
- return this.content
64
- .flatMap((item) => item instanceof components_1.Section ? item.blocks : item);
65
- }
66
- get firstBlock() {
67
- // find first block
68
- for (const item of this.content) {
69
- // return item if it matches
70
- if (item instanceof components_1.Block) {
71
- return item;
72
- }
73
- // search deeply into sections
74
- else {
75
- const { blocks } = item;
76
- if (blocks.length > 0) {
77
- return blocks[0];
78
- }
79
- }
80
- }
81
- // or return undefined
82
- return undefined;
83
- }
84
- get firstItem() {
85
- return this.content[0];
86
- }
87
- get items() {
88
- return [...this._content];
89
- }
90
- get assets() {
91
- return this._assets;
92
- }
93
- get collections() {
94
- return this._collections;
95
- }
96
- get initialTags() {
97
- return this._initialTags;
98
- }
99
- get tagGroups() {
100
- return this.template.tags;
101
- }
102
- get tags() {
103
- return this._tags;
104
- }
105
- getItem(identifier) {
106
- // skip if there's no identifier
107
- if (!identifier) {
108
- return undefined;
109
- }
110
- // or return settings
111
- else if (identifier === components_1.PageSettings.id) {
112
- return this.settings;
113
- }
114
- // search content for item
115
- for (const item of this.items) {
116
- // return item if it matches
117
- if (item.identifier === identifier) {
118
- return item;
119
- }
120
- // search deeply into sections
121
- if (item instanceof components_1.Section) {
122
- for (const block of item.blocks) {
123
- // return block if it matches
124
- if (block.identifier === identifier) {
125
- return block;
126
- }
127
- }
128
- }
129
- }
130
- // or return undefined
131
- return undefined;
132
- }
133
- coerceItem(identifier) {
134
- var _a, _b;
135
- return (_b = (_a = this.getItem(identifier)) !== null && _a !== void 0 ? _a : this.firstBlock) !== null && _b !== void 0 ? _b : this.firstItem;
136
- }
137
- deleteBlock(area, key) {
138
- throw new Error('Method not implemented.');
139
- }
140
- getAsset(assetId) {
141
- return this._assets.find((asset) => asset.value.id === assetId);
142
- }
143
- getAssetScope(range) {
144
- throw new Error('Method not implemented.');
145
- }
146
- getSearchScope() {
147
- throw new Error('Method not implemented.');
148
- }
149
- addAsset(asset) {
150
- throw new Error('Method not implemented.');
151
- }
152
- removeAsset(assetId) {
153
- throw new Error('Method not implemented.');
154
- }
155
- getCollection(collectionId) {
156
- throw new Error('Method not implemented.');
157
- }
158
- addCollection(collection) {
159
- throw new Error('Method not implemented.');
160
- }
161
- removeCollection(collectionId) {
162
- throw new Error('Method not implemented.');
163
- }
164
- getPageRef(pageId) {
165
- return pageId && pageId !== funnel_core_1.Schema.Page.Id.draft ? this._pages.find((ref) => ref.id === pageId) : undefined;
166
- }
167
- addPageRef(ref) {
168
- throw new Error('Method not implemented.');
169
- }
170
- removePageRef(pageId) {
171
- throw new Error('Method not implemented.');
172
- }
173
- addTag(tag) {
174
- throw new Error('Method not implemented.');
175
- }
176
- removeTag(tag) {
177
- throw new Error('Method not implemented.');
178
- }
179
- }
180
- exports.Page = Page;
@@ -1,12 +0,0 @@
1
- import { EventBus } from '@nascentdigital/funnel-core';
2
- import { EditorApiClient } from '../api';
3
- export declare class PageRepository {
4
- readonly editorApi: EditorApiClient;
5
- constructor(editorApi: EditorApiClient);
6
- load({ eventBus }: PageRepository.LoadArgs): Promise<import("..").Page | undefined>;
7
- }
8
- export declare namespace PageRepository {
9
- type LoadArgs = {
10
- eventBus: EventBus;
11
- };
12
- }
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PageRepository = void 0;
4
- const PageSerializer_1 = require("./PageSerializer");
5
- // class
6
- class PageRepository {
7
- constructor(editorApi) {
8
- this.editorApi = editorApi;
9
- }
10
- async load({ eventBus }) {
11
- // fetch current page
12
- const { page: flattenedPage } = await this.editorApi.currentPageGroup();
13
- if (!flattenedPage) {
14
- return undefined;
15
- }
16
- // deserialize page
17
- return PageSerializer_1.PageSerializer.deserializePage({
18
- eventBus,
19
- flattenedPage
20
- });
21
- }
22
- }
23
- exports.PageRepository = PageRepository;