@builder.io/sdk-svelte 0.0.6 → 0.0.8

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 (80) hide show
  1. package/package/--package.json +3 -3
  2. package/package/blocks/button/button.svelte +35 -3
  3. package/package/blocks/columns/columns.svelte +1 -2
  4. package/package/blocks/columns/component-info.js +2 -2
  5. package/package/blocks/embed/component-info.js +2 -2
  6. package/package/blocks/form/form.svelte +29 -1
  7. package/package/blocks/image/component-info.js +2 -2
  8. package/package/blocks/img/img.svelte +29 -1
  9. package/package/blocks/input/input.svelte +29 -1
  10. package/package/blocks/section/section.svelte +30 -2
  11. package/package/blocks/select/select.svelte +29 -1
  12. package/package/blocks/submit-button/submit-button.svelte +33 -2
  13. package/package/blocks/symbol/symbol.svelte +33 -8
  14. package/package/blocks/textarea/textarea.svelte +36 -2
  15. package/package/blocks/util.d.ts +4 -1
  16. package/package/blocks/util.js +13 -4
  17. package/package/blocks/video/video.svelte +30 -2
  18. package/package/components/render-block/block-styles.svelte +5 -3
  19. package/package/components/render-block/render-block.svelte +36 -15
  20. package/package/components/render-block/render-component.svelte +1 -2
  21. package/package/components/render-content/builder-editing.svelte +4 -0
  22. package/package/components/render-content/builder-editing.svelte.d.ts +14 -0
  23. package/package/components/render-content/render-content.svelte +6 -5
  24. package/package/components/render-inlined-styles.svelte +3 -3
  25. package/package/constants/device-sizes.d.ts +12 -1
  26. package/package/constants/device-sizes.js +27 -1
  27. package/package/functions/evaluate.d.ts +2 -1
  28. package/package/functions/evaluate.js +8 -5
  29. package/package/functions/event-handler-name.js +1 -4
  30. package/package/functions/get-block-actions-handler.d.ts +5 -2
  31. package/package/functions/get-block-actions-handler.js +7 -8
  32. package/package/functions/get-block-actions.js +2 -2
  33. package/package/functions/get-builder-search-params/index.d.ts +1 -1
  34. package/package/functions/get-content/index.js +5 -2
  35. package/package/functions/get-content/types.d.ts +4 -0
  36. package/package/functions/register-component.js +1 -13
  37. package/package/functions/track.d.ts +6 -1
  38. package/package/functions/track.js +4 -0
  39. package/package/index.d.ts +3 -1
  40. package/package/index.js +1 -1
  41. package/package/scripts/init-editing.js +6 -0
  42. package/package/types/builder-content.d.ts +7 -0
  43. package/package.json +2 -2
  44. package/src/blocks/button/button.svelte +41 -2
  45. package/src/blocks/columns/columns.svelte +1 -2
  46. package/src/blocks/columns/component-info.ts +2 -2
  47. package/src/blocks/embed/component-info.ts +2 -2
  48. package/src/blocks/form/form.svelte +36 -1
  49. package/src/blocks/image/component-info.ts +2 -2
  50. package/src/blocks/img/img.svelte +36 -1
  51. package/src/blocks/input/input.svelte +36 -1
  52. package/src/blocks/section/section.svelte +36 -1
  53. package/src/blocks/select/select.svelte +36 -1
  54. package/src/blocks/submit-button/submit-button.svelte +39 -1
  55. package/src/blocks/symbol/symbol.svelte +40 -8
  56. package/src/blocks/textarea/textarea.svelte +42 -1
  57. package/src/blocks/util.ts +18 -6
  58. package/src/blocks/video/video.svelte +36 -1
  59. package/src/components/render-block/block-styles.svelte +16 -3
  60. package/src/components/render-block/render-block.svelte +41 -15
  61. package/src/components/render-block/render-component.svelte +1 -2
  62. package/src/components/render-content/builder-editing.svelte +4 -0
  63. package/src/components/render-content/render-content.svelte +8 -5
  64. package/src/components/render-inlined-styles.svelte +3 -3
  65. package/src/constants/device-sizes.ts +39 -2
  66. package/src/functions/evaluate.ts +11 -6
  67. package/src/functions/event-handler-name.ts +1 -6
  68. package/src/functions/get-block-actions-handler.ts +10 -9
  69. package/src/functions/get-block-actions.ts +2 -2
  70. package/src/functions/get-builder-search-params/index.ts +1 -1
  71. package/src/functions/get-content/index.ts +6 -1
  72. package/src/functions/get-content/types.ts +5 -0
  73. package/src/functions/register-component.ts +1 -18
  74. package/src/functions/track.ts +13 -1
  75. package/src/index.ts +3 -1
  76. package/src/scripts/init-editing.ts +6 -0
  77. package/src/types/builder-content.ts +7 -0
  78. package/package/functions/mark-mutable.d.ts +0 -2
  79. package/package/functions/mark-mutable.js +0 -6
  80. package/src/functions/mark-mutable.ts +0 -7
@@ -14,6 +14,22 @@ import { extractTextStyles } from "../../functions/extract-text-styles.js";
14
14
  import RenderComponentWithContext from "./render-component-with-context.svelte";
15
15
  import RenderComponent from "./render-component.svelte";
16
16
  import { getReactNativeBlockStyles } from "../../functions/get-react-native-block-styles.js";
17
+ const setAttrs = (node, attrs) => {
18
+ const attrKeys = Object.keys(attrs);
19
+ const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
20
+ const teardown = (attr) => node.removeEventListener(attr.substr(3), attrs[attr]);
21
+ attrKeys.map(setup);
22
+ return {
23
+ update(attrs) {
24
+ const attrKeys = Object.keys(attrs);
25
+ attrKeys.map(teardown);
26
+ attrKeys.map(setup);
27
+ },
28
+ destroy() {
29
+ attrKeys.map(teardown);
30
+ },
31
+ };
32
+ };
17
33
  export let block;
18
34
  export let context;
19
35
  $: component = () => {
@@ -38,7 +54,7 @@ $: component = () => {
38
54
  return ref;
39
55
  }
40
56
  };
41
- $: tagName = () => {
57
+ $: tag = () => {
42
58
  return getBlockTag(useBlock());
43
59
  };
44
60
  $: useBlock = () => {
@@ -51,14 +67,16 @@ $: useBlock = () => {
51
67
  shouldEvaluateBindings: true,
52
68
  });
53
69
  };
70
+ $: actions = () => {
71
+ return getBlockActions({
72
+ block: useBlock(),
73
+ state: context.state,
74
+ context: context.context,
75
+ });
76
+ };
54
77
  $: attributes = () => {
55
78
  return {
56
79
  ...getBlockProperties(useBlock()),
57
- ...getBlockActions({
58
- block: useBlock(),
59
- state: context.state,
60
- context: context.context,
61
- }),
62
80
  ...(TARGET === "reactNative"
63
81
  ? {
64
82
  style: getReactNativeBlockStyles({
@@ -74,7 +92,7 @@ $: shouldWrap = () => {
74
92
  };
75
93
  $: renderComponentProps = () => {
76
94
  return {
77
- blockChildren: children(),
95
+ blockChildren: useChildren(),
78
96
  componentRef: component?.()?.component,
79
97
  componentOptions: {
80
98
  ...getBlockComponentOptions(useBlock()),
@@ -85,13 +103,16 @@ $: renderComponentProps = () => {
85
103
  ...(shouldWrap()
86
104
  ? {}
87
105
  : {
88
- attributes: attributes(),
106
+ attributes: {
107
+ ...attributes(),
108
+ ...actions(),
109
+ },
89
110
  }),
90
111
  },
91
112
  context: childrenContext(),
92
113
  };
93
114
  };
94
- $: children = () => {
115
+ $: useChildren = () => {
95
116
  // TO-DO: When should `canHaveChildren` dictate rendering?
96
117
  // This is currently commented out because some Builder components (e.g. Box) do not have `canHaveChildren: true`,
97
118
  // but still receive and need to render children.
@@ -106,7 +127,7 @@ $: childrenWithoutParentComponent = () => {
106
127
  * blocks, and the children will be repeated within those blocks.
107
128
  */
108
129
  const shouldRenderChildrenOutsideRef = !component?.()?.component && !repeatItemData();
109
- return shouldRenderChildrenOutsideRef ? children() : [];
130
+ return shouldRenderChildrenOutsideRef ? useChildren() : [];
110
131
  };
111
132
  $: repeatItemData = () => {
112
133
  /**
@@ -177,18 +198,18 @@ $: renderComponentTag = () => {
177
198
  </script>
178
199
 
179
200
  {#if shouldWrap()}
180
- {#if isEmptyHtmlElement(tagName())}
181
- <svelte:element this={tagName()} {...attributes()} />
201
+ {#if isEmptyHtmlElement(tag())}
202
+ <svelte:element this={tag()} {...attributes()} use:setAttrs={actions()} />
182
203
  {/if}
183
204
 
184
- {#if !isEmptyHtmlElement(tagName()) && repeatItemData()}
205
+ {#if !isEmptyHtmlElement(tag()) && repeatItemData()}
185
206
  {#each repeatItemData() as data, index (index)}
186
207
  <RenderRepeatedBlock repeatContext={data.context} block={data.block} />
187
208
  {/each}
188
209
  {/if}
189
210
 
190
- {#if !isEmptyHtmlElement(tagName()) && !repeatItemData()}
191
- <svelte:element this={tagName()} {...attributes()}>
211
+ {#if !isEmptyHtmlElement(tag()) && !repeatItemData()}
212
+ <svelte:element this={tag()} {...attributes()} use:setAttrs={actions()}>
192
213
  <svelte:component
193
214
  this={renderComponentTag()}
194
215
  {...renderComponentProps()}
@@ -2,7 +2,6 @@
2
2
 
3
3
  <script>import BlockStyles from "./block-styles.svelte";
4
4
  import RenderBlock from "./render-block.svelte";
5
- import { markPropsMutable } from "../../functions/mark-mutable.js";
6
5
  export let componentRef;
7
6
  export let componentOptions;
8
7
  export let blockChildren;
@@ -10,7 +9,7 @@ export let context;
10
9
  </script>
11
10
 
12
11
  {#if componentRef}
13
- <svelte:component this={componentRef} {...markPropsMutable(componentOptions)}>
12
+ <svelte:component this={componentRef} {...componentOptions}>
14
13
  {#each blockChildren as child ("render-block-" + child.id)}
15
14
  <RenderBlock block={child} {context} />
16
15
  {/each}
@@ -0,0 +1,4 @@
1
+ <script>"use strict";
2
+ </script>
3
+
4
+ <div />
@@ -0,0 +1,14 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {};
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ };
9
+ export declare type BuilderEditingProps = typeof __propDef.props;
10
+ export declare type BuilderEditingEvents = typeof __propDef.events;
11
+ export declare type BuilderEditingSlots = typeof __propDef.slots;
12
+ export default class BuilderEditing extends SvelteComponentTyped<BuilderEditingProps, BuilderEditingEvents, BuilderEditingSlots> {
13
+ }
14
+ export {};
@@ -3,7 +3,6 @@
3
3
  <script>import { onDestroy, onMount, setContext, } from "svelte";
4
4
  import { getDefaultRegisteredComponents } from "../../constants/builder-registered-components.js";
5
5
  import { TARGET } from "../../constants/target.js";
6
- import BuilderContext from "../../context/builder.context.js";
7
6
  import { evaluate } from "../../functions/evaluate.js";
8
7
  import { getContent } from "../../functions/get-content/index.js";
9
8
  import { getFetch } from "../../functions/get-fetch.js";
@@ -14,8 +13,8 @@ import { components, createRegisterComponentMessage, } from "../../functions/reg
14
13
  import { _track } from "../../functions/track.js";
15
14
  import RenderBlocks from "../render-blocks.svelte";
16
15
  import RenderContentStyles from "./components/render-styles.svelte";
16
+ import BuilderContext from "../../context/builder.context.js";
17
17
  import { registerInsertMenu, setupBrowserForEditing, } from "../../scripts/init-editing.js";
18
- import { markMutable } from "../../functions/mark-mutable.js";
19
18
  export let content;
20
19
  export let data;
21
20
  export let canTrack;
@@ -193,10 +192,12 @@ let overrideContent = null;
193
192
  let update = 0;
194
193
  let overrideState = {};
195
194
  onMount(() => {
195
+ if (!apiKey) {
196
+ console.error("[Builder.io]: No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
197
+ }
196
198
  if (isBrowser()) {
197
199
  if (isEditing()) {
198
200
  forceReRenderCount = forceReRenderCount + 1;
199
- // QWIK-REPLACE: _useMutableProps
200
201
  registerInsertMenu();
201
202
  setupBrowserForEditing();
202
203
  Object.values(allRegisteredComponents()).forEach((registeredComponent) => {
@@ -242,7 +243,7 @@ onMount(() => {
242
243
  function onUpdateFn_0() {
243
244
  evaluateJsCode();
244
245
  }
245
- $: onUpdateFn_0(...[useContent?.()?.data?.jsCode]);
246
+ $: onUpdateFn_0(...[useContent?.()?.data?.jsCode, contentState()]);
246
247
  function onUpdateFn_1() {
247
248
  runHttpRequests();
248
249
  }
@@ -275,7 +276,7 @@ onDestroy(() => {
275
276
  />
276
277
  {/if}
277
278
  <RenderBlocks
278
- blocks={markMutable(useContent?.()?.data?.blocks)}
279
+ blocks={useContent?.()?.data?.blocks}
279
280
  key={forceReRenderCount}
280
281
  />
281
282
  </div>
@@ -3,9 +3,9 @@
3
3
  <script>import { TARGET } from "../constants/target.js";
4
4
  export let styles;
5
5
  $: injectedStyleScript = () => {
6
- return `<${tagName()}>${styles}</${tagName()}>`;
6
+ return `<${tag()}>${styles}</${tag()}>`;
7
7
  };
8
- $: tagName = () => {
8
+ $: tag = () => {
9
9
  // NOTE: we have to obfusctate the name of the tag due to a limitation in the svelte-preprocessor plugin.
10
10
  // https://github.com/sveltejs/vite-plugin-svelte/issues/315#issuecomment-1109000027
11
11
  return "sty" + "le";
@@ -15,5 +15,5 @@ $: tagName = () => {
15
15
  {#if TARGET === "svelte"}
16
16
  {@html injectedStyleScript()}
17
17
  {:else}
18
- <svelte:element this={tagName()}>{styles}</svelte:element>
18
+ <svelte:element this={tag()}>{styles}</svelte:element>
19
19
  {/if}
@@ -1,2 +1,13 @@
1
1
  export declare type SizeName = 'large' | 'medium' | 'small';
2
- export declare const getMaxWidthQueryForSize: (size: SizeName) => string;
2
+ interface Size {
3
+ min: number;
4
+ default: number;
5
+ max: number;
6
+ }
7
+ export declare const getMaxWidthQueryForSize: (size: SizeName, sizeValues?: Record<SizeName, Size>) => string;
8
+ interface Breakpoints {
9
+ small?: number;
10
+ medium?: number;
11
+ }
12
+ export declare const getSizesForBreakpoints: ({ small, medium }: Breakpoints) => Record<SizeName, Size>;
13
+ export {};
@@ -1,3 +1,4 @@
1
+ import { fastClone } from '../functions/fast-clone';
1
2
  const SIZES = {
2
3
  small: {
3
4
  min: 320,
@@ -15,4 +16,29 @@ const SIZES = {
15
16
  max: 1200,
16
17
  },
17
18
  };
18
- export const getMaxWidthQueryForSize = (size) => `@media (max-width: ${SIZES[size].max}px)`;
19
+ export const getMaxWidthQueryForSize = (size, sizeValues = SIZES) => `@media (max-width: ${sizeValues[size].max}px)`;
20
+ export const getSizesForBreakpoints = ({ small, medium }) => {
21
+ const newSizes = fastClone(SIZES); // Note: this helps to get a deep clone of fields like small, medium etc
22
+ if (!small || !medium) {
23
+ return newSizes;
24
+ }
25
+ const smallMin = Math.floor(small / 2);
26
+ newSizes.small = {
27
+ max: small,
28
+ min: smallMin,
29
+ default: smallMin + 1,
30
+ };
31
+ const mediumMin = newSizes.small.max + 1;
32
+ newSizes.medium = {
33
+ max: medium,
34
+ min: mediumMin,
35
+ default: mediumMin + 1,
36
+ };
37
+ const largeMin = newSizes.medium.max + 1;
38
+ newSizes.large = {
39
+ max: 2000,
40
+ min: largeMin,
41
+ default: largeMin + 1,
42
+ };
43
+ return newSizes;
44
+ };
@@ -1,5 +1,6 @@
1
1
  import type { BuilderContextInterface } from '../context/types.js';
2
- export declare function evaluate({ code, context, state, event, }: {
2
+ export declare function evaluate({ code, context, state, event, isExpression, }: {
3
3
  code: string;
4
4
  event?: Event;
5
+ isExpression?: boolean;
5
6
  } & Pick<BuilderContextInterface, 'state' | 'context'>): any;
@@ -1,6 +1,6 @@
1
1
  import { isBrowser } from './is-browser.js';
2
2
  import { isEditing } from './is-editing.js';
3
- export function evaluate({ code, context, state, event, }) {
3
+ export function evaluate({ code, context, state, event, isExpression = true, }) {
4
4
  if (code === '') {
5
5
  console.warn('Skipping evaluation of empty code block.');
6
6
  return;
@@ -12,14 +12,17 @@ export function evaluate({ code, context, state, event, }) {
12
12
  };
13
13
  // Be able to handle simple expressions like "state.foo" or "1 + 1"
14
14
  // as well as full blocks like "var foo = "bar"; return foo"
15
- const useReturn = !(code.includes(';') ||
16
- code.includes(' return ') ||
17
- code.trim().startsWith('return '));
15
+ const useReturn =
16
+ // we disable this for cases where we definitely don't want a return
17
+ isExpression &&
18
+ !(code.includes(';') ||
19
+ code.includes(' return ') ||
20
+ code.trim().startsWith('return '));
18
21
  const useCode = useReturn ? `return (${code});` : code;
19
22
  try {
20
23
  return new Function('builder', 'Builder' /* <- legacy */, 'state', 'context', 'event', useCode)(builder, builder, state, context, event);
21
24
  }
22
25
  catch (e) {
23
- console.warn('Builder custom code error: \n While Evaluating: \n ', useCode, '\n', e.message || e);
26
+ console.warn('Builder custom code error: \n While Evaluating: \n ', useCode, '\n', e);
24
27
  }
25
28
  }
@@ -1,4 +1 @@
1
- function capitalizeFirstLetter(string) {
2
- return string.charAt(0).toUpperCase() + string.slice(1);
3
- }
4
- export const getEventHandlerName = (key) => `on${capitalizeFirstLetter(key)}`;
1
+ export const getEventHandlerName = (key) => `on:${key.toLowerCase()}`;
@@ -1,5 +1,8 @@
1
1
  import type { BuilderContextInterface } from '../context/types.js';
2
2
  import type { BuilderBlock } from '../types/builder-block.js';
3
- export declare function crateEventHandler(value: string, options: {
3
+ declare type Options = {
4
4
  block: BuilderBlock;
5
- } & Pick<BuilderContextInterface, 'state' | 'context'>): (event: Event) => any;
5
+ } & Pick<BuilderContextInterface, 'state' | 'context'>;
6
+ declare type EventHandler = (event: Event) => any;
7
+ export declare const createEventHandler: (value: string, options: Options) => EventHandler;
8
+ export {};
@@ -1,9 +1,8 @@
1
1
  import { evaluate } from './evaluate.js';
2
- export function crateEventHandler(value, options) {
3
- return (event) => evaluate({
4
- code: value,
5
- context: options.context,
6
- state: options.state,
7
- event,
8
- });
9
- }
2
+ export const createEventHandler = (value, options) => (event) => evaluate({
3
+ code: value,
4
+ context: options.context,
5
+ state: options.state,
6
+ event,
7
+ isExpression: false,
8
+ });
@@ -1,5 +1,5 @@
1
1
  import { getEventHandlerName } from './event-handler-name.js';
2
- import { crateEventHandler } from './get-block-actions-handler.js';
2
+ import { createEventHandler } from './get-block-actions-handler.js';
3
3
  export function getBlockActions(options) {
4
4
  const obj = {};
5
5
  const optionActions = options.block.actions ?? {};
@@ -9,7 +9,7 @@ export function getBlockActions(options) {
9
9
  continue;
10
10
  }
11
11
  const value = optionActions[key];
12
- obj[getEventHandlerName(key)] = crateEventHandler(value, options);
12
+ obj[getEventHandlerName(key)] = createEventHandler(value, options);
13
13
  }
14
14
  return obj;
15
15
  }
@@ -1,4 +1,4 @@
1
- declare type QueryObject = Record<string, string>;
1
+ declare type QueryObject = Record<string, string | string[]>;
2
2
  export declare const convertSearchParamsToQueryObject: (searchParams: URLSearchParams) => QueryObject;
3
3
  export declare const getBuilderSearchParams: (_options: QueryObject | URLSearchParams | undefined) => QueryObject;
4
4
  export declare const getBuilderSearchParamsFromWindow: () => QueryObject;
@@ -6,8 +6,11 @@ export async function getContent(options) {
6
6
  return (await getAllContent({ ...options, limit: 1 })).results[0] || null;
7
7
  }
8
8
  export const generateContentUrl = (options) => {
9
- const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, } = options;
10
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}`);
9
+ const { limit = 30, userAttributes, query, noTraverse = false, model, apiKey, includeRefs = true, } = options;
10
+ if (!apiKey) {
11
+ throw new Error('Missing API key');
12
+ }
13
+ const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}`);
11
14
  const queryOptions = {
12
15
  ...getBuilderSearchParamsFromWindow(),
13
16
  ...normalizeSearchParams(options.options || {}),
@@ -28,4 +28,8 @@ export interface GetContentOptions {
28
28
  * Defaults to `true`.
29
29
  */
30
30
  canTrack?: boolean;
31
+ /**
32
+ * Include references in the response. Defaults to `true`.
33
+ */
34
+ includeRefs?: boolean;
31
35
  }
@@ -1,3 +1,4 @@
1
+ import { serializeFn } from '../blocks/util.js';
1
2
  import { fastClone } from './fast-clone.js';
2
3
  /**
3
4
  * @deprecated. Use the `customComponents` prop in RenderContent instead to provide your custom components to the builder SDK.
@@ -16,19 +17,6 @@ export const createRegisterComponentMessage = ({ component: _, ...info }) => ({
16
17
  data: prepareComponentInfoToSend(info),
17
18
  });
18
19
  const serializeValue = (value) => typeof value === 'function' ? serializeFn(value) : fastClone(value);
19
- /**
20
- * Input attributes that are functions must be converted to strings before being serialized to JSON.
21
- */
22
- // eslint-disable-next-line @typescript-eslint/ban-types
23
- const serializeFn = (fnValue) => {
24
- const fnStr = fnValue.toString().trim();
25
- // we need to account for a few different fn syntaxes:
26
- // 1. `function name(args) => {code}`
27
- // 2. `name(args) => {code}`
28
- // 3. `(args) => {}`
29
- const appendFunction = !fnStr.startsWith('function') && !fnStr.startsWith('(');
30
- return `return (${appendFunction ? 'function ' : ''}${fnStr}).apply(this, arguments)`;
31
- };
32
20
  const prepareComponentInfoToSend = ({ inputs, ...info }) => ({
33
21
  ...fastClone(info),
34
22
  inputs: inputs?.map((input) => Object.entries(input).reduce((acc, [key, value]) => ({
@@ -1,6 +1,11 @@
1
1
  import type { CanTrack } from '../types/can-track.js';
2
2
  interface Event {
3
- type: 'click' | 'impression';
3
+ /**
4
+ * The type of your event.
5
+ *
6
+ * Examples: `click`, `conversion`, `pageview`, `impression`
7
+ */
8
+ type: string;
4
9
  data: {
5
10
  /**
6
11
  * (Optional) The content's ID. Useful if this event pertains to a specific piece of content.
@@ -24,6 +24,10 @@ const createEvent = async ({ type: eventType, canTrack, apiKey, metadata, ...pro
24
24
  },
25
25
  });
26
26
  export async function _track(eventProps) {
27
+ if (!eventProps.apiKey) {
28
+ console.error('[Builder.io]: Missing API key for track call. Please provide your API key.');
29
+ return;
30
+ }
27
31
  if (!eventProps.canTrack) {
28
32
  return;
29
33
  }
@@ -1,4 +1,4 @@
1
- import './index-helpers/top-of-file.js';
1
+ export * from './index-helpers/top-of-file.js';
2
2
  import './scripts/init-editing.js';
3
3
  export * from './index-helpers/blocks-exports.js';
4
4
  export * from './functions/is-editing.js';
@@ -9,3 +9,5 @@ export * from './functions/set-editor-settings.js';
9
9
  export * from './functions/get-content/index.js';
10
10
  export * from './functions/get-builder-search-params/index.js';
11
11
  export { track } from './functions/track';
12
+ export type { RegisteredComponent } from './context/types';
13
+ export type { ComponentInfo } from './types/components';
package/package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import './index-helpers/top-of-file.js';
1
+ export * from './index-helpers/top-of-file.js';
2
2
  import './scripts/init-editing.js';
3
3
  export * from './index-helpers/blocks-exports.js';
4
4
  export * from './functions/is-editing.js';
@@ -21,7 +21,12 @@ export const registerInsertMenu = () => {
21
21
  ],
22
22
  });
23
23
  };
24
+ let isSetupForEditing = false;
24
25
  export const setupBrowserForEditing = () => {
26
+ if (isSetupForEditing) {
27
+ return;
28
+ }
29
+ isSetupForEditing = true;
25
30
  if (isBrowser()) {
26
31
  window.parent?.postMessage({
27
32
  type: 'builder.sdkInfo',
@@ -34,6 +39,7 @@ export const setupBrowserForEditing = () => {
34
39
  // Supports builder-model="..." attribute which is needed to
35
40
  // scope our '+ add block' button styling
36
41
  supportsAddBlockScoping: true,
42
+ supportsCustomBreakpoints: true,
37
43
  },
38
44
  }, '*');
39
45
  window.addEventListener('message', ({ data }) => {
@@ -18,6 +18,13 @@ export interface BuilderContentVariation {
18
18
  name?: string;
19
19
  testRatio?: number;
20
20
  id?: string;
21
+ meta?: {
22
+ breakpoints?: {
23
+ small: number;
24
+ medium: number;
25
+ };
26
+ [key: string]: any;
27
+ };
21
28
  }
22
29
  export interface BuilderContent extends BuilderContentVariation {
23
30
  '@version'?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@builder.io/sdk-svelte",
3
3
  "description": "Builder.io SDK for Svelte",
4
- "version": "0.0.6",
4
+ "version": "0.0.8",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "package",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "main": "./package/index.js",
17
17
  "module": "./package/index.js",
18
- "svelte": "./src/index.ts",
18
+ "svelte": "./package/index.js",
19
19
  "exports": {
20
20
  "./src": {
21
21
  "import": "./src/index.js",
@@ -8,6 +8,40 @@
8
8
  </script>
9
9
 
10
10
  <script lang="ts">
11
+ const isEvent = (attr) => attr.startsWith("on:");
12
+ const isNonEvent = (attr) => !attr.startsWith("on:");
13
+
14
+ const filterAttrs = (attrs, filter) => {
15
+ const validAttr = {};
16
+ Object.keys(attrs).forEach((attr) => {
17
+ if (filter(attr)) {
18
+ validAttr[attr] = attrs[attr];
19
+ }
20
+ });
21
+ return validAttr;
22
+ };
23
+
24
+ const setAttrs = (node, attrs) => {
25
+ const attrKeys = Object.keys(attrs);
26
+
27
+ const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
28
+ const teardown = (attr) =>
29
+ node.removeEventListener(attr.substr(3), attrs[attr]);
30
+
31
+ attrKeys.map(setup);
32
+
33
+ return {
34
+ update(attrs) {
35
+ const attrKeys = Object.keys(attrs);
36
+ attrKeys.map(teardown);
37
+ attrKeys.map(setup);
38
+ },
39
+ destroy() {
40
+ attrKeys.map(teardown);
41
+ },
42
+ };
43
+ };
44
+
11
45
  export let attributes: ButtonProps["attributes"];
12
46
  export let text: ButtonProps["text"];
13
47
  export let link: ButtonProps["link"];
@@ -16,15 +50,20 @@
16
50
 
17
51
  {#if link}
18
52
  <a
19
- {...attributes}
20
53
  role="button"
54
+ {...filterAttrs(attributes, isNonEvent)}
21
55
  href={link}
22
56
  target={openLinkInNewTab ? "_blank" : undefined}
57
+ use:setAttrs={filterAttrs(attributes, isEvent)}
23
58
  >
24
59
  {text}
25
60
  </a>
26
61
  {:else}
27
- <button {...attributes} class="button">
62
+ <button
63
+ class="button"
64
+ {...filterAttrs(attributes, isNonEvent)}
65
+ use:setAttrs={filterAttrs(attributes, isEvent)}
66
+ >
28
67
  {text}
29
68
  </button>
30
69
  {/if}
@@ -28,7 +28,6 @@
28
28
 
29
29
  <script lang="ts">
30
30
  import RenderBlocks from "../../components/render-blocks.svelte";
31
- import { markMutable } from "../../functions/mark-mutable";
32
31
 
33
32
  export let space: ColumnProps["space"];
34
33
  export let columns: ColumnProps["columns"];
@@ -101,7 +100,7 @@
101
100
  class="builder-column div-2"
102
101
  >
103
102
  <RenderBlocks
104
- blocks={markMutable(column.blocks)}
103
+ blocks={column.blocks}
105
104
  path={`component.options.columns.${index}.blocks`}
106
105
  parent={builderBlock.id}
107
106
  styleProp={{
@@ -1,5 +1,5 @@
1
1
  import type { ComponentInfo } from '../../types/components';
2
- import { markSerializable } from '../util.js';
2
+ import { serializeFn } from '../util.js';
3
3
 
4
4
  export const componentInfo: ComponentInfo = {
5
5
  // TODO: ways to statically preprocess JSON for references, functions, etc
@@ -194,7 +194,7 @@ export const componentInfo: ComponentInfo = {
194
194
  ],
195
195
  },
196
196
  ],
197
- onChange: markSerializable((options: Map<string, any>) => {
197
+ onChange: serializeFn((options: Map<string, any>) => {
198
198
  function clearWidths() {
199
199
  columns.forEach((col) => {
200
200
  col.delete('width');
@@ -1,5 +1,5 @@
1
1
  import type { ComponentInfo } from '../../types/components';
2
- import { markSerializable } from '../util.js';
2
+ import { serializeFn } from '../util.js';
3
3
 
4
4
  export const componentInfo: ComponentInfo = {
5
5
  name: 'Embed',
@@ -12,7 +12,7 @@ export const componentInfo: ComponentInfo = {
12
12
  required: true,
13
13
  defaultValue: '',
14
14
  helperText: 'e.g. enter a youtube url, google map, etc',
15
- onChange: markSerializable((options: Map<string, any>) => {
15
+ onChange: serializeFn((options: Map<string, any>) => {
16
16
  const url = options.get('url');
17
17
  if (url) {
18
18
  options.set('content', 'Loading...');