Files
webstudio/packages/react-sdk/src/collection-utils.ts
Oleg Isonen b0fe05611b feat: Collection improvements (#5571)
## Description

- Provide a key variable next to collection item to access array index
or object key
- Add .length autocomplete for arrays
- Add coercion rules when validating bindings, so you can bind a number
to a text attribute or textContent without errors/warnings

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2026-01-18 09:55:41 +01:00

53 lines
1.5 KiB
TypeScript

/**
* Shared collection iteration logic for both builder and published sites.
*
* Collections support both arrays and objects:
* - Arrays: [item1, item2] -> entries are [["0", item1], ["1", item2]]
* - Objects: {key1: val1, key2: val2} -> entries are [["key1", val1], ["key2", val2]]
*
* Using Object.entries() unifies both cases since arrays are objects with numeric keys.
*/
/**
* Normalize collection data to entries format [key, value][].
* Returns empty array if data is not iterable.
* For arrays, keys are converted to numbers.
*/
export const getCollectionEntries = (
data: unknown
): Array<[string | number, unknown]> => {
if (data === null || data === undefined) {
return [];
}
if (typeof data !== "object") {
return [];
}
const entries = Object.entries(data);
// Convert string indices to numbers for arrays
if (Array.isArray(data)) {
return entries.map(([key, value]) => [Number(key), value]);
}
return entries;
};
/**
* Template for generated code that iterates over collections.
* Used by component-generator.ts to ensure consistency.
*/
export const generateCollectionIterationCode = ({
dataExpression,
keyVariable,
itemVariable,
}: {
dataExpression: string;
keyVariable: string;
itemVariable: string;
}) => {
return `Object.entries(
// @ts-ignore
${dataExpression} ?? {}
).map(([_key, ${itemVariable}]: any) => {
const ${keyVariable} = Array.isArray(${dataExpression}) ? Number(_key) : _key;
return`;
};