@saltcorn/builder 0.0.1-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.
Files changed (38) hide show
  1. package/.babelrc +3 -0
  2. package/CHANGELOG.md +8 -0
  3. package/dist/builder_bundle.js +80 -0
  4. package/package.json +47 -0
  5. package/src/components/Builder.js +477 -0
  6. package/src/components/Library.js +224 -0
  7. package/src/components/RenderNode.js +203 -0
  8. package/src/components/Toolbox.js +688 -0
  9. package/src/components/context.js +9 -0
  10. package/src/components/elements/Action.js +204 -0
  11. package/src/components/elements/Aggregation.js +179 -0
  12. package/src/components/elements/BoxModelEditor.js +398 -0
  13. package/src/components/elements/Card.js +152 -0
  14. package/src/components/elements/Column.js +63 -0
  15. package/src/components/elements/Columns.js +201 -0
  16. package/src/components/elements/Container.js +947 -0
  17. package/src/components/elements/DropDownFilter.js +154 -0
  18. package/src/components/elements/DropMenu.js +156 -0
  19. package/src/components/elements/Empty.js +30 -0
  20. package/src/components/elements/Field.js +239 -0
  21. package/src/components/elements/HTMLCode.js +61 -0
  22. package/src/components/elements/Image.js +320 -0
  23. package/src/components/elements/JoinField.js +206 -0
  24. package/src/components/elements/LineBreak.js +46 -0
  25. package/src/components/elements/Link.js +305 -0
  26. package/src/components/elements/SearchBar.js +141 -0
  27. package/src/components/elements/Tabs.js +347 -0
  28. package/src/components/elements/Text.js +330 -0
  29. package/src/components/elements/ToggleFilter.js +243 -0
  30. package/src/components/elements/View.js +189 -0
  31. package/src/components/elements/ViewLink.js +225 -0
  32. package/src/components/elements/boxmodel.html +253 -0
  33. package/src/components/elements/faicons.js +1643 -0
  34. package/src/components/elements/utils.js +1217 -0
  35. package/src/components/preview_context.js +9 -0
  36. package/src/components/storage.js +506 -0
  37. package/src/index.js +73 -0
  38. package/webpack.config.js +21 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/DropDownFilter
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { useContext, Fragment } from "react";
8
+ import { useNode } from "@craftjs/core";
9
+ import optionsCtx from "../context";
10
+ import { blockProps, BlockSetting, TextStyleRow } from "./utils";
11
+
12
+ export /**
13
+ * @param {object} props
14
+ * @param {string} props.name
15
+ * @param {boolean} props.block
16
+ * @param {boolean} props.full_width
17
+ * @returns {span}
18
+ * @namespace
19
+ * @category saltcorn-builder
20
+ * @subcategory components
21
+ */
22
+ const DropDownFilter = ({ name, block, full_width }) => {
23
+ const {
24
+ selected,
25
+ connectors: { connect, drag },
26
+ } = useNode((node) => ({ selected: node.events.selected }));
27
+ return (
28
+ <span
29
+ className={selected ? "selected-node" : ""}
30
+ {...blockProps(block)}
31
+ ref={(dom) => connect(drag(dom))}
32
+ >
33
+ <select disabled={true} className={full_width ? "w-100" : ""}>
34
+ <option>{name}</option>
35
+ </select>
36
+ </span>
37
+ );
38
+ };
39
+
40
+ export /**
41
+ * @returns {table}
42
+ * @namespace
43
+ * @category saltcorn-builder
44
+ * @subcategory components
45
+ */
46
+ const DropDownFilterSettings = () => {
47
+ const {
48
+ actions: { setProp },
49
+ name,
50
+ block,
51
+ neutral_label,
52
+ full_width,
53
+ where,
54
+ } = useNode((node) => ({
55
+ name: node.data.props.name,
56
+ block: node.data.props.block,
57
+ neutral_label: node.data.props.neutral_label,
58
+ full_width: node.data.props.full_width,
59
+ where: node.data.props.where,
60
+ }));
61
+ const options = useContext(optionsCtx);
62
+ return (
63
+ <table className="w-100">
64
+ <tbody>
65
+ <tr>
66
+ <td>
67
+ <label>Field</label>
68
+ </td>
69
+ <td>
70
+ <select
71
+ value={name}
72
+ className="form-control form-select"
73
+ onChange={(e) => setProp((prop) => (prop.name = e.target.value))}
74
+ >
75
+ {options.fields.map((f, ix) => (
76
+ <option key={ix} value={f.name}>
77
+ {f.label}
78
+ </option>
79
+ ))}
80
+ </select>
81
+ </td>
82
+ </tr>
83
+ <tr>
84
+ <td>
85
+ <label>Neutral label</label>
86
+ </td>
87
+ <td>
88
+ <input
89
+ value={neutral_label}
90
+ className="form-control"
91
+ onChange={(e) =>
92
+ setProp((prop) => (prop.neutral_label = e.target.value))
93
+ }
94
+ />
95
+ </td>
96
+ </tr>
97
+ <tr>
98
+ <td>
99
+ <label>Where</label>
100
+ </td>
101
+ <td>
102
+ <input
103
+ value={where}
104
+ className="form-control"
105
+ onChange={(e) => setProp((prop) => (prop.where = e.target.value))}
106
+ />
107
+ </td>
108
+ </tr>
109
+ <tr>
110
+ <td></td>
111
+ <td>
112
+ <BlockSetting block={block} setProp={setProp} />
113
+ </td>
114
+ </tr>
115
+ <tr>
116
+ <td></td>
117
+ <td>
118
+ <div className="form-check">
119
+ <input
120
+ className="form-check-input"
121
+ name="block"
122
+ type="checkbox"
123
+ checked={full_width}
124
+ onChange={(e) =>
125
+ setProp((prop) => (prop.full_width = e.target.checked))
126
+ }
127
+ />
128
+ <label className="form-check-label">Full width</label>
129
+ </div>
130
+ </td>
131
+ </tr>
132
+ </tbody>
133
+ </table>
134
+ );
135
+ };
136
+
137
+ /**
138
+ * @type {object}
139
+ */
140
+ DropDownFilter.craft = {
141
+ displayName: "DropDownFilter",
142
+ related: {
143
+ settings: DropDownFilterSettings,
144
+ segment_type: "dropdown_filter",
145
+ column_type: "DropDownFilter",
146
+ fields: [
147
+ { name: "name", segment_name: "field_name", column_name: "field_name" },
148
+ "full_width",
149
+ "neutral_label",
150
+ "where",
151
+ "block",
152
+ ],
153
+ },
154
+ };
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/DropMenu
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { Fragment, useState } from "react";
8
+ import { Element, useNode } from "@craftjs/core";
9
+ import { Column } from "./Column";
10
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
11
+ import { faCaretDown } from "@fortawesome/free-solid-svg-icons";
12
+ import {
13
+ SettingsRow,
14
+ BlockSetting,
15
+ ButtonOrLinkSettingsRows,
16
+ DynamicFontAwesomeIcon,
17
+ } from "./utils";
18
+
19
+ export /**
20
+ * @param {object} props
21
+ * @param {boolean} props.has_dropdown
22
+ * @param {string} props.children
23
+ * @param {boolean} props.show_badges
24
+ * @returns {div}
25
+ * @namespace
26
+ * @category saltcorn-builder
27
+ * @subcategory components
28
+ */
29
+ const DropMenu = ({
30
+ children,
31
+ action_style,
32
+ action_size,
33
+ action_icon,
34
+ action_bgcol,
35
+ action_bordercol,
36
+ action_textcol,
37
+ block,
38
+ label,
39
+ }) => {
40
+ const {
41
+ selected,
42
+ connectors: { connect, drag },
43
+ } = useNode((node) => ({ selected: node.events.selected }));
44
+ const [showDropdown, setDropdown] = useState(false);
45
+ //const [dropWidth, setDropWidth] = useState(200);
46
+ return (
47
+ <div
48
+ className={`${selected ? "selected-node" : ""} ${block ? "d-block" : ""}`}
49
+ ref={(dom) => connect(drag(dom))}
50
+ >
51
+ <button
52
+ className={`btn ${action_style || "btn-primary"} ${action_size || ""} `}
53
+ style={
54
+ action_style === "btn-custom-color"
55
+ ? {
56
+ backgroundColor: action_bgcol || "#000000",
57
+ borderColor: action_bordercol || "#000000",
58
+ color: action_textcol || "#000000",
59
+ }
60
+ : {}
61
+ }
62
+ >
63
+ <DynamicFontAwesomeIcon icon={action_icon} className="me-1" />
64
+
65
+ {label}
66
+ <FontAwesomeIcon
67
+ icon={faCaretDown}
68
+ className="ms-1"
69
+ onClick={() => setDropdown(!showDropdown)}
70
+ />
71
+ </button>
72
+ <div
73
+ className={`dropdown-menu dropmenu-dropdown ${
74
+ showDropdown ? "show" : ""
75
+ }`}
76
+ >
77
+ <div className="canvas d-flex flex-column">{children}</div>
78
+ </div>
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export /**
84
+ * @returns {div}
85
+ * @namespace
86
+ * @category saltcorn-builder
87
+ * @subcategory components
88
+ */
89
+ const DropMenuSettings = () => {
90
+ const node = useNode((node) => ({
91
+ label: node.data.props.label,
92
+ block: node.data.props.block,
93
+ action_style: node.data.props.action_style,
94
+ action_size: node.data.props.action_size,
95
+ action_icon: node.data.props.action_icon,
96
+ action_bgcol: node.data.props.action_bgcol,
97
+ action_bordercol: node.data.props.action_bordercol,
98
+ action_textcol: node.data.props.action_textcol,
99
+ }));
100
+ const {
101
+ actions: { setProp },
102
+ label,
103
+ block,
104
+ } = node;
105
+ return (
106
+ <table className="w-100">
107
+ <tbody>
108
+ <SettingsRow
109
+ field={{
110
+ label: "Label",
111
+ name: "label",
112
+ type: "String",
113
+ }}
114
+ node={node}
115
+ setProp={setProp}
116
+ />
117
+ <ButtonOrLinkSettingsRows
118
+ setProp={setProp}
119
+ keyPrefix="action_"
120
+ values={node}
121
+ />
122
+ <tr>
123
+ <td colSpan="2">
124
+ <BlockSetting block={block} setProp={setProp} />
125
+ </td>
126
+ </tr>
127
+ </tbody>
128
+ </table>
129
+ );
130
+ };
131
+
132
+ /**
133
+ * @type {object}
134
+ */
135
+ DropMenu.craft = {
136
+ displayName: "DropMenu",
137
+ props: {
138
+ label: "Menu",
139
+ block: false,
140
+ },
141
+ related: {
142
+ settings: DropMenuSettings,
143
+ segment_type: "dropdown_menu",
144
+ hasContents: true,
145
+ fields: [
146
+ "label",
147
+ "block",
148
+ "action_style",
149
+ "action_size",
150
+ "action_icon",
151
+ "action_bgcol",
152
+ "action_bordercol",
153
+ "action_textcol",
154
+ ],
155
+ },
156
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/Empty
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { Fragment } from "react";
8
+ import { useNode } from "@craftjs/core";
9
+
10
+ export /**
11
+ * @param {object} [props = {}]
12
+ * @returns {Fragment}
13
+ * @namespace
14
+ * @category saltcorn-builder
15
+ * @subcategory components
16
+ */
17
+ const Empty = ({}) => {
18
+ const {
19
+ selected,
20
+ connectors: { connect, drag },
21
+ } = useNode((node) => ({ selected: node.events.selected }));
22
+ return null;
23
+ };
24
+
25
+ /**
26
+ * @type {object}
27
+ */
28
+ Empty.craft = {
29
+ displayName: "Empty",
30
+ };
@@ -0,0 +1,239 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/Field
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { useContext, useEffect, Fragment } from "react";
8
+ import { useNode } from "@craftjs/core";
9
+ import optionsCtx from "../context";
10
+ import previewCtx from "../preview_context";
11
+ import {
12
+ blockProps,
13
+ BlockOrInlineSetting,
14
+ TextStyleRow,
15
+ ConfigForm,
16
+ setInitialConfig,
17
+ isBlock,
18
+ fetchFieldPreview,
19
+ } from "./utils";
20
+
21
+ export /**
22
+ * @param {object} props
23
+ * @param {string} props.name
24
+ * @param {string} props.fieldview
25
+ * @param {boolean} props.block
26
+ * @param {string} props.textStyle
27
+ * @param {object} props.configuration
28
+ * @returns {div}
29
+ * @category saltcorn-builder
30
+ * @subcategory components
31
+ * @namespace
32
+ */
33
+ const Field = ({
34
+ name,
35
+ fieldview,
36
+ block,
37
+ inline,
38
+ textStyle,
39
+ configuration,
40
+ }) => {
41
+ const {
42
+ selected,
43
+ node_id,
44
+ connectors: { connect, drag },
45
+ } = useNode((node) => ({ selected: node.events.selected, node_id: node.id }));
46
+ const { previews, setPreviews } = useContext(previewCtx);
47
+ const myPreview = previews[node_id];
48
+ const options = useContext(optionsCtx);
49
+ const blockDisplays = (options.blockDisplay || {})[name];
50
+ const blockDisplay = blockDisplays && blockDisplays.includes(fieldview);
51
+ useEffect(() => {
52
+ fetchFieldPreview({
53
+ options,
54
+ name,
55
+ fieldview,
56
+ configuration,
57
+ setPreviews,
58
+ node_id,
59
+ })();
60
+ }, []);
61
+ return (
62
+ <div
63
+ className={`${textStyle} ${selected ? "selected-node" : ""} ${
64
+ isBlock(block, inline, textStyle) || blockDisplay
65
+ ? "d-block"
66
+ : "d-inline-block"
67
+ }`}
68
+ ref={(dom) => connect(drag(dom))}
69
+ >
70
+ {myPreview ? (
71
+ <div
72
+ className="d-inline"
73
+ dangerouslySetInnerHTML={{ __html: myPreview }}
74
+ ></div>
75
+ ) : (
76
+ `[${fieldview} ${name}]`
77
+ )}
78
+ </div>
79
+ );
80
+ };
81
+
82
+ export /**
83
+ * @returns {Fragment}
84
+ * @namespace
85
+ * @category saltcorn-builder
86
+ * @subcategory components
87
+ */
88
+ const FieldSettings = () => {
89
+ const {
90
+ actions: { setProp },
91
+ name,
92
+ fieldview,
93
+ block,
94
+ inline,
95
+ configuration,
96
+ node_id,
97
+ textStyle,
98
+ } = useNode((node) => ({
99
+ name: node.data.props.name,
100
+ fieldview: node.data.props.fieldview,
101
+ block: node.data.props.block,
102
+ inline: node.data.props.inline,
103
+ textStyle: node.data.props.textStyle,
104
+ configuration: node.data.props.configuration,
105
+ node_id: node.id,
106
+ }));
107
+ const options = useContext(optionsCtx);
108
+ const { setPreviews } = useContext(previewCtx);
109
+
110
+ const fvs = options.field_view_options[name];
111
+ const handlesTextStyle = (options.handlesTextStyle || {})[name];
112
+ const blockDisplay = (options.blockDisplay || {})[name];
113
+ const getCfgFields = (fv) =>
114
+ ((options.fieldViewConfigForms || {})[name] || {})[fv];
115
+ const cfgFields = getCfgFields(fieldview);
116
+ const refetchPreview = fetchFieldPreview({
117
+ options,
118
+ name,
119
+ fieldview,
120
+ configuration,
121
+ setPreviews,
122
+ node_id,
123
+ });
124
+
125
+ return (
126
+ <Fragment>
127
+ <i>
128
+ <small>
129
+ Previews shown in canvas are indicative based on random rows
130
+ </small>
131
+ </i>
132
+ <table className="w-100">
133
+ <tbody>
134
+ <tr>
135
+ <td>
136
+ <label>Field</label>
137
+ </td>
138
+ <td>
139
+ <select
140
+ value={name}
141
+ className="form-control form-select"
142
+ onChange={(e) => {
143
+ setProp((prop) => (prop.name = e.target.value));
144
+ const newfvs = options.field_view_options[e.target.value];
145
+ if (newfvs && newfvs.length > 0) {
146
+ setProp((prop) => (prop.fieldview = newfvs[0]));
147
+ refetchPreview({
148
+ name: e.target.value,
149
+ fieldview: newfvs[0],
150
+ });
151
+ } else refetchPreview({ name: e.target.value });
152
+ }}
153
+ >
154
+ {options.fields.map((f, ix) => (
155
+ <option key={ix} value={f.name}>
156
+ {f.label}
157
+ </option>
158
+ ))}
159
+ </select>
160
+ </td>
161
+ </tr>
162
+ {fvs && (
163
+ <tr>
164
+ <td>
165
+ <label>Field view</label>
166
+ </td>
167
+
168
+ <td>
169
+ <select
170
+ value={fieldview}
171
+ className="form-control form-select"
172
+ onChange={(e) => {
173
+ setProp((prop) => (prop.fieldview = e.target.value));
174
+ setInitialConfig(
175
+ setProp,
176
+ e.target.value,
177
+ getCfgFields(e.target.value)
178
+ );
179
+ refetchPreview({ fieldview: e.target.value });
180
+ }}
181
+ >
182
+ {(fvs || []).map((fvnm, ix) => (
183
+ <option key={ix} value={fvnm}>
184
+ {fvnm}
185
+ </option>
186
+ ))}
187
+ </select>
188
+ </td>
189
+ </tr>
190
+ )}
191
+ {!(blockDisplay && blockDisplay.includes(fieldview)) && (
192
+ <tr>
193
+ <td></td>
194
+ <td>
195
+ <BlockOrInlineSetting
196
+ block={block}
197
+ inline={inline}
198
+ textStyle={textStyle}
199
+ setProp={setProp}
200
+ />
201
+ </td>
202
+ </tr>
203
+ )}
204
+ {!(handlesTextStyle && handlesTextStyle.includes(fieldview)) && (
205
+ <TextStyleRow textStyle={textStyle} setProp={setProp} />
206
+ )}
207
+ </tbody>
208
+ </table>
209
+ {cfgFields ? (
210
+ <ConfigForm
211
+ fields={cfgFields}
212
+ configuration={configuration}
213
+ setProp={setProp}
214
+ onChange={(k, v) => refetchPreview({ configuration: { [k]: v } })}
215
+ />
216
+ ) : null}
217
+ </Fragment>
218
+ );
219
+ };
220
+
221
+ /**
222
+ * @type {object}
223
+ */
224
+ Field.craft = {
225
+ displayName: "Field",
226
+ related: {
227
+ settings: FieldSettings,
228
+ segment_type: "field",
229
+ column_type: "Field",
230
+ fields: [
231
+ { name: "name", segment_name: "field_name", column_name: "field_name" },
232
+ "fieldview",
233
+ "textStyle",
234
+ "block",
235
+ "inline",
236
+ { name: "configuration", default: {} },
237
+ ],
238
+ },
239
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/HTMLCode
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React from "react";
8
+ import { useNode } from "@craftjs/core";
9
+ import {
10
+ blockProps,
11
+ BlockSetting,
12
+ SettingsFromFields,
13
+ TextStyleSetting,
14
+ } from "./utils";
15
+
16
+ export /**
17
+ * @param {object} props
18
+ * @param {string} props.text
19
+ * @returns {span}
20
+ * @namespace
21
+ * @category saltcorn-builder
22
+ * @subcategory components
23
+ */
24
+ const HTMLCode = ({ text }) => {
25
+ const {
26
+ selected,
27
+ connectors: { connect, drag },
28
+ } = useNode((node) => ({ selected: node.events.selected }));
29
+ return (
30
+ <span
31
+ className={`is-html-block ${selected ? "selected-node" : ""}`}
32
+ ref={(dom) => connect(drag(dom))}
33
+ >
34
+ <div style={{ fontSize: "8px" }}>HTML</div>
35
+ <div dangerouslySetInnerHTML={{ __html: text }}></div>
36
+ </span>
37
+ );
38
+ };
39
+
40
+ const fields = [
41
+ {
42
+ label: "HTML Code",
43
+ name: "text",
44
+ type: "textarea",
45
+ segment_name: "contents"
46
+ },
47
+ ];
48
+
49
+ /**
50
+ * @type {object}
51
+ */
52
+ HTMLCode.craft = {
53
+ displayName: "HTMLCode",
54
+ related: {
55
+ settings: SettingsFromFields(fields),
56
+ segment_type: "blank",
57
+ segment_vars: { isHTML: true },
58
+ segment_match: (segment) => segment.isHTML,
59
+ fields,
60
+ },
61
+ };