@nascentdigital/funnel-editor 5.0.1 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/components.d.ts +3 -1
  2. package/dist/components.js +3 -1
  3. package/dist/core/client/EditorApiClient.js +1 -1
  4. package/dist/core/components/fields/OptInField.js +42 -2
  5. package/dist/core/components/fields/asset/AssetEditor.d.ts +1 -2
  6. package/dist/core/components/fields/asset/AssetEditor.js +18 -6
  7. package/dist/core/components/fields/asset/AssetUploader.d.ts +1 -2
  8. package/dist/core/components/fields/asset/AssetUploader.js +18 -6
  9. package/dist/core/components/fields/collection/CollectionEditor.d.ts +2 -1
  10. package/dist/core/components/fields/collection/CollectionEditor.js +17 -3
  11. package/dist/core/components/fields/embed/EmbeddedVideoEditor.d.ts +2 -2
  12. package/dist/core/components/fields/embed/EmbeddedVideoEditor.js +17 -5
  13. package/dist/core/components/fields/factories/AssetFactory.d.ts +3 -3
  14. package/dist/core/components/fields/factories/AssetFactory.js +18 -13
  15. package/dist/core/components/fields/factories/CollectionFactory.d.ts +3 -3
  16. package/dist/core/components/fields/factories/CollectionFactory.js +20 -13
  17. package/dist/core/components/fields/factories/EmbeddedVideoFactory.d.ts +3 -3
  18. package/dist/core/components/fields/factories/EmbeddedVideoFactory.js +17 -8
  19. package/dist/core/components/fields/factories/FieldValueFactory.d.ts +7 -5
  20. package/dist/core/components/fields/factories/FieldValueFactory.js +49 -12
  21. package/dist/core/components/fields/factories/LinkFactory.d.ts +3 -3
  22. package/dist/core/components/fields/factories/LinkFactory.js +17 -8
  23. package/dist/core/components/fields/factories/MediaFactory.d.ts +3 -3
  24. package/dist/core/components/fields/factories/MediaFactory.js +105 -149
  25. package/dist/core/components/fields/factories/ObjectFactory.d.ts +3 -2
  26. package/dist/core/components/fields/factories/ObjectFactory.js +16 -2
  27. package/dist/core/components/fields/factories/TextFactory.d.ts +3 -3
  28. package/dist/core/components/fields/factories/TextFactory.js +16 -10
  29. package/dist/core/components/fields/link/LinkEditor.d.ts +2 -2
  30. package/dist/core/components/fields/link/LinkEditor.js +18 -6
  31. package/dist/core/components/fields/media/MediaEditor.d.ts +2 -3
  32. package/dist/core/components/fields/media/MediaEditor.js +40 -11
  33. package/dist/core/components/fields/media/index.d.ts +0 -1
  34. package/dist/core/components/fields/media/index.js +0 -1
  35. package/dist/core/components/fields/object/ObjectEditor.d.ts +2 -1
  36. package/dist/core/components/fields/object/ObjectEditor.js +15 -1
  37. package/dist/core/components/fields/page/PagePicker.js +1 -1
  38. package/dist/core/components/interaction/Popup.d.ts +11 -7
  39. package/dist/core/components/interaction/Popup.js +8 -6
  40. package/dist/core/components/interaction/QuickInput.d.ts +2 -4
  41. package/dist/core/components/interaction/QuickInput.js +6 -2
  42. package/dist/core/components/interaction/menu/Menu.d.ts +8 -19
  43. package/dist/core/components/interaction/menu/Menu.js +26 -60
  44. package/dist/core/components/interaction/menu/useMenuController.d.ts +4 -2
  45. package/dist/core/components/interaction/menu/useMenuController.js +4 -1
  46. package/dist/core/domain/CollectionFieldProxy.js +1 -1
  47. package/dist/core/domain/Collections.js +0 -2
  48. package/dist/core/domain/ICollection.d.ts +1 -0
  49. package/dist/core/domain/IPage.d.ts +6 -1
  50. package/dist/core/domain/IPage.js +30 -0
  51. package/dist/core/domain/PageOverview.d.ts +6 -0
  52. package/dist/core/domain/PageOverview.js +17 -0
  53. package/dist/core/domain/PageSummary.d.ts +9 -7
  54. package/dist/core/domain/PageSummary.js +12 -16
  55. package/dist/core/domain/Pages.js +1 -2
  56. package/dist/core/domain/Site.js +0 -2
  57. package/dist/core/hooks/useCollectionRepository.d.ts +1 -1
  58. package/dist/core/hooks/useCollections.js +4 -0
  59. package/dist/core/hooks/usePageRepository.d.ts +1 -1
  60. package/dist/core/hooks/useSite.js +4 -0
  61. package/dist/core/repository/CollectionRepository.d.ts +2 -2
  62. package/dist/core/repository/ICollectionRepository.d.ts +2 -3
  63. package/dist/core/repository/IPageRepository.d.ts +0 -1
  64. package/dist/core/repository/PageRepository.js +1 -1
  65. package/dist/core/repository/SerializeCollectionUpdate.d.ts +5 -5
  66. package/dist/core/repository/SerializePageUpdate.d.ts +7 -8
  67. package/dist/core/splash/SplashContainer.d.ts +4 -2
  68. package/dist/core/splash/SplashContainer.js +3 -3
  69. package/dist/explore/screens/PageExplorer.js +2 -1
  70. package/dist/page/components/BlockEditor.d.ts +3 -1
  71. package/dist/page/components/BlockEditor.js +4 -3
  72. package/dist/page/components/config/BlockConfigurationProvider.d.ts +10 -2
  73. package/dist/page/components/config/BlockConfigurationProvider.js +11 -3
  74. package/dist/page/components/config/BlockPreview.d.ts +4 -2
  75. package/dist/page/components/config/BlockPreview.js +5 -11
  76. package/dist/page/components/config/index.d.ts +1 -0
  77. package/dist/page/components/config/index.js +1 -0
  78. package/dist/page/components/config/useBlockConfiguration$.d.ts +3 -0
  79. package/dist/page/components/config/useBlockConfiguration$.js +22 -0
  80. package/dist/page/components/panels/BlockConfigPanel.js +3 -3
  81. package/dist/page/hooks/PageController.js +2 -1
  82. package/dist/styles/index.css +34 -9
  83. package/dist/styles/tailwind.js +1 -0
  84. package/package.json +3 -3
  85. package/dist/core/components/fields/media/MediaPicker.d.ts +0 -15
  86. package/dist/core/components/fields/media/MediaPicker.js +0 -251
@@ -1,10 +1,30 @@
1
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
+ };
2
13
  Object.defineProperty(exports, "__esModule", { value: true });
3
14
  exports.IPage = void 0;
4
15
  const funnel_core_1 = require("@nascentdigital/funnel-core");
5
16
  // extension
6
17
  var IPage;
7
18
  (function (IPage) {
19
+ let Ref;
20
+ (function (Ref) {
21
+ function fromData(_a) {
22
+ var { tags } = _a, data = __rest(_a, ["tags"]);
23
+ const template = funnel_core_1.Schema.Site.getPage(data.type, data.region);
24
+ return Object.assign({ template, tags: template.parseTags(tags !== null && tags !== void 0 ? tags : []) }, data);
25
+ }
26
+ Ref.fromData = fromData;
27
+ })(Ref = IPage.Ref || (IPage.Ref = {}));
8
28
  let Event;
9
29
  (function (Event) {
10
30
  // methods
@@ -17,4 +37,14 @@ var IPage;
17
37
  }
18
38
  Event.create = create;
19
39
  })(Event = IPage.Event || (IPage.Event = {}));
40
+ // helpers
41
+ function getPreviewUrl(path) {
42
+ // get base url
43
+ const url = new URL('/api/preview', window.location.href);
44
+ // apply args
45
+ url.searchParams.set('redirect', path);
46
+ // return url
47
+ return url;
48
+ }
49
+ IPage.getPreviewUrl = getPreviewUrl;
20
50
  })(IPage || (exports.IPage = IPage = {}));
@@ -17,14 +17,20 @@ export declare class StaticPageOverview extends PageOverviewBase {
17
17
  readonly refs: Readonly<Record<Language, Schema.Page.Data.AsLink>>;
18
18
  readonly languages: ReadonlyArray<Language>;
19
19
  constructor({ refs, ...args }: StaticPageOverview.ConstructorArgs);
20
+ get pages(): Schema.Page.Data.AsLink<Schema.Page<Schema.Page.Content, string>, string>[];
20
21
  get isEmpty(): boolean;
21
22
  hasLanguage(language: Language): boolean;
23
+ findPage({ region, language }: StaticPageOverview.FindPageArgs): Schema.Page.Data.AsLink | undefined;
22
24
  getClosestPageRef(language: Language, fallback?: Language): IPage.Ref | undefined;
23
25
  }
24
26
  export declare namespace StaticPageOverview {
25
27
  type ConstructorArgs = Omit<PageOverviewBase.ConstructorArgs, 'variant'> & {
26
28
  refs: Record<Language, Schema.Page.Data.AsLink>;
27
29
  };
30
+ type FindPageArgs = {
31
+ region: string;
32
+ language?: Language;
33
+ };
28
34
  }
29
35
  export declare class DynamicPageOverview extends PageOverviewBase {
30
36
  readonly count: number;
@@ -32,12 +32,29 @@ class StaticPageOverview extends PageOverviewBase {
32
32
  this.refs = refs;
33
33
  this.languages = Object.keys(refs).map(funnel_core_1.Language.parse);
34
34
  }
35
+ get pages() {
36
+ return Object.values(this.refs);
37
+ }
35
38
  get isEmpty() {
36
39
  return this.languages.length === 0;
37
40
  }
38
41
  hasLanguage(language) {
39
42
  return this.languages.includes(language);
40
43
  }
44
+ findPage({ region, language }) {
45
+ var _a;
46
+ // narrow down to region
47
+ const pages = this.pages.filter(page => page.region === region);
48
+ // return exact match (if any) if a language is provided
49
+ if (language) {
50
+ return pages.find(page => page.language === language);
51
+ }
52
+ // or pick the best match
53
+ else {
54
+ const { defaultLanguage } = funnel_core_1.AppConfig.brandConfig().regionalization.regions[region];
55
+ return (_a = pages.find(page => page.language === defaultLanguage)) !== null && _a !== void 0 ? _a : pages[0];
56
+ }
57
+ }
41
58
  getClosestPageRef(language, fallback) {
42
59
  var _a, _b;
43
60
  const { template, languages, refs } = this;
@@ -4,7 +4,6 @@ export declare class PageSummary {
4
4
  readonly template: Schema.Page;
5
5
  readonly brand: string;
6
6
  readonly groupId: Schema.Page.GroupId;
7
- readonly region: string;
8
7
  readonly slug?: string;
9
8
  readonly pages: ReadonlyArray<PageSummary.PageRef>;
10
9
  readonly status: PageSummary.Status;
@@ -12,10 +11,10 @@ export declare class PageSummary {
12
11
  get type(): Schema.Page.Type;
13
12
  get variant(): Schema.Page.Variant;
14
13
  get hasPages(): boolean;
15
- hasLanguage(language: Language): boolean;
16
- getPage(language: Language): PageSummary.PageRef | undefined;
17
- getClosestPageRef(language: Language, fallback?: Language): IPage.Ref;
18
- isInGroup({ template, region }: PageSummary.IsInGroupArgs): boolean;
14
+ hasLanguage(region: string, language: Language): boolean;
15
+ getPage(region: string, language: Language): PageSummary.PageRef | undefined;
16
+ getClosestPageRef({ region, language, fallbackLanguage }: PageSummary.GetClosestPageRefArgs): IPage.Ref;
17
+ isInGroup({ template }: PageSummary.IsInGroupArgs): boolean;
19
18
  }
20
19
  export declare namespace PageSummary {
21
20
  type Status = 'draft' | 'ready' | 'live' | 'unpublished' | 'changed' | 'empty';
@@ -23,13 +22,16 @@ export declare namespace PageSummary {
23
22
  template: Schema.Page;
24
23
  brand: string;
25
24
  groupId: Schema.Page.GroupId;
26
- region: string;
27
25
  slug?: string;
28
26
  pages: PageSummary.PageRef[];
29
27
  };
30
28
  type PageRef = Schema.Page.Data.AsGroup.Instance & Pick<Schema.Page.Data.AsLink, 'state' | 'errors' | 'createdOn' | 'updatedOn' | 'publishedOn'>;
29
+ type GetClosestPageRefArgs = {
30
+ region: string;
31
+ language: Language;
32
+ fallbackLanguage?: Language;
33
+ };
31
34
  type IsInGroupArgs = {
32
35
  template: Schema.Page;
33
- region: string;
34
36
  };
35
37
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PageSummary = void 0;
4
4
  const funnel_core_1 = require("@nascentdigital/funnel-core");
5
+ const IPage_1 = require("./IPage");
5
6
  // class
6
7
  class PageSummary {
7
8
  constructor(args) {
@@ -9,7 +10,6 @@ class PageSummary {
9
10
  this.template = args.template;
10
11
  this.brand = args.brand;
11
12
  this.groupId = args.groupId;
12
- this.region = args.region;
13
13
  this.slug = args.slug;
14
14
  this.pages = args.pages;
15
15
  this.status = getStatus(args.pages);
@@ -23,24 +23,20 @@ class PageSummary {
23
23
  get hasPages() {
24
24
  return this.groupId !== funnel_core_1.Schema.Page.GroupId.empty;
25
25
  }
26
- hasLanguage(language) {
27
- return this.pages.some(page => page.language === language);
26
+ hasLanguage(region, language) {
27
+ return this.pages.some(page => page.region === region && page.language === language);
28
28
  }
29
- getPage(language) {
30
- return this.pages.find(page => page.language === language);
29
+ getPage(region, language) {
30
+ return this.pages.find(page => page.region === region && page.language === language);
31
31
  }
32
- getClosestPageRef(language, fallback) {
33
- var _a, _b;
34
- const { template, brand, groupId, region, pages } = this;
35
- const ref = (_b = (_a = pages.find(page => page.language === language)) !== null && _a !== void 0 ? _a : (fallback && pages.find(page => page.language === fallback))) !== null && _b !== void 0 ? _b : pages[0];
36
- return Object.assign(Object.assign({}, ref), { template,
37
- brand,
38
- groupId,
39
- region, tags: template.tags.flatMap(tagGroup => tagGroup.parse(ref.tags)) });
32
+ getClosestPageRef({ region, language, fallbackLanguage }) {
33
+ var _a, _b, _c, _d;
34
+ const { template, brand, groupId, pages } = this;
35
+ const ref = (_d = (_c = (_b = (_a = pages.find(page => page.region === region && page.language === language)) !== null && _a !== void 0 ? _a : (fallbackLanguage && pages.find(page => page.region === region && page.language === fallbackLanguage))) !== null && _b !== void 0 ? _b : pages.find(page => page.language === language)) !== null && _c !== void 0 ? _c : (fallbackLanguage && pages.find(page => page.language === fallbackLanguage))) !== null && _d !== void 0 ? _d : pages[0];
36
+ return IPage_1.IPage.Ref.fromData(Object.assign(Object.assign({}, ref), { groupId, type: template.type, brand }));
40
37
  }
41
- isInGroup({ template, region }) {
42
- return this.template.type === template.type
43
- && this.region === region;
38
+ isInGroup({ template }) {
39
+ return this.template.type === template.type;
44
40
  }
45
41
  }
46
42
  exports.PageSummary = PageSummary;
@@ -60,7 +60,6 @@ class Pages {
60
60
  const { region } = site;
61
61
  const { items: pages } = await site.repository.search({
62
62
  template,
63
- region: region.id,
64
63
  tags: tags.map(tag => tag.data),
65
64
  pagination: 'all'
66
65
  });
@@ -77,7 +76,6 @@ class Pages {
77
76
  template,
78
77
  brand: page.brand,
79
78
  groupId: page.groupId,
80
- region: region.id,
81
79
  slug: page.slug,
82
80
  pages: []
83
81
  };
@@ -88,6 +86,7 @@ class Pages {
88
86
  // add page to args
89
87
  args.pages.push({
90
88
  id: page.id,
89
+ region: page.region,
91
90
  language: page.language,
92
91
  slug: page.slug,
93
92
  name: page.name,
@@ -21,8 +21,6 @@ class Site {
21
21
  this._overviews = [];
22
22
  this._pages = new Map();
23
23
  this._pagesToSync = new Set();
24
- // start initial loading of data
25
- this.sync().catch(console.error);
26
24
  // listen to app state for page changes
27
25
  this._subscription = this.appState.pageEvents$.subscribe(e => this.onPageEvent(e));
28
26
  }
@@ -1,3 +1,3 @@
1
1
  import { ICollectionRepository } from '../repository';
2
- export declare function useCollectionRepository(): ICollectionRepository;
2
+ export declare function useCollectionRepository<TRepository extends ICollectionRepository = ICollectionRepository>(): TRepository;
3
3
  export declare const CollectionRepositoryContext: import("react").Context<ICollectionRepository>;
@@ -17,6 +17,10 @@ function usePossibleCollections() {
17
17
  if (!collections) {
18
18
  return;
19
19
  }
20
+ // sync if it's not ready
21
+ else if (collections.state === 'uninitialized') {
22
+ collections.sync().catch(console.error);
23
+ }
20
24
  // subscribe to changes
21
25
  const subscription = collections.events$.subscribe(() => touch());
22
26
  // unsubscribe on unmount
@@ -1,3 +1,3 @@
1
1
  import { IPageRepository } from '../repository';
2
- export declare function usePageRepository(): IPageRepository;
2
+ export declare function usePageRepository<TRepository extends IPageRepository = IPageRepository>(): TRepository;
3
3
  export declare const PageRepositoryContext: import("react").Context<IPageRepository>;
@@ -17,6 +17,10 @@ function usePossibleSite() {
17
17
  if (!site) {
18
18
  return;
19
19
  }
20
+ // sync if it's not ready
21
+ else if (site.state === 'uninitialized') {
22
+ site.sync().catch(console.error);
23
+ }
20
24
  // subscribe to changes
21
25
  const subscription = site.events$.subscribe(() => touch());
22
26
  // unsubscribe on unmount
@@ -1,7 +1,7 @@
1
1
  import { Schema } from '@nascentdigital/funnel-core';
2
2
  import { UpdateCollectionCommand } from '../../api/collections';
3
3
  import { EditorApiClient } from '../client';
4
- import { Collection, CollectionFieldProxy } from '../domain';
4
+ import { Collection, CollectionFieldProxy, ICollection } from '../domain';
5
5
  import { CollectionTarget } from './CollectionTarget';
6
6
  import { ICollectionRepository } from './ICollectionRepository';
7
7
  export declare class CollectionRepository implements ICollectionRepository {
@@ -26,5 +26,5 @@ export declare class CollectionRepository implements ICollectionRepository {
26
26
  getItems(args: ICollectionRepository.GetItems.Args): Promise<ICollectionRepository.GetItems.Result>;
27
27
  get(args: ICollectionRepository.Get.Args): Promise<ICollectionRepository.Get.Result>;
28
28
  update(args: ICollectionRepository.Update.Args): Promise<ICollectionRepository.Update.Result>;
29
- serializeUpdate(collection: Collection | CollectionFieldProxy, savables: ICollectionRepository.Savable[]): UpdateCollectionCommand.Data;
29
+ serializeUpdate(collection: Collection | CollectionFieldProxy, savables: ICollection.Savable[]): UpdateCollectionCommand.Data;
30
30
  }
@@ -1,5 +1,5 @@
1
1
  import { CollectionClient } from '@nascentdigital/funnel-cms';
2
- import { EventBus, FieldModel, Schema } from '@nascentdigital/funnel-core';
2
+ import { EventBus, Schema } from '@nascentdigital/funnel-core';
3
3
  import { CollectionFieldProxy, ICollection } from '../domain';
4
4
  export interface ICollectionRepository {
5
5
  create(args: ICollectionRepository.Create.Args): Promise<ICollectionRepository.Create.Result>;
@@ -11,10 +11,9 @@ export interface ICollectionRepository {
11
11
  getItems(args: ICollectionRepository.GetItems.Args): Promise<ICollectionRepository.GetItems.Result>;
12
12
  get(args: ICollectionRepository.Get.Args): Promise<ICollectionRepository.Get.Result>;
13
13
  update(args: ICollectionRepository.Update.Args): Promise<ICollectionRepository.Update.Result>;
14
- serializeUpdate(collection: ICollection | CollectionFieldProxy, savables: ICollectionRepository.Savable[]): ICollectionRepository.SerializeUpdates.Result;
14
+ serializeUpdate(collection: ICollection | CollectionFieldProxy, savables: ICollection.Savable[]): ICollectionRepository.SerializeUpdates.Result;
15
15
  }
16
16
  export declare namespace ICollectionRepository {
17
- type Savable = FieldModel;
18
17
  namespace Create {
19
18
  type Args = Omit<CollectionClient.Create.NewArgs, 'brand' | 'type' | 'version'> & {
20
19
  template: Schema.Collection;
@@ -13,7 +13,6 @@ export declare namespace IPageRepository {
13
13
  namespace Search {
14
14
  type Args = Omit<PageClient.Search.Args, 'version' | 'brand' | 'type' | 'region'> & {
15
15
  template: Schema.Page;
16
- region: string;
17
16
  };
18
17
  type Result = Pagination.Paginated<IPage.Ref>;
19
18
  }
@@ -57,7 +57,7 @@ class PageRepository {
57
57
  const { eventBus, template } = args, query = __rest(args, ["eventBus", "template"]);
58
58
  const data = await this.editorApi.createPage(Object.assign(Object.assign({}, query), { type: template.type }));
59
59
  // return page
60
- return PageSerializer_1.PageSerializer.deserializePageWithSummary(Object.assign(Object.assign({ region: data.group.region }, args), data));
60
+ return PageSerializer_1.PageSerializer.deserializePageWithSummary(Object.assign(Object.assign({}, args), data));
61
61
  }
62
62
  async save(page) {
63
63
  // get page update
@@ -1,8 +1,8 @@
1
1
  import { Field, FieldList, FieldModel, ObjectField, Schema } from '@nascentdigital/funnel-core';
2
- import { ICollectionRepository } from './ICollectionRepository';
2
+ import { ICollection } from '../domain';
3
3
  export declare namespace SerializeCollectionUpdate {
4
- function serializeFieldsUpdate(updates: Schema.Collection.Update[], fields: ReadonlyArray<FieldModel>, parentPath: ReadonlyArray<string>, savables: ICollectionRepository.Savable[]): Schema.Collection.Update[];
5
- function serializeObjectFieldUpdate(updates: Schema.Collection.Update[], field: ObjectField, parentPath: ReadonlyArray<string>, savables: ICollectionRepository.Savable[]): void;
6
- function serializeFieldUpdate(updates: Schema.Collection.Update[], field: Field, parentPath: ReadonlyArray<string>, savables: ICollectionRepository.Savable[]): void;
7
- function serializeListUpdate(updates: Schema.Collection.Update[], list: FieldList, parentPath: ReadonlyArray<string>, savables: ICollectionRepository.Savable[]): void;
4
+ function serializeFieldsUpdate(updates: Schema.Collection.Update[], fields: ReadonlyArray<FieldModel>, parentPath: ReadonlyArray<string>, savables: ICollection.Savable[]): Schema.Collection.Update[];
5
+ function serializeObjectFieldUpdate(updates: Schema.Collection.Update[], field: ObjectField, parentPath: ReadonlyArray<string>, savables: ICollection.Savable[]): void;
6
+ function serializeFieldUpdate(updates: Schema.Collection.Update[], field: Field, parentPath: ReadonlyArray<string>, savables: ICollection.Savable[]): void;
7
+ function serializeListUpdate(updates: Schema.Collection.Update[], list: FieldList, parentPath: ReadonlyArray<string>, savables: ICollection.Savable[]): void;
8
8
  }
@@ -1,11 +1,10 @@
1
1
  import { Field, FieldList, FieldModel, ObjectField, Schema } from '@nascentdigital/funnel-core';
2
- import type { Block, Section } from '../domain';
2
+ import { Block, IPage, Section } from '../domain';
3
3
  export declare namespace SerializePageUpdate {
4
- type Savable = Section | Block | FieldModel;
5
- function serializeSectionUpdate(updates: Schema.Page.Update[], section: Section, parentPath: string, savables: Savable[]): void;
6
- function serializeBlockUpdate(updates: Schema.Page.Update[], block: Block, parentPath: string, savables: Savable[]): void;
7
- function serializeFieldsUpdate(updates: Schema.Page.Update[], fields: ReadonlyArray<FieldModel>, parentPath: ReadonlyArray<string>, savables: Savable[]): Schema.Page.Update[];
8
- function serializeObjectFieldUpdate(updates: Schema.Page.Update[], field: ObjectField, parentPath: ReadonlyArray<string>, savables: Savable[]): void;
9
- function serializeFieldUpdate(updates: Schema.Page.Update[], field: Field, parentPath: ReadonlyArray<string>, savables: Savable[]): void;
10
- function serializeListUpdate(updates: Schema.Page.Update[], list: FieldList, parentPath: ReadonlyArray<string>, savables: Savable[]): void;
4
+ function serializeSectionUpdate(updates: Schema.Page.Update[], section: Section, parentPath: string, savables: IPage.Savable[]): void;
5
+ function serializeBlockUpdate(updates: Schema.Page.Update[], block: Block, parentPath: string, savables: IPage.Savable[]): void;
6
+ function serializeFieldsUpdate(updates: Schema.Page.Update[], fields: ReadonlyArray<FieldModel>, parentPath: ReadonlyArray<string>, savables: IPage.Savable[]): Schema.Page.Update[];
7
+ function serializeObjectFieldUpdate(updates: Schema.Page.Update[], field: ObjectField, parentPath: ReadonlyArray<string>, savables: IPage.Savable[]): void;
8
+ function serializeFieldUpdate(updates: Schema.Page.Update[], field: Field, parentPath: ReadonlyArray<string>, savables: IPage.Savable[]): void;
9
+ function serializeListUpdate(updates: Schema.Page.Update[], list: FieldList, parentPath: ReadonlyArray<string>, savables: IPage.Savable[]): void;
11
10
  }
@@ -1,5 +1,7 @@
1
1
  import { PropsWithChildren } from 'react';
2
- export declare function SplashContainer({ children }: SplashContainer.Props): import("react/jsx-runtime").JSX.Element;
2
+ export declare function SplashContainer({ message, children }: SplashContainer.Props): import("react/jsx-runtime").JSX.Element;
3
3
  export declare namespace SplashContainer {
4
- type Props = PropsWithChildren;
4
+ type Props = PropsWithChildren & {
5
+ message?: string;
6
+ };
5
7
  }
@@ -8,16 +8,16 @@ const Splash_1 = require("./Splash");
8
8
  const SplashContext_1 = require("./SplashContext");
9
9
  const SplashService_1 = require("./SplashService");
10
10
  // component
11
- function SplashContainer({ children }) {
11
+ function SplashContainer({ message = 'Signing you in', children }) {
12
12
  // bind hooks + memo
13
13
  const service = (0, react_2.useMemo)(() => {
14
14
  // create service
15
15
  const service = new SplashService_1.SplashService();
16
16
  // start in a loading state
17
- service.showLoading(`Signing you in`);
17
+ service.showLoading(message);
18
18
  // return service
19
19
  return service;
20
- }, []);
20
+ }, [message]);
21
21
  const [context, setContext] = (0, react_2.useState)(() => ({ service }));
22
22
  // update context on event changes
23
23
  (0, react_2.useEffect)(() => {
@@ -72,9 +72,10 @@ function renderPages({ template, groupedPages, onCreatePage, onOpenPage }) {
72
72
  }
73
73
  function groupPages(site, summaries) {
74
74
  // group pages
75
+ const { region: { id: region }, defaultLanguage: language } = site;
75
76
  const groupedPages = summaries
76
77
  // enrich summaries with links
77
- .map(summary => ({ summary, link: summary.getClosestPageRef(site.defaultLanguage) }))
78
+ .map(summary => ({ summary, link: summary.getClosestPageRef({ region, language }) }))
78
79
  // group summaries based on status
79
80
  .reduce((groupedPages, linkedSummary) => {
80
81
  // bind page to group (drop empty pages groups, which shouldn't occur)
@@ -1,10 +1,12 @@
1
1
  import { Callback } from '@nascentdigital/funnel-core';
2
+ import { ReactNode } from 'react';
2
3
  import { Block, PageSettings, Section, SectionBlock } from '../../core';
3
- export declare function BlockEditor({ className, block, onSelectItem }: BlockEditor.Props): import("react/jsx-runtime").JSX.Element | null;
4
+ export declare function BlockEditor({ className, block, headerActions, onSelectItem }: BlockEditor.Props): import("react/jsx-runtime").JSX.Element | null;
4
5
  export declare namespace BlockEditor {
5
6
  type Props = {
6
7
  className?: string;
7
8
  block: Block | SectionBlock;
9
+ headerActions?: ReactNode;
8
10
  onSelectItem: Callback<Block | SectionBlock | Section | PageSettings>;
9
11
  };
10
12
  }
@@ -10,8 +10,9 @@ const react_1 = require("react");
10
10
  const core_1 = require("../../core");
11
11
  const config_1 = require("./config");
12
12
  // component
13
- function BlockEditor({ className, block, onSelectItem }) {
13
+ function BlockEditor({ className, block, headerActions, onSelectItem }) {
14
14
  // bind props + hooks
15
+ const page = (0, core_1.usePage)();
15
16
  const dialog = (0, core_1.useDialog)();
16
17
  const menu = (0, core_1.useMenuController)(blockMenu);
17
18
  const anchorId = (0, react_1.useId)();
@@ -58,8 +59,8 @@ function BlockEditor({ className, block, onSelectItem }) {
58
59
  };
59
60
  // render editor
60
61
  const { messageFields, visualFields, listsFields, extendedFields } = block;
61
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(className, 'max-h-full h-full flex flex-col'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center px-l6 pt-l10 pb-l4", children: [(0, jsx_runtime_1.jsx)("h2", { className: "heading-lg flex-1", children: block.name }), (0, jsx_runtime_1.jsx)("div", { className: "shrink-0 flex items-center gap-l5", children: block.canDelete &&
62
- (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.IconButton, { anchorId: anchorId, className: "DeleteAction text-content-primary hover:text-destructive shrink-0", variant: "util", icon: "EllipsisVertical", onClick: e => menu.open(anchorId) }), (0, jsx_runtime_1.jsx)(core_1.Menu, { controller: menu, onItemClick: onMenuClick })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex flex-col gap-l8 px-l6 pb-l10 overflow-y-scroll scrollbar-thin scroller-fade-top bg-background", tabIndex: -1, children: [messageFields.length > 0 &&
62
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(className, 'max-h-full h-full flex flex-col'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center px-l6 pt-l10 pb-l4", children: [(0, jsx_runtime_1.jsx)("h2", { className: "heading-lg flex-1", children: (0, jsx_runtime_1.jsx)("a", { href: core_1.IPage.getPreviewUrl(page.url).href, target: `${page.brand}.preview`, children: block.name }) }), (0, jsx_runtime_1.jsxs)("div", { className: "shrink-0 flex items-center gap-l5", children: [headerActions, block.canDelete &&
63
+ (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.IconButton, { anchorId: anchorId, className: "DeleteAction text-content-primary hover:text-destructive shrink-0", variant: "util", icon: "EllipsisVertical", onClick: e => menu.open(anchorId) }), (0, jsx_runtime_1.jsx)(core_1.Menu, { controller: menu, onItemClick: onMenuClick })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex flex-col gap-l8 px-l6 pb-l10 overflow-y-scroll scrollbar-thin scroller-fade-top bg-background", tabIndex: -1, children: [messageFields.length > 0 &&
63
64
  (0, jsx_runtime_1.jsx)(core_1.FieldsPanel, { title: "Messaging", actions: (0, jsx_runtime_1.jsx)(config_1.BlockConfigButton, { target: "message" }), fields: messageFields }), visualFields.length > 0 &&
64
65
  (0, jsx_runtime_1.jsx)(core_1.FieldsPanel, { title: "Visual", actions: (0, jsx_runtime_1.jsx)(config_1.BlockConfigButton, { target: "visual" }), fields: visualFields }), listsFields.length > 0 &&
65
66
  (0, jsx_runtime_1.jsx)(core_1.FieldsPanel, { title: "List", actions: (0, jsx_runtime_1.jsx)(config_1.BlockConfigButton, { target: "list" }), fields: listsFields }), extendedFields.length > 0 &&
@@ -1,8 +1,16 @@
1
1
  import { PropsWithChildren } from 'react';
2
- import { Block, PageSettings, Section, SectionBlock } from '../../../core';
3
- export declare function BlockConfigurationProvider({ item, children }: BlockConfigurationProvider.Props): import("react/jsx-runtime").JSX.Element;
2
+ import { Observable } from 'rxjs';
3
+ import { Block, BlockConfiguration, PageSettings, Section, SectionBlock } from '../../../core';
4
+ export declare const BlockConfigurationProvider: import("react").ForwardRefExoticComponent<{
5
+ children?: import("react").ReactNode | undefined;
6
+ } & {
7
+ item?: Block | SectionBlock | Section | PageSettings;
8
+ } & import("react").RefAttributes<BlockConfigurationProvider.Ref>>;
4
9
  export declare namespace BlockConfigurationProvider {
5
10
  type Props = PropsWithChildren & {
6
11
  item?: Block | SectionBlock | Section | PageSettings;
7
12
  };
13
+ interface Ref {
14
+ readonly configuration$: Observable<BlockConfiguration | undefined>;
15
+ }
8
16
  }
@@ -1,17 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BlockConfigurationProvider = BlockConfigurationProvider;
3
+ exports.BlockConfigurationProvider = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
+ const rxjs_1 = require("rxjs");
6
7
  const core_1 = require("../../../core");
7
8
  // provider
8
- function BlockConfigurationProvider({ item, children }) {
9
+ exports.BlockConfigurationProvider = (0, react_1.forwardRef)(function BlockConfigurationProvider({ item, children }, ref) {
9
10
  // bind context
10
11
  const context = (0, react_1.useMemo)(() => ({
11
12
  configuration: item instanceof core_1.Block || item instanceof core_1.SectionBlock
12
13
  ? item.getConfiguration()
13
14
  : undefined
14
15
  }), [item]);
16
+ const configuration$ = (0, react_1.useMemo)(() => new rxjs_1.BehaviorSubject(undefined), []);
17
+ // bind interface
18
+ (0, react_1.useImperativeHandle)(ref, () => ({ configuration$ }), [configuration$]);
19
+ // sync configuration when context updates
20
+ (0, react_1.useEffect)(() => {
21
+ configuration$.next(context.configuration);
22
+ }, [configuration$, context]);
15
23
  // render
16
24
  return ((0, jsx_runtime_1.jsx)(core_1.BlockConfigurationContext.Provider, { value: context, children: children }));
17
- }
25
+ });
@@ -1,8 +1,10 @@
1
+ import { BlockLayout } from '@nascentdigital/funnel-core';
1
2
  import { BlockConfiguration } from '../../../core';
2
- export declare function BlockPreview({ className, configuration }: BlockPreview.Props): import("react/jsx-runtime").JSX.Element;
3
+ export declare function BlockPreview({ className, scope, layout }: BlockPreview.Props): import("react/jsx-runtime").JSX.Element;
3
4
  export declare namespace BlockPreview {
4
5
  type Props = {
5
6
  className?: string;
6
- configuration?: BlockConfiguration;
7
+ scope: BlockConfiguration.Scope;
8
+ layout: BlockLayout;
7
9
  };
8
10
  }
@@ -10,12 +10,11 @@ const classnames_1 = __importDefault(require("classnames"));
10
10
  const react_1 = require("motion/react");
11
11
  const preview_1 = require("./preview");
12
12
  // components
13
- function BlockPreview({ className, configuration }) {
13
+ function BlockPreview({ className, scope, layout }) {
14
14
  // bind props
15
- const { scope = 'desktop', layout } = configuration !== null && configuration !== void 0 ? configuration : {};
16
15
  const tight = scope === 'mobile'
17
- ? layout === null || layout === void 0 ? void 0 : layout.tight.mobile
18
- : layout === null || layout === void 0 ? void 0 : layout.tight.desktop;
16
+ ? layout.tight.mobile
17
+ : layout.tight.desktop;
19
18
  // render
20
19
  return ((0, jsx_runtime_1.jsx)(react_1.motion.section, { className: (0, classnames_1.default)(className, 'bg-surface2 rounded-xs interpolate-all', {
21
20
  'min-h-[100px]': !layout,
@@ -24,14 +23,9 @@ function BlockPreview({ className, configuration }) {
24
23
  'pb-l4': tight === 'above',
25
24
  'pt-l4': tight === 'below',
26
25
  'py-l4': tight === 'none'
27
- }), layoutRoot: true, layout: true, children: configuration && renderLayout({ configuration }) }));
26
+ }), layoutRoot: true, layout: true, children: renderLayout({ scope, layout }) }));
28
27
  }
29
- function renderLayout({ configuration }) {
30
- // skip if there's no layout
31
- const { scope, layout } = configuration;
32
- if (!layout) {
33
- return null;
34
- }
28
+ function renderLayout({ scope, layout }) {
35
29
  // render layout based on root type
36
30
  const mobile = scope === 'mobile';
37
31
  const { root } = layout;
@@ -1,3 +1,4 @@
1
1
  export * from './BlockConfigButton';
2
2
  export * from './BlockConfigurationProvider';
3
3
  export * from './BlockPreview';
4
+ export * from './useBlockConfiguration$';
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./BlockConfigButton"), exports);
18
18
  __exportStar(require("./BlockConfigurationProvider"), exports);
19
19
  __exportStar(require("./BlockPreview"), exports);
20
+ __exportStar(require("./useBlockConfiguration$"), exports);
@@ -0,0 +1,3 @@
1
+ import { Observable } from 'rxjs';
2
+ import { BlockConfiguration } from '../../../core';
3
+ export declare function useBlockConfiguration$(configuration$?: Observable<BlockConfiguration | undefined>): BlockConfiguration | undefined;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useBlockConfiguration$ = useBlockConfiguration$;
4
+ const react_1 = require("react");
5
+ function useBlockConfiguration$(configuration$) {
6
+ // bind hooks
7
+ const [configuration, setConfiguration] = (0, react_1.useState)();
8
+ // sync configuration
9
+ (0, react_1.useEffect)(() => {
10
+ // skip if there's no stream
11
+ if (!configuration$) {
12
+ setConfiguration(undefined);
13
+ return;
14
+ }
15
+ // watch stream and sync
16
+ const subscription = configuration$.subscribe(setConfiguration);
17
+ // stop on unmount
18
+ return () => subscription.unsubscribe();
19
+ }, [configuration$]);
20
+ // return configuration
21
+ return configuration;
22
+ }
@@ -11,12 +11,12 @@ function BlockConfigPanel() {
11
11
  const id = (0, react_1.useId)();
12
12
  const configuration = (0, core_1.useBlockConfiguration)();
13
13
  // skip if there's no config (shouldn't happen)
14
- if (!configuration || !configuration.hasPanels) {
14
+ const { scope = 'desktop', layout } = configuration !== null && configuration !== void 0 ? configuration : {};
15
+ if (!configuration || !configuration.hasPanels || !layout) {
15
16
  return null;
16
17
  }
17
18
  // render
18
- const { scope } = configuration;
19
- return ((0, jsx_runtime_1.jsx)(core_1.FadeIn, { children: (0, jsx_runtime_1.jsxs)(core_1.Popup.AnchorElement, { tag: "div", anchorId: id, className: "h-full flex flex-col gap-l6 py-l7 bg-surface1 rounded-xxl interpolate-all", children: [(0, jsx_runtime_1.jsx)(core_1.Tabs, { className: "mx-l7", variant: "highlighted", size: "sm", items: blockScopes, selectedItem: scope, onSelect: scope => configuration.scope = scope }), (0, jsx_runtime_1.jsx)(config_1.BlockPreview, { className: "self-center", configuration: configuration }), (0, jsx_runtime_1.jsx)("div", { className: "px-l7", children: (0, jsx_runtime_1.jsx)(config_1.BlockConfigButton, { anchorId: id, target: "block" }) })] }) }, "block.config"));
19
+ return ((0, jsx_runtime_1.jsx)(core_1.FadeIn, { children: (0, jsx_runtime_1.jsxs)(core_1.Popup.AnchorElement, { tag: "div", anchorId: id, className: "h-full flex flex-col gap-l6 py-l7 bg-surface1 rounded-xxl interpolate-all", children: [(0, jsx_runtime_1.jsx)(core_1.Tabs, { className: "mx-l7", variant: "highlighted", size: "sm", items: blockScopes, selectedItem: scope, onSelect: scope => configuration.scope = scope }), (0, jsx_runtime_1.jsx)(config_1.BlockPreview, { className: "self-center", scope: scope, layout: layout }), (0, jsx_runtime_1.jsx)("div", { className: "px-l7", children: (0, jsx_runtime_1.jsx)(config_1.BlockConfigButton, { anchorId: id, target: "block" }) })] }) }, "block.config"));
20
20
  }
21
21
  // helpers
22
22
  const blockScopes = [
@@ -206,11 +206,12 @@ class PageController {
206
206
  if (existingSummary
207
207
  && existingSummary.isInGroup(target)
208
208
  && existingSummary.groupId !== funnel_core_1.Schema.Page.GroupId.empty) {
209
- const { template, slug, language } = target;
209
+ const { template, slug, region, language } = target;
210
210
  result = await this.repository.createLanguage({
211
211
  template,
212
212
  groupId: existingSummary.groupId,
213
213
  slug,
214
+ region,
214
215
  language,
215
216
  eventBus
216
217
  });