Skip to content

Commit 8d21b6c

Browse files
DEVREL-3672 et al: Component props (#35)
* DEVREL-2759: resetAllProps() * DEVREL-2758: setProps() * DEVREL-2757: getResolvedProps() * DEVREL-2756: getProps() * Apply suggestions from code review Co-authored-by: James Mosier <2854919+jamesmosier@users.noreply.github.com> --------- Co-authored-by: James Mosier <2854919+jamesmosier@users.noreply.github.com>
1 parent 4b890b1 commit 8d21b6c

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

src/designer-extension-typings/elements-generated.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,15 @@ interface ComponentElement
179179
readonly plugin: '';
180180
getComponent(): Promise<Component>;
181181
getSlots(): Promise<Array<SlotInstanceElement>>;
182+
getResolvedProps(): Promise<Array<ResolvedInstanceProp>>;
182183
getProps(): Promise<Array<InstancePropSummary>>;
183184
searchProps(
184185
options?: SearchInstancePropsOptions
185186
): Promise<Array<InstanceProp>>;
186187
setProps(
187188
props: Array<SetInstancePropEntry>
188189
): Promise<Array<SetInstancePropEntry>>;
190+
resetAllProps(): Promise<null>;
189191
}
190192

191193
interface UnknownElement

src/examples/components.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,136 @@ export const Components = {
297297
await myComponent.setName('My New Component Name')
298298
},
299299

300+
getProps: async () => {
301+
// Get the selected component instance
302+
const instanceEl = await webflow.getSelectedElement();
303+
304+
if (instanceEl?.type === 'ComponentInstance') {
305+
const props = await instanceEl.getProps();
306+
307+
// Distinguish bound props from static values using the sourceType property
308+
for (const prop of props) {
309+
if (typeof prop.value === 'object' && prop.value !== null && 'sourceType' in prop.value) {
310+
console.log(`${prop.propId}: bound to ${(prop.value as { sourceType: string }).sourceType}`);
311+
} else {
312+
console.log(`${prop.propId}: ${JSON.stringify(prop.value)}${prop.hasOverride ? ' (overridden)' : ''}`);
313+
}
314+
}
315+
316+
// Round-trip: read current values, modify one, and write them back with setProps
317+
const updatedProps = props.map((prop) => {
318+
if (prop.propId === props[0].propId) {
319+
return { propId: prop.propId, value: 'Updated value' };
320+
}
321+
return { propId: prop.propId, value: prop.value };
322+
});
323+
324+
await instanceEl.setProps(updatedProps);
325+
} else {
326+
console.log('Please select a component instance.');
327+
}
328+
},
329+
330+
getResolvedProps: async () => {
331+
// Get the selected component instance
332+
const instanceEl = await webflow.getSelectedElement();
333+
334+
if (instanceEl?.type === 'ComponentInstance') {
335+
// Get what each prop actually renders — bindings resolved to their output values
336+
const resolvedProps = await instanceEl.getResolvedProps();
337+
338+
for (const prop of resolvedProps) {
339+
console.log(`${prop.propId}: ${JSON.stringify(prop.value)}`);
340+
}
341+
342+
// Comparison of all three instance prop read APIs:
343+
344+
// searchProps — full metadata: wrapped value, resolved value, display info, override status
345+
const search = await instanceEl.searchProps();
346+
console.log(search[0].value); // { sourceType: 'static', value: 'My Custom Title' }
347+
console.log(search[0].resolvedValue); // 'My Custom Title'
348+
console.log(search[0].display); // { label: 'Heading', group: 'Content' }
349+
console.log(search[0].hasOverride); // true
350+
351+
// getProps — raw values with override status, no display metadata
352+
const props = await instanceEl.getProps();
353+
console.log(props[0].value); // 'My Custom Title' (bare value)
354+
console.log(props[0].hasOverride); // true
355+
356+
// getResolvedProps — just the final resolved output, no binding metadata
357+
const resolved = await instanceEl.getResolvedProps();
358+
console.log(resolved[0].value); // 'My Custom Title'
359+
} else {
360+
console.log('Please select a component instance.');
361+
}
362+
},
363+
364+
setProps: async () => {
365+
// Get the selected component instance
366+
const instanceEl = await webflow.getSelectedElement();
367+
368+
if (instanceEl?.type === 'ComponentInstance') {
369+
// Read current prop values (round-trip: read, modify, write back)
370+
const currentProps = await instanceEl.getProps();
371+
console.log('Current props:', currentProps);
372+
373+
await instanceEl.setProps([
374+
// Static value override — set the first prop to a new string value
375+
{ propId: currentProps[0].propId, value: 'New Heading' },
376+
377+
// Bind to a parent component prop
378+
{ propId: 'prop_2', value: { sourceType: 'prop', propId: 'parent_prop_5' } },
379+
380+
// Bind to a CMS field
381+
{ propId: 'prop_3', value: { sourceType: 'cms', collectionId: 'col_abc', fieldId: 'field_author' } },
382+
383+
// Bind to a page field
384+
{ propId: 'prop_4', value: { sourceType: 'page', fieldKey: 'seoTitle' } },
385+
386+
// Disconnect a binding / reset a prop to its component default
387+
{ propId: 'prop_5', value: null },
388+
]);
389+
390+
// Confirm updated values
391+
const updatedProps = await instanceEl.getProps();
392+
console.log('Updated props:', updatedProps);
393+
} else {
394+
console.log('Please select a component instance.');
395+
}
396+
},
397+
398+
resetAllProps: async () => {
399+
// Get the selected component instance
400+
const instanceEl = await webflow.getSelectedElement();
401+
402+
if (instanceEl?.type === 'ComponentInstance') {
403+
// Get the instance's props to find a prop ID to override
404+
const props = await instanceEl.searchProps();
405+
406+
if (props.length > 0) {
407+
const firstProp = props[0];
408+
409+
// Set an override on the first prop
410+
await instanceEl.setProps([{ propId: firstProp.propId, value: 'Custom value' }]);
411+
412+
// Confirm the override is applied
413+
const before = await instanceEl.getProps();
414+
console.log('Has override:', before[0].hasOverride); // true
415+
416+
// Reset all overrides to component defaults in one call
417+
await instanceEl.resetAllProps();
418+
419+
// All props now show defaults, no overrides
420+
const after = await instanceEl.getProps();
421+
console.log('Has override after reset:', after[0].hasOverride); // false
422+
} else {
423+
console.log('This component instance has no props.');
424+
}
425+
} else {
426+
console.log('Please select a component instance.');
427+
}
428+
},
429+
300430
getComponent: async () => {
301431
// Select Component Element on Page
302432
const elements = await webflow.getAllElements()

0 commit comments

Comments
 (0)