@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,243 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/ToggleFilter
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 {*} props.name
15
+ * @param {string} [props.value]
16
+ * @param {string} [props.preset_value]
17
+ * @param {boolean} props.block
18
+ * @param {string} [props.label]
19
+ * @param {string} props.size
20
+ * @param {string} props.style
21
+ * @returns {table}
22
+ * @namespace
23
+ * @category saltcorn-builder
24
+ * @subcategory components
25
+ */
26
+ const ToggleFilter = ({
27
+ name,
28
+ value,
29
+ preset_value,
30
+ block,
31
+ label,
32
+ size,
33
+ style,
34
+ }) => {
35
+ const {
36
+ selected,
37
+ connectors: { connect, drag },
38
+ } = useNode((node) => ({ selected: node.events.selected }));
39
+ return (
40
+ <span
41
+ className={selected ? "selected-node" : ""}
42
+ {...blockProps(block)}
43
+ ref={(dom) => connect(drag(dom))}
44
+ >
45
+ <button className={`btn btn-outline-${style || "primary"} ${size}`}>
46
+ {label || value || preset_value || "Set label"}
47
+ </button>
48
+ </span>
49
+ );
50
+ };
51
+
52
+ export /**
53
+ * @returns {table}
54
+ * @namespace
55
+ * @category saltcorn-builder
56
+ * @subcategory components
57
+ */
58
+ const ToggleFilterSettings = () => {
59
+ const {
60
+ actions: { setProp },
61
+ name,
62
+ value,
63
+ block,
64
+ preset_value,
65
+ label,
66
+ size,
67
+ style,
68
+ } = useNode((node) => ({
69
+ name: node.data.props.name,
70
+ value: node.data.props.value,
71
+ preset_value: node.data.props.preset_value,
72
+ block: node.data.props.block,
73
+ label: node.data.props.label,
74
+ size: node.data.props.size,
75
+ style: node.data.props.style,
76
+ }));
77
+ const options = useContext(optionsCtx);
78
+ const field = options.fields.find((f) => f.name === name);
79
+ const preset_options = field.preset_options;
80
+ const isBool = field && field.type.name === "Bool";
81
+ const setAProp = (key) => (e) => {
82
+ if (e.target) {
83
+ const target_value = e.target.value;
84
+ setProp((prop) => (prop[key] = target_value));
85
+ }
86
+ };
87
+ return (
88
+ <table className="w-100">
89
+ <tbody>
90
+ <tr>
91
+ <td>
92
+ <label>Field</label>
93
+ </td>
94
+ <td>
95
+ <select
96
+ value={name}
97
+ className="form-control form-select"
98
+ onChange={(e) => {
99
+ setProp((prop) => (prop.name = e.target.value));
100
+ const field = options.fields.find(
101
+ (f) => f.name === e.target.value
102
+ );
103
+ const isBool = field && field.type.name === "Bool";
104
+ if (isBool) setProp((prop) => (prop.value = "on"));
105
+ setProp((prop) => (prop.preset_value = ""));
106
+ }}
107
+ >
108
+ {options.fields.map((f, ix) => (
109
+ <option key={ix} value={f.name}>
110
+ {f.label}
111
+ </option>
112
+ ))}
113
+ </select>
114
+ </td>
115
+ </tr>
116
+ <tr>
117
+ <td>
118
+ <label>Value</label>
119
+ </td>
120
+ <td>
121
+ {isBool ? (
122
+ <select
123
+ value={value}
124
+ className="w-100 form-select"
125
+ onChange={setAProp("value")}
126
+ >
127
+ <option value="on">True</option>
128
+ <option value="off">False</option>
129
+ <option value="?">Both</option>
130
+ </select>
131
+ ) : (
132
+ <input
133
+ value={value}
134
+ className="w-100"
135
+ onChange={setAProp("value")}
136
+ />
137
+ )}
138
+ </td>
139
+ </tr>
140
+ {preset_options && preset_options.length > 0 ? (
141
+ <tr>
142
+ <td>
143
+ <label>Preset</label>
144
+ </td>
145
+ <td>
146
+ <select
147
+ value={preset_value}
148
+ className="form-control form-select"
149
+ onChange={setAProp("preset_value")}
150
+ >
151
+ <option value=""></option>
152
+ {preset_options.map((po, ix) => (
153
+ <option key={ix} value={po}>
154
+ {po}
155
+ </option>
156
+ ))}
157
+ </select>
158
+ </td>
159
+ </tr>
160
+ ) : null}
161
+ <tr>
162
+ <td>
163
+ <label>Label</label>
164
+ </td>
165
+ <td>
166
+ <input
167
+ value={label}
168
+ className="w-100"
169
+ onChange={setAProp("label")}
170
+ />
171
+ </td>
172
+ </tr>
173
+ <tr>
174
+ <td>
175
+ <label>Button size</label>
176
+ </td>
177
+ <td>
178
+ <select
179
+ className="form-control form-select"
180
+ value={size}
181
+ onChange={setAProp("size")}
182
+ >
183
+ <option value="">Standard</option>
184
+ <option value="btn-lg">Large</option>
185
+ <option value="btn-sm">Small</option>
186
+ <option value="btn-block">Block</option>
187
+ <option value="btn-block btn-lg">Large block</option>
188
+ <option value="btn-block btn-sm">Small block</option>
189
+ </select>
190
+ </td>
191
+ </tr>
192
+ <tr>
193
+ <td>
194
+ <label>Button style</label>
195
+ </td>
196
+ <td>
197
+ <select
198
+ className="form-control form-select"
199
+ value={style}
200
+ onChange={setAProp("style")}
201
+ >
202
+ <option value="primary">Primary</option>
203
+ <option value="secondary">Secondary</option>
204
+ <option value="success">Success</option>
205
+ <option value="danger">Danger</option>
206
+ <option value="warning">Warning</option>
207
+ <option value="info">Info</option>
208
+ <option value="light">Light</option>
209
+ <option value="dark">Dark</option>
210
+ </select>
211
+ </td>
212
+ </tr>
213
+ <tr>
214
+ <td></td>
215
+ <td>
216
+ <BlockSetting block={block} setProp={setProp} />
217
+ </td>
218
+ </tr>
219
+ </tbody>
220
+ </table>
221
+ );
222
+ };
223
+
224
+ /**
225
+ * @type {object}
226
+ */
227
+ ToggleFilter.craft = {
228
+ displayName: "ToggleFilter",
229
+ related: {
230
+ settings: ToggleFilterSettings,
231
+ segment_type: "toggle_filter",
232
+ column_type: "ToggleFilter",
233
+ fields: [
234
+ { name: "name", segment_name: "field_name", column_name: "field_name" },
235
+ "value",
236
+ "preset_value",
237
+ "block",
238
+ "label",
239
+ "size",
240
+ "style",
241
+ ],
242
+ },
243
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/View
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { Fragment, useContext, useEffect } from "react";
8
+ import { useNode } from "@craftjs/core";
9
+ import optionsCtx from "../context";
10
+ import previewCtx from "../preview_context";
11
+
12
+ import {
13
+ blockProps,
14
+ BlockSetting,
15
+ MinRoleSetting,
16
+ fetchViewPreview,
17
+ ConfigForm,
18
+ } from "./utils";
19
+
20
+ export /**
21
+ * @param {object} props
22
+ * @param {*} props.name
23
+ * @param {string} props.view
24
+ * @param {*} props.state
25
+ * @returns {div}
26
+ * @category saltcorn-builder
27
+ * @subcategory components
28
+ * @namespace
29
+ */
30
+ const View = ({ name, view, configuration, state }) => {
31
+ const {
32
+ selected,
33
+ node_id,
34
+ connectors: { connect, drag },
35
+ } = useNode((node) => ({ selected: node.events.selected, node_id: node.id }));
36
+ const options = useContext(optionsCtx);
37
+
38
+ const views = options.views;
39
+ const theview = views.find((v) => v.name === view);
40
+ const label = theview ? theview.label : view;
41
+ const { previews, setPreviews } = useContext(previewCtx);
42
+ const myPreview = previews[node_id];
43
+ useEffect(() => {
44
+ fetchViewPreview({
45
+ options,
46
+ view,
47
+ setPreviews,
48
+ configuration,
49
+ node_id,
50
+ })();
51
+ }, [view, configuration, state]);
52
+ return (
53
+ <div
54
+ ref={(dom) => connect(drag(dom))}
55
+ className={`${myPreview ? "" : "builder-embed-view"} text-center ${
56
+ selected ? "selected-node" : ""
57
+ }`}
58
+ >
59
+ {myPreview ? (
60
+ <div
61
+ className="d-inline"
62
+ dangerouslySetInnerHTML={{ __html: myPreview }}
63
+ ></div>
64
+ ) : (
65
+ `View: ${label}`
66
+ )}
67
+ </div>
68
+ );
69
+ };
70
+
71
+ export /**
72
+ * @returns {div}
73
+ * @category saltcorn-builder
74
+ * @subcategory components
75
+ * @namespace
76
+ */
77
+ const ViewSettings = () => {
78
+ const node = useNode((node) => ({
79
+ name: node.data.props.name,
80
+ view: node.data.props.view,
81
+ state: node.data.props.state,
82
+ extra_state_fml: node.data.props.extra_state_fml,
83
+ configuration: node.data.props.configuration, // fixed states
84
+ node_id: node.id,
85
+ }));
86
+
87
+ const {
88
+ actions: { setProp },
89
+ name,
90
+ view,
91
+ state,
92
+ node_id,
93
+ configuration,
94
+ extra_state_fml,
95
+ } = node;
96
+ const options = useContext(optionsCtx);
97
+ const views = options.views;
98
+ const fixed_state_fields =
99
+ options.fixed_state_fields && options.fixed_state_fields[view];
100
+ const { setPreviews } = useContext(previewCtx);
101
+
102
+ const setAProp = (key) => (e) => {
103
+ if (e.target) {
104
+ const target_value = e.target.value;
105
+ setProp((prop) => (prop[key] = target_value));
106
+ }
107
+ };
108
+ return (
109
+ <div>
110
+ <div>
111
+ <label>View to {options.mode === "show" ? "embed" : "show"}</label>
112
+ <select
113
+ value={view}
114
+ className="form-control form-select"
115
+ onChange={(e) => {
116
+ setProp((prop) => (prop.view = e.target.value));
117
+ }}
118
+ >
119
+ {views.map((f, ix) => (
120
+ <option key={ix} value={f.name}>
121
+ {f.label || f.name}
122
+ </option>
123
+ ))}
124
+ </select>
125
+ </div>
126
+ {options.mode === "page" && (
127
+ <Fragment>
128
+ <div>
129
+ <label>State</label>
130
+ <select
131
+ value={state}
132
+ className="form-control form-select"
133
+ onChange={setAProp("state")}
134
+ >
135
+ <option value="shared">Shared</option>
136
+ <option value="fixed">Fixed</option>
137
+ </select>
138
+ </div>
139
+ {state === "fixed" &&
140
+ fixed_state_fields &&
141
+ fixed_state_fields.length > 0 && (
142
+ <Fragment>
143
+ <h6>View state fields</h6>
144
+ <ConfigForm
145
+ fields={fixed_state_fields}
146
+ configuration={configuration || {}}
147
+ setProp={setProp}
148
+ node={node}
149
+ />
150
+ </Fragment>
151
+ )}
152
+ </Fragment>
153
+ )}
154
+ {(state === "shared" || options.mode === "page") && (
155
+ <Fragment>
156
+ {" "}
157
+ <label>Extra state Formula</label>
158
+ <input
159
+ type="text"
160
+ className="viewlink-label form-control"
161
+ value={extra_state_fml}
162
+ onChange={(e) =>
163
+ setProp((prop) => (prop.extra_state_fml = e.target.value))
164
+ }
165
+ />
166
+ </Fragment>
167
+ )}
168
+ {view ? (
169
+ <a
170
+ className="d-block mt-2"
171
+ target="_blank"
172
+ href={`/viewedit/config/${view}`}
173
+ >
174
+ Configure this view
175
+ </a>
176
+ ) : null}
177
+ </div>
178
+ );
179
+ };
180
+
181
+ /**
182
+ * @type {object}
183
+ */
184
+ View.craft = {
185
+ displayName: "View",
186
+ related: {
187
+ settings: ViewSettings,
188
+ },
189
+ };
@@ -0,0 +1,225 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/ViewLink
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { useContext } from "react";
8
+ import { useNode } from "@craftjs/core";
9
+ import optionsCtx from "../context";
10
+ import {
11
+ blockProps,
12
+ BlockSetting,
13
+ MinRoleSettingRow,
14
+ OrFormula,
15
+ TextStyleSetting,
16
+ ButtonOrLinkSettingsRows,
17
+ } from "./utils";
18
+
19
+ export /**
20
+ * @param {object} props
21
+ * @param {string} props.name
22
+ * @param {boolean} props.block
23
+ * @param {*} props.minRole
24
+ * @param {string} props.link_style
25
+ * @param {string} props.link_size
26
+ * @param {string} [props.link_icon]
27
+ * @param {boolean} props.inModal
28
+ * @param {string} [props.label]
29
+ * @param {string} props.textStyle
30
+ * @param {string} [props.link_bgcol]
31
+ * @param {string} [props.link_bordercol]
32
+ * @param {string} [props.link_textcol]
33
+ * @returns {tr}
34
+ * @category saltcorn-builder
35
+ * @subcategory components
36
+ * @namespace
37
+ */
38
+ const ViewLink = ({
39
+ name,
40
+ block,
41
+ minRole,
42
+ link_style,
43
+ link_size,
44
+ link_icon,
45
+ inModal,
46
+ label,
47
+ textStyle,
48
+ link_bgcol,
49
+ link_bordercol,
50
+ link_textcol,
51
+ }) => {
52
+ const {
53
+ selected,
54
+ connectors: { connect, drag },
55
+ } = useNode((node) => ({ selected: node.events.selected }));
56
+ const names = name.split(":");
57
+ const displabel = label || (names.length > 1 ? names[1] : names[0]);
58
+ return (
59
+ <span
60
+ className={`${textStyle} ${inModal ? "btn btn-secondary btn-sm" : ""} ${
61
+ selected ? "selected-node" : "is-builder-link"
62
+ } ${link_style} ${link_size}`}
63
+ {...blockProps(block)}
64
+ ref={(dom) => connect(drag(dom))}
65
+ style={
66
+ link_style === "btn btn-custom-color"
67
+ ? {
68
+ backgroundColor: link_bgcol || "#000000",
69
+ borderColor: link_bordercol || "#000000",
70
+ color: link_textcol || "#000000",
71
+ }
72
+ : {}
73
+ }
74
+ >
75
+ {link_icon ? <i className={`${link_icon} me-1`}></i> : ""}
76
+ {displabel}
77
+ </span>
78
+ );
79
+ };
80
+
81
+ export /**
82
+ * @returns {div}
83
+ * @category saltcorn-builder
84
+ * @subcategory components
85
+ * @namespace
86
+ */
87
+ const ViewLinkSettings = () => {
88
+ const node = useNode((node) => ({
89
+ name: node.data.props.name,
90
+ block: node.data.props.block,
91
+ minRole: node.data.props.minRole,
92
+ isFormula: node.data.props.isFormula,
93
+ label: node.data.props.label,
94
+ inModal: node.data.props.inModal,
95
+ link_style: node.data.props.link_style,
96
+ link_size: node.data.props.link_size,
97
+ link_icon: node.data.props.link_icon,
98
+ textStyle: node.data.props.textStyle,
99
+ link_bgcol: node.data.props.link_bgcol,
100
+ link_bordercol: node.data.props.link_bordercol,
101
+ link_textcol: node.data.props.link_textcol,
102
+ extra_state_fml: node.data.props.extra_state_fml,
103
+ }));
104
+ const {
105
+ actions: { setProp },
106
+ name,
107
+ block,
108
+ minRole,
109
+ label,
110
+ isFormula,
111
+ inModal,
112
+ textStyle,
113
+ extra_state_fml,
114
+ } = node;
115
+ const options = useContext(optionsCtx);
116
+ return (
117
+ <div>
118
+ <table className="w-100">
119
+ <tbody>
120
+ <tr>
121
+ <td colSpan="2">
122
+ <label>View to link to</label>
123
+ <select
124
+ value={name}
125
+ className="form-control form-select"
126
+ onChange={(e) =>
127
+ setProp((prop) => (prop.name = e.target.value))
128
+ }
129
+ >
130
+ {options.link_view_opts.map((f, ix) => (
131
+ <option key={ix} value={f.name}>
132
+ {f.label}
133
+ </option>
134
+ ))}
135
+ </select>
136
+ </td>
137
+ </tr>
138
+ <tr>
139
+ <td colSpan="2">
140
+ <label>Label (leave blank for default)</label>
141
+ <OrFormula nodekey="label" {...{ setProp, isFormula, node }}>
142
+ <input
143
+ type="text"
144
+ className="viewlink-label form-control"
145
+ value={label}
146
+ onChange={(e) =>
147
+ setProp((prop) => (prop.label = e.target.value))
148
+ }
149
+ />
150
+ </OrFormula>
151
+ </td>
152
+ </tr>
153
+ <tr>
154
+ <td colSpan="2">
155
+ <label>Extra state Formula</label>
156
+ <input
157
+ type="text"
158
+ className="viewlink-label form-control"
159
+ value={extra_state_fml}
160
+ onChange={(e) =>
161
+ setProp((prop) => (prop.extra_state_fml = e.target.value))
162
+ }
163
+ />
164
+ </td>
165
+ </tr>
166
+
167
+ <ButtonOrLinkSettingsRows
168
+ setProp={setProp}
169
+ keyPrefix="link_"
170
+ btnClass="btn"
171
+ values={node}
172
+ linkFirst={true}
173
+ />
174
+ </tbody>
175
+ </table>
176
+ <div className="form-check">
177
+ <input
178
+ className="form-check-input"
179
+ name="block"
180
+ type="checkbox"
181
+ checked={inModal}
182
+ onChange={(e) => setProp((prop) => (prop.inModal = e.target.checked))}
183
+ />
184
+ <label className="form-check-label">Open in popup modal?</label>
185
+ </div>
186
+ <BlockSetting block={block} setProp={setProp} />
187
+ <TextStyleSetting textStyle={textStyle} setProp={setProp} />
188
+ <table>
189
+ <tbody>
190
+ <MinRoleSettingRow minRole={minRole} setProp={setProp} />
191
+ </tbody>
192
+ </table>
193
+ </div>
194
+ );
195
+ };
196
+
197
+ /**
198
+ * @type {object}
199
+ */
200
+ ViewLink.craft = {
201
+ displayName: "ViewLink",
202
+ defaultProps: {
203
+ isFormula: {},
204
+ },
205
+ related: {
206
+ settings: ViewLinkSettings,
207
+ segment_type: "view_link",
208
+ column_type: "ViewLink",
209
+ fields: [
210
+ { name: "name", segment_name: "view", column_name: "view" },
211
+ { name: "label", segment_name: "view_label", canBeFormula: true },
212
+ "block",
213
+ "textStyle",
214
+ { name: "inModal", segment_name: "in_modal", column_name: "in_modal" },
215
+ "minRole",
216
+ "link_style",
217
+ "link_icon",
218
+ "link_size",
219
+ "link_bgcol",
220
+ "link_bordercol",
221
+ "link_textcol",
222
+ "extra_state_fml",
223
+ ],
224
+ },
225
+ };