Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@types/node": "^22.13.5",
"@types/prismjs": "^1.26.3",
"@vitejs/plugin-react": "^4.0.0",
"@webflow/designer-extension-typings": "^2.0.25",
"@webflow/designer-extension-typings": "^2.0.29",
"@webflow/webflow-cli": "^1.8.6",
"@xatom/wf-app-hot-reload": "^1.0.5",
"concurrently": "^6.3.0",
Expand Down
3 changes: 3 additions & 0 deletions src/components/PermissionsMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export const permissionsMap: PermissionsMap = {
setName: { permissions: ['canModifyComponents'] },
getRootElement: { permissions: ['canAccessCanvas'] },
registerComponent: { permissions: ['canCreateComponents'] },
createComponentWithoutRoot: { permissions: ['canCreateComponents'] },
createComponentFromElement: { permissions: ['canCreateComponents'] },
duplicateComponent: { permissions: ['canCreateComponents'] },
unregisterComponent: { permissions: ['canCreateComponents'] },
getAllComponents: { permissions: ['canAccessCanvas'] },
enterComponent: { permissions: ['canModifyComponents'] },
Expand Down
29 changes: 27 additions & 2 deletions src/designer-extension-typings/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ interface WebflowApi {
/**
* Create a component by promoting a Root Element.
* @param name - The name of the component.
* @param rootElement - An Element that will become the Root Element of the Component.
* @param root - An Element that will become the Root Element of the Component.
* @returns A Promise resolving to an object containing the newly created Component - with the id property.
* @example
* ```ts
Expand All @@ -136,8 +136,33 @@ interface WebflowApi {
*/
registerComponent(
name: string,
root: AnyElement | ElementPreset<AnyElement> | Component
root?: AnyElement | ElementPreset<AnyElement> | Component | ComponentId
): Promise<Component>;

/**
* Create a component by converting an element into a component or duplicating a component.
* @param options - The options for the new component.
* @param root - An Element that will become the Root Element of the Component.
* @returns A Promise resolving to an object containing the newly created Component - with the id property.
* @example
* ```ts
* // Convert an existing element into a component
* const selectedElement = await webflow.getSelectedElement()
* const heroComponent = await webflow.registerComponent(
* {
* name: 'Hero Section',
* group: 'Sections',
* description: 'Main hero with heading and CTA'
* },
* selectedElement
* )
* ```
*/
registerComponent(
options: ComponentOptions,
root?: AnyElement | ElementPreset<AnyElement> | Component | ComponentId
): Promise<Component>;

/**
* Delete a component from the Designer. If there are any instances of the Component within the site, they will
* be converted to regular Elements.
Expand Down
11 changes: 11 additions & 0 deletions src/designer-extension-typings/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ interface Component {
}

type ComponentId = string;

interface ComponentOptions {
/** The name of the component (required) */
name: string;
/** The group/folder to place the component in (optional) */
group?: string;
/** A description for the component (optional) */
description?: string;
/** Whether to replace the existing element (optional) */
replace?: Boolean;
}
31 changes: 31 additions & 0 deletions src/examples/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,37 @@ export const Components = {
}
},

createComponentWithoutRoot: async () => {
// Create a hero component in the Sections group that is not within an existing element
const hero = await webflow.registerComponent({
name: 'Hero Section',
group: 'Sections',
description: 'A reusable hero section with heading and CTA',
});
console.log(`Component registered with ID: ${hero.id}`)
},

createComponentFromElement: async () => {
// Convert an existing element into a component, by default replacing the element with the new component
const selectedElement = await webflow.getSelectedElement()
if (selectedElement) {
const heroComponent = await webflow.registerComponent(
{
name: 'Hero Section',
group: 'Sections',
description: 'Main hero with heading and CTA'
},
selectedElement
)
}
},

duplicateComponent: async () => {
// Duplicate a component
const [original] = await webflow.getAllComponents()
const copy = await webflow.registerComponent({ name: 'Card Copy' }, original)
},

deleteComponent: async () => {
// Get selected element
const selectedElement = await webflow.getSelectedElement()
Expand Down