@nascentdigital/funnel-editor 4.6.7 → 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.
- package/dist/EditorApp.js +1 -1
- package/dist/EditorRoutes.js +7 -5
- package/dist/changesets/screens/ChangeSetViewer.js +1 -1
- package/dist/changesets/screens/ChangeSetsExplorer.js +1 -2
- package/dist/collection/hooks/CollectionController.d.ts +5 -16
- package/dist/collection/hooks/CollectionController.js +18 -37
- package/dist/collection/hooks/ICollectionController.d.ts +24 -0
- package/dist/collection/hooks/ICollectionController.js +20 -0
- package/dist/collection/hooks/index.d.ts +1 -0
- package/dist/collection/hooks/index.js +1 -0
- package/dist/collection/hooks/useCollectionController.d.ts +3 -3
- package/dist/collection/screens/CollectionEditor.js +2 -2
- package/dist/components.d.ts +14 -3
- package/dist/components.js +17 -3
- package/dist/core/components/feedback/dialog/MinimalDialogLayout.js +1 -1
- package/dist/core/components/fields/BooleanField.d.ts +2 -1
- package/dist/core/components/fields/BooleanField.js +2 -2
- package/dist/core/components/fields/DateField.d.ts +2 -1
- package/dist/core/components/fields/DateField.js +2 -2
- package/dist/core/components/fields/DynamicPagesEditor.d.ts +2 -1
- package/dist/core/components/fields/DynamicPagesEditor.js +1 -1
- package/dist/core/components/fields/EnumField.d.ts +2 -1
- package/dist/core/components/fields/EnumField.js +2 -2
- package/dist/core/components/fields/FieldCard.d.ts +1 -0
- package/dist/core/components/fields/FieldCard.js +8 -1
- package/dist/core/components/fields/FieldEditor.d.ts +2 -1
- package/dist/core/components/fields/FieldEditor.js +11 -11
- package/dist/core/components/fields/FieldLayout.d.ts +2 -1
- package/dist/core/components/fields/FieldLayout.js +3 -3
- package/dist/core/components/fields/ListEditor.d.ts +2 -1
- package/dist/core/components/fields/ListEditor.js +5 -6
- package/dist/core/components/fields/OptInField.d.ts +2 -1
- package/dist/core/components/fields/OptInField.js +2 -2
- package/dist/core/components/fields/RichTextEditor.js +1 -1
- package/dist/core/components/fields/RichTextField.d.ts +2 -1
- package/dist/core/components/fields/RichTextField.js +3 -5
- package/dist/core/components/fields/TextField.d.ts +2 -0
- package/dist/core/components/fields/TextField.js +2 -2
- package/dist/core/components/fields/TimestampField.d.ts +2 -1
- package/dist/core/components/fields/TimestampField.js +3 -3
- package/dist/core/components/fields/asset/AssetEditor.js +12 -44
- package/dist/core/components/fields/asset/AssetPicker.js +6 -6
- package/dist/core/components/fields/asset/AssetUploader.js +23 -31
- package/dist/core/components/fields/asset/preview/VideoPreview.js +16 -11
- package/dist/core/components/fields/asset/useAssetFields.d.ts +2 -17
- package/dist/core/components/fields/asset/useAssetFields.js +0 -21
- package/dist/core/components/fields/collection/CollectionEditor.js +1 -1
- package/dist/core/components/fields/collection/CollectionPicker.d.ts +2 -2
- package/dist/core/components/fields/collection/CollectionPicker.js +3 -4
- package/dist/core/components/fields/dynamicPages/PagePriorityDialog.js +1 -1
- package/dist/core/components/fields/embed/EmbeddedVideoEditor.js +34 -27
- package/dist/core/components/fields/factories/FieldValueFactory.js +11 -4
- package/dist/core/components/fields/factories/MediaFactory.d.ts +13 -0
- package/dist/core/components/fields/factories/MediaFactory.js +256 -0
- package/dist/core/components/fields/list/CreateFieldButton.js +1 -1
- package/dist/core/components/fields/media/MediaCard.d.ts +7 -0
- package/dist/core/components/fields/media/MediaCard.js +92 -0
- package/dist/core/components/fields/media/MediaEditor.d.ts +37 -0
- package/dist/core/components/fields/media/MediaEditor.js +235 -0
- package/dist/core/components/fields/media/MediaPicker.d.ts +15 -0
- package/dist/core/components/fields/media/MediaPicker.js +251 -0
- package/dist/core/components/fields/media/index.d.ts +3 -0
- package/dist/core/components/fields/media/index.js +19 -0
- package/dist/core/components/fields/object/ObjectEditor.js +1 -1
- package/dist/core/components/fields/page/PagePicker.js +1 -1
- package/dist/core/components/interaction/Combobox.js +1 -1
- package/dist/core/components/interaction/MultiSelectControls.js +2 -5
- package/dist/core/components/interaction/QuickEditor.js +1 -1
- package/dist/core/components/interaction/QuickPicker.js +1 -1
- package/dist/core/components/interaction/SideSheet.js +1 -1
- package/dist/core/components/interaction/centersheet/CenterSheet.js +7 -1
- package/dist/core/components/interaction/centersheet/CenterSheetContainer.js +3 -1
- package/dist/core/components/transitions/FadeIn.js +1 -1
- package/dist/core/components/visuals/Icon.d.ts +1 -1
- package/dist/core/components/visuals/Icon.js +3 -0
- package/dist/core/containers/AssetRepositoryContainer.d.ts +2 -0
- package/dist/core/containers/AssetRepositoryContainer.js +18 -0
- package/dist/core/containers/CollectionRepositoryContainer.d.ts +2 -0
- package/dist/core/containers/CollectionRepositoryContainer.js +18 -0
- package/dist/core/containers/PageRepositoryContainer.d.ts +2 -0
- package/dist/core/containers/PageRepositoryContainer.js +18 -0
- package/dist/core/containers/index.d.ts +3 -0
- package/dist/core/containers/index.js +19 -0
- package/dist/core/domain/Block.js +2 -1
- package/dist/core/domain/BlockConfiguration.d.ts +4 -1
- package/dist/core/domain/BlockConfiguration.js +59 -3
- package/dist/core/domain/Collection.d.ts +7 -25
- package/dist/core/domain/Collection.js +2 -16
- package/dist/core/domain/CollectionBrowser.d.ts +3 -2
- package/dist/core/domain/CollectionBrowser.js +3 -3
- package/dist/core/domain/CollectionFieldProxy.d.ts +12 -8
- package/dist/core/domain/CollectionFieldProxy.js +14 -8
- package/dist/core/domain/CollectionGroup.d.ts +0 -5
- package/dist/core/domain/CollectionGroup.js +0 -7
- package/dist/core/domain/CollectionSummary.d.ts +2 -2
- package/dist/core/domain/Collections.d.ts +3 -3
- package/dist/core/domain/Collections.js +4 -4
- package/dist/core/domain/ICollection.d.ts +71 -0
- package/dist/core/domain/ICollection.js +20 -0
- package/dist/core/domain/IPage.d.ts +14 -0
- package/dist/core/domain/Page.js +2 -2
- package/dist/core/domain/Pages.js +4 -6
- package/dist/core/domain/SectionBlock.js +2 -1
- package/dist/core/domain/Site.d.ts +4 -4
- package/dist/core/domain/Site.js +3 -3
- package/dist/core/domain/index.d.ts +1 -1
- package/dist/core/domain/index.js +1 -1
- package/dist/core/hooks/index.d.ts +4 -3
- package/dist/core/hooks/index.js +4 -3
- package/dist/core/hooks/useAssetRepository.d.ts +3 -0
- package/dist/core/hooks/useAssetRepository.js +11 -0
- package/dist/core/hooks/useCollection.d.ts +4 -4
- package/dist/core/hooks/useCollectionRepository.d.ts +3 -2
- package/dist/core/hooks/useCollectionRepository.js +4 -4
- package/dist/core/hooks/usePageRepository.d.ts +3 -2
- package/dist/core/hooks/usePageRepository.js +4 -4
- package/dist/core/hooks/useTempFields.d.ts +2 -3
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/repository/AssetRepository.d.ts +10 -0
- package/dist/core/repository/AssetRepository.js +22 -0
- package/dist/core/repository/CollectionRepository.d.ts +21 -20
- package/dist/core/repository/CollectionRepository.js +23 -161
- package/dist/core/repository/CollectionSerializer.d.ts +4 -1
- package/dist/core/repository/CollectionSerializer.js +3 -3
- package/dist/core/repository/IAssetRepository.d.ts +25 -0
- package/dist/core/repository/ICollectionRepository.d.ts +62 -0
- package/dist/core/repository/ICollectionRepository.js +2 -0
- package/dist/core/repository/IPageRepository.d.ts +40 -0
- package/dist/core/repository/IPageRepository.js +2 -0
- package/dist/core/repository/PageRepository.d.ts +5 -8
- package/dist/core/repository/PageRepository.js +7 -280
- package/dist/core/repository/SerializeCollectionUpdate.d.ts +8 -0
- package/dist/core/repository/SerializeCollectionUpdate.js +168 -0
- package/dist/core/repository/SerializePageUpdate.d.ts +11 -0
- package/dist/core/repository/SerializePageUpdate.js +292 -0
- package/dist/core/repository/index.d.ts +4 -0
- package/dist/core/repository/index.js +4 -0
- package/dist/dashboard/screens/Dashboard.js +1 -1
- package/dist/devtools/screens/Devtools.js +1 -1
- package/dist/explore/components/CreatePageDialog.d.ts +2 -2
- package/dist/explore/screens/CollectionExplorer.js +1 -1
- package/dist/explore/screens/CollectionsExplorer.js +1 -1
- package/dist/explore/screens/PageExplorer.js +1 -1
- package/dist/explore/screens/SiteExplorer.js +1 -1
- package/dist/page/components/BlockEditor.js +1 -1
- package/dist/page/components/SettingsEditor.js +0 -7
- package/dist/page/components/config/BlockConfigButton.js +71 -14
- package/dist/page/screens/PageEditor.js +1 -1
- package/dist/styles/index.css +24 -20
- package/dist/styles/tailwind.js +1 -0
- package/dist/users/screens/UserExplorer.js +1 -1
- package/package.json +2 -2
- package/dist/core/domain/TranslateSchema.d.ts +0 -7
- /package/dist/core/{domain/TranslateSchema.js → repository/IAssetRepository.js} +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MediaFactory = MediaFactory;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
6
|
+
const funnel_ui_1 = require("@nascentdigital/funnel-ui");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const interaction_1 = require("../../interaction");
|
|
9
|
+
const asset_1 = require("../asset");
|
|
10
|
+
const embed_1 = require("../embed");
|
|
11
|
+
const media_1 = require("../media");
|
|
12
|
+
// component
|
|
13
|
+
function MediaFactory({ schema, language, media: initialValue, anchor, onCommit: onCommitRaw, onCancel: onCancelRaw }) {
|
|
14
|
+
// bind refs
|
|
15
|
+
const menu = (0, interaction_1.useMenuController)();
|
|
16
|
+
const pickerRef = (0, react_1.useRef)(null);
|
|
17
|
+
const editorRef = (0, react_1.useRef)(null);
|
|
18
|
+
const assetPickerRef = (0, react_1.useRef)(null);
|
|
19
|
+
const assetUploaderRef = (0, react_1.useRef)(null);
|
|
20
|
+
const embeddedVideoEditorRef = (0, react_1.useRef)(null);
|
|
21
|
+
const anchorRef = (0, react_1.useRef)(anchor);
|
|
22
|
+
anchorRef.current = anchor;
|
|
23
|
+
const onCommitRef = (0, react_1.useRef)(onCommitRaw);
|
|
24
|
+
onCommitRef.current = onCommitRaw;
|
|
25
|
+
const onCancelRef = (0, react_1.useRef)(onCancelRaw);
|
|
26
|
+
onCancelRef.current = onCancelRaw;
|
|
27
|
+
const collectionOptions = schema.collections;
|
|
28
|
+
// open menu when bound
|
|
29
|
+
(0, react_1.useEffect)(() => {
|
|
30
|
+
// open menu if new
|
|
31
|
+
if (!initialValue) {
|
|
32
|
+
menu.items = mediaMenuOption;
|
|
33
|
+
menu.open(anchorRef.current);
|
|
34
|
+
}
|
|
35
|
+
// or open editor
|
|
36
|
+
else {
|
|
37
|
+
// blow up if editor isn't available (shouldn't happen)
|
|
38
|
+
const editor = editorRef.current;
|
|
39
|
+
const anchor = anchorRef.current;
|
|
40
|
+
if (!editor) {
|
|
41
|
+
throw new funnel_core_1.IllegalStateError('Unable to resolve reference to MediaEditor');
|
|
42
|
+
}
|
|
43
|
+
// start picker (cancel if nothing was picked
|
|
44
|
+
editor.edit({
|
|
45
|
+
schema,
|
|
46
|
+
target: { type: 'media', media: initialValue },
|
|
47
|
+
anchor
|
|
48
|
+
})
|
|
49
|
+
.then(async (media) => {
|
|
50
|
+
var _a;
|
|
51
|
+
console.debug('[MediaFactory/onEdit] editing completed', media);
|
|
52
|
+
// cancel if there's no media
|
|
53
|
+
if (!media) {
|
|
54
|
+
onCancelRef.current();
|
|
55
|
+
}
|
|
56
|
+
// or switch to picker
|
|
57
|
+
else if (media === 'pick') {
|
|
58
|
+
// start picker (cancel if nothing was picked
|
|
59
|
+
const media = await ((_a = pickerRef.current) === null || _a === void 0 ? void 0 : _a.pick({ schema }));
|
|
60
|
+
if (!media) {
|
|
61
|
+
onCancelRef.current();
|
|
62
|
+
}
|
|
63
|
+
// otherwise, return result
|
|
64
|
+
else {
|
|
65
|
+
onCommitRef.current({
|
|
66
|
+
id: media.id,
|
|
67
|
+
type: media.template.type
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// or commit change
|
|
72
|
+
else {
|
|
73
|
+
onCommitRef.current(media);
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.catch(console.error);
|
|
77
|
+
}
|
|
78
|
+
}, [menu, schema, collectionOptions, initialValue]);
|
|
79
|
+
// helpers
|
|
80
|
+
const onEdit = async (target) => {
|
|
81
|
+
var _a;
|
|
82
|
+
// start picker (cancel if nothing was picked
|
|
83
|
+
const media = await ((_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.edit({
|
|
84
|
+
schema,
|
|
85
|
+
target,
|
|
86
|
+
anchor
|
|
87
|
+
}));
|
|
88
|
+
// stop if cancelled
|
|
89
|
+
if (!media) {
|
|
90
|
+
onCancel();
|
|
91
|
+
}
|
|
92
|
+
// or switch to picker
|
|
93
|
+
else if (media === 'pick') {
|
|
94
|
+
// pick media
|
|
95
|
+
const pick = await onPickMedia();
|
|
96
|
+
// cancel if nothing got picked
|
|
97
|
+
if (!pick) {
|
|
98
|
+
onCancel();
|
|
99
|
+
}
|
|
100
|
+
// or commit selection
|
|
101
|
+
else {
|
|
102
|
+
onCommit({
|
|
103
|
+
id: pick.id,
|
|
104
|
+
type: pick.template.type
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// otherwise, return result
|
|
109
|
+
else {
|
|
110
|
+
onCommit(media);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const onPickMedia = async () => {
|
|
114
|
+
var _a;
|
|
115
|
+
// start picker (cancel if nothing was picked
|
|
116
|
+
const media = await ((_a = pickerRef.current) === null || _a === void 0 ? void 0 : _a.pick({ schema }));
|
|
117
|
+
return media !== null && media !== void 0 ? media : undefined;
|
|
118
|
+
};
|
|
119
|
+
const onUploadAsset = async () => {
|
|
120
|
+
var _a;
|
|
121
|
+
// launch uploader (or skip if there's no result)
|
|
122
|
+
const result = await ((_a = assetUploaderRef.current) === null || _a === void 0 ? void 0 : _a.upload({
|
|
123
|
+
schema: mediaUploadSchema,
|
|
124
|
+
anchor
|
|
125
|
+
}));
|
|
126
|
+
if (!result) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
// or switch to picking
|
|
130
|
+
else if (result === 'pick') {
|
|
131
|
+
return onPickAsset();
|
|
132
|
+
}
|
|
133
|
+
// create new image media
|
|
134
|
+
const { value: asset } = result;
|
|
135
|
+
if (funnel_core_1.Schema.AssetField.LinkedValue.Image.filter(asset)) {
|
|
136
|
+
console.debug('[MediaFactory] creating new image media');
|
|
137
|
+
return asset;
|
|
138
|
+
}
|
|
139
|
+
// or create new video media
|
|
140
|
+
else if (funnel_core_1.Schema.AssetField.LinkedValue.Video.filter(asset)) {
|
|
141
|
+
console.debug('[MediaFactory] creating new video media');
|
|
142
|
+
return asset;
|
|
143
|
+
}
|
|
144
|
+
// or abort
|
|
145
|
+
else {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const onPickAsset = async () => {
|
|
150
|
+
var _a;
|
|
151
|
+
// launch picker (or cancel if nothing is selected)
|
|
152
|
+
const result = await ((_a = assetPickerRef.current) === null || _a === void 0 ? void 0 : _a.pick({
|
|
153
|
+
schema: mediaUploadSchema
|
|
154
|
+
}));
|
|
155
|
+
if (!result) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
// or launch uploader if the directive was received
|
|
159
|
+
else if (result === 'upload') {
|
|
160
|
+
return onUploadAsset();
|
|
161
|
+
}
|
|
162
|
+
// create new image media
|
|
163
|
+
const { value: asset } = result;
|
|
164
|
+
if (funnel_core_1.Schema.AssetField.LinkedValue.Image.filter(asset)) {
|
|
165
|
+
console.debug('[MediaFactory] creating new image media');
|
|
166
|
+
return asset;
|
|
167
|
+
}
|
|
168
|
+
// or create new video media
|
|
169
|
+
else if (funnel_core_1.Schema.AssetField.LinkedValue.Video.filter(asset)) {
|
|
170
|
+
console.debug('[MediaFactory] creating new video media');
|
|
171
|
+
return asset;
|
|
172
|
+
}
|
|
173
|
+
// or abort
|
|
174
|
+
else {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const onLinkVideo = async () => {
|
|
179
|
+
var _a, _b;
|
|
180
|
+
// start editor (cancel if dismissed)
|
|
181
|
+
const value = await ((_a = embeddedVideoEditorRef.current) === null || _a === void 0 ? void 0 : _a.edit({
|
|
182
|
+
schema: funnel_ui_1.Media.Video.Source.schema.content.remote.schema,
|
|
183
|
+
anchor: anchorRef.current
|
|
184
|
+
}));
|
|
185
|
+
return (_b = value === null || value === void 0 ? void 0 : value.value) !== null && _b !== void 0 ? _b : undefined;
|
|
186
|
+
};
|
|
187
|
+
const onMenuSelect = async (option) => {
|
|
188
|
+
// process based on option
|
|
189
|
+
switch (option) {
|
|
190
|
+
case 'pick': {
|
|
191
|
+
// pick media (or cancel if nothing was picked)
|
|
192
|
+
const media = await onPickMedia();
|
|
193
|
+
if (!media) {
|
|
194
|
+
onCancel();
|
|
195
|
+
}
|
|
196
|
+
// or commit
|
|
197
|
+
else {
|
|
198
|
+
onCommitRef.current({
|
|
199
|
+
id: media.id,
|
|
200
|
+
type: media.template.type
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
// stop processing
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case 'add.asset': {
|
|
207
|
+
// get visual (or cancel)
|
|
208
|
+
const asset = await onUploadAsset();
|
|
209
|
+
if (!asset) {
|
|
210
|
+
onCancel();
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
// open editor with asset
|
|
214
|
+
await onEdit(funnel_core_1.Schema.AssetField.LinkedValue.Image.filter(asset)
|
|
215
|
+
? { type: 'image', image: asset }
|
|
216
|
+
: { type: 'video.local', video: asset });
|
|
217
|
+
// stop processing
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case 'add.url': {
|
|
221
|
+
// link video (or cancel)
|
|
222
|
+
const video = await onLinkVideo();
|
|
223
|
+
if (!video) {
|
|
224
|
+
onCancel();
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
// open editor with video
|
|
228
|
+
await onEdit({ type: 'video.remote', video });
|
|
229
|
+
// stop processing
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const onCommit = (media) => onCommitRef.current(media);
|
|
235
|
+
const onCancel = () => onCancelRef.current();
|
|
236
|
+
// render
|
|
237
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(interaction_1.Menu, { controller: menu, onItemClick: onMenuSelect, onClose: onCancel }), (0, jsx_runtime_1.jsx)(media_1.MediaPicker, { ref: pickerRef, language: language }), (0, jsx_runtime_1.jsx)(media_1.MediaEditor, { ref: editorRef, language: language }), (0, jsx_runtime_1.jsx)(asset_1.AssetUploader, { ref: assetUploaderRef }), (0, jsx_runtime_1.jsx)(asset_1.AssetPicker, { ref: assetPickerRef }), (0, jsx_runtime_1.jsx)(embed_1.EmbeddedVideoEditor, { ref: embeddedVideoEditorRef, language: language })] }));
|
|
238
|
+
}
|
|
239
|
+
const mediaMenuOption = [
|
|
240
|
+
{
|
|
241
|
+
id: 'pick',
|
|
242
|
+
label: 'Use existing media',
|
|
243
|
+
icon: 'FileSearchCorner'
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: 'add.asset',
|
|
247
|
+
label: 'Upload new asset',
|
|
248
|
+
icon: 'ImageDown'
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
id: 'add.url',
|
|
252
|
+
label: 'Link to Video',
|
|
253
|
+
icon: 'Link2'
|
|
254
|
+
}
|
|
255
|
+
];
|
|
256
|
+
const mediaUploadSchema = funnel_core_1.Schema.Field.visual({ name: 'Image or Video' });
|
|
@@ -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: "
|
|
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,37 @@
|
|
|
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 = {
|
|
32
|
+
schema: Media.Schema;
|
|
33
|
+
target: Target;
|
|
34
|
+
anchor: Popup.Anchor;
|
|
35
|
+
};
|
|
36
|
+
type Result = Media.Value | 'pick' | undefined;
|
|
37
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MediaEditor = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
6
|
+
const funnel_ui_1 = require("@nascentdigital/funnel-ui");
|
|
7
|
+
const framer_motion_1 = require("framer-motion");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const domain_1 = require("../../../domain");
|
|
10
|
+
const hooks_1 = require("../../../hooks");
|
|
11
|
+
const feedback_1 = require("../../feedback");
|
|
12
|
+
const interaction_1 = require("../../interaction");
|
|
13
|
+
const FieldEditor_1 = require("../FieldEditor");
|
|
14
|
+
const FieldErrorController_1 = require("../FieldErrorController");
|
|
15
|
+
const OptInField_1 = require("../OptInField");
|
|
16
|
+
// component
|
|
17
|
+
exports.MediaEditor = (0, react_1.forwardRef)(function MediaEditor({ language }, ref) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
// bind props + hooks
|
|
20
|
+
const [deferral, setDeferral] = (0, react_1.useState)(undefined);
|
|
21
|
+
const [result, setResult] = (0, react_1.useState)();
|
|
22
|
+
const [target, setTarget] = (0, react_1.useState)();
|
|
23
|
+
const [anchor, setAnchor] = (0, react_1.useState)();
|
|
24
|
+
const [fieldSchema, setFieldSchema] = (0, react_1.useState)();
|
|
25
|
+
const [mediaSchema, setMediaSchema] = (0, react_1.useState)();
|
|
26
|
+
const [shared, setShared] = (0, react_1.useState)(false);
|
|
27
|
+
const [errorLevel, setErrorLevel] = (0, react_1.useState)('none');
|
|
28
|
+
const [error, setError] = (0, react_1.useState)();
|
|
29
|
+
const [field, setField] = (0, react_1.useState)();
|
|
30
|
+
const page = (0, hooks_1.usePossiblePage)();
|
|
31
|
+
const collection = (0, hooks_1.usePossibleCollection)();
|
|
32
|
+
const collectionRepository = (0, hooks_1.useCollectionRepository)();
|
|
33
|
+
const collectionStore = page !== null && page !== void 0 ? page : collection;
|
|
34
|
+
const assetStore = page !== null && page !== void 0 ? page : collection;
|
|
35
|
+
const dialog = (0, feedback_1.useDialog)();
|
|
36
|
+
const valid = (_a = field === null || field === void 0 ? void 0 : field.valid) !== null && _a !== void 0 ? _a : false;
|
|
37
|
+
const modified = (_b = field === null || field === void 0 ? void 0 : field.modified) !== null && _b !== void 0 ? _b : false;
|
|
38
|
+
// sync with field
|
|
39
|
+
(0, hooks_1.useCollectionFieldProxy)(field);
|
|
40
|
+
// export service
|
|
41
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
42
|
+
edit: async ({ schema, target, anchor }) => {
|
|
43
|
+
// reset state
|
|
44
|
+
setFieldSchema(schema);
|
|
45
|
+
setMediaSchema(target.type === 'image' || (target.type === 'media' && funnel_ui_1.Media.Value.isImage(target.media))
|
|
46
|
+
? funnel_ui_1.Media.Image.collection
|
|
47
|
+
: funnel_ui_1.Media.Video.collection);
|
|
48
|
+
setTarget(target);
|
|
49
|
+
setField(undefined);
|
|
50
|
+
setShared(false);
|
|
51
|
+
setAnchor(anchor);
|
|
52
|
+
setErrorLevel('none');
|
|
53
|
+
setError(undefined);
|
|
54
|
+
// create deferral
|
|
55
|
+
const deferral = new funnel_core_1.Deferral();
|
|
56
|
+
setDeferral(deferral);
|
|
57
|
+
setResult(undefined);
|
|
58
|
+
// wait until deferral is resolved
|
|
59
|
+
return deferral.promise;
|
|
60
|
+
}
|
|
61
|
+
}), []);
|
|
62
|
+
// create field
|
|
63
|
+
(0, react_1.useEffect)(() => {
|
|
64
|
+
// ignore if schemas aren't set
|
|
65
|
+
if (!fieldSchema || !mediaSchema || !collectionStore || !assetStore || !target) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// create new field (wraps existing data for editing)
|
|
69
|
+
domain_1.CollectionFieldProxy
|
|
70
|
+
.create({
|
|
71
|
+
collectionRepository,
|
|
72
|
+
collectionStore,
|
|
73
|
+
assetStore,
|
|
74
|
+
schema: fieldSchema,
|
|
75
|
+
collectionSchema: mediaSchema,
|
|
76
|
+
language,
|
|
77
|
+
initialValue: target.type === 'media' ? target.media : undefined
|
|
78
|
+
})
|
|
79
|
+
.then(field => {
|
|
80
|
+
// bind image (if partial)
|
|
81
|
+
switch (target.type) {
|
|
82
|
+
case 'image': {
|
|
83
|
+
const collection = field;
|
|
84
|
+
const imageField = collection.getField('image');
|
|
85
|
+
imageField.value = funnel_core_1.Schema.AssetField.Value.toData(target.image);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'video.local': {
|
|
89
|
+
const collection = field;
|
|
90
|
+
const videoField = collection.getField('video');
|
|
91
|
+
const typeField = videoField.getField('type');
|
|
92
|
+
typeField.value = funnel_core_1.Schema.EnumField.Value.toData('local');
|
|
93
|
+
const localVideoField = videoField.getField('local');
|
|
94
|
+
localVideoField.optIn();
|
|
95
|
+
localVideoField.value = funnel_core_1.Schema.AssetField.Value.toData(target.video);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'video.remote': {
|
|
99
|
+
const collection = field;
|
|
100
|
+
const videoField = collection.getField('video');
|
|
101
|
+
const typeField = videoField.getField('type');
|
|
102
|
+
typeField.value = funnel_core_1.Schema.EnumField.Value.toData('remote');
|
|
103
|
+
const remoteVideoField = videoField.getField('remote');
|
|
104
|
+
remoteVideoField.optIn();
|
|
105
|
+
remoteVideoField.value = funnel_core_1.Schema.EmbeddedVideoField.Value.toData(target.video);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// bind field
|
|
110
|
+
setField(field);
|
|
111
|
+
setShared(!field.isNew && field.isRef);
|
|
112
|
+
});
|
|
113
|
+
}, [language, collectionRepository, collectionStore, assetStore, fieldSchema, mediaSchema, target]);
|
|
114
|
+
// skip if there's no schema or value
|
|
115
|
+
if (!fieldSchema || !mediaSchema || !field || !target || !collectionStore || !assetStore) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
// helpers
|
|
119
|
+
const onValidate = () => {
|
|
120
|
+
// update error level
|
|
121
|
+
setErrorLevel('all');
|
|
122
|
+
// return validity
|
|
123
|
+
return valid;
|
|
124
|
+
};
|
|
125
|
+
const onSave = async () => {
|
|
126
|
+
// skip there's no field (should never happen)
|
|
127
|
+
if (!field) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// confirm if it's shared (skip if user bails)
|
|
131
|
+
if (shared) {
|
|
132
|
+
const confirmed = await dialog.confirm(field.isNew
|
|
133
|
+
?
|
|
134
|
+
{
|
|
135
|
+
title: `Create a new ${mediaSchema.name}?`,
|
|
136
|
+
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."] })] })),
|
|
137
|
+
confirmLabel: 'Update'
|
|
138
|
+
}
|
|
139
|
+
:
|
|
140
|
+
{
|
|
141
|
+
title: `Update shared ${mediaSchema.name}?`,
|
|
142
|
+
message: 'Updating this content may affect other pages.',
|
|
143
|
+
confirmLabel: 'Update'
|
|
144
|
+
});
|
|
145
|
+
if (!confirmed) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// TODO: handle errors
|
|
150
|
+
// save
|
|
151
|
+
await field.save(shared);
|
|
152
|
+
// update after closing
|
|
153
|
+
setResult(field.value);
|
|
154
|
+
};
|
|
155
|
+
const onCancel = async () => {
|
|
156
|
+
// skip there's no field (should never happen)
|
|
157
|
+
if (!field) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// confirm if there are unsaved changes
|
|
161
|
+
if (field.modified) {
|
|
162
|
+
// confirm
|
|
163
|
+
const confirmed = await dialog.confirm({
|
|
164
|
+
title: 'Are you sure?',
|
|
165
|
+
message: 'You have unsaved changes that you\'ll lose.',
|
|
166
|
+
confirmLabel: 'Yes',
|
|
167
|
+
destructive: true
|
|
168
|
+
});
|
|
169
|
+
// skip if user cancelled
|
|
170
|
+
if (!confirmed) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// set result (triggers editor to close)
|
|
175
|
+
setResult(null);
|
|
176
|
+
};
|
|
177
|
+
const onClosed = () => {
|
|
178
|
+
// skip if missing or already completed
|
|
179
|
+
if (!deferral || deferral.isComplete) {
|
|
180
|
+
console.debug('[MediaEditor/onClosed] ignoring invalid trigger');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
console.debug('[MediaEditor/onClosed] completing edit:', result);
|
|
184
|
+
// clear field
|
|
185
|
+
setFieldSchema(undefined);
|
|
186
|
+
setMediaSchema(undefined);
|
|
187
|
+
setTarget(undefined);
|
|
188
|
+
setField(undefined);
|
|
189
|
+
// complete deferral
|
|
190
|
+
deferral.resolve(result !== null && result !== void 0 ? result : undefined);
|
|
191
|
+
};
|
|
192
|
+
// render
|
|
193
|
+
return ((0, jsx_runtime_1.jsx)(interaction_1.MiniEditor, { className: "flex flex-col gap-l8", title: `Edit Media`, open: !!deferral && result === undefined, placement: "right", anchor: anchor, anchorOffset: 4, disableSave: !modified, canSave: onValidate, onSave: onSave, renderSaveLabel: state => state === 'saving' ? 'Updating...' : 'Update', customActions: (0, jsx_runtime_1.jsx)(interaction_1.Button, { variant: "secondary", size: "sm", onClick: () => setResult('pick'), children: "Use existing media" }), onClose: onCancel, onClosed: onClosed, children: (0, jsx_runtime_1.jsx)(hooks_1.CollectionStoreContext.Provider, { value: collectionStore, children: (0, jsx_runtime_1.jsxs)(hooks_1.AssetStoreContext.Provider, { value: assetStore, children: [mediaSchema.description && !error &&
|
|
194
|
+
(0, jsx_runtime_1.jsx)(feedback_1.Note, { variant: "tip", children: mediaSchema.description }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: (0, jsx_runtime_1.jsxs)(FieldErrorController_1.FieldErrorController, { errorLevel: errorLevel, children: [(0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: field.nameField, autoFocus: true }), renderFields({ field })] }) })] }) }) }));
|
|
195
|
+
});
|
|
196
|
+
function renderFields(args) {
|
|
197
|
+
// render image fields
|
|
198
|
+
const value = args.field.value;
|
|
199
|
+
if (funnel_ui_1.Media.Value.isImage(value)) {
|
|
200
|
+
return renderImageFields(args);
|
|
201
|
+
}
|
|
202
|
+
// or video fields
|
|
203
|
+
else {
|
|
204
|
+
return renderVideoFields(args);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function renderImageFields({ field }) {
|
|
208
|
+
// resolve fields
|
|
209
|
+
const desktopImageField = field.getField('image');
|
|
210
|
+
const mobileImageField = field.getField('mobileImage');
|
|
211
|
+
// render
|
|
212
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: desktopImageField, disableDelete: true }), mobileImageField.exists
|
|
213
|
+
? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: mobileImageField })
|
|
214
|
+
: (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { className: "self-start", field: mobileImageField })] }));
|
|
215
|
+
}
|
|
216
|
+
function renderVideoFields({ field }) {
|
|
217
|
+
var _a, _b;
|
|
218
|
+
// resolve fields
|
|
219
|
+
const sourceField = field.getField('video');
|
|
220
|
+
const localVideoField = sourceField.getField('local');
|
|
221
|
+
const localVideo = (_a = localVideoField.value) === null || _a === void 0 ? void 0 : _a.value;
|
|
222
|
+
const remoteVideoField = sourceField.getField('remote');
|
|
223
|
+
const remoteVideo = (_b = remoteVideoField.value) === null || _b === void 0 ? void 0 : _b.value;
|
|
224
|
+
const coverField = field.getField('cover');
|
|
225
|
+
// TODO render error if there's no video source
|
|
226
|
+
if (!localVideo && !remoteVideo) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
// render
|
|
230
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: localVideo
|
|
231
|
+
? localVideoField
|
|
232
|
+
: remoteVideoField, disableDelete: true }), coverField.exists
|
|
233
|
+
? (0, jsx_runtime_1.jsx)(FieldEditor_1.FieldEditor, { field: coverField })
|
|
234
|
+
: (0, jsx_runtime_1.jsx)(OptInField_1.OptInField, { className: "self-start", field: coverField })] }));
|
|
235
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Language, Schema } from '@nascentdigital/funnel-core';
|
|
2
|
+
import { ICollection } from '../../../domain';
|
|
3
|
+
export declare const MediaPicker: import("react").ForwardRefExoticComponent<MediaPicker.Props & import("react").RefAttributes<MediaPicker.Ref>>;
|
|
4
|
+
export declare namespace MediaPicker {
|
|
5
|
+
type Props = {
|
|
6
|
+
language: Language;
|
|
7
|
+
};
|
|
8
|
+
interface Ref {
|
|
9
|
+
pick(options?: Options): Promise<Result>;
|
|
10
|
+
}
|
|
11
|
+
type Options = {
|
|
12
|
+
schema: Schema.CollectionField;
|
|
13
|
+
};
|
|
14
|
+
type Result = ICollection.Ref | undefined;
|
|
15
|
+
}
|