@nascentdigital/funnel-editor 4.5.1 → 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.
- package/dist/core/components/interaction/SideSheet.d.ts +26 -0
- package/dist/core/components/interaction/SideSheet.js +200 -0
- package/dist/core/components/interaction/index.d.ts +1 -0
- package/dist/core/components/interaction/index.js +1 -0
- package/dist/page/components/config/BlockConfig.js +6 -21
- package/dist/page/components/config/BlockConfigEditor.d.ts +6 -10
- package/dist/page/components/config/BlockConfigEditor.js +10 -33
- package/dist/page/components/config/LegacyBlockConfigEditor.d.ts +6 -10
- package/dist/page/components/config/LegacyBlockConfigEditor.js +13 -41
- package/dist/styles/index.css +17 -3
- package/package.json +2 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Callback, Provider, Transform } from '@nascentdigital/funnel-core';
|
|
2
|
+
import { HTMLMotionProps, Variants } from 'framer-motion';
|
|
3
|
+
import { PropsWithChildren, ReactNode } from 'react';
|
|
4
|
+
export declare function SideSheet({ className, title, wide, backdrop, disabled, disableDismiss, disableOverlay, disableSave, canSave, renderSaveLabel, onSave: onSaveRaw, open, onOpened: onOpenedRaw, onClose: onCloseRaw, onClosed: onClosedRaw, onKeyDown: onKeyDownRaw, customActions, children, ...props }: SideSheet.Props): import("react").ReactPortal | null;
|
|
5
|
+
export declare namespace SideSheet {
|
|
6
|
+
type Props = Omit<HTMLMotionProps<'div'>, 'children'> & PropsWithChildren & {
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
wide?: boolean;
|
|
9
|
+
backdrop?: Backdrop;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
disableDismiss?: boolean;
|
|
12
|
+
disableOverlay?: boolean;
|
|
13
|
+
disableSave?: boolean;
|
|
14
|
+
canSave?: Provider<boolean> | Provider.Async<boolean>;
|
|
15
|
+
renderSaveLabel?: Transform<State, string>;
|
|
16
|
+
onSave?: Callback.Void | Callback.AsyncVoid;
|
|
17
|
+
customActions?: ReactNode;
|
|
18
|
+
open?: boolean;
|
|
19
|
+
onOpened?: Callback.Void;
|
|
20
|
+
onClose?: Callback.Void;
|
|
21
|
+
onClosed?: Callback.Void;
|
|
22
|
+
};
|
|
23
|
+
type State = 'editing' | 'validating' | 'saving' | 'error' | 'saved';
|
|
24
|
+
type Backdrop = 'none' | 'glass';
|
|
25
|
+
}
|
|
26
|
+
export declare const Animations: Record<'background' | 'slideRight', Variants>;
|
|
@@ -0,0 +1,200 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Animations = void 0;
|
|
18
|
+
exports.SideSheet = SideSheet;
|
|
19
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
20
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
21
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
22
|
+
const framer_motion_1 = require("framer-motion");
|
|
23
|
+
const react_1 = require("motion/react");
|
|
24
|
+
const react_2 = require("react");
|
|
25
|
+
const react_dom_1 = require("react-dom");
|
|
26
|
+
const Button_1 = require("./Button");
|
|
27
|
+
// component
|
|
28
|
+
function SideSheet(_a) {
|
|
29
|
+
var { className, title, wide, backdrop = 'none', disabled = false, disableDismiss = false, disableOverlay = false, disableSave = false, canSave = funnel_core_1.Fn.True, renderSaveLabel = onRenderSaveLabel, onSave: onSaveRaw = funnel_core_1.Fn.NoOp, open = false, onOpened: onOpenedRaw = funnel_core_1.Fn.NoOp, onClose: onCloseRaw = funnel_core_1.Fn.NoOp, onClosed: onClosedRaw = funnel_core_1.Fn.NoOp, onKeyDown: onKeyDownRaw, customActions, children } = _a, props = __rest(_a, ["className", "title", "wide", "backdrop", "disabled", "disableDismiss", "disableOverlay", "disableSave", "canSave", "renderSaveLabel", "onSave", "open", "onOpened", "onClose", "onClosed", "onKeyDown", "customActions", "children"]);
|
|
30
|
+
// bind state + hooksb= + refs
|
|
31
|
+
const [state, setState] = (0, react_2.useState)('editing');
|
|
32
|
+
const locked = disabled || state === 'validating' || state === 'saving' || state === 'saved';
|
|
33
|
+
const id = (0, react_2.useId)();
|
|
34
|
+
const openRef = (0, react_2.useRef)(open);
|
|
35
|
+
openRef.current = open;
|
|
36
|
+
const onOpenedRef = (0, react_2.useRef)(onOpenedRaw);
|
|
37
|
+
onOpenedRef.current = onOpenedRaw;
|
|
38
|
+
const onClosedRef = (0, react_2.useRef)(onClosedRaw);
|
|
39
|
+
onClosedRef.current = onClosedRaw;
|
|
40
|
+
// reset state on open
|
|
41
|
+
(0, react_2.useEffect)(() => {
|
|
42
|
+
if (open) {
|
|
43
|
+
setState('editing');
|
|
44
|
+
}
|
|
45
|
+
}, [open]);
|
|
46
|
+
// lock tab focus
|
|
47
|
+
(0, react_2.useEffect)(() => {
|
|
48
|
+
// lock when opened
|
|
49
|
+
let unlock = undefined;
|
|
50
|
+
if (open) {
|
|
51
|
+
unlock = funnel_core_1.Browser.lockFocus(`#${CSS.escape(id)}`);
|
|
52
|
+
}
|
|
53
|
+
// unlock on unmount
|
|
54
|
+
return () => unlock && unlock();
|
|
55
|
+
}, [open, id]);
|
|
56
|
+
// skip for SSR
|
|
57
|
+
if (!funnel_core_1.Browser.available) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// helpers
|
|
61
|
+
const onSave = async (e) => {
|
|
62
|
+
console.debug('[SideSheet/onSave]', { state, disabled, open });
|
|
63
|
+
// consume event
|
|
64
|
+
if (e) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
}
|
|
68
|
+
// ignore if state is invalid
|
|
69
|
+
if (state !== 'editing' && state !== 'error') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// try to save
|
|
73
|
+
try {
|
|
74
|
+
// update state
|
|
75
|
+
setState('validating');
|
|
76
|
+
// skip if not valid
|
|
77
|
+
const valid = await Promise.resolve(canSave());
|
|
78
|
+
if (!valid) {
|
|
79
|
+
setState('error');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// update state
|
|
83
|
+
setState('saving');
|
|
84
|
+
// try to save
|
|
85
|
+
await Promise.resolve(onSaveRaw());
|
|
86
|
+
// mark as saved
|
|
87
|
+
setState('saved');
|
|
88
|
+
}
|
|
89
|
+
// handle error
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.warn('[SideSheet/onSave] error', e);
|
|
92
|
+
// update state
|
|
93
|
+
setState('error');
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const onClose = (e) => {
|
|
97
|
+
// consume event
|
|
98
|
+
if (e) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
e.stopPropagation();
|
|
101
|
+
}
|
|
102
|
+
// close
|
|
103
|
+
onCloseRaw();
|
|
104
|
+
};
|
|
105
|
+
const onKeyDown = async (e) => {
|
|
106
|
+
// ignore if disabled OR state is invalid
|
|
107
|
+
if (disabled || (state !== 'editing' && state !== 'error')) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// cancel on escape
|
|
111
|
+
switch (e.key) {
|
|
112
|
+
case 'Escape':
|
|
113
|
+
if (!disableDismiss) {
|
|
114
|
+
onClose(e);
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
case 'Enter':
|
|
118
|
+
await onSave(e);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const onAnimationComplete = (definition) => {
|
|
123
|
+
if (definition === 'visible') {
|
|
124
|
+
onOpenedRef.current();
|
|
125
|
+
}
|
|
126
|
+
else if (definition === 'exit') {
|
|
127
|
+
onClosedRef.current();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const onBackdropClick = (e) => {
|
|
131
|
+
// close only if the backdrop is directly clicked
|
|
132
|
+
const target = e.target;
|
|
133
|
+
if ((target === null || target === void 0 ? void 0 : target.id) === id) {
|
|
134
|
+
// stop bubbling
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
// close
|
|
137
|
+
onClose();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
// render
|
|
141
|
+
return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(react_1.AnimatePresence, { children: open &&
|
|
142
|
+
(0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { id: id, className: (0, classnames_1.default)('fixed inset-0 z-popup', {
|
|
143
|
+
'pointer-events-none': disableOverlay
|
|
144
|
+
}), variants: exports.Animations.background, initial: "initial", animate: "animate", exit: "exit", onAnimationComplete: definition => onAnimationComplete(definition), onClick: disableDismiss || locked ? undefined : onBackdropClick, layout: true, children: [backdrop !== 'none' &&
|
|
145
|
+
(0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: (0, classnames_1.default)('fixed inset-0 z-backdrop pointer-events-none', {
|
|
146
|
+
'backdrop-blur-[9px] bg-glass/backdrop will-change-[backdrop-filter]': backdrop === 'glass'
|
|
147
|
+
}) }, "backdrop"), (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, Object.assign({}, props, { className: (0, classnames_1.default)(className, 'fixed right-0 inset-y-0 pointer-events-none', {
|
|
148
|
+
'w-full sm:w-[380px]': !wide,
|
|
149
|
+
'w-full md:w-screen-sm': wide,
|
|
150
|
+
}), variants: exports.Animations.slideRight, initial: "initial", animate: "animate", exit: "exit", onKeyDown: onKeyDown, tabIndex: -1, children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(className, 'w-full h-full max-h-full pointer-events-auto', 'flex flex-col', 'bg-background border-l border-solid border-border-l1 rounded-tl-md rounded-bl-md'), children: [(0, jsx_runtime_1.jsx)("h2", { className: "heading-md text-content-primary p-l8", children: title }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-scroll", children: children }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end items-center gap-l4 p-l8", children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { variant: "text", size: "sm", disabled: locked, onClick: onClose, children: "Cancel" }), customActions &&
|
|
151
|
+
(0, jsx_runtime_1.jsx)("div", { className: "flex-1 flex justify-end items-center gap-l4", children: customActions }), (0, jsx_runtime_1.jsx)(Button_1.Button, { variant: "primary", size: "sm", loading: state === 'saving', disabled: disableSave || locked, onClick: onSave, children: renderSaveLabel(state) })] })] }) }))] }, id) }), document.body);
|
|
152
|
+
}
|
|
153
|
+
// helpers
|
|
154
|
+
exports.Animations = {
|
|
155
|
+
background: {
|
|
156
|
+
hidden: {
|
|
157
|
+
opacity: 0
|
|
158
|
+
},
|
|
159
|
+
visible: {
|
|
160
|
+
opacity: 1,
|
|
161
|
+
transition: {
|
|
162
|
+
ease: 'easeIn',
|
|
163
|
+
duration: 0.3,
|
|
164
|
+
when: 'beforeChildren'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
exit: {
|
|
168
|
+
opacity: 0,
|
|
169
|
+
transition: {
|
|
170
|
+
ease: 'easeIn',
|
|
171
|
+
duration: 0.15,
|
|
172
|
+
bounce: 0,
|
|
173
|
+
when: 'afterChildren'
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
slideRight: {
|
|
178
|
+
initial: {
|
|
179
|
+
x: '100%'
|
|
180
|
+
},
|
|
181
|
+
animate: {
|
|
182
|
+
x: '0'
|
|
183
|
+
},
|
|
184
|
+
exit: {
|
|
185
|
+
x: '100%'
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
function onRenderSaveLabel(state) {
|
|
190
|
+
switch (state) {
|
|
191
|
+
case 'editing':
|
|
192
|
+
case 'validating':
|
|
193
|
+
case 'error':
|
|
194
|
+
return 'Save';
|
|
195
|
+
case 'saving':
|
|
196
|
+
return 'Saving...';
|
|
197
|
+
case 'saved':
|
|
198
|
+
return 'Saved';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -41,6 +41,7 @@ __exportStar(require("./Profile"), exports);
|
|
|
41
41
|
__exportStar(require("./QuickInput"), exports);
|
|
42
42
|
__exportStar(require("./QuickPicker"), exports);
|
|
43
43
|
__exportStar(require("./SegmentedButton"), exports);
|
|
44
|
+
__exportStar(require("./SideSheet"), exports);
|
|
44
45
|
__exportStar(require("./Sortable"), exports);
|
|
45
46
|
__exportStar(require("./Tabs"), exports);
|
|
46
47
|
__exportStar(require("./Toggle"), exports);
|
|
@@ -9,8 +9,7 @@ const LegacyBlockConfigEditor_1 = require("./LegacyBlockConfigEditor");
|
|
|
9
9
|
// component
|
|
10
10
|
function BlockConfig({ className, block: blockOrSectionBlock }) {
|
|
11
11
|
// bind ref
|
|
12
|
-
const
|
|
13
|
-
const legacyEditorRef = (0, react_1.useRef)(null);
|
|
12
|
+
const [configuration, setConfiguration] = (0, react_1.useState)();
|
|
14
13
|
// skip if there's no config
|
|
15
14
|
const block = blockOrSectionBlock instanceof core_1.SectionBlock
|
|
16
15
|
? blockOrSectionBlock.block
|
|
@@ -19,25 +18,11 @@ function BlockConfig({ className, block: blockOrSectionBlock }) {
|
|
|
19
18
|
if (config.length === 0) {
|
|
20
19
|
return undefined;
|
|
21
20
|
}
|
|
22
|
-
// helpers
|
|
23
|
-
const onEdit = async (event) => {
|
|
24
|
-
var _a, _b;
|
|
25
|
-
// use new configurator (if enabled)
|
|
26
|
-
if (process.env.NEXT_PUBLIC_EDITOR_BLOCK_CONFIG === 'experimental') {
|
|
27
|
-
await ((_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.edit({
|
|
28
|
-
block: blockOrSectionBlock,
|
|
29
|
-
anchor: event.currentTarget
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
// or use legacy version
|
|
33
|
-
else {
|
|
34
|
-
await ((_b = legacyEditorRef.current) === null || _b === void 0 ? void 0 : _b.edit({
|
|
35
|
-
block: blockOrSectionBlock,
|
|
36
|
-
anchor: event.currentTarget
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
21
|
// render
|
|
41
22
|
const valid = config.every(field => field.valid);
|
|
42
|
-
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:
|
|
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'
|
|
24
|
+
?
|
|
25
|
+
(0, jsx_runtime_1.jsx)(BlockConfigEditor_1.BlockConfigEditor, { configuration: configuration, onClose: () => setConfiguration(undefined) })
|
|
26
|
+
:
|
|
27
|
+
(0, jsx_runtime_1.jsx)(LegacyBlockConfigEditor_1.LegacyBlockConfigEditor, { configuration: configuration, onClose: () => setConfiguration(undefined) })] }));
|
|
43
28
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export declare
|
|
1
|
+
import { Callback } from '@nascentdigital/funnel-core';
|
|
2
|
+
import { BlockConfiguration } from '../../../core';
|
|
3
|
+
export declare function BlockConfigEditor({ configuration, onClose }: BlockConfigEditor.Props): import("react/jsx-runtime").JSX.Element | null;
|
|
4
4
|
export declare namespace BlockConfigEditor {
|
|
5
|
-
type Props = {
|
|
6
|
-
|
|
7
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BlockConfigEditor =
|
|
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
6
|
const client_1 = require("@nascentdigital/funnel-ui/client");
|
|
@@ -11,11 +11,8 @@ const core_1 = require("../../../core");
|
|
|
11
11
|
const hooks_1 = require("../../hooks");
|
|
12
12
|
const BlockPreview_1 = require("./BlockPreview");
|
|
13
13
|
// editor
|
|
14
|
-
|
|
14
|
+
function BlockConfigEditor({ configuration, onClose }) {
|
|
15
15
|
// bind state + hooks
|
|
16
|
-
const [deferral, setDeferral] = (0, react_2.useState)(undefined);
|
|
17
|
-
const [configuration, setConfiguration] = (0, react_2.useState)();
|
|
18
|
-
const [anchor, setAnchor] = (0, react_2.useState)();
|
|
19
16
|
const [blockView, setBlockView] = (0, react_2.useState)('desktop');
|
|
20
17
|
const pageController = (0, hooks_1.usePageController)();
|
|
21
18
|
const touch = (0, client_1.useTouch)();
|
|
@@ -24,40 +21,20 @@ exports.BlockConfigEditor = (0, react_2.forwardRef)(function BlockConfigEditor(_
|
|
|
24
21
|
const settingsFields = blockView === 'desktop' ? desktopFields : mobileFields;
|
|
25
22
|
// sync w/ configuration
|
|
26
23
|
(0, core_1.useBlockConfiguration)(configuration);
|
|
27
|
-
//
|
|
28
|
-
(0, react_2.
|
|
29
|
-
|
|
30
|
-
// reset state
|
|
31
|
-
setConfiguration(block.getConfiguration());
|
|
32
|
-
setAnchor(anchor);
|
|
24
|
+
// reset to desktop when open
|
|
25
|
+
(0, react_2.useEffect)(() => {
|
|
26
|
+
if (configuration) {
|
|
33
27
|
setBlockView('desktop');
|
|
34
|
-
// create deferral
|
|
35
|
-
const deferral = new funnel_core_1.Deferral();
|
|
36
|
-
setDeferral(deferral);
|
|
37
|
-
// wait until deferral is resolved
|
|
38
|
-
return deferral.promise;
|
|
39
28
|
}
|
|
40
|
-
}
|
|
29
|
+
}, [configuration]);
|
|
41
30
|
// helpers
|
|
42
31
|
const onSave = async () => {
|
|
43
32
|
// save config
|
|
44
33
|
configuration === null || configuration === void 0 ? void 0 : configuration.save();
|
|
45
34
|
// wait for page to save
|
|
46
35
|
await (0, rxjs_1.firstValueFrom)(pageController.saved$);
|
|
47
|
-
// complete
|
|
48
|
-
|
|
49
|
-
// refresh
|
|
50
|
-
touch();
|
|
51
|
-
};
|
|
52
|
-
const onCancel = () => {
|
|
53
|
-
// skip if missing or already completed
|
|
54
|
-
if (!deferral || deferral.isComplete) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
// cancel
|
|
58
|
-
deferral.resolve(undefined);
|
|
59
|
-
// touch
|
|
60
|
-
touch();
|
|
36
|
+
// complete
|
|
37
|
+
onClose();
|
|
61
38
|
};
|
|
62
39
|
const onChangePanelLayout = async (e) => {
|
|
63
40
|
var _a;
|
|
@@ -88,10 +65,10 @@ exports.BlockConfigEditor = (0, react_2.forwardRef)(function BlockConfigEditor(_
|
|
|
88
65
|
return null;
|
|
89
66
|
}
|
|
90
67
|
// render
|
|
91
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(core_1.
|
|
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 &&
|
|
92
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 &&
|
|
93
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) })] }));
|
|
94
|
-
}
|
|
71
|
+
}
|
|
95
72
|
function renderPanelLayoutItem(item) {
|
|
96
73
|
switch (item.id) {
|
|
97
74
|
case 'stack.h':
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export declare
|
|
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
|
-
|
|
7
|
-
|
|
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 =
|
|
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
|
-
|
|
10
|
+
function LegacyBlockConfigEditor({ configuration, onClose }) {
|
|
13
11
|
// bind state + hooks
|
|
14
|
-
const [
|
|
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
|
-
//
|
|
23
|
-
(0, react_1.
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
42
|
-
|
|
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.
|
|
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
|
+
}
|
package/dist/styles/index.css
CHANGED
|
@@ -4711,9 +4711,6 @@ video {
|
|
|
4711
4711
|
.w-\[50px\]{
|
|
4712
4712
|
width: 50px;
|
|
4713
4713
|
}
|
|
4714
|
-
.w-\[550px\]{
|
|
4715
|
-
width: 550px;
|
|
4716
|
-
}
|
|
4717
4714
|
.w-\[64px\]{
|
|
4718
4715
|
width: 64px;
|
|
4719
4716
|
}
|
|
@@ -4723,6 +4720,9 @@ video {
|
|
|
4723
4720
|
.w-full{
|
|
4724
4721
|
width: 100%;
|
|
4725
4722
|
}
|
|
4723
|
+
.w-screen-sm{
|
|
4724
|
+
width: 600px;
|
|
4725
|
+
}
|
|
4726
4726
|
.min-w-18{
|
|
4727
4727
|
min-width: 18px;
|
|
4728
4728
|
}
|
|
@@ -5035,6 +5035,12 @@ video {
|
|
|
5035
5035
|
border-top-left-radius: 18px;
|
|
5036
5036
|
border-top-right-radius: 18px;
|
|
5037
5037
|
}
|
|
5038
|
+
.rounded-bl-md{
|
|
5039
|
+
border-bottom-left-radius: 12px;
|
|
5040
|
+
}
|
|
5041
|
+
.rounded-tl-md{
|
|
5042
|
+
border-top-left-radius: 12px;
|
|
5043
|
+
}
|
|
5038
5044
|
.border{
|
|
5039
5045
|
border-width: 1px;
|
|
5040
5046
|
}
|
|
@@ -6201,6 +6207,10 @@ video {
|
|
|
6201
6207
|
width: 80%;
|
|
6202
6208
|
}
|
|
6203
6209
|
|
|
6210
|
+
.sm\:w-\[380px\]{
|
|
6211
|
+
width: 380px;
|
|
6212
|
+
}
|
|
6213
|
+
|
|
6204
6214
|
.sm\:max-w-screen-sm{
|
|
6205
6215
|
max-width: 480px;
|
|
6206
6216
|
}
|
|
@@ -6231,6 +6241,10 @@ video {
|
|
|
6231
6241
|
width: 280px;
|
|
6232
6242
|
}
|
|
6233
6243
|
|
|
6244
|
+
.md\:w-screen-sm{
|
|
6245
|
+
width: 600px;
|
|
6246
|
+
}
|
|
6247
|
+
|
|
6234
6248
|
.md\:grid-cols-3{
|
|
6235
6249
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
6236
6250
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nascentdigital/funnel-editor",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "restricted"
|
|
@@ -89,5 +89,5 @@
|
|
|
89
89
|
"ts-jest": "^29",
|
|
90
90
|
"type-fest": "^4"
|
|
91
91
|
},
|
|
92
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "5b63f9cd8843cc111b4458c71aa031a974455241"
|
|
93
93
|
}
|