@nascentdigital/funnel-editor 4.5.2 → 4.5.4

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 (70) hide show
  1. package/dist/EditorApp.js +1 -1
  2. package/dist/core/components/ColorModeToggle.d.ts +2 -2
  3. package/dist/core/components/feedback/Note.d.ts +3 -1
  4. package/dist/core/components/feedback/Note.js +6 -3
  5. package/dist/core/components/fields/BooleanField.d.ts +3 -1
  6. package/dist/core/components/fields/BooleanField.js +2 -2
  7. package/dist/core/components/fields/DateField.d.ts +3 -1
  8. package/dist/core/components/fields/DateField.js +2 -2
  9. package/dist/core/components/fields/EnumField.d.ts +3 -1
  10. package/dist/core/components/fields/EnumField.js +4 -4
  11. package/dist/core/components/fields/FieldEditor.d.ts +3 -1
  12. package/dist/core/components/fields/FieldEditor.js +7 -7
  13. package/dist/core/components/fields/FieldHeader.d.ts +3 -1
  14. package/dist/core/components/fields/FieldHeader.js +18 -5
  15. package/dist/core/components/fields/FieldLayout.d.ts +3 -1
  16. package/dist/core/components/fields/FieldLayout.js +17 -4
  17. package/dist/core/components/fields/FieldSize.d.ts +1 -0
  18. package/dist/core/components/fields/FieldSize.js +2 -0
  19. package/dist/core/components/fields/FieldsPanel.js +5 -4
  20. package/dist/core/components/fields/RichTextEditor.d.ts +2 -3
  21. package/dist/core/components/fields/RichTextEditor.js +13 -10
  22. package/dist/core/components/fields/RichTextField.d.ts +1 -2
  23. package/dist/core/components/fields/RichTextField.js +4 -16
  24. package/dist/core/components/fields/TextField.d.ts +3 -2
  25. package/dist/core/components/fields/TextField.js +8 -7
  26. package/dist/core/components/fields/TimestampField.d.ts +3 -1
  27. package/dist/core/components/fields/TimestampField.js +2 -2
  28. package/dist/core/components/fields/collection/CollectionPicker.js +3 -4
  29. package/dist/core/components/fields/index.d.ts +2 -0
  30. package/dist/core/components/fields/index.js +2 -0
  31. package/dist/core/components/fields/page/PagePicker.js +2 -3
  32. package/dist/core/components/fields/richtext/Theme.d.ts +1 -2
  33. package/dist/core/components/fields/richtext/Theme.js +2 -2
  34. package/dist/core/components/interaction/Animate.d.ts +1 -1
  35. package/dist/core/components/interaction/Animate.js +12 -2
  36. package/dist/core/components/interaction/Button.js +3 -3
  37. package/dist/core/components/interaction/Combobox.d.ts +8 -1
  38. package/dist/core/components/interaction/Combobox.js +39 -12
  39. package/dist/core/components/interaction/IconButton.d.ts +2 -2
  40. package/dist/core/components/interaction/IconButton.js +2 -1
  41. package/dist/core/components/interaction/QuickEditor.d.ts +11 -0
  42. package/dist/core/components/interaction/QuickEditor.js +33 -0
  43. package/dist/core/components/interaction/QuickInput.js +1 -1
  44. package/dist/core/components/interaction/QuickPicker.js +5 -3
  45. package/dist/core/components/interaction/SegmentedButton.d.ts +3 -1
  46. package/dist/core/components/interaction/SegmentedButton.js +4 -1
  47. package/dist/core/components/interaction/SideSheet.d.ts +5 -5
  48. package/dist/core/components/interaction/SideSheet.js +15 -43
  49. package/dist/core/components/interaction/centersheet/CenterSheet.js +1 -1
  50. package/dist/core/components/interaction/centersheet/CenterSheetContainer.js +1 -1
  51. package/dist/core/components/interaction/index.d.ts +1 -0
  52. package/dist/core/components/interaction/index.js +1 -0
  53. package/dist/core/components/visuals/Icon.d.ts +2 -2
  54. package/dist/core/components/visuals/Icon.js +5 -0
  55. package/dist/core/domain/BlockConfiguration.d.ts +16 -1
  56. package/dist/core/domain/BlockConfiguration.js +109 -5
  57. package/dist/page/components/config/BlockConfig.js +1 -1
  58. package/dist/page/components/config/BlockConfigEditor.d.ts +1 -1
  59. package/dist/page/components/config/BlockConfigEditor.js +40 -13
  60. package/dist/page/components/config/BlockPreview.js +23 -17
  61. package/dist/page/components/config/LegacyBlockConfigEditor.js +1 -9
  62. package/dist/page/components/config/ListPanelEditor.d.ts +4 -2
  63. package/dist/page/components/config/ListPanelEditor.js +52 -2
  64. package/dist/page/components/config/MessagePanelEditor.d.ts +4 -2
  65. package/dist/page/components/config/MessagePanelEditor.js +6 -2
  66. package/dist/page/components/config/VisualPanelEditor.d.ts +4 -2
  67. package/dist/page/components/config/VisualPanelEditor.js +65 -2
  68. package/dist/styles/index.css +367 -193
  69. package/dist/styles/tailwind.js +11 -16
  70. package/package.json +2 -2
@@ -38,6 +38,7 @@ __exportStar(require("./NavButton"), exports);
38
38
  __exportStar(require("./Picker"), exports);
39
39
  __exportStar(require("./Popup"), exports);
40
40
  __exportStar(require("./Profile"), exports);
41
+ __exportStar(require("./QuickEditor"), exports);
41
42
  __exportStar(require("./QuickInput"), exports);
42
43
  __exportStar(require("./QuickPicker"), exports);
43
44
  __exportStar(require("./SegmentedButton"), exports);
@@ -5,8 +5,8 @@ export declare namespace Icon {
5
5
  variant: Variant;
6
6
  size?: Size;
7
7
  };
8
- type Size = 'xl' | 'lg' | 'md' | 'sm' | 'xs' | 'nav' | 'card' | Sizing;
9
- type Variant = 'Archive' | 'ArrowLeft' | 'ArrowLeftRight' | 'Atom' | 'Blocks' | 'Bold' | 'Check' | 'ChevronDown' | 'ChevronRight' | 'ChevronUp' | 'Circle' | 'CircleAlert' | 'CircleCheck' | 'CircleCheckBig' | 'CirclePlus' | 'CircleQuestionMark' | 'CloudCheck' | 'CloudUpload' | 'CornerDownRight' | 'EllipsisVertical' | 'Eye' | 'EyeOff' | 'File' | 'FileDown' | 'FilePlusCorner' | 'FileSearchCorner' | 'Goal' | 'Globe' | 'GripVertical' | 'HatGlasses' | 'History' | 'Highlighter' | 'Image' | 'ImageDown' | 'Info' | 'Italic' | 'Layers' | 'LayoutTemplate' | 'Link' | 'Link2' | 'List' | 'ListChecks' | 'ListIndentDecrease' | 'ListIndentIncrease' | 'ListOrdered' | 'Lock' | 'LockOpen' | 'Mail' | 'MessageSquareQuote' | 'Minus' | 'MonitorCog' | 'Moon' | 'NotebookPen' | 'Pencil' | 'Pin' | 'Plus' | 'Redo' | 'RefreshCw' | 'RotateCcw' | 'RotateCw' | 'SearchCode' | 'Settings' | 'SquarePlay' | 'Star' | 'Strikethrough' | 'Subscript' | 'Sun' | 'Superscript' | 'TextAlignStart' | 'Trash' | 'TriangleAlert' | 'Trophy' | 'Underline' | 'Undo' | 'Upload' | 'UserRound' | 'X';
8
+ type Size = 'xl' | 'lg' | 'md' | 'sm' | 'xs' | 'xxs' | 'nav' | 'card' | Sizing;
9
+ type Variant = 'Archive' | 'ArrowLeft' | 'ArrowRight' | 'ArrowLeftRight' | 'Atom' | 'Blocks' | 'Bold' | 'Check' | 'ChevronDown' | 'ChevronRight' | 'ChevronUp' | 'Circle' | 'CircleAlert' | 'CircleCheck' | 'CircleCheckBig' | 'CirclePlus' | 'CircleQuestionMark' | 'CloudCheck' | 'CloudUpload' | 'CornerDownRight' | 'EllipsisVertical' | 'Eye' | 'EyeOff' | 'File' | 'FileDown' | 'FilePlusCorner' | 'FileSearchCorner' | 'Goal' | 'Globe' | 'GripVertical' | 'HatGlasses' | 'History' | 'Highlighter' | 'Image' | 'ImageDown' | 'Info' | 'Italic' | 'Layers' | 'LayoutTemplate' | 'Link' | 'Link2' | 'List' | 'ListChecks' | 'ListIndentDecrease' | 'ListIndentIncrease' | 'ListOrdered' | 'Lock' | 'LockOpen' | 'Mail' | 'MessageSquareQuote' | 'Minus' | 'MonitorCog' | 'Moon' | 'NotebookPen' | 'Pencil' | 'Pin' | 'Plus' | 'Redo' | 'RefreshCw' | 'RotateCcw' | 'RotateCw' | 'SearchCode' | 'Settings' | 'SquarePlay' | 'Star' | 'Strikethrough' | 'Subscript' | 'Sun' | 'Superscript' | 'TextAlignStart' | 'Trash' | 'TriangleAlert' | 'Trophy' | 'Underline' | 'Undo' | 'Upload' | 'UserRound' | 'X';
10
10
  namespace Variant {
11
11
  function filter(value: any): value is Variant;
12
12
  }
@@ -20,6 +20,7 @@ function Icon({ className, variant, size: sizing = 'md' }) {
20
20
  const values = [
21
21
  'Archive',
22
22
  'ArrowLeft',
23
+ 'ArrowRight',
23
24
  'ArrowLeftRight',
24
25
  'Atom',
25
26
  'Blocks',
@@ -112,6 +113,8 @@ function getIcon(variant) {
112
113
  return lucide_react_1.Archive;
113
114
  case 'ArrowLeft':
114
115
  return lucide_react_1.ArrowLeft;
116
+ case 'ArrowRight':
117
+ return lucide_react_1.ArrowRight;
115
118
  case 'ArrowLeftRight':
116
119
  return lucide_react_1.ArrowLeftRight;
117
120
  case 'Atom':
@@ -281,6 +284,8 @@ function getSizing(size) {
281
284
  return { size: 16, strokeWidth: 2 };
282
285
  case 'xs':
283
286
  return { size: 14, strokeWidth: 2 };
287
+ case 'xxs':
288
+ return { size: 10, strokeWidth: 1, absoluteStrokeWidth: true };
284
289
  default:
285
290
  return { size: 20, strokeWidth: 2 };
286
291
  }
@@ -1,5 +1,5 @@
1
1
  import { BlockLayout, EventBus, Field, FieldModel, Schema } from '@nascentdigital/funnel-core';
2
- import { PanelLayout } from '@nascentdigital/funnel-ui';
2
+ import { ListPanel, MessagePanel, PanelLayout, SlotVariation, VisualPanel } from '@nascentdigital/funnel-ui';
3
3
  import { Block } from './Block';
4
4
  import { IAssetStore } from './IAssetStore';
5
5
  import { SectionBlock } from './SectionBlock';
@@ -11,6 +11,7 @@ export declare class BlockConfiguration {
11
11
  readonly fields: ReadonlyArray<FieldModel.Config>;
12
12
  private _editableFields;
13
13
  private _layout?;
14
+ private _slotState;
14
15
  private _defaultConfig?;
15
16
  private _isConfigInDefault?;
16
17
  constructor({ block: blockOrSectionBlock, assetStore }: BlockConfiguration.ConstructorArgs);
@@ -23,11 +24,19 @@ export declare class BlockConfiguration {
23
24
  get nameField(): FieldModel.Config | undefined;
24
25
  get themeField(): FieldModel.Config | undefined;
25
26
  get layoutField(): Field<Schema.EnumField<Schema.EnumField.Options<PanelLayout>>> | undefined;
27
+ get slotState(): Readonly<BlockConfiguration.SlotState>;
28
+ gotToNextSlot(): void;
29
+ gotToPreviousSlot(): void;
30
+ get messageFields(): Record<keyof MessagePanel.Config.Keys<'message'>, FieldModel.Config | undefined>;
31
+ get listFields(): Record<keyof ListPanel.Config.Keys<'list'>, FieldModel.Config | undefined>;
32
+ get visualFields(): Record<keyof VisualPanel.Config.Keys<'visual'>, FieldModel.Config | undefined>;
26
33
  get layout(): BlockLayout | undefined;
27
34
  get events$(): import("rxjs").Observable<EventBus.Event<string, string>>;
28
35
  get valid(): boolean;
29
36
  get modified(): boolean;
30
37
  getField(fieldId: string): FieldModel;
38
+ getFieldData(fieldId: string): Schema.Field.LinkedData | undefined;
39
+ getEditableField(fieldId: string): FieldModel.Config | undefined;
31
40
  save(): void;
32
41
  reset(): void;
33
42
  get isConfigInDefault(): boolean | undefined;
@@ -35,6 +44,12 @@ export declare class BlockConfiguration {
35
44
  private raiseEvent;
36
45
  }
37
46
  export declare namespace BlockConfiguration {
47
+ type SlotState = {
48
+ field?: Field<Schema.EnumField<Schema.EnumField.Options<SlotVariation>>>;
49
+ options: ReadonlyArray<SlotVariation>;
50
+ currentOption?: SlotVariation | undefined;
51
+ currentIndex?: number;
52
+ };
38
53
  type ConstructorArgs = {
39
54
  assetStore: IAssetStore;
40
55
  block: Block | SectionBlock;
@@ -16,6 +16,7 @@ class BlockConfiguration {
16
16
  this.fields = fields;
17
17
  this._editableFields = fields;
18
18
  this._isConfigInDefault = false;
19
+ this._slotState = { options: [] };
19
20
  // initialize section block
20
21
  if (blockOrSectionBlock instanceof SectionBlock_1.SectionBlock) {
21
22
  // capture parents
@@ -28,7 +29,6 @@ class BlockConfiguration {
28
29
  }
29
30
  // or regular block
30
31
  else {
31
- // capture parent
32
32
  this.block = blockOrSectionBlock;
33
33
  }
34
34
  // add fields
@@ -76,7 +76,7 @@ class BlockConfiguration {
76
76
  }
77
77
  get desktopFields() {
78
78
  return [
79
- this._editableFields.find(field => field.id === 'contentAlign')
79
+ this.getEditableField('contentAlign')
80
80
  ].filter(funnel_core_1.Value.isDefined);
81
81
  }
82
82
  get mobileFields() {
@@ -85,15 +85,75 @@ class BlockConfiguration {
85
85
  get nameField() {
86
86
  const { block, sectionBlock } = this;
87
87
  return sectionBlock
88
- ? this._editableFields.find(field => field.id === block.nameField.id)
88
+ ? this.getEditableField(block.nameField.id)
89
89
  : undefined;
90
90
  }
91
91
  get themeField() {
92
- return this._editableFields.find(field => field.id === funnel_ui_1.BlockConfig.Presets.ThemeOnly.key);
92
+ return this.getEditableField(funnel_ui_1.BlockConfig.Presets.ThemeOnly.key);
93
93
  }
94
94
  get layoutField() {
95
95
  return this._editableFields.find(field => field.id === 'layout');
96
96
  }
97
+ get slotState() {
98
+ return this._slotState;
99
+ }
100
+ gotToNextSlot() {
101
+ // skip if there's no options
102
+ const { field, options, currentIndex } = this._slotState;
103
+ if (!field || options.length < 0 || currentIndex === undefined) {
104
+ return;
105
+ }
106
+ // update the slot
107
+ const newIndex = (currentIndex + 1) % options.length;
108
+ const newOption = options[newIndex];
109
+ this._slotState = {
110
+ field, options, currentIndex: newIndex, currentOption: newOption
111
+ };
112
+ field.value = funnel_core_1.Schema.EnumField.Value.toData(newOption);
113
+ }
114
+ gotToPreviousSlot() {
115
+ // skip if there's no options
116
+ const { field, options, currentIndex } = this._slotState;
117
+ if (!field || options.length < 0 || currentIndex === undefined) {
118
+ return;
119
+ }
120
+ // update the slot
121
+ const newIndex = currentIndex === 0
122
+ ? options.length - 1
123
+ : currentIndex - 1;
124
+ const newOption = options[newIndex];
125
+ this._slotState = {
126
+ field, options, currentIndex: newIndex, currentOption: newOption
127
+ };
128
+ field.value = funnel_core_1.Schema.EnumField.Value.toData(newOption);
129
+ }
130
+ get messageFields() {
131
+ const keys = funnel_ui_1.MessagePanel.Config.getKeys('message');
132
+ return {
133
+ textAlign: this.getEditableField(keys.textAlign),
134
+ width: this.getEditableField(keys.width),
135
+ horizontalAlign: this.getEditableField(keys.horizontalAlign),
136
+ verticalAlign: this.getEditableField(keys.verticalAlign)
137
+ };
138
+ }
139
+ get listFields() {
140
+ const keys = funnel_ui_1.ListPanel.Config.getKeys('list');
141
+ return {
142
+ layout: this.getEditableField(keys.layout),
143
+ width: this.getEditableField(keys.width),
144
+ horizontalAlign: this.getEditableField(keys.horizontalAlign),
145
+ verticalAlign: this.getEditableField(keys.verticalAlign)
146
+ };
147
+ }
148
+ get visualFields() {
149
+ const keys = funnel_ui_1.VisualPanel.Config.getKeys('visual');
150
+ return {
151
+ aspect: this.getEditableField(keys.aspect),
152
+ anchor: this.getEditableField(keys.anchor),
153
+ width: this.getEditableField(keys.width),
154
+ horizontalAlign: this.getEditableField(keys.horizontalAlign)
155
+ };
156
+ }
97
157
  get layout() {
98
158
  return this._layout;
99
159
  }
@@ -104,7 +164,13 @@ class BlockConfiguration {
104
164
  return this.editableFields.every(field => field.valid);
105
165
  }
106
166
  get modified() {
107
- return !funnel_core_1.Value.equals(this.fields.filter(field => field.hasValue).map(field => field.value), this.editableFields.map(field => field.value));
167
+ const original = this.fields
168
+ .filter(field => field.hasValue)
169
+ .map(field => field.value);
170
+ const updated = this.editableFields
171
+ .filter(field => field.hasValue)
172
+ .map(field => field.value);
173
+ return !funnel_core_1.Value.equals(original, updated);
108
174
  }
109
175
  getField(fieldId) {
110
176
  // return field or throw
@@ -115,6 +181,32 @@ class BlockConfiguration {
115
181
  // return field
116
182
  return field;
117
183
  }
184
+ getFieldData(fieldId) {
185
+ // skip if it's not there
186
+ const { block, assetStore } = this;
187
+ const field = block.fields.find(field => field.id === fieldId);
188
+ if (!field) {
189
+ return undefined;
190
+ }
191
+ // link assets
192
+ const fieldValue = field.value;
193
+ if ((fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.type) === 'asset') {
194
+ const assetData = funnel_core_1.Schema.AssetField.Value.fromData(fieldValue);
195
+ const asset = (assetData === null || assetData === void 0 ? void 0 : assetData.id)
196
+ ? assetStore.getAsset(assetData === null || assetData === void 0 ? void 0 : assetData.id)
197
+ : undefined;
198
+ return assetData && asset
199
+ ? funnel_core_1.Schema.AssetField.LinkedValue.toData(funnel_core_1.Schema.AssetField.Value.toLinked(assetData, asset))
200
+ : undefined;
201
+ }
202
+ // or return other values as-is
203
+ else {
204
+ return fieldValue;
205
+ }
206
+ }
207
+ getEditableField(fieldId) {
208
+ return this._editableFields.find(field => field.id === fieldId);
209
+ }
118
210
  save() {
119
211
  // save each modified field
120
212
  const { sectionBlock, block, editableFields } = this;
@@ -196,6 +288,7 @@ class BlockConfiguration {
196
288
  return this._isConfigInDefault;
197
289
  }
198
290
  sync() {
291
+ var _a;
199
292
  // recompute the editable fields
200
293
  const { block, blockFieldData: fieldData, fields, editableFields } = this;
201
294
  const configData = editableFields.reduce((data, field) => {
@@ -236,6 +329,17 @@ class BlockConfiguration {
236
329
  this._layout = getLayout
237
330
  ? getLayout({ config: updatedConfig, fields: fieldData })
238
331
  : undefined;
332
+ // setup slot
333
+ const slotField = configFields.find(field => field.id === 'slotVariation');
334
+ const slotOptions = (slotField ? Object.keys(slotField.schema.options) : []);
335
+ const slotOption = (_a = slotField === null || slotField === void 0 ? void 0 : slotField.value) === null || _a === void 0 ? void 0 : _a.value;
336
+ const slotOptionIndex = slotOption ? slotOptions.indexOf(slotOption) : -1;
337
+ this._slotState = {
338
+ field: slotField,
339
+ options: slotOptions,
340
+ currentIndex: slotOptionIndex < 0 ? undefined : slotOptionIndex,
341
+ currentOption: slotOption
342
+ };
239
343
  // assign to editable fields (raised event)
240
344
  this.editableFields = configFields;
241
345
  // compute the default config
@@ -20,7 +20,7 @@ function BlockConfig({ className, block: blockOrSectionBlock }) {
20
20
  }
21
21
  // render
22
22
  const valid = config.every(field => field.valid);
23
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.StatusChip, { className: className, variant: valid ? 'success' : 'error', onClick: () => setConfiguration(block.getConfiguration()), children: "Configure" }), process.env.NEXT_PUBLIC_EDITOR_BLOCK_CONFIG === 'experimental'
23
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.StatusChip, { className: className, variant: valid ? 'success' : 'error', onClick: () => setConfiguration(blockOrSectionBlock.getConfiguration()), children: "Configure" }), process.env.NEXT_PUBLIC_EDITOR_BLOCK_CONFIG === 'experimental'
24
24
  ?
25
25
  (0, jsx_runtime_1.jsx)(BlockConfigEditor_1.BlockConfigEditor, { configuration: configuration, onClose: () => setConfiguration(undefined) })
26
26
  :
@@ -1,6 +1,6 @@
1
1
  import { Callback } from '@nascentdigital/funnel-core';
2
2
  import { BlockConfiguration } from '../../../core';
3
- export declare function BlockConfigEditor({ configuration, onClose }: BlockConfigEditor.Props): import("react/jsx-runtime").JSX.Element | null;
3
+ export declare function BlockConfigEditor({ configuration, onClose }: BlockConfigEditor.Props): import("react/jsx-runtime").JSX.Element;
4
4
  export declare namespace BlockConfigEditor {
5
5
  type Props = {
6
6
  configuration?: BlockConfiguration;
@@ -3,19 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BlockConfigEditor = BlockConfigEditor;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const funnel_core_1 = require("@nascentdigital/funnel-core");
6
- const client_1 = require("@nascentdigital/funnel-ui/client");
7
6
  const react_1 = require("motion/react");
8
7
  const react_2 = require("react");
9
8
  const rxjs_1 = require("rxjs");
10
9
  const core_1 = require("../../../core");
10
+ const FieldHeader_1 = require("../../../core/components/fields/FieldHeader");
11
11
  const hooks_1 = require("../../hooks");
12
12
  const BlockPreview_1 = require("./BlockPreview");
13
13
  // editor
14
14
  function BlockConfigEditor({ configuration, onClose }) {
15
+ var _a;
15
16
  // bind state + hooks
16
17
  const [blockView, setBlockView] = (0, react_2.useState)('desktop');
17
18
  const pageController = (0, hooks_1.usePageController)();
18
- const touch = (0, client_1.useTouch)();
19
19
  const panelLayoutPickerRef = (0, react_2.useRef)(null);
20
20
  const { modified = false, valid = false, blocksFields = [], desktopFields = [], mobileFields = [] } = configuration !== null && configuration !== void 0 ? configuration : {};
21
21
  const settingsFields = blockView === 'desktop' ? desktopFields : mobileFields;
@@ -60,23 +60,50 @@ function BlockConfigEditor({ configuration, onClose }) {
60
60
  layoutField.value = funnel_core_1.Schema.EnumField.Value.toData(selectedLayout);
61
61
  }
62
62
  };
63
- // skip if there's no config
64
- if (!configuration) {
65
- return null;
66
- }
67
63
  // render
68
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(core_1.SideSheet, { title: "Block Configuration", open: !!configuration, onSave: onSave, onClose: onClose, 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)("section", { className: "flex items-center gap-l4", children: [(0, jsx_runtime_1.jsx)("span", { className: "label-sm text-content-primary flex-1", children: "Layout" }), (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "sm", iconLeft: "ArrowLeftRight", children: "Rearrange" }), (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "sm", iconLeft: "LayoutTemplate", onClick: onChangePanelLayout, children: "Change" })] }), blocksFields.length > 0 &&
69
- (0, jsx_runtime_1.jsx)("section", { className: "grid grid-cols-2 auto-rows-auto items-start gap-l6", children: (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: blocksFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-2", field: field, variant: "wide" }, field.id)) }) }), (0, jsx_runtime_1.jsx)(core_1.Tabs, { items: blockViews, selectedItem: blockView, onSelect: setBlockView }), (0, jsx_runtime_1.jsx)("section", { className: "stacked p-l6 bg-surface1 rounded-md", children: (0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { children: (0, jsx_runtime_1.jsx)(core_1.Animate, { effect: "fade", present: true, children: (0, jsx_runtime_1.jsx)(BlockPreview_1.BlockPreview, { variant: blockView, configuration: configuration }) }, blockView) }) }), settingsFields.length > 0 &&
70
- (0, jsx_runtime_1.jsx)("section", { className: "grid grid-cols-2 auto-rows-auto items-start gap-l6", children: (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: settingsFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-2", field: field, variant: "wide" }, field.id)) }) }), (0, jsx_runtime_1.jsx)("hr", { className: "divider border-border-l1" })] }), (0, jsx_runtime_1.jsx)(core_1.QuickPicker, { ref: panelLayoutPickerRef, variant: "card", title: "Pick Block Layout", description: "Select an available layout for this block.", renderItem: (item) => renderPanelLayoutItem(item) })] }));
64
+ const { options: slotOptions = [], currentIndex: slotIndex = 0 } = (_a = configuration === null || configuration === void 0 ? void 0 : configuration.slotState) !== null && _a !== void 0 ? _a : {};
65
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.SideSheet, { title: "Block Configuration", size: "xs", backdrop: "glass", open: !!configuration, onSave: onSave, onClose: onClose, disableDismiss: modified, 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" }), children: (0, jsx_runtime_1.jsxs)("div", { className: "h-full flex flex-col gap-l6", children: [(0, jsx_runtime_1.jsxs)("section", { className: "grid grid-cols-2 gap-x-l5 gap-y-l4", children: [blocksFields.length > 0 &&
66
+ (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: blocksFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-full", field: field, size: "xs" }, field.id)) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [(0, jsx_runtime_1.jsx)(FieldHeader_1.FieldHeader, { label: "Layout", size: "xs" }), (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", iconLeft: "LayoutTemplate", onClick: onChangePanelLayout, children: "Change" })] }), slotOptions.length > 1 &&
67
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l2", children: [(0, jsx_runtime_1.jsx)(FieldHeader_1.FieldHeader, { label: "Arrangement", size: "xs" }), slotOptions.length === 2
68
+ ?
69
+ (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", iconLeft: "ArrowLeftRight", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToNextSlot(), children: "Swap" })
70
+ :
71
+ (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-l4", children: [(0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToPreviousSlot(), children: (0, jsx_runtime_1.jsx)(core_1.Icon, { variant: "ArrowLeft", size: { size: 16, strokeWidth: 1, absoluteStrokeWidth: true } }) }), (0, jsx_runtime_1.jsxs)("span", { className: "label-xs", children: [slotIndex + 1, " of ", slotOptions.length] }), (0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", onClick: () => configuration === null || configuration === void 0 ? void 0 : configuration.gotToNextSlot(), children: (0, jsx_runtime_1.jsx)(core_1.Icon, { variant: "ArrowRight", size: { size: 16, strokeWidth: 1, absoluteStrokeWidth: true } }) })] })] })] }), (0, jsx_runtime_1.jsx)(core_1.Tabs, { items: blockViews, selectedItem: blockView, onSelect: setBlockView }), (0, jsx_runtime_1.jsx)(react_1.motion.section, { className: "p-l6 bg-surface-placeholder-raised rounded-md", layout: true, children: configuration &&
72
+ (0, jsx_runtime_1.jsx)(BlockPreview_1.BlockPreview, { variant: blockView, configuration: configuration }) }), settingsFields.length > 0 &&
73
+ (0, jsx_runtime_1.jsx)("section", { className: "grid grid-cols-2 auto-rows-auto items-start gap-l6", children: (0, jsx_runtime_1.jsx)(core_1.FieldErrorController, { children: settingsFields.map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { className: "col-span-2", field: field, size: "xs" }, field.id)) }) })] }) }), (0, jsx_runtime_1.jsx)(core_1.QuickPicker, { ref: panelLayoutPickerRef, variant: "card", title: "Pick Block Layout", description: "Select an available layout for this block.", renderItem: (item) => renderPanelLayoutItem(item) })] }));
71
74
  }
72
75
  function renderPanelLayoutItem(item) {
73
76
  switch (item.id) {
74
- case 'stack.h':
75
- return ((0, jsx_runtime_1.jsx)("div", { children: "Stack H" }));
77
+ case 'solo':
78
+ return ((0, jsx_runtime_1.jsx)("div", { className: "p-l4 size-full", children: (0, jsx_runtime_1.jsx)("div", { className: "size-full bg-surface-placeholder" }) }));
76
79
  case 'stack.v':
77
- return ((0, jsx_runtime_1.jsx)("div", { children: "Stack V" }));
80
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] }));
81
+ case 'stack.h':
82
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] }));
83
+ case 'brick.v':
84
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] }));
85
+ case 'brick.t':
86
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-full h-[20px] bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-1 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]r" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] })] }));
87
+ case 'brick.r':
88
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full p-l4 gap-l1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-1 flex-col gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-full w-[30px] bg-surface-placeholder rounded-[2px]" })] }));
89
+ case 'brick.b':
90
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-1 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full h-[20px] bg-surface-placeholder rounded-[2px]" })] }));
91
+ case 'brick.l':
92
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-full w-[30px] bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-1 flex-col gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder rounded-[2px]" })] })] }));
78
93
  case 'nested':
79
- return ((0, jsx_runtime_1.jsx)("div", { children: "Nested" }));
94
+ return ((0, jsx_runtime_1.jsx)("div", { className: "p-l4 size-full", children: (0, jsx_runtime_1.jsx)("div", { className: "flex h-full px-l5 py-l2 bg-surface-placeholder rounded-[2px]", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-surface-placeholder-raised rounded-[2px]" }) }) }));
95
+ case 'nested.v':
96
+ return ((0, jsx_runtime_1.jsx)("div", { className: "h-full w-full p-l4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col px-l4 py-l2 gap-l1 bg-surface-placeholder rounded-[2px]", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder-raised rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder-raised rounded-[2px]" })] }) }));
97
+ case 'nested.h':
98
+ return ((0, jsx_runtime_1.jsx)("div", { className: "h-full w-full p-l4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex h-full px-l4 py-l3 gap-l1 bg-surface-placeholder rounded-[2px]", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder-raised rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-surface-placeholder-raised rounded-[2px]" })] }) }));
99
+ case 'nested.t':
100
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full w-7/12 bg-surface-placeholder-raised rounded-[2px]" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]" })] }));
101
+ case 'nested.r':
102
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-1 flex-col p-l2 bg-surface-placeholder rounded-[2px]", children: (0, jsx_runtime_1.jsx)("div", { className: "w-full h-[60%] bg-surface-placeholder-raised rounded-[2px]" }) })] }));
103
+ case 'nested.b':
104
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full flex-col p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full w-7/12 bg-surface-placeholder-raised rounded-[2px]" }) })] }));
105
+ case 'nested.l':
106
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex h-full p-l4 gap-l1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex flex-1 flex-col p-l2 bg-surface-placeholder rounded-[2px]", children: (0, jsx_runtime_1.jsx)("div", { className: "w-full h-[60%] bg-surface-placeholder-raised rounded-[2px]" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 p-l2 bg-surface-placeholder rounded-[2px]" })] }));
80
107
  default:
81
108
  return ((0, jsx_runtime_1.jsx)("div", { children: item.id }));
82
109
  }
@@ -20,43 +20,49 @@ const funnel_core_1 = require("@nascentdigital/funnel-core");
20
20
  const classnames_1 = __importDefault(require("classnames"));
21
21
  const react_1 = require("react");
22
22
  const core_1 = require("../../../core");
23
+ const ListPanelEditor_1 = require("./ListPanelEditor");
24
+ const MessagePanelEditor_1 = require("./MessagePanelEditor");
25
+ const VisualPanelEditor_1 = require("./VisualPanelEditor");
26
+ const react_2 = require("motion/react");
23
27
  // component
24
28
  function BlockPreview({ className, variant, configuration }) {
25
- // determine active panels
29
+ // bind props + state + refs
26
30
  const { layout } = configuration;
31
+ const [editingPanel, setEditingPanel] = (0, react_1.useState)();
32
+ const previewRef = (0, react_1.useRef)(null);
27
33
  // sync configuration
28
34
  (0, core_1.useBlockConfiguration)(configuration);
29
35
  // helpers
30
36
  const onPanelClick = (panel) => {
31
- console.debug('[BlockPreview] opening panel editor', panel);
37
+ setEditingPanel(panel.type);
32
38
  };
33
39
  // render
34
40
  const tight = variant === 'mobile'
35
41
  ? layout === null || layout === void 0 ? void 0 : layout.tight.mobile
36
42
  : 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 }) }) }));
43
+ return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(react_2.motion.div, { ref: previewRef, className: (0, classnames_1.default)(className, 'w-full flex justify-center'), layout: true, children: [(0, jsx_runtime_1.jsx)(react_2.motion.div, { className: (0, classnames_1.default)('bg-surface2 rounded-xs', {
44
+ 'min-h-[100px]': !layout,
45
+ 'w-[120px]': variant === 'desktop',
46
+ 'w-[64px]': variant === 'mobile',
47
+ 'pb-l4': tight === 'above',
48
+ 'pt-l4': tight === 'below',
49
+ 'py-l4': tight === 'none'
50
+ }), layoutRoot: true, layout: true, children: renderLayout({ variant, layout, onPanelClick }) }), (0, jsx_runtime_1.jsx)(MessagePanelEditor_1.MessagePanelEditor, { open: editingPanel === 'message', onClose: () => setEditingPanel(panel => panel === 'message' ? undefined : panel), anchor: previewRef.current, configuration: configuration }), (0, jsx_runtime_1.jsx)(ListPanelEditor_1.ListPanelEditor, { open: editingPanel === 'list', onClose: () => setEditingPanel(panel => panel === 'list' ? undefined : panel), anchor: previewRef.current, configuration: configuration }), (0, jsx_runtime_1.jsx)(VisualPanelEditor_1.VisualPanelEditor, { open: editingPanel === 'visual', onClose: () => setEditingPanel(panel => panel === 'visual' ? undefined : panel), anchor: previewRef.current, configuration: configuration })] }) }));
45
51
  }
46
52
  // helpers
47
53
  var Skeleton;
48
54
  (function (Skeleton) {
49
55
  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', {
56
+ return ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: (0, classnames_1.default)(className, 'bg-ix-primary rounded-xxs overflow-hidden', {
51
57
  'h-6 ': size === 'sm',
52
58
  'h-8': size === 'md'
53
- }) }));
59
+ }), layout: true }));
54
60
  }
55
61
  Skeleton.HeadlinePart = HeadlinePart;
56
62
  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', {
63
+ return ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: (0, classnames_1.default)(className, 'h-4 bg-draft/tint3 rounded-px overflow-hidden', {
58
64
  '': size === 'sm'
59
- }) }));
65
+ }), layout: true }));
60
66
  }
61
67
  Skeleton.CaptionPart = CaptionPart;
62
68
  function MediaPart({ className, aspect }) {
@@ -95,7 +101,7 @@ function renderLayout({ className, variant, layout, onPanelClick }) {
95
101
  }
96
102
  // render root layout
97
103
  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({
104
+ return ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: getContainerClasses({ className, variant, siblingCount: 1, item: layout.root }), layout: true, children: items.map((item, parentOffset) => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderItem({
99
105
  className: (0, classnames_1.default)({
100
106
  'flex-1': type === 'row' && variant !== 'mobile'
101
107
  }),
@@ -119,7 +125,7 @@ function renderItem({ className, parent, parentNested, siblingCount, variant, it
119
125
  case 'row':
120
126
  case 'column':
121
127
  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({
128
+ return ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: getContainerClasses({ className, parent, siblingCount, variant, item }), layout: true, children: item.items.map((item, parentOffset, items) => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderItem({
123
129
  className: (0, classnames_1.default)({
124
130
  'flex-1': itemType === 'row'
125
131
  }),
@@ -437,7 +443,7 @@ function getPanelClasses({ className, variant, parent, parentNested, item: { ali
437
443
  function EditablePanel(_a) {
438
444
  var { panelClassName, children } = _a, args = __rest(_a, ["panelClassName", "children"]);
439
445
  // render
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" }) }) })] }) }));
446
+ return ((0, jsx_runtime_1.jsx)(react_2.motion.div, { className: getPanelWrapClasses(args), layout: true, layoutId: args.item.key, 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" }) }) })] }) }, args.item.key));
441
447
  }
442
448
  // TODO: scrap this
443
449
  class ItemPosition {
@@ -2,24 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LegacyBlockConfigEditor = LegacyBlockConfigEditor;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
5
  const rxjs_1 = require("rxjs");
7
6
  const core_1 = require("../../../core");
8
7
  const hooks_1 = require("../../hooks");
9
8
  // editor
10
9
  function LegacyBlockConfigEditor({ configuration, onClose }) {
11
10
  // bind state + hooks
12
- const [closing, setClosing] = (0, react_1.useState)(false);
13
11
  const pageController = (0, hooks_1.usePageController)();
14
12
  const { modified = false, valid = false } = configuration !== null && configuration !== void 0 ? configuration : {};
15
13
  // sync w/ configuration
16
14
  (0, core_1.useBlockConfiguration)(configuration);
17
- // reset closing on new open
18
- (0, react_1.useEffect)(() => {
19
- if (configuration) {
20
- setClosing(false);
21
- }
22
- }, [configuration]);
23
15
  // helpers
24
16
  const onSave = async () => {
25
17
  // save config
@@ -31,5 +23,5 @@ function LegacyBlockConfigEditor({ configuration, onClose }) {
31
23
  };
32
24
  // render
33
25
  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)) }) })] }) }));
26
+ return ((0, jsx_runtime_1.jsx)(core_1.SideSheet, { size: "lg", title: "Block Configuration", backdrop: "glass", open: !!configuration, 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" }), 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
27
  }
@@ -1,6 +1,8 @@
1
- export declare function ListPanelEditor({ className }: ListPanelEditor.Props): import("react/jsx-runtime").JSX.Element;
1
+ import { BlockConfiguration, Popup } from '../../../core';
2
+ export declare function ListPanelEditor({ className, anchor, open, onClose, configuration }: ListPanelEditor.Props): import("react/jsx-runtime").JSX.Element;
2
3
  export declare namespace ListPanelEditor {
3
- type Props = {
4
+ type Props = Pick<Popup.Props, 'open' | 'onClose' | 'anchor'> & {
4
5
  className?: string;
6
+ configuration: BlockConfiguration;
5
7
  };
6
8
  }
@@ -1,13 +1,63 @@
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.ListPanelEditor = ListPanelEditor;
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 ListPanelEditor({ className }) {
24
+ function ListPanelEditor({ className, anchor, open, onClose, configuration }) {
25
+ // bind props + refs
26
+ const _a = configuration.listFields, { layout: layoutField } = _a, listFields = __rest(_a, ["layout"]);
27
+ const layoutPickerRef = (0, react_1.useRef)(null);
28
+ // helpers
29
+ const onChangeLayout = async (e) => {
30
+ var _a;
31
+ // skip if there's no layout field (shouldn't happen)
32
+ const layoutSchema = layoutField === null || layoutField === void 0 ? void 0 : layoutField.schema;
33
+ if (!layoutField || !layoutSchema) {
34
+ return;
35
+ }
36
+ // pick new layout
37
+ const { value: layoutData } = layoutField;
38
+ const selectedLayout = await ((_a = layoutPickerRef.current) === null || _a === void 0 ? void 0 : _a.open({
39
+ anchor: e.currentTarget,
40
+ anchorOffset: 4,
41
+ placement: 'top',
42
+ items: Object.entries(layoutSchema.options).map(([layout, option]) => ({
43
+ id: layout,
44
+ label: option.name
45
+ })),
46
+ selectedItem: layoutData === null || layoutData === void 0 ? void 0 : layoutData.value
47
+ }));
48
+ // update if something was picked
49
+ if (selectedLayout) {
50
+ layoutField.value = funnel_core_1.Schema.EnumField.Value.toData(selectedLayout);
51
+ }
52
+ };
11
53
  // render
12
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(className), children: "ListPanelEditor" }));
54
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(core_1.QuickEditor, { className: (0, classnames_1.default)(className), title: "List Configuration", tip: "Lorem ipsum.", anchor: anchor, placement: "left", anchorOffset: 4, viewportPadding: 4, open: open, onClose: onClose, size: "sm", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-l4", children: [(0, jsx_runtime_1.jsx)(core_1.Button, { variant: "secondary", size: "xs", iconLeft: "LayoutTemplate", onClick: onChangeLayout, children: "Change" }), Object.values(listFields)
55
+ .filter(funnel_core_1.Value.isDefined)
56
+ .map(field => (0, jsx_runtime_1.jsx)(core_1.FieldEditor, { field: field, size: "xs" }, field.id))] }) }), (0, jsx_runtime_1.jsx)(core_1.QuickPicker, { ref: layoutPickerRef, variant: "card", title: "Pick List Layout", description: "Select an available layout for this list.", renderItem: (item) => renderListLayoutItem(item) })] }));
57
+ }
58
+ function renderListLayoutItem(item) {
59
+ switch (item.id) {
60
+ default:
61
+ return ((0, jsx_runtime_1.jsx)("div", { children: item.id }));
62
+ }
13
63
  }
@@ -1,6 +1,8 @@
1
- export declare function MessagePanelEditor({ className }: MessagePanelEditor.Props): import("react/jsx-runtime").JSX.Element;
1
+ import { BlockConfiguration, Popup } from '../../../core';
2
+ export declare function MessagePanelEditor({ className, anchor, open, onClose, configuration }: MessagePanelEditor.Props): import("react/jsx-runtime").JSX.Element;
2
3
  export declare namespace MessagePanelEditor {
3
- type Props = {
4
+ type Props = Pick<Popup.Props, 'open' | 'onClose' | 'anchor'> & {
4
5
  className?: string;
6
+ configuration: BlockConfiguration;
5
7
  };
6
8
  }