@builder.io/sdk-svelte 0.0.1-3 → 0.0.1-30

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 (77) hide show
  1. package/README.md +19 -0
  2. package/package.json +8 -1
  3. package/src/blocks/button/button.svelte +25 -47
  4. package/src/blocks/columns/columns.svelte +115 -102
  5. package/src/blocks/columns/component-info.js +25 -1
  6. package/src/blocks/custom-code/custom-code.svelte +59 -61
  7. package/src/blocks/embed/component-info.js +20 -1
  8. package/src/blocks/embed/embed.svelte +38 -56
  9. package/src/blocks/embed/helpers.js +9 -0
  10. package/src/blocks/form/form.svelte +264 -294
  11. package/src/blocks/fragment/fragment.svelte +1 -25
  12. package/src/blocks/image/component-info.js +47 -1
  13. package/src/blocks/image/image.helpers.js +48 -0
  14. package/src/blocks/image/image.svelte +126 -116
  15. package/src/blocks/img/img.svelte +25 -35
  16. package/src/blocks/input/input.svelte +17 -30
  17. package/src/blocks/raw-text/raw-text.svelte +4 -25
  18. package/src/blocks/section/section.svelte +20 -35
  19. package/src/blocks/select/select.svelte +16 -36
  20. package/src/blocks/submit-button/submit-button.svelte +4 -29
  21. package/src/blocks/symbol/component-info.js +1 -0
  22. package/src/blocks/symbol/symbol.svelte +67 -52
  23. package/src/blocks/text/text.svelte +1 -24
  24. package/src/blocks/textarea/textarea.svelte +5 -28
  25. package/src/blocks/video/video.svelte +60 -41
  26. package/src/components/render-block/block-styles.svelte +54 -50
  27. package/src/components/render-block/render-block.helpers.js +23 -0
  28. package/src/components/render-block/render-block.svelte +199 -159
  29. package/src/components/render-block/render-component.svelte +20 -0
  30. package/src/components/render-block/render-repeated-block.svelte +29 -0
  31. package/src/components/render-block/types.js +0 -0
  32. package/src/components/render-blocks.svelte +74 -79
  33. package/src/components/render-content/components/render-styles.svelte +43 -63
  34. package/src/components/render-content/index.js +4 -0
  35. package/src/components/render-content/render-content.svelte +266 -207
  36. package/src/components/render-inlined-styles.svelte +15 -43
  37. package/src/constants/builder-registered-components.js +48 -0
  38. package/src/constants/device-sizes.js +3 -21
  39. package/src/context/builder.context.js +7 -1
  40. package/src/functions/camel-to-kebab-case.js +4 -0
  41. package/src/functions/convert-style-object.js +6 -0
  42. package/src/functions/get-block-component-options.js +6 -1
  43. package/src/functions/get-block-styles.js +7 -4
  44. package/src/functions/get-builder-search-params/index.js +12 -1
  45. package/src/functions/get-content/ab-testing.js +38 -0
  46. package/src/functions/get-content/fn.test.js +1 -1
  47. package/src/functions/get-content/index.js +16 -58
  48. package/src/functions/get-content/types.js +0 -0
  49. package/src/functions/get-processed-block.js +15 -8
  50. package/src/functions/get-processed-block.test.js +2 -1
  51. package/src/functions/register-component.js +45 -26
  52. package/src/functions/sanitize-styles.js +5 -0
  53. package/src/helpers/css.js +12 -0
  54. package/src/helpers/flatten.js +34 -0
  55. package/src/index-helpers/blocks-exports.js +10 -8
  56. package/src/types/components.js +0 -0
  57. package/src/types/element.js +0 -0
  58. package/src/blocks/button/index.js +0 -7
  59. package/src/blocks/columns/index.js +0 -7
  60. package/src/blocks/custom-code/index.js +0 -7
  61. package/src/blocks/embed/index.js +0 -7
  62. package/src/blocks/form/index.js +0 -7
  63. package/src/blocks/fragment/index.js +0 -7
  64. package/src/blocks/image/index.js +0 -7
  65. package/src/blocks/img/index.js +0 -7
  66. package/src/blocks/input/index.js +0 -7
  67. package/src/blocks/raw-text/index.js +0 -7
  68. package/src/blocks/section/index.js +0 -7
  69. package/src/blocks/select/index.js +0 -7
  70. package/src/blocks/submit-button/index.js +0 -7
  71. package/src/blocks/symbol/index.js +0 -7
  72. package/src/blocks/text/index.js +0 -7
  73. package/src/blocks/textarea/index.js +0 -7
  74. package/src/blocks/video/index.js +0 -7
  75. package/src/components/error-boundary.svelte +0 -26
  76. package/src/functions/macro-eval.js +0 -5
  77. package/src/functions/previewing-model-name.js +0 -11
@@ -1,27 +1,20 @@
1
1
  <script>
2
-
3
-
4
-
5
-
6
- import RenderInlinedStyles, { } from '../../render-inlined-styles.svelte';
2
+ import RenderInlinedStyles from "../../render-inlined-styles.svelte";
7
3
 
8
-
4
+ export let cssCode;
5
+ export let customFonts;
9
6
 
10
-
7
+ const getCssFromFont = function getCssFromFont(font) {
8
+ // TODO: compute what font sizes are used and only load those.......
9
+ const family =
10
+ font.family +
11
+ (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
12
+ const name = family.split(",")[0];
13
+ const url = font.fileUrl ?? font?.files?.regular;
14
+ let str = "";
11
15
 
12
-
13
- export let cssCode;
14
- export let customFonts;
15
-
16
- function getCssFromFont(font) {
17
- // TODO: compute what font sizes are used and only load those.......
18
- const family = font.family + (font.kind && !font.kind.includes('#') ? ', ' + font.kind : '');
19
- const name = family.split(',')[0];
20
- const url = font.fileUrl ?? font?.files?.regular;
21
- let str = '';
22
-
23
- if (url && family && name) {
24
- str += `
16
+ if (url && family && name) {
17
+ str += `
25
18
  @font-face {
26
19
  font-family: "${family}";
27
20
  src: local("${name}"), url('${url}') format('woff2');
@@ -29,21 +22,20 @@ if (url && family && name) {
29
22
  font-weight: 400;
30
23
  }
31
24
  `.trim();
32
- }
33
-
34
- if (font.files) {
35
- for (const weight in font.files) {
36
- const isNumber = String(Number(weight)) === weight;
25
+ }
37
26
 
38
- if (!isNumber) {
39
- continue;
40
- } // TODO: maybe limit number loaded
27
+ if (font.files) {
28
+ for (const weight in font.files) {
29
+ const isNumber = String(Number(weight)) === weight;
41
30
 
31
+ if (!isNumber) {
32
+ continue;
33
+ } // TODO: maybe limit number loaded
42
34
 
43
- const weightUrl = font.files[weight];
35
+ const weightUrl = font.files[weight];
44
36
 
45
- if (weightUrl && weightUrl !== url) {
46
- str += `
37
+ if (weightUrl && weightUrl !== url) {
38
+ str += `
47
39
  @font-face {
48
40
  font-family: "${family}";
49
41
  src: url('${weightUrl}') format('woff2');
@@ -51,40 +43,28 @@ if (font.files) {
51
43
  font-weight: ${weight};
52
44
  }
53
45
  `.trim();
46
+ }
47
+ }
54
48
  }
55
- }
56
- }
57
49
 
58
- return str;
59
- }
60
-
61
- function getFontCss({
62
- customFonts
63
- }) {
64
- // TODO: flag for this
65
- // if (!builder.allowCustomFonts) {
66
- // return '';
67
- // }
68
- // TODO: separate internal data from external
69
- return customFonts?.map(font => getCssFromFont(font))?.join(' ') || '';
70
- }
71
- $: injectedStyles = () => {
72
- return `
73
- ${cssCode || ''}
50
+ return str;
51
+ };
52
+
53
+ const getFontCss = function getFontCss({ customFonts }) {
54
+ // TODO: flag for this
55
+ // if (!builder.allowCustomFonts) {
56
+ // return '';
57
+ // }
58
+ // TODO: separate internal data from external
59
+ return customFonts?.map((font) => getCssFromFont(font))?.join(" ") || "";
60
+ };
61
+ $: injectedStyles = () => {
62
+ return `
63
+ ${cssCode || ""}
74
64
  ${getFontCss({
75
- customFonts: customFonts
65
+ customFonts: customFonts,
76
66
  })}`;
77
- };
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
- </script>
67
+ };
68
+ </script>
89
69
 
90
- <RenderInlinedStyles styles={injectedStyles()} ></RenderInlinedStyles>
70
+ <RenderInlinedStyles styles={injectedStyles()} />
@@ -0,0 +1,4 @@
1
+ import { default as default2 } from "./render-content.svelte";
2
+ export {
3
+ default2 as default
4
+ };
@@ -1,228 +1,287 @@
1
1
  <script>
2
- import { onMount } from 'svelte'
3
- import { afterUpdate } from 'svelte'
4
- import { onDestroy } from 'svelte'
5
-
6
- import { TARGET } from '../../constants/target.js';
7
- import BuilderContext, { } from '../../context/builder.context';
8
- import { evaluate } from '../../functions/evaluate.js';
9
- import { convertSearchParamsToQueryObject , getBuilderSearchParams } from '../../functions/get-builder-search-params/index.js';
10
- import { getContent } from '../../functions/get-content/index.js';
11
- import { getFetch } from '../../functions/get-fetch.js';
12
- import { isBrowser } from '../../functions/is-browser.js';
13
- import { isEditing } from '../../functions/is-editing.js';
14
- import { isPreviewing } from '../../functions/is-previewing.js';
15
- import { previewingModelName } from '../../functions/previewing-model-name.js';
16
- import { track } from '../../functions/track.js';
17
- import RenderBlocks, { } from '../render-blocks.svelte';
18
- import RenderContentStyles, { } from './components/render-styles.svelte';
19
-
20
-
21
-
22
- import { getContext, setContext } from "svelte";
23
-
24
-
25
- export let content;
26
- export let data;
27
- export let model;
28
- export let apiKey;
29
-
30
- function processMessage(event) {
31
- const {
32
- data
33
- } = event;
34
-
35
- if (data) {
36
- switch (data.type) {
37
- case 'builder.contentUpdate':
38
- {
39
- const messageContent = data.data;
40
- const key = messageContent.key || messageContent.alias || messageContent.entry || messageContent.modelName;
41
- const contentData = messageContent.data;
42
-
43
- if (key === model) {
44
- overrideContent = contentData;
2
+ import { onMount } from "svelte";
3
+ import { afterUpdate } from "svelte";
4
+ import { onDestroy } from "svelte";
5
+
6
+ import { getDefaultRegisteredComponents } from "../../constants/builder-registered-components.js";
7
+ import { TARGET } from "../../constants/target.js";
8
+ import BuilderContext from "../../context/builder.context";
9
+ import { evaluate } from "../../functions/evaluate.js";
10
+ import { getContent } from "../../functions/get-content/index.js";
11
+ import { getFetch } from "../../functions/get-fetch.js";
12
+ import { isBrowser } from "../../functions/is-browser.js";
13
+ import { isEditing } from "../../functions/is-editing.js";
14
+ import { isPreviewing } from "../../functions/is-previewing.js";
15
+ import {
16
+ components,
17
+ createRegisterComponentMessage,
18
+ } from "../../functions/register-component.js";
19
+ import { track } from "../../functions/track.js";
20
+ import RenderBlocks from "../render-blocks.svelte";
21
+ import RenderContentStyles from "./components/render-styles.svelte";
22
+
23
+ import { getContext, setContext } from "svelte";
24
+
25
+ export let content;
26
+ export let data;
27
+ export let context;
28
+ export let customComponents;
29
+ export let model;
30
+ export let canTrack;
31
+ export let apiKey;
32
+
33
+ const processMessage = function processMessage(event) {
34
+ const { data } = event;
35
+
36
+ if (data) {
37
+ switch (data.type) {
38
+ case "builder.contentUpdate": {
39
+ const messageContent = data.data;
40
+ const key =
41
+ messageContent.key ||
42
+ messageContent.alias ||
43
+ messageContent.entry ||
44
+ messageContent.modelName;
45
+ const contentData = messageContent.data;
46
+
47
+ if (key === model) {
48
+ overrideContent = contentData;
49
+ }
50
+
51
+ break;
45
52
  }
46
53
 
47
- break;
48
- }
49
-
50
- case 'builder.patchUpdates':
51
- {
52
- // TODO
53
- break;
54
+ case "builder.patchUpdates": {
55
+ // TODO
56
+ break;
57
+ }
54
58
  }
55
- }
56
- }
57
- }
58
-
59
- function evaluateJsCode() {
60
- // run any dynamic JS code attached to content
61
- const jsCode = useContent?.()?.data?.jsCode;
62
-
63
- if (jsCode) {
64
- evaluate({
65
- code: jsCode,
66
- context: context(),
67
- state: contentState()
68
- });
69
- }
70
- }
71
-
72
- function evalExpression(expression) {
73
- return expression.replace(/{{([^}]+)}}/g, (_match, group) => evaluate({
74
- code: group,
75
- context: context(),
76
- state: contentState()
77
- }));
78
- }
79
-
80
- function handleRequest({
81
- url,
82
- key
83
- }) {
84
- const fetchAndSetState = async () => {
85
- const fetch = await getFetch();
86
- const response = await fetch(url);
87
- const json = await response.json();
88
- const newOverrideState = { ...overrideState,
89
- [key]: json
59
+ }
90
60
  };
91
- overrideState = newOverrideState;
92
- };
93
-
94
- fetchAndSetState();
95
- }
96
-
97
- function runHttpRequests() {
98
- const requests = useContent?.()?.data?.httpRequests ?? {};
99
- Object.entries(requests).forEach(([key, url]) => {
100
- if (url && (!httpReqsData()[key] || isEditing())) {
101
- const evaluatedUrl = evalExpression(url);
102
- handleRequest({
103
- url: evaluatedUrl,
104
- key
105
- });
106
- }
107
- });
108
- }
109
-
110
- function emitStateUpdate() {
111
- window.dispatchEvent(new CustomEvent('builder:component:stateChange', {
112
- detail: {
113
- state: contentState(),
114
- ref: {
115
- name: model
61
+
62
+ const evaluateJsCode = function evaluateJsCode() {
63
+ // run any dynamic JS code attached to content
64
+ const jsCode = useContent?.()?.data?.jsCode;
65
+
66
+ if (jsCode) {
67
+ evaluate({
68
+ code: jsCode,
69
+ context: contextContext(),
70
+ state: contentState(),
71
+ });
116
72
  }
117
- }
118
- }));
119
- }
120
- $: useContent = () => {
121
- const mergedContent = { ...content,
122
- ...overrideContent,
123
- data: { ...content?.data,
124
- ...data,
125
- ...overrideContent?.data
126
- }
127
- };
128
- return mergedContent;
129
- };
130
-
131
- $: contentState = () => {
132
- return { ...content?.data?.state,
133
- ...data,
134
- ...overrideState
135
- };
136
- };
137
-
138
- $: context = () => {
139
- return {};
140
- };
141
-
142
- $: httpReqsData = () => {
143
- return {};
144
- };
145
-
146
-
147
- setContext(BuilderContext.key, { get content() {
148
- return useContent();
149
- }, get state() {
150
- return contentState();
151
- }, get context() {
152
- return context();
153
- }, get apiKey() {
154
- return apiKey;
155
- },});
156
- let overrideContent = null;
157
- let update = 0;
158
- let overrideState = {};
159
-
160
- onMount(() => { if (isBrowser()) {
161
- if (isEditing()) {
162
- window.addEventListener('message', processMessage);
163
- window.addEventListener('builder:component:stateChangeListenerActivated', emitStateUpdate);
164
- }
165
-
166
- if (useContent()) {
167
- track('impression', {
168
- contentId: useContent().id
169
- });
170
- } // override normal content in preview mode
171
-
172
-
173
- if (isPreviewing()) {
174
- if (model && previewingModelName() === model) {
175
- const currentUrl = new URL(location.href);
176
- const previewApiKey = currentUrl.searchParams.get('apiKey');
177
-
178
- if (previewApiKey) {
179
- getContent({
180
- model: model,
181
- apiKey: previewApiKey,
182
- options: getBuilderSearchParams(convertSearchParamsToQueryObject(currentUrl.searchParams))
183
- }).then(content => {
184
- if (content) {
185
- overrideContent = content;
186
- }
73
+ };
74
+
75
+ const onClick = function onClick(_event) {
76
+ if (useContent() && canTrack !== false) {
77
+ track("click", {
78
+ contentId: useContent().id,
187
79
  });
188
80
  }
189
- }
190
- }
81
+ };
191
82
 
192
- evaluateJsCode();
193
- runHttpRequests();
194
- emitStateUpdate();
195
- } });
83
+ const evalExpression = function evalExpression(expression) {
84
+ return expression.replace(/{{([^}]+)}}/g, (_match, group) =>
85
+ evaluate({
86
+ code: group,
87
+ context: contextContext(),
88
+ state: contentState(),
89
+ })
90
+ );
91
+ };
196
92
 
197
- afterUpdate(() => { evaluateJsCode(); });afterUpdate(() => { runHttpRequests(); });afterUpdate(() => { emitStateUpdate(); })
93
+ const handleRequest = function handleRequest({ url, key }) {
94
+ const fetchAndSetState = async () => {
95
+ const fetch = await getFetch();
96
+ const response = await fetch(url);
97
+ const json = await response.json();
98
+ const newOverrideState = { ...overrideState, [key]: json };
99
+ overrideState = newOverrideState;
100
+ };
198
101
 
199
- onDestroy(() => { if (isBrowser()) {
200
- window.removeEventListener('message', processMessage);
201
- window.removeEventListener('builder:component:stateChangeListenerActivated', emitStateUpdate);
202
- } });
203
- </script>
102
+ fetchAndSetState();
103
+ };
104
+
105
+ const runHttpRequests = function runHttpRequests() {
106
+ const requests = useContent?.()?.data?.httpRequests ?? {};
107
+ Object.entries(requests).forEach(([key, url]) => {
108
+ if (url && (!httpReqsData()[key] || isEditing())) {
109
+ const evaluatedUrl = evalExpression(url);
110
+ handleRequest({
111
+ url: evaluatedUrl,
112
+ key,
113
+ });
114
+ }
115
+ });
116
+ };
204
117
 
205
-
206
- {#if useContent() }
118
+ const emitStateUpdate = function emitStateUpdate() {
119
+ if (isEditing()) {
120
+ window.dispatchEvent(
121
+ new CustomEvent("builder:component:stateChange", {
122
+ detail: {
123
+ state: contentState(),
124
+ ref: {
125
+ name: model,
126
+ },
127
+ },
128
+ })
129
+ );
130
+ }
131
+ };
132
+ $: useContent = () => {
133
+ const mergedContent = {
134
+ ...content,
135
+ ...overrideContent,
136
+ data: { ...content?.data, ...data, ...overrideContent?.data },
137
+ };
138
+ return mergedContent;
139
+ };
207
140
 
208
-
209
- <div on:click="{event => track('click', {
210
- contentId: useContent().id
211
- })}" data-builder-content-id={useContent?.()?.id} >
212
-
141
+ $: contentState = () => {
142
+ return { ...content?.data?.state, ...data, ...overrideState };
143
+ };
213
144
 
214
- {#if (useContent?.()?.data?.cssCode || useContent?.()?.data?.customFonts?.length) && TARGET !== 'reactNative' }
215
- <RenderContentStyles cssCode={useContent().data.cssCode} customFonts={useContent().data.customFonts} ></RenderContentStyles>
145
+ $: contextContext = () => {
146
+ return context || {};
147
+ };
216
148
 
149
+ $: allRegisteredComponents = () => {
150
+ const allComponentsArray = [
151
+ ...getDefaultRegisteredComponents(), // While this `components` object is deprecated, we must maintain support for it.
152
+ // Since users are able to override our default components, we need to make sure that we do not break such
153
+ // existing usage.
154
+ // This is why we spread `components` after the default Builder.io components, but before the `customComponents`,
155
+ // which is the new standard way of providing custom components, and must therefore take precedence.
156
+ ...components,
157
+ ...(customComponents || []),
158
+ ];
159
+ const allComponents = allComponentsArray.reduce(
160
+ (acc, curr) => ({ ...acc, [curr.name]: curr }),
161
+ {}
162
+ );
163
+ return allComponents;
164
+ };
217
165
 
218
- {/if}
166
+ $: httpReqsData = () => {
167
+ return {};
168
+ };
219
169
 
220
-
221
- <RenderBlocks blocks={useContent?.()?.data?.blocks} ></RenderBlocks>
170
+ $: shouldRenderContentStyles = () => {
171
+ return Boolean(
172
+ (useContent?.()?.data?.cssCode ||
173
+ useContent?.()?.data?.customFonts?.length) &&
174
+ TARGET !== "reactNative"
175
+ );
176
+ };
222
177
 
223
- </div>
178
+ setContext(BuilderContext.key, {
179
+ get content() {
180
+ return useContent();
181
+ },
182
+ get state() {
183
+ return contentState();
184
+ },
185
+ get context() {
186
+ return contextContext();
187
+ },
188
+ get apiKey() {
189
+ return apiKey;
190
+ },
191
+ get registeredComponents() {
192
+ return allRegisteredComponents();
193
+ },
194
+ });
195
+ let overrideContent = null;
196
+ let update = 0;
197
+ let overrideState = {};
198
+
199
+ onMount(() => {
200
+ if (isBrowser()) {
201
+ if (isEditing()) {
202
+ Object.values(allRegisteredComponents()).forEach(
203
+ (registeredComponent) => {
204
+ const message = createRegisterComponentMessage(registeredComponent);
205
+ window.parent?.postMessage(message, "*");
206
+ }
207
+ );
208
+ window.addEventListener("message", processMessage);
209
+ window.addEventListener(
210
+ "builder:component:stateChangeListenerActivated",
211
+ emitStateUpdate
212
+ );
213
+ }
224
214
 
225
-
215
+ if (useContent() && canTrack !== false) {
216
+ track("impression", {
217
+ contentId: useContent().id,
218
+ });
219
+ } // override normal content in preview mode
220
+
221
+ if (isPreviewing()) {
222
+ const searchParams = new URL(location.href).searchParams;
223
+
224
+ if (model && searchParams.get("builder.preview") === model) {
225
+ const previewApiKey =
226
+ searchParams.get("apiKey") || searchParams.get("builder.space");
227
+
228
+ if (previewApiKey) {
229
+ getContent({
230
+ model: model,
231
+ apiKey: previewApiKey,
232
+ }).then((content) => {
233
+ if (content) {
234
+ overrideContent = content;
235
+ }
236
+ });
237
+ }
238
+ }
239
+ }
226
240
 
241
+ evaluateJsCode();
242
+ runHttpRequests();
243
+ emitStateUpdate();
244
+ }
245
+ });
227
246
 
228
- {/if}
247
+ function onUpdateFn_0() {
248
+ evaluateJsCode();
249
+ }
250
+ $: onUpdateFn_0(...[useContent?.()?.data?.jsCode]);
251
+ function onUpdateFn_1() {
252
+ runHttpRequests();
253
+ }
254
+ $: onUpdateFn_1(...[useContent?.()?.data?.httpRequests]);
255
+ function onUpdateFn_2() {
256
+ emitStateUpdate();
257
+ }
258
+ $: onUpdateFn_2(...[contentState()]);
259
+
260
+ onDestroy(() => {
261
+ if (isBrowser()) {
262
+ window.removeEventListener("message", processMessage);
263
+ window.removeEventListener(
264
+ "builder:component:stateChangeListenerActivated",
265
+ emitStateUpdate
266
+ );
267
+ }
268
+ });
269
+ </script>
270
+
271
+ {#if useContent()}
272
+ <div
273
+ on:click={(event) => {
274
+ onClick(event);
275
+ }}
276
+ builder-content-id={useContent?.()?.id}
277
+ >
278
+ {#if shouldRenderContentStyles()}
279
+ <RenderContentStyles
280
+ cssCode={useContent?.()?.data?.cssCode}
281
+ customFonts={useContent?.()?.data?.customFonts}
282
+ />
283
+ {/if}
284
+
285
+ <RenderBlocks blocks={useContent?.()?.data?.blocks} />
286
+ </div>
287
+ {/if}