diff --git a/.changeset/stupid-plums-hug.md b/.changeset/stupid-plums-hug.md
new file mode 100644
index 0000000000..54496e3533
--- /dev/null
+++ b/.changeset/stupid-plums-hug.md
@@ -0,0 +1,12 @@
+---
+"@builder.io/sdk-angular": patch
+"@builder.io/sdk-react-nextjs": patch
+"@builder.io/sdk-qwik": patch
+"@builder.io/sdk-react": patch
+"@builder.io/sdk-react-native": patch
+"@builder.io/sdk-solid": patch
+"@builder.io/sdk-svelte": patch
+"@builder.io/sdk-vue": patch
+---
+
+Fix: repeat items when they are Symbols
diff --git a/packages/sdks-tests/src/e2e-tests/repeat-items-bindings.spec.ts b/packages/sdks-tests/src/e2e-tests/repeat-items-bindings.spec.ts
index 360d6cb137..fcafe832cc 100644
--- a/packages/sdks-tests/src/e2e-tests/repeat-items-bindings.spec.ts
+++ b/packages/sdks-tests/src/e2e-tests/repeat-items-bindings.spec.ts
@@ -15,4 +15,17 @@ test.describe('Repeat items bindings', () => {
await expect(page.locator('text=4')).toBeVisible();
await expect(page.locator('text=5')).toBeVisible();
});
+
+ test('repeat Symbols with content bound to content inputs should render correctly', async ({
+ page,
+ }) => {
+ // here data prop is { products: [{ header: 'title1' }, { header: 'title2' }, { header: 'title3' }] }
+ await page.goto('/symbol-with-repeat-input-binding');
+
+ const promises = [];
+ for (let i = 1; i <= 3; i++) {
+ promises.push(expect(page.locator(`text=title${i}`)).toBeVisible());
+ }
+ await Promise.all(promises);
+ });
});
diff --git a/packages/sdks-tests/src/specs/index.ts b/packages/sdks-tests/src/specs/index.ts
index 3ea746978c..7830a652e0 100644
--- a/packages/sdks-tests/src/specs/index.ts
+++ b/packages/sdks-tests/src/specs/index.ts
@@ -58,6 +58,7 @@ import { CUSTOM_COMPONENTS_MODELS_RESTRICTION } from './custom-components-models
import { EDITING_BOX_TO_COLUMN_INNER_LAYOUT } from './editing-columns-inner-layout.js';
import { REACT_NATIVE_STRICT_STYLE_MODE_CONTENT } from './react-native-strict-style-mode.js';
import type { Sdk } from '../helpers/sdk.js';
+import { SYMBOL_WITH_REPEAT_INPUT_BINDING } from './symbol-with-repeat-input-binding.js';
function isBrowser(): boolean {
return typeof window !== 'undefined' && typeof document !== 'undefined';
@@ -133,6 +134,7 @@ export const PAGES = {
'/custom-components-models-show': CUSTOM_COMPONENTS_MODELS_RESTRICTION,
'/custom-components-models-not-show': CUSTOM_COMPONENTS_MODELS_RESTRICTION,
'/editing-box-columns-inner-layout': EDITING_BOX_TO_COLUMN_INNER_LAYOUT,
+ '/symbol-with-repeat-input-binding': SYMBOL_WITH_REPEAT_INPUT_BINDING,
} as const;
const apiVersionPathToProp = {
@@ -236,6 +238,11 @@ export const getProps = async (args: {
strictStyleMode: true,
};
break;
+ case '/symbol-with-repeat-input-binding':
+ extraProps = {
+ data: { products: [{ header: 'title1' }, { header: 'title2' }, { header: 'title3' }] },
+ };
+ break;
default:
break;
}
diff --git a/packages/sdks-tests/src/specs/symbol-with-repeat-input-binding.ts b/packages/sdks-tests/src/specs/symbol-with-repeat-input-binding.ts
new file mode 100644
index 0000000000..890778f0bf
--- /dev/null
+++ b/packages/sdks-tests/src/specs/symbol-with-repeat-input-binding.ts
@@ -0,0 +1,224 @@
+export const SYMBOL_WITH_REPEAT_INPUT_BINDING = {
+ ownerId: 'ad30f9a246614faaa6a03374f83554c9',
+ lastUpdateBy: null,
+ createdDate: 1725872832969,
+ id: '3413ca2078c24216be71bacf54adbfc9',
+ '@version': 4,
+ name: 'data-symbols',
+ modelId: '17c6065109ef4062ba083f5741f4ee6a',
+ published: 'published',
+ meta: {
+ symbolsUsed: {
+ f8f9e85ab8504e7db68c1d896d652c91: true,
+ },
+ kind: 'page',
+ hasLinks: false,
+ lastPreviewUrl:
+ 'http://localhost:5173/data-symbols?builder.space=ad30f9a246614faaa6a03374f83554c9&builder.user.permissions=read%2Ccreate%2Cpublish%2CeditCode%2CeditDesigns%2Cadmin%2CeditLayouts%2CeditLayers&builder.user.role.name=Admin&builder.user.role.id=admin&builder.cachebust=true&builder.preview=page&builder.noCache=true&builder.allowTextEdit=true&__builder_editing__=true&builder.overrides.page=3413ca2078c24216be71bacf54adbfc9&builder.overrides.3413ca2078c24216be71bacf54adbfc9=3413ca2078c24216be71bacf54adbfc9&builder.overrides.page:/data-symbols=3413ca2078c24216be71bacf54adbfc9&builder.options.locale=Default',
+ },
+ priority: -647,
+ stage: 'b3ee01559a244a078973f545ad475eba',
+ query: [
+ {
+ '@type': '@builder.io/core:Query',
+ property: 'urlPath',
+ operator: 'is',
+ value: '/data-symbols',
+ },
+ ],
+ data: {
+ themeId: false,
+ inputs: [],
+ title: 'data-symbols',
+ blocks: [
+ {
+ '@type': '@builder.io/sdk:Element',
+ '@version': 2,
+ bindings: {
+ 'component.options.symbol.data.header':
+ 'var _virtual_index=state.productsItem.header;return _virtual_index',
+ },
+ code: {
+ bindings: {
+ 'component.options.symbol.data.header': 'state.productsItem.header',
+ },
+ },
+ repeat: {
+ collection: 'state.products',
+ },
+ id: 'builder-c4c338558fb747068e63cd6b97f037ba',
+ meta: {
+ bindingActions: {
+ component: {
+ options: {
+ symbol: {
+ data: {
+ header: null,
+ },
+ },
+ },
+ },
+ },
+ },
+ component: {
+ name: 'Symbol',
+ options: {
+ dataOnly: false,
+ inheritState: false,
+ renderToLiquid: false,
+ symbol: {
+ model: 'symbol',
+ entry: 'f8f9e85ab8504e7db68c1d896d652c91',
+ data: {
+ header: 'nothing',
+ },
+ ownerId: 'ad30f9a246614faaa6a03374f83554c9',
+ content: {
+ ownerId: 'ad30f9a246614faaa6a03374f83554c9',
+ lastUpdateBy: null,
+ createdDate: 1725873478428,
+ id: 'f8f9e85ab8504e7db68c1d896d652c91',
+ '@version': 4,
+ name: 'data-symbol-symbol',
+ modelId: '5e1209efea0045f58d9b871d81b652fa',
+ published: 'published',
+ meta: {
+ hasLinks: false,
+ kind: 'component',
+ lastPreviewUrl:
+ 'https://preview.builder.codes?model=symbol&previewing=true&apiKey=ad30f9a246614faaa6a03374f83554c9&builder.space=ad30f9a246614faaa6a03374f83554c9&builder.user.permissions=read%2Ccreate%2Cpublish%2CeditCode%2CeditDesigns%2Cadmin%2CeditLayouts%2CeditLayers&builder.user.role.name=Admin&builder.user.role.id=admin&builder.cachebust=true&builder.preview=symbol&builder.noCache=true&builder.allowTextEdit=true&__builder_editing__=true&builder.overrides.symbol=f8f9e85ab8504e7db68c1d896d652c91&builder.overrides.f8f9e85ab8504e7db68c1d896d652c91=f8f9e85ab8504e7db68c1d896d652c91&builder.options.locale=Default',
+ },
+ priority: -652,
+ stage: 'b3ee01559a244a078973f545ad475eba',
+ query: [],
+ data: {
+ inputs: [
+ {
+ '@type': '@builder.io/core:Field',
+ meta: {},
+ name: 'header',
+ type: 'text',
+ defaultValue: 'default',
+ required: false,
+ subFields: [],
+ helperText: '',
+ autoFocus: false,
+ simpleTextOnly: false,
+ disallowRemove: false,
+ broadcast: false,
+ bubble: false,
+ hideFromUI: false,
+ hideFromFieldsEditor: false,
+ showTemplatePicker: true,
+ permissionsRequiredToEdit: '',
+ advanced: false,
+ copyOnAdd: true,
+ onChange: '',
+ behavior: '',
+ showIf: '',
+ mandatory: false,
+ hidden: false,
+ noPhotoPicker: false,
+ model: '',
+ supportsAiGeneration: false,
+ defaultCollapsed: false,
+ },
+ ],
+ blocks: [
+ {
+ '@type': '@builder.io/sdk:Element',
+ '@version': 2,
+ id: 'builder-ad60c140982d45f58d7190fd84481967',
+ component: {
+ name: 'Text',
+ options: {
+ text: 'HEADER:
',
+ },
+ },
+ responsiveStyles: {
+ large: {
+ display: 'flex',
+ flexDirection: 'column',
+ position: 'relative',
+ flexShrink: '0',
+ boxSizing: 'border-box',
+ marginTop: '20px',
+ lineHeight: 'normal',
+ height: 'auto',
+ },
+ },
+ },
+ {
+ '@type': '@builder.io/sdk:Element',
+ '@version': 2,
+ bindings: {
+ 'component.options.text':
+ 'var _virtual_index=state.header;return _virtual_index',
+ },
+ code: {
+ bindings: {
+ 'component.options.text': 'state.header',
+ },
+ },
+ id: 'builder-3d3ef778f0734f259daa268388104ee0',
+ component: {
+ name: 'Text',
+ options: {
+ text: 'Enter some text...',
+ },
+ },
+ responsiveStyles: {
+ large: {
+ display: 'flex',
+ flexDirection: 'column',
+ position: 'relative',
+ flexShrink: '0',
+ boxSizing: 'border-box',
+ marginTop: '20px',
+ lineHeight: 'normal',
+ height: 'auto',
+ },
+ },
+ },
+ ],
+ },
+ metrics: {
+ clicks: 0,
+ impressions: 0,
+ },
+ variations: {},
+ lastUpdated: 1725874311648,
+ firstPublished: 1725873773459,
+ testRatio: 1,
+ createdBy: 'RuGeCLr9ryVt1xRazFYc72uWwIK2',
+ lastUpdatedBy: 'RuGeCLr9ryVt1xRazFYc72uWwIK2',
+ folders: [],
+ },
+ },
+ },
+ },
+ responsiveStyles: {
+ large: {
+ display: 'flex',
+ flexDirection: 'column',
+ position: 'relative',
+ flexShrink: '0',
+ boxSizing: 'border-box',
+ marginTop: '20px',
+ },
+ },
+ },
+ ],
+ },
+ metrics: {
+ clicks: 0,
+ impressions: 0,
+ },
+ variations: {},
+ lastUpdated: 1725874514331,
+ firstPublished: 1725874440040,
+ testRatio: 1,
+ createdBy: 'RuGeCLr9ryVt1xRazFYc72uWwIK2',
+ lastUpdatedBy: 'RuGeCLr9ryVt1xRazFYc72uWwIK2',
+ folders: [],
+};
diff --git a/packages/sdks/e2e/angular-ssr/src/app/catch-all.component.ts b/packages/sdks/e2e/angular-ssr/src/app/catch-all.component.ts
index de3d059b6b..abaaa3eaec 100644
--- a/packages/sdks/e2e/angular-ssr/src/app/catch-all.component.ts
+++ b/packages/sdks/e2e/angular-ssr/src/app/catch-all.component.ts
@@ -11,6 +11,7 @@ interface BuilderProps {
apiKey: string;
model: string;
content: any;
+ data?: any;
}
@Component({
@@ -24,6 +25,7 @@ interface BuilderProps {
[trustedHosts]="trustedHosts"
[canTrack]="canTrack"
[customComponents]="customComponents"
+ [data]="data"
>
@@ -38,6 +40,7 @@ export class CatchAllComponent {
apiKey: BuilderProps['apiKey'] = 'abcd';
model: BuilderProps['model'] = 'page';
content: BuilderProps['content'];
+ data: BuilderProps['data'];
customComponents = [
{
@@ -54,6 +57,7 @@ export class CatchAllComponent {
this.content = data.content?.content;
this.canTrack = data.content?.canTrack;
this.trustedHosts = data.content?.trustedHosts;
+ this.data = data.content?.data;
});
}
}
diff --git a/packages/sdks/e2e/angular/src/app/app.component.ts b/packages/sdks/e2e/angular/src/app/app.component.ts
index 14e11e5f09..6c485a8d07 100644
--- a/packages/sdks/e2e/angular/src/app/app.component.ts
+++ b/packages/sdks/e2e/angular/src/app/app.component.ts
@@ -14,6 +14,7 @@ interface BuilderProps {
apiKey: string;
model: string;
content: any;
+ data?: any;
}
@Component({
@@ -27,6 +28,7 @@ interface BuilderProps {
[trustedHosts]="trustedHosts"
[canTrack]="canTrack"
[customComponents]="customComponents"
+ [data]="data"
>
@@ -43,6 +45,7 @@ export class AppComponent {
apiKey: BuilderProps['apiKey'] = 'abcd';
model: BuilderProps['model'] = 'page';
content: BuilderProps['content'];
+ data: BuilderProps['data'];
customComponents = [
{
@@ -74,5 +77,6 @@ export class AppComponent {
this.apiKey = builderProps.apiKey;
this.model = builderProps.model;
this.apiVersion = builderProps.apiVersion;
+ this.data = builderProps.data;
}
}
diff --git a/packages/sdks/e2e/react/src/App.tsx b/packages/sdks/e2e/react/src/App.tsx
index be5f3776af..256c8c5fd5 100644
--- a/packages/sdks/e2e/react/src/App.tsx
+++ b/packages/sdks/e2e/react/src/App.tsx
@@ -66,7 +66,7 @@ function App() {
{({ data }) => (
+
+ {(data, index) => (
+
+ )}
+
+ }
+ >
+
+
}
>