@builder.io/sdk-react 0.1.11 → 0.1.13

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 (29) hide show
  1. package/dist/react/blocks/columns/columns.js +68 -73
  2. package/dist/react/blocks/symbol/symbol.js +40 -35
  3. package/dist/react/components/render-content/render-content.js +7 -0
  4. package/dist/react/context/builder.context.js +1 -0
  5. package/dist/react/functions/get-content/generate-content-url.js +5 -2
  6. package/dist/react/functions/get-content/generate-content-url.test.js +42 -0
  7. package/dist/react/types/api-version.js +1 -0
  8. package/dist/rsc/blocks/columns/columns.js +68 -75
  9. package/dist/rsc/blocks/symbol/symbol.js +46 -19
  10. package/dist/rsc/components/render-content/render-content.js +1 -0
  11. package/dist/rsc/context/builder.context.js +1 -0
  12. package/dist/rsc/functions/get-content/generate-content-url.js +5 -2
  13. package/dist/rsc/functions/get-content/generate-content-url.test.js +42 -0
  14. package/dist/rsc/types/api-version.js +1 -0
  15. package/package.json +1 -1
  16. package/packages/react/src/blocks/columns/columns.jsx +81 -79
  17. package/packages/react/src/blocks/symbol/symbol.jsx +36 -28
  18. package/packages/react/src/components/render-content/render-content.jsx +7 -0
  19. package/packages/react/src/context/builder.context.js +1 -0
  20. package/packages/react/src/functions/get-content/generate-content-url.js +6 -2
  21. package/packages/react/src/functions/get-content/generate-content-url.test.js +42 -0
  22. package/packages/react/src/types/api-version.js +0 -0
  23. package/packages/rsc/src/blocks/columns/columns.jsx +73 -78
  24. package/packages/rsc/src/blocks/symbol/symbol.jsx +51 -18
  25. package/packages/rsc/src/components/render-content/render-content.jsx +1 -0
  26. package/packages/rsc/src/context/builder.context.js +1 -0
  27. package/packages/rsc/src/functions/get-content/generate-content-url.js +6 -2
  28. package/packages/rsc/src/functions/get-content/generate-content-url.test.js +42 -0
  29. package/packages/rsc/src/types/api-version.js +0 -0
@@ -3,54 +3,79 @@ import RenderBlocks from "../../components/render-blocks";
3
3
  import { getSizesForBreakpoints } from "../../constants/device-sizes";
4
4
  import RenderInlinedStyles from "../../components/render-inlined-styles";
5
5
  import { TARGET } from "../../constants/target.js";
6
- import { convertStyleMapToCSS } from "../../helpers/css";
7
6
  import BuilderContext from "../../context/builder.context.js";
8
7
 
9
8
  function Columns(props) {
10
9
  const _context = { ...props["_context"] };
11
10
 
12
11
  const state = {
13
- getGutterSize() {
14
- return typeof props.space === "number" ? props.space || 0 : 20;
15
- },
16
- getColumns() {
17
- return props.columns || [];
18
- },
12
+ gutterSize: typeof props.space === "number" ? props.space || 0 : 20,
13
+ cols: props.columns || [],
14
+ stackAt: props.stackColumnsAt || "tablet",
19
15
  getWidth(index) {
20
- const columns = state.getColumns();
21
- return columns[index]?.width || 100 / columns.length;
16
+ return state.cols[index]?.width || 100 / state.cols.length;
22
17
  },
23
18
  getColumnCssWidth(index) {
24
- const columns = state.getColumns();
25
- const gutterSize = state.getGutterSize();
26
19
  const subtractWidth =
27
- (gutterSize * (columns.length - 1)) / columns.length;
20
+ (state.gutterSize * (state.cols.length - 1)) / state.cols.length;
28
21
  return `calc(${state.getWidth(index)}% - ${subtractWidth}px)`;
29
22
  },
30
- maybeApplyForTablet(prop) {
31
- const _stackColumnsAt = props.stackColumnsAt || "tablet";
32
- return _stackColumnsAt === "tablet" ? prop : "inherit";
23
+ getTabletStyle({ stackedStyle, desktopStyle }) {
24
+ return state.stackAt === "tablet" ? stackedStyle : desktopStyle;
25
+ },
26
+ getMobileStyle({ stackedStyle, desktopStyle }) {
27
+ return state.stackAt === "never" ? desktopStyle : stackedStyle;
33
28
  },
29
+ flexDir:
30
+ props.stackColumnsAt === "never"
31
+ ? "row"
32
+ : props.reverseColumnsWhenStacked
33
+ ? "column-reverse"
34
+ : "column",
34
35
  get columnsCssVars() {
35
- const flexDir =
36
- props.stackColumnsAt === "never"
37
- ? "inherit"
38
- : props.reverseColumnsWhenStacked
39
- ? "column-reverse"
40
- : "column";
36
+ if (TARGET === "reactNative") {
37
+ return {
38
+ flexDirection: state.flexDir,
39
+ };
40
+ }
41
41
  return {
42
- "--flex-dir": flexDir,
43
- "--flex-dir-tablet": state.maybeApplyForTablet(flexDir),
42
+ "--flex-dir": state.flexDir,
43
+ "--flex-dir-tablet": state.getTabletStyle({
44
+ stackedStyle: state.flexDir,
45
+ desktopStyle: "row",
46
+ }),
44
47
  };
45
48
  },
46
- get columnCssVars() {
47
- const width = "100%";
48
- const marginLeft = "0";
49
+ columnCssVars(index) {
50
+ const width = state.getColumnCssWidth(index);
51
+ const gutter = `${index === 0 ? 0 : state.gutterSize}px`;
52
+ if (TARGET === "reactNative") {
53
+ return {
54
+ width,
55
+ marginLeft: props.stackColumnsAt === "never" ? gutter : "0",
56
+ };
57
+ }
58
+ const mobileWidth = "100%";
59
+ const mobileMarginLeft = "0";
49
60
  return {
50
- "--column-width": width,
51
- "--column-margin-left": marginLeft,
52
- "--column-width-tablet": state.maybeApplyForTablet(width),
53
- "--column-margin-left-tablet": state.maybeApplyForTablet(marginLeft),
61
+ width,
62
+ "margin-left": gutter,
63
+ "--column-width-mobile": state.getMobileStyle({
64
+ stackedStyle: mobileWidth,
65
+ desktopStyle: width,
66
+ }),
67
+ "--column-margin-left-mobile": state.getMobileStyle({
68
+ stackedStyle: mobileMarginLeft,
69
+ desktopStyle: gutter,
70
+ }),
71
+ "--column-width-tablet": state.getTabletStyle({
72
+ stackedStyle: mobileWidth,
73
+ desktopStyle: width,
74
+ }),
75
+ "--column-margin-left-tablet": state.getTabletStyle({
76
+ stackedStyle: mobileMarginLeft,
77
+ desktopStyle: gutter,
78
+ }),
54
79
  };
55
80
  },
56
81
  getWidthForBreakpointSize(size) {
@@ -59,59 +84,33 @@ function Columns(props) {
59
84
  );
60
85
  return breakpointSizes[size].max;
61
86
  },
62
- get columnStyleObjects() {
63
- return {
64
- columns: {
65
- small: {
66
- flexDirection: "var(--flex-dir)",
67
- alignItems: "stretch",
68
- },
69
- medium: {
70
- flexDirection: "var(--flex-dir-tablet)",
71
- alignItems: "stretch",
72
- },
73
- },
74
- column: {
75
- small: {
76
- width: "var(--column-width) !important",
77
- marginLeft: "var(--column-margin-left) !important",
78
- },
79
- medium: {
80
- width: "var(--column-width-tablet) !important",
81
- marginLeft: "var(--column-margin-left-tablet) !important",
82
- },
83
- },
84
- };
85
- },
86
87
  get columnsStyles() {
87
88
  return `
88
89
  @media (max-width: ${state.getWidthForBreakpointSize("medium")}px) {
89
90
  .${props.builderBlock.id}-breakpoints {
90
- ${convertStyleMapToCSS(state.columnStyleObjects.columns.medium)}
91
+ flex-direction: var(--flex-dir-tablet);
92
+ align-items: stretch;
91
93
  }
92
94
 
93
95
  .${props.builderBlock.id}-breakpoints > .builder-column {
94
- ${convertStyleMapToCSS(state.columnStyleObjects.column.medium)}
96
+ width: var(--column-width-tablet) !important;
97
+ margin-left: var(--column-margin-left-tablet) !important;
95
98
  }
96
99
  }
97
100
 
98
101
  @media (max-width: ${state.getWidthForBreakpointSize("small")}px) {
99
102
  .${props.builderBlock.id}-breakpoints {
100
- ${convertStyleMapToCSS(state.columnStyleObjects.columns.small)}
103
+ flex-direction: var(--flex-dir);
104
+ align-items: stretch;
101
105
  }
102
106
 
103
107
  .${props.builderBlock.id}-breakpoints > .builder-column {
104
- ${convertStyleMapToCSS(state.columnStyleObjects.column.small)}
108
+ width: var(--column-width-mobile) !important;
109
+ margin-left: var(--column-margin-left-mobile) !important;
105
110
  }
106
111
  },
107
112
  `;
108
113
  },
109
- get reactNativeColumnsStyles() {
110
- return this.columnStyleObjects.columns.small;
111
- },
112
- get reactNativeColumnStyles() {
113
- return this.columnStyleObjects.column.small;
114
- },
115
114
  };
116
115
 
117
116
  const builderContext = _context["BuilderContext"];
@@ -121,11 +120,11 @@ function Columns(props) {
121
120
  <div
122
121
  className={
123
122
  `builder-columns ${props.builderBlock.id}-breakpoints` +
124
- " div-fbdb9b00"
123
+ " div-263839f0"
125
124
  }
126
- style={{
127
- ...(TARGET === "reactNative" ? state.reactNativeColumnsStyles : {}),
128
- ...state.columnsCssVars,
125
+ style={state.columnsCssVars}
126
+ dataSet={{
127
+ "builder-block-name": "builder-columns",
129
128
  }}
130
129
  >
131
130
  {TARGET !== "reactNative" ? (
@@ -139,14 +138,10 @@ function Columns(props) {
139
138
 
140
139
  {props.columns?.map((column, index) => (
141
140
  <div
142
- className="builder-column div-fbdb9b00-2"
143
- style={{
144
- width: state.getColumnCssWidth(index),
145
- marginLeft: `${index === 0 ? 0 : state.getGutterSize()}px`,
146
- ...(TARGET === "reactNative"
147
- ? state.reactNativeColumnStyles
148
- : {}),
149
- ...state.columnCssVars,
141
+ className="builder-column div-263839f0-2"
142
+ style={state.columnCssVars(index)}
143
+ dataSet={{
144
+ "builder-block-name": "builder-column",
150
145
  }}
151
146
  key={index}
152
147
  >
@@ -162,10 +157,10 @@ function Columns(props) {
162
157
  </div>
163
158
  ))}
164
159
  </div>
165
- <style>{`.div-fbdb9b00 {
160
+ <style>{`.div-263839f0 {
166
161
  display: flex;
167
162
  line-height: normal;
168
- }.div-fbdb9b00-2 {
163
+ }.div-263839f0-2 {
169
164
  display: flex;
170
165
  flex-direction: column;
171
166
  align-items: stretch;
@@ -8,23 +8,55 @@ function Symbol(props) {
8
8
  const _context = { ...props["_context"] };
9
9
 
10
10
  const state = {
11
- get className() {
12
- return [
13
- ...(TARGET === "vue2" || TARGET === "vue3"
14
- ? Object.keys(props.attributes.class)
15
- : [props.attributes.class]),
16
- "builder-symbol",
17
- props.symbol?.inline ? "builder-inline-symbol" : undefined,
18
- props.symbol?.dynamic || props.dynamic
19
- ? "builder-dynamic-symbol"
20
- : undefined,
21
- ]
22
- .filter(Boolean)
23
- .join(" ");
24
- },
25
- fetchedContent: null,
26
- get contentToUse() {
27
- return props.symbol?.content || state.fetchedContent;
11
+ className: [
12
+ ...(TARGET === "vue2" || TARGET === "vue3"
13
+ ? Object.keys(props.attributes.class)
14
+ : [props.attributes.class]),
15
+ "builder-symbol",
16
+ props.symbol?.inline ? "builder-inline-symbol" : undefined,
17
+ props.symbol?.dynamic || props.dynamic
18
+ ? "builder-dynamic-symbol"
19
+ : undefined,
20
+ ]
21
+ .filter(Boolean)
22
+ .join(" "),
23
+ contentToUse: props.symbol?.content,
24
+ fetchContent() {
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
+ */
34
+ if (
35
+ !state.contentToUse &&
36
+ props.symbol?.model &&
37
+ // This is a hack, we should not need to check for this, but it is needed for Svelte.
38
+ builderContext?.apiKey
39
+ ) {
40
+ getContent({
41
+ model: props.symbol.model,
42
+ apiKey: builderContext.apiKey,
43
+ apiVersion: builderContext.apiVersion,
44
+ query: {
45
+ id: props.symbol.entry,
46
+ },
47
+ })
48
+ .then((response) => {
49
+ if (response) {
50
+ state.contentToUse = response;
51
+ }
52
+ })
53
+ .catch((err) => {
54
+ console.error(
55
+ "[Builder.io]: Could not fetch symbol content: ",
56
+ err
57
+ );
58
+ });
59
+ }
28
60
  },
29
61
  };
30
62
 
@@ -39,13 +71,14 @@ function Symbol(props) {
39
71
  className={state.className}
40
72
  >
41
73
  <RenderContent
74
+ apiVersion={builderContext.apiVersion}
42
75
  apiKey={builderContext.apiKey}
43
76
  context={builderContext.context}
44
77
  customComponents={Object.values(builderContext.registeredComponents)}
45
78
  data={{
46
79
  ...props.symbol?.data,
47
80
  ...builderContext.state,
48
- ...props.symbol?.content?.data?.state,
81
+ ...state.contentToUse?.data?.state,
49
82
  }}
50
83
  model={props.symbol?.model}
51
84
  content={state.contentToUse}
@@ -214,6 +214,7 @@ function RenderContent(props) {
214
214
  setState: state.setContextState,
215
215
  context: props.context || {},
216
216
  apiKey: props.apiKey,
217
+ apiVersion: props.apiVersion,
217
218
  registeredComponents: state.allRegisteredComponents,
218
219
  };
219
220
 
@@ -5,6 +5,7 @@ var stdin_default = {
5
5
  setState() {
6
6
  },
7
7
  apiKey: null,
8
+ apiVersion: void 0,
8
9
  registeredComponents: {},
9
10
  inheritedStyles: {}
10
11
  };
@@ -28,12 +28,16 @@ const generateContentUrl = (options) => {
28
28
  model,
29
29
  apiKey,
30
30
  includeRefs = true,
31
- locale
31
+ locale,
32
+ apiVersion = "v2"
32
33
  } = options;
33
34
  if (!apiKey) {
34
35
  throw new Error("Missing API key");
35
36
  }
36
- const url = new URL(`https://cdn.builder.io/api/v2/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
+ if (!["v2", "v3"].includes(apiVersion)) {
38
+ throw new Error(`Invalid apiVersion: expected 'v2' or 'v3', received '${apiVersion}'`);
39
+ }
40
+ const url = new URL(`https://cdn.builder.io/api/${apiVersion}/content/${model}?apiKey=${apiKey}&limit=${limit}&noTraverse=${noTraverse}&includeRefs=${includeRefs}${locale ? `&locale=${locale}` : ""}`);
37
41
  const queryOptions = __spreadValues(__spreadValues({}, getBuilderSearchParamsFromWindow()), normalizeSearchParams(options.options || {}));
38
42
  const flattened = flatten(queryOptions);
39
43
  for (const key in flattened) {
@@ -28,4 +28,46 @@ describe("Generate Content URL", () => {
28
28
  });
29
29
  expect(output).toMatchSnapshot();
30
30
  });
31
+ test("generate content url with apiVersion as v2", () => {
32
+ const output = generateContentUrl({
33
+ apiKey: testKey,
34
+ model: testModel,
35
+ query: { id: testId },
36
+ options,
37
+ apiVersion: "v2"
38
+ });
39
+ expect(output).toMatchSnapshot();
40
+ });
41
+ test("generate content url with apiVersion as v3", () => {
42
+ const output = generateContentUrl({
43
+ apiKey: testKey,
44
+ model: testModel,
45
+ query: { id: testId },
46
+ options,
47
+ apiVersion: "v3"
48
+ });
49
+ expect(output).toMatchSnapshot();
50
+ });
51
+ test("throw error when trying to generate content url with apiVersion as v1", () => {
52
+ expect(() => {
53
+ generateContentUrl({
54
+ apiKey: testKey,
55
+ model: testModel,
56
+ query: { id: testId },
57
+ options,
58
+ apiVersion: "v1"
59
+ });
60
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'v1'`);
61
+ });
62
+ test("throw error when trying to generate content url with an invalid apiVersion value", () => {
63
+ expect(() => {
64
+ generateContentUrl({
65
+ apiKey: testKey,
66
+ model: testModel,
67
+ query: { id: testId },
68
+ options,
69
+ apiVersion: "INVALID_API_VERSION"
70
+ });
71
+ }).toThrow(`Invalid apiVersion: expected 'v2' or 'v3', received 'INVALID_API_VERSION'`);
72
+ });
31
73
  });
File without changes