@builder.io/sdk-svelte 0.0.1-22 → 0.0.1-25

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.
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.1-22",
4
+ "version": "0.0.1-25",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "src"
@@ -186,7 +186,31 @@ const componentInfo = {
186
186
  ]
187
187
  }
188
188
  ],
189
- onChange: " function clearWidths() { columns.forEach(col => { col.delete('width'); }); } const columns = options.get('columns') as Array<Map<String, any>>; if (Array.isArray(columns)) { const containsColumnWithWidth = !!columns.find(col => col.get('width')); if (containsColumnWithWidth) { const containsColumnWithoutWidth = !!columns.find(col => !col.get('width')); if (containsColumnWithoutWidth) { clearWidths(); } else { const sumWidths = columns.reduce((memo, col) => { return memo + col.get('width'); }, 0); const widthsDontAddUp = sumWidths !== 100; if (widthsDontAddUp) { clearWidths(); } } } } "
189
+ onChange(options) {
190
+ function clearWidths() {
191
+ columns.forEach((col) => {
192
+ col.delete("width");
193
+ });
194
+ }
195
+ const columns = options.get("columns");
196
+ if (Array.isArray(columns)) {
197
+ const containsColumnWithWidth = !!columns.find((col) => col.get("width"));
198
+ if (containsColumnWithWidth) {
199
+ const containsColumnWithoutWidth = !!columns.find((col) => !col.get("width"));
200
+ if (containsColumnWithoutWidth) {
201
+ clearWidths();
202
+ } else {
203
+ const sumWidths = columns.reduce((memo, col) => {
204
+ return memo + col.get("width");
205
+ }, 0);
206
+ const widthsDontAddUp = sumWidths !== 100;
207
+ if (widthsDontAddUp) {
208
+ clearWidths();
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
190
214
  },
191
215
  {
192
216
  name: "space",
@@ -9,7 +9,7 @@ const componentInfo = {
9
9
  required: true,
10
10
  defaultValue: "",
11
11
  helperText: "e.g. enter a youtube url, google map, etc",
12
- onChange: (options) => {
12
+ onChange(options) {
13
13
  const url = options.get("url");
14
14
  if (url) {
15
15
  options.set("content", "Loading...");
@@ -18,7 +18,53 @@ const componentInfo = {
18
18
  allowedFileTypes: ["jpeg", "jpg", "png", "svg"],
19
19
  required: true,
20
20
  defaultValue: "https://cdn.builder.io/api/v1/image/assets%2Fpwgjf0RoYWbdnJSbpBAjXNRMe9F2%2Ffb27a7c790324294af8be1c35fe30f4d",
21
- onChange: " const DEFAULT_ASPECT_RATIO = 0.7041; options.delete('srcset'); options.delete('noWebp'); function loadImage(url, timeout) { return new Promise((resolve, reject) => { const img = document.createElement('img'); let loaded = false; img.onload = () => { loaded = true; resolve(img); }; img.addEventListener('error', event => { console.warn('Image load failed', event.error); reject(event.error); }); img.src = url; setTimeout(() => { if (!loaded) { reject(new Error('Image load timed out')); } }, timeout); }); } function round(num) { return Math.round(num * 1000) / 1000; } const value = options.get('image'); const aspectRatio = options.get('aspectRatio'); // For SVG images - don't render as webp, keep them as SVG fetch(value) .then(res => res.blob()) .then(blob => { if (blob.type.includes('svg')) { options.set('noWebp', true); } }); if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) { return loadImage(value).then(img => { const possiblyUpdatedAspectRatio = options.get('aspectRatio'); if ( options.get('image') === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO) ) { if (img.width && img.height) { options.set('aspectRatio', round(img.height / img.width)); options.set('height', img.height); options.set('width', img.width); } } }); }"
21
+ onChange(options) {
22
+ const DEFAULT_ASPECT_RATIO = 0.7041;
23
+ options.delete("srcset");
24
+ options.delete("noWebp");
25
+ function loadImage(url, timeout = 6e4) {
26
+ return new Promise((resolve, reject) => {
27
+ const img = document.createElement("img");
28
+ let loaded = false;
29
+ img.onload = () => {
30
+ loaded = true;
31
+ resolve(img);
32
+ };
33
+ img.addEventListener("error", (event) => {
34
+ console.warn("Image load failed", event.error);
35
+ reject(event.error);
36
+ });
37
+ img.src = url;
38
+ setTimeout(() => {
39
+ if (!loaded) {
40
+ reject(new Error("Image load timed out"));
41
+ }
42
+ }, timeout);
43
+ });
44
+ }
45
+ function round(num) {
46
+ return Math.round(num * 1e3) / 1e3;
47
+ }
48
+ const value = options.get("image");
49
+ const aspectRatio = options.get("aspectRatio");
50
+ fetch(value).then((res) => res.blob()).then((blob) => {
51
+ if (blob.type.includes("svg")) {
52
+ options.set("noWebp", true);
53
+ }
54
+ });
55
+ if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) {
56
+ return loadImage(value).then((img) => {
57
+ const possiblyUpdatedAspectRatio = options.get("aspectRatio");
58
+ if (options.get("image") === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO)) {
59
+ if (img.width && img.height) {
60
+ options.set("aspectRatio", round(img.height / img.width));
61
+ options.set("height", img.height);
62
+ options.set("width", img.width);
63
+ }
64
+ }
65
+ });
66
+ }
67
+ }
22
68
  },
23
69
  {
24
70
  name: "backgroundSize",
@@ -0,0 +1,48 @@
1
+ function removeProtocol(path) {
2
+ return path.replace(/http(s)?:/, "");
3
+ }
4
+ function updateQueryParam(uri = "", key, value) {
5
+ const re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
6
+ const separator = uri.indexOf("?") !== -1 ? "&" : "?";
7
+ if (uri.match(re)) {
8
+ return uri.replace(re, "$1" + key + "=" + encodeURIComponent(value) + "$2");
9
+ }
10
+ return uri + separator + key + "=" + encodeURIComponent(value);
11
+ }
12
+ function getShopifyImageUrl(src, size) {
13
+ if (!src || !(src == null ? void 0 : src.match(/cdn\.shopify\.com/)) || !size) {
14
+ return src;
15
+ }
16
+ if (size === "master") {
17
+ return removeProtocol(src);
18
+ }
19
+ const match = src.match(/(_\d+x(\d+)?)?(\.(jpg|jpeg|gif|png|bmp|bitmap|tiff|tif)(\?v=\d+)?)/i);
20
+ if (match) {
21
+ const prefix = src.split(match[0]);
22
+ const suffix = match[3];
23
+ const useSize = size.match("x") ? size : `${size}x`;
24
+ return removeProtocol(`${prefix[0]}_${useSize}${suffix}`);
25
+ }
26
+ return null;
27
+ }
28
+ function getSrcSet(url) {
29
+ if (!url) {
30
+ return url;
31
+ }
32
+ const sizes = [100, 200, 400, 800, 1200, 1600, 2e3];
33
+ if (url.match(/builder\.io/)) {
34
+ let srcUrl = url;
35
+ const widthInSrc = Number(url.split("?width=")[1]);
36
+ if (!isNaN(widthInSrc)) {
37
+ srcUrl = `${srcUrl} ${widthInSrc}w`;
38
+ }
39
+ return sizes.filter((size) => size !== widthInSrc).map((size) => `${updateQueryParam(url, "width", size)} ${size}w`).concat([srcUrl]).join(", ");
40
+ }
41
+ if (url.match(/cdn\.shopify\.com/)) {
42
+ return sizes.map((size) => [getShopifyImageUrl(url, `${size}x${size}`), size]).filter(([sizeUrl]) => !!sizeUrl).map(([sizeUrl, size]) => `${sizeUrl} ${size}w`).concat([url]).join(", ");
43
+ }
44
+ return url;
45
+ }
46
+ export {
47
+ getSrcSet
48
+ };
@@ -1,9 +1,13 @@
1
1
  <script>
2
+ import { getSrcSet } from "./image.helpers";
3
+
4
+ export let image;
5
+ export let src;
6
+ export let srcset;
7
+ export let noWebp;
2
8
  export let altText;
3
9
  export let backgroundSize;
4
10
  export let className;
5
- export let image;
6
- export let srcset;
7
11
  export let sizes;
8
12
  export let aspectRatio;
9
13
  export let fitContent;
@@ -14,10 +18,41 @@
14
18
  node.style[p] = v;
15
19
  });
16
20
  }
21
+
22
+ $: srcSetToUse = () => {
23
+ const imageToUse = image || src;
24
+ const url = imageToUse;
25
+
26
+ if (
27
+ !url || // We can auto add srcset for cdn.builder.io and shopify
28
+ // images, otherwise you can supply this prop manually
29
+ !(url.match(/builder\.io/) || url.match(/cdn\.shopify\.com/))
30
+ ) {
31
+ return srcset;
32
+ }
33
+
34
+ if (srcset && image?.includes("builder.io/api/v1/image")) {
35
+ if (!srcset.includes(image.split("?")[0])) {
36
+ console.debug("Removed given srcset");
37
+ return getSrcSet(url);
38
+ }
39
+ } else if (image && !srcset) {
40
+ return getSrcSet(url);
41
+ }
42
+
43
+ return getSrcSet(url);
44
+ };
17
45
  </script>
18
46
 
19
47
  <div class="div">
20
48
  <picture>
49
+ {#if srcSetToUse?.()?.match(/builder\.io/) && !noWebp}
50
+ <source
51
+ type="image/webp"
52
+ srcset={srcSetToUse?.()?.replace(/\?/g, "?format=webp&")}
53
+ />
54
+ {/if}
55
+
21
56
  <img
22
57
  use:mitosis_styling={{
23
58
  objectPosition: backgroundSize || "center",
@@ -26,18 +61,19 @@
26
61
  loading="lazy"
27
62
  alt={altText}
28
63
  role={altText ? "presentation" : undefined}
29
- class={"builder-image" + (className ? " " + className : "") + "img"}
64
+ class={"builder-image" + (className ? " " + className : "") + " img"}
30
65
  src={image}
31
- {srcset}
66
+ srcset={srcSetToUse()}
32
67
  {sizes}
33
68
  />
34
69
 
35
- <source {srcset} />
70
+ <source srcset={srcSetToUse()} />
36
71
  </picture>
37
72
 
38
73
  {#if aspectRatio && !(fitContent && builderBlock?.children?.length)}
39
74
  <div
40
75
  use:mitosis_styling={{
76
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
41
77
  paddingTop: aspectRatio * 100 + "%",
42
78
  }}
43
79
  class="builder-image-sizer div-2"
@@ -22,13 +22,22 @@
22
22
 
23
23
  function onUpdateFn_0() {
24
24
  const symbolToUse = symbol;
25
+ /**
26
+ * If:
27
+ * - we have a symbol prop
28
+ * - yet it does not have any content
29
+ * - and we have not already stored content from before
30
+ * - and it has a model name
31
+ *
32
+ * then we want to re-fetch the symbol content.
33
+ */
25
34
 
26
35
  if (symbolToUse && !symbolToUse.content && !content && symbolToUse.model) {
27
36
  getContent({
28
37
  model: symbolToUse.model,
29
38
  apiKey: builderContext.apiKey,
30
- options: {
31
- entry: symbolToUse.entry,
39
+ query: {
40
+ id: symbolToUse.entry,
32
41
  },
33
42
  }).then((response) => {
34
43
  content = response;
@@ -48,6 +57,7 @@
48
57
  <RenderContent
49
58
  apiKey={builderContext.apiKey}
50
59
  context={builderContext.context}
60
+ customComponents={Object.values(builderContext.registeredComponents)}
51
61
  data={{
52
62
  ...symbol?.data,
53
63
  ...builderContext.state,
@@ -139,34 +139,33 @@
139
139
  return undefined;
140
140
  }
141
141
 
142
- const { collection, itemName } = repeat;
143
142
  const itemsArray = evaluate({
144
- code: collection,
143
+ code: repeat.collection,
145
144
  state: builderContext.state,
146
145
  context: builderContext.context,
147
146
  });
148
147
 
149
- if (Array.isArray(itemsArray)) {
150
- const collectionName = collection.split(".").pop();
151
- const itemNameToUse =
152
- itemName || (collectionName ? collectionName + "Item" : "item");
153
- const repeatArray = itemsArray.map((item, index) => ({
154
- context: {
155
- ...builderContext,
156
- state: {
157
- ...builderContext.state,
158
- $index: index,
159
- $item: item,
160
- [itemNameToUse]: item,
161
- [`$${itemNameToUse}Index`]: index,
162
- },
163
- },
164
- block: blockWithoutRepeat,
165
- }));
166
- return repeatArray;
167
- } else {
148
+ if (!Array.isArray(itemsArray)) {
168
149
  return undefined;
169
150
  }
151
+
152
+ const collectionName = repeat.collection.split(".").pop();
153
+ const itemNameToUse =
154
+ repeat.itemName || (collectionName ? collectionName + "Item" : "item");
155
+ const repeatArray = itemsArray.map((item, index) => ({
156
+ context: {
157
+ ...builderContext,
158
+ state: {
159
+ ...builderContext.state,
160
+ $index: index,
161
+ $item: item,
162
+ [itemNameToUse]: item,
163
+ [`$${itemNameToUse}Index`]: index,
164
+ },
165
+ },
166
+ block: blockWithoutRepeat,
167
+ }));
168
+ return repeatArray;
170
169
  };
171
170
 
172
171
  let builderContext = getContext(BuilderContext.key);
@@ -42,7 +42,7 @@
42
42
  </script>
43
43
 
44
44
  <div
45
- class={className() + "div"}
45
+ class={className() + " div"}
46
46
  builder-path={path}
47
47
  builder-parent-id={parent}
48
48
  dataSet={{
@@ -208,15 +208,16 @@
208
208
 
209
209
  if (isPreviewing()) {
210
210
  if (model && previewingModelName() === model) {
211
- const currentUrl = new URL(location.href);
212
- const previewApiKey = currentUrl.searchParams.get("apiKey");
211
+ const searchParams = new URL(location.href).searchParams;
212
+ const previewApiKey =
213
+ searchParams.get("apiKey") || searchParams.get("builder.space");
213
214
 
214
215
  if (previewApiKey) {
215
216
  getContent({
216
217
  model: model,
217
218
  apiKey: previewApiKey,
218
219
  options: getBuilderSearchParams(
219
- convertSearchParamsToQueryObject(currentUrl.searchParams)
220
+ convertSearchParamsToQueryObject(searchParams)
220
221
  ),
221
222
  }).then((content) => {
222
223
  if (content) {
@@ -0,0 +1,38 @@
1
+ const handleABTesting = (item, testGroups) => {
2
+ if (item.variations && Object.keys(item.variations).length) {
3
+ const testGroup = item.id ? testGroups[item.id] : void 0;
4
+ const variationValue = testGroup ? item.variations[testGroup] : void 0;
5
+ if (testGroup && variationValue) {
6
+ item.data = variationValue.data;
7
+ item.testVariationId = variationValue.id;
8
+ item.testVariationName = variationValue.name;
9
+ } else {
10
+ let n = 0;
11
+ const random = Math.random();
12
+ let set = false;
13
+ for (const id in item.variations) {
14
+ const variation = item.variations[id];
15
+ const testRatio = variation.testRatio;
16
+ n += testRatio;
17
+ if (random < n) {
18
+ const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
19
+ set = true;
20
+ Object.assign(item, {
21
+ data: variation.data,
22
+ testVariationId: variation.id,
23
+ testVariationName: variationName
24
+ });
25
+ }
26
+ }
27
+ if (!set) {
28
+ Object.assign(item, {
29
+ testVariationId: item.id,
30
+ testVariationName: "Default"
31
+ });
32
+ }
33
+ }
34
+ }
35
+ };
36
+ export {
37
+ handleABTesting
38
+ };
@@ -37,20 +37,10 @@ var __async = (__this, __arguments, generator) => {
37
37
  step((generator = generator.apply(__this, __arguments)).next());
38
38
  });
39
39
  };
40
+ import { flatten } from "../../helpers/flatten.js";
40
41
  import { getFetch } from "../get-fetch.js";
42
+ import { handleABTesting } from "./ab-testing.js";
41
43
  const fetch$ = getFetch();
42
- function flatten(object, path = null, separator = ".") {
43
- return Object.keys(object).reduce((acc, key) => {
44
- const value = object[key];
45
- const newPath = [path, key].filter(Boolean).join(separator);
46
- const isObject = [
47
- typeof value === "object",
48
- value !== null,
49
- !(Array.isArray(value) && value.length === 0)
50
- ].every(Boolean);
51
- return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
52
- }, {});
53
- }
54
44
  function getContent(options) {
55
45
  return __async(this, null, function* () {
56
46
  return (yield getAllContent(__spreadProps(__spreadValues({}, options), { limit: 1 }))).results[0] || null;
@@ -83,50 +73,15 @@ const generateContentUrl = (options) => {
83
73
  }
84
74
  return url;
85
75
  };
86
- const handleABTesting = (content, testGroups) => {
87
- for (const item of content.results) {
88
- if (item.variations && Object.keys(item.variations).length) {
89
- const testGroup = testGroups[item.id];
90
- const variationValue = item.variations[testGroup];
91
- if (testGroup && variationValue) {
92
- item.data = variationValue.data;
93
- item.testVariationId = variationValue.id;
94
- item.testVariationName = variationValue.name;
95
- } else {
96
- let n = 0;
97
- const random = Math.random();
98
- let set = false;
99
- for (const id in item.variations) {
100
- const variation = item.variations[id];
101
- const testRatio = variation.testRatio;
102
- n += testRatio;
103
- if (random < n) {
104
- const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
105
- set = true;
106
- Object.assign(item, {
107
- data: variation.data,
108
- testVariationId: variation.id,
109
- testVariationName: variationName
110
- });
111
- }
112
- }
113
- if (!set) {
114
- Object.assign(item, {
115
- testVariationId: item.id,
116
- testVariationName: "Default"
117
- });
118
- }
119
- }
120
- }
121
- }
122
- };
123
76
  function getAllContent(options) {
124
77
  return __async(this, null, function* () {
125
78
  const url = generateContentUrl(options);
126
79
  const fetch = yield fetch$;
127
80
  const content = yield fetch(url.href).then((res) => res.json());
128
81
  if (options.testGroups) {
129
- handleABTesting(content, options.testGroups);
82
+ for (const item of content.results) {
83
+ handleABTesting(item, options.testGroups);
84
+ }
130
85
  }
131
86
  return content;
132
87
  });
File without changes
@@ -46,12 +46,22 @@ const createRegisterComponentMessage = (_a) => {
46
46
  data: prepareComponentInfoToSend(info)
47
47
  };
48
48
  };
49
- const serializeFn = (fn) => `return (${fn.toString()}).apply(this, arguments)`;
50
- const prepareComponentInfoToSend = (info) => {
51
- var _a;
52
- return __spreadProps(__spreadValues({}, info), {
53
- inputs: (_a = info.inputs) == null ? void 0 : _a.map((input) => Object.entries(input).reduce((acc, [key, value]) => __spreadProps(__spreadValues({}, acc), {
54
- [key]: typeof value === "function" ? serializeFn(value) : value
49
+ const fastClone = (obj) => JSON.parse(JSON.stringify(obj));
50
+ const serializeValue = (value) => typeof value === "function" ? serializeFn(value) : fastClone(value);
51
+ const serializeFn = (fnValue) => {
52
+ const fnStr = fnValue.toString().trim();
53
+ const appendFunction = !fnStr.startsWith("function") && !fnStr.startsWith("(");
54
+ return `return (${appendFunction ? "function " : ""}${fnStr}).apply(this, arguments)`;
55
+ };
56
+ const prepareComponentInfoToSend = (_c) => {
57
+ var _d = _c, {
58
+ inputs
59
+ } = _d, info = __objRest(_d, [
60
+ "inputs"
61
+ ]);
62
+ return __spreadProps(__spreadValues({}, fastClone(info)), {
63
+ inputs: inputs == null ? void 0 : inputs.map((input) => Object.entries(input).reduce((acc, [key, value]) => __spreadProps(__spreadValues({}, acc), {
64
+ [key]: serializeValue(value)
55
65
  }), {}))
56
66
  });
57
67
  };
@@ -0,0 +1,34 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function flatten(object, path = null, separator = ".") {
21
+ return Object.keys(object).reduce((acc, key) => {
22
+ const value = object[key];
23
+ const newPath = [path, key].filter(Boolean).join(separator);
24
+ const isObject = [
25
+ typeof value === "object",
26
+ value !== null,
27
+ !(Array.isArray(value) && value.length === 0)
28
+ ].every(Boolean);
29
+ return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
30
+ }, {});
31
+ }
32
+ export {
33
+ flatten
34
+ };