@nascentdigital/funnel-editor 4.5.0 → 4.5.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.
@@ -1,13 +1,456 @@
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
  };
5
16
  Object.defineProperty(exports, "__esModule", { value: true });
6
17
  exports.BlockPreview = BlockPreview;
7
18
  const jsx_runtime_1 = require("react/jsx-runtime");
19
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
8
20
  const classnames_1 = __importDefault(require("classnames"));
21
+ const react_1 = require("react");
22
+ const core_1 = require("../../../core");
9
23
  // component
10
- function BlockPreview({ className, variant }) {
24
+ function BlockPreview({ className, variant, configuration }) {
25
+ // determine active panels
26
+ const { layout } = configuration;
27
+ // sync configuration
28
+ (0, core_1.useBlockConfiguration)(configuration);
29
+ // helpers
30
+ const onPanelClick = (panel) => {
31
+ console.debug('[BlockPreview] opening panel editor', panel);
32
+ };
33
+ // render
34
+ const tight = variant === 'mobile'
35
+ ? layout === null || layout === void 0 ? void 0 : layout.tight.mobile
36
+ : layout === null || layout === void 0 ? void 0 : layout.tight.desktop;
37
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'w-full flex justify-center'), children: (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('bg-surface2 rounded-xs', {
38
+ 'min-h-[100px]': !layout,
39
+ 'w-[120px]': variant === 'desktop',
40
+ 'w-[64px]': variant === 'mobile',
41
+ 'pb-l4': tight === 'above',
42
+ 'pt-l4': tight === 'below',
43
+ 'py-l4': tight === 'none'
44
+ }), children: renderLayout({ variant, layout, onPanelClick }) }) }));
45
+ }
46
+ // helpers
47
+ var Skeleton;
48
+ (function (Skeleton) {
49
+ function HeadlinePart({ className, size }) {
50
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'bg-ix-primary rounded-xxs overflow-hidden', {
51
+ 'h-6 ': size === 'sm',
52
+ 'h-8': size === 'md'
53
+ }) }));
54
+ }
55
+ Skeleton.HeadlinePart = HeadlinePart;
56
+ function CaptionPart({ className, size }) {
57
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'h-4 bg-draft/tint3 rounded-px overflow-hidden', {
58
+ '': size === 'sm'
59
+ }) }));
60
+ }
61
+ Skeleton.CaptionPart = CaptionPart;
62
+ function MediaPart({ className, aspect }) {
63
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'flex justify-center items-center bg-draft/tint3 rounded-xxs overflow-hidden', {
64
+ 'aspect-square': aspect === 'square' || aspect === 'auto',
65
+ 'aspect-phone': aspect === 'phone',
66
+ 'aspect-tv': aspect === 'tv',
67
+ 'aspect-widescreen': aspect === 'widescreen',
68
+ 'aspect-cinema': aspect === 'cinema'
69
+ }), children: (0, jsx_runtime_1.jsx)(core_1.Icon, { className: "text-content-tertiary", variant: "Image", size: {
70
+ size: 20,
71
+ strokeWidth: 1.5,
72
+ absoluteStrokeWidth: false
73
+ } }) }));
74
+ }
75
+ Skeleton.MediaPart = MediaPart;
76
+ function IconPart({ className, size }) {
77
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'bg-draft/tint3 rounded-full overflow-hidden', {
78
+ 'w-10 h-10': size === 'sm',
79
+ 'w-14 h-14': size === 'md'
80
+ }) }));
81
+ }
82
+ Skeleton.IconPart = IconPart;
83
+ function LogoPart({ className, size }) {
84
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'bg-draft/tint3 rounded-px overflow-hidden', {
85
+ 'w-14 h-6': size === 'sm',
86
+ 'w-20 h-9': size === 'md'
87
+ }) }));
88
+ }
89
+ Skeleton.LogoPart = LogoPart;
90
+ })(Skeleton || (Skeleton = {}));
91
+ function renderLayout({ className, variant, layout, onPanelClick }) {
92
+ // TODO: render empty state if there's no layout
93
+ if (!layout) {
94
+ return null;
95
+ }
96
+ // render root layout
97
+ const { type, items } = layout.root;
98
+ return ((0, jsx_runtime_1.jsx)("div", { className: getContainerClasses({ className, variant, siblingCount: 1, item: layout.root }), children: items.map((item, parentOffset) => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderItem({
99
+ className: (0, classnames_1.default)({
100
+ 'flex-1': type === 'row' && variant !== 'mobile'
101
+ }),
102
+ variant,
103
+ parent: type,
104
+ parentNested: false,
105
+ siblingCount: items.length,
106
+ item,
107
+ itemPosition: new ItemPosition({
108
+ parent: type,
109
+ parentOffset,
110
+ parentSize: items.length
111
+ }),
112
+ onPanelClick
113
+ }) }, `${item.type}.${parentOffset}`)) }));
114
+ }
115
+ function renderItem({ className, parent, parentNested, siblingCount, variant, item, itemPosition, onPanelClick }) {
116
+ // render item
117
+ const { type: itemType } = item;
118
+ switch (itemType) {
119
+ case 'row':
120
+ case 'column':
121
+ case 'stack':
122
+ return ((0, jsx_runtime_1.jsx)("div", { className: getContainerClasses({ className, parent, siblingCount, variant, item }), children: item.items.map((item, parentOffset, items) => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderItem({
123
+ className: (0, classnames_1.default)({
124
+ 'flex-1': itemType === 'row'
125
+ }),
126
+ variant,
127
+ parent: itemType,
128
+ parentNested: true,
129
+ siblingCount: items.length,
130
+ item: item,
131
+ itemPosition: new ItemPosition({
132
+ parent: itemType,
133
+ parentOffset,
134
+ parentSize: items.length
135
+ }),
136
+ onPanelClick
137
+ }) }, `${item.type}.${parentOffset}`)) }));
138
+ case 'message':
139
+ return renderMessage({ className, parent, parentNested, siblingCount, variant, item, itemPosition, onPanelClick });
140
+ case 'visual':
141
+ return renderVisual({ className, parent, parentNested, siblingCount, variant, item, itemPosition, onPanelClick });
142
+ case 'list':
143
+ return renderList({ className, parent, parentNested, siblingCount, variant, item, itemPosition, onPanelClick });
144
+ default:
145
+ console.error('[SkeletonLayout] no support for BlockLayout item', item);
146
+ return null;
147
+ }
148
+ }
149
+ function getContainerClasses({ className, variant, parent, item }) {
150
+ const { type, alignY } = item;
151
+ // row style
152
+ if (type === 'row' && variant !== 'mobile') {
153
+ return (0, classnames_1.default)(className, 'grid gap-l3 px-l4', {
154
+ 'items-start': alignY === 'start',
155
+ 'items-center': alignY === 'center',
156
+ 'items-end': alignY === 'end',
157
+ 'grid-cols-[1fr,1fr]': item.ratio.desktop === '1/1',
158
+ 'grid-cols-[1fr,2fr]': item.ratio.desktop === '1/2',
159
+ 'grid-cols-[1fr,3fr]': item.ratio.desktop === '1/3',
160
+ 'grid-cols-[2fr,1fr]': item.ratio.desktop === '2/1',
161
+ 'grid-cols-[2fr,3fr]': item.ratio.desktop === '2/3',
162
+ 'grid-cols-[3fr,1fr]': item.ratio.desktop === '3/1',
163
+ 'grid-cols-[3fr,2fr]': item.ratio.desktop === '3/2'
164
+ });
165
+ }
166
+ // or stack
167
+ else if (type === 'stack') {
168
+ return (0, classnames_1.default)(className, 'stacked-stretch');
169
+ }
170
+ // or column
171
+ else {
172
+ return (0, classnames_1.default)(className, 'flex flex-col gap-l4');
173
+ }
174
+ }
175
+ function renderMessage(args) {
176
+ // resolve props
177
+ const { variant, item: { textAlign } } = args;
178
+ const messageClasses = variant === 'mobile'
179
+ ? (0, classnames_1.default)({
180
+ 'items-start': textAlign.mobile === 'left',
181
+ 'items-center': textAlign.mobile === 'center',
182
+ 'items-end': textAlign.mobile === 'right'
183
+ })
184
+ : (0, classnames_1.default)({
185
+ 'items-start': textAlign.desktop === 'left',
186
+ 'items-center': textAlign.desktop === 'center',
187
+ 'items-end': textAlign.desktop === 'right'
188
+ });
189
+ // render
190
+ return ((0, jsx_runtime_1.jsxs)(EditablePanel, Object.assign({}, args, { panelClassName: (0, classnames_1.default)(messageClasses, getPanelClasses(Object.assign(Object.assign({}, args), { className: 'flex flex-col' }))), children: [(0, jsx_runtime_1.jsx)(Skeleton.HeadlinePart, { className: "w-full mb-l2", size: "md" }), (0, jsx_runtime_1.jsx)(Skeleton.CaptionPart, { className: "w-full mb-px", size: "md" }), (0, jsx_runtime_1.jsx)(Skeleton.CaptionPart, { className: "w-full mb-px", size: "md" }), (0, jsx_runtime_1.jsx)(Skeleton.CaptionPart, { className: "w-20", size: "md" })] })));
191
+ }
192
+ function renderVisual(args) {
193
+ // resolve props
194
+ const { variant, item: { aspectRatio }, parent } = args;
195
+ const aspect = variant === 'mobile' ? aspectRatio.mobile : aspectRatio.desktop;
196
+ // render
197
+ return ((0, jsx_runtime_1.jsx)(EditablePanel, Object.assign({}, args, { panelClassName: (0, classnames_1.default)(getPanelClasses(Object.assign(Object.assign({}, args), { className: '' }))), children: (0, jsx_runtime_1.jsx)(Skeleton.MediaPart, { className: "w-full", aspect: aspect }) })));
198
+ }
199
+ function renderList(args) {
200
+ // resolve props
201
+ const { variant, parent, parentNested, item: { layout: layoutRaw, itemType, itemCount: itemCountRaw } } = args;
202
+ const layout = variant === 'mobile'
203
+ ? layoutRaw.mobile
204
+ : layoutRaw.desktop;
205
+ // render a grid
206
+ if (layout === 'grid') {
207
+ return renderGrid(args);
208
+ }
209
+ // or render row/column
210
+ const itemCount = variant === 'mobile'
211
+ ? itemCountRaw.mobile
212
+ : itemCountRaw.desktop;
213
+ return ((0, jsx_runtime_1.jsx)(EditablePanel, Object.assign({}, args, { panelClassName: getListPanelClasses(args), children: funnel_core_1.ArrayUtils.series(itemCount, 1).map(row => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderListItem({ variant, parent, parentNested, layout, itemType, index: row, count: itemCount }) }, `list.${row}`)) })));
214
+ }
215
+ function getListPanelClasses(args) {
216
+ // resolve props
217
+ const { variant, item: { layout: layoutRaw } } = args;
218
+ const layout = variant === 'mobile'
219
+ ? layoutRaw.mobile
220
+ : layoutRaw.desktop;
221
+ // determine list classes
222
+ let listClasses = '';
223
+ switch (layout) {
224
+ case 'row':
225
+ listClasses = 'grid grid-rows-1 auto-cols-auto grid-flow-col gap-l2';
226
+ break;
227
+ case 'column':
228
+ listClasses = 'flex flex-col gap-l2';
229
+ break;
230
+ }
231
+ // return completed classes
232
+ return getPanelClasses(Object.assign(Object.assign({}, args), { className: listClasses }));
233
+ }
234
+ function renderListItem({ className, variant, parent, parentNested, layout, itemType, index, count }) {
235
+ let itemClassName = '';
236
+ switch (itemType) {
237
+ case 'message':
238
+ case 'message+visual':
239
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(className, 'flex flex-row p-3 bg-background rounded-xxs'), children: [itemType === 'message+visual' &&
240
+ (0, jsx_runtime_1.jsx)("div", { className: "flex justify-center items-center", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-content-tertiary rounded-full w-4 h-4" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex flex-col", children: [(0, jsx_runtime_1.jsx)(Skeleton.HeadlinePart, { className: "w-11/12 mb-l1", size: "sm" }), (0, jsx_runtime_1.jsx)(Skeleton.CaptionPart, { className: "w-full mb-px", size: "sm" }), (0, jsx_runtime_1.jsx)(Skeleton.CaptionPart, { className: "w-8/12", size: "sm" })] })] }));
241
+ case 'visual': {
242
+ // determine aspect
243
+ let aspect;
244
+ switch (layout) {
245
+ case 'column':
246
+ aspect = parent === 'row' || parentNested
247
+ ? 'widescreen'
248
+ : variant === 'mobile'
249
+ ? 'widescreen'
250
+ : 'cinema';
251
+ break;
252
+ case 'row':
253
+ aspect = parent === 'row' || parentNested
254
+ ? 'square'
255
+ : 'widescreen';
256
+ break;
257
+ case 'grid': {
258
+ // aspect for mobile/nested
259
+ if (variant === 'mobile' || parent === 'row' || parentNested) {
260
+ itemClassName = 'w-full';
261
+ aspect = count === 1
262
+ ? 'square'
263
+ : count <= 3
264
+ ? 'tv'
265
+ : 'widescreen';
266
+ }
267
+ // adjust aspect based on layout (if it's a grid)
268
+ else if (layout === 'grid') {
269
+ // set base class
270
+ itemClassName = 'min-w-[50px]';
271
+ // override base + pick aspect
272
+ switch (count) {
273
+ case 1:
274
+ aspect = 'widescreen';
275
+ break;
276
+ case 2:
277
+ aspect = 'widescreen';
278
+ break;
279
+ case 3:
280
+ itemClassName = index === 1
281
+ ? 'min-w-full'
282
+ : 'min-w-[50px]';
283
+ aspect = index === 1
284
+ ? 'cinema'
285
+ : 'tv';
286
+ break;
287
+ case 4:
288
+ aspect = 'tv';
289
+ break;
290
+ case 5:
291
+ itemClassName = index === 3
292
+ ? 'min-w-full'
293
+ : 'min-w-[50px]';
294
+ aspect = index === 3
295
+ ? 'cinema'
296
+ : 'tv';
297
+ break;
298
+ default:
299
+ aspect = 'widescreen';
300
+ break;
301
+ }
302
+ }
303
+ // otherwise standard
304
+ else {
305
+ aspect = 'widescreen';
306
+ }
307
+ break;
308
+ }
309
+ }
310
+ // create visual
311
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, itemClassName), children: (0, jsx_runtime_1.jsx)(Skeleton.MediaPart, { aspect: aspect }) }));
312
+ }
313
+ case 'icon':
314
+ return ((0, jsx_runtime_1.jsx)(Skeleton.IconPart, { className: (0, classnames_1.default)(className, itemClassName), size: variant === 'mobile' ? 'md' : 'sm' }));
315
+ case 'logo':
316
+ return ((0, jsx_runtime_1.jsx)(Skeleton.LogoPart, { className: (0, classnames_1.default)(className, itemClassName), size: variant === 'mobile' ? 'md' : 'sm' }));
317
+ default:
318
+ return null;
319
+ }
320
+ }
321
+ function renderGrid(args) {
322
+ // determine props
323
+ const { variant, parent, parentNested, item: { itemType, itemCount: itemCountRaw } } = args;
324
+ const itemCount = variant === 'mobile'
325
+ ? itemCountRaw.mobile
326
+ : itemCountRaw.desktop;
327
+ const { panelClassName, panelItemClassName } = getGridPanelClasses(args);
328
+ // render grid (really a flexbox layout with controlled item widths)
329
+ return ((0, jsx_runtime_1.jsx)(EditablePanel, Object.assign({}, args, { panelClassName: panelClassName, children: funnel_core_1.ArrayUtils.series(itemCount, 1).map(row => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderListItem({
330
+ className: panelItemClassName,
331
+ variant,
332
+ parent,
333
+ parentNested,
334
+ layout: 'grid',
335
+ itemType, index: row,
336
+ count: itemCount
337
+ }) }, `list.${row}`)) })));
338
+ }
339
+ function getGridPanelClasses(args) {
340
+ // resolve props
341
+ const { variant, parent, parentNested, item: { itemType, itemCount: itemCountRaw, itemAlign: itemAlignRaw } } = args;
342
+ const itemAlign = variant === 'mobile'
343
+ ? itemAlignRaw.mobile
344
+ : itemAlignRaw.desktop;
345
+ // determine list classes
346
+ const panelClasses = (0, classnames_1.default)('flex flex-wrap gap-l2', {
347
+ 'justify-center': itemAlign === 'center',
348
+ 'justify-end': itemAlign === 'end'
349
+ });
350
+ let panelItemClasses = '';
351
+ switch (itemType) {
352
+ case 'message':
353
+ case 'message+visual':
354
+ panelItemClasses = (0, classnames_1.default)({
355
+ 'w-full': variant === 'mobile' || (variant === 'desktop' && (parent === 'row' || parentNested)),
356
+ 'w-[50px]': variant === 'desktop' && parent !== 'row' && !parentNested
357
+ });
358
+ break;
359
+ case 'visual':
360
+ panelItemClasses = (0, classnames_1.default)({
361
+ '': variant === 'mobile' || (variant === 'desktop' && (parent === 'row' || parentNested)),
362
+ 'flex-1': variant === 'desktop' && parent !== 'row' && !parentNested
363
+ });
364
+ break;
365
+ case 'icon':
366
+ panelItemClasses = (0, classnames_1.default)({});
367
+ break;
368
+ case 'logo':
369
+ panelItemClasses = (0, classnames_1.default)({
370
+ '': variant === 'desktop',
371
+ '': variant === 'mobile'
372
+ });
373
+ break;
374
+ }
375
+ // return completed classes
376
+ return {
377
+ panelClassName: getPanelClasses(Object.assign(Object.assign({}, args), { className: panelClasses })),
378
+ panelItemClassName: panelItemClasses
379
+ };
380
+ }
381
+ function getPanelWrapClasses({ className, variant, parent, parentNested, item: { mobileOrder, alignY, fullBleed }, itemPosition }) {
382
+ return variant === 'mobile'
383
+ ? (0, classnames_1.default)(className, 'relative w-full flex flex-col', {
384
+ 'justify-start': alignY === 'start',
385
+ 'justify-center': alignY === 'center',
386
+ 'justify-end': alignY === 'end',
387
+ 'order-first': mobileOrder === 'first',
388
+ 'order-last': mobileOrder === 'last',
389
+ 'px-l4': !fullBleed.mobile
390
+ })
391
+ : (0, classnames_1.default)(className, 'relative grid grid-cols-12', {
392
+ 'items-start': alignY === 'start',
393
+ 'items-center': alignY === 'center',
394
+ 'items-end': alignY === 'end',
395
+ 'px-l4': parent !== 'row' && !fullBleed.desktop && !parentNested,
396
+ '-ml-l4': itemPosition.left && fullBleed.desktop,
397
+ '-mr-l4': itemPosition.right && fullBleed.desktop
398
+ });
399
+ }
400
+ function getPanelClasses({ className, variant, parent, parentNested, item: { alignX, size } }) {
401
+ // force full width for mobile
402
+ if (variant === 'mobile') {
403
+ return (0, classnames_1.default)(className);
404
+ }
405
+ // or size for desktop
406
+ switch (parent === 'row' || parentNested ? 'full' : size) {
407
+ case 'xs':
408
+ return (0, classnames_1.default)(className, 'col-span-4', {
409
+ 'col-start-1': alignX === 'start',
410
+ 'col-start-5': alignX === 'center',
411
+ 'col-end-13': alignX === 'end'
412
+ });
413
+ case 'sm':
414
+ return (0, classnames_1.default)(className, 'col-span-6', {
415
+ 'col-start-1': alignX === 'start',
416
+ 'col-start-4': alignX === 'center',
417
+ 'col-end-13': alignX === 'end'
418
+ });
419
+ case 'md':
420
+ return (0, classnames_1.default)(className, 'col-span-8', {
421
+ 'col-start-1': alignX === 'start',
422
+ 'col-start-3': alignX === 'center',
423
+ 'col-end-13': alignX === 'end'
424
+ });
425
+ case 'lg':
426
+ return (0, classnames_1.default)(className, 'col-span-10', {
427
+ 'col-start-1': alignX === 'start',
428
+ 'col-start-2': alignX === 'center',
429
+ 'col-end-13': alignX === 'end'
430
+ });
431
+ case 'full':
432
+ return (0, classnames_1.default)(className, 'col-span-full');
433
+ default:
434
+ return className;
435
+ }
436
+ }
437
+ function EditablePanel(_a) {
438
+ var { panelClassName, children } = _a, args = __rest(_a, ["panelClassName", "children"]);
11
439
  // render
12
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className, 'w-full flex justify-center items-center text-center'), children: variant === 'desktop' ? 'Desktop' : 'Mobile' }));
440
+ return ((0, jsx_runtime_1.jsx)("div", { className: getPanelWrapClasses(args), children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(panelClassName, 'relative'), children: [children, (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('group absolute inset-0 z-overlay cursor-pointer interpolate', 'bg-surface1 border border-solid, border-ix-primary rounded-xxs overflow-hidden', 'opacity-none hover:opacity-full'), onClick: () => args.onPanelClick(args.item), children: (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('w-full h-full interpolate', 'flex flex-col justify-center items-center gap-l6', 'text-ix-primary group-hover:bg-ix-primary/tint1 group-active:bg-ix-primary/tint3'), children: (0, jsx_runtime_1.jsx)("span", { className: "label-xs label-strong", children: "Edit" }) }) })] }) }));
441
+ }
442
+ // TODO: scrap this
443
+ class ItemPosition {
444
+ constructor(args) {
445
+ // initialize instance variables
446
+ this.parent = args.parent;
447
+ this.parentOffset = args.parentOffset;
448
+ this.parentSize = args.parentSize;
449
+ }
450
+ get left() {
451
+ return this.parent === 'row' && this.parentOffset === 0;
452
+ }
453
+ get right() {
454
+ return this.parent === 'row' && this.parentOffset === 1;
455
+ }
13
456
  }
@@ -1,13 +1,9 @@
1
- import { Rect } from '@nascentdigital/funnel-core';
2
- import { Block, SectionBlock } from '../../../core';
3
- export declare const LegacyBlockConfigEditor: import("react").ForwardRefExoticComponent<import("react").RefAttributes<LegacyBlockConfigEditor.Ref>>;
1
+ import { Callback } from '@nascentdigital/funnel-core';
2
+ import { BlockConfiguration } from '../../../core';
3
+ export declare function LegacyBlockConfigEditor({ configuration, onClose }: LegacyBlockConfigEditor.Props): import("react/jsx-runtime").JSX.Element;
4
4
  export declare namespace LegacyBlockConfigEditor {
5
- type Props = {};
6
- interface Ref {
7
- edit(options: Options): Promise<void>;
8
- }
9
- type Options = {
10
- block: Block | SectionBlock;
11
- anchor: HTMLElement | Rect;
5
+ type Props = {
6
+ configuration?: BlockConfiguration;
7
+ onClose: Callback.Void;
12
8
  };
13
9
  }
@@ -1,63 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LegacyBlockConfigEditor = void 0;
3
+ exports.LegacyBlockConfigEditor = LegacyBlockConfigEditor;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const funnel_core_1 = require("@nascentdigital/funnel-core");
6
- const client_1 = require("@nascentdigital/funnel-ui/client");
7
5
  const react_1 = require("react");
8
6
  const rxjs_1 = require("rxjs");
9
7
  const core_1 = require("../../../core");
10
8
  const hooks_1 = require("../../hooks");
11
9
  // editor
12
- exports.LegacyBlockConfigEditor = (0, react_1.forwardRef)(function LegacyBlockConfigEditor(_, ref) {
10
+ function LegacyBlockConfigEditor({ configuration, onClose }) {
13
11
  // bind state + hooks
14
- const [deferral, setDeferral] = (0, react_1.useState)(undefined);
15
- const [configuration, setConfiguration] = (0, react_1.useState)();
16
- const [anchor, setAnchor] = (0, react_1.useState)();
12
+ const [closing, setClosing] = (0, react_1.useState)(false);
17
13
  const pageController = (0, hooks_1.usePageController)();
18
- const touch = (0, client_1.useTouch)();
19
14
  const { modified = false, valid = false } = configuration !== null && configuration !== void 0 ? configuration : {};
20
15
  // sync w/ configuration
21
16
  (0, core_1.useBlockConfiguration)(configuration);
22
- // bind ref
23
- (0, react_1.useImperativeHandle)(ref, () => ({
24
- edit: async ({ block, anchor }) => {
25
- // reset state
26
- setConfiguration(block.getConfiguration());
27
- setAnchor(anchor);
28
- // create deferral
29
- const deferral = new funnel_core_1.Deferral();
30
- setDeferral(deferral);
31
- // wait until deferral is resolved
32
- return deferral.promise;
17
+ // reset closing on new open
18
+ (0, react_1.useEffect)(() => {
19
+ if (configuration) {
20
+ setClosing(false);
33
21
  }
34
- }), []);
22
+ }, [configuration]);
35
23
  // helpers
36
24
  const onSave = async () => {
37
25
  // save config
38
26
  configuration === null || configuration === void 0 ? void 0 : configuration.save();
39
27
  // wait for page to save
40
28
  await (0, rxjs_1.firstValueFrom)(pageController.saved$);
41
- // complete (we're done)
42
- deferral === null || deferral === void 0 ? void 0 : deferral.resolve();
43
- // refresh
44
- touch();
29
+ // complete
30
+ onClose();
45
31
  };
46
- const onCancel = () => {
47
- // skip if missing or already completed
48
- if (!deferral || deferral.isComplete) {
49
- return;
50
- }
51
- // cancel
52
- deferral.resolve(undefined);
53
- // touch
54
- touch();
55
- };
56
- // skip if there's no config
57
- if (!configuration) {
58
- return null;
59
- }
60
32
  // render
61
- const { layout } = configuration;
62
- return ((0, jsx_runtime_1.jsx)(core_1.MiniEditor, { title: "Block Configuration", open: !!deferral && !deferral.isComplete, anchor: anchor, anchorOffset: 4, onSave: onSave, onClose: onCancel, disableSave: !modified || !valid, customActions: (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "sm", disabled: configuration.isConfigInDefault, onClick: () => configuration.reset(), children: "Reset to Default" }), wide: true, children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-start items-start gap-l9", children: [(0, jsx_runtime_1.jsxs)("section", { className: "flex flex-col items-start gap-l8", children: [(0, jsx_runtime_1.jsx)(core_1.SkeletonLayout, { variant: "desktop", layout: layout }), (0, jsx_runtime_1.jsx)(core_1.SkeletonLayout, { variant: "mobile", layout: layout })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-[max-content_1fr] auto-rows-auto items-start gap-l6", children: (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: configuration.editableFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-2", field: field, variant: "wide" }, field.id)) }) })] }) }));
63
- });
33
+ const { layout } = configuration !== null && configuration !== void 0 ? configuration : {};
34
+ return ((0, jsx_runtime_1.jsx)(core_1.SideSheet, { title: "Block Configuration", backdrop: "none", open: !!configuration || closing, onSave: onSave, onClose: onClose, disableSave: !modified || !valid, customActions: (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "sm", disabled: configuration === null || configuration === void 0 ? void 0 : configuration.isConfigInDefault, onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.reset(), children: "Reset to Default" }), wide: true, children: (0, jsx_runtime_1.jsxs)("div", { className: "h-full flex flex-col gap-l9 p-l8", children: [(0, jsx_runtime_1.jsxs)("section", { className: "flex flex-wrap justify-center items-start gap-l8", children: [(0, jsx_runtime_1.jsx)(core_1.SkeletonLayout, { variant: "desktop", layout: layout }), (0, jsx_runtime_1.jsx)(core_1.SkeletonLayout, { variant: "mobile", layout: layout })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-[max-content_1fr] auto-rows-auto items-start gap-l6", children: (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: configuration === null || configuration === void 0 ? void 0 : configuration.editableFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-2", field: field, variant: "wide" }, field.id)) }) })] }) }));
35
+ }