@saltcorn/builder 0.7.4 → 0.8.0-beta.1

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.
@@ -90,102 +90,99 @@ export /**
90
90
  * @category saltcorn-builder
91
91
  * @subcategory components
92
92
  */
93
- const Container = ({
94
- children,
95
- minHeight,
96
- height,
97
- width,
98
- minHeightUnit,
99
- heightUnit,
100
- widthUnit,
101
- vAlign,
102
- hAlign,
103
- bgFileId,
104
- imageSize,
105
- bgType,
106
- display,
107
- bgColor,
108
- setTextColor,
109
- textColor,
110
- customClass,
111
- customCSS,
112
- margin,
113
- padding,
114
- minScreenWidth,
115
- gradStartColor,
116
- gradEndColor,
117
- gradDirection,
118
- rotate,
119
- style,
120
- htmlElement,
121
- }) => {
122
- const {
123
- selected,
124
- connectors: { connect, drag },
125
- } = useNode((node) => ({ selected: node.events.selected }));
126
- //console.log("container style", style);
127
- return React.createElement(
93
+ const Container = ({
94
+ children,
95
+ minHeight,
96
+ height,
97
+ width,
98
+ minHeightUnit,
99
+ heightUnit,
100
+ widthUnit,
101
+ vAlign,
102
+ hAlign,
103
+ bgFileId,
104
+ imageSize,
105
+ bgType,
106
+ display,
107
+ bgColor,
108
+ setTextColor,
109
+ textColor,
110
+ customClass,
111
+ customCSS,
112
+ margin,
113
+ padding,
114
+ minScreenWidth,
115
+ gradStartColor,
116
+ gradEndColor,
117
+ gradDirection,
118
+ rotate,
119
+ style,
128
120
  htmlElement,
129
- {
130
- ref: (dom) => connect(drag(dom)),
131
- className: `${customClass || ""} canvas text-${hAlign} ${
132
- vAlign === "middle" ? "d-flex align-items-center" : ""
133
- } ${
134
- vAlign === "middle" && hAlign === "center" && "justify-content-center"
135
- } ${selected ? "selected-node" : ""}`,
136
- style: {
137
- ...parseStyles(customCSS || ""),
138
- ...reactifyStyles(style),
139
- display,
140
- //padding: padding.map((p) => p + "px").join(" "),
141
- //margin: margin.map((p) => p + "px").join(" "),
142
- minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
143
- ...(bgType === "Image" && bgFileId && +bgFileId
144
- ? {
121
+ }) => {
122
+ const {
123
+ selected,
124
+ connectors: { connect, drag },
125
+ } = useNode((node) => ({ selected: node.events.selected }));
126
+ //console.log("container style", style);
127
+ return React.createElement(
128
+ htmlElement,
129
+ {
130
+ ref: (dom) => connect(drag(dom)),
131
+ className: `${customClass || ""} canvas text-${hAlign} ${vAlign === "middle" ? "d-flex align-items-center" : ""
132
+ } ${vAlign === "middle" && hAlign === "center" && "justify-content-center"
133
+ } ${selected ? "selected-node" : ""}`,
134
+ style: {
135
+ ...parseStyles(customCSS || ""),
136
+ ...reactifyStyles(style),
137
+ display,
138
+ //padding: padding.map((p) => p + "px").join(" "),
139
+ //margin: margin.map((p) => p + "px").join(" "),
140
+ minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
141
+ ...(bgType === "Image" && bgFileId
142
+ ? {
145
143
  backgroundImage: `url('/files/serve/${bgFileId}')`,
146
144
  backgroundSize:
147
145
  imageSize === "repeat" ? undefined : imageSize || "contain",
148
146
  backgroundRepeat:
149
147
  imageSize === "repeat" ? imageSize : "no-repeat",
150
148
  }
151
- : {}),
152
- ...(bgType === "Color"
153
- ? {
149
+ : {}),
150
+ ...(bgType === "Color"
151
+ ? {
154
152
  backgroundColor: bgColor,
155
153
  }
156
- : {}),
157
- ...(bgType === "Gradient"
158
- ? {
159
- backgroundImage: `linear-gradient(${
160
- gradDirection || 0
161
- }deg, ${gradStartColor}, ${gradEndColor})`,
154
+ : {}),
155
+ ...(bgType === "Gradient"
156
+ ? {
157
+ backgroundImage: `linear-gradient(${gradDirection || 0
158
+ }deg, ${gradStartColor}, ${gradEndColor})`,
162
159
  }
163
- : {}),
164
- ...(setTextColor
165
- ? {
160
+ : {}),
161
+ ...(setTextColor
162
+ ? {
166
163
  color: textColor,
167
164
  }
168
- : {}),
169
- ...(typeof height !== "undefined"
170
- ? {
165
+ : {}),
166
+ ...(typeof height !== "undefined"
167
+ ? {
171
168
  height: `${height}${heightUnit || "px"}`,
172
169
  }
173
- : {}),
174
- ...(typeof width !== "undefined"
175
- ? {
170
+ : {}),
171
+ ...(typeof width !== "undefined"
172
+ ? {
176
173
  width: `${width}${widthUnit || "px"}`,
177
174
  }
178
- : {}),
179
- ...(rotate
180
- ? {
175
+ : {}),
176
+ ...(rotate
177
+ ? {
181
178
  transform: `rotate(${rotate}deg)`,
182
179
  }
183
- : {}),
180
+ : {}),
181
+ },
184
182
  },
185
- },
186
- children
187
- );
188
- };
183
+ children
184
+ );
185
+ };
189
186
 
190
187
  export /**
191
188
  * @returns {div}
@@ -194,710 +191,710 @@ export /**
194
191
  * @category saltcorn-builder
195
192
  * @subcategory components
196
193
  */
197
- const ContainerSettings = () => {
198
- const node = useNode((node) => ({
199
- minHeight: node.data.props.minHeight,
200
- height: node.data.props.height,
201
- width: node.data.props.width,
202
- minHeightUnit: node.data.props.minHeightUnit,
203
- heightUnit: node.data.props.heightUnit,
204
- widthUnit: node.data.props.widthUnit,
205
- bgType: node.data.props.bgType,
206
- bgColor: node.data.props.bgColor,
207
- isFormula: node.data.props.isFormula,
208
- bgFileId: node.data.props.bgFileId,
209
- imageSize: node.data.props.imageSize,
210
- htmlElement: node.data.props.htmlElement,
211
- vAlign: node.data.props.vAlign,
212
- hAlign: node.data.props.hAlign,
213
- fullPageWidth: node.data.props.fullPageWidth,
214
- showIfFormula: node.data.props.showIfFormula,
215
- setTextColor: node.data.props.setTextColor,
216
- showForRole: node.data.props.showForRole,
217
- textColor: node.data.props.textColor,
218
- customClass: node.data.props.customClass,
219
- customCSS: node.data.props.customCSS,
220
- minScreenWidth: node.data.props.minScreenWidth,
221
- maxScreenWidth: node.data.props.maxScreenWidth,
222
- show_for_owner: node.data.props.show_for_owner,
223
- margin: node.data.props.margin,
224
- padding: node.data.props.padding,
225
- url: node.data.props.url,
226
- hoverColor: node.data.props.hoverColor,
227
- gradStartColor: node.data.props.gradStartColor,
228
- gradEndColor: node.data.props.gradEndColor,
229
- gradDirection: node.data.props.gradDirection,
230
- overflow: node.data.props.overflow,
231
- rotate: node.data.props.rotate,
232
- display: node.data.props.display,
233
- style: node.data.props.style,
234
- imgResponsiveWidths: node.data.props.imgResponsiveWidths,
235
- }));
236
- const {
237
- actions: { setProp },
238
- bgFileId,
239
- imageSize,
240
- bgType,
241
- display,
242
- bgColor,
243
- setTextColor,
244
- textColor,
245
- showIfFormula,
246
- isFormula,
247
- showForRole,
248
- customClass,
249
- customCSS,
250
- minScreenWidth,
251
- maxScreenWidth,
252
- show_for_owner,
253
- margin,
254
- padding,
255
- url,
256
- hoverColor,
257
- gradStartColor,
258
- gradEndColor,
259
- gradDirection,
260
- fullPageWidth,
261
- overflow,
262
- htmlElement,
263
- imgResponsiveWidths,
264
- } = node;
265
- const options = useContext(optionsCtx);
266
- const { uploadedFiles } = useContext(previewCtx);
194
+ const ContainerSettings = () => {
195
+ const node = useNode((node) => ({
196
+ minHeight: node.data.props.minHeight,
197
+ height: node.data.props.height,
198
+ width: node.data.props.width,
199
+ minHeightUnit: node.data.props.minHeightUnit,
200
+ heightUnit: node.data.props.heightUnit,
201
+ widthUnit: node.data.props.widthUnit,
202
+ bgType: node.data.props.bgType,
203
+ bgColor: node.data.props.bgColor,
204
+ isFormula: node.data.props.isFormula,
205
+ bgFileId: node.data.props.bgFileId,
206
+ imageSize: node.data.props.imageSize,
207
+ htmlElement: node.data.props.htmlElement,
208
+ vAlign: node.data.props.vAlign,
209
+ hAlign: node.data.props.hAlign,
210
+ fullPageWidth: node.data.props.fullPageWidth,
211
+ showIfFormula: node.data.props.showIfFormula,
212
+ setTextColor: node.data.props.setTextColor,
213
+ showForRole: node.data.props.showForRole,
214
+ textColor: node.data.props.textColor,
215
+ customClass: node.data.props.customClass,
216
+ customCSS: node.data.props.customCSS,
217
+ minScreenWidth: node.data.props.minScreenWidth,
218
+ maxScreenWidth: node.data.props.maxScreenWidth,
219
+ show_for_owner: node.data.props.show_for_owner,
220
+ margin: node.data.props.margin,
221
+ padding: node.data.props.padding,
222
+ url: node.data.props.url,
223
+ hoverColor: node.data.props.hoverColor,
224
+ gradStartColor: node.data.props.gradStartColor,
225
+ gradEndColor: node.data.props.gradEndColor,
226
+ gradDirection: node.data.props.gradDirection,
227
+ overflow: node.data.props.overflow,
228
+ rotate: node.data.props.rotate,
229
+ display: node.data.props.display,
230
+ style: node.data.props.style,
231
+ imgResponsiveWidths: node.data.props.imgResponsiveWidths,
232
+ }));
233
+ const {
234
+ actions: { setProp },
235
+ bgFileId,
236
+ imageSize,
237
+ bgType,
238
+ display,
239
+ bgColor,
240
+ setTextColor,
241
+ textColor,
242
+ showIfFormula,
243
+ isFormula,
244
+ showForRole,
245
+ customClass,
246
+ customCSS,
247
+ minScreenWidth,
248
+ maxScreenWidth,
249
+ show_for_owner,
250
+ margin,
251
+ padding,
252
+ url,
253
+ hoverColor,
254
+ gradStartColor,
255
+ gradEndColor,
256
+ gradDirection,
257
+ fullPageWidth,
258
+ overflow,
259
+ htmlElement,
260
+ imgResponsiveWidths,
261
+ } = node;
262
+ const options = useContext(optionsCtx);
263
+ const { uploadedFiles } = useContext(previewCtx);
267
264
 
268
- const ownership = !!options.ownership;
265
+ const ownership = !!options.ownership;
269
266
 
270
- /**
271
- * @param {string} key
272
- * @returns {function}
273
- */
274
- const setAProp = setAPropGen(setProp);
275
- return (
276
- <Accordion>
277
- <div accordiontitle="Box" className="w-100">
278
- <BoxModelEditor setProp={setProp} node={node} />
279
- </div>
280
- <table className="w-100" accordiontitle="Display">
281
- <tbody>
282
- <SettingsRow
283
- field={{
284
- name: "display",
285
- label: "Display",
286
- type: "select",
287
- options: [
288
- "block",
289
- "inline",
290
- "inline-block",
291
- "none",
292
- "flex",
293
- "inline-flex",
294
- ],
295
- }}
296
- node={node}
297
- setProp={setProp}
298
- />
299
- <SettingsRow
300
- field={{
301
- name: "htmlElement",
302
- label: "HTML element",
303
- type: "select",
304
- options: [
305
- "div",
306
- "span",
307
- "article",
308
- "section",
309
- "header",
310
- "nav",
311
- "main",
312
- "aside",
313
- "footer",
314
- ],
315
- }}
316
- node={node}
317
- setProp={setProp}
318
- />
319
- <SettingsRow
320
- field={{
321
- name: "overflow",
322
- label: "Overflow",
323
- type: "btn_select",
324
- options: [
325
- { value: "visible", title: "Visible", label: <EyeFill /> },
326
- { value: "hidden", title: "Hidden", label: <EyeSlashFill /> },
327
- {
328
- value: "scroll",
329
- title: "Scroll",
330
- label: <FontAwesomeIcon icon={faScroll} />,
331
- },
332
- {
333
- value: "auto",
334
- title: "Auto",
335
- label: <FontAwesomeIcon icon={faRobot} />,
336
- },
337
- ],
338
- }}
339
- node={node}
340
- setProp={setProp}
341
- />
342
- <tr>
343
- <td colSpan="2">
344
- <div className="form-check">
345
- <input
346
- className="form-check-input"
347
- name="block"
348
- type="checkbox"
349
- checked={fullPageWidth}
350
- onChange={setAProp("fullPageWidth", { checked: true })}
351
- />
352
- <label className="form-check-label">
353
- Expand to full page width
354
- </label>
355
- </div>
356
- </td>
357
- </tr>
358
- </tbody>
359
- </table>
360
- <table className="w-100" accordiontitle="Contents">
361
- <tbody>
362
- <SettingsRow
363
- field={{
364
- name: "rotate",
365
- label: "Rotate °",
366
- type: "Integer",
367
- }}
368
- node={node}
369
- setProp={setProp}
370
- />
371
- <SettingsSectionHeaderRow title="Align" />
372
- <SettingsRow
373
- field={{
374
- name: "vAlign",
375
- label: "Vertical",
376
- type: "btn_select",
377
- options: [
378
- { value: "top", title: "All", label: <AlignTop /> },
379
- { value: "middle", title: "All", label: <AlignMiddle /> },
380
- { value: "bottom", title: "All", label: <AlignBottom /> },
381
- ],
382
- }}
383
- node={node}
384
- setProp={setProp}
385
- />
386
- <SettingsRow
387
- field={{
388
- name: "hAlign",
389
- label: "Horizontal",
390
- type: "btn_select",
391
- options: [
392
- { value: "left", title: "Left", label: <AlignStart /> },
393
- { value: "center", title: "Center", label: <AlignCenter /> },
394
- { value: "right", title: "Right", label: <AlignEnd /> },
395
- ],
396
- }}
397
- node={node}
398
- setProp={setProp}
399
- />
400
- <SettingsSectionHeaderRow title="Background" />
401
- <SettingsRow
402
- field={{
403
- name: "bgType",
404
- label: "Type",
405
- type: "btn_select",
406
- options: [
407
- { value: "None", label: <SlashCircle /> },
408
- { value: "Image", label: <Image /> },
409
- { value: "Color", label: <Palette /> },
410
- { value: "Gradient", label: <Rainbow /> },
411
- ],
412
- }}
413
- node={node}
414
- setProp={setProp}
415
- onChange={(v) =>
416
- setProp((prop) => {
417
- prop.bgFileId =
418
- prop.bgFileId ||
419
- (options.images.length + uploadedFiles.length > 0 &&
420
- options.images[0].id);
421
- })
422
- }
423
- />
424
- {bgType === "Gradient" && (
425
- <Fragment>
267
+ /**
268
+ * @param {string} key
269
+ * @returns {function}
270
+ */
271
+ const setAProp = setAPropGen(setProp);
272
+ return (
273
+ <Accordion>
274
+ <div accordiontitle="Box" className="w-100">
275
+ <BoxModelEditor setProp={setProp} node={node} />
276
+ </div>
277
+ <table className="w-100" accordiontitle="Display">
278
+ <tbody>
279
+ <SettingsRow
280
+ field={{
281
+ name: "display",
282
+ label: "Display",
283
+ type: "select",
284
+ options: [
285
+ "block",
286
+ "inline",
287
+ "inline-block",
288
+ "none",
289
+ "flex",
290
+ "inline-flex",
291
+ ],
292
+ }}
293
+ node={node}
294
+ setProp={setProp}
295
+ />
296
+ <SettingsRow
297
+ field={{
298
+ name: "htmlElement",
299
+ label: "HTML element",
300
+ type: "select",
301
+ options: [
302
+ "div",
303
+ "span",
304
+ "article",
305
+ "section",
306
+ "header",
307
+ "nav",
308
+ "main",
309
+ "aside",
310
+ "footer",
311
+ ],
312
+ }}
313
+ node={node}
314
+ setProp={setProp}
315
+ />
316
+ <SettingsRow
317
+ field={{
318
+ name: "overflow",
319
+ label: "Overflow",
320
+ type: "btn_select",
321
+ options: [
322
+ { value: "visible", title: "Visible", label: <EyeFill /> },
323
+ { value: "hidden", title: "Hidden", label: <EyeSlashFill /> },
324
+ {
325
+ value: "scroll",
326
+ title: "Scroll",
327
+ label: <FontAwesomeIcon icon={faScroll} />,
328
+ },
329
+ {
330
+ value: "auto",
331
+ title: "Auto",
332
+ label: <FontAwesomeIcon icon={faRobot} />,
333
+ },
334
+ ],
335
+ }}
336
+ node={node}
337
+ setProp={setProp}
338
+ />
339
+ <tr>
340
+ <td colSpan="2">
341
+ <div className="form-check">
342
+ <input
343
+ className="form-check-input"
344
+ name="block"
345
+ type="checkbox"
346
+ checked={fullPageWidth}
347
+ onChange={setAProp("fullPageWidth", { checked: true })}
348
+ />
349
+ <label className="form-check-label">
350
+ Expand to full page width
351
+ </label>
352
+ </div>
353
+ </td>
354
+ </tr>
355
+ </tbody>
356
+ </table>
357
+ <table className="w-100" accordiontitle="Contents">
358
+ <tbody>
359
+ <SettingsRow
360
+ field={{
361
+ name: "rotate",
362
+ label: "Rotate °",
363
+ type: "Integer",
364
+ }}
365
+ node={node}
366
+ setProp={setProp}
367
+ />
368
+ <SettingsSectionHeaderRow title="Align" />
369
+ <SettingsRow
370
+ field={{
371
+ name: "vAlign",
372
+ label: "Vertical",
373
+ type: "btn_select",
374
+ options: [
375
+ { value: "top", title: "All", label: <AlignTop /> },
376
+ { value: "middle", title: "All", label: <AlignMiddle /> },
377
+ { value: "bottom", title: "All", label: <AlignBottom /> },
378
+ ],
379
+ }}
380
+ node={node}
381
+ setProp={setProp}
382
+ />
383
+ <SettingsRow
384
+ field={{
385
+ name: "hAlign",
386
+ label: "Horizontal",
387
+ type: "btn_select",
388
+ options: [
389
+ { value: "left", title: "Left", label: <AlignStart /> },
390
+ { value: "center", title: "Center", label: <AlignCenter /> },
391
+ { value: "right", title: "Right", label: <AlignEnd /> },
392
+ ],
393
+ }}
394
+ node={node}
395
+ setProp={setProp}
396
+ />
397
+ <SettingsSectionHeaderRow title="Background" />
398
+ <SettingsRow
399
+ field={{
400
+ name: "bgType",
401
+ label: "Type",
402
+ type: "btn_select",
403
+ options: [
404
+ { value: "None", label: <SlashCircle /> },
405
+ { value: "Image", label: <Image /> },
406
+ { value: "Color", label: <Palette /> },
407
+ { value: "Gradient", label: <Rainbow /> },
408
+ ],
409
+ }}
410
+ node={node}
411
+ setProp={setProp}
412
+ onChange={(v) =>
413
+ setProp((prop) => {
414
+ prop.bgFileId =
415
+ prop.bgFileId ||
416
+ (options.images.length + uploadedFiles.length > 0 &&
417
+ options.images[0].location);
418
+ })
419
+ }
420
+ />
421
+ {bgType === "Gradient" && (
422
+ <Fragment>
423
+ <tr>
424
+ <td>Start</td>
425
+ <td>
426
+ <OrFormula
427
+ nodekey="gradStartColor"
428
+ {...{ setProp, isFormula, node }}
429
+ >
430
+ <input
431
+ type="color"
432
+ value={gradStartColor}
433
+ className="form-control-sm w-50"
434
+ onChange={setAProp("gradStartColor")}
435
+ />
436
+ </OrFormula>
437
+ </td>
438
+ </tr>
439
+ <tr>
440
+ <td>End</td>
441
+ <td>
442
+ <OrFormula
443
+ nodekey="gradEndColor"
444
+ {...{ setProp, isFormula, node }}
445
+ >
446
+ <input
447
+ type="color"
448
+ value={gradEndColor}
449
+ className="form-control-sm w-50"
450
+ onChange={setAProp("gradEndColor")}
451
+ />
452
+ </OrFormula>
453
+ </td>
454
+ </tr>
455
+ <tr>
456
+ <td>Direction (&deg;)</td>
457
+ <td>
458
+ <OrFormula
459
+ nodekey="gradDirection"
460
+ {...{ setProp, isFormula, node }}
461
+ >
462
+ <input
463
+ type="number"
464
+ min="0"
465
+ max="360"
466
+ value={gradDirection}
467
+ className="form-control-sm w-50"
468
+ onChange={setAProp("gradDirection")}
469
+ />
470
+ </OrFormula>
471
+ </td>
472
+ </tr>
473
+ </Fragment>
474
+ )}
475
+ {bgType === "Image" && (
476
+ <Fragment>
477
+ <tr>
478
+ <td>
479
+ <label>File</label>
480
+ </td>
481
+ <td>
482
+ <select
483
+ value={bgFileId}
484
+ className="form-control-sm w-100 form-select"
485
+ onChange={setAProp("bgFileId")}
486
+ >
487
+ {options.images.map((f, ix) => (
488
+ <option key={ix} value={f.location}>
489
+ {f.filename}
490
+ </option>
491
+ ))}
492
+ {(uploadedFiles || []).map((uf, ix) => (
493
+ <option key={ix} value={uf.location}>
494
+ {uf.filename}
495
+ </option>
496
+ ))}{" "}
497
+ </select>
498
+ </td>
499
+ </tr>
500
+ <tr>
501
+ <td>
502
+ <label>Size</label>
503
+ </td>
504
+
505
+ <td>
506
+ <select
507
+ value={imageSize}
508
+ className="form-control-sm form-select"
509
+ onChange={setAProp("imageSize")}
510
+ >
511
+ <option>contain</option>
512
+ <option>cover</option>
513
+ <option>repeat</option>
514
+ </select>
515
+ </td>
516
+ </tr>
517
+ {imageSize !== "repeat" && (
518
+ <tr>
519
+ <td>
520
+ <label>Responsive widths</label>
521
+ </td>
522
+
523
+ <td>
524
+ <input
525
+ type="text"
526
+ value={imgResponsiveWidths}
527
+ className="form-control"
528
+ onChange={setAProp("imgResponsiveWidths")}
529
+ />
530
+ <small>
531
+ <i>
532
+ List of widths to serve resized images, e.g. 300, 400,
533
+ 600
534
+ </i>
535
+ </small>
536
+ </td>
537
+ </tr>
538
+ )}
539
+ </Fragment>
540
+ )}
541
+ {bgType === "Color" && (
426
542
  <tr>
427
- <td>Start</td>
543
+ <td>Color</td>
428
544
  <td>
429
- <OrFormula
430
- nodekey="gradStartColor"
431
- {...{ setProp, isFormula, node }}
432
- >
545
+ <OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
433
546
  <input
434
547
  type="color"
435
- value={gradStartColor}
548
+ value={bgColor}
436
549
  className="form-control-sm w-50"
437
- onChange={setAProp("gradStartColor")}
550
+ onChange={setAProp("bgColor")}
438
551
  />
439
552
  </OrFormula>
440
553
  </td>
441
554
  </tr>
555
+ )}
556
+ <SettingsSectionHeaderRow title="Typography" />
557
+ <SettingsRow
558
+ field={{
559
+ name: "font-family",
560
+ label: "Font family",
561
+ type: "Font",
562
+ }}
563
+ node={node}
564
+ setProp={setProp}
565
+ isStyle={true}
566
+ />
567
+ <SettingsRow
568
+ field={{
569
+ name: "font-size",
570
+ label: "Font size",
571
+ type: "DimUnits",
572
+ }}
573
+ node={node}
574
+ setProp={setProp}
575
+ isStyle={true}
576
+ />
577
+ <SettingsRow
578
+ field={{
579
+ name: "font-weight",
580
+ label: "Weight",
581
+ type: "Integer",
582
+ min: 100,
583
+ max: 900,
584
+ step: 100,
585
+ }}
586
+ node={node}
587
+ setProp={setProp}
588
+ isStyle={true}
589
+ />
590
+ <SettingsRow
591
+ field={{
592
+ name: "line-height",
593
+ label: "Line height",
594
+ type: "DimUnits",
595
+ }}
596
+ node={node}
597
+ setProp={setProp}
598
+ isStyle={true}
599
+ />
600
+ <tr>
601
+ <td colSpan="2">
602
+ <label>
603
+ Set text color
604
+ <input
605
+ name="setTextColor"
606
+ type="checkbox"
607
+ checked={setTextColor}
608
+ onChange={setAProp("setTextColor", { checked: true })}
609
+ />
610
+ </label>
611
+ </td>
612
+ </tr>
613
+ {setTextColor && (
442
614
  <tr>
443
- <td>End</td>
444
615
  <td>
445
- <OrFormula
446
- nodekey="gradEndColor"
447
- {...{ setProp, isFormula, node }}
448
- >
449
- <input
450
- type="color"
451
- value={gradEndColor}
452
- className="form-control-sm w-50"
453
- onChange={setAProp("gradEndColor")}
454
- />
455
- </OrFormula>
616
+ <label>Text</label>
456
617
  </td>
457
- </tr>
458
- <tr>
459
- <td>Direction (&deg;)</td>
460
618
  <td>
461
- <OrFormula
462
- nodekey="gradDirection"
463
- {...{ setProp, isFormula, node }}
464
- >
465
- <input
466
- type="number"
467
- min="0"
468
- max="360"
469
- value={gradDirection}
470
- className="form-control-sm w-50"
471
- onChange={setAProp("gradDirection")}
472
- />
473
- </OrFormula>
619
+ <input
620
+ type="color"
621
+ value={textColor}
622
+ className="form-control-sm"
623
+ onChange={setAProp("textColor")}
624
+ />
474
625
  </td>
475
626
  </tr>
476
- </Fragment>
477
- )}
478
- {bgType === "Image" && (
479
- <Fragment>
627
+ )}
628
+ </tbody>
629
+ </table>
630
+ <table className="w-100" accordiontitle="Flex properties">
631
+ <tbody>
632
+ <SettingsSectionHeaderRow title="Flex item" />
633
+ <SettingsRow
634
+ field={{ name: "flex-grow", label: "Grow", type: "Float" }}
635
+ node={node}
636
+ setProp={setProp}
637
+ isStyle={true}
638
+ />
639
+ <SettingsRow
640
+ field={{ name: "flex-shrink", label: "Shrink", type: "Float" }}
641
+ node={node}
642
+ setProp={setProp}
643
+ isStyle={true}
644
+ />
645
+ {display && display.includes("flex") && (
646
+ <Fragment>
647
+ <SettingsSectionHeaderRow title="Flex container" />
648
+ <SettingsRow
649
+ field={{
650
+ name: "flex-direction",
651
+ label: "Direction",
652
+ type: "select",
653
+ options: ["row", "row-reverse", "column", "column-reverse"],
654
+ }}
655
+ node={node}
656
+ setProp={setProp}
657
+ isStyle={true}
658
+ />
659
+ <SettingsRow
660
+ field={{
661
+ name: "flex-wrap",
662
+ label: "Wrap",
663
+ type: "select",
664
+ options: ["nowrap", "wrap", "wrap-reverse"],
665
+ }}
666
+ node={node}
667
+ setProp={setProp}
668
+ isStyle={true}
669
+ />
670
+ <SettingsRow
671
+ field={{
672
+ name: "justify-content",
673
+ label: "Justify content",
674
+ type: "select",
675
+ options: [
676
+ "flex-start",
677
+ "flex-end",
678
+ "center",
679
+ "space-between",
680
+ "space-around",
681
+ "space-evenly",
682
+ "start",
683
+ "end",
684
+ "left",
685
+ "right",
686
+ ],
687
+ }}
688
+ node={node}
689
+ setProp={setProp}
690
+ isStyle={true}
691
+ />
692
+ <SettingsRow
693
+ field={{
694
+ name: "align-items",
695
+ label: "Align items",
696
+ type: "select",
697
+ options: [
698
+ "stretch",
699
+ "flex-start",
700
+ "flex-end",
701
+ "center",
702
+ "baseline",
703
+ "first baseline",
704
+ "last baseline",
705
+ "start",
706
+ "end",
707
+ "self-start",
708
+ "self-end",
709
+ ],
710
+ }}
711
+ node={node}
712
+ setProp={setProp}
713
+ isStyle={true}
714
+ />
715
+ <SettingsRow
716
+ field={{
717
+ name: "align-content",
718
+ label: "Align content",
719
+ type: "select",
720
+ options: [
721
+ "flex-start",
722
+ "flex-end",
723
+ "center",
724
+ "space-between",
725
+ "space-around",
726
+ "space-evenly",
727
+ "stretch",
728
+ "start",
729
+ "end",
730
+ "baseline",
731
+ "first baseline",
732
+ "last baseline",
733
+ ],
734
+ }}
735
+ node={node}
736
+ setProp={setProp}
737
+ isStyle={true}
738
+ />
739
+ </Fragment>
740
+ )}
741
+ </tbody>
742
+ </table>
743
+ <table className="w-100" accordiontitle="Show if...">
744
+ <tbody>
745
+ {["show", "edit"].includes(options.mode) && (
746
+ <SettingsSectionHeaderRow title="Formula - show if true" />
747
+ )}
748
+ {["show", "edit"].includes(options.mode) && (
480
749
  <tr>
481
750
  <td>
482
- <label>File</label>
483
- </td>
484
- <td>
485
- <select
486
- value={bgFileId}
487
- className="form-control-sm w-100 form-select"
488
- onChange={setAProp("bgFileId")}
489
- >
490
- {options.images.map((f, ix) => (
491
- <option key={ix} value={f.id}>
492
- {f.filename}
493
- </option>
494
- ))}
495
- {(uploadedFiles || []).map((uf, ix) => (
496
- <option key={ix} value={uf.id}>
497
- {uf.filename}
498
- </option>
499
- ))}{" "}
500
- </select>
751
+ <input
752
+ type="text"
753
+ className="form-control text-to-display"
754
+ value={showIfFormula}
755
+ onChange={setAProp("showIfFormula")}
756
+ />
757
+ <div style={{ marginTop: "-5px" }}>
758
+ <small className="text-muted font-monospace">FORMULA <FormulaTooltip /></small>
759
+ </div>
501
760
  </td>
502
761
  </tr>
503
- <tr>
504
- <td>
505
- <label>Size</label>
506
- </td>
507
-
508
- <td>
509
- <select
510
- value={imageSize}
511
- className="form-control-sm form-select"
512
- onChange={setAProp("imageSize")}
513
- >
514
- <option>contain</option>
515
- <option>cover</option>
516
- <option>repeat</option>
517
- </select>
762
+ )}
763
+ <SettingsSectionHeaderRow title="Role" />
764
+ {options.roles.map(({ role, id }) => (
765
+ <tr key={id}>
766
+ <td colSpan="2">
767
+ <div className="form-check">
768
+ <input
769
+ className="form-check-input"
770
+ name="block"
771
+ type="checkbox"
772
+ checked={
773
+ typeof showForRole[id] === "undefined"
774
+ ? true
775
+ : showForRole[id]
776
+ }
777
+ onChange={(e) => {
778
+ if (!e?.target) return;
779
+ const checked = e.target.checked;
780
+ setProp((prop) => {
781
+ if (!prop.showForRole || prop.showForRole.length === 0)
782
+ options.roles.forEach(
783
+ (r) => (prop.showForRole[r.id] = true)
784
+ );
785
+ prop.showForRole[id] = checked;
786
+ });
787
+ }}
788
+ />
789
+ <label className="form-check-label">{role}</label>
790
+ </div>
518
791
  </td>
519
792
  </tr>
520
- {imageSize !== "repeat" && (
521
- <tr>
522
- <td>
523
- <label>Responsive widths</label>
524
- </td>
525
-
526
- <td>
793
+ ))}
794
+ {ownership ? (
795
+ <tr>
796
+ <td colSpan="2">
797
+ <div className="form-check">
527
798
  <input
528
- type="text"
529
- value={imgResponsiveWidths}
530
- className="form-control"
531
- onChange={setAProp("imgResponsiveWidths")}
799
+ className="form-check-input"
800
+ name="block"
801
+ type="checkbox"
802
+ checked={show_for_owner}
803
+ onChange={setAProp("show_for_owner", { checked: true })}
532
804
  />
533
- <small>
534
- <i>
535
- List of widths to serve resized images, e.g. 300, 400,
536
- 600
537
- </i>
538
- </small>
539
- </td>
540
- </tr>
541
- )}
542
- </Fragment>
543
- )}
544
- {bgType === "Color" && (
545
- <tr>
546
- <td>Color</td>
547
- <td>
548
- <OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
549
- <input
550
- type="color"
551
- value={bgColor}
552
- className="form-control-sm w-50"
553
- onChange={setAProp("bgColor")}
554
- />
555
- </OrFormula>
556
- </td>
557
- </tr>
558
- )}
559
- <SettingsSectionHeaderRow title="Typography" />
560
- <SettingsRow
561
- field={{
562
- name: "font-family",
563
- label: "Font family",
564
- type: "Font",
565
- }}
566
- node={node}
567
- setProp={setProp}
568
- isStyle={true}
569
- />
570
- <SettingsRow
571
- field={{
572
- name: "font-size",
573
- label: "Font size",
574
- type: "DimUnits",
575
- }}
576
- node={node}
577
- setProp={setProp}
578
- isStyle={true}
579
- />
580
- <SettingsRow
581
- field={{
582
- name: "font-weight",
583
- label: "Weight",
584
- type: "Integer",
585
- min: 100,
586
- max: 900,
587
- step: 100,
588
- }}
589
- node={node}
590
- setProp={setProp}
591
- isStyle={true}
592
- />
593
- <SettingsRow
594
- field={{
595
- name: "line-height",
596
- label: "Line height",
597
- type: "DimUnits",
598
- }}
599
- node={node}
600
- setProp={setProp}
601
- isStyle={true}
602
- />
603
- <tr>
604
- <td colSpan="2">
605
- <label>
606
- Set text color
607
- <input
608
- name="setTextColor"
609
- type="checkbox"
610
- checked={setTextColor}
611
- onChange={setAProp("setTextColor", { checked: true })}
612
- />
613
- </label>
614
- </td>
615
- </tr>
616
- {setTextColor && (
805
+ <label className="form-check-label">Owner</label>
806
+ </div>
807
+ </td>
808
+ </tr>
809
+ ) : null}
617
810
  <tr>
618
811
  <td>
619
- <label>Text</label>
812
+ <label>Min screen width</label>
620
813
  </td>
621
814
  <td>
622
- <input
623
- type="color"
624
- value={textColor}
625
- className="form-control-sm"
626
- onChange={setAProp("textColor")}
627
- />
815
+ <select
816
+ value={minScreenWidth}
817
+ className="form-control form-select"
818
+ onChange={setAProp("minScreenWidth")}
819
+ >
820
+ <option value="">all</option>
821
+ <option value="sm">small</option>
822
+ <option value="md">medium</option>
823
+ <option value="lg">large</option>
824
+ <option value="xl">x-large</option>
825
+ </select>
628
826
  </td>
629
827
  </tr>
630
- )}
631
- </tbody>
632
- </table>
633
- <table className="w-100" accordiontitle="Flex properties">
634
- <tbody>
635
- <SettingsSectionHeaderRow title="Flex item" />
636
- <SettingsRow
637
- field={{ name: "flex-grow", label: "Grow", type: "Float" }}
638
- node={node}
639
- setProp={setProp}
640
- isStyle={true}
641
- />
642
- <SettingsRow
643
- field={{ name: "flex-shrink", label: "Shrink", type: "Float" }}
644
- node={node}
645
- setProp={setProp}
646
- isStyle={true}
647
- />
648
- {display && display.includes("flex") && (
649
- <Fragment>
650
- <SettingsSectionHeaderRow title="Flex container" />
651
- <SettingsRow
652
- field={{
653
- name: "flex-direction",
654
- label: "Direction",
655
- type: "select",
656
- options: ["row", "row-reverse", "column", "column-reverse"],
657
- }}
658
- node={node}
659
- setProp={setProp}
660
- isStyle={true}
661
- />
662
- <SettingsRow
663
- field={{
664
- name: "flex-wrap",
665
- label: "Wrap",
666
- type: "select",
667
- options: ["nowrap", "wrap", "wrap-reverse"],
668
- }}
669
- node={node}
670
- setProp={setProp}
671
- isStyle={true}
672
- />
673
- <SettingsRow
674
- field={{
675
- name: "justify-content",
676
- label: "Justify content",
677
- type: "select",
678
- options: [
679
- "flex-start",
680
- "flex-end",
681
- "center",
682
- "space-between",
683
- "space-around",
684
- "space-evenly",
685
- "start",
686
- "end",
687
- "left",
688
- "right",
689
- ],
690
- }}
691
- node={node}
692
- setProp={setProp}
693
- isStyle={true}
694
- />
695
- <SettingsRow
696
- field={{
697
- name: "align-items",
698
- label: "Align items",
699
- type: "select",
700
- options: [
701
- "stretch",
702
- "flex-start",
703
- "flex-end",
704
- "center",
705
- "baseline",
706
- "first baseline",
707
- "last baseline",
708
- "start",
709
- "end",
710
- "self-start",
711
- "self-end",
712
- ],
713
- }}
714
- node={node}
715
- setProp={setProp}
716
- isStyle={true}
717
- />
718
- <SettingsRow
719
- field={{
720
- name: "align-content",
721
- label: "Align content",
722
- type: "select",
723
- options: [
724
- "flex-start",
725
- "flex-end",
726
- "center",
727
- "space-between",
728
- "space-around",
729
- "space-evenly",
730
- "stretch",
731
- "start",
732
- "end",
733
- "baseline",
734
- "first baseline",
735
- "last baseline",
736
- ],
737
- }}
738
- node={node}
739
- setProp={setProp}
740
- isStyle={true}
741
- />
742
- </Fragment>
743
- )}
744
- </tbody>
745
- </table>
746
- <table className="w-100" accordiontitle="Show if...">
747
- <tbody>
748
- {["show", "edit"].includes(options.mode) && (
749
- <SettingsSectionHeaderRow title="Formula - show if true" />
750
- )}
751
- {["show", "edit"].includes(options.mode) && (
752
828
  <tr>
753
829
  <td>
754
- <input
755
- type="text"
756
- className="form-control text-to-display"
757
- value={showIfFormula}
758
- onChange={setAProp("showIfFormula")}
759
- />
760
- <div style={{ marginTop: "-5px" }}>
761
- <small className="text-muted font-monospace">FORMULA <FormulaTooltip /></small>
762
- </div>
830
+ <label>Max screen width</label>
763
831
  </td>
764
- </tr>
765
- )}
766
- <SettingsSectionHeaderRow title="Role" />
767
- {options.roles.map(({ role, id }) => (
768
- <tr key={id}>
769
- <td colSpan="2">
770
- <div className="form-check">
771
- <input
772
- className="form-check-input"
773
- name="block"
774
- type="checkbox"
775
- checked={
776
- typeof showForRole[id] === "undefined"
777
- ? true
778
- : showForRole[id]
779
- }
780
- onChange={(e) => {
781
- if (!e?.target) return;
782
- const checked = e.target.checked;
783
- setProp((prop) => {
784
- if (!prop.showForRole || prop.showForRole.length === 0)
785
- options.roles.forEach(
786
- (r) => (prop.showForRole[r.id] = true)
787
- );
788
- prop.showForRole[id] = checked;
789
- });
790
- }}
791
- />
792
- <label className="form-check-label">{role}</label>
793
- </div>
794
- </td>
795
- </tr>
796
- ))}
797
- {ownership ? (
798
- <tr>
799
- <td colSpan="2">
800
- <div className="form-check">
801
- <input
802
- className="form-check-input"
803
- name="block"
804
- type="checkbox"
805
- checked={show_for_owner}
806
- onChange={setAProp("show_for_owner", { checked: true })}
807
- />
808
- <label className="form-check-label">Owner</label>
809
- </div>
832
+ <td>
833
+ <select
834
+ value={maxScreenWidth}
835
+ className="form-control form-select"
836
+ onChange={setAProp("maxScreenWidth")}
837
+ >
838
+ <option value="">all</option>
839
+ <option value="md">small</option>
840
+ <option value="lg">medium</option>
841
+ <option value="xl">large</option>
842
+ </select>
810
843
  </td>
811
844
  </tr>
812
- ) : null}
813
- <tr>
814
- <td>
815
- <label>Min screen width</label>
816
- </td>
817
- <td>
818
- <select
819
- value={minScreenWidth}
820
- className="form-control form-select"
821
- onChange={setAProp("minScreenWidth")}
822
- >
823
- <option value="">all</option>
824
- <option value="sm">small</option>
825
- <option value="md">medium</option>
826
- <option value="lg">large</option>
827
- <option value="xl">x-large</option>
828
- </select>
829
- </td>
830
- </tr>
831
- <tr>
832
- <td>
833
- <label>Max screen width</label>
834
- </td>
835
- <td>
836
- <select
837
- value={maxScreenWidth}
838
- className="form-control form-select"
839
- onChange={setAProp("maxScreenWidth")}
840
- >
841
- <option value="">all</option>
842
- <option value="md">small</option>
843
- <option value="lg">medium</option>
844
- <option value="xl">large</option>
845
- </select>
846
- </td>
847
- </tr>
848
- </tbody>
849
- </table>
850
- <div accordiontitle="Container link">
851
- <label>URL</label>
852
- <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
853
- <input
854
- type="text"
855
- className="form-control"
856
- value={url}
857
- onChange={setAProp("url")}
858
- />
859
- </OrFormula>
860
-
861
- <label>Hover color</label>
862
- <select
863
- value={hoverColor}
864
- className="form-control form-select"
865
- onChange={setAProp("hoverColor")}
866
- >
867
- <option value="">None</option>
868
- <option value="gray">gray</option>
869
- <option value="gray-dark">gray-dark</option>
870
- <option value="light">light</option>
871
- <option value="dark">dark</option>
872
- </select>
873
- </div>
845
+ </tbody>
846
+ </table>
847
+ <div accordiontitle="Container link">
848
+ <label>URL</label>
849
+ <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
850
+ <input
851
+ type="text"
852
+ className="form-control"
853
+ value={url}
854
+ onChange={setAProp("url")}
855
+ />
856
+ </OrFormula>
874
857
 
875
- <div accordiontitle="Custom class/CSS">
876
- <div>
877
- <label>Custom class</label>
858
+ <label>Hover color</label>
859
+ <select
860
+ value={hoverColor}
861
+ className="form-control form-select"
862
+ onChange={setAProp("hoverColor")}
863
+ >
864
+ <option value="">None</option>
865
+ <option value="gray">gray</option>
866
+ <option value="gray-dark">gray-dark</option>
867
+ <option value="light">light</option>
868
+ <option value="dark">dark</option>
869
+ </select>
878
870
  </div>
879
- <OrFormula nodekey="customClass" {...{ setProp, isFormula, node }}>
880
- <input
871
+
872
+ <div accordiontitle="Custom class/CSS">
873
+ <div>
874
+ <label>Custom class</label>
875
+ </div>
876
+ <OrFormula nodekey="customClass" {...{ setProp, isFormula, node }}>
877
+ <input
878
+ type="text"
879
+ className="form-control text-to-display"
880
+ value={customClass}
881
+ onChange={setAProp("customClass")}
882
+ />
883
+ </OrFormula>
884
+ <div>
885
+ <label>Custom CSS</label>
886
+ </div>
887
+ <textarea
888
+ rows="4"
881
889
  type="text"
882
- className="form-control text-to-display"
883
- value={customClass}
884
- onChange={setAProp("customClass")}
885
- />
886
- </OrFormula>
887
- <div>
888
- <label>Custom CSS</label>
890
+ className="text-to-display form-control"
891
+ value={customCSS}
892
+ onChange={setAProp("customCSS")}
893
+ ></textarea>
889
894
  </div>
890
- <textarea
891
- rows="4"
892
- type="text"
893
- className="text-to-display form-control"
894
- value={customCSS}
895
- onChange={setAProp("customCSS")}
896
- ></textarea>
897
- </div>
898
- </Accordion>
899
- );
900
- };
895
+ </Accordion>
896
+ );
897
+ };
901
898
 
902
899
  /**
903
900
  * @type {object}