@vonaffenfels/slate-editor 1.0.49 → 1.0.53

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/package.json CHANGED
@@ -1,20 +1,21 @@
1
1
  {
2
2
  "name": "@vonaffenfels/slate-editor",
3
- "version": "1.0.49",
3
+ "version": "1.0.53",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "prepublish": "yarn run build",
8
8
  "test": "echo \"Error: no test specified\" && exit 1",
9
9
  "build": "rm -rf dist && webpack --config webpack.config.build.js",
10
- "buildWatch": "rm -rf dist && webpack --config webpack.config.build.js --watch",
10
+ "buildWatch": "rm -rf dist && webpack --config webpack.config.watch.js --watch",
11
11
  "dev": "webpack serve --config webpack.config.dev.js --open"
12
12
  },
13
13
  "author": "",
14
14
  "license": "ISC",
15
15
  "peerDependencies": {
16
- "react": "17.0.2",
17
- "react-dom": "17.0.2"
16
+ "next": "^12.3.4",
17
+ "react": "^18",
18
+ "react-dom": "^18"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@babel/core": "^7.20.12",
@@ -43,13 +44,12 @@
43
44
  "graphql": "16.5.0",
44
45
  "html-webpack-plugin": "^5.3.1",
45
46
  "mini-css-extract-plugin": "^1.5.0",
46
- "next": "^12.3.4",
47
47
  "path-browserify": "^1.0.1",
48
48
  "postcss": "8.4.14",
49
49
  "postcss-import": "^15.1.0",
50
50
  "postcss-loader": "^5.2.0",
51
- "react": "18.2.0",
52
- "react-dom": "18.2.0",
51
+ "react": "^18.2.0",
52
+ "react-dom": "^18.2.0",
53
53
  "sass": "^1.32.11",
54
54
  "sass-loader": "^10.0.1",
55
55
  "shortid": "^2.2.16",
@@ -71,7 +71,7 @@
71
71
  "cssnano": "^5.0.1",
72
72
  "escape-html": "^1.0.3"
73
73
  },
74
- "gitHead": "b9487e3c2407021c202cb464a6073bb11ccb6bb4",
74
+ "gitHead": "2dc913432ea48a4eaf107ff9c5f15b572eeda4d6",
75
75
  "publishConfig": {
76
76
  "access": "public"
77
77
  }
package/scss/editor.scss CHANGED
@@ -11,6 +11,12 @@
11
11
  max-width: 100%;
12
12
  width: 100%;
13
13
 
14
+ .slate-editor-element-selected {
15
+ .storybook-element-component {
16
+ outline: 2px dashed #61a2e9;
17
+ }
18
+ }
19
+
14
20
  &.storybook-active {
15
21
  .slate-editor {
16
22
  display: none;
@@ -161,7 +167,7 @@
161
167
  }
162
168
 
163
169
  .arrow-list li::before {
164
- content: none !important;
170
+ content: none !important;
165
171
  }
166
172
 
167
173
  div[data-slate-editor="true"] {
@@ -303,21 +309,15 @@
303
309
  }
304
310
  }
305
311
 
306
- .layout-block-auto-fill {
307
- grid-template-columns: auto 1fr;
308
- }
309
-
310
- .layout-block-fill-auto {
311
- grid-template-columns: 1fr auto;
312
+ .layout-block-grid {
313
+ display: grid;
312
314
  }
313
315
 
314
- .layout-block-auto-fill-auto {
315
- grid-template-columns: auto 1fr auto;
316
+ .layout-block-flex {
317
+ display: flex;
316
318
  }
317
319
 
318
320
  .layout-block {
319
- display: grid;
320
-
321
321
  &.article-width {
322
322
  width: 44.44444444435556%;
323
323
  }
@@ -359,6 +359,15 @@
359
359
  display: inline-block;
360
360
  }
361
361
  }
362
+
363
+ &.layout-slot-grid-fill {
364
+ flex-grow: 1;
365
+ }
366
+
367
+ &.layout-slot-grid-auto {
368
+ flex-grow: 0;
369
+ width: auto;
370
+ }
362
371
  }
363
372
 
364
373
  @media only screen and (max-width: 360px) {
@@ -407,4 +416,26 @@
407
416
  .button.button--secondary:active {
408
417
  background-color: #0262C9 !important;
409
418
  color: #FFFFFF !important;
419
+ }
420
+
421
+ .resizable {
422
+ .resizable-left {
423
+ position: relative;
424
+ }
425
+
426
+ .resizable-right {
427
+ position: relative;
428
+ }
429
+
430
+ .resizable-x-handle {
431
+ cursor: ew-resize;
432
+ content: "";
433
+ position: absolute;
434
+ height: 100%;
435
+ width: 10px;
436
+ text-align: center;
437
+ top: 0;
438
+ left: -2px;
439
+ background-color: transparent;
440
+ }
410
441
  }
@@ -17,15 +17,15 @@
17
17
  * {
18
18
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
19
19
  }
20
-
20
+
21
21
  p, label, b, span {
22
22
  color: rgb(90, 101, 124);
23
23
  }
24
-
24
+
25
25
  label {
26
26
  margin: 0 0 2px 0 !important;
27
27
  }
28
-
28
+
29
29
  input[type="text"],
30
30
  input[type="number"],
31
31
  input[type="color"],
@@ -48,46 +48,47 @@
48
48
  height: 42px;
49
49
  max-height: 200px;
50
50
  }
51
-
51
+
52
52
  input[type="color"] {
53
53
  padding: 4px !important;
54
54
  }
55
-
55
+
56
56
  input[type="range"] {
57
57
  display: block;
58
58
  width: 100%;
59
59
  }
60
-
60
+
61
61
  input[type="radio"],
62
62
  input[type="checkbox"] {
63
63
  margin-right: 8px;
64
+ margin-left: 4px;
64
65
  }
65
66
 
66
67
  option[disabled] {
67
68
  color: rgba(0, 0, 0, 0.3)
68
69
  }
69
-
70
+
70
71
  /* button[data-test-id="cf-ui-button"] span {
71
72
  color: #036fe3 !important;
72
73
  }
73
-
74
+
74
75
  button[data-test-id="cf-ui-button"] svg {
75
76
  fill: #036fe3 !important;
76
77
  }
77
-
78
+
78
79
  button[data-test-id="cf-ui-button"]:hover span {
79
80
  color: #FFFFFF !important;
80
81
  }
81
-
82
+
82
83
  button[data-test-id="cf-ui-button"]:hover svg {
83
84
  fill: #FFFFFF !important;
84
85
  } */
85
-
86
+
86
87
  .inline-check-wrapper {
87
88
  display: inline-block;
88
89
  margin-right: 8px;
89
90
  }
90
-
91
+
91
92
  details {
92
93
  display: block;
93
94
  font-size: 0.875rem !important;
@@ -9,7 +9,7 @@
9
9
  z-index: 10;
10
10
  background-color: rgba(255, 255, 255, 0.7);
11
11
  color: black;
12
- font-size: 2em;
12
+ font-size: 1em;
13
13
  align-items: center;
14
14
  justify-content: center;
15
15
  content-visibility: auto;
@@ -131,4 +131,10 @@
131
131
  min-height: 100px;
132
132
  min-width: 100px;
133
133
  }
134
+ }
135
+
136
+ @container (min-width: 100px) {
137
+ .storybook-element-component-overlay {
138
+ font-size: 2em;
139
+ }
134
140
  }
@@ -19,6 +19,7 @@ import ErrorBoundary from "../src/Blocks/ErrorBoundary";
19
19
  import SidebarEditor from './SidebarEditor';
20
20
  import {Spinner} from '@contentful/forma-36-react-components';
21
21
  import {ObjectId} from "./ObjectId";
22
+ import {Resizable} from "./SidebarEditor/Resizable";
22
23
 
23
24
  export default function BlockEditor({
24
25
  onChange,
@@ -44,6 +45,15 @@ export default function BlockEditor({
44
45
  let node = ReactEditor.toSlateNode(editor, attributes.ref.current);
45
46
  let path = ReactEditor.findPath(editor, node);
46
47
 
48
+ document.querySelectorAll(".slate-editor-element-selected").forEach(el => {
49
+ el.classList.remove("slate-editor-element-selected");
50
+ });
51
+
52
+ if (attributes.ref.current) {
53
+ attributes.ref.current.classList.add("slate-editor-element-selected");
54
+ }
55
+
56
+
47
57
  setSelectedStorybookElement({
48
58
  ...element,
49
59
  editorAttributes: attributes,
@@ -169,10 +179,14 @@ export default function BlockEditor({
169
179
  block: newStorybookElement.block,
170
180
  isEmpty: false,
171
181
  isInline: selectedStorybookElement.isInline,
172
- attributes: newStorybookElement.attributes || {},
182
+ attributes: {...(newStorybookElement.attributes || {})},
173
183
  type: "storybook",
174
184
  };
175
185
 
186
+ if (!newNodeProps.attributes.teasermanagerSlotId) {
187
+ newNodeProps.attributes.teasermanagerSlotId = ObjectId();
188
+ }
189
+
176
190
  Transforms.setNodes(editor, newNodeProps, {at: selectedStorybookElement.path});
177
191
 
178
192
  onSlateChange(editor.children);
@@ -182,10 +196,6 @@ export default function BlockEditor({
182
196
  ...newNodeProps,
183
197
  };
184
198
 
185
- if (!mergedValue.attributes.teasermanagerSlotId) {
186
- mergedValue.attributes.teasermanagerSlotId = ObjectId();
187
- }
188
-
189
199
  setSelectedStorybookElement(mergedValue);
190
200
  };
191
201
 
@@ -262,63 +272,68 @@ export default function BlockEditor({
262
272
 
263
273
  return (
264
274
  <div className={classNames({"block-editor-wrapper h-full": true})}>
265
- <div className="slate-editor h-full">
266
- <Slate
267
- editor={editor}
268
- value={value}
269
- onChange={onSlateChange}
270
- >
271
- <div>
272
- <Toolbar
273
- hover={false}
274
- onSaveClick={onSaveClick}
275
- storybookStories={loadedStorybookStories}
276
- isLoadingStories={isLoadingStories}
277
- editor={editor}
278
- sdk={contentfulSdk}/>
279
- </div>
280
- <div className="relative h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
281
- {isLoading && (
282
- <div className="pointer-events-none fixed left-0 top-0 z-50" style={{padding: "61px 0 0 16px"}}>
283
- <Spinner color={window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? "white" : "default"} />
284
- </div>
285
- )}
286
- <ErrorBoundary
287
- name="editor"
288
- fallback={(
289
- <>
290
- Invalid Content! Call Support!
291
- </>
292
- )}>
293
- <Editable
294
- renderLeaf={renderLeaf}
295
- renderElement={renderElement}
296
- onKeyDown={(event) => {
297
- if (event.code === "Backspace") {
298
- // event.preventDefault();
299
- // return false;
300
- }
301
-
302
- if (!ListItemPlugin.onKeyDown(event, editor)) {
303
- SoftBreakPlugin.onKeyDown(event, editor);
304
- }
305
- }}
306
- />
307
- </ErrorBoundary>
308
- </div>
309
- </Slate>
310
- </div>
311
- {!!selectedStorybookElement && <SidebarEditor
312
- sdk={contentfulSdk}
313
- storybookElement={selectedStorybookElement}
314
- onChange={handleSidebarEditorChange}
315
- storybookStories={loadedStorybookStories}
316
- isLoading={isLoadingStories}
317
- onClose={handleSidebarClose}
318
- onDelete={handleSidebarDeleteClick}
319
- onMove={handleSidebarMoveClick}
320
- editor={editor}/>
321
- }
275
+ <Resizable
276
+ left={<div className="slate-editor h-full">
277
+ <Slate
278
+ editor={editor}
279
+ value={value}
280
+ onChange={onSlateChange}
281
+ >
282
+ <div>
283
+ <Toolbar
284
+ hover={false}
285
+ onSaveClick={onSaveClick}
286
+ storybookStories={loadedStorybookStories}
287
+ isLoadingStories={isLoadingStories}
288
+ editor={editor}
289
+ sdk={contentfulSdk}/>
290
+ </div>
291
+ <div className="relative h-full max-h-full overflow-scroll px-8 py-4" ref={scrollContainer}>
292
+ {isLoading && (
293
+ <div
294
+ className="pointer-events-none fixed left-0 top-0 z-50"
295
+ style={{padding: "61px 0 0 16px"}}>
296
+ <Spinner
297
+ color={window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? "white" : "default"}/>
298
+ </div>
299
+ )}
300
+ <ErrorBoundary
301
+ name="editor"
302
+ fallback={(
303
+ <>
304
+ Invalid Content! Call Support!
305
+ </>
306
+ )}>
307
+ <Editable
308
+ renderLeaf={renderLeaf}
309
+ renderElement={renderElement}
310
+ onKeyDown={(event) => {
311
+ if (event.code === "Backspace") {
312
+ // event.preventDefault();
313
+ // return false;
314
+ }
315
+
316
+ if (!ListItemPlugin.onKeyDown(event, editor)) {
317
+ SoftBreakPlugin.onKeyDown(event, editor);
318
+ }
319
+ }}
320
+ />
321
+ </ErrorBoundary>
322
+ </div>
323
+ </Slate>
324
+ </div>}
325
+ right={!!selectedStorybookElement && <SidebarEditor
326
+ sdk={contentfulSdk}
327
+ storybookElement={selectedStorybookElement}
328
+ onChange={handleSidebarEditorChange}
329
+ storybookStories={loadedStorybookStories}
330
+ isLoading={isLoadingStories}
331
+ onClose={handleSidebarClose}
332
+ onDelete={handleSidebarDeleteClick}
333
+ onMove={handleSidebarMoveClick}
334
+ editor={editor}/>
335
+ }
336
+ />
322
337
  </div>
323
338
  );
324
339
  }
@@ -190,7 +190,15 @@ export const LayoutBlock = ({
190
190
  }, {at: fromPath});
191
191
  };
192
192
 
193
- console.log({element});
193
+ let isGrid = true;
194
+
195
+ if (Array.isArray(element?.children)) {
196
+ element.children.forEach(child => {
197
+ if (child.type === "layout-slot" && ["grid-auto", "grid-fill"].includes(child.attributes.name)) {
198
+ isGrid = false;
199
+ }
200
+ });
201
+ }
194
202
 
195
203
  return <div className="options-wrapper" onClick={() => onElementClick(element)}>
196
204
  <div className="options-container">
@@ -239,7 +247,9 @@ export const LayoutBlock = ({
239
247
  <ToolMargin margin={element?.attributes?.margin} onChange={onMarginChange}/>
240
248
  </div>
241
249
  <div
242
- className={`layout-block layout-grid layout-grid-cols-${children.length} ${element?.attributes?.className || ""} ` + classNames({
250
+ className={`layout-block layout-grid layout-grid-cols-${children.length} ` + classNames({
251
+ "layout-block-flex": !isGrid,
252
+ "layout-block-grid": isGrid,
243
253
  [classNameArticle + " article-width"]: element?.attributes?.width === "article" || !element?.attributes?.width,
244
254
  [classNameSite + " site-width"]: element?.attributes?.width === "full",
245
255
  "block-editor-table-border-wrapper": element?.attributes?.tableBorder,
@@ -30,7 +30,7 @@ export const LayoutSlot = ({
30
30
 
31
31
  return <div
32
32
  className={classNames({
33
- ["layout-slot"]: true,
33
+ ["layout-slot layout-slot-" + element.attributes.name]: true,
34
34
  "editor-mt-4": element?.attributes?.margin?.top,
35
35
  "editor-mr-4": element?.attributes?.margin?.right,
36
36
  "editor-mb-4": element?.attributes?.margin?.bottom,
@@ -22,7 +22,7 @@ export const StorybookDisplay = (props) => {
22
22
 
23
23
  const interval = setInterval(() => {
24
24
  // innerText for regular elements, img for inline images and such :)
25
- if (elRef.current && !elRef.current.innerText && !elRef.current.querySelector("img, svg, iframe, video, audio, picture, frame")) {
25
+ if (elRef.current && !elRef.current.innerText && !elRef.current.querySelector("img, svg, iframe, video, audio, picture, frame, input")) {
26
26
  elRef.current.classList.add("storybook-element-display-empty");
27
27
  elRef.current.dataset.content = `Leeres Element :: ${element.block}`;
28
28
  } else if (elRef.current) {
@@ -126,19 +126,37 @@ export function Serializer({
126
126
 
127
127
  return <Wrapper><StorybookDisplay {...storyProps} /></Wrapper>;
128
128
  }
129
- case 'layout':
129
+ case 'layout': {
130
+ let isGrid = true;
131
+
132
+ if (Array.isArray(props.children)) {
133
+ props.children.forEach(child => {
134
+ if (child.type === "layout-slot" && ["grid-auto", "grid-fill"].includes(child.attributes.name)) {
135
+ isGrid = false;
136
+ }
137
+ });
138
+ }
139
+
130
140
  return <Wrapper>
131
141
  <div
132
142
  data-cols={props.children.length}
133
- className={classNames(props?.attributes?.className || "", {
134
- "block-editor-layout": true,
143
+ className={classNames("block-editor-layout", {
144
+ "block-editor-layout-grid": isGrid,
145
+ "block-editor-layout-flex": !isGrid,
146
+ "block-editor-table-border-wrapper": props?.attributes?.tableBorder,
147
+ "md:grid-cols-1": props.children.length === 1,
148
+ "md:grid-cols-2": props.children.length === 2,
149
+ "md:grid-cols-3": props.children.length === 3,
150
+ "md:grid-cols-4": props.children.length === 4,
151
+ "md:grid-cols-5": props.children.length === 5,
152
+ "grid-cols-1": props?.attributes?.mobileColumnSpan === 1,
153
+ "grid-cols-2": props?.attributes?.mobileColumnSpan === 2,
135
154
  "md:space-x-4": props.attributes?.spacing,
136
155
  "mt-16": props?.attributes?.margin?.top,
137
156
  "mr-16": props?.attributes?.margin?.right,
138
157
  "mb-16": props?.attributes?.margin?.bottom,
139
158
  "ml-16": props?.attributes?.margin?.left,
140
- "block-editor-table-border-wrapper": props?.attributes?.tableBorder,
141
- "mx-auto": props?.attributes?.justifyCenter,
159
+ "justify-center": props?.attributes?.justifyCenter,
142
160
  [typeProps.classNameSite + " site-width"]: !isInSlot && (props.attributes?.width === "site" || props.attributes?.width === "full"),
143
161
  [typeProps.classNameArticle + " article-width"]: !isInSlot && (props.attributes?.width === "article" || !props.attributes?.width),
144
162
  })}
@@ -146,6 +164,7 @@ export function Serializer({
146
164
  {props.children.map((v, i) => <Fragment key={"layout-pos-" + i}>{serializeNode(v, i, isInSlot)}</Fragment>)}
147
165
  </div>
148
166
  </Wrapper>;
167
+ }
149
168
  case 'layout-slot':
150
169
  return <Wrapper>
151
170
  <div
@@ -0,0 +1,78 @@
1
+ import {useEffect, useRef} from "react";
2
+
3
+ export const Resizable = ({left, right}) => {
4
+ const containerRef = useRef();
5
+ const leftRef = useRef();
6
+ const handleRef = useRef();
7
+ const rightRef = useRef();
8
+
9
+ const checkWidth = (width) => {
10
+ if (!containerRef.current || !width) {
11
+ return width;
12
+ }
13
+
14
+ if (width < 300) {
15
+ return 300;
16
+ } else if (containerRef.current.getBoundingClientRect().width - width < 300) {
17
+ return containerRef.current.getBoundingClientRect().width - 300
18
+ }
19
+
20
+ return width;
21
+ }
22
+
23
+ useEffect(() => {
24
+ if (rightRef.current) {
25
+ const savedWidth = localStorage.getItem("slate-editor-resizable-width");
26
+
27
+ if (checkWidth(savedWidth)) {
28
+ rightRef.current.style.width = savedWidth + 'px';
29
+ }
30
+
31
+ const onMouseDown = (e) => {
32
+ if (!rightRef.current) {
33
+ return;
34
+ }
35
+ rightRef.current.resizingStartWidth = rightRef.current.getBoundingClientRect().width;
36
+ rightRef.current.resizingStartMouseX = e.pageX;
37
+ rightRef.current.resizing = true;
38
+ };
39
+ const onMouseMove = (e) => {
40
+ if (!rightRef?.current?.resizing) {
41
+ return;
42
+ }
43
+
44
+ let newWidth = rightRef.current.resizingStartWidth - (e.pageX - rightRef.current.resizingStartMouseX)
45
+ newWidth = checkWidth(newWidth);
46
+
47
+ localStorage.setItem("slate-editor-resizable-width", newWidth);
48
+
49
+ rightRef.current.style.width = newWidth + 'px';
50
+ }
51
+ const onMouseUp = (e) => {
52
+ if (rightRef.current) {
53
+ rightRef.current.resizing = false;
54
+ }
55
+ }
56
+
57
+ rightRef.current.addEventListener("mousedown", onMouseDown);
58
+ document.addEventListener("mousemove", onMouseMove);
59
+ document.addEventListener("mouseup", onMouseUp);
60
+
61
+ return () => {
62
+ if (rightRef.current) {
63
+ rightRef.current.removeEventListener("mousedown", onMouseDown);
64
+ }
65
+ document.removeEventListener("mousemove", onMouseMove);
66
+ document.removeEventListener("mouseup", onMouseUp);
67
+ }
68
+ }
69
+ }, [right, left]);
70
+
71
+ return <div className="w-full flex resizable" ref={containerRef}>
72
+ <div ref={leftRef} className="resizable-left flex-grow">{left}</div>
73
+ {right && <div ref={rightRef} className="resizable-right">
74
+ <div ref={handleRef} className="resizable-x-handle"/>
75
+ {right}
76
+ </div>}
77
+ </div>
78
+ }
@@ -31,7 +31,7 @@ const SidebarEditor = ({
31
31
 
32
32
  const story = storybookStories?.find(v => storybookElement.block?.toLowerCase() === v.id?.toLowerCase());
33
33
 
34
- if (story) {
34
+ if (story?.argTypes) {
35
35
  Object.keys(story.argTypes).forEach(key => {
36
36
  const argType = story.argTypes[key];
37
37
 
@@ -225,7 +225,7 @@ const SidebarEditor = ({
225
225
  <hr className="my-4" style={{borderColor: "#cfd9e0"}}/>
226
226
  </div>
227
227
  )}
228
- {!!story && (
228
+ {!!story && !!fields.fields && (
229
229
  <>
230
230
  {Object.keys(fields.fields).map(key => {
231
231
  const field = fields.fields[key];
@@ -392,11 +392,11 @@ const BlockSelect = ({
392
392
  const result = {};
393
393
 
394
394
  array.forEach(item => {
395
- if (!item.id) {
395
+ if (!item?.id) {
396
396
  return;
397
397
  }
398
398
 
399
- let splitStoryContext = storyContext.split(",");
399
+ let splitStoryContext = String(storyContext || "").split(",");
400
400
  let isItemInContext = splitStoryContext.find(context => {
401
401
  return Array.isArray(item.storyContext) ? item.storyContext.includes(context) : context === item.storyContext;
402
402
  });
@@ -273,7 +273,6 @@ export const InsertGridButton = () => {
273
273
  </InsertLayoutButton>
274
274
  <InsertLayoutButton insert={{
275
275
  "type": "layout",
276
- "attributes": {"className": "layout-block-auto-fill"},
277
276
  "children": [
278
277
  {
279
278
  "type": "layout-slot",
@@ -305,7 +304,6 @@ export const InsertGridButton = () => {
305
304
  </InsertLayoutButton>
306
305
  <InsertLayoutButton insert={{
307
306
  "type": "layout",
308
- "attributes": {"className": "layout-block-fill-auto"},
309
307
  "children": [
310
308
  {
311
309
  "type": "layout-slot",
@@ -337,7 +335,6 @@ export const InsertGridButton = () => {
337
335
  </InsertLayoutButton>
338
336
  <InsertLayoutButton insert={{
339
337
  "type": "layout",
340
- "attributes": {"className": "layout-block-auto-fill-auto"},
341
338
  "children": [
342
339
  {
343
340
  "type": "layout-slot",