From 871b408509b681d157700578556b578480d00752 Mon Sep 17 00:00:00 2001 From: Tim McMackin Date: Fri, 27 Mar 2026 13:19:16 -0400 Subject: [PATCH 1/2] DEVREL-2730: component.createVariant() --- src/components/PermissionsMap.tsx | 1 + .../components.d.ts | 21 +++++++++++++++++++ src/examples/components.ts | 16 ++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/components/PermissionsMap.tsx b/src/components/PermissionsMap.tsx index 40d80dd..2b72567 100644 --- a/src/components/PermissionsMap.tsx +++ b/src/components/PermissionsMap.tsx @@ -57,6 +57,7 @@ export const permissionsMap: PermissionsMap = { getInstanceCount: { permissions: ['canAccessCanvas'] }, getVariants: { permissions: ['canAccessCanvas'] }, getSelectedVariant: { permissions: ['canAccessCanvas'] }, + createVariant: { permissions: ['canModifyComponents'] }, enterComponent: { permissions: ['canModifyComponents'] }, openCanvas: { permissions: ['canModifyComponents'] }, selectComponent: { permissions: ['canModifyComponents'] }, diff --git a/src/designer-extension-typings/components.d.ts b/src/designer-extension-typings/components.d.ts index 422596c..ad0dfd7 100644 --- a/src/designer-extension-typings/components.d.ts +++ b/src/designer-extension-typings/components.d.ts @@ -70,6 +70,20 @@ interface Component { * ``` */ getSelectedVariant(): Promise; + /** + * Creates a new variant on a component. Name conflicts are resolved by auto-incrementing (e.g. "Variant" → "Variant 2"). + * @returns A Promise resolving to the newly created Variant. + * @example + * ```ts + * const variant = await component.createVariant({ + * name: 'Secondary Hero', + * isSelected: true, + * }); + * console.log(variant); + * // { id: 'variant-123', name: 'Secondary Hero', isSelected: true } + * ``` + */ + createVariant(options: CreateVariantOptions): Promise; getRootElement(): Promise; } @@ -81,6 +95,13 @@ interface Variant { isSelected: boolean; } +interface CreateVariantOptions { + /** The name for the new variant */ + name: string; + /** Whether to select this variant immediately after creation (defaults to false) */ + isSelected?: boolean; +} + interface SearchComponentsOptions { /** Fuzzy search query matching Component panel search behavior */ q?: string; diff --git a/src/examples/components.ts b/src/examples/components.ts index 66a44bb..06e0cef 100644 --- a/src/examples/components.ts +++ b/src/examples/components.ts @@ -114,6 +114,22 @@ export const Components = { */ }, + createVariant: async () => { + const component = (await webflow.getAllComponents())[0] + + // Create a new variant and select it immediately + const variant = await component.createVariant({ + name: 'Secondary Hero', + isSelected: true, + }) + console.log(variant) + // { id: 'variant-123', name: 'Secondary Hero', isSelected: true } + + // Name conflicts auto-increment + const variant2 = await component.createVariant({ name: 'Secondary Hero' }) + console.log(variant2.name) // 'Secondary Hero 2' + }, + createComponent: async () => { // Get selected element const rootElement = await webflow.getSelectedElement() From 8cb1ef01e4c7d8caa440ce99c11df164fc62f9a4 Mon Sep 17 00:00:00 2001 From: Tim McMackin Date: Fri, 27 Mar 2026 13:47:06 -0400 Subject: [PATCH 2/2] DEVREL-2728: Duplicate a variant --- src/designer-extension-typings/components.d.ts | 1 + src/examples/components.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/designer-extension-typings/components.d.ts b/src/designer-extension-typings/components.d.ts index ad0dfd7..35dc0b1 100644 --- a/src/designer-extension-typings/components.d.ts +++ b/src/designer-extension-typings/components.d.ts @@ -84,6 +84,7 @@ interface Component { * ``` */ createVariant(options: CreateVariantOptions): Promise; + createVariant(options: CreateVariantOptions, sourceVariantId: string): Promise; getRootElement(): Promise; } diff --git a/src/examples/components.ts b/src/examples/components.ts index 06e0cef..1cb1b38 100644 --- a/src/examples/components.ts +++ b/src/examples/components.ts @@ -128,6 +128,13 @@ export const Components = { // Name conflicts auto-increment const variant2 = await component.createVariant({ name: 'Secondary Hero' }) console.log(variant2.name) // 'Secondary Hero 2' + + // Duplicate a variant by passing its ID as the second parameter + const duplicateVariant = await component.createVariant({ + name: 'Duplicate of Secondary Hero', + isSelected: true, + }, variant.id) + console.log(duplicateVariant.name) // 'Duplicate of Secondary Hero' }, createComponent: async () => {