@nascentdigital/funnel-editor 4.6.7 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/EditorApp.js +1 -1
  2. package/dist/EditorRoutes.js +7 -5
  3. package/dist/changesets/screens/ChangeSetViewer.js +1 -1
  4. package/dist/changesets/screens/ChangeSetsExplorer.js +1 -2
  5. package/dist/collection/hooks/CollectionController.d.ts +5 -16
  6. package/dist/collection/hooks/CollectionController.js +18 -37
  7. package/dist/collection/hooks/ICollectionController.d.ts +24 -0
  8. package/dist/collection/hooks/ICollectionController.js +20 -0
  9. package/dist/collection/hooks/index.d.ts +1 -0
  10. package/dist/collection/hooks/index.js +1 -0
  11. package/dist/collection/hooks/useCollectionController.d.ts +3 -3
  12. package/dist/collection/screens/CollectionEditor.js +2 -2
  13. package/dist/components.d.ts +15 -3
  14. package/dist/components.js +18 -3
  15. package/dist/core/components/feedback/dialog/MinimalDialogLayout.js +1 -1
  16. package/dist/core/components/fields/BooleanField.d.ts +2 -1
  17. package/dist/core/components/fields/BooleanField.js +2 -2
  18. package/dist/core/components/fields/DateField.d.ts +2 -1
  19. package/dist/core/components/fields/DateField.js +2 -2
  20. package/dist/core/components/fields/DynamicPagesEditor.d.ts +2 -1
  21. package/dist/core/components/fields/DynamicPagesEditor.js +1 -1
  22. package/dist/core/components/fields/EnumField.d.ts +2 -1
  23. package/dist/core/components/fields/EnumField.js +2 -2
  24. package/dist/core/components/fields/FieldCard.d.ts +1 -0
  25. package/dist/core/components/fields/FieldCard.js +8 -1
  26. package/dist/core/components/fields/FieldEditor.d.ts +2 -1
  27. package/dist/core/components/fields/FieldEditor.js +11 -11
  28. package/dist/core/components/fields/FieldLayout.d.ts +2 -1
  29. package/dist/core/components/fields/FieldLayout.js +3 -3
  30. package/dist/core/components/fields/ListEditor.d.ts +2 -1
  31. package/dist/core/components/fields/ListEditor.js +5 -6
  32. package/dist/core/components/fields/OptInField.d.ts +2 -1
  33. package/dist/core/components/fields/OptInField.js +43 -3
  34. package/dist/core/components/fields/RichTextEditor.js +1 -1
  35. package/dist/core/components/fields/RichTextField.d.ts +2 -1
  36. package/dist/core/components/fields/RichTextField.js +3 -5
  37. package/dist/core/components/fields/TextField.d.ts +2 -0
  38. package/dist/core/components/fields/TextField.js +2 -2
  39. package/dist/core/components/fields/TimestampField.d.ts +2 -1
  40. package/dist/core/components/fields/TimestampField.js +3 -3
  41. package/dist/core/components/fields/asset/AssetEditor.d.ts +1 -2
  42. package/dist/core/components/fields/asset/AssetEditor.js +29 -49
  43. package/dist/core/components/fields/asset/AssetPicker.js +6 -6
  44. package/dist/core/components/fields/asset/AssetUploader.d.ts +1 -2
  45. package/dist/core/components/fields/asset/AssetUploader.js +39 -35
  46. package/dist/core/components/fields/asset/preview/VideoPreview.js +16 -11
  47. package/dist/core/components/fields/asset/useAssetFields.d.ts +2 -17
  48. package/dist/core/components/fields/asset/useAssetFields.js +0 -21
  49. package/dist/core/components/fields/collection/CollectionEditor.d.ts +2 -1
  50. package/dist/core/components/fields/collection/CollectionEditor.js +18 -4
  51. package/dist/core/components/fields/collection/CollectionPicker.d.ts +2 -2
  52. package/dist/core/components/fields/collection/CollectionPicker.js +3 -4
  53. package/dist/core/components/fields/dynamicPages/PagePriorityDialog.js +1 -1
  54. package/dist/core/components/fields/embed/EmbeddedVideoEditor.d.ts +2 -2
  55. package/dist/core/components/fields/embed/EmbeddedVideoEditor.js +50 -31
  56. package/dist/core/components/fields/factories/AssetFactory.d.ts +3 -3
  57. package/dist/core/components/fields/factories/AssetFactory.js +18 -13
  58. package/dist/core/components/fields/factories/CollectionFactory.d.ts +3 -3
  59. package/dist/core/components/fields/factories/CollectionFactory.js +20 -13
  60. package/dist/core/components/fields/factories/EmbeddedVideoFactory.d.ts +3 -3
  61. package/dist/core/components/fields/factories/EmbeddedVideoFactory.js +17 -8
  62. package/dist/core/components/fields/factories/FieldValueFactory.d.ts +7 -5
  63. package/dist/core/components/fields/factories/FieldValueFactory.js +57 -13
  64. package/dist/core/components/fields/factories/LinkFactory.d.ts +3 -3
  65. package/dist/core/components/fields/factories/LinkFactory.js +17 -8
  66. package/dist/core/components/fields/factories/MediaFactory.d.ts +13 -0
  67. package/dist/core/components/fields/factories/MediaFactory.js +212 -0
  68. package/dist/core/components/fields/factories/ObjectFactory.d.ts +3 -2
  69. package/dist/core/components/fields/factories/ObjectFactory.js +16 -2
  70. package/dist/core/components/fields/factories/TextFactory.d.ts +3 -3
  71. package/dist/core/components/fields/factories/TextFactory.js +16 -10
  72. package/dist/core/components/fields/link/LinkEditor.d.ts +2 -2
  73. package/dist/core/components/fields/link/LinkEditor.js +18 -6
  74. package/dist/core/components/fields/list/CreateFieldButton.js +1 -1
  75. package/dist/core/components/fields/media/MediaCard.d.ts +7 -0
  76. package/dist/core/components/fields/media/MediaCard.js +92 -0
  77. package/dist/core/components/fields/media/MediaEditor.d.ts +36 -0
  78. package/dist/core/components/fields/media/MediaEditor.js +264 -0
  79. package/dist/core/components/fields/media/index.d.ts +2 -0
  80. package/dist/core/components/fields/media/index.js +18 -0
  81. package/dist/core/components/fields/object/ObjectEditor.d.ts +2 -1
  82. package/dist/core/components/fields/object/ObjectEditor.js +16 -2
  83. package/dist/core/components/fields/page/PagePicker.js +1 -1
  84. package/dist/core/components/interaction/Combobox.js +1 -1
  85. package/dist/core/components/interaction/MultiSelectControls.js +2 -5
  86. package/dist/core/components/interaction/Popup.d.ts +11 -7
  87. package/dist/core/components/interaction/Popup.js +8 -6
  88. package/dist/core/components/interaction/QuickEditor.js +1 -1
  89. package/dist/core/components/interaction/QuickInput.d.ts +2 -4
  90. package/dist/core/components/interaction/QuickInput.js +6 -2
  91. package/dist/core/components/interaction/QuickPicker.js +1 -1
  92. package/dist/core/components/interaction/SideSheet.js +1 -1
  93. package/dist/core/components/interaction/centersheet/CenterSheet.js +7 -1
  94. package/dist/core/components/interaction/centersheet/CenterSheetContainer.js +3 -1
  95. package/dist/core/components/interaction/menu/Menu.d.ts +8 -19
  96. package/dist/core/components/interaction/menu/Menu.js +26 -60
  97. package/dist/core/components/interaction/menu/useMenuController.d.ts +4 -2
  98. package/dist/core/components/interaction/menu/useMenuController.js +4 -1
  99. package/dist/core/components/transitions/FadeIn.js +1 -1
  100. package/dist/core/components/visuals/Icon.d.ts +1 -1
  101. package/dist/core/components/visuals/Icon.js +3 -0
  102. package/dist/core/containers/AssetRepositoryContainer.d.ts +2 -0
  103. package/dist/core/containers/AssetRepositoryContainer.js +18 -0
  104. package/dist/core/containers/CollectionRepositoryContainer.d.ts +2 -0
  105. package/dist/core/containers/CollectionRepositoryContainer.js +18 -0
  106. package/dist/core/containers/PageRepositoryContainer.d.ts +2 -0
  107. package/dist/core/containers/PageRepositoryContainer.js +18 -0
  108. package/dist/core/containers/index.d.ts +3 -0
  109. package/dist/core/containers/index.js +19 -0
  110. package/dist/core/domain/Block.js +2 -1
  111. package/dist/core/domain/BlockConfiguration.d.ts +4 -1
  112. package/dist/core/domain/BlockConfiguration.js +59 -3
  113. package/dist/core/domain/Collection.d.ts +7 -25
  114. package/dist/core/domain/Collection.js +2 -16
  115. package/dist/core/domain/CollectionBrowser.d.ts +3 -2
  116. package/dist/core/domain/CollectionBrowser.js +3 -3
  117. package/dist/core/domain/CollectionFieldProxy.d.ts +12 -8
  118. package/dist/core/domain/CollectionFieldProxy.js +15 -9
  119. package/dist/core/domain/CollectionGroup.d.ts +0 -5
  120. package/dist/core/domain/CollectionGroup.js +0 -7
  121. package/dist/core/domain/CollectionSummary.d.ts +2 -2
  122. package/dist/core/domain/Collections.d.ts +3 -3
  123. package/dist/core/domain/Collections.js +4 -6
  124. package/dist/core/domain/ICollection.d.ts +72 -0
  125. package/dist/core/domain/ICollection.js +20 -0
  126. package/dist/core/domain/IPage.d.ts +16 -1
  127. package/dist/core/domain/Page.js +2 -2
  128. package/dist/core/domain/Pages.js +4 -6
  129. package/dist/core/domain/SectionBlock.js +2 -1
  130. package/dist/core/domain/Site.d.ts +4 -4
  131. package/dist/core/domain/Site.js +3 -5
  132. package/dist/core/domain/index.d.ts +1 -1
  133. package/dist/core/domain/index.js +1 -1
  134. package/dist/core/hooks/index.d.ts +4 -3
  135. package/dist/core/hooks/index.js +4 -3
  136. package/dist/core/hooks/useAssetRepository.d.ts +3 -0
  137. package/dist/core/hooks/useAssetRepository.js +11 -0
  138. package/dist/core/hooks/useCollection.d.ts +4 -4
  139. package/dist/core/hooks/useCollectionRepository.d.ts +3 -2
  140. package/dist/core/hooks/useCollectionRepository.js +4 -4
  141. package/dist/core/hooks/useCollections.js +4 -0
  142. package/dist/core/hooks/usePageRepository.d.ts +3 -2
  143. package/dist/core/hooks/usePageRepository.js +4 -4
  144. package/dist/core/hooks/useSite.js +4 -0
  145. package/dist/core/hooks/useTempFields.d.ts +2 -3
  146. package/dist/core/index.d.ts +1 -0
  147. package/dist/core/index.js +1 -0
  148. package/dist/core/repository/AssetRepository.d.ts +10 -0
  149. package/dist/core/repository/AssetRepository.js +22 -0
  150. package/dist/core/repository/CollectionRepository.d.ts +22 -21
  151. package/dist/core/repository/CollectionRepository.js +23 -161
  152. package/dist/core/repository/CollectionSerializer.d.ts +4 -1
  153. package/dist/core/repository/CollectionSerializer.js +3 -3
  154. package/dist/core/repository/IAssetRepository.d.ts +25 -0
  155. package/dist/core/repository/ICollectionRepository.d.ts +61 -0
  156. package/dist/core/repository/ICollectionRepository.js +2 -0
  157. package/dist/core/repository/IPageRepository.d.ts +40 -0
  158. package/dist/core/repository/IPageRepository.js +2 -0
  159. package/dist/core/repository/PageRepository.d.ts +5 -8
  160. package/dist/core/repository/PageRepository.js +7 -280
  161. package/dist/core/repository/SerializeCollectionUpdate.d.ts +8 -0
  162. package/dist/core/repository/SerializeCollectionUpdate.js +168 -0
  163. package/dist/core/repository/SerializePageUpdate.d.ts +10 -0
  164. package/dist/core/repository/SerializePageUpdate.js +292 -0
  165. package/dist/core/repository/index.d.ts +4 -0
  166. package/dist/core/repository/index.js +4 -0
  167. package/dist/core/splash/SplashContainer.d.ts +4 -2
  168. package/dist/core/splash/SplashContainer.js +3 -3
  169. package/dist/dashboard/screens/Dashboard.js +1 -1
  170. package/dist/devtools/screens/Devtools.js +1 -1
  171. package/dist/explore/components/CreatePageDialog.d.ts +2 -2
  172. package/dist/explore/screens/CollectionExplorer.js +1 -1
  173. package/dist/explore/screens/CollectionsExplorer.js +1 -1
  174. package/dist/explore/screens/PageExplorer.js +1 -1
  175. package/dist/explore/screens/SiteExplorer.js +1 -1
  176. package/dist/page/components/BlockEditor.js +1 -1
  177. package/dist/page/components/SettingsEditor.js +0 -7
  178. package/dist/page/components/config/BlockConfigButton.js +71 -14
  179. package/dist/page/screens/PageEditor.js +1 -1
  180. package/dist/styles/index.css +24 -20
  181. package/dist/styles/tailwind.js +1 -0
  182. package/dist/users/screens/UserExplorer.js +1 -1
  183. package/package.json +2 -2
  184. package/dist/core/domain/TranslateSchema.d.ts +0 -7
  185. /package/dist/core/{domain/TranslateSchema.js → repository/IAssetRepository.js} +0 -0
@@ -1,13 +1,27 @@
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.ObjectFactory = ObjectFactory;
4
15
  const jsx_runtime_1 = require("react/jsx-runtime");
5
16
  const react_1 = require("react");
6
17
  const object_1 = require("../object");
7
18
  // component
8
- function ObjectFactory({ schema, field, onCommit, onCancel }) {
19
+ function ObjectFactory(_a) {
20
+ var { schema, fieldId, field, onCommit, onCancel } = _a, popupProps = __rest(_a, ["schema", "fieldId", "field", "onCommit", "onCancel"]);
9
21
  // bind refs
10
22
  const editorRef = (0, react_1.useRef)(null);
23
+ const popupPropsRef = (0, react_1.useRef)(popupProps);
24
+ popupPropsRef.current = popupProps;
11
25
  const onCommitRef = (0, react_1.useRef)(onCommit);
12
26
  onCommitRef.current = onCommit;
13
27
  const onCancelRef = (0, react_1.useRef)(onCancel);
@@ -20,7 +34,7 @@ function ObjectFactory({ schema, field, onCommit, onCancel }) {
20
34
  // start editor (cancel if dismissed)
21
35
  const value = await ((_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.edit({
22
36
  schema,
23
- field
37
+ field,
24
38
  }));
25
39
  if (!value) {
26
40
  console.debug('[ObjectFactory] editing cancelled');
@@ -1,10 +1,10 @@
1
1
  import { Callback, Schema } from '@nascentdigital/funnel-core';
2
- export declare function TextFactory({ schema, initialValue, anchor, onCommit, onCancel }: TextFactory.Props): import("react/jsx-runtime").JSX.Element;
2
+ import { Popup } from '../../interaction';
3
+ export declare function TextFactory({ schema, initialValue, onCommit, onCancel, ...popupProps }: TextFactory.Props): import("react/jsx-runtime").JSX.Element;
3
4
  export declare namespace TextFactory {
4
- type Props = {
5
+ type Props = Popup.Props.Delegated & {
5
6
  schema: Schema.TextField;
6
7
  initialValue?: Schema.Field.Data<Schema.TextField>;
7
- anchor: string;
8
8
  onCommit: Callback<Schema.Field.Data<Schema.TextField>>;
9
9
  onCancel: Callback.Void;
10
10
  };
@@ -1,4 +1,15 @@
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.TextFactory = TextFactory;
4
15
  const jsx_runtime_1 = require("react/jsx-runtime");
@@ -6,11 +17,12 @@ const funnel_core_1 = require("@nascentdigital/funnel-core");
6
17
  const react_1 = require("react");
7
18
  const interaction_1 = require("../../interaction");
8
19
  // component
9
- function TextFactory({ schema, initialValue, anchor, onCommit, onCancel }) {
20
+ function TextFactory(_a) {
21
+ var { schema, initialValue, onCommit, onCancel } = _a, popupProps = __rest(_a, ["schema", "initialValue", "onCommit", "onCancel"]);
10
22
  // bind refs
11
23
  const quickInputRef = (0, react_1.useRef)(null);
12
- const anchorRef = (0, react_1.useRef)(anchor);
13
- anchorRef.current = anchor;
24
+ const popupPropsRef = (0, react_1.useRef)(popupProps);
25
+ popupPropsRef.current = popupProps;
14
26
  const onCommitRef = (0, react_1.useRef)(onCommit);
15
27
  onCommitRef.current = onCommit;
16
28
  const onCancelRef = (0, react_1.useRef)(onCancel);
@@ -25,13 +37,7 @@ function TextFactory({ schema, initialValue, anchor, onCommit, onCancel }) {
25
37
  throw new funnel_core_1.IllegalStateError('Unable to resolve QuickInput ref');
26
38
  }
27
39
  // start editor (cancel if dismissed)
28
- const value = await quickInput.open({
29
- schema,
30
- anchor: anchorRef.current,
31
- initialValue: initialValue === null || initialValue === void 0 ? void 0 : initialValue.value,
32
- placement: 'right',
33
- anchorOffset: 2
34
- });
40
+ const value = await quickInput.open(Object.assign({ schema, initialValue: initialValue === null || initialValue === void 0 ? void 0 : initialValue.value }, (popupPropsRef.current)));
35
41
  if (!value) {
36
42
  onCancelRef.current();
37
43
  }
@@ -1,4 +1,5 @@
1
1
  import { Language, Schema } from '@nascentdigital/funnel-core';
2
+ import { Popup } from '../../interaction';
2
3
  export declare const LinkEditor: import("react").ForwardRefExoticComponent<LinkEditor.Props & import("react").RefAttributes<LinkEditor.Ref>>;
3
4
  export declare namespace LinkEditor {
4
5
  type Props = {
@@ -8,9 +9,8 @@ export declare namespace LinkEditor {
8
9
  interface Ref {
9
10
  edit(options: Options): Promise<Schema.Field.Data<Schema.LinkField> | undefined>;
10
11
  }
11
- type Options = {
12
+ type Options = Popup.Props.Delegated & {
12
13
  schema: Schema.LinkField;
13
14
  initialValue?: Schema.Field.Data<Schema.LinkField>;
14
- anchor: string;
15
15
  };
16
16
  }
@@ -1,4 +1,15 @@
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
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
15
  };
@@ -25,7 +36,7 @@ exports.LinkEditor = (0, react_1.forwardRef)(function LinkEditor({ region, langu
25
36
  const [deferral, setDeferral] = (0, react_1.useState)(undefined);
26
37
  const [schema, setSchema] = (0, react_1.useState)();
27
38
  const [initialValue, setInitialValue] = (0, react_1.useState)();
28
- const [anchor, setAnchor] = (0, react_1.useState)();
39
+ const [popupProps, setPopupProps] = (0, react_1.useState)();
29
40
  const [pickedPage, setPickedPage] = (0, react_1.useState)();
30
41
  const [pickingPage, setPickingPage] = (0, react_1.useState)(false);
31
42
  const [errorLevel, setErrorLevel] = (0, react_1.useState)('none');
@@ -48,11 +59,12 @@ exports.LinkEditor = (0, react_1.forwardRef)(function LinkEditor({ region, langu
48
59
  const pagesAvailable = allowInternal && pageStore !== undefined;
49
60
  // export service
50
61
  (0, react_1.useImperativeHandle)(ref, () => ({
51
- edit: async ({ schema, initialValue, anchor }) => {
62
+ edit: async (_a) => {
63
+ var { schema, initialValue } = _a, popupProps = __rest(_a, ["schema", "initialValue"]);
52
64
  // reset state
53
65
  setSchema(schema);
54
66
  setInitialValue(initialValue);
55
- setAnchor(anchor);
67
+ setPopupProps(popupProps);
56
68
  setPickedPage(undefined);
57
69
  setPickingPage(false);
58
70
  setErrorLevel('none');
@@ -217,11 +229,11 @@ exports.LinkEditor = (0, react_1.forwardRef)(function LinkEditor({ region, langu
217
229
  touch();
218
230
  };
219
231
  // skip if params are missing
220
- if (!anchor) {
232
+ if (!popupProps) {
221
233
  return null;
222
234
  }
223
235
  // render
224
- return ((0, jsx_runtime_1.jsxs)(interaction_1.MiniEditor, { title: `${initialValue ? 'Edit' : 'Create'} ${name}`, open: !!deferral && !deferral.isComplete, anchor: anchor, anchorOffset: 4, canSave: canSave, onSave: onSave, onClose: onCancel, disabled: pickingPage, children: [description &&
236
+ return ((0, jsx_runtime_1.jsxs)(interaction_1.MiniEditor, Object.assign({ title: `${initialValue ? 'Edit' : 'Create'} ${name}`, open: !!deferral && !deferral.isComplete, canSave: canSave, onSave: onSave, onClose: onCancel, disabled: pickingPage }, popupProps, { children: [description &&
225
237
  (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: description }), (0, jsx_runtime_1.jsxs)(FieldErrorController_1.FieldErrorController, { errorLevel: errorLevel, children: [(0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: labelField, autoFocus: true }), pickedPage
226
238
  // show picked page (if selected)
227
239
  ?
@@ -232,5 +244,5 @@ exports.LinkEditor = (0, react_1.forwardRef)(function LinkEditor({ region, langu
232
244
  ?
233
245
  (0, jsx_runtime_1.jsx)(interaction_1.IconButton, { icon: "Globe", onClick: onPickPage })
234
246
  : undefined }) }, "field.input")] }), allowInternal &&
235
- (0, jsx_runtime_1.jsx)(page_1.PagePicker, { ref: pagePickerRef, language: language })] }));
247
+ (0, jsx_runtime_1.jsx)(page_1.PagePicker, { ref: pagePickerRef, language: language })] })));
236
248
  });
@@ -39,6 +39,6 @@ function CreateFieldButton(_a) {
39
39
  setCreating(false);
40
40
  };
41
41
  // render
42
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(interaction_1.Button, Object.assign({}, props, { anchorId: id, onClick: onCreateStart, variant: "text", iconLeft: "Plus", children: children })), creating &&
42
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(interaction_1.Button, Object.assign({}, props, { anchorId: id, onClick: onCreateStart, variant: "secondary", iconLeft: "Plus", children: children })), creating &&
43
43
  (0, jsx_runtime_1.jsx)(factories_1.FieldValueFactory, { itemSchema: schema, anchor: id, onCommit: onCreate, onCancel: onCreateCancel })] }));
44
44
  }
@@ -0,0 +1,7 @@
1
+ import { Field } from '@nascentdigital/funnel-core';
2
+ import { Media } from '@nascentdigital/funnel-ui';
3
+ import type { FieldCard } from '../FieldCard';
4
+ export declare function MediaCard({ className, field, ...props }: MediaCard.Props): import("react/jsx-runtime").JSX.Element;
5
+ export declare namespace MediaCard {
6
+ type Props = FieldCard.Props.For<Field<Media.Schema>>;
7
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.MediaCard = MediaCard;
15
+ const jsx_runtime_1 = require("react/jsx-runtime");
16
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
17
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
18
+ const react_1 = require("react");
19
+ const hooks_1 = require("../../../hooks");
20
+ const AssetPreview_1 = require("../asset/AssetPreview");
21
+ const FieldCardLayout_1 = require("../FieldCardLayout");
22
+ // component
23
+ function MediaCard(_a) {
24
+ var _b;
25
+ var { className, field } = _a, props = __rest(_a, ["className", "field"]);
26
+ // bind props + hooks
27
+ const [active, setActive] = (0, react_1.useState)(false);
28
+ const collectionStore = (0, hooks_1.useCollectionStore)();
29
+ const assetStore = (0, hooks_1.useAssetStore)();
30
+ const value = (_b = field.value) === null || _b === void 0 ? void 0 : _b.value;
31
+ const media = value
32
+ ? funnel_core_1.Schema.CollectionField.Value.ForRef.filter(value)
33
+ ? collectionStore.getCollection(value.id)
34
+ : value
35
+ : undefined;
36
+ // render
37
+ return ((0, jsx_runtime_1.jsx)(FieldCardLayout_1.FieldCardLayout, Object.assign({}, props, { className: className, field: field, onActiveChanged: setActive, children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex-1 w-full h-full flex flex-col", children: renderMedia({ assetStore, media, active }) }) })));
38
+ }
39
+ function renderMedia({ assetStore, media, active }) {
40
+ var _a, _b, _c, _d, _e, _f, _g, _h;
41
+ // skip if there's no media
42
+ if (!media) {
43
+ return ((0, jsx_runtime_1.jsx)("div", { className: "flex-1" }));
44
+ }
45
+ // or image
46
+ else if (funnel_ui_1.Media.Value.isImage(media)) {
47
+ // bind props
48
+ const { image: desktopImageData, mobileImage: mobileImageData } = (_a = media.fields) !== null && _a !== void 0 ? _a : {};
49
+ const desktopImageId = (_b = desktopImageData === null || desktopImageData === void 0 ? void 0 : desktopImageData.value) === null || _b === void 0 ? void 0 : _b.id;
50
+ const desktopImage = desktopImageId
51
+ ? assetStore.getAsset(desktopImageId)
52
+ : undefined;
53
+ const mobileImageId = (_c = mobileImageData === null || mobileImageData === void 0 ? void 0 : mobileImageData.value) === null || _c === void 0 ? void 0 : _c.id;
54
+ const mobileImage = mobileImageId
55
+ ? assetStore.getAsset(mobileImageId)
56
+ : undefined;
57
+ const mobileImageUrl = (_d = mobileImage === null || mobileImage === void 0 ? void 0 : mobileImage.value) === null || _d === void 0 ? void 0 : _d.url;
58
+ // render image (crossfade)
59
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(AssetPreview_1.AssetPreview, { asset: desktopImage === null || desktopImage === void 0 ? void 0 : desktopImage.value, active: active }), mobileImageUrl &&
60
+ (0, jsx_runtime_1.jsx)("img", { className: "absolute inset-0 object-cover z-supersurface interpolate opacity-none hover:opacity-full", src: mobileImageUrl, alt: "Mobile preview" })] }));
61
+ }
62
+ // or video
63
+ else if (funnel_ui_1.Media.Value.isVideo(media)) {
64
+ // bind props
65
+ const { video, cover: coverRaw } = (_e = media.fields) !== null && _e !== void 0 ? _e : {};
66
+ const { local: localRaw, remote: remoteRaw } = video.value;
67
+ const coverId = (_f = coverRaw === null || coverRaw === void 0 ? void 0 : coverRaw.value) === null || _f === void 0 ? void 0 : _f.id;
68
+ const cover = coverId
69
+ ? assetStore.getAsset(coverId)
70
+ : undefined;
71
+ const localVideoId = (_g = localRaw === null || localRaw === void 0 ? void 0 : localRaw.value) === null || _g === void 0 ? void 0 : _g.id;
72
+ const localVideo = localVideoId
73
+ ? assetStore.getAsset(localVideoId)
74
+ : undefined;
75
+ const remoteThumbUrl = (_h = remoteRaw === null || remoteRaw === void 0 ? void 0 : remoteRaw.value) === null || _h === void 0 ? void 0 : _h.thumbUrl;
76
+ // render video
77
+ if (localVideo) {
78
+ return ((0, jsx_runtime_1.jsx)(AssetPreview_1.AssetPreview, { asset: localVideo === null || localVideo === void 0 ? void 0 : localVideo.value, active: active }));
79
+ }
80
+ // or remove
81
+ else if (remoteThumbUrl) {
82
+ return ((0, jsx_runtime_1.jsx)("img", { className: "w-full h-full object-cover", src: remoteThumbUrl, alt: "Video thumbnail preview", draggable: false }));
83
+ }
84
+ else {
85
+ return null;
86
+ }
87
+ }
88
+ // or skip (shouldn't happen
89
+ else {
90
+ return ((0, jsx_runtime_1.jsx)("div", { className: "flex-1" }));
91
+ }
92
+ }
@@ -0,0 +1,36 @@
1
+ import { Language, Schema } from '@nascentdigital/funnel-core';
2
+ import { Media } from '@nascentdigital/funnel-ui';
3
+ import { Popup } from '../../interaction';
4
+ export declare const MediaEditor: import("react").ForwardRefExoticComponent<MediaEditor.Props & import("react").RefAttributes<MediaEditor.Ref>>;
5
+ export declare namespace MediaEditor {
6
+ type Target = Target.Image | Target.LocalVideo | Target.RemoteVideo | Target.Media;
7
+ namespace Target {
8
+ type Image = {
9
+ type: 'image';
10
+ image: Schema.AssetField.LinkedValue.Image;
11
+ };
12
+ type LocalVideo = {
13
+ type: 'video.local';
14
+ video: Schema.AssetField.LinkedValue.Video;
15
+ };
16
+ type RemoteVideo = {
17
+ type: 'video.remote';
18
+ video: Schema.EmbeddedVideoField.Value;
19
+ };
20
+ type Media = {
21
+ type: 'media';
22
+ media: Media.Value;
23
+ };
24
+ }
25
+ type Props = {
26
+ language: Language;
27
+ };
28
+ interface Ref {
29
+ edit(options: Options): Promise<Result>;
30
+ }
31
+ type Options = Popup.Props.Delegated & {
32
+ schema: Media.Schema;
33
+ target: Target;
34
+ };
35
+ type Result = Media.Value | undefined;
36
+ }
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.MediaEditor = void 0;
15
+ const jsx_runtime_1 = require("react/jsx-runtime");
16
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
17
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
18
+ const framer_motion_1 = require("framer-motion");
19
+ const react_1 = require("react");
20
+ const domain_1 = require("../../../domain");
21
+ const hooks_1 = require("../../../hooks");
22
+ const feedback_1 = require("../../feedback");
23
+ const interaction_1 = require("../../interaction");
24
+ const FieldEditor_1 = require("../FieldEditor");
25
+ const FieldErrorController_1 = require("../FieldErrorController");
26
+ const OptInField_1 = require("../OptInField");
27
+ // component
28
+ exports.MediaEditor = (0, react_1.forwardRef)(function MediaEditor({ language }, ref) {
29
+ var _a, _b;
30
+ // bind props + hooks
31
+ const [deferral, setDeferral] = (0, react_1.useState)(undefined);
32
+ const [result, setResult] = (0, react_1.useState)();
33
+ const [target, setTarget] = (0, react_1.useState)();
34
+ const [popupProps, setPopupProps] = (0, react_1.useState)();
35
+ const [fieldSchema, setFieldSchema] = (0, react_1.useState)();
36
+ const [mediaSchema, setMediaSchema] = (0, react_1.useState)();
37
+ const [shared, setShared] = (0, react_1.useState)(false);
38
+ const [errorLevel, setErrorLevel] = (0, react_1.useState)('none');
39
+ const [error, setError] = (0, react_1.useState)();
40
+ const [field, setField] = (0, react_1.useState)();
41
+ const page = (0, hooks_1.usePossiblePage)();
42
+ const collection = (0, hooks_1.usePossibleCollection)();
43
+ const collectionRepository = (0, hooks_1.useCollectionRepository)();
44
+ const collectionStore = page !== null && page !== void 0 ? page : collection;
45
+ const assetStore = page !== null && page !== void 0 ? page : collection;
46
+ const dialog = (0, feedback_1.useDialog)();
47
+ const valid = (_a = field === null || field === void 0 ? void 0 : field.valid) !== null && _a !== void 0 ? _a : false;
48
+ const modified = (_b = field === null || field === void 0 ? void 0 : field.modified) !== null && _b !== void 0 ? _b : false;
49
+ // sync with field
50
+ (0, hooks_1.useCollectionFieldProxy)(field);
51
+ // export service
52
+ (0, react_1.useImperativeHandle)(ref, () => ({
53
+ edit: async (_a) => {
54
+ var { schema, target } = _a, popupProps = __rest(_a, ["schema", "target"]);
55
+ // reset state
56
+ setFieldSchema(schema);
57
+ setMediaSchema(target.type === 'image' || (target.type === 'media' && funnel_ui_1.Media.Value.isImage(target.media))
58
+ ? funnel_ui_1.Media.Image.collection
59
+ : funnel_ui_1.Media.Video.collection);
60
+ setTarget(target);
61
+ setField(undefined);
62
+ setShared(false);
63
+ setPopupProps(popupProps);
64
+ setErrorLevel('none');
65
+ setError(undefined);
66
+ // create deferral
67
+ const deferral = new funnel_core_1.Deferral();
68
+ setDeferral(deferral);
69
+ setResult(undefined);
70
+ // wait until deferral is resolved
71
+ return deferral.promise;
72
+ }
73
+ }), []);
74
+ // create field
75
+ (0, react_1.useEffect)(() => {
76
+ // ignore if schemas aren't set
77
+ if (!fieldSchema || !mediaSchema || !collectionStore || !assetStore || !target) {
78
+ return;
79
+ }
80
+ // create new field (wraps existing data for editing)
81
+ domain_1.CollectionFieldProxy
82
+ .create({
83
+ collectionRepository,
84
+ collectionStore,
85
+ assetStore,
86
+ schema: fieldSchema,
87
+ collectionSchema: mediaSchema,
88
+ language,
89
+ initialValue: target.type === 'media' ? target.media : undefined
90
+ })
91
+ .then(field => {
92
+ // bind image (if partial)
93
+ switch (target.type) {
94
+ case 'image': {
95
+ const collection = field;
96
+ const imageField = collection.getField('image');
97
+ imageField.value = funnel_core_1.Schema.AssetField.Value.toData(target.image);
98
+ break;
99
+ }
100
+ case 'video.local': {
101
+ const collection = field;
102
+ const videoField = collection.getField('video');
103
+ const typeField = videoField.getField('type');
104
+ typeField.value = funnel_core_1.Schema.EnumField.Value.toData('local');
105
+ const localVideoField = videoField.getField('local');
106
+ localVideoField.optIn();
107
+ localVideoField.value = funnel_core_1.Schema.AssetField.Value.toData(target.video);
108
+ break;
109
+ }
110
+ case 'video.remote': {
111
+ const collection = field;
112
+ const videoField = collection.getField('video');
113
+ const typeField = videoField.getField('type');
114
+ typeField.value = funnel_core_1.Schema.EnumField.Value.toData('remote');
115
+ const remoteVideoField = videoField.getField('remote');
116
+ remoteVideoField.optIn();
117
+ remoteVideoField.value = funnel_core_1.Schema.EmbeddedVideoField.Value.toData(target.video);
118
+ break;
119
+ }
120
+ }
121
+ // bind field
122
+ setField(field);
123
+ setShared(!field.isNew && field.isRef);
124
+ });
125
+ }, [language, collectionRepository, collectionStore, assetStore, fieldSchema, mediaSchema, target]);
126
+ // skip if there's no schema or value
127
+ if (!fieldSchema || !mediaSchema || !field || !target || !collectionStore || !assetStore) {
128
+ return null;
129
+ }
130
+ // helpers
131
+ const onValidate = () => {
132
+ // update error level
133
+ setErrorLevel('all');
134
+ // return validity
135
+ return valid;
136
+ };
137
+ const onSave = async () => {
138
+ // skip there's no field (should never happen)
139
+ if (!field) {
140
+ return;
141
+ }
142
+ // confirm if it's shared (skip if user bails)
143
+ if (shared) {
144
+ const confirmed = await dialog.confirm(field.isNew
145
+ ?
146
+ {
147
+ title: `Create a new ${mediaSchema.name}?`,
148
+ message: ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("p", { children: [(0, jsx_runtime_1.jsx)("b", { children: field.name }), " will be created as a shared content entry."] }), (0, jsx_runtime_1.jsxs)("p", { children: ["You will also need to go to the Collection editor in order to publish this entry before attempting to the changes to this ", page ? 'page' : 'collection', " can go live."] })] })),
149
+ confirmLabel: 'Update'
150
+ }
151
+ :
152
+ {
153
+ title: `Update shared ${mediaSchema.name}?`,
154
+ message: 'Updating this content may affect other pages.',
155
+ confirmLabel: 'Update'
156
+ });
157
+ if (!confirmed) {
158
+ return;
159
+ }
160
+ }
161
+ // TODO: handle errors
162
+ // save
163
+ await field.save(shared);
164
+ // update after closing
165
+ setResult(field.value);
166
+ };
167
+ const onCancel = async () => {
168
+ // skip there's no field (should never happen)
169
+ if (!field) {
170
+ return;
171
+ }
172
+ // confirm if there are unsaved changes
173
+ if (field.modified) {
174
+ // confirm
175
+ const confirmed = await dialog.confirm({
176
+ title: 'Are you sure?',
177
+ message: 'You have unsaved changes that you\'ll lose.',
178
+ confirmLabel: 'Yes',
179
+ destructive: true
180
+ });
181
+ // skip if user cancelled
182
+ if (!confirmed) {
183
+ return;
184
+ }
185
+ }
186
+ // set result (triggers editor to close)
187
+ setResult(null);
188
+ };
189
+ const onClosed = () => {
190
+ // skip if missing or already completed
191
+ if (!deferral || deferral.isComplete) {
192
+ console.debug('[MediaEditor/onClosed] ignoring invalid trigger');
193
+ return;
194
+ }
195
+ console.debug('[MediaEditor/onClosed] completing edit:', result);
196
+ // clear field
197
+ setFieldSchema(undefined);
198
+ setMediaSchema(undefined);
199
+ setTarget(undefined);
200
+ setField(undefined);
201
+ // complete deferral
202
+ deferral.resolve(result !== null && result !== void 0 ? result : undefined);
203
+ };
204
+ // skip if not ready
205
+ if (!popupProps) {
206
+ return null;
207
+ }
208
+ // render
209
+ return ((0, jsx_runtime_1.jsx)(interaction_1.MiniEditor, Object.assign({ className: "flex flex-col gap-l8", title: `Edit Media`, open: !!deferral && result === undefined, disableSave: !modified, canSave: onValidate, onSave: onSave, renderSaveLabel: state => state === 'saving' ? 'Updating...' : 'Update', onClose: onCancel, onClosed: onClosed }, popupProps, { children: (0, jsx_runtime_1.jsx)(hooks_1.CollectionStoreContext.Provider, { value: collectionStore, children: (0, jsx_runtime_1.jsx)(hooks_1.AssetStoreContext.Provider, { value: assetStore, children: renderFields({ field, error, errorLevel }) }) }) })));
210
+ });
211
+ function renderFields(args) {
212
+ // render image fields
213
+ let content;
214
+ const value = args.field.value;
215
+ if (funnel_ui_1.Media.Value.isImage(value)) {
216
+ content = renderImageFields(args);
217
+ }
218
+ // or video fields
219
+ else {
220
+ content = renderVideoFields(args);
221
+ }
222
+ // render
223
+ return ((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: (0, jsx_runtime_1.jsx)(FieldErrorController_1.FieldErrorController, { errorLevel: args.errorLevel, children: content }) }));
224
+ }
225
+ function renderImageFields({ field, error }) {
226
+ // resolve fields
227
+ const desktopImageField = field.getField('image');
228
+ const mobileImageField = field.getField('mobileImage');
229
+ const hasMobileImage = mobileImageField.exists;
230
+ // render
231
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!error &&
232
+ (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: hasMobileImage
233
+ ? 'The mobile version on phones and smaller displays.'
234
+ : 'Without a mobile version, this image is used at every screen size.' }), (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: desktopImageField, disableDelete: true }), hasMobileImage
235
+ ? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: mobileImageField })
236
+ : (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { className: "self-start", field: mobileImageField })] }));
237
+ }
238
+ function renderVideoFields({ field, error }) {
239
+ var _a, _b;
240
+ // resolve fields
241
+ const sourceField = field.getField('video');
242
+ const localVideoField = sourceField.getField('local');
243
+ const localVideo = (_a = localVideoField.value) === null || _a === void 0 ? void 0 : _a.value;
244
+ const remoteVideoField = sourceField.getField('remote');
245
+ const remoteVideo = (_b = remoteVideoField.value) === null || _b === void 0 ? void 0 : _b.value;
246
+ const coverField = field.getField('cover');
247
+ const hasCover = coverField.exists;
248
+ const isRemote = !localVideo;
249
+ // TODO render error if there's no video source
250
+ if (!localVideo && !remoteVideo) {
251
+ return null;
252
+ }
253
+ // render
254
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!error &&
255
+ (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: hasCover
256
+ ? 'Your cover image will be shown before the video plays, replacing the default first frame.'
257
+ : isRemote
258
+ ? 'You can customize the video cover image.'
259
+ : 'Without a cover image, a blurhash will be displayed before it plays.' }), (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: localVideo
260
+ ? localVideoField
261
+ : remoteVideoField, disableDelete: true }), coverField.exists
262
+ ? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: coverField })
263
+ : (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { className: "self-start", field: coverField })] }));
264
+ }
@@ -0,0 +1,2 @@
1
+ export * from './MediaCard';
2
+ export * from './MediaEditor';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./MediaCard"), exports);
18
+ __exportStar(require("./MediaEditor"), exports);
@@ -1,11 +1,12 @@
1
1
  import { ObjectField, Schema } from '@nascentdigital/funnel-core';
2
+ import { Popup } from '../../interaction';
2
3
  export declare const ObjectEditor: import("react").ForwardRefExoticComponent<import("react").RefAttributes<ObjectEditor.Ref>>;
3
4
  export declare namespace ObjectEditor {
4
5
  type Props = {};
5
6
  interface Ref {
6
7
  edit(options: Options): Promise<Schema.Field.Data<Schema.ObjectField> | undefined>;
7
8
  }
8
- type Options = {
9
+ type Options = Popup.Props.Delegated & {
9
10
  schema: Schema.ObjectField;
10
11
  field?: ObjectField;
11
12
  };