@nascentdigital/funnel-editor 4.6.1 → 5.0.1

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 (209) 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 +20 -0
  14. package/dist/components.js +41 -0
  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 +2 -2
  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.js +12 -44
  42. package/dist/core/components/fields/asset/AssetPicker.js +6 -6
  43. package/dist/core/components/fields/asset/AssetUploader.js +23 -31
  44. package/dist/core/components/fields/asset/preview/VideoPreview.js +16 -11
  45. package/dist/core/components/fields/asset/useAssetFields.d.ts +2 -17
  46. package/dist/core/components/fields/asset/useAssetFields.js +0 -21
  47. package/dist/core/components/fields/collection/CollectionEditor.js +1 -1
  48. package/dist/core/components/fields/collection/CollectionPicker.d.ts +2 -2
  49. package/dist/core/components/fields/collection/CollectionPicker.js +3 -4
  50. package/dist/core/components/fields/dynamicPages/PagePriorityDialog.js +1 -1
  51. package/dist/core/components/fields/embed/EmbeddedVideoEditor.js +34 -27
  52. package/dist/core/components/fields/factories/FieldValueFactory.js +11 -4
  53. package/dist/core/components/fields/factories/MediaFactory.d.ts +13 -0
  54. package/dist/core/components/fields/factories/MediaFactory.js +256 -0
  55. package/dist/core/components/fields/list/CreateFieldButton.js +1 -1
  56. package/dist/core/components/fields/media/MediaCard.d.ts +7 -0
  57. package/dist/core/components/fields/media/MediaCard.js +92 -0
  58. package/dist/core/components/fields/media/MediaEditor.d.ts +37 -0
  59. package/dist/core/components/fields/media/MediaEditor.js +235 -0
  60. package/dist/core/components/fields/media/MediaPicker.d.ts +15 -0
  61. package/dist/core/components/fields/media/MediaPicker.js +251 -0
  62. package/dist/core/components/fields/media/index.d.ts +3 -0
  63. package/dist/core/components/fields/media/index.js +19 -0
  64. package/dist/core/components/fields/object/ObjectEditor.js +1 -1
  65. package/dist/core/components/fields/page/PagePicker.d.ts +2 -2
  66. package/dist/core/components/fields/page/PagePicker.js +1 -1
  67. package/dist/core/components/interaction/Combobox.js +1 -1
  68. package/dist/core/components/interaction/DateTimePicker.d.ts +0 -1
  69. package/dist/core/components/interaction/DateTimePicker.js +0 -2
  70. package/dist/core/components/interaction/MultiSelectControls.js +2 -5
  71. package/dist/core/components/interaction/Popup.js +1 -0
  72. package/dist/core/components/interaction/QuickEditor.js +1 -1
  73. package/dist/core/components/interaction/QuickPicker.js +1 -1
  74. package/dist/core/components/interaction/SideSheet.js +1 -1
  75. package/dist/core/components/interaction/centersheet/CenterSheet.js +7 -1
  76. package/dist/core/components/interaction/centersheet/CenterSheetContainer.js +3 -1
  77. package/dist/core/components/transitions/FadeIn.js +2 -14
  78. package/dist/core/components/visuals/Icon.d.ts +1 -1
  79. package/dist/core/components/visuals/Icon.js +3 -0
  80. package/dist/core/containers/AssetRepositoryContainer.d.ts +2 -0
  81. package/dist/core/containers/AssetRepositoryContainer.js +18 -0
  82. package/dist/core/containers/CollectionRepositoryContainer.d.ts +2 -0
  83. package/dist/core/containers/CollectionRepositoryContainer.js +18 -0
  84. package/dist/core/containers/PageRepositoryContainer.d.ts +2 -0
  85. package/dist/core/containers/PageRepositoryContainer.js +18 -0
  86. package/dist/core/containers/index.d.ts +3 -0
  87. package/dist/core/containers/index.js +19 -0
  88. package/dist/core/domain/Block.d.ts +1 -0
  89. package/dist/core/domain/Block.js +8 -5
  90. package/dist/core/domain/BlockConfiguration.d.ts +4 -1
  91. package/dist/core/domain/BlockConfiguration.js +64 -3
  92. package/dist/core/domain/Collection.d.ts +10 -28
  93. package/dist/core/domain/Collection.js +2 -16
  94. package/dist/core/domain/CollectionBrowser.d.ts +3 -2
  95. package/dist/core/domain/CollectionBrowser.js +3 -3
  96. package/dist/core/domain/CollectionFieldProxy.d.ts +12 -8
  97. package/dist/core/domain/CollectionFieldProxy.js +14 -8
  98. package/dist/core/domain/CollectionGroup.d.ts +0 -5
  99. package/dist/core/domain/CollectionGroup.js +0 -7
  100. package/dist/core/domain/CollectionSummary.d.ts +2 -2
  101. package/dist/core/domain/Collections.d.ts +3 -3
  102. package/dist/core/domain/Collections.js +4 -4
  103. package/dist/core/domain/ICollection.d.ts +71 -0
  104. package/dist/core/domain/ICollection.js +20 -0
  105. package/dist/core/domain/IPage.d.ts +72 -0
  106. package/dist/core/domain/IPage.js +20 -0
  107. package/dist/core/domain/IPageRefStore.d.ts +3 -3
  108. package/dist/core/domain/ItemBase.d.ts +6 -6
  109. package/dist/core/domain/ItemBase.js +5 -5
  110. package/dist/core/domain/Page.d.ts +9 -22
  111. package/dist/core/domain/Page.js +3 -18
  112. package/dist/core/domain/PageOverview.d.ts +2 -2
  113. package/dist/core/domain/PageRefStoreProxy.d.ts +4 -4
  114. package/dist/core/domain/PageSettings.d.ts +3 -3
  115. package/dist/core/domain/PageSummary.d.ts +2 -2
  116. package/dist/core/domain/Pages.js +4 -6
  117. package/dist/core/domain/SectionBlock.js +2 -1
  118. package/dist/core/domain/Site.d.ts +4 -4
  119. package/dist/core/domain/Site.js +3 -3
  120. package/dist/core/domain/index.d.ts +2 -1
  121. package/dist/core/domain/index.js +2 -1
  122. package/dist/core/hooks/index.d.ts +4 -3
  123. package/dist/core/hooks/index.js +4 -3
  124. package/dist/core/hooks/useAssetRepository.d.ts +3 -0
  125. package/dist/core/hooks/useAssetRepository.js +11 -0
  126. package/dist/core/hooks/useCollection.d.ts +4 -4
  127. package/dist/core/hooks/useCollectionRepository.d.ts +3 -2
  128. package/dist/core/hooks/useCollectionRepository.js +4 -4
  129. package/dist/core/hooks/usePage.d.ts +4 -4
  130. package/dist/core/hooks/usePageRef.d.ts +1 -1
  131. package/dist/core/hooks/usePageRepository.d.ts +3 -2
  132. package/dist/core/hooks/usePageRepository.js +4 -4
  133. package/dist/core/hooks/useTempFields.d.ts +2 -3
  134. package/dist/core/index.d.ts +1 -0
  135. package/dist/core/index.js +1 -0
  136. package/dist/core/repository/AssetRepository.d.ts +10 -0
  137. package/dist/core/repository/AssetRepository.js +22 -0
  138. package/dist/core/repository/CollectionRepository.d.ts +21 -20
  139. package/dist/core/repository/CollectionRepository.js +23 -161
  140. package/dist/core/repository/CollectionSerializer.d.ts +4 -1
  141. package/dist/core/repository/CollectionSerializer.js +3 -3
  142. package/dist/core/repository/IAssetRepository.d.ts +25 -0
  143. package/dist/core/repository/ICollectionRepository.d.ts +62 -0
  144. package/dist/core/repository/ICollectionRepository.js +2 -0
  145. package/dist/core/repository/IPageRepository.d.ts +40 -0
  146. package/dist/core/repository/IPageRepository.js +2 -0
  147. package/dist/core/repository/PageRepository.d.ts +6 -9
  148. package/dist/core/repository/PageRepository.js +7 -280
  149. package/dist/core/repository/PageSerializer.d.ts +34 -1
  150. package/dist/core/repository/PageSerializer.js +4 -0
  151. package/dist/core/repository/SerializeCollectionUpdate.d.ts +8 -0
  152. package/dist/core/repository/SerializeCollectionUpdate.js +168 -0
  153. package/dist/core/repository/SerializePageUpdate.d.ts +11 -0
  154. package/dist/core/repository/SerializePageUpdate.js +292 -0
  155. package/dist/core/repository/index.d.ts +4 -0
  156. package/dist/core/repository/index.js +4 -0
  157. package/dist/dashboard/screens/Dashboard.js +1 -1
  158. package/dist/devtools/screens/Devtools.js +1 -1
  159. package/dist/explore/components/CreatePageDialog.d.ts +2 -2
  160. package/dist/explore/screens/CollectionExplorer.js +1 -1
  161. package/dist/explore/screens/CollectionsExplorer.js +1 -1
  162. package/dist/explore/screens/PageExplorer.js +1 -1
  163. package/dist/explore/screens/SiteExplorer.js +1 -1
  164. package/dist/page/components/BlockEditor.js +1 -1
  165. package/dist/page/components/PageHeader.d.ts +2 -2
  166. package/dist/page/components/PageNotCreated.d.ts +2 -2
  167. package/dist/page/components/PageNotFound.d.ts +2 -2
  168. package/dist/page/components/SettingsEditor.js +0 -7
  169. package/dist/page/components/config/BlockConfigButton.d.ts +2 -1
  170. package/dist/page/components/config/BlockConfigButton.js +84 -24
  171. package/dist/page/components/config/BlockPreview.d.ts +8 -0
  172. package/dist/page/components/config/BlockPreview.js +53 -0
  173. package/dist/page/components/config/index.d.ts +1 -1
  174. package/dist/page/components/config/index.js +1 -1
  175. package/dist/page/components/config/preview/ColumnLayout.d.ts +10 -0
  176. package/dist/page/components/config/preview/ColumnLayout.js +15 -0
  177. package/dist/page/components/config/preview/ItemLayout.d.ts +12 -0
  178. package/dist/page/components/config/preview/ItemLayout.js +45 -0
  179. package/dist/page/components/config/preview/ListPanel.d.ts +12 -0
  180. package/dist/page/components/config/preview/ListPanel.js +14 -0
  181. package/dist/page/components/config/preview/MessagePanel.d.ts +12 -0
  182. package/dist/page/components/config/preview/MessagePanel.js +21 -0
  183. package/dist/page/components/config/preview/Panel.d.ts +15 -0
  184. package/dist/page/components/config/preview/Panel.js +74 -0
  185. package/dist/page/components/config/preview/RowLayout.d.ts +10 -0
  186. package/dist/page/components/config/preview/RowLayout.js +26 -0
  187. package/dist/page/components/config/preview/StackLayout.d.ts +10 -0
  188. package/dist/page/components/config/preview/StackLayout.js +15 -0
  189. package/dist/page/components/config/preview/VisualPanel.d.ts +12 -0
  190. package/dist/page/components/config/preview/VisualPanel.js +27 -0
  191. package/dist/page/components/config/preview/index.d.ts +3 -0
  192. package/dist/page/components/config/preview/index.js +19 -0
  193. package/dist/page/components/panels/BlockConfigPanel.js +4 -4
  194. package/dist/page/hooks/IPageController.d.ts +42 -0
  195. package/dist/page/hooks/IPageController.js +32 -0
  196. package/dist/page/hooks/PageController.d.ts +11 -36
  197. package/dist/page/hooks/PageController.js +7 -33
  198. package/dist/page/hooks/index.d.ts +1 -0
  199. package/dist/page/hooks/index.js +1 -0
  200. package/dist/page/hooks/usePageController.d.ts +3 -3
  201. package/dist/page/screens/PageEditor.js +1 -1
  202. package/dist/styles/index.css +809 -60
  203. package/dist/styles/tailwind.js +1 -0
  204. package/dist/users/screens/UserExplorer.js +1 -1
  205. package/package.json +3 -2
  206. package/dist/core/domain/TranslateSchema.d.ts +0 -7
  207. package/dist/page/components/config/LegacyBlockPreview.d.ts +0 -8
  208. package/dist/page/components/config/LegacyBlockPreview.js +0 -452
  209. /package/dist/core/{domain/TranslateSchema.js → repository/IAssetRepository.js} +0 -0
@@ -5,7 +5,6 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const funnel_core_1 = require("@nascentdigital/funnel-core");
6
6
  const react_1 = require("motion/react");
7
7
  const react_2 = require("react");
8
- const client_1 = require("../../../client");
9
8
  const hooks_1 = require("../../../hooks");
10
9
  const feedback_1 = require("../../feedback");
11
10
  const interaction_1 = require("../../interaction");
@@ -21,14 +20,15 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
21
20
  // bind props + hooks
22
21
  const [deferral, setDeferral] = (0, react_2.useState)(undefined);
23
22
  const [result, setResult] = (0, react_2.useState)();
23
+ const [uploading, setUploading] = (0, react_2.useState)(false);
24
24
  const [schema, setSchema] = (0, react_2.useState)();
25
25
  const [anchor, setAnchor] = (0, react_2.useState)();
26
26
  const [errorLevel, setErrorLevel] = (0, react_2.useState)('none');
27
27
  const [error, setError] = (0, react_2.useState)();
28
28
  const [assetInfo, setAssetInfo] = (0, react_2.useState)();
29
- const { nameField, anchorField, descriptionField, accessibleField } = (0, useAssetFields_1.useAssetFields)();
29
+ const { nameField, descriptionField } = (0, useAssetFields_1.useAssetFields)();
30
30
  const [shared, setShared] = (0, react_2.useState)(false);
31
- const editorApi = (0, client_1.useEditorApi)();
31
+ const assetRepo = (0, hooks_1.useAssetRepository)();
32
32
  const assetStore = (0, hooks_1.useAssetStore)();
33
33
  const assetOptions = (0, react_2.useMemo)(() => getAssetOptions(schema), [schema]);
34
34
  // export service
@@ -56,9 +56,7 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
56
56
  // update fields if there's a file
57
57
  if (assetInfo) {
58
58
  nameField.reset(funnel_core_1.Schema.TextField.Value.toData(assetInfo.fileName));
59
- anchorField.reset(funnel_core_1.Schema.EnumField.Value.toData('center'));
60
59
  descriptionField.reset(null);
61
- accessibleField.reset(funnel_core_1.Schema.EnumField.Value.toData('system'));
62
60
  }
63
61
  };
64
62
  const onValidate = () => {
@@ -69,8 +67,7 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
69
67
  // check if level
70
68
  let valid = nameField.valid;
71
69
  if (valid && assetInfo.isVisual) {
72
- valid = anchorField.valid &&
73
- (!descriptionField.exists || descriptionField.valid);
70
+ valid = !descriptionField.exists || descriptionField.valid;
74
71
  }
75
72
  // update error level
76
73
  setErrorLevel('all');
@@ -86,11 +83,13 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
86
83
  }
87
84
  // handle upload
88
85
  try {
86
+ // start upload
87
+ setUploading(true);
89
88
  // create meta
90
- const metadata = await getAssetMetadata({ assetInfo, anchorField, accessibleField });
89
+ const metadata = await getAssetMetadata({ assetInfo });
91
90
  console.debug('[AssetUploader/onUpload] uploading asset', { assetInfo, metadata });
92
91
  // upload new file
93
- const uploadedFile = await editorApi.uploadFile({
92
+ const uploadedFile = await assetRepo.uploadFile({
94
93
  file: assetInfo.file,
95
94
  type: assetInfo.mimeType,
96
95
  size: assetInfo.size,
@@ -115,6 +114,10 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
115
114
  console.error('[AssetUploader/upload] file upload failure', e);
116
115
  setError(feedback_1.ErrorMessage.getGenericError((e instanceof Error) ? e : new funnel_core_1.ServerError()));
117
116
  }
117
+ // clear uploading flag
118
+ finally {
119
+ setUploading(false);
120
+ }
118
121
  };
119
122
  const onCancel = () => {
120
123
  // set result (triggers uploader to close)
@@ -133,8 +136,8 @@ exports.AssetUploader = (0, react_2.forwardRef)(function AssetUploader(_, ref) {
133
136
  return null;
134
137
  }
135
138
  // render
136
- return ((0, jsx_runtime_1.jsxs)(interaction_1.MiniEditor, { className: "flex flex-col gap-l8", title: "Upload Asset", open: result === undefined, placement: "right", anchor: anchor, anchorOffset: 4, canSave: onValidate, disableSave: !(assetInfo === null || assetInfo === void 0 ? void 0 : assetInfo.isValid), renderSaveLabel: () => 'Upload', onSave: onUpload, onClose: onCancel, onClosed: onPickerClosed, children: [schema.description &&
137
- (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: schema.description }), (0, jsx_runtime_1.jsx)(AssetSelectorPane_1.AssetSelectorPane, { options: assetOptions, onAssetChanged: onAssetChanged }), (0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { children: (0, jsx_runtime_1.jsx)(FieldErrorController_1.FieldErrorController, { errorLevel: errorLevel, children: renderAssetInfo({ assetInfo, nameField, anchorField, descriptionField, accessibleField, shared, setShared }) }) })] }));
139
+ return ((0, jsx_runtime_1.jsxs)(interaction_1.MiniEditor, { className: "flex flex-col gap-l8", title: "Upload Asset", open: result === undefined, placement: "right", anchor: anchor, anchorOffset: 4, canSave: onValidate, disableSave: !(assetInfo === null || assetInfo === void 0 ? void 0 : assetInfo.isValid), renderSaveLabel: () => 'Upload', customActions: (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", iconLeft: "ImageDown", disabled: uploading, onClick: () => setResult('pick'), children: "Open Library" }), onSave: onUpload, onClose: onCancel, onClosed: onPickerClosed, children: [schema.description &&
140
+ (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: schema.description }), (0, jsx_runtime_1.jsx)(AssetSelectorPane_1.AssetSelectorPane, { options: assetOptions, onAssetChanged: onAssetChanged }), (0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { children: (0, jsx_runtime_1.jsx)(FieldErrorController_1.FieldErrorController, { errorLevel: errorLevel, children: renderAssetInfo({ assetInfo, nameField, descriptionField, shared, setShared, uploading }) }) })] }));
138
141
  });
139
142
  function getAssetOptions(schema) {
140
143
  // return empty options if there's no schema
@@ -158,52 +161,41 @@ function getAssetOptions(schema) {
158
161
  // normalize options
159
162
  return AssetInfo_1.AssetInfo.Options.normalize(options);
160
163
  }
161
- function renderAssetInfo({ assetInfo, nameField, anchorField, descriptionField, accessibleField, shared, setShared }) {
164
+ function renderAssetInfo({ assetInfo, nameField, descriptionField, shared, setShared, uploading }) {
162
165
  // skip if there's no asset info
163
166
  if (!assetInfo || !assetInfo.isValid) {
164
167
  return null;
165
168
  }
166
169
  // build fields
167
170
  const fields = [
168
- (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: nameField }, "name")
171
+ (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: nameField, disabled: uploading }, "name")
169
172
  ];
170
173
  // add fields related to visuals
171
174
  if (assetInfo.isVisual) {
172
- // add anchor
173
- fields.push((0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: anchorField }, "anchor"));
174
- // add accessible flag (for videos)
175
- if (assetInfo.isVideo) {
176
- fields.push((0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: accessibleField }, "accessible"));
177
- }
178
- // get description
179
175
  fields.push(descriptionField.exists
180
- ? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: descriptionField }, "desc")
181
- : (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { field: descriptionField }, "desc.option"));
176
+ ? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: descriptionField, disabled: uploading }, "desc")
177
+ : (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { field: descriptionField, disabled: uploading }, "desc.option"));
182
178
  }
183
179
  // render editing fields
184
- return ((0, jsx_runtime_1.jsxs)(transitions_1.FadeIn, { className: "flex flex-col gap-l8", children: [fields, (0, jsx_runtime_1.jsx)(interaction_1.Checkbox, { checked: shared, onChange: setShared, children: "Store in global media library" })] }, "fields"));
180
+ return ((0, jsx_runtime_1.jsxs)(transitions_1.FadeIn, { className: "flex flex-col gap-l8", children: [fields, (0, jsx_runtime_1.jsx)(interaction_1.Checkbox, { checked: shared, onChange: setShared, disabled: uploading, children: "Store in global media library" })] }, "fields"));
185
181
  }
186
- async function getAssetMetadata({ assetInfo, anchorField, accessibleField }) {
187
- var _a;
182
+ async function getAssetMetadata({ assetInfo }) {
188
183
  const { fileType, dimensions, blurHash } = assetInfo;
189
184
  switch (fileType) {
190
185
  case 'image':
191
186
  return {
192
- crop: funnel_core_1.Schema.EnumField.Value.fromData(anchorField.value),
187
+ crop: 'center',
193
188
  dimensions,
194
189
  blurHash
195
190
  };
196
191
  case 'icon':
197
192
  return { dimensions };
198
193
  case 'video': {
199
- const accessible = (_a = funnel_core_1.Schema.EnumField.Value.fromData(accessibleField.value)) !== null && _a !== void 0 ? _a : 'system';
200
194
  return {
201
- crop: funnel_core_1.Schema.EnumField.Value.fromData(anchorField.value),
195
+ crop: 'center',
202
196
  dimensions,
203
197
  blurHash,
204
- accessible: accessible === 'system'
205
- ? 'system'
206
- : accessible === 'true'
198
+ accessible: 'system'
207
199
  };
208
200
  }
209
201
  default:
@@ -11,11 +11,13 @@ const classnames_1 = __importDefault(require("classnames"));
11
11
  const react_1 = require("react");
12
12
  // component
13
13
  function VideoPreview({ className, asset, active }) {
14
+ var _a;
14
15
  // bind state + refs
15
16
  const { url, metadata } = asset;
16
17
  const { blurHash } = metadata;
17
18
  const [videoRef, video] = (0, client_1.useRefElement)();
18
19
  const videoProxy = (0, client_1.useVideoProxy)(video);
20
+ const videoState = (_a = videoProxy === null || videoProxy === void 0 ? void 0 : videoProxy.state) !== null && _a !== void 0 ? _a : 'uninitialized';
19
21
  const blurCanvasRef = (0, react_1.useRef)(null);
20
22
  // decode blurhash (if any)
21
23
  (0, react_1.useEffect)(() => {
@@ -44,7 +46,10 @@ function VideoPreview({ className, asset, active }) {
44
46
  });
45
47
  // cancel on unmount
46
48
  return () => {
49
+ // mark cancelled
47
50
  cancelled = true;
51
+ // stop video (if required)
52
+ videoProxy.pause().catch(console.error);
48
53
  };
49
54
  }, [videoProxy]);
50
55
  // start/stop video when active
@@ -53,22 +58,22 @@ function VideoPreview({ className, asset, active }) {
53
58
  if (!videoProxy) {
54
59
  return;
55
60
  }
56
- // start video
57
- if (active) {
61
+ // or ignore if it's not ready (playing or paused)
62
+ else if (videoState !== 'ready' && videoState !== 'playing') {
63
+ return;
64
+ }
65
+ // start video if not playing
66
+ const playbackRate = active ? 1 : 0.33;
67
+ if (videoProxy.state !== 'playing') {
58
68
  videoProxy
59
- .play({ playbackRate: 1, loop: true })
69
+ .play({ playbackRate, loop: true })
60
70
  .catch(console.error);
61
71
  }
72
+ // or adjust speed
62
73
  else {
63
- videoProxy
64
- .pause()
65
- .catch(console.error);
74
+ videoProxy.video.playbackRate = playbackRate;
66
75
  }
67
- // stop on unmount
68
- return () => {
69
- videoProxy.pause().catch(console.error);
70
- };
71
- }, [videoProxy, active]);
76
+ }, [videoProxy, videoState, active]);
72
77
  // render
73
78
  return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(className, 'relative w-full h-full'), children: [blurHash &&
74
79
  (0, jsx_runtime_1.jsx)("canvas", { ref: blurCanvasRef, className: "absolute inset-0 w-full h-full", width: 32, height: 32, draggable: false }), (0, jsx_runtime_1.jsx)("video", { ref: videoRef, className: (0, classnames_1.default)('absolute inset-0 w-full h-full object-cover cursor-pointer interpolate', {
@@ -1,20 +1,5 @@
1
- import { Position, Schema } from '@nascentdigital/funnel-core';
2
- export declare function useAssetFields(): import("../../..").TranslateSchema.Fields<{
1
+ import { Schema } from '@nascentdigital/funnel-core';
2
+ export declare function useAssetFields(): import("@nascentdigital/funnel-core").SchemaToFields<{
3
3
  nameField: Schema.TextField;
4
- anchorField: Schema.EnumField<Schema.EnumField.Options<Position>>;
5
- accessibleField: Schema.EnumField<{
6
- system: {
7
- name: string;
8
- hint: string;
9
- };
10
- true: {
11
- name: string;
12
- hint: string;
13
- };
14
- false: {
15
- name: string;
16
- hint: string;
17
- };
18
- }>;
19
4
  descriptionField: Schema.TextField;
20
5
  }>;
@@ -9,27 +9,6 @@ function useAssetFields() {
9
9
  nameField: funnel_core_1.Schema.TextField.slug({
10
10
  name: 'Name'
11
11
  }),
12
- anchorField: funnel_core_1.Schema.Field.enumeration({
13
- name: 'Cropping',
14
- options: funnel_core_1.Position.values.reduce((options, position) => {
15
- // bind position
16
- options[position] = {
17
- name: funnel_core_1.Position.getName(position)
18
- };
19
- // keep reducing
20
- return options;
21
- }, {}),
22
- defaultOption: 'center',
23
- required: true
24
- }),
25
- accessibleField: funnel_core_1.Schema.Field.enumeration({
26
- name: 'Pause Button',
27
- options: {
28
- system: { name: 'Site Default', hint: `Use the default for the site (${funnel_core_1.AppConfig.get().accessible ? 'enabled' : 'disabled'})` },
29
- true: { name: 'Enable', hint: 'A pause button will be included' },
30
- false: { name: 'Disable', hint: 'There will be no way to pause the video' }
31
- }
32
- }),
33
12
  descriptionField: funnel_core_1.Schema.TextField.text({
34
13
  name: 'Alt Text',
35
14
  hint: 'What\'s happening in this visual?',
@@ -147,7 +147,7 @@ exports.CollectionEditor = (0, react_1.forwardRef)(function CollectionEditor({ l
147
147
  ? () => setShared(!shared)
148
148
  : undefined, children: shared ? 'Shared' : 'Unshared' }), (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "primary", size: "sm", disabled: !field || !field.nameField.valid || !field.modified, onClick: onSave, children: !initialValue ? 'Create' : 'Update' })] }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", initial: false, children: field
149
149
  ?
150
- (0, jsx_runtime_1.jsxs)(transitions_1.FadeIn, { className: "flex flex-col gap-l7", children: [(0, jsx_runtime_1.jsx)(FieldsPanel_1.FieldsPanel, { className: "flex-1 px-l7", fields: field.allFields, autoFocus: true }), field.tagGroups.length > 0 &&
150
+ (0, jsx_runtime_1.jsxs)(transitions_1.FadeIn, { className: "flex-1 flex flex-col gap-l10 px-l6 py-l10 overflow-y-scroll scrollbar-thin bg-background", children: [(0, jsx_runtime_1.jsx)(FieldsPanel_1.FieldsPanel, { className: "flex-1", fields: field.allFields, autoFocus: true }), field.tagGroups.length > 0 &&
151
151
  (0, jsx_runtime_1.jsx)("div", { className: "px-l7", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l8 p-l8 bg-surface1 rounded-md", children: [(0, jsx_runtime_1.jsx)("h2", { className: "display-xxs flex-1", children: "Tags" }), (0, jsx_runtime_1.jsx)(TagEditor_1.TagEditor, { className: "bg-surface2 p-l6 rounded-sm", tagged: field })] }) })] }, "fields")
152
152
  :
153
153
  (0, jsx_runtime_1.jsx)(transitions_1.FadeIn, { className: "w-full h-full flex flex-col justify-center items-center", children: (0, jsx_runtime_1.jsx)(interaction_1.Loader, { size: "lg" }) }, "loader") })] }) }) }));
@@ -1,5 +1,5 @@
1
1
  import { Language, Schema } from '@nascentdigital/funnel-core';
2
- import { Collection } from '../../../domain';
2
+ import { ICollection } from '../../../domain';
3
3
  export declare const CollectionPicker: import("react").ForwardRefExoticComponent<CollectionPicker.Props & import("react").RefAttributes<CollectionPicker.Ref>>;
4
4
  export declare namespace CollectionPicker {
5
5
  type Props = {
@@ -11,5 +11,5 @@ export declare namespace CollectionPicker {
11
11
  type Options = {
12
12
  schema: Schema.CollectionField;
13
13
  };
14
- type Result = Collection.Ref | undefined;
14
+ type Result = ICollection.Ref | undefined;
15
15
  }
@@ -9,7 +9,6 @@ const funnel_core_1 = require("@nascentdigital/funnel-core");
9
9
  const classnames_1 = __importDefault(require("classnames"));
10
10
  const framer_motion_1 = require("framer-motion");
11
11
  const react_1 = require("react");
12
- const client_1 = require("../../../client");
13
12
  const hooks_1 = require("../../../hooks");
14
13
  const feedback_1 = require("../../feedback");
15
14
  const interaction_1 = require("../../interaction");
@@ -28,7 +27,7 @@ exports.CollectionPicker = (0, react_1.forwardRef)(function CollectionPicker({ l
28
27
  const [tagTooltip, setTagTooltip] = (0, react_1.useState)();
29
28
  const [fetching, setFetching] = (0, react_1.useState)(false);
30
29
  const [error, setError] = (0, react_1.useState)();
31
- const editorApi = (0, client_1.useEditorApi)();
30
+ const collectionRepo = (0, hooks_1.useCollectionRepository)();
32
31
  const siteCollections = (0, hooks_1.useCollections)();
33
32
  const collectionStore = (0, hooks_1.useCollectionStore)();
34
33
  // export service
@@ -144,7 +143,7 @@ exports.CollectionPicker = (0, react_1.forwardRef)(function CollectionPicker({ l
144
143
  setTagTooltip(undefined);
145
144
  // fetch ref (or fail)
146
145
  const { template, id, name } = collectionRef;
147
- const collection = await editorApi.getCollection({ id, version: 'draft' });
146
+ const collection = await collectionRepo.get({ id, version: 'draft' });
148
147
  if (!collection) {
149
148
  setFetching(false);
150
149
  setError({
@@ -173,7 +172,7 @@ exports.CollectionPicker = (0, react_1.forwardRef)(function CollectionPicker({ l
173
172
  deferral.resolve(result !== null && result !== void 0 ? result : undefined);
174
173
  };
175
174
  // render
176
- return ((0, jsx_runtime_1.jsxs)(interaction_1.Picker, { className: "flex", open: deferral && result === undefined, disableDismiss: fetching, onClose: onCancel, onClosed: onPickerClosed, children: [(0, jsx_runtime_1.jsxs)("section", { className: "shrink-0 w-[206px] flex flex-col gap-l8 p-l8 bg-modal-background", children: [(0, jsx_runtime_1.jsx)("h1", { className: "heading-md text-content-primary", children: "Select Collection" }), (0, jsx_runtime_1.jsx)(interaction_1.ChipFilters, { title: "Site Collections", options: collectionGroups, selectedOptions: collectionGroup && [collectionGroup], onToggle: (collectionGroup, selected) => selected && setCollectionGroup(collectionGroup), renderLabel: collectionGroup => collectionGroup.template.name, disabled: fetching })] }), (0, jsx_runtime_1.jsxs)("section", { className: "flex-1 flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l8 overflow-y-scroll", children: (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", initial: false, children: renderPicker({ language, error, collectionGroups, collectionGroup, collections, tagOptions, tagFilters, onPick, setTagTooltip, fetching }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex justify-end items-center p-l8 border-t border-solid border-border-l1", children: (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onCancel, disabled: fetching, children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(interaction_1.Popup, { className: (0, classnames_1.default)('max-w-[200px] bg-surface2 rounded-md p-l5', 'border border-solid border-border-l1 shadow-tooltip', 'flex flex-wrap items-center gap-l4'), open: !!tagTooltip, anchor: tagTooltip === null || tagTooltip === void 0 ? void 0 : tagTooltip.anchor, anchorOffset: 4, placement: "top", disableOverlay: true, onClose: () => setTagTooltip(undefined), children: tagTooltip === null || tagTooltip === void 0 ? void 0 : tagTooltip.tags.map(tag => (0, jsx_runtime_1.jsx)(feedback_1.Badge, { variant: "outlinedTiny", status: "draft", label: tag.name }, tag.data)) })] })] }));
175
+ return ((0, jsx_runtime_1.jsxs)(interaction_1.Picker, { className: "flex", open: deferral && result === undefined, disableDismiss: fetching, onClose: onCancel, onClosed: onPickerClosed, children: [(0, jsx_runtime_1.jsxs)("section", { className: "shrink-0 w-[206px] flex flex-col gap-l8 p-l8 bg-modal-background", children: [(0, jsx_runtime_1.jsx)("h1", { className: "heading-md text-content-primary", children: "Select Collection" }), (0, jsx_runtime_1.jsx)(interaction_1.ChipFilters, { title: "Site Collections", options: collectionGroups, selectedOptions: collectionGroup && [collectionGroup], onToggle: (collectionGroup, selected) => selected && setCollectionGroup(collectionGroup), renderLabel: collectionGroup => collectionGroup.template.name, disabled: fetching })] }), (0, jsx_runtime_1.jsxs)("section", { className: "flex-1 flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l8 overflow-y-scroll", tabIndex: -1, children: (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", initial: false, children: renderPicker({ language, error, collectionGroups, collectionGroup, collections, tagOptions, tagFilters, onPick, setTagTooltip, fetching }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex justify-end items-center p-l8 border-t border-solid border-border-l1", children: (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onCancel, disabled: fetching, children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(interaction_1.Popup, { className: (0, classnames_1.default)('max-w-[200px] bg-surface2 rounded-md p-l5', 'border border-solid border-border-l1 shadow-tooltip', 'flex flex-wrap items-center gap-l4'), open: !!tagTooltip, anchor: tagTooltip === null || tagTooltip === void 0 ? void 0 : tagTooltip.anchor, anchorOffset: 4, placement: "top", disableOverlay: true, onClose: () => setTagTooltip(undefined), children: tagTooltip === null || tagTooltip === void 0 ? void 0 : tagTooltip.tags.map(tag => (0, jsx_runtime_1.jsx)(feedback_1.Badge, { variant: "outlinedTiny", status: "draft", label: tag.name }, tag.data)) })] })] }));
177
176
  });
178
177
  function renderPicker({ language, schema, error, collectionGroups, collectionGroup, collections, tagOptions, tagFilters, onPick, setTagTooltip, fetching }) {
179
178
  // show error if we have one
@@ -50,7 +50,7 @@ exports.PagePriorityDialog = (0, react_1.forwardRef)(function CreatePageDialog({
50
50
  return;
51
51
  }
52
52
  // render
53
- return ((0, jsx_runtime_1.jsxs)(interaction_1.Picker, { open: !!deferral, onClose: onClose, className: "flex", children: [(0, jsx_runtime_1.jsxs)("section", { className: "shrink-0 w-[206px] flex flex-col gap-l8 p-l8 bg-modal-background", children: [(0, jsx_runtime_1.jsx)("h1", { className: "heading-md text-content-primary", children: "Priority Settings" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l6", children: [(0, jsx_runtime_1.jsx)("h2", { className: "label-sm label-strong text-content-tertiary", children: "Site Pages" }), (0, jsx_runtime_1.jsx)(feedback_1.Badge, { label: currentPage.name })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "flex-1 flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l8 overflow-y-scroll", children: currentPage.tags.map(group => (0, jsx_runtime_1.jsx)(TagGroup, { page: currentPage, group: group, state: pageTagState }, group.id)) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-l4 items-center p-l8 border-t border-solid border-border-l1", children: [(0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onClose, children: "Cancel" }), (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onReset, children: "Reset" }), (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "primary", size: "sm", onClick: onSave, children: "Save" })] })] })] }));
53
+ return ((0, jsx_runtime_1.jsxs)(interaction_1.Picker, { open: !!deferral, onClose: onClose, className: "flex", children: [(0, jsx_runtime_1.jsxs)("section", { className: "shrink-0 w-[206px] flex flex-col gap-l8 p-l8 bg-modal-background", children: [(0, jsx_runtime_1.jsx)("h1", { className: "heading-md text-content-primary", children: "Priority Settings" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l6", children: [(0, jsx_runtime_1.jsx)("h2", { className: "label-sm label-strong text-content-tertiary", children: "Site Pages" }), (0, jsx_runtime_1.jsx)(feedback_1.Badge, { label: currentPage.name })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "flex-1 flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l8 overflow-y-scroll", tabIndex: -1, children: currentPage.tags.map(group => (0, jsx_runtime_1.jsx)(TagGroup, { page: currentPage, group: group, state: pageTagState }, group.id)) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-l4 items-center p-l8 border-t border-solid border-border-l1", children: [(0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onClose, children: "Cancel" }), (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: onReset, children: "Reset" }), (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "primary", size: "sm", onClick: onSave, children: "Save" })] })] })] }));
54
54
  });
55
55
  var PageTagState;
56
56
  (function (PageTagState) {
@@ -14,7 +14,6 @@ const hooks_1 = require("../../../hooks");
14
14
  const feedback_1 = require("../../feedback");
15
15
  const interaction_1 = require("../../interaction");
16
16
  const visuals_1 = require("../../visuals");
17
- const FieldEditor_1 = require("../FieldEditor");
18
17
  const FieldErrorController_1 = require("../FieldErrorController");
19
18
  const TextField_1 = require("../TextField");
20
19
  // component
@@ -26,19 +25,12 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
26
25
  const [anchor, setAnchor] = (0, react_1.useState)();
27
26
  const [state, setState] = (0, react_1.useState)('initializing');
28
27
  const touch = (0, client_1.useTouch)();
29
- const { uriField, mutedField } = (0, hooks_1.useTempFields)({
28
+ const { uriField } = (0, hooks_1.useTempFields)({
30
29
  uriField: funnel_core_1.Schema.Field.uri({
31
30
  name: 'YouTube or Vimeo URL',
32
31
  hint: 'Enter video link',
33
32
  required: true
34
33
  }),
35
- mutedField: funnel_core_1.Schema.Field.boolean({
36
- name: 'Muted',
37
- hint: 'Video starts off on mute',
38
- semantics: 'toggle',
39
- required: true,
40
- defaultValue: true
41
- })
42
34
  });
43
35
  const uri = uriField.valid
44
36
  ? funnel_core_1.Schema.TextField.Value.fromData(uriField.value)
@@ -49,7 +41,6 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
49
41
  // export service
50
42
  (0, react_1.useImperativeHandle)(ref, () => ({
51
43
  edit: async ({ schema, initialValue, anchor }) => {
52
- var _a;
53
44
  // reset state
54
45
  setSchema(schema);
55
46
  setInitialValue(initialValue);
@@ -61,14 +52,13 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
61
52
  uriField.reset(video
62
53
  ? funnel_core_1.Schema.TextField.Value.toData(funnel_core_1.Schema.EmbeddedVideoField.Value.toUrl(video).href)
63
54
  : null);
64
- mutedField.reset(funnel_core_1.Schema.BooleanField.Value.toData(schema.allowMuting ? (_a = video === null || video === void 0 ? void 0 : video.muted) !== null && _a !== void 0 ? _a : true : true));
65
55
  // create deferral
66
56
  const deferral = new funnel_core_1.Deferral();
67
57
  setDeferral(deferral);
68
58
  // wait until deferral is resolved
69
59
  return deferral.promise;
70
60
  }
71
- }), [uriField, mutedField, video$]);
61
+ }), [uriField, video$]);
72
62
  // sync uri on change
73
63
  (0, react_1.useEffect)(() => {
74
64
  var _a;
@@ -100,7 +90,7 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
100
90
  return;
101
91
  }
102
92
  // or if there's already a thumb
103
- else if (video.thumbUrl) {
93
+ else if (video.thumbUrl && video.dimensions.width && video.dimensions.height) {
104
94
  setState('valid');
105
95
  return;
106
96
  }
@@ -113,18 +103,28 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
113
103
  return;
114
104
  }
115
105
  // or fail if we couldn't get a thumbnail (means no video)
116
- if (!thumbUrl) {
106
+ else if (!thumbUrl) {
117
107
  setState('error');
108
+ return;
118
109
  }
119
- // otherwise, update video with valid thumb
120
- else {
121
- // update video
122
- video$.next(Object.assign(Object.assign({}, video), { thumbUrl: thumbUrl.href }));
123
- // update state
124
- setState('valid');
125
- // touch (just in case we were already valid)
126
- touch();
110
+ // get video dimensions
111
+ const dimensions = await getVideoThumbnailSize(thumbUrl.href);
112
+ console.debug('[EmbeddedVideoEditor] got video size as ', dimensions);
113
+ // skip if video has changed (debounced)
114
+ if (video$.value !== video) {
115
+ return;
116
+ }
117
+ // or fail if we couldn't get dimensions (means no thumbnail)
118
+ else if (!dimensions || !dimensions.width || !dimensions.height) {
119
+ setState('error');
120
+ return;
127
121
  }
122
+ // update video
123
+ video$.next(Object.assign(Object.assign({}, video), { dimensions, thumbUrl: thumbUrl.href }));
124
+ // update state
125
+ setState('valid');
126
+ // touch (just in case we were already valid)
127
+ touch();
128
128
  });
129
129
  // unsubscribe on unmount
130
130
  return () => subscription.unsubscribe();
@@ -134,14 +134,12 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
134
134
  return state === 'valid';
135
135
  };
136
136
  const onSave = async () => {
137
- var _a;
138
137
  // blow up if missing uri (should never happen)
139
138
  if (!video || state !== 'valid') {
140
139
  throw new funnel_core_1.IllegalStateError('Missing URI');
141
140
  }
142
141
  // resolve embed (we're done)
143
- const muted = (_a = funnel_core_1.Schema.BooleanField.Value.fromData(mutedField.value)) !== null && _a !== void 0 ? _a : true;
144
- deferral === null || deferral === void 0 ? void 0 : deferral.resolve(funnel_core_1.Schema.EmbeddedVideoField.Value.toData(Object.assign(Object.assign({}, video), { muted })));
142
+ deferral === null || deferral === void 0 ? void 0 : deferral.resolve(funnel_core_1.Schema.EmbeddedVideoField.Value.toData(Object.assign({}, video)));
145
143
  // refresh
146
144
  touch();
147
145
  };
@@ -157,8 +155,7 @@ exports.EmbeddedVideoEditor = (0, react_1.forwardRef)(function EmbeddedVideoEdit
157
155
  };
158
156
  // render
159
157
  return ((0, jsx_runtime_1.jsxs)(interaction_1.MiniEditor, { title: `${initialValue ? 'Edit' : 'Add'} ${name}`, open: !!deferral && !deferral.isComplete, placement: "right", anchor: anchor, anchorOffset: 4, canSave: canSave, onSave: onSave, onClose: onCancel, disabled: false, children: [description &&
160
- (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: description }), renderPreview({ state, video }), (0, jsx_runtime_1.jsxs)(FieldErrorController_1.FieldErrorController, { errorLevel: "none", children: [(0, jsx_runtime_1.jsx)(TextField_1.TextField, { field: uriField }), (schema === null || schema === void 0 ? void 0 : schema.allowMuting) &&
161
- (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: mutedField })] })] }));
158
+ (0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: description }), renderPreview({ state, video }), (0, jsx_runtime_1.jsx)(FieldErrorController_1.FieldErrorController, { errorLevel: "none", children: (0, jsx_runtime_1.jsx)(TextField_1.TextField, { field: uriField }) })] }));
162
159
  });
163
160
  async function getVideoThumbnailUrl(video) {
164
161
  // skip if there's no video
@@ -207,6 +204,16 @@ async function getVideoThumbnailUrl(video) {
207
204
  return null;
208
205
  }
209
206
  }
207
+ async function getVideoThumbnailSize(url) {
208
+ // get blob
209
+ const response = await fetch(url);
210
+ const blob = await response.blob();
211
+ // get image
212
+ const imageProxy = new funnel_core_1.BlobImageProxy(blob);
213
+ await imageProxy.waitUntilReady();
214
+ // return dimensions
215
+ return imageProxy.intrinsicSize;
216
+ }
210
217
  function renderPreview({ state, video }) {
211
218
  // show loader if checking
212
219
  let content;
@@ -3,17 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FieldValueFactory = FieldValueFactory;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const funnel_core_1 = require("@nascentdigital/funnel-core");
6
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
6
7
  const hooks_1 = require("../../../hooks");
7
8
  const AssetFactory_1 = require("./AssetFactory");
8
9
  const CollectionFactory_1 = require("./CollectionFactory");
9
10
  const EmbeddedVideoFactory_1 = require("./EmbeddedVideoFactory");
10
11
  const LinkFactory_1 = require("./LinkFactory");
12
+ const MediaFactory_1 = require("./MediaFactory");
11
13
  const ObjectFactory_1 = require("./ObjectFactory");
12
14
  const PageFactory_1 = require("./PageFactory");
13
15
  const TextFactory_1 = require("./TextFactory");
14
16
  // factory
15
17
  function FieldValueFactory({ anchor, itemSchema, field, onCommit = funnel_core_1.Fn.NoOp, onCancel = funnel_core_1.Fn.NoOp }) {
16
- var _a, _b, _c, _d, _e, _f;
18
+ var _a, _b, _c, _d, _e, _f, _g;
17
19
  // bind language
18
20
  const brandConfig = funnel_core_1.AppConfig.brandConfig();
19
21
  const page = (0, hooks_1.usePossiblePage)();
@@ -21,11 +23,9 @@ function FieldValueFactory({ anchor, itemSchema, field, onCommit = funnel_core_1
21
23
  const region = (_a = page === null || page === void 0 ? void 0 : page.region) !== null && _a !== void 0 ? _a : funnel_core_1.RegionsConfig.getDefaultRegion(brandConfig.regionalization);
22
24
  const language = (_c = (_b = page === null || page === void 0 ? void 0 : page.language) !== null && _b !== void 0 ? _b : collection === null || collection === void 0 ? void 0 : collection.language) !== null && _c !== void 0 ? _c : funnel_core_1.RegionsConfig.getDefaultLanguage(brandConfig.regionalization);
23
25
  const commit = (item) => {
24
- console.debug(`[FieldValueFactory/commit] creating value for "${itemSchema.name}"`, item);
25
26
  onCommit(item);
26
27
  };
27
28
  const cancel = () => {
28
- console.debug(`[FieldValueFactory/cancel] cancelling "${itemSchema.name}"`);
29
29
  onCancel();
30
30
  };
31
31
  // handle based on item type
@@ -42,7 +42,14 @@ function FieldValueFactory({ anchor, itemSchema, field, onCommit = funnel_core_1
42
42
  case 'page':
43
43
  return ((0, jsx_runtime_1.jsx)(PageFactory_1.PageFactory, { schema: itemSchema, region: region, language: language, onCommit: item => commit(item), onCancel: cancel }));
44
44
  case 'collection':
45
- return ((0, jsx_runtime_1.jsx)(CollectionFactory_1.CollectionFactory, { schema: itemSchema, language: language, collection: (_f = field === null || field === void 0 ? void 0 : field.value) === null || _f === void 0 ? void 0 : _f.value, anchor: anchor, onCommit: item => commit(item), onCancel: cancel }));
45
+ // custom handling for media
46
+ if (funnel_ui_1.Media.Schema.filter(itemSchema)) {
47
+ return ((0, jsx_runtime_1.jsx)(MediaFactory_1.MediaFactory, { schema: itemSchema, language: language, media: (_f = field === null || field === void 0 ? void 0 : field.value) === null || _f === void 0 ? void 0 : _f.value, anchor: anchor, onCommit: item => commit(funnel_core_1.Schema.CollectionField.Value.toData(item)), onCancel: cancel }));
48
+ }
49
+ // or generic collection
50
+ else {
51
+ return ((0, jsx_runtime_1.jsx)(CollectionFactory_1.CollectionFactory, { schema: itemSchema, language: language, collection: (_g = field === null || field === void 0 ? void 0 : field.value) === null || _g === void 0 ? void 0 : _g.value, anchor: anchor, onCommit: item => commit(item), onCancel: cancel }));
52
+ }
46
53
  case 'object':
47
54
  return ((0, jsx_runtime_1.jsx)(ObjectFactory_1.ObjectFactory, { schema: itemSchema, field: field, onCommit: item => commit(item), onCancel: cancel }));
48
55
  default:
@@ -0,0 +1,13 @@
1
+ import { Callback, Language } from '@nascentdigital/funnel-core';
2
+ import { Media } from '@nascentdigital/funnel-ui';
3
+ export declare function MediaFactory({ schema, language, media: initialValue, anchor, onCommit: onCommitRaw, onCancel: onCancelRaw }: MediaFactory.Props): import("react/jsx-runtime").JSX.Element;
4
+ export declare namespace MediaFactory {
5
+ type Props = {
6
+ schema: Media.Schema;
7
+ language: Language;
8
+ media?: Media.Value;
9
+ anchor: string;
10
+ onCommit: Callback<Media.Value>;
11
+ onCancel: Callback.Void;
12
+ };
13
+ }