@nascentdigital/funnel-editor 4.5.6 → 4.6.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.
Files changed (136) hide show
  1. package/dist/collection/hooks/CollectionController.d.ts +1 -1
  2. package/dist/core/components/ColorModeToggle.js +6 -4
  3. package/dist/core/components/Header.js +3 -2
  4. package/dist/core/components/UserEditor.d.ts +2 -2
  5. package/dist/core/components/feedback/Badge.d.ts +2 -1
  6. package/dist/core/components/feedback/Badge.js +4 -3
  7. package/dist/core/components/fields/DynamicPagesEditor.js +7 -6
  8. package/dist/core/components/fields/EmptyFieldCard.js +4 -4
  9. package/dist/core/components/fields/FieldCardLayout.js +5 -5
  10. package/dist/core/components/fields/FieldHeader.js +3 -2
  11. package/dist/core/components/fields/FieldsPanel.js +4 -4
  12. package/dist/core/components/fields/FormEditor.js +5 -4
  13. package/dist/core/components/fields/asset/AssetEditor.d.ts +3 -2
  14. package/dist/core/components/fields/asset/AssetEditor.js +1 -1
  15. package/dist/core/components/fields/asset/AssetUploader.d.ts +3 -2
  16. package/dist/core/components/fields/asset/AssetUploader.js +1 -1
  17. package/dist/core/components/fields/collection/CollectionCard.js +1 -11
  18. package/dist/core/components/fields/collection/CollectionPicker.js +3 -2
  19. package/dist/core/components/fields/collection/previews/index.d.ts +0 -1
  20. package/dist/core/components/fields/collection/previews/index.js +0 -1
  21. package/dist/core/components/fields/embed/EmbeddedVideoEditor.d.ts +2 -2
  22. package/dist/core/components/fields/factories/AssetFactory.d.ts +1 -1
  23. package/dist/core/components/fields/factories/CollectionFactory.d.ts +1 -1
  24. package/dist/core/components/fields/factories/EmbeddedVideoFactory.d.ts +2 -2
  25. package/dist/core/components/fields/factories/FieldValueFactory.d.ts +1 -1
  26. package/dist/core/components/fields/factories/FieldValueFactory.js +1 -1
  27. package/dist/core/components/fields/factories/LinkFactory.d.ts +2 -2
  28. package/dist/core/components/fields/factories/TextFactory.d.ts +2 -2
  29. package/dist/core/components/fields/form/FormFieldEditor.d.ts +3 -2
  30. package/dist/core/components/fields/index.d.ts +1 -0
  31. package/dist/core/components/fields/index.js +1 -0
  32. package/dist/core/components/fields/link/LinkEditor.d.ts +2 -2
  33. package/dist/core/components/fields/link/LinkEditor.js +4 -0
  34. package/dist/core/components/fields/list/CreateFieldButton.d.ts +1 -1
  35. package/dist/core/components/fields/list/CreateFieldButton.js +4 -5
  36. package/dist/core/components/fields/list/CreateFieldCard.js +4 -4
  37. package/dist/core/components/fields/page/PagePicker.js +4 -2
  38. package/dist/core/components/fields/richtext/FloatingToolbarPlugin.js +3 -2
  39. package/dist/core/components/fields/richtext/LinkEditor.js +17 -4
  40. package/dist/core/components/fields/richtext/LinkPopup.js +11 -7
  41. package/dist/core/components/interaction/AvatarButton.d.ts +2 -1
  42. package/dist/core/components/interaction/AvatarButton.js +3 -2
  43. package/dist/core/components/interaction/Button.d.ts +2 -0
  44. package/dist/core/components/interaction/Button.js +3 -2
  45. package/dist/core/components/interaction/Combobox.js +2 -2
  46. package/dist/core/components/interaction/IconButton.d.ts +2 -0
  47. package/dist/core/components/interaction/IconButton.js +3 -2
  48. package/dist/core/components/interaction/IconLink.d.ts +1 -1
  49. package/dist/core/components/interaction/MiniEditor.d.ts +3 -2
  50. package/dist/core/components/interaction/MiniEditor.js +7 -5
  51. package/dist/core/components/interaction/Popup.d.ts +20 -15
  52. package/dist/core/components/interaction/Popup.js +63 -66
  53. package/dist/core/components/interaction/QuickInput.js +2 -0
  54. package/dist/core/components/interaction/QuickPicker.d.ts +1 -0
  55. package/dist/core/components/interaction/QuickPicker.js +5 -5
  56. package/dist/core/components/interaction/Tabs.d.ts +5 -1
  57. package/dist/core/components/interaction/Tabs.js +18 -8
  58. package/dist/core/components/interaction/menu/useMenuController.d.ts +2 -2
  59. package/dist/core/components/interaction/table/TableItem.d.ts +2 -1
  60. package/dist/core/components/interaction/table/TableItem.js +5 -3
  61. package/dist/core/components/layout/InfoPanel.js +4 -2
  62. package/dist/core/components/visuals/Icon.d.ts +1 -1
  63. package/dist/core/components/visuals/Icon.js +6 -0
  64. package/dist/core/components/visuals/index.d.ts +0 -1
  65. package/dist/core/components/visuals/index.js +0 -1
  66. package/dist/core/domain/Block.d.ts +4 -0
  67. package/dist/core/domain/Block.js +7 -0
  68. package/dist/core/domain/BlockConfiguration.d.ts +11 -3
  69. package/dist/core/domain/BlockConfiguration.js +77 -14
  70. package/dist/core/domain/CollectionBrowser.d.ts +2 -2
  71. package/dist/core/domain/CollectionFieldProxy.d.ts +7 -2
  72. package/dist/core/domain/CollectionFieldProxy.js +55 -66
  73. package/dist/core/domain/SectionBlock.d.ts +5 -0
  74. package/dist/core/domain/SectionBlock.js +15 -0
  75. package/dist/core/hooks/useBlockConfiguration.d.ts +7 -1
  76. package/dist/core/hooks/useBlockConfiguration.js +8 -1
  77. package/dist/core/hooks/usePage.d.ts +2 -2
  78. package/dist/core/hooks/usePage.js +5 -4
  79. package/dist/core/repository/CollectionRepository.js +1 -1
  80. package/dist/core/repository/CollectionSerializer.d.ts +3 -2
  81. package/dist/core/repository/CollectionSerializer.js +12 -7
  82. package/dist/core/repository/PageRepository.js +2 -2
  83. package/dist/core/repository/PageSerializer.d.ts +5 -3
  84. package/dist/core/repository/PageSerializer.js +10 -11
  85. package/dist/explore/components/CreateCollectionDialog.d.ts +2 -3
  86. package/dist/explore/components/CreateCollectionDialog.js +1 -1
  87. package/dist/explore/components/CreatePageDialog.d.ts +3 -3
  88. package/dist/explore/components/CreatePageDialog.js +2 -2
  89. package/dist/explore/screens/CollectionExplorer.js +4 -4
  90. package/dist/explore/screens/PageExplorer.js +4 -4
  91. package/dist/page/components/BlockEditor.js +10 -2
  92. package/dist/page/components/config/BlockConfigButton.d.ts +8 -0
  93. package/dist/page/components/config/BlockConfigButton.js +320 -0
  94. package/dist/page/components/config/BlockConfigurationProvider.d.ts +8 -0
  95. package/dist/page/components/config/BlockConfigurationProvider.js +17 -0
  96. package/dist/page/components/config/LegacyBlockPreview.d.ts +8 -0
  97. package/dist/page/components/config/{BlockPreview.js → LegacyBlockPreview.js} +30 -40
  98. package/dist/page/components/config/index.d.ts +3 -1
  99. package/dist/page/components/config/index.js +3 -1
  100. package/dist/page/components/index.d.ts +1 -1
  101. package/dist/page/components/index.js +1 -1
  102. package/dist/page/components/nav/NavSection.js +4 -3
  103. package/dist/page/components/panels/BlockConfigPanel.d.ts +1 -0
  104. package/dist/page/components/panels/BlockConfigPanel.js +25 -0
  105. package/dist/page/components/{PageStatus.d.ts → panels/PageStatus.d.ts} +3 -3
  106. package/dist/page/components/{PageStatus.js → panels/PageStatus.js} +10 -14
  107. package/dist/page/components/panels/index.d.ts +2 -0
  108. package/dist/page/components/{status → panels}/index.js +2 -1
  109. package/dist/page/hooks/PageController.d.ts +2 -2
  110. package/dist/page/screens/PageEditor.js +8 -1
  111. package/dist/styles/index.css +174 -56
  112. package/dist/styles/tailwind.js +7 -3
  113. package/dist/users/screens/UserExplorer.js +7 -6
  114. package/package.json +3 -2
  115. package/dist/core/components/fields/collection/previews/ClientPreview.d.ts +0 -10
  116. package/dist/core/components/fields/collection/previews/ClientPreview.js +0 -29
  117. package/dist/core/components/visuals/SkeletonLayout.d.ts +0 -9
  118. package/dist/core/components/visuals/SkeletonLayout.js +0 -429
  119. package/dist/page/components/config/BlockConfig.d.ts +0 -8
  120. package/dist/page/components/config/BlockConfig.js +0 -28
  121. package/dist/page/components/config/BlockConfigEditor.d.ts +0 -9
  122. package/dist/page/components/config/BlockConfigEditor.js +0 -114
  123. package/dist/page/components/config/BlockPreview.d.ts +0 -10
  124. package/dist/page/components/config/BlockView.d.ts +0 -4
  125. package/dist/page/components/config/BlockView.js +0 -9
  126. package/dist/page/components/config/LegacyBlockConfigEditor.d.ts +0 -9
  127. package/dist/page/components/config/LegacyBlockConfigEditor.js +0 -27
  128. package/dist/page/components/config/ListPanelEditor.d.ts +0 -8
  129. package/dist/page/components/config/ListPanelEditor.js +0 -89
  130. package/dist/page/components/config/MessagePanelEditor.d.ts +0 -8
  131. package/dist/page/components/config/MessagePanelEditor.js +0 -17
  132. package/dist/page/components/config/VisualPanelEditor.d.ts +0 -8
  133. package/dist/page/components/config/VisualPanelEditor.js +0 -76
  134. package/dist/page/components/status/index.d.ts +0 -1
  135. /package/dist/page/components/{status → panels}/AutoSave.d.ts +0 -0
  136. /package/dist/page/components/{status → panels}/AutoSave.js +0 -0
@@ -73,8 +73,8 @@ class PageRepository {
73
73
  // return new page if it was updated
74
74
  if (pageData) {
75
75
  console.debug('[PageRepository/save] received new page');
76
- const { eventBus, template, region } = page;
77
- return PageSerializer_1.PageSerializer.deserializePage(Object.assign(Object.assign({}, pageData), { eventBus, template, region }));
76
+ const { eventBus, template, region, language } = page;
77
+ return PageSerializer_1.PageSerializer.deserializePage({ flattenedPage: pageData, eventBus, target: { template, region, language } });
78
78
  }
79
79
  // or simply update the page updated stamp
80
80
  else {
@@ -5,9 +5,11 @@ export declare namespace PageSerializer {
5
5
  type DeserializePageWithSummaryArgs = Schema.Page.Data.AsGroup & PageTarget & {
6
6
  eventBus: EventBus;
7
7
  };
8
- function deserializePageWithSummary({ eventBus, group: groupData, page: pageData, ...args }: DeserializePageWithSummaryArgs): Page.WithSummary;
9
- type DeserializePageArgs = Schema.Page.Data & PageTarget & {
8
+ function deserializePageWithSummary({ eventBus, group: groupData, page: flattenedPage, ...target }: DeserializePageWithSummaryArgs): Page.WithSummary;
9
+ type DeserializePageArgs = {
10
+ flattenedPage: Schema.Page.FlattenedData;
11
+ target: PageTarget;
10
12
  eventBus: EventBus;
11
13
  };
12
- function deserializePage({ eventBus, template, tags, discover, content, files, pages, collections, snapshot, ...data }: DeserializePageArgs): Page;
14
+ function deserializePage({ flattenedPage, target, eventBus }: DeserializePageArgs): Page;
13
15
  }
@@ -20,30 +20,30 @@ const TagSerializer_1 = require("./TagSerializer");
20
20
  var PageSerializer;
21
21
  (function (PageSerializer) {
22
22
  function deserializePageWithSummary(_a) {
23
- var { eventBus, group: groupData, page: pageData } = _a, args = __rest(_a, ["eventBus", "group", "page"]);
23
+ var { eventBus, group: groupData, page: flattenedPage } = _a, target = __rest(_a, ["eventBus", "group", "page"]);
24
24
  // deserialize page (if any)
25
- const { template, region } = args;
26
- const page = pageData && deserializePage(Object.assign(Object.assign({}, pageData), { template, region, eventBus }));
25
+ const page = flattenedPage && deserializePage({ flattenedPage, target, eventBus });
27
26
  // deserialize summary
28
27
  const { brand, groupId, instances } = groupData;
29
- const summary = new domain_1.PageSummary(Object.assign(Object.assign({}, args), { brand,
28
+ const summary = new domain_1.PageSummary(Object.assign(Object.assign({}, target), { brand,
30
29
  groupId, pages: instances }));
31
30
  // return result
32
31
  return { summary, page };
33
32
  }
34
33
  PageSerializer.deserializePageWithSummary = deserializePageWithSummary;
35
- function deserializePage(_a) {
36
- var { eventBus, template, tags, discover = {}, content = {}, files = [], pages = [], collections = [], snapshot } = _a, data = __rest(_a, ["eventBus", "template", "tags", "discover", "content", "files", "pages", "collections", "snapshot"]);
34
+ function deserializePage({ flattenedPage, target, eventBus }) {
35
+ const { data, files, pages, collections } = flattenedPage;
36
+ const { snapshot, discover, content, tags } = data, dataRest = __rest(data, ["snapshot", "discover", "content", "tags"]);
37
+ const { template, region } = target;
37
38
  // determine latest snapshot (if any)
38
39
  const { discover: discoverSnapshot = {}, preview: previewSnapshot = {}, content: contentSnapshot = {} } = snapshot !== null && snapshot !== void 0 ? snapshot : {};
39
40
  // create new page using shared bus
40
- const region = data.region;
41
41
  const pageSchemas = funnel_core_1.Schema.Site.current().regions[region];
42
42
  const page = new domain_1.Page(Object.assign(Object.assign({ eventBus,
43
43
  template, tags: TagSerializer_1.TagSerializer.deserializeTags({
44
44
  groups: template.tags,
45
45
  tagsData: tags
46
- }) }, data), { discover: [
46
+ }) }, dataRest), { discover: [
47
47
  deserializeBlock({ schema: funnel_core_1.Schema.Seo, eventBus, key: 'seo', content: discover['seo'], snapshot: discoverSnapshot['seo'] })
48
48
  ], content: Object.entries(template.content).map(([key, schema]) => deserializeContent({
49
49
  key,
@@ -51,11 +51,10 @@ var PageSerializer;
51
51
  eventBus,
52
52
  content: content[key],
53
53
  snapshot: contentSnapshot[key]
54
- })), files, pages: pages.map((_a) => {
54
+ })), files: Object.values(files), pages: Object.values(pages).map((_a) => {
55
55
  var { type, tags } = _a, ref = __rest(_a, ["type", "tags"]);
56
56
  return (Object.assign(Object.assign({}, ref), { template: pageSchemas[type], tags: template.tags.flatMap(tagGroup => tagGroup.parse(tags)) }));
57
- }), collections,
58
- snapshot }));
57
+ }), collections: Object.values(collections), snapshot }));
59
58
  // repair any issues on the page
60
59
  page.repair();
61
60
  // return page
@@ -1,5 +1,4 @@
1
- import { Rect } from '@nascentdigital/funnel-core';
2
- import { Collection, CollectionBrowser } from '../../core';
1
+ import { Collection, CollectionBrowser, Popup } from '../../core';
3
2
  export declare const CreateCollectionDialog: import("react").ForwardRefExoticComponent<import("react").RefAttributes<CreateCollectionDialog.Ref>>;
4
3
  export declare namespace CreateCollectionDialog {
5
4
  type Props = {};
@@ -8,6 +7,6 @@ export declare namespace CreateCollectionDialog {
8
7
  }
9
8
  type Options = {
10
9
  collectionBrowser: CollectionBrowser;
11
- anchor: HTMLElement | Rect;
10
+ anchor: Popup.Anchor;
12
11
  };
13
12
  }
@@ -110,7 +110,7 @@ exports.CreateCollectionDialog = (0, react_1.forwardRef)(function CreateCollecti
110
110
  deferral.resolve(result !== null && result !== void 0 ? result : undefined);
111
111
  };
112
112
  // skip if we don't have any params
113
- if (!deferral || !collectionBrowser) {
113
+ if (!deferral || !collectionBrowser || !anchor) {
114
114
  return null;
115
115
  }
116
116
  // render
@@ -1,5 +1,5 @@
1
- import { Rect, Schema } from '@nascentdigital/funnel-core';
2
- import { Page, Pages, Site } from '../../core';
1
+ import { Schema } from '@nascentdigital/funnel-core';
2
+ import { Page, Pages, Popup, Site } from '../../core';
3
3
  export declare const CreatePageDialog: import("react").ForwardRefExoticComponent<import("react").RefAttributes<CreatePageDialog.Ref>>;
4
4
  export declare namespace CreatePageDialog {
5
5
  type Props = {};
@@ -10,6 +10,6 @@ export declare namespace CreatePageDialog {
10
10
  site: Site;
11
11
  template: Schema.Page;
12
12
  collection: Pages;
13
- anchor: HTMLElement | Rect;
13
+ anchor: Popup.Anchor;
14
14
  };
15
15
  }
@@ -159,11 +159,11 @@ exports.CreatePageDialog = (0, react_1.forwardRef)(function CreatePageDialog(_,
159
159
  deferral.resolve(result !== null && result !== void 0 ? result : undefined);
160
160
  };
161
161
  // skip if we don't have any params
162
- if (!deferral || !site || !template) {
162
+ if (!deferral || !site || !template || !anchor) {
163
163
  return null;
164
164
  }
165
165
  // render
166
- return ((0, jsx_runtime_1.jsxs)(core_1.MiniEditor, { className: "flex flex-col gap-l8", title: `Create new ${(_d = template.name) !== null && _d !== void 0 ? _d : 'page'}`, open: result === undefined, anchor: anchor, anchorOffset: 4, placement: "bottom-end", renderSaveLabel: state => state === 'saving' ? 'Creating...' : 'Create', canSave: onValidate, onSave: onCreate, onClose: onCancel, onClosed: onClosed, children: [(0, jsx_runtime_1.jsx)(core_1.ErrorMessage, { error: error }), (0, jsx_runtime_1.jsxs)(core_1.FieldErrorController, { errorLevel: errorLevel, children: [(0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: nameField, autoFocus: true }), (0, jsx_runtime_1.jsx)(core_1.TextField, { ref: slugFieldRef, field: slugField, onKeyDown: onSlugKeyDown }), multiLanguage &&
166
+ return ((0, jsx_runtime_1.jsxs)(core_1.MiniEditor, { className: "flex flex-col gap-l8", title: `Create new ${(_d = template.name) !== null && _d !== void 0 ? _d : 'page'}`, open: result === undefined, anchor: anchor, anchorOffset: 4, placement: "left", renderSaveLabel: state => state === 'saving' ? 'Creating...' : 'Create', canSave: onValidate, onSave: onCreate, onClose: onCancel, onClosed: onClosed, children: [(0, jsx_runtime_1.jsx)(core_1.ErrorMessage, { error: error }), (0, jsx_runtime_1.jsxs)(core_1.FieldErrorController, { errorLevel: errorLevel, children: [(0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: nameField, autoFocus: true }), (0, jsx_runtime_1.jsx)(core_1.TextField, { ref: slugFieldRef, field: slugField, onKeyDown: onSlugKeyDown }), multiLanguage &&
167
167
  (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: languageField })] })] }));
168
168
  });
169
169
  function getLanguageOptions(site) {
@@ -25,7 +25,7 @@ function CollectionExplorer({ type }) {
25
25
  }
26
26
  }, [splash, groupedCollections]);
27
27
  // helpers
28
- const onCreateCollection = async (e) => {
28
+ const onCreateCollection = async (e, anchorId) => {
29
29
  var _a;
30
30
  // ignore if template isn't bound
31
31
  if (!collectionBrowser) {
@@ -34,7 +34,7 @@ function CollectionExplorer({ type }) {
34
34
  // open dialog (skip if the page creation was cancelled)
35
35
  const collection = await ((_a = createDialogRef.current) === null || _a === void 0 ? void 0 : _a.createCollection({
36
36
  collectionBrowser,
37
- anchor: e.currentTarget
37
+ anchor: anchorId
38
38
  }));
39
39
  if (!collection) {
40
40
  return;
@@ -56,10 +56,10 @@ function renderCollections({ template, groupedCollections, onOpenLink, onCreateC
56
56
  // or render
57
57
  const { inProgress, live } = groupedCollections;
58
58
  if (inProgress.length === 0 && live.length === 0) {
59
- return ((0, jsx_runtime_1.jsxs)(core_1.EmptyState, { variant: "missing", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-sm flex flex-col items-center gap-l4 text-center text-pretty whitespace-pre", children: [(0, jsx_runtime_1.jsx)("p", { children: "It doesn't look like you've created anything yet." }), (0, jsx_runtime_1.jsx)("p", { children: "Get started by creating your first item. It's pretty simple and shouldn't take too long!" })] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { variant: "primary", onClick: onCreateCollection, children: ["Create a ", template.name] })] }, "empty"));
59
+ return ((0, jsx_runtime_1.jsxs)(core_1.EmptyState, { variant: "missing", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-sm flex flex-col items-center gap-l4 text-center text-pretty whitespace-pre", children: [(0, jsx_runtime_1.jsx)("p", { children: "It doesn't look like you've created anything yet." }), (0, jsx_runtime_1.jsx)("p", { children: "Get started by creating your first item. It's pretty simple and shouldn't take too long!" })] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { anchorId: "collection.create", variant: "primary", onClick: e => onCreateCollection(e, 'collection.create'), children: ["Create a ", template.name] })] }, "empty"));
60
60
  }
61
61
  // render pages
62
- return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap gap-l8 justify-between items-center", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "heading-lg text-content-primary", children: [template.name, " data"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { variant: "primary", iconLeft: "Plus", onClick: onCreateCollection, children: ["Create a new ", template.name] })] }), inProgress.length > 0 &&
62
+ return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap gap-l8 justify-between items-center", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "heading-lg text-content-primary", children: [template.name, " data"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { className: "collection.createNew", variant: "primary", iconLeft: "Plus", onClick: e => onCreateCollection(e, 'collection.createNew'), children: ["Create a new ", template.name] })] }), inProgress.length > 0 &&
63
63
  (0, jsx_runtime_1.jsx)(core_1.Table, { className: "flex-1", title: "Work in progress", children: inProgress.map(({ status, link }) => (0, jsx_runtime_1.jsx)(core_1.TableItem, { details: status === 'ready'
64
64
  ? (0, jsx_runtime_1.jsx)(core_1.StatusBadge, { variant: "success", label: "Ready to go" })
65
65
  : status === 'changed'
@@ -25,7 +25,7 @@ function PageExplorer({ region, page: pageType }) {
25
25
  }
26
26
  }, [splash, ready]);
27
27
  // helpers
28
- const onCreatePage = async (e) => {
28
+ const onCreatePage = async (e, anchorId) => {
29
29
  var _a;
30
30
  // skip if there are no collections (should never happen)
31
31
  if (!collection) {
@@ -36,7 +36,7 @@ function PageExplorer({ region, page: pageType }) {
36
36
  site,
37
37
  template,
38
38
  collection,
39
- anchor: e.currentTarget
39
+ anchor: anchorId
40
40
  }));
41
41
  if (!page) {
42
42
  return;
@@ -58,10 +58,10 @@ function renderPages({ template, groupedPages, onCreatePage, onOpenPage }) {
58
58
  // or show empty state if there are no pages
59
59
  const { inProgress, live, unpublished } = groupedPages;
60
60
  if (inProgress.length === 0 && live.length === 0 && unpublished.length === 0) {
61
- return ((0, jsx_runtime_1.jsxs)(core_1.EmptyState, { variant: "missing", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "heading-md text-content-primary", children: ["There are no ", template.name, " pages created yet!"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { variant: "primary", iconLeft: "Plus", onClick: onCreatePage, children: ["Create a ", template.name] })] }, "empty"));
61
+ return ((0, jsx_runtime_1.jsxs)(core_1.EmptyState, { variant: "missing", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "heading-md text-content-primary", children: ["There are no ", template.name, " pages created yet!"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { anchorId: "page-create", variant: "primary", iconLeft: "Plus", onClick: e => onCreatePage(e, 'page-create'), children: ["Create a ", template.name] })] }, "empty"));
62
62
  }
63
63
  // render pages
64
- return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap gap-l8 justify-between items-center", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "heading-lg text-content-primary", children: [template.name, " pages"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { variant: "primary", iconLeft: "Plus", onClick: onCreatePage, children: ["Create a new ", template.name] })] }), inProgress.length > 0 &&
64
+ return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap gap-l8 justify-between items-center", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "heading-lg text-content-primary", children: [template.name, " pages"] }), (0, jsx_runtime_1.jsxs)(core_1.Button, { anchorId: "page-create", variant: "primary", iconLeft: "Plus", onClick: e => onCreatePage(e, 'page-create'), children: ["Create a new ", template.name] })] }), inProgress.length > 0 &&
65
65
  (0, jsx_runtime_1.jsx)(core_1.Table, { className: "flex-1", title: "Work in progress", children: inProgress.map(({ summary: { status }, link }) => (0, jsx_runtime_1.jsx)(core_1.TableItem, { details: status === 'ready'
66
66
  ? (0, jsx_runtime_1.jsx)(core_1.StatusBadge, { variant: "success", label: "Ready to publish" })
67
67
  : status === 'changed'
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.BlockEditor = BlockEditor;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const classnames_1 = __importDefault(require("classnames"));
9
+ const react_1 = require("react");
9
10
  const core_1 = require("../../core");
10
11
  const config_1 = require("./config");
11
12
  // component
@@ -13,6 +14,8 @@ function BlockEditor({ className, block, onSelectItem }) {
13
14
  // bind props + hooks
14
15
  const dialog = (0, core_1.useDialog)();
15
16
  const menu = (0, core_1.useMenuController)(blockMenu);
17
+ const anchorId = (0, react_1.useId)();
18
+ // sync block
16
19
  (0, core_1.useBlock)(block);
17
20
  // render empty state if block isn't selected
18
21
  if (!block) {
@@ -54,8 +57,13 @@ function BlockEditor({ className, block, onSelectItem }) {
54
57
  }
55
58
  };
56
59
  // render editor
57
- return ((0, jsx_runtime_1.jsx)(core_1.FieldsPanel, { className: (0, classnames_1.default)(className, 'px-l6 py-l10'), title: block.name, actions: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(config_1.BlockConfig, { className: "shrink-0", block: block }), block.canDelete &&
58
- (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.IconButton, { className: "DeleteAction text-content-primary hover:text-destructive shrink-0", variant: "util", icon: "EllipsisVertical", onClick: e => menu.open(e.currentTarget) }), (0, jsx_runtime_1.jsx)(core_1.Menu, { controller: menu, onItemClick: onMenuClick })] })] }), fields: block.fields }));
60
+ 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", children: [messageFields.length > 0 &&
63
+ (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
+ (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
+ (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 &&
66
+ (0, jsx_runtime_1.jsx)(core_1.FieldsPanel, { fields: extendedFields })] })] }));
59
67
  }
60
68
  const blockMenu = [
61
69
  {
@@ -0,0 +1,8 @@
1
+ import { PropsWithChildren } from 'react';
2
+ export declare function BlockConfigButton({ target, children }: BlockConfigButton.Props): import("react/jsx-runtime").JSX.Element | null;
3
+ export declare namespace BlockConfigButton {
4
+ type Target = 'block' | 'message' | 'visual' | 'list';
5
+ type Props = PropsWithChildren & {
6
+ target: Target;
7
+ };
8
+ }
@@ -0,0 +1,320 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.BlockConfigButton = BlockConfigButton;
18
+ const jsx_runtime_1 = require("react/jsx-runtime");
19
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
20
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
21
+ const classnames_1 = __importDefault(require("classnames"));
22
+ const react_1 = require("motion/react");
23
+ const react_2 = require("react");
24
+ const rxjs_1 = require("rxjs");
25
+ const core_1 = require("../../../core");
26
+ const hooks_1 = require("../../hooks");
27
+ // component
28
+ function BlockConfigButton({ target, children = 'Configure' }) {
29
+ var _a;
30
+ // bind state + hooks
31
+ const [open, setOpen] = (0, react_2.useState)(false);
32
+ const anchorId = (0, react_2.useId)();
33
+ const panelLayoutPickerRef = (0, react_2.useRef)(null);
34
+ const listLayoutPickerRef = (0, react_2.useRef)(null);
35
+ const configuration = (0, core_1.useBlockConfiguration)();
36
+ const pageController = (0, hooks_1.usePageController)();
37
+ // skip if there's no config
38
+ if (!configuration) {
39
+ return null;
40
+ }
41
+ // determine popup
42
+ let size;
43
+ let placement;
44
+ let title;
45
+ let tip = undefined;
46
+ let content;
47
+ switch (target) {
48
+ case 'block': {
49
+ // helper
50
+ const onChangePanelLayout = async (e) => {
51
+ var _a;
52
+ // skip if there's no layout field (shouldn't happen)
53
+ if (!layoutField) {
54
+ return;
55
+ }
56
+ // pick new layout
57
+ const { schema: layoutSchema, value: layoutData } = layoutField;
58
+ const selectedLayout = await ((_a = panelLayoutPickerRef.current) === null || _a === void 0 ? void 0 : _a.open({
59
+ anchor: anchorId,
60
+ anchorOffset: 4,
61
+ placement: 'top',
62
+ items: Object.entries(layoutSchema.options).map(([layout, option]) => ({
63
+ id: layout,
64
+ label: option.name
65
+ })),
66
+ selectedItem: layoutData === null || layoutData === void 0 ? void 0 : layoutData.value
67
+ }));
68
+ // update if something was picked
69
+ if (selectedLayout) {
70
+ layoutField.value = funnel_core_1.Schema.EnumField.Value.toData(selectedLayout);
71
+ }
72
+ };
73
+ // set variables
74
+ size = 'sm';
75
+ placement = 'left';
76
+ title = 'Block Configuration';
77
+ // render content
78
+ const { scope, layoutField, blocksFields = [], desktopFields = [], mobileFields = [] } = configuration;
79
+ const settingsFields = scope === 'desktop'
80
+ ? desktopFields
81
+ : mobileFields;
82
+ const { options: slotOptions = [], currentIndex: slotIndex = 0 } = configuration.slotState;
83
+ content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("section", { className: "grid grid-cols-2 gap-x-l5 gap-y-l4", children: [blocksFields.length > 0 &&
84
+ (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: blocksFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-full", field: field, size: "xs" }, field.id)) }), layoutField && layoutField.schema.enum.length > 1 &&
85
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [(0, jsx_runtime_1.jsx)(core_1.FieldHeader, { label: "Layout", size: "xs" }), (0, jsx_runtime_1.jsx)(core_1.Button, { anchorId: anchorId, variant: "secondary", size: "xs", iconLeft: "LayoutTemplate", onClick: onChangePanelLayout, children: "Change" })] }), slotOptions.length > 1 &&
86
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [(0, jsx_runtime_1.jsx)(core_1.FieldHeader, { label: "Arrangement", size: "xs" }), slotOptions.length === 2
87
+ ?
88
+ (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", iconLeft: "ArrowLeftRight", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToNextSlot(), children: "Swap" })
89
+ :
90
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-l4", children: [(0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToPreviousSlot(), children: (0, jsx_runtime_1.jsx)(core_1.Icon, { variant: "ArrowLeft", size: { size: 16, strokeWidth: 1, absoluteStrokeWidth: true } }) }), (0, jsx_runtime_1.jsxs)("span", { className: "label-xs", children: [slotIndex + 1, " of ", slotOptions.length] }), (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToNextSlot(), children: (0, jsx_runtime_1.jsx)(core_1.Icon, { variant: "ArrowRight", size: { size: 16, strokeWidth: 1, absoluteStrokeWidth: true } }) })] })] }), settingsFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-full", field: field, size: "xs" }, field.id))] }), (0, jsx_runtime_1.jsx)(core_1.QuickPicker, { ref: panelLayoutPickerRef, variant: "card", title: "Pick Block Layout", description: "Select an available layout for this block.", renderItem: (item) => renderPanelLayoutItem(item) })] }));
91
+ break;
92
+ }
93
+ case 'message':
94
+ size = 'xs';
95
+ placement = 'bottom-end';
96
+ title = 'Message Configuration';
97
+ tip = 'Medium and Large are relative to this block\'s text area, not the page width.';
98
+ content = Object.values(configuration.messageFields)
99
+ .filter(funnel_core_1.Value.isDefined)
100
+ .map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: field, size: "xs" }, field.id));
101
+ break;
102
+ case 'list': {
103
+ // pull out layout from listFields
104
+ const _b = configuration.listFields, { layout: layoutField } = _b, listFields = __rest(_b, ["layout"]);
105
+ // helpers
106
+ const onChangeLayout = async (e) => {
107
+ var _a;
108
+ // skip if there's no layout field (shouldn't happen)
109
+ const layoutSchema = layoutField === null || layoutField === void 0 ? void 0 : layoutField.schema;
110
+ if (!layoutField || !layoutSchema) {
111
+ return;
112
+ }
113
+ // pick new layout
114
+ const { value: layoutData } = layoutField;
115
+ const selectedLayout = await ((_a = listLayoutPickerRef.current) === null || _a === void 0 ? void 0 : _a.open({
116
+ anchor: anchorId,
117
+ anchorOffset: 4,
118
+ placement: 'top',
119
+ items: Object.entries(layoutSchema.options).map(([layout, option]) => ({
120
+ id: layout,
121
+ label: option.name
122
+ })),
123
+ selectedItem: layoutData === null || layoutData === void 0 ? void 0 : layoutData.value
124
+ }));
125
+ // update if something was picked
126
+ if (selectedLayout) {
127
+ layoutField.value = funnel_core_1.Schema.EnumField.Value.toData(selectedLayout);
128
+ }
129
+ };
130
+ // set variables
131
+ size = 'xs';
132
+ placement = 'bottom-end';
133
+ title = 'List Configuration';
134
+ // render content
135
+ content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l4", children: [(0, jsx_runtime_1.jsx)(core_1.Button, { anchorId: anchorId, variant: "secondary", size: "xs", iconLeft: "LayoutTemplate", onClick: onChangeLayout, children: "Change" }), Object.values(listFields)
136
+ .filter(funnel_core_1.Value.isDefined)
137
+ .map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: field, size: "xs" }, field.id))] }), (0, jsx_runtime_1.jsx)(core_1.QuickPicker, { ref: listLayoutPickerRef, variant: "card", title: "Pick List Layout", description: "Select an available layout for this list.", renderItem: (item) => renderListLayoutItem(item) })] }));
138
+ break;
139
+ }
140
+ case 'visual': {
141
+ // set variables
142
+ size = 'xs';
143
+ placement = 'bottom-end';
144
+ title = 'Visual Configuration';
145
+ tip = 'Cropping changes how the image appears on your site, not your original file.';
146
+ // get fields
147
+ const { aspect: aspectField, anchor: anchorField, width: widthField, horizontalAlign: horizontalAlignField } = configuration.visualFields;
148
+ const { value } = (_a = configuration.getFieldData('visual')) !== null && _a !== void 0 ? _a : {};
149
+ const visual = funnel_core_1.Schema.AssetField.LinkedValue.Visual.filter(value)
150
+ ? value
151
+ : undefined;
152
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l9", children: [(0, jsx_runtime_1.jsxs)("section", { className: "flex flex-col gap-l4", children: [aspectField &&
153
+ (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: aspectField, size: "xs" }), anchorField
154
+ ? (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: anchorField, size: "xs" })
155
+ :
156
+ (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(core_1.FieldHeader, { label: "Anchor", size: "xs" }), (0, jsx_runtime_1.jsx)("p", { className: "label-xs text-content-secondary text-pretty", children: "Your current image size and aspect ratio don't require and anchor (there's no cropping)." })] })] }), visual && renderVisual({
157
+ configuration,
158
+ visual,
159
+ aspectField: aspectField,
160
+ anchorField: anchorField
161
+ })] }));
162
+ break;
163
+ }
164
+ default:
165
+ throw new funnel_core_1.NotImplementedError();
166
+ }
167
+ // helpers
168
+ const onSave = async () => {
169
+ // try to save
170
+ configuration.save();
171
+ // wait for page to save
172
+ await (0, rxjs_1.firstValueFrom)(pageController.saved$);
173
+ // re-sync config
174
+ configuration.reset();
175
+ // close
176
+ setOpen(false);
177
+ };
178
+ const onClosed = () => {
179
+ // reset configuration (drops changes)
180
+ configuration.reset();
181
+ };
182
+ // render
183
+ return ((0, jsx_runtime_1.jsx)(core_1.MiniEditor, { title: title, size: size, anchor: (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", onClick: () => setOpen(true), children: children }), anchorOffset: 4, placement: placement, open: open, onSave: onSave, disableSave: !configuration.modified, onClose: () => setOpen(false), onClosed: onClosed, customActions: (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", iconLeft: configuration.scope === 'mobile'
184
+ ? 'Smartphone'
185
+ : 'Monitor', onClick: () => configuration.scope = configuration.scope === 'desktop' ? 'mobile' : 'desktop', children: configuration.scope === 'mobile' ? 'Mobile' : 'Desktop' }), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l4", children: [tip &&
186
+ (0, jsx_runtime_1.jsx)(core_1.Note, { variant: "tip", size: size, children: (0, jsx_runtime_1.jsx)(funnel_ui_1.Markup, { markdown: `**Tip:** ${tip}` }) }), content] }) }));
187
+ }
188
+ function renderPanelLayoutItem(item) {
189
+ const panel = (className = 'flex-1') => ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('bg-surface-placeholder rounded-[2px]', className) }));
190
+ const panelPaddedX = 'px-l4';
191
+ const panelPaddedY = 'py-l4';
192
+ const panelPadded = (0, classnames_1.default)(panelPaddedX, panelPaddedY);
193
+ const panelGap = 'gap-l1';
194
+ const nestedPanel = (config = {}) => {
195
+ // unpack config
196
+ const { panelClassName, nestedPanelClassName, multipleItems = false } = config;
197
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex h-full bg-surface-placeholder rounded-[2px]', panelClassName, panelGap, { 'p-l2': multipleItems }), children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('flex-1 bg-surface-placeholder-raised rounded-[2px]', nestedPanelClassName, { 'm-l2': !multipleItems }) }), multipleItems &&
198
+ (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('flex-1 bg-surface-placeholder-raised rounded-[2px]', nestedPanelClassName) })] }));
199
+ };
200
+ switch (item.id) {
201
+ case 'solo':
202
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('size-full', panelPadded), children: panel('size-full') }));
203
+ case 'stack.v':
204
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex flex-col h-full", panelPadded, panelGap), children: [panel(), panel()] }));
205
+ case 'stack.h':
206
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex h-full", panelPadded, panelGap), children: [panel(), panel()] }));
207
+ case 'brick.v':
208
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex flex-col h-full", panelPadded, panelGap), children: [panel(), panel(), panel()] }));
209
+ case 'brick.t':
210
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex flex-col h-full", panelPadded, panelGap), children: [panel('flex-1 w-full h-[20px]'), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex flex-1', panelGap), children: [panel(), panel()] })] }));
211
+ case 'brick.r':
212
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex h-full', panelPadded, panelGap), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex h-full flex-1 flex-col', panelGap), children: [panel(), panel()] }), panel('h-full w-[30px]')] }));
213
+ case 'brick.b':
214
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex flex-col h-full", panelPadded, panelGap), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex flex-1', panelGap), children: [panel(), panel()] }), panel('flex-1 w-full h-[20px]')] }));
215
+ case 'brick.l':
216
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex h-full', panelPadded, panelGap), children: [panel('h-full w-[30px]'), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex h-full flex-1 flex-col', panelGap), children: [panel(), panel()] })] }));
217
+ case 'nested':
218
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('size-full', panelPadded), children: nestedPanel() }));
219
+ case 'nested.v':
220
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('size-full', panelPadded), children: nestedPanel({ panelClassName: 'flex-col', multipleItems: true }) }));
221
+ case 'nested.h':
222
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('size-full', panelPadded), children: nestedPanel({ multipleItems: true }) }));
223
+ case 'nested.t':
224
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex h-full flex-col", panelPadded, panelGap), children: [nestedPanel({ panelClassName: 'flex-1' }), panel()] }));
225
+ case 'nested.r':
226
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex h-full", panelPadded, panelGap), children: [panel(), nestedPanel({ panelClassName: 'flex-1' })] }));
227
+ case 'nested.b':
228
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex h-full flex-col", panelPadded, panelGap), children: [panel(), nestedPanel({ panelClassName: 'flex-1' })] }));
229
+ case 'nested.l':
230
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)("flex h-full", panelPadded, panelGap), children: [nestedPanel({ panelClassName: 'flex-1' }), panel()] }));
231
+ default:
232
+ return ((0, jsx_runtime_1.jsx)("div", { children: item.id }));
233
+ }
234
+ }
235
+ function renderListLayoutItem(item) {
236
+ // panel
237
+ const panel = (className = 'w-full') => ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('bg-surface-placeholder-raised rounded-[2px]', className) }));
238
+ // get content
239
+ const panelClassName = 'w-full h-full';
240
+ const panelPaddedX = 'px-10';
241
+ const panelPaddedY = 'py-10';
242
+ const panelPadded = (0, classnames_1.default)(panelPaddedX, panelPaddedY);
243
+ let content;
244
+ switch (item.id) {
245
+ case 'card':
246
+ case 'grid':
247
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPadded, 'grid grid-cols-3 auto-cols-fr gap-x-l3 gap-y-l2 '), children: [panel(), panel(), panel(), panel(), panel()] }));
248
+ break;
249
+ case 'flexWrap':
250
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPadded, 'flex flex-wrap justify-center items-center gap-l3'), children: [panel('w-12 h-12'), panel('w-12 h-12'), panel('w-12 h-12'), panel('w-12 h-12'), panel('w-12 h-12')] }));
251
+ break;
252
+ case 'verticalStack':
253
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPadded, 'grid grid-cols-1 auto-rows-fr gap-y-l2 '), children: [panel(), panel(), panel()] }));
254
+ break;
255
+ case 'horizontalStack':
256
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPadded, 'grid grid-rows-1 auto-cols-fr grid-flow-col gap-x-l3 '), children: [panel(), panel(), panel()] }));
257
+ break;
258
+ case 'masonry':
259
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPaddedX, 'grid grid-cols-3 grid-flow-col gap-x-l3 pt-10'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [panel('h-l5'), panel('h-l6'), panel('h-l5')] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [panel('h-22'), panel('h-l6')] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [panel('h-l4'), panel('h-l7'), panel('h-l5')] })] }));
260
+ break;
261
+ case 'bento':
262
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPadded, 'grid auto-rows-auto auto-cols-auto gap-l3'), children: [panel('w-20 row-start-1 row-span-2 col-start-1'), panel('w-28 row-start-1 col-start-2'), panel('w-18 row-start-2 col-start-2')] }));
263
+ break;
264
+ case 'brick':
265
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPaddedX, 'grid grid-cols-2 gap-l3 pt-10'), children: [panel('h-12 row-start-1 col-span-full'), panel('h-12 row-start-2 col-start-1'), panel('h-12 row-start-2 col-start-2'), panel('h-12 row-start-3 col-span-full')] }));
266
+ break;
267
+ case 'brickFlipped':
268
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, panelPaddedX, 'grid grid-cols-2 gap-l3 pt-10'), children: [panel('h-12 row-start-1 col-start-1'), panel('h-12 row-start-1 col-start-2'), panel('h-12 row-start-2 col-span-full'), panel('h-12 row-start-3 col-start-1'), panel('h-12 row-start-3 col-start-2')] }));
269
+ break;
270
+ case 'carousel':
271
+ content = ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, 'flex flex-col gap-l2 pt-10 pb-l3'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex items-stretch gap-l3", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-8 bg-surface-placeholder rounded-r-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder-raised rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "w-8 bg-surface-placeholder rounded-l-[2px]" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center items-center gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-4 h-4 bg-surface-placeholder-raised rounded-full" }), (0, jsx_runtime_1.jsx)("div", { className: "w-4 h-4 bg-surface-placeholder-raised rounded-full" }), (0, jsx_runtime_1.jsx)("div", { className: "w-4 h-4 bg-surface-placeholder-raised rounded-full" })] })] }));
272
+ break;
273
+ default:
274
+ content = ((0, jsx_runtime_1.jsx)("div", { children: item.id }));
275
+ break;
276
+ }
277
+ // render item in frame
278
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('w-full h-full flex justify-center items-center'), children: content }));
279
+ }
280
+ function renderVisual({ configuration, visual, aspectField, anchorField }) {
281
+ var _a, _b, _c;
282
+ // determine layout info
283
+ const { metadata, name, description } = visual;
284
+ const { dimensions: { width, height } } = metadata;
285
+ const isPortrait = width < height;
286
+ const aspect = (_b = (_a = aspectField === null || aspectField === void 0 ? void 0 : aspectField.value) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 'auto';
287
+ const anchor = (_c = anchorField === null || anchorField === void 0 ? void 0 : anchorField.value) === null || _c === void 0 ? void 0 : _c.value;
288
+ const anchorDirection = anchorField
289
+ ? anchorField.schema.isValidOption('left')
290
+ ? 'x'
291
+ : 'y'
292
+ : undefined;
293
+ // render
294
+ return ((0, jsx_runtime_1.jsx)("section", { className: (0, classnames_1.default)('w-full h-[210px]', 'flex flex-col justify-center items-center', 'bg-background rounded-xs'), children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('relative bg-destructive', {
295
+ 'h-full max-h-full w-auto': isPortrait,
296
+ 'w-full': !isPortrait
297
+ }), children: [funnel_core_1.Schema.AssetField.LinkedValue.Image.filter(visual)
298
+ ? renderImage({ configuration, visual })
299
+ : renderVideo({ configuration, visual }), aspect !== 'auto' && anchor && anchorDirection &&
300
+ (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('absolute inset-0 z-supersurface flex', {
301
+ 'flex-col': anchorDirection === 'y'
302
+ }), children: (0, jsx_runtime_1.jsxs)(react_1.AnimatePresence, { mode: "popLayout", children: [anchor !== 'left' && anchor !== 'top' &&
303
+ (0, jsx_runtime_1.jsx)(react_1.motion.div, { className: "flex-1 bg-content-button-contrast/backdrop", layout: true, variants: core_1.Animate.Variants.fade, initial: "initial", animate: "animate", exit: "exit" }, "crop.start"), (0, jsx_runtime_1.jsx)(react_1.motion.div, { className: (0, classnames_1.default)('shrink-0 outline outline-1 outline-ix-primary', {
304
+ 'h-full w-auto': anchorDirection === 'x',
305
+ 'w-full h-auto': anchorDirection === 'y',
306
+ 'aspect-square': aspect === 'square',
307
+ 'aspect-phone': aspect === 'phone',
308
+ 'aspect-tv': aspect === 'tv',
309
+ 'aspect-widescreen': aspect === 'widescreen',
310
+ 'aspect-cinema': aspect === 'cinema'
311
+ }), layout: true }, "visible"), anchor !== 'right' && anchor !== 'bottom' &&
312
+ (0, jsx_runtime_1.jsx)(react_1.motion.div, { className: "flex-1 bg-content-button-contrast/backdrop", layout: true, variants: core_1.Animate.Variants.fade, initial: "initial", animate: "animate", exit: "exit" }, "crop.end")] }) })] }) }));
313
+ }
314
+ function renderImage({ visual }) {
315
+ var _a;
316
+ return ((0, jsx_runtime_1.jsx)("img", { className: "max-w-full max-h-full", src: visual.url, alt: (_a = visual.description) !== null && _a !== void 0 ? _a : visual.name }));
317
+ }
318
+ function renderVideo({ visual }) {
319
+ return ((0, jsx_runtime_1.jsx)("video", { className: "max-w-full max-h-full", src: visual.url, autoPlay: true, muted: true, loop: true, playsInline: true }));
320
+ }
@@ -0,0 +1,8 @@
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;
4
+ export declare namespace BlockConfigurationProvider {
5
+ type Props = PropsWithChildren & {
6
+ item?: Block | SectionBlock | Section | PageSettings;
7
+ };
8
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BlockConfigurationProvider = BlockConfigurationProvider;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const core_1 = require("../../../core");
7
+ // provider
8
+ function BlockConfigurationProvider({ item, children }) {
9
+ // bind context
10
+ const context = (0, react_1.useMemo)(() => ({
11
+ configuration: item instanceof core_1.Block || item instanceof core_1.SectionBlock
12
+ ? item.getConfiguration()
13
+ : undefined
14
+ }), [item]);
15
+ // render
16
+ return ((0, jsx_runtime_1.jsx)(core_1.BlockConfigurationContext.Provider, { value: context, children: children }));
17
+ }