lkb-fields-document 1.0.0
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/component-blocks/dist/lkb-fields-document-component-blocks.cjs.d.ts +2 -0
- package/component-blocks/dist/lkb-fields-document-component-blocks.cjs.js +306 -0
- package/component-blocks/dist/lkb-fields-document-component-blocks.esm.js +300 -0
- package/component-blocks/dist/lkb-fields-document-component-blocks.node.cjs.js +306 -0
- package/component-blocks/dist/lkb-fields-document-component-blocks.node.esm.js +300 -0
- package/component-blocks/package.json +4 -0
- package/dist/Cell-0ac0ac66.node.cjs.js +21 -0
- package/dist/Cell-242f7404.esm.js +17 -0
- package/dist/Cell-3103f73d.node.esm.js +17 -0
- package/dist/Cell-bfb56d74.cjs.js +21 -0
- package/dist/Field-0e0f75ed.node.cjs.js +1628 -0
- package/dist/Field-28177061.cjs.js +1628 -0
- package/dist/Field-35b79e6b.node.esm.js +1619 -0
- package/dist/Field-92d13205.esm.js +1619 -0
- package/dist/api-2f524611.esm.js +502 -0
- package/dist/api-73636987.cjs.js +506 -0
- package/dist/api-8e2b20b8.node.cjs.js +506 -0
- package/dist/api-c32e360e.node.esm.js +502 -0
- package/dist/callout-ui-2aded278.cjs.js +131 -0
- package/dist/callout-ui-3e5ca544.node.esm.js +126 -0
- package/dist/callout-ui-8b5f2376.esm.js +126 -0
- package/dist/callout-ui-ad50f301.node.cjs.js +131 -0
- package/dist/declarations/src/component-blocks.d.ts +4 -0
- package/dist/declarations/src/component-blocks.d.ts.map +1 -0
- package/dist/declarations/src/document-editor/component-blocks/api.d.ts +120 -0
- package/dist/declarations/src/document-editor/component-blocks/api.d.ts.map +1 -0
- package/dist/declarations/src/document-editor/component-blocks/types.d.ts +241 -0
- package/dist/declarations/src/document-editor/component-blocks/types.d.ts.map +1 -0
- package/dist/declarations/src/document-editor/toolset/relationship/relationship-shared.d.ts +10 -0
- package/dist/declarations/src/document-editor/toolset/relationship/relationship-shared.d.ts.map +1 -0
- package/dist/declarations/src/index.d.ts +7 -0
- package/dist/declarations/src/index.d.ts.map +1 -0
- package/dist/declarations/src/my-component-blocks/index.d.ts +46 -0
- package/dist/declarations/src/my-component-blocks/index.d.ts.map +1 -0
- package/dist/declarations/src/structure/Cell.d.ts +5 -0
- package/dist/declarations/src/structure/Cell.d.ts.map +1 -0
- package/dist/declarations/src/structure/Field.d.ts +5 -0
- package/dist/declarations/src/structure/Field.d.ts.map +1 -0
- package/dist/declarations/src/structure/controller.d.ts +10 -0
- package/dist/declarations/src/structure/controller.d.ts.map +1 -0
- package/dist/declarations/src/structure/structure.d.ts +4 -0
- package/dist/declarations/src/structure/structure.d.ts.map +1 -0
- package/dist/declarations/src/structure-views.d.ts +5 -0
- package/dist/declarations/src/structure-views.d.ts.map +1 -0
- package/dist/declarations/src/types/DocumentFeatures.d.ts +33 -0
- package/dist/declarations/src/types/DocumentFeatures.d.ts.map +1 -0
- package/dist/declarations/src/types/DocumentFieldConfig.d.ts +18 -0
- package/dist/declarations/src/types/DocumentFieldConfig.d.ts.map +1 -0
- package/dist/declarations/src/types/FormattingConfig.d.ts +28 -0
- package/dist/declarations/src/types/FormattingConfig.d.ts.map +1 -0
- package/dist/declarations/src/types/RelationshipsConfig.d.ts +9 -0
- package/dist/declarations/src/types/RelationshipsConfig.d.ts.map +1 -0
- package/dist/declarations/src/types/StructureFieldConfig.d.ts +10 -0
- package/dist/declarations/src/types/StructureFieldConfig.d.ts.map +1 -0
- package/dist/declarations/src/validation/structure-validation.d.ts +218 -0
- package/dist/declarations/src/validation/structure-validation.d.ts.map +1 -0
- package/dist/declarations/src/views/Cell.d.ts +5 -0
- package/dist/declarations/src/views/Cell.d.ts.map +1 -0
- package/dist/declarations/src/views/Field.d.ts +5 -0
- package/dist/declarations/src/views/Field.d.ts.map +1 -0
- package/dist/declarations/src/views/controller.d.ts +15 -0
- package/dist/declarations/src/views/controller.d.ts.map +1 -0
- package/dist/declarations/src/views/document.d.ts +4 -0
- package/dist/declarations/src/views/document.d.ts.map +1 -0
- package/dist/declarations/src/views.d.ts +7 -0
- package/dist/declarations/src/views.d.ts.map +1 -0
- package/dist/editor-shared-a6e340e6.node.esm.js +1993 -0
- package/dist/editor-shared-a997ae98.node.cjs.js +2007 -0
- package/dist/editor-shared-cc1293ed.cjs.js +2007 -0
- package/dist/editor-shared-da518ba3.esm.js +1993 -0
- package/dist/form-from-preview-2042b9ef.cjs.js +512 -0
- package/dist/form-from-preview-5df6e492.node.esm.js +508 -0
- package/dist/form-from-preview-9e501058.node.cjs.js +512 -0
- package/dist/form-from-preview-b3a66f37.esm.js +508 -0
- package/dist/index-06c36775.cjs.js +14 -0
- package/dist/index-586adb8f.node.esm.js +11 -0
- package/dist/index-67d52357.esm.js +11 -0
- package/dist/index-c3223fdc.node.cjs.js +14 -0
- package/dist/layouts-6412fa2a.esm.js +189 -0
- package/dist/layouts-a4a3cf0b.node.cjs.js +196 -0
- package/dist/layouts-ba9a558b.cjs.js +196 -0
- package/dist/layouts-e653b908.node.esm.js +189 -0
- package/dist/lkb-fields-document.cjs.d.ts +2 -0
- package/dist/lkb-fields-document.cjs.js +1167 -0
- package/dist/lkb-fields-document.esm.js +1162 -0
- package/dist/lkb-fields-document.node.cjs.js +1167 -0
- package/dist/lkb-fields-document.node.esm.js +1162 -0
- package/dist/shared-0533009e.cjs.js +594 -0
- package/dist/shared-4684cc24.node.cjs.js +594 -0
- package/dist/shared-5e864055.node.esm.js +579 -0
- package/dist/shared-aaba5901.esm.js +579 -0
- package/dist/toolbar-state-3359e2f3.cjs.js +994 -0
- package/dist/toolbar-state-945823b8.node.esm.js +971 -0
- package/dist/toolbar-state-9611743f.node.cjs.js +994 -0
- package/dist/toolbar-state-bc8fe661.esm.js +971 -0
- package/dist/utils-06bcddc4.node.cjs.js +747 -0
- package/dist/utils-200ff260.node.esm.js +722 -0
- package/dist/utils-6409f730.cjs.js +747 -0
- package/dist/utils-bc6a0b82.esm.js +722 -0
- package/package.json +118 -0
- package/structure-views/dist/lkb-fields-document-structure-views.cjs.d.ts +2 -0
- package/structure-views/dist/lkb-fields-document-structure-views.cjs.js +138 -0
- package/structure-views/dist/lkb-fields-document-structure-views.esm.js +131 -0
- package/structure-views/dist/lkb-fields-document-structure-views.node.cjs.js +138 -0
- package/structure-views/dist/lkb-fields-document-structure-views.node.esm.js +131 -0
- package/structure-views/package.json +4 -0
- package/views/dist/lkb-fields-document-views.cjs.d.ts +2 -0
- package/views/dist/lkb-fields-document-views.cjs.js +114 -0
- package/views/dist/lkb-fields-document-views.esm.js +95 -0
- package/views/dist/lkb-fields-document-views.node.cjs.js +114 -0
- package/views/dist/lkb-fields-document-views.node.esm.js +95 -0
- package/views/package.json +4 -0
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback, useMemo, useContext, Fragment, forwardRef, useId, cloneElement, createContext } from 'react';
|
|
2
|
+
import { ReactEditor, useSelected, useSlateStatic, useSlate } from 'slate-react';
|
|
3
|
+
import { Transforms, Editor, Node } from 'slate';
|
|
4
|
+
import { css, tokenSchema, transition } from '@keystar/ui/style';
|
|
5
|
+
import { d as assert, f as getKeysForArrayValue, g as getInitialPropsValue, q as createGetPreviewProps, p as clientSideValidateProp, n as nodeTypeMatcher, w as getInitialValue, k as insertNodesButReplaceIfSelectionIsAtEmptyParagraphOrHeading } from './utils-200ff260.node.esm.js';
|
|
6
|
+
import { a as areArraysEqual, j as createToolbarState } from './shared-5e864055.node.esm.js';
|
|
7
|
+
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
8
|
+
import { Icon } from '@keystar/ui/icon';
|
|
9
|
+
import { trash2Icon } from '@keystar/ui/icon/icons/trash2Icon';
|
|
10
|
+
import { ActionButton, ButtonGroup, Button } from '@keystar/ui/button';
|
|
11
|
+
import { Heading } from '@keystar/ui/typography';
|
|
12
|
+
import { N as NotEditable } from './api-c32e360e.node.esm.js';
|
|
13
|
+
import { p as previewPropsToValue, a as previewPropsOnChange, F as FormValueContentFromPreviewProps } from './form-from-preview-5df6e492.node.esm.js';
|
|
14
|
+
import { DialogContainer, Dialog } from '@keystar/ui/dialog';
|
|
15
|
+
import { FieldMessage } from '@keystar/ui/field';
|
|
16
|
+
import { Flex } from '@keystar/ui/layout';
|
|
17
|
+
import { Content } from '@keystar/ui/slots';
|
|
18
|
+
import { TooltipTrigger, Tooltip } from '@keystar/ui/tooltip';
|
|
19
|
+
import { trashIcon } from '@keystar/ui/icon/icons/trashIcon';
|
|
20
|
+
import { useOverlay, useOverlayPosition } from '@react-aria/overlays';
|
|
21
|
+
import { useLayoutEffect, mergeProps } from '@react-aria/utils';
|
|
22
|
+
import { useOverlayTriggerState } from '@react-stately/overlays';
|
|
23
|
+
import { Overlay } from '@keystar/ui/overlays';
|
|
24
|
+
import '@emotion/weak-memoize';
|
|
25
|
+
import { LayoutOptionsProvider } from './layouts-e653b908.node.esm.js';
|
|
26
|
+
import { useList } from 'lkb-core/admin-ui/context';
|
|
27
|
+
import { ComboboxSingle } from 'lkb-core/fields/types/relationship/views';
|
|
28
|
+
|
|
29
|
+
// this ensures that when changes happen, they are immediately shown
|
|
30
|
+
// this stops the problem of a cursor resetting to the end when a change is made
|
|
31
|
+
// because the changes are applied asynchronously
|
|
32
|
+
function useElementWithSetNodes(editor, element) {
|
|
33
|
+
const [state, setState] = useState({
|
|
34
|
+
element,
|
|
35
|
+
elementWithChanges: element
|
|
36
|
+
});
|
|
37
|
+
if (state.element !== element) {
|
|
38
|
+
setState({
|
|
39
|
+
element,
|
|
40
|
+
elementWithChanges: element
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const elementRef = useRef(element);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
elementRef.current = element;
|
|
46
|
+
});
|
|
47
|
+
const setNodes = useCallback(changesOrCallback => {
|
|
48
|
+
const currentElement = elementRef.current;
|
|
49
|
+
const changes = typeof changesOrCallback === 'function' ? changesOrCallback(currentElement) : changesOrCallback;
|
|
50
|
+
Transforms.setNodes(editor, changes, {
|
|
51
|
+
at: ReactEditor.findPath(editor, currentElement)
|
|
52
|
+
});
|
|
53
|
+
setState({
|
|
54
|
+
element: currentElement,
|
|
55
|
+
elementWithChanges: {
|
|
56
|
+
...currentElement,
|
|
57
|
+
...changes
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}, [editor]);
|
|
61
|
+
return [state.elementWithChanges, setNodes];
|
|
62
|
+
}
|
|
63
|
+
function useEventCallback(callback) {
|
|
64
|
+
const callbackRef = useRef(callback);
|
|
65
|
+
const cb = useCallback((...args) => {
|
|
66
|
+
return callbackRef.current(...args);
|
|
67
|
+
}, []);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
callbackRef.current = callback;
|
|
70
|
+
});
|
|
71
|
+
return cb;
|
|
72
|
+
}
|
|
73
|
+
const ForceValidationContext = /*#__PURE__*/React.createContext(false);
|
|
74
|
+
const ForceValidationProvider = ForceValidationContext.Provider;
|
|
75
|
+
function focusWithPreviousSelection(editor) {
|
|
76
|
+
const selection = window.getSelection();
|
|
77
|
+
if (selection) {
|
|
78
|
+
selection.removeAllRanges();
|
|
79
|
+
selection.addRange(ReactEditor.toDOMRange(editor, editor.selection));
|
|
80
|
+
}
|
|
81
|
+
ReactEditor.focus(editor);
|
|
82
|
+
}
|
|
83
|
+
const blockElementSpacing = css({
|
|
84
|
+
marginBlock: '0.75em',
|
|
85
|
+
'&:first-child': {
|
|
86
|
+
marginBlockStart: 0
|
|
87
|
+
},
|
|
88
|
+
'&:last-child': {
|
|
89
|
+
marginBlockEnd: 0
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
function updateComponentBlockElementProps(editor, componentBlock, prevProps, newProps, basePath, setElement) {
|
|
94
|
+
Editor.withoutNormalizing(editor, () => {
|
|
95
|
+
setElement({
|
|
96
|
+
props: newProps
|
|
97
|
+
});
|
|
98
|
+
const childPropPaths = findChildPropPathsWithPrevious(newProps, prevProps, {
|
|
99
|
+
kind: 'object',
|
|
100
|
+
fields: componentBlock.schema
|
|
101
|
+
}, [], [], []);
|
|
102
|
+
const getNode = () => Node.get(editor, basePath);
|
|
103
|
+
const elementForChildren = getNode();
|
|
104
|
+
if (childPropPaths.length === 0) {
|
|
105
|
+
const indexes = elementForChildren.children.map((_, i) => i).reverse();
|
|
106
|
+
for (const idx of indexes) {
|
|
107
|
+
Transforms.removeNodes(editor, {
|
|
108
|
+
at: [...basePath, idx]
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
Transforms.insertNodes(editor, {
|
|
112
|
+
type: 'component-inline-prop',
|
|
113
|
+
propPath: undefined,
|
|
114
|
+
children: [{
|
|
115
|
+
text: ''
|
|
116
|
+
}]
|
|
117
|
+
}, {
|
|
118
|
+
at: [...basePath, 0]
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const initialPropPathsToEditorPath = new Map();
|
|
123
|
+
for (const [idx, node] of elementForChildren.children.entries()) {
|
|
124
|
+
assert(node.type === 'component-block-prop' || node.type === 'component-inline-prop');
|
|
125
|
+
initialPropPathsToEditorPath.set(node.propPath === undefined ? undefined : JSON.stringify(node.propPath), idx);
|
|
126
|
+
}
|
|
127
|
+
const childrenLeftToAdd = new Set(childPropPaths);
|
|
128
|
+
for (const childProp of childPropPaths) {
|
|
129
|
+
if (childProp.prevPath === undefined) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const stringifiedPath = JSON.stringify(childProp.prevPath);
|
|
133
|
+
const idxInChildren = initialPropPathsToEditorPath.get(stringifiedPath);
|
|
134
|
+
if (idxInChildren !== undefined) {
|
|
135
|
+
const prevNode = elementForChildren.children[idxInChildren];
|
|
136
|
+
assert(prevNode.propPath !== undefined);
|
|
137
|
+
if (!areArraysEqual(childProp.path, prevNode.propPath)) {
|
|
138
|
+
Transforms.setNodes(editor, {
|
|
139
|
+
propPath: childProp.path
|
|
140
|
+
}, {
|
|
141
|
+
at: [...basePath, idxInChildren]
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
childrenLeftToAdd.delete(childProp);
|
|
145
|
+
initialPropPathsToEditorPath.delete(stringifiedPath);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
let newIdx = getNode().children.length;
|
|
149
|
+
for (const childProp of childrenLeftToAdd) {
|
|
150
|
+
Transforms.insertNodes(editor, {
|
|
151
|
+
type: `component-${childProp.options.kind}-prop`,
|
|
152
|
+
propPath: childProp.path,
|
|
153
|
+
children: [childProp.options.kind === 'block' ? {
|
|
154
|
+
type: 'paragraph',
|
|
155
|
+
children: [{
|
|
156
|
+
text: ''
|
|
157
|
+
}]
|
|
158
|
+
} : {
|
|
159
|
+
text: ''
|
|
160
|
+
}]
|
|
161
|
+
}, {
|
|
162
|
+
at: [...basePath, newIdx]
|
|
163
|
+
});
|
|
164
|
+
newIdx++;
|
|
165
|
+
}
|
|
166
|
+
const pathsToRemove = [];
|
|
167
|
+
for (const [, idxInChildren] of initialPropPathsToEditorPath) {
|
|
168
|
+
pathsToRemove.push(Editor.pathRef(editor, [...basePath, idxInChildren]));
|
|
169
|
+
}
|
|
170
|
+
for (const pathRef of pathsToRemove) {
|
|
171
|
+
const path = pathRef.unref();
|
|
172
|
+
assert(path !== null);
|
|
173
|
+
Transforms.removeNodes(editor, {
|
|
174
|
+
at: path
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const propPathsToExpectedIndexes = new Map();
|
|
178
|
+
for (const [idx, thing] of childPropPaths.entries()) {
|
|
179
|
+
propPathsToExpectedIndexes.set(JSON.stringify(thing.path), idx);
|
|
180
|
+
}
|
|
181
|
+
outer: while (true) {
|
|
182
|
+
for (const [idx, childNode] of getNode().children.entries()) {
|
|
183
|
+
assert(childNode.type === 'component-block-prop' || childNode.type === 'component-inline-prop');
|
|
184
|
+
const expectedIndex = propPathsToExpectedIndexes.get(JSON.stringify(childNode.propPath));
|
|
185
|
+
assert(expectedIndex !== undefined);
|
|
186
|
+
if (idx === expectedIndex) continue;
|
|
187
|
+
Transforms.moveNodes(editor, {
|
|
188
|
+
at: [...basePath, idx],
|
|
189
|
+
to: [...basePath, expectedIndex]
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// start the for-loop again
|
|
193
|
+
continue outer;
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function findChildPropPathsWithPrevious(value, prevValue, schema, newPath, prevPath, pathWithKeys) {
|
|
200
|
+
switch (schema.kind) {
|
|
201
|
+
case 'form':
|
|
202
|
+
return [];
|
|
203
|
+
case 'relationship':
|
|
204
|
+
return [];
|
|
205
|
+
case 'child':
|
|
206
|
+
return [{
|
|
207
|
+
path: newPath,
|
|
208
|
+
prevPath,
|
|
209
|
+
options: schema.options
|
|
210
|
+
}];
|
|
211
|
+
case 'conditional':
|
|
212
|
+
{
|
|
213
|
+
const hasChangedDiscriminant = value.discriminant === prevValue.discriminant;
|
|
214
|
+
return findChildPropPathsWithPrevious(value.value, hasChangedDiscriminant ? prevValue.value : getInitialPropsValue(schema.values[value.discriminant]), schema.values[value.discriminant], newPath.concat('value'), hasChangedDiscriminant ? undefined : prevPath === null || prevPath === void 0 ? void 0 : prevPath.concat('value'), hasChangedDiscriminant ? undefined : pathWithKeys === null || pathWithKeys === void 0 ? void 0 : pathWithKeys.concat('value'));
|
|
215
|
+
}
|
|
216
|
+
case 'object':
|
|
217
|
+
{
|
|
218
|
+
const paths = [];
|
|
219
|
+
for (const key of Object.keys(schema.fields)) {
|
|
220
|
+
paths.push(...findChildPropPathsWithPrevious(value[key], prevValue[key], schema.fields[key], newPath.concat(key), prevPath === null || prevPath === void 0 ? void 0 : prevPath.concat(key), pathWithKeys === null || pathWithKeys === void 0 ? void 0 : pathWithKeys.concat(key)));
|
|
221
|
+
}
|
|
222
|
+
return paths;
|
|
223
|
+
}
|
|
224
|
+
case 'array':
|
|
225
|
+
{
|
|
226
|
+
const paths = [];
|
|
227
|
+
const prevKeys = getKeysForArrayValue(prevValue);
|
|
228
|
+
const keys = getKeysForArrayValue(value);
|
|
229
|
+
for (const [i, val] of value.entries()) {
|
|
230
|
+
const key = keys[i];
|
|
231
|
+
const prevIdx = prevKeys.indexOf(key);
|
|
232
|
+
let prevVal;
|
|
233
|
+
if (prevIdx === -1) {
|
|
234
|
+
prevVal = getInitialPropsValue(schema.element);
|
|
235
|
+
} else {
|
|
236
|
+
prevVal = prevValue[prevIdx];
|
|
237
|
+
}
|
|
238
|
+
paths.push(...findChildPropPathsWithPrevious(val, prevVal, schema.element, newPath.concat(i), prevIdx === -1 ? undefined : prevPath === null || prevPath === void 0 ? void 0 : prevPath.concat(prevIdx), prevIdx === -1 ? undefined : pathWithKeys === null || pathWithKeys === void 0 ? void 0 : pathWithKeys.concat(key)));
|
|
239
|
+
}
|
|
240
|
+
return paths;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const ChildrenByPathContext = /*#__PURE__*/React.createContext({});
|
|
246
|
+
function ChildFieldEditable({
|
|
247
|
+
path
|
|
248
|
+
}) {
|
|
249
|
+
const childrenByPath = useContext(ChildrenByPathContext);
|
|
250
|
+
const child = childrenByPath[JSON.stringify(path)];
|
|
251
|
+
if (child === undefined) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
return child;
|
|
255
|
+
}
|
|
256
|
+
function ComponentBlockRender({
|
|
257
|
+
componentBlock,
|
|
258
|
+
element,
|
|
259
|
+
onChange,
|
|
260
|
+
children
|
|
261
|
+
}) {
|
|
262
|
+
const getPreviewProps = useMemo(() => {
|
|
263
|
+
return createGetPreviewProps({
|
|
264
|
+
kind: 'object',
|
|
265
|
+
fields: componentBlock.schema
|
|
266
|
+
}, onChange, path => /*#__PURE__*/jsx(ChildFieldEditable, {
|
|
267
|
+
path: path
|
|
268
|
+
}));
|
|
269
|
+
}, [onChange, componentBlock]);
|
|
270
|
+
const previewProps = getPreviewProps(element.props);
|
|
271
|
+
const childrenByPath = {};
|
|
272
|
+
let maybeChild;
|
|
273
|
+
for (const child of children) {
|
|
274
|
+
const propPath = child.props.children.props.element.propPath;
|
|
275
|
+
if (propPath === undefined) {
|
|
276
|
+
maybeChild = child;
|
|
277
|
+
} else {
|
|
278
|
+
childrenByPath[JSON.stringify(propPathWithIndiciesToKeys(propPath, element.props))] = child;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const ComponentBlockPreview = componentBlock.preview;
|
|
282
|
+
return /*#__PURE__*/jsxs(ChildrenByPathContext.Provider, {
|
|
283
|
+
value: childrenByPath,
|
|
284
|
+
children: [useMemo(() => /*#__PURE__*/jsx(ComponentBlockPreview, {
|
|
285
|
+
...previewProps
|
|
286
|
+
}), [previewProps, ComponentBlockPreview]), /*#__PURE__*/jsx("span", {
|
|
287
|
+
className: css({
|
|
288
|
+
caretColor: 'transparent',
|
|
289
|
+
'& ::selection': {
|
|
290
|
+
backgroundColor: 'transparent'
|
|
291
|
+
}
|
|
292
|
+
}),
|
|
293
|
+
children: maybeChild
|
|
294
|
+
})]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// note this is written to avoid crashing when the given prop path doesn't exist in the value
|
|
299
|
+
// this is because editor updates happen asynchronously but we have some logic to ensure
|
|
300
|
+
// that updating the props of a component block synchronously updates it
|
|
301
|
+
// (this is primarily to not mess up things like cursors in inputs)
|
|
302
|
+
// this means that sometimes the child elements will be inconsistent with the values
|
|
303
|
+
// so to deal with this, we return a prop path this is "wrong" but won't break anything
|
|
304
|
+
function propPathWithIndiciesToKeys(propPath, val) {
|
|
305
|
+
return propPath.map(key => {
|
|
306
|
+
var _val2;
|
|
307
|
+
if (typeof key === 'string') {
|
|
308
|
+
var _val;
|
|
309
|
+
val = (_val = val) === null || _val === void 0 ? void 0 : _val[key];
|
|
310
|
+
return key;
|
|
311
|
+
}
|
|
312
|
+
if (!Array.isArray(val)) {
|
|
313
|
+
val = undefined;
|
|
314
|
+
return '';
|
|
315
|
+
}
|
|
316
|
+
const keys = getKeysForArrayValue(val);
|
|
317
|
+
val = (_val2 = val) === null || _val2 === void 0 ? void 0 : _val2[key];
|
|
318
|
+
return keys[key];
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function ChromefulComponentBlockElement(props) {
|
|
323
|
+
var _props$componentBlock;
|
|
324
|
+
const selected = useSelected();
|
|
325
|
+
const isValid = useMemo(() => clientSideValidateProp({
|
|
326
|
+
kind: 'object',
|
|
327
|
+
fields: props.componentBlock.schema
|
|
328
|
+
}, props.elementProps), [props.componentBlock, props.elementProps]);
|
|
329
|
+
const [editMode, setEditMode] = useState(false);
|
|
330
|
+
const onCloseEditMode = useCallback(() => {
|
|
331
|
+
setEditMode(false);
|
|
332
|
+
}, []);
|
|
333
|
+
const onShowEditMode = useCallback(() => {
|
|
334
|
+
setEditMode(true);
|
|
335
|
+
}, []);
|
|
336
|
+
const ChromefulToolbar = (_props$componentBlock = props.componentBlock.toolbar) !== null && _props$componentBlock !== void 0 ? _props$componentBlock : DefaultToolbarWithChrome;
|
|
337
|
+
return /*#__PURE__*/jsx(BlockPrimitive, {
|
|
338
|
+
selected: selected,
|
|
339
|
+
...props.attributes,
|
|
340
|
+
children: /*#__PURE__*/jsx(Flex, {
|
|
341
|
+
gap: "medium",
|
|
342
|
+
direction: "column",
|
|
343
|
+
children: /*#__PURE__*/jsx(Fragment, {
|
|
344
|
+
children: /*#__PURE__*/jsxs("div", {
|
|
345
|
+
children: [props.renderedBlock, /*#__PURE__*/jsx(ChromefulToolbar, {
|
|
346
|
+
isValid: isValid,
|
|
347
|
+
onRemove: props.onRemove,
|
|
348
|
+
props: props.previewProps,
|
|
349
|
+
onShowEditMode: onShowEditMode
|
|
350
|
+
}), /*#__PURE__*/jsx(DialogContainer, {
|
|
351
|
+
onDismiss: () => onCloseEditMode(),
|
|
352
|
+
children: (() => {
|
|
353
|
+
if (!editMode) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
return /*#__PURE__*/jsxs(Dialog, {
|
|
357
|
+
children: [/*#__PURE__*/jsxs(Heading, {
|
|
358
|
+
children: ["\u7F16\u8F91\u3010", props.componentBlock.label, "\u3011\u5C5E\u6027"]
|
|
359
|
+
}), /*#__PURE__*/jsx(FormValue, {
|
|
360
|
+
props: props.previewProps,
|
|
361
|
+
onClose: onCloseEditMode
|
|
362
|
+
})]
|
|
363
|
+
});
|
|
364
|
+
})()
|
|
365
|
+
})]
|
|
366
|
+
})
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Wrap block content, delimiting it from surrounding content, and provide a
|
|
374
|
+
* focus indicator because the cursor may not be present.
|
|
375
|
+
*/
|
|
376
|
+
const BlockPrimitive = /*#__PURE__*/forwardRef(function BlockPrimitive({
|
|
377
|
+
children,
|
|
378
|
+
selected,
|
|
379
|
+
...attributes
|
|
380
|
+
}, ref) {
|
|
381
|
+
return /*#__PURE__*/jsx("div", {
|
|
382
|
+
...attributes,
|
|
383
|
+
ref: ref,
|
|
384
|
+
className: css(blockElementSpacing, {
|
|
385
|
+
position: 'relative',
|
|
386
|
+
paddingInlineStart: 0,
|
|
387
|
+
// tokenSchema.size.space.xlarge,
|
|
388
|
+
marginBottom: 0,
|
|
389
|
+
// tokenSchema.size.space.xlarge,
|
|
390
|
+
|
|
391
|
+
'::before': {
|
|
392
|
+
display: 'block',
|
|
393
|
+
content: '" "',
|
|
394
|
+
backgroundColor: selected ? tokenSchema.color.alias.borderSelected : tokenSchema.color.alias.borderIdle,
|
|
395
|
+
borderRadius: 4,
|
|
396
|
+
width: 0,
|
|
397
|
+
// 4,
|
|
398
|
+
position: 'absolute',
|
|
399
|
+
left: 0,
|
|
400
|
+
top: 0,
|
|
401
|
+
bottom: 0,
|
|
402
|
+
zIndex: 1
|
|
403
|
+
}
|
|
404
|
+
}),
|
|
405
|
+
children: children
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
function DefaultToolbarWithChrome({
|
|
409
|
+
onShowEditMode,
|
|
410
|
+
onRemove,
|
|
411
|
+
isValid
|
|
412
|
+
}) {
|
|
413
|
+
return /*#__PURE__*/jsx(NotEditable, {
|
|
414
|
+
children: /*#__PURE__*/jsxs(Flex, {
|
|
415
|
+
direction: "column",
|
|
416
|
+
gap: "medium",
|
|
417
|
+
children: [/*#__PURE__*/jsxs(Flex, {
|
|
418
|
+
alignItems: "center",
|
|
419
|
+
gap: "regular",
|
|
420
|
+
UNSAFE_style: {
|
|
421
|
+
userSelect: 'none'
|
|
422
|
+
},
|
|
423
|
+
justifyContent: "flex-end",
|
|
424
|
+
children: [/*#__PURE__*/jsxs(TooltipTrigger, {
|
|
425
|
+
children: [/*#__PURE__*/jsx(ActionButton, {
|
|
426
|
+
prominence: "low",
|
|
427
|
+
onPress: onRemove,
|
|
428
|
+
children: /*#__PURE__*/jsx(Icon, {
|
|
429
|
+
src: trash2Icon
|
|
430
|
+
})
|
|
431
|
+
}), /*#__PURE__*/jsx(Tooltip, {
|
|
432
|
+
tone: "critical",
|
|
433
|
+
children: "\u5220\u9664"
|
|
434
|
+
})]
|
|
435
|
+
}), /*#__PURE__*/jsx(ActionButton, {
|
|
436
|
+
onPress: () => onShowEditMode(),
|
|
437
|
+
children: "\u7F16\u8F91"
|
|
438
|
+
})]
|
|
439
|
+
}), !isValid && /*#__PURE__*/jsx(FieldMessage, {
|
|
440
|
+
children: "Contains invalid fields. Please edit."
|
|
441
|
+
})]
|
|
442
|
+
})
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function FormValue({
|
|
446
|
+
onClose,
|
|
447
|
+
props
|
|
448
|
+
}) {
|
|
449
|
+
const formId = useId();
|
|
450
|
+
const [forceValidation, setForceValidation] = useState(false);
|
|
451
|
+
const [state, setState] = useState(() => previewPropsToValue(props));
|
|
452
|
+
const previewProps = useMemo(() => createGetPreviewProps(props.schema, setState, () => undefined), [props.schema])(state);
|
|
453
|
+
return /*#__PURE__*/jsxs(Fragment$1, {
|
|
454
|
+
children: [/*#__PURE__*/jsx(Content, {
|
|
455
|
+
children: /*#__PURE__*/jsx(Flex, {
|
|
456
|
+
id: formId,
|
|
457
|
+
elementType: "form",
|
|
458
|
+
onSubmit: event => {
|
|
459
|
+
if (event.target !== event.currentTarget) return;
|
|
460
|
+
event.preventDefault();
|
|
461
|
+
if (!clientSideValidateProp(props.schema, state)) {
|
|
462
|
+
setForceValidation(true);
|
|
463
|
+
} else {
|
|
464
|
+
previewPropsOnChange(state, props);
|
|
465
|
+
onClose();
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
direction: "column",
|
|
469
|
+
gap: "xxlarge",
|
|
470
|
+
children: /*#__PURE__*/jsx(FormValueContentFromPreviewProps, {
|
|
471
|
+
...previewProps,
|
|
472
|
+
forceValidation: forceValidation
|
|
473
|
+
})
|
|
474
|
+
})
|
|
475
|
+
}), /*#__PURE__*/jsxs(ButtonGroup, {
|
|
476
|
+
children: [/*#__PURE__*/jsx(Button, {
|
|
477
|
+
onPress: onClose,
|
|
478
|
+
children: "\u53D6\u6D88"
|
|
479
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
480
|
+
form: formId,
|
|
481
|
+
prominence: "high",
|
|
482
|
+
type: "submit",
|
|
483
|
+
children: "\u786E\u5B9A"
|
|
484
|
+
})]
|
|
485
|
+
})]
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const BlockPopoverContext = /*#__PURE__*/createContext(null);
|
|
490
|
+
function useBlockPopoverContext() {
|
|
491
|
+
const context = useContext(BlockPopoverContext);
|
|
492
|
+
if (!context) {
|
|
493
|
+
throw new Error('useBlockPopoverContext must be used within a BlockPopoverTrigger');
|
|
494
|
+
}
|
|
495
|
+
return context;
|
|
496
|
+
}
|
|
497
|
+
const typeMatcher = nodeTypeMatcher('code', 'component-block', 'layout', 'link', 'heading');
|
|
498
|
+
const ActiveBlockPopoverContext = /*#__PURE__*/createContext(undefined);
|
|
499
|
+
function useActiveBlockPopover() {
|
|
500
|
+
return useContext(ActiveBlockPopoverContext);
|
|
501
|
+
}
|
|
502
|
+
function ActiveBlockPopoverProvider(props) {
|
|
503
|
+
const nodeWithPopover = Editor.above(props.editor, {
|
|
504
|
+
match: typeMatcher
|
|
505
|
+
});
|
|
506
|
+
return /*#__PURE__*/jsx(ActiveBlockPopoverContext.Provider, {
|
|
507
|
+
value: nodeWithPopover === null || nodeWithPopover === void 0 ? void 0 : nodeWithPopover[0],
|
|
508
|
+
children: props.children
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
const BlockPopoverTrigger = ({
|
|
512
|
+
children,
|
|
513
|
+
element
|
|
514
|
+
}) => {
|
|
515
|
+
const [trigger, popover] = children;
|
|
516
|
+
const activePopoverElement = useActiveBlockPopover();
|
|
517
|
+
const triggerRef = useRef(null);
|
|
518
|
+
const state = useOverlayTriggerState({
|
|
519
|
+
isOpen: activePopoverElement === element
|
|
520
|
+
});
|
|
521
|
+
const context = useMemo(() => ({
|
|
522
|
+
state,
|
|
523
|
+
triggerRef
|
|
524
|
+
}), [state, triggerRef]);
|
|
525
|
+
return /*#__PURE__*/jsxs(BlockPopoverContext.Provider, {
|
|
526
|
+
value: context,
|
|
527
|
+
children: [/*#__PURE__*/cloneElement(trigger, {
|
|
528
|
+
ref: triggerRef
|
|
529
|
+
}), popover]
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
function BlockPopover(props) {
|
|
533
|
+
const {
|
|
534
|
+
state
|
|
535
|
+
} = useBlockPopoverContext();
|
|
536
|
+
let wrapperRef = useRef(null);
|
|
537
|
+
return /*#__PURE__*/jsx(Overlay, {
|
|
538
|
+
isOpen: state.isOpen,
|
|
539
|
+
nodeRef: wrapperRef,
|
|
540
|
+
children: /*#__PURE__*/jsx(BlockPopoverWrapper, {
|
|
541
|
+
wrapperRef: wrapperRef,
|
|
542
|
+
...props
|
|
543
|
+
})
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
const BlockPopoverWrapper = ({
|
|
547
|
+
children,
|
|
548
|
+
placement: preferredPlacement = 'bottom'
|
|
549
|
+
}) => {
|
|
550
|
+
let popoverRef = useRef(null);
|
|
551
|
+
let {
|
|
552
|
+
state,
|
|
553
|
+
triggerRef
|
|
554
|
+
} = useBlockPopoverContext();
|
|
555
|
+
let {
|
|
556
|
+
placement,
|
|
557
|
+
popoverProps
|
|
558
|
+
} = useBlockPopover({
|
|
559
|
+
isNonModal: true,
|
|
560
|
+
isKeyboardDismissDisabled: false,
|
|
561
|
+
placement: preferredPlacement,
|
|
562
|
+
triggerRef,
|
|
563
|
+
popoverRef
|
|
564
|
+
}, state);
|
|
565
|
+
return /*#__PURE__*/jsx("div", {
|
|
566
|
+
ref: popoverRef,
|
|
567
|
+
...popoverProps,
|
|
568
|
+
"data-open": state.isOpen,
|
|
569
|
+
"data-placement": placement,
|
|
570
|
+
contentEditable: false,
|
|
571
|
+
className: css({
|
|
572
|
+
backgroundColor: tokenSchema.color.background.surface,
|
|
573
|
+
// TODO: component token?
|
|
574
|
+
borderRadius: tokenSchema.size.radius.medium,
|
|
575
|
+
// TODO: component token?
|
|
576
|
+
border: `${tokenSchema.size.border.regular} solid ${tokenSchema.color.border.emphasis}`,
|
|
577
|
+
boxSizing: 'content-box',
|
|
578
|
+
// resolves measurement/scroll issues related to border
|
|
579
|
+
// boxShadow: `0 0 0 ${tokenSchema.size.border.regular} ${tokenSchema.color.border.emphasis}`,
|
|
580
|
+
minHeight: tokenSchema.size.element.regular,
|
|
581
|
+
minWidth: tokenSchema.size.element.regular,
|
|
582
|
+
opacity: 0,
|
|
583
|
+
outline: 0,
|
|
584
|
+
pointerEvents: 'auto',
|
|
585
|
+
position: 'absolute',
|
|
586
|
+
// use filter:drop-shadow instead of box-shadow so the arrow is included
|
|
587
|
+
filter: `drop-shadow(0 1px 4px ${tokenSchema.color.shadow.regular})`,
|
|
588
|
+
// filter bug in safari: https://stackoverflow.com/questions/56478925/safari-drop-shadow-filter-remains-visible-even-with-hidden-element
|
|
589
|
+
willChange: 'filter',
|
|
590
|
+
userSelect: 'none',
|
|
591
|
+
// placement
|
|
592
|
+
'&[data-placement="top"]': {
|
|
593
|
+
marginBottom: tokenSchema.size.space.regular,
|
|
594
|
+
transform: `translateY(${tokenSchema.size.space.regular})`
|
|
595
|
+
},
|
|
596
|
+
'&[data-placement="bottom"]': {
|
|
597
|
+
marginTop: tokenSchema.size.space.regular,
|
|
598
|
+
transform: `translateY(calc(${tokenSchema.size.space.regular} * -1))`
|
|
599
|
+
},
|
|
600
|
+
'&[data-open="true"]': {
|
|
601
|
+
opacity: 1,
|
|
602
|
+
transform: `translateX(0) translateY(0)`,
|
|
603
|
+
// enter animation
|
|
604
|
+
transition: transition(['opacity', 'transform'], {
|
|
605
|
+
easing: 'easeOut'
|
|
606
|
+
})
|
|
607
|
+
}
|
|
608
|
+
}),
|
|
609
|
+
children: typeof children === 'function' ? children(state.close) : children
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Provides the behavior and accessibility implementation for a popover component.
|
|
615
|
+
* A popover is an overlay element positioned relative to a trigger.
|
|
616
|
+
*/
|
|
617
|
+
function useBlockPopover(props, state) {
|
|
618
|
+
var _triggerRef$current2;
|
|
619
|
+
let {
|
|
620
|
+
triggerRef,
|
|
621
|
+
popoverRef,
|
|
622
|
+
isNonModal,
|
|
623
|
+
isKeyboardDismissDisabled,
|
|
624
|
+
...otherProps
|
|
625
|
+
} = props;
|
|
626
|
+
let [isSticky, setSticky] = useState(false);
|
|
627
|
+
let {
|
|
628
|
+
overlayProps,
|
|
629
|
+
underlayProps
|
|
630
|
+
} = useOverlay({
|
|
631
|
+
isOpen: state.isOpen,
|
|
632
|
+
onClose: state.close,
|
|
633
|
+
shouldCloseOnBlur: true,
|
|
634
|
+
isDismissable: !isNonModal,
|
|
635
|
+
isKeyboardDismissDisabled: false
|
|
636
|
+
}, popoverRef);
|
|
637
|
+
|
|
638
|
+
// stick the popover to the bottom of the viewport instead of flipping
|
|
639
|
+
const containerPadding = 8;
|
|
640
|
+
useEffect(() => {
|
|
641
|
+
if (state.isOpen) {
|
|
642
|
+
const checkForStickiness = () => {
|
|
643
|
+
var _popoverRef$current, _triggerRef$current;
|
|
644
|
+
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
|
|
645
|
+
let popoverRect = (_popoverRef$current = popoverRef.current) === null || _popoverRef$current === void 0 ? void 0 : _popoverRef$current.getBoundingClientRect();
|
|
646
|
+
let triggerRect = (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 ? void 0 : _triggerRef$current.getBoundingClientRect();
|
|
647
|
+
if (popoverRect && triggerRect) {
|
|
648
|
+
setSticky(triggerRect.bottom + popoverRect.height + containerPadding * 2 > vh && triggerRect.top < vh);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
checkForStickiness();
|
|
652
|
+
window.addEventListener('scroll', checkForStickiness);
|
|
653
|
+
return () => {
|
|
654
|
+
checkForStickiness();
|
|
655
|
+
window.removeEventListener('scroll', checkForStickiness);
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
}, [popoverRef, triggerRef, state.isOpen]);
|
|
659
|
+
let {
|
|
660
|
+
overlayProps: positionProps,
|
|
661
|
+
arrowProps,
|
|
662
|
+
placement,
|
|
663
|
+
updatePosition
|
|
664
|
+
} = useOverlayPosition({
|
|
665
|
+
...otherProps,
|
|
666
|
+
containerPadding,
|
|
667
|
+
shouldFlip: false,
|
|
668
|
+
targetRef: triggerRef,
|
|
669
|
+
overlayRef: popoverRef,
|
|
670
|
+
isOpen: state.isOpen,
|
|
671
|
+
onClose: undefined
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
// force update position when the trigger changes
|
|
675
|
+
let previousBoundingRect = usePrevious((_triggerRef$current2 = triggerRef.current) === null || _triggerRef$current2 === void 0 ? void 0 : _triggerRef$current2.getBoundingClientRect());
|
|
676
|
+
useLayoutEffect(() => {
|
|
677
|
+
if (previousBoundingRect) {
|
|
678
|
+
var _triggerRef$current3;
|
|
679
|
+
const currentBoundingRect = (_triggerRef$current3 = triggerRef.current) === null || _triggerRef$current3 === void 0 ? void 0 : _triggerRef$current3.getBoundingClientRect();
|
|
680
|
+
if (currentBoundingRect) {
|
|
681
|
+
const hasChanged = previousBoundingRect.height !== currentBoundingRect.height || previousBoundingRect.width !== currentBoundingRect.width || previousBoundingRect.x !== currentBoundingRect.x || previousBoundingRect.y !== currentBoundingRect.y;
|
|
682
|
+
if (hasChanged) {
|
|
683
|
+
updatePosition();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}, [previousBoundingRect, triggerRef, updatePosition]);
|
|
688
|
+
|
|
689
|
+
// make sure popovers are below modal dialogs and their blanket
|
|
690
|
+
if (positionProps.style) {
|
|
691
|
+
positionProps.style.zIndex = 1;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// switching to position: fixed will undoubtedly bite me later, but this hack works for now
|
|
695
|
+
if (isSticky) {
|
|
696
|
+
positionProps.style = {
|
|
697
|
+
...positionProps.style,
|
|
698
|
+
// @ts-expect-error
|
|
699
|
+
maxHeight: null,
|
|
700
|
+
position: 'fixed',
|
|
701
|
+
// @ts-expect-error
|
|
702
|
+
top: null,
|
|
703
|
+
bottom: containerPadding
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
arrowProps,
|
|
708
|
+
placement,
|
|
709
|
+
popoverProps: mergeProps(overlayProps, positionProps),
|
|
710
|
+
underlayProps,
|
|
711
|
+
updatePosition
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function usePrevious(value) {
|
|
715
|
+
const ref = useRef(undefined);
|
|
716
|
+
useEffect(() => {
|
|
717
|
+
ref.current = value;
|
|
718
|
+
});
|
|
719
|
+
return ref.current;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function ChromelessComponentBlockElement(props) {
|
|
723
|
+
var _props$componentBlock;
|
|
724
|
+
const hasToolbar = props.componentBlock.toolbar !== null;
|
|
725
|
+
const ChromelessToolbar = (_props$componentBlock = props.componentBlock.toolbar) !== null && _props$componentBlock !== void 0 ? _props$componentBlock : DefaultToolbarWithoutChrome;
|
|
726
|
+
return /*#__PURE__*/jsx("div", {
|
|
727
|
+
...props.attributes,
|
|
728
|
+
className: blockElementSpacing,
|
|
729
|
+
children: hasToolbar ? /*#__PURE__*/jsxs(BlockPopoverTrigger, {
|
|
730
|
+
element: props.element,
|
|
731
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
732
|
+
children: props.renderedBlock
|
|
733
|
+
}), /*#__PURE__*/jsx(BlockPopover, {
|
|
734
|
+
children: /*#__PURE__*/jsx(ChromelessToolbar, {
|
|
735
|
+
onRemove: props.onRemove,
|
|
736
|
+
props: props.previewProps
|
|
737
|
+
})
|
|
738
|
+
})]
|
|
739
|
+
}) : /*#__PURE__*/jsx("div", {
|
|
740
|
+
children: props.renderedBlock
|
|
741
|
+
})
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
function DefaultToolbarWithoutChrome({
|
|
745
|
+
onRemove
|
|
746
|
+
}) {
|
|
747
|
+
return /*#__PURE__*/jsxs(TooltipTrigger, {
|
|
748
|
+
children: [/*#__PURE__*/jsx(ActionButton, {
|
|
749
|
+
onPress: onRemove,
|
|
750
|
+
margin: "regular",
|
|
751
|
+
children: /*#__PURE__*/jsx(Icon, {
|
|
752
|
+
src: trashIcon
|
|
753
|
+
})
|
|
754
|
+
}), /*#__PURE__*/jsx(Tooltip, {
|
|
755
|
+
tone: "critical",
|
|
756
|
+
children: "Remove"
|
|
757
|
+
})]
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const ComponentBlockContext = /*#__PURE__*/createContext({});
|
|
762
|
+
function ComponentInlineProp(props) {
|
|
763
|
+
return /*#__PURE__*/jsx("span", {
|
|
764
|
+
...props.attributes,
|
|
765
|
+
children: props.children
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
function insertComponentBlock(editor, componentBlocks, componentBlock) {
|
|
769
|
+
const node = getInitialValue(componentBlock, componentBlocks[componentBlock]);
|
|
770
|
+
insertNodesButReplaceIfSelectionIsAtEmptyParagraphOrHeading(editor, node);
|
|
771
|
+
const componentBlockEntry = Editor.above(editor, {
|
|
772
|
+
match: node => node.type === 'component-block'
|
|
773
|
+
});
|
|
774
|
+
if (componentBlockEntry) {
|
|
775
|
+
const start = Editor.start(editor, componentBlockEntry[1]);
|
|
776
|
+
Transforms.setSelection(editor, {
|
|
777
|
+
anchor: start,
|
|
778
|
+
focus: start
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function ComponentBlocksElement({
|
|
783
|
+
attributes,
|
|
784
|
+
children,
|
|
785
|
+
element: __elementToGetPath
|
|
786
|
+
}) {
|
|
787
|
+
const editor = useSlateStatic();
|
|
788
|
+
const [currentElement, setElement] = useElementWithSetNodes(editor, __elementToGetPath);
|
|
789
|
+
const blockComponents = useContext(ComponentBlockContext);
|
|
790
|
+
const componentBlock = blockComponents[currentElement.component];
|
|
791
|
+
const elementToGetPathRef = useRef({
|
|
792
|
+
__elementToGetPath,
|
|
793
|
+
currentElement
|
|
794
|
+
});
|
|
795
|
+
useEffect(() => {
|
|
796
|
+
elementToGetPathRef.current = {
|
|
797
|
+
__elementToGetPath,
|
|
798
|
+
currentElement
|
|
799
|
+
};
|
|
800
|
+
});
|
|
801
|
+
const onRemove = useEventCallback(() => {
|
|
802
|
+
const path = ReactEditor.findPath(editor, __elementToGetPath);
|
|
803
|
+
Transforms.removeNodes(editor, {
|
|
804
|
+
at: path
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
const onPropsChange = useCallback(cb => {
|
|
808
|
+
const prevProps = elementToGetPathRef.current.currentElement.props;
|
|
809
|
+
updateComponentBlockElementProps(editor, componentBlock, prevProps, cb(prevProps), ReactEditor.findPath(editor, elementToGetPathRef.current.__elementToGetPath), setElement);
|
|
810
|
+
}, [setElement, componentBlock, editor]);
|
|
811
|
+
const getToolbarPreviewProps = useMemo(() => {
|
|
812
|
+
if (!componentBlock) {
|
|
813
|
+
return () => {
|
|
814
|
+
throw new Error('expected component block to exist when called');
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
return createGetPreviewProps({
|
|
818
|
+
kind: 'object',
|
|
819
|
+
fields: componentBlock.schema
|
|
820
|
+
}, onPropsChange, () => undefined);
|
|
821
|
+
}, [componentBlock, onPropsChange]);
|
|
822
|
+
if (!componentBlock) {
|
|
823
|
+
return /*#__PURE__*/jsxs("div", {
|
|
824
|
+
className: css({
|
|
825
|
+
border: 'red 4px solid',
|
|
826
|
+
padding: tokenSchema.size.space.medium
|
|
827
|
+
}),
|
|
828
|
+
children: [/*#__PURE__*/jsx("pre", {
|
|
829
|
+
contentEditable: false,
|
|
830
|
+
className: css({
|
|
831
|
+
userSelect: 'none'
|
|
832
|
+
}),
|
|
833
|
+
children: `The block "${currentElement.component}" no longer exists.
|
|
834
|
+
|
|
835
|
+
Props:
|
|
836
|
+
|
|
837
|
+
${JSON.stringify(currentElement.props, null, 2)}
|
|
838
|
+
|
|
839
|
+
Content:`
|
|
840
|
+
}), children]
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
const toolbarPreviewProps = getToolbarPreviewProps(currentElement.props);
|
|
844
|
+
const renderedBlock = /*#__PURE__*/jsx(ComponentBlockRender, {
|
|
845
|
+
children: children,
|
|
846
|
+
componentBlock: componentBlock,
|
|
847
|
+
element: currentElement,
|
|
848
|
+
onChange: onPropsChange
|
|
849
|
+
});
|
|
850
|
+
return componentBlock.chromeless ? /*#__PURE__*/jsx(ChromelessComponentBlockElement, {
|
|
851
|
+
attributes: attributes,
|
|
852
|
+
renderedBlock: renderedBlock,
|
|
853
|
+
componentBlock: componentBlock,
|
|
854
|
+
onRemove: onRemove,
|
|
855
|
+
element: __elementToGetPath,
|
|
856
|
+
previewProps: toolbarPreviewProps
|
|
857
|
+
}) : /*#__PURE__*/jsx(ChromefulComponentBlockElement, {
|
|
858
|
+
attributes: attributes,
|
|
859
|
+
children: children,
|
|
860
|
+
componentBlock: componentBlock,
|
|
861
|
+
onRemove: onRemove,
|
|
862
|
+
previewProps: toolbarPreviewProps,
|
|
863
|
+
renderedBlock: renderedBlock,
|
|
864
|
+
elementProps: currentElement.props
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const DocumentFieldRelationshipsContext = /*#__PURE__*/createContext({});
|
|
869
|
+
function useDocumentFieldRelationships() {
|
|
870
|
+
return useContext(DocumentFieldRelationshipsContext);
|
|
871
|
+
}
|
|
872
|
+
const DocumentFieldRelationshipsProvider = DocumentFieldRelationshipsContext.Provider;
|
|
873
|
+
function RelationshipElement({
|
|
874
|
+
attributes,
|
|
875
|
+
children,
|
|
876
|
+
element
|
|
877
|
+
}) {
|
|
878
|
+
var _element$data$label;
|
|
879
|
+
const editor = useSlateStatic();
|
|
880
|
+
const relationships = useContext(DocumentFieldRelationshipsContext);
|
|
881
|
+
const relationship = relationships[element.relationship];
|
|
882
|
+
const list = useList(relationship.listKey);
|
|
883
|
+
return /*#__PURE__*/jsxs("span", {
|
|
884
|
+
...attributes,
|
|
885
|
+
className: css({
|
|
886
|
+
display: 'inline-flex',
|
|
887
|
+
alignItems: 'center'
|
|
888
|
+
}),
|
|
889
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
890
|
+
contentEditable: false,
|
|
891
|
+
className: css({
|
|
892
|
+
userSelect: 'none',
|
|
893
|
+
width: 200,
|
|
894
|
+
display: 'inline-block',
|
|
895
|
+
paddingLeft: 4,
|
|
896
|
+
paddingRight: 4,
|
|
897
|
+
flex: 1
|
|
898
|
+
}),
|
|
899
|
+
children: relationship ? /*#__PURE__*/jsx(ComboboxSingle, {
|
|
900
|
+
list: list,
|
|
901
|
+
labelField: list.labelField,
|
|
902
|
+
searchFields: list.initialSearchFields,
|
|
903
|
+
filter: list.initialFilter,
|
|
904
|
+
sort: list.initialSort,
|
|
905
|
+
state: {
|
|
906
|
+
kind: 'one',
|
|
907
|
+
value: element.data === null ? null : {
|
|
908
|
+
id: element.data.id,
|
|
909
|
+
label: (_element$data$label = element.data.label) !== null && _element$data$label !== void 0 ? _element$data$label : null,
|
|
910
|
+
built: undefined
|
|
911
|
+
},
|
|
912
|
+
onChange(newItem) {
|
|
913
|
+
const at = ReactEditor.findPath(editor, element);
|
|
914
|
+
if (newItem === null) {
|
|
915
|
+
Transforms.removeNodes(editor, {
|
|
916
|
+
at
|
|
917
|
+
});
|
|
918
|
+
} else {
|
|
919
|
+
Transforms.setNodes(editor, {
|
|
920
|
+
data: {
|
|
921
|
+
id: newItem.id,
|
|
922
|
+
label: newItem.label,
|
|
923
|
+
data: newItem.data
|
|
924
|
+
}
|
|
925
|
+
}, {
|
|
926
|
+
at
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}) : 'Invalid relationship'
|
|
932
|
+
}), /*#__PURE__*/jsx("span", {
|
|
933
|
+
className: css({
|
|
934
|
+
flex: 0
|
|
935
|
+
}),
|
|
936
|
+
children: children
|
|
937
|
+
})]
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
const ToolbarStateContext = /*#__PURE__*/React.createContext(null);
|
|
942
|
+
function useToolbarState() {
|
|
943
|
+
const toolbarState = useContext(ToolbarStateContext);
|
|
944
|
+
if (!toolbarState) {
|
|
945
|
+
throw new Error('ToolbarStateProvider must be used to use useToolbarState');
|
|
946
|
+
}
|
|
947
|
+
return toolbarState;
|
|
948
|
+
}
|
|
949
|
+
const ToolbarStateProvider = ({
|
|
950
|
+
children,
|
|
951
|
+
componentBlocks,
|
|
952
|
+
editorDocumentFeatures,
|
|
953
|
+
relationships
|
|
954
|
+
}) => {
|
|
955
|
+
const editor = useSlate();
|
|
956
|
+
return /*#__PURE__*/jsx(DocumentFieldRelationshipsProvider, {
|
|
957
|
+
value: relationships,
|
|
958
|
+
children: /*#__PURE__*/jsx(LayoutOptionsProvider, {
|
|
959
|
+
value: editorDocumentFeatures.layouts,
|
|
960
|
+
children: /*#__PURE__*/jsx(ComponentBlockContext.Provider, {
|
|
961
|
+
value: componentBlocks,
|
|
962
|
+
children: /*#__PURE__*/jsx(ToolbarStateContext.Provider, {
|
|
963
|
+
value: createToolbarState(editor, componentBlocks, editorDocumentFeatures),
|
|
964
|
+
children: children
|
|
965
|
+
})
|
|
966
|
+
})
|
|
967
|
+
})
|
|
968
|
+
});
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
export { ActiveBlockPopoverProvider as A, BlockPopoverTrigger as B, ComponentBlockContext as C, DocumentFieldRelationshipsContext as D, ForceValidationProvider as F, RelationshipElement as R, ToolbarStateProvider as T, useActiveBlockPopover as a, useEventCallback as b, BlockPopover as c, useToolbarState as d, ComponentInlineProp as e, focusWithPreviousSelection as f, ComponentBlocksElement as g, useDocumentFieldRelationships as h, insertComponentBlock as i, blockElementSpacing as j, useElementWithSetNodes as u };
|