@builder.io/sdk-solid 0.1.2 → 0.1.3

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/dist/sdk-solid.cjs +34 -0
  2. package/dist/sdk-solid.js +3937 -0
  3. package/package.json +5 -6
  4. package/src/blocks/BaseText.jsx +5 -1
  5. package/src/blocks/button/button.jsx +25 -7
  6. package/src/blocks/columns/columns.jsx +84 -38
  7. package/src/blocks/custom-code/custom-code.jsx +25 -3
  8. package/src/blocks/embed/embed.jsx +14 -2
  9. package/src/blocks/form/form.jsx +175 -121
  10. package/src/blocks/fragment/fragment.jsx +2 -1
  11. package/src/blocks/image/image.jsx +75 -38
  12. package/src/blocks/img/img.jsx +15 -5
  13. package/src/blocks/input/input.jsx +17 -2
  14. package/src/blocks/raw-text/raw-text.jsx +8 -2
  15. package/src/blocks/section/section.jsx +24 -14
  16. package/src/blocks/select/select.jsx +21 -6
  17. package/src/blocks/submit-button/submit-button.jsx +6 -3
  18. package/src/blocks/symbol/symbol.jsx +54 -15
  19. package/src/blocks/text/text.jsx +2 -1
  20. package/src/blocks/textarea/textarea.jsx +11 -2
  21. package/src/blocks/video/video.jsx +49 -27
  22. package/src/components/render-block/block-styles.jsx +45 -21
  23. package/src/components/render-block/render-block.helpers.js +90 -0
  24. package/src/components/render-block/render-block.jsx +110 -131
  25. package/src/components/render-block/render-component.jsx +26 -9
  26. package/src/components/render-block/render-repeated-block.jsx +20 -24
  27. package/src/components/render-blocks.jsx +70 -30
  28. package/src/components/render-content/builder-editing.jsx +2 -1
  29. package/src/components/render-content/components/render-styles.jsx +17 -8
  30. package/src/components/render-content/render-content.jsx +234 -148
  31. package/src/components/render-inlined-styles.jsx +14 -4
  32. package/src/functions/track/helpers.js +50 -0
  33. package/src/functions/{track.js → track/index.js} +10 -6
  34. package/src/functions/track/interaction.js +53 -0
  35. package/src/index.js +1 -1
  36. package/vite.config.ts +18 -0
  37. package/solid-index.jsx +0 -5
  38. package/src/components/render-block/render-component-with-context.jsx +0 -28
@@ -1,15 +1,22 @@
1
1
  import { useContext, Show, For, createSignal } from "solid-js";
2
+
2
3
  import { css } from "solid-styled-components";
4
+
3
5
  import RenderBlock from "../../components/render-block/render-block.jsx";
4
6
  import BuilderBlocks from "../../components/render-blocks.jsx";
5
7
  import { isEditing } from "../../functions/is-editing.js";
8
+
6
9
  function FormComponent(props) {
7
10
  const [formState, setFormState] = createSignal("unsubmitted");
11
+
8
12
  const [responseData, setResponseData] = createSignal(null);
13
+
9
14
  const [formErrorMessage, setFormErrorMessage] = createSignal("");
15
+
10
16
  function submissionState() {
11
- return isEditing() && props.previewState || formState();
17
+ return (isEditing() && props.previewState) || formState();
12
18
  }
19
+
13
20
  function onSubmit(event) {
14
21
  const sendWithJs = props.sendWithJs || props.sendSubmissionsTo === "email";
15
22
  if (props.sendSubmissionsTo === "zapier") {
@@ -26,47 +33,53 @@ function FormComponent(props) {
26
33
  const formData = new FormData(el);
27
34
 
28
35
  // TODO: maybe support null
29
- const formPairs = Array.from(event.currentTarget.querySelectorAll("input,select,textarea")).filter(el => !!el.name).map(el => {
30
- let value;
31
- const key = el.name;
32
- if (el instanceof HTMLInputElement) {
33
- if (el.type === "radio") {
34
- if (el.checked) {
35
- value = el.name;
36
- return {
37
- key,
38
- value
39
- };
40
- }
41
- } else if (el.type === "checkbox") {
42
- value = el.checked;
43
- } else if (el.type === "number" || el.type === "range") {
44
- const num = el.valueAsNumber;
45
- if (!isNaN(num)) {
46
- value = num;
36
+ const formPairs = Array.from(
37
+ event.currentTarget.querySelectorAll("input,select,textarea")
38
+ )
39
+ .filter((el) => !!el.name)
40
+ .map((el) => {
41
+ let value;
42
+ const key = el.name;
43
+ if (el instanceof HTMLInputElement) {
44
+ if (el.type === "radio") {
45
+ if (el.checked) {
46
+ value = el.name;
47
+ return {
48
+ key,
49
+ value,
50
+ };
51
+ }
52
+ } else if (el.type === "checkbox") {
53
+ value = el.checked;
54
+ } else if (el.type === "number" || el.type === "range") {
55
+ const num = el.valueAsNumber;
56
+ if (!isNaN(num)) {
57
+ value = num;
58
+ }
59
+ } else if (el.type === "file") {
60
+ // TODO: one vs multiple files
61
+ value = el.files;
62
+ } else {
63
+ value = el.value;
47
64
  }
48
- } else if (el.type === "file") {
49
- // TODO: one vs multiple files
50
- value = el.files;
51
65
  } else {
52
66
  value = el.value;
53
67
  }
54
- } else {
55
- value = el.value;
56
- }
57
- return {
58
- key,
59
- value
60
- };
61
- });
68
+ return {
69
+ key,
70
+ value,
71
+ };
72
+ });
62
73
  let contentType = props.contentType;
63
74
  if (props.sendSubmissionsTo === "email") {
64
75
  contentType = "multipart/form-data";
65
76
  }
66
- Array.from(formPairs).forEach(({
67
- value
68
- }) => {
69
- if (value instanceof File || Array.isArray(value) && value[0] instanceof File || value instanceof FileList) {
77
+ Array.from(formPairs).forEach(({ value }) => {
78
+ if (
79
+ value instanceof File ||
80
+ (Array.isArray(value) && value[0] instanceof File) ||
81
+ value instanceof FileList
82
+ ) {
70
83
  contentType = "multipart/form-data";
71
84
  }
72
85
  });
@@ -79,24 +92,23 @@ function FormComponent(props) {
79
92
  } else {
80
93
  // Json
81
94
  const json = {};
82
- Array.from(formPairs).forEach(({
83
- value,
84
- key
85
- }) => {
95
+ Array.from(formPairs).forEach(({ value, key }) => {
86
96
  set(json, key, value);
87
97
  });
88
98
  body = JSON.stringify(json);
89
99
  }
90
100
  if (contentType && contentType !== "multipart/form-data") {
91
- if ( /* Zapier doesn't allow content-type header to be sent from browsers */
92
- !(sendWithJs && props.action?.includes("zapier.com"))) {
101
+ if (
102
+ /* Zapier doesn't allow content-type header to be sent from browsers */
103
+ !(sendWithJs && props.action?.includes("zapier.com"))
104
+ ) {
93
105
  headers["content-type"] = contentType;
94
106
  }
95
107
  }
96
108
  const presubmitEvent = new CustomEvent("presubmit", {
97
109
  detail: {
98
- body
99
- }
110
+ body,
111
+ },
100
112
  });
101
113
  if (formRef) {
102
114
  formRef.dispatchEvent(presubmitEvent);
@@ -105,114 +117,156 @@ function FormComponent(props) {
105
117
  }
106
118
  }
107
119
  setFormState("sending");
108
- const formUrl = `${builder.env === "dev" ? "http://localhost:5000" : "https://builder.io"}/api/v1/form-submit?apiKey=${builder.apiKey}&to=${btoa(props.sendSubmissionsToEmail || "")}&name=${encodeURIComponent(props.name || "")}`;
109
- fetch(props.sendSubmissionsTo === "email" ? formUrl : props.action /* TODO: throw error if no action URL */, {
110
- body,
111
- headers,
112
- method: props.method || "post"
113
- }).then(async res => {
114
- let body;
115
- const contentType = res.headers.get("content-type");
116
- if (contentType && contentType.indexOf("application/json") !== -1) {
117
- body = await res.json();
118
- } else {
119
- body = await res.text();
120
+ const formUrl = `${
121
+ builder.env === "dev" ? "http://localhost:5000" : "https://builder.io"
122
+ }/api/v1/form-submit?apiKey=${builder.apiKey}&to=${btoa(
123
+ props.sendSubmissionsToEmail || ""
124
+ )}&name=${encodeURIComponent(props.name || "")}`;
125
+ fetch(
126
+ props.sendSubmissionsTo === "email"
127
+ ? formUrl
128
+ : props.action /* TODO: throw error if no action URL */,
129
+ {
130
+ body,
131
+ headers,
132
+ method: props.method || "post",
120
133
  }
121
- if (!res.ok && props.errorMessagePath) {
122
- /* TODO: allow supplying an error formatter function */
123
- let message = get(body, props.errorMessagePath);
124
- if (message) {
125
- if (typeof message !== "string") {
126
- /* TODO: ideally convert json to yaml so it woul dbe like
127
- error: - email has been taken */
128
- message = JSON.stringify(message);
129
- }
130
- setFormErrorMessage(message);
134
+ ).then(
135
+ async (res) => {
136
+ let body;
137
+ const contentType = res.headers.get("content-type");
138
+ if (contentType && contentType.indexOf("application/json") !== -1) {
139
+ body = await res.json();
140
+ } else {
141
+ body = await res.text();
131
142
  }
132
- }
133
- setResponseData(body);
134
- setFormState(res.ok ? "success" : "error");
135
- if (res.ok) {
136
- const submitSuccessEvent = new CustomEvent("submit:success", {
137
- detail: {
138
- res,
139
- body
140
- }
141
- });
142
- if (formRef) {
143
- formRef.dispatchEvent(submitSuccessEvent);
144
- if (submitSuccessEvent.defaultPrevented) {
145
- return;
146
- }
147
- /* TODO: option to turn this on/off? */
148
- if (props.resetFormOnSubmit !== false) {
149
- formRef.reset();
143
+ if (!res.ok && props.errorMessagePath) {
144
+ /* TODO: allow supplying an error formatter function */
145
+ let message = get(body, props.errorMessagePath);
146
+ if (message) {
147
+ if (typeof message !== "string") {
148
+ /* TODO: ideally convert json to yaml so it woul dbe like
149
+ error: - email has been taken */
150
+ message = JSON.stringify(message);
151
+ }
152
+ setFormErrorMessage(message);
150
153
  }
151
154
  }
152
-
153
- /* TODO: client side route event first that can be preventDefaulted */
154
- if (props.successUrl) {
155
+ setResponseData(body);
156
+ setFormState(res.ok ? "success" : "error");
157
+ if (res.ok) {
158
+ const submitSuccessEvent = new CustomEvent("submit:success", {
159
+ detail: {
160
+ res,
161
+ body,
162
+ },
163
+ });
155
164
  if (formRef) {
156
- const event = new CustomEvent("route", {
157
- detail: {
158
- url: props.successUrl
165
+ formRef.dispatchEvent(submitSuccessEvent);
166
+ if (submitSuccessEvent.defaultPrevented) {
167
+ return;
168
+ }
169
+ /* TODO: option to turn this on/off? */
170
+ if (props.resetFormOnSubmit !== false) {
171
+ formRef.reset();
172
+ }
173
+ }
174
+
175
+ /* TODO: client side route event first that can be preventDefaulted */
176
+ if (props.successUrl) {
177
+ if (formRef) {
178
+ const event = new CustomEvent("route", {
179
+ detail: {
180
+ url: props.successUrl,
181
+ },
182
+ });
183
+ formRef.dispatchEvent(event);
184
+ if (!event.defaultPrevented) {
185
+ location.href = props.successUrl;
159
186
  }
160
- });
161
- formRef.dispatchEvent(event);
162
- if (!event.defaultPrevented) {
187
+ } else {
163
188
  location.href = props.successUrl;
164
189
  }
165
- } else {
166
- location.href = props.successUrl;
167
190
  }
168
191
  }
169
- }
170
- }, err => {
171
- const submitErrorEvent = new CustomEvent("submit:error", {
172
- detail: {
173
- error: err
174
- }
175
- });
176
- if (formRef) {
177
- formRef.dispatchEvent(submitErrorEvent);
178
- if (submitErrorEvent.defaultPrevented) {
179
- return;
192
+ },
193
+ (err) => {
194
+ const submitErrorEvent = new CustomEvent("submit:error", {
195
+ detail: {
196
+ error: err,
197
+ },
198
+ });
199
+ if (formRef) {
200
+ formRef.dispatchEvent(submitErrorEvent);
201
+ if (submitErrorEvent.defaultPrevented) {
202
+ return;
203
+ }
180
204
  }
205
+ setResponseData(err);
206
+ setFormState("error");
181
207
  }
182
- setResponseData(err);
183
- setFormState("error");
184
- });
208
+ );
185
209
  }
186
210
  }
211
+
187
212
  let formRef;
213
+
188
214
  const builderContext = useContext(BuilderContext);
189
- return <form validate={props.validate} ref={formRef} action={!props.sendWithJs && props.action} method={props.method} name={props.name} onSubmit={event => onSubmit(event)} {...props.attributes}>
215
+
216
+ return (
217
+ <form
218
+ validate={props.validate}
219
+ ref={formRef}
220
+ action={!props.sendWithJs && props.action}
221
+ method={props.method}
222
+ name={props.name}
223
+ onSubmit={(event) => onSubmit(event)}
224
+ {...props.attributes}
225
+ >
190
226
  <Show when={props.builderBlock && props.builderBlock.children}>
191
227
  <For each={props.builderBlock?.children}>
192
228
  {(block, _index) => {
193
- const index = _index();
194
- return <RenderBlock block={block} context={builderContext}></RenderBlock>;
195
- }}
229
+ const index = _index();
230
+ return (
231
+ <RenderBlock block={block} context={builderContext}></RenderBlock>
232
+ );
233
+ }}
196
234
  </For>
197
235
  </Show>
198
236
  <Show when={submissionState() === "error"}>
199
- <BuilderBlocks dataPath="errorMessage" blocks={props.errorMessage}></BuilderBlocks>
237
+ <BuilderBlocks
238
+ dataPath="errorMessage"
239
+ blocks={props.errorMessage}
240
+ ></BuilderBlocks>
200
241
  </Show>
201
242
  <Show when={submissionState() === "sending"}>
202
- <BuilderBlocks dataPath="sendingMessage" blocks={props.sendingMessage}></BuilderBlocks>
243
+ <BuilderBlocks
244
+ dataPath="sendingMessage"
245
+ blocks={props.sendingMessage}
246
+ ></BuilderBlocks>
203
247
  </Show>
204
248
  <Show when={submissionState() === "error" && responseData()}>
205
- <pre class={"builder-form-error-text " + css({
206
- padding: "10px",
207
- color: "red",
208
- textAlign: "center"
209
- })}>
249
+ <pre
250
+ class={
251
+ "builder-form-error-text " +
252
+ css({
253
+ padding: "10px",
254
+ color: "red",
255
+ textAlign: "center",
256
+ })
257
+ }
258
+ >
210
259
  {JSON.stringify(responseData(), null, 2)}
211
260
  </pre>
212
261
  </Show>
213
262
  <Show when={submissionState() === "success"}>
214
- <BuilderBlocks dataPath="successMessage" blocks={props.successMessage}></BuilderBlocks>
263
+ <BuilderBlocks
264
+ dataPath="successMessage"
265
+ blocks={props.successMessage}
266
+ ></BuilderBlocks>
215
267
  </Show>
216
- </form>;
268
+ </form>
269
+ );
217
270
  }
218
- export default FormComponent;
271
+
272
+ export default FormComponent;
@@ -1,4 +1,5 @@
1
1
  function FragmentComponent(props) {
2
2
  return <span>{props.children}</span>;
3
3
  }
4
- export default FragmentComponent;
4
+
5
+ export default FragmentComponent;
@@ -1,14 +1,19 @@
1
- import { Show } from "solid-js";
1
+ import { Show, createSignal } from "solid-js";
2
+
2
3
  import { css } from "solid-styled-components";
4
+
3
5
  import { getSrcSet } from "./image.helpers.js";
6
+
4
7
  function Image(props) {
5
8
  function srcSetToUse() {
6
9
  const imageToUse = props.image || props.src;
7
10
  const url = imageToUse;
8
- if (!url ||
9
- // We can auto add srcset for cdn.builder.io and shopify
10
- // images, otherwise you can supply this prop manually
11
- !(url.match(/builder\.io/) || url.match(/cdn\.shopify\.com/))) {
11
+ if (
12
+ !url ||
13
+ // We can auto add srcset for cdn.builder.io and shopify
14
+ // images, otherwise you can supply this prop manually
15
+ !(url.match(/builder\.io/) || url.match(/cdn\.shopify\.com/))
16
+ ) {
12
17
  return props.srcset;
13
18
  }
14
19
  if (props.srcset && props.image?.includes("builder.io/api/v1/image")) {
@@ -21,6 +26,7 @@ function Image(props) {
21
26
  }
22
27
  return getSrcSet(url);
23
28
  }
29
+
24
30
  function webpSrcSet() {
25
31
  if (srcSetToUse()?.match(/builder\.io/) && !props.noWebp) {
26
32
  return srcSetToUse().replace(/\?/g, "?format=webp&");
@@ -28,60 +34,91 @@ function Image(props) {
28
34
  return "";
29
35
  }
30
36
  }
37
+
31
38
  function aspectRatioCss() {
32
39
  const aspectRatioStyles = {
33
40
  position: "absolute",
34
41
  height: "100%",
35
42
  width: "100%",
36
43
  left: "0px",
37
- top: "0px"
44
+ top: "0px",
38
45
  };
39
46
  const out = props.aspectRatio ? aspectRatioStyles : undefined;
40
47
  return out;
41
48
  }
42
- return <>
49
+
50
+ return (
51
+ <>
43
52
  <picture>
44
53
  <Show when={webpSrcSet()}>
45
54
  <source type="image/webp" srcset={webpSrcSet()} />
46
55
  </Show>
47
- <img class={"builder-image" + (props.className ? " " + props.className : "") + " " + css({
48
- opacity: "1",
49
- transition: "opacity 0.2s ease-in-out"
50
- })} loading="lazy" alt={props.altText} role={props.altText ? "presentation" : undefined} style={{
51
- "object-position": props.backgroundPosition || "center",
52
- "object-fit": props.backgroundSize || "cover",
53
- ...aspectRatioCss()
54
- }} src={props.image} srcset={srcSetToUse()} sizes={props.sizes} />
55
- <source srcset={srcSetToUse()} />
56
+ <img
57
+ class={
58
+ "builder-image" +
59
+ (props.className ? " " + props.className : "") +
60
+ " " +
61
+ css({
62
+ opacity: "1",
63
+ transition: "opacity 0.2s ease-in-out",
64
+ })
65
+ }
66
+ loading="lazy"
67
+ alt={props.altText}
68
+ role={props.altText ? "presentation" : undefined}
69
+ style={{
70
+ "object-position": props.backgroundPosition || "center",
71
+ "object-fit": props.backgroundSize || "cover",
72
+ ...aspectRatioCss(),
73
+ }}
74
+ src={props.image}
75
+ srcset={srcSetToUse()}
76
+ sizes={props.sizes}
77
+ />
56
78
  </picture>
57
- <Show when={props.aspectRatio && !(props.builderBlock?.children?.length && props.fitContent)}>
58
- <div class={"builder-image-sizer " + css({
59
- width: "100%",
60
- pointerEvents: "none",
61
- fontSize: "0"
62
- })} style={{
63
- "padding-top":
64
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
65
- props.aspectRatio * 100 + "%"
66
- }}></div>
79
+ <Show
80
+ when={
81
+ props.aspectRatio &&
82
+ !(props.builderBlock?.children?.length && props.fitContent)
83
+ }
84
+ >
85
+ <div
86
+ class={
87
+ "builder-image-sizer " +
88
+ css({
89
+ width: "100%",
90
+ pointerEvents: "none",
91
+ fontSize: "0",
92
+ })
93
+ }
94
+ style={{
95
+ "padding-top":
96
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
97
+ props.aspectRatio * 100 + "%",
98
+ }}
99
+ ></div>
67
100
  </Show>
68
101
  <Show when={props.builderBlock?.children?.length && props.fitContent}>
69
102
  {props.children}
70
103
  </Show>
71
104
  <Show when={!props.fitContent && props.children}>
72
- <div class={css({
73
- display: "flex",
74
- flexDirection: "column",
75
- alignItems: "stretch",
76
- position: "absolute",
77
- top: "0",
78
- left: "0",
79
- width: "100%",
80
- height: "100%"
81
- })}>
105
+ <div
106
+ class={css({
107
+ display: "flex",
108
+ flexDirection: "column",
109
+ alignItems: "stretch",
110
+ position: "absolute",
111
+ top: "0",
112
+ left: "0",
113
+ width: "100%",
114
+ height: "100%",
115
+ })}
116
+ >
82
117
  {props.children}
83
118
  </div>
84
119
  </Show>
85
- </>;
120
+ </>
121
+ );
86
122
  }
87
- export default Image;
123
+
124
+ export default Image;
@@ -1,8 +1,18 @@
1
1
  import { isEditing } from "../../functions/is-editing.js";
2
+
2
3
  function ImgComponent(props) {
3
- return <img style={{
4
- "object-fit": props.backgroundSize || "cover",
5
- "object-position": props.backgroundPosition || "center"
6
- }} key={isEditing() && props.imgSrc || "default-key"} alt={props.altText} src={props.imgSrc || props.image} {...props.attributes} />;
4
+ return (
5
+ <img
6
+ style={{
7
+ "object-fit": props.backgroundSize || "cover",
8
+ "object-position": props.backgroundPosition || "center",
9
+ }}
10
+ key={(isEditing() && props.imgSrc) || "default-key"}
11
+ alt={props.altText}
12
+ src={props.imgSrc || props.image}
13
+ {...props.attributes}
14
+ />
15
+ );
7
16
  }
8
- export default ImgComponent;
17
+
18
+ export default ImgComponent;
@@ -1,5 +1,20 @@
1
1
  import { isEditing } from "../../functions/is-editing.js";
2
+
2
3
  function FormInputComponent(props) {
3
- return <input {...props.attributes} key={isEditing() && props.defaultValue ? props.defaultValue : "default-key"} placeholder={props.placeholder} type={props.type} name={props.name} value={props.value} defaultValue={props.defaultValue} required={props.required} />;
4
+ return (
5
+ <input
6
+ {...props.attributes}
7
+ key={
8
+ isEditing() && props.defaultValue ? props.defaultValue : "default-key"
9
+ }
10
+ placeholder={props.placeholder}
11
+ type={props.type}
12
+ name={props.name}
13
+ value={props.value}
14
+ defaultValue={props.defaultValue}
15
+ required={props.required}
16
+ />
17
+ );
4
18
  }
5
- export default FormInputComponent;
19
+
20
+ export default FormInputComponent;
@@ -1,4 +1,10 @@
1
1
  function RawText(props) {
2
- return <span class={props.attributes?.class || props.attributes?.className} innerHTML={props.text || ""}></span>;
2
+ return (
3
+ <span
4
+ class={props.attributes?.class || props.attributes?.className}
5
+ innerHTML={props.text || ""}
6
+ ></span>
7
+ );
3
8
  }
4
- export default RawText;
9
+
10
+ export default RawText;
@@ -1,17 +1,27 @@
1
1
  function SectionComponent(props) {
2
- return <section {...props.attributes} style={{
3
- width: "100%",
4
- "align-self": "stretch",
5
- "flex-grow": "1",
6
- "box-sizing": "border-box",
7
- "max-width": `${props.maxWidth && typeof props.maxWidth === "number" ? props.maxWidth : 1200}px`,
8
- display: "flex",
9
- "flex-direction": "column",
10
- "align-items": "stretch",
11
- "margin-left": "auto",
12
- "margin-right": "auto"
13
- }}>
2
+ return (
3
+ <section
4
+ {...props.attributes}
5
+ style={{
6
+ width: "100%",
7
+ "align-self": "stretch",
8
+ "flex-grow": "1",
9
+ "box-sizing": "border-box",
10
+ "max-width": `${
11
+ props.maxWidth && typeof props.maxWidth === "number"
12
+ ? props.maxWidth
13
+ : 1200
14
+ }px`,
15
+ display: "flex",
16
+ "flex-direction": "column",
17
+ "align-items": "stretch",
18
+ "margin-left": "auto",
19
+ "margin-right": "auto",
20
+ }}
21
+ >
14
22
  {props.children}
15
- </section>;
23
+ </section>
24
+ );
16
25
  }
17
- export default SectionComponent;
26
+
27
+ export default SectionComponent;