diff --git a/.changeset/shy-plants-argue.md b/.changeset/shy-plants-argue.md new file mode 100644 index 00000000..6a67ee5c --- /dev/null +++ b/.changeset/shy-plants-argue.md @@ -0,0 +1,5 @@ +--- +"penpot-exporter": minor +--- + +Improvements in overrides management diff --git a/plugin-src/libraries.ts b/plugin-src/libraries.ts index 7c115a73..86f07784 100644 --- a/plugin-src/libraries.ts +++ b/plugin-src/libraries.ts @@ -1,7 +1,9 @@ import { ComponentShape } from '@ui/lib/types/shapes/componentShape'; +import { ComponentProperty } from '@ui/types'; export const textStyles: Map = new Map(); export const paintStyles: Map = new Map(); export const overrides: Map = new Map(); export const images: Map = new Map(); export const components: Map = new Map(); +export const componentProperties: Map = new Map(); diff --git a/plugin-src/transformers/partials/transformOverrides.ts b/plugin-src/transformers/partials/transformOverrides.ts index 9845a833..c6a54b18 100644 --- a/plugin-src/transformers/partials/transformOverrides.ts +++ b/plugin-src/transformers/partials/transformOverrides.ts @@ -1,23 +1,13 @@ -import { overrides as overridesLibrary } from '@plugin/libraries'; -import { syncAttributes } from '@plugin/utils/syncAttributes'; +import { overrides } from '@plugin/libraries'; +import { translateTouched } from '@plugin/translators'; -import { SyncGroups } from '@ui/lib/types/utils/syncGroups'; - -export const transformOverrides = (node: SceneNode) => { - const overrides = overridesLibrary.get(node.id); - if (!overrides) { - return {}; - } - - const touched: SyncGroups[] = []; - - overrides.forEach(override => { - if (syncAttributes[override]) { - touched.push(...syncAttributes[override]); - } - }); +import { ShapeAttributes } from '@ui/lib/types/shapes/shape'; +export const transformOverrides = ( + node: SceneNode +): Pick => { return { - touched + touched: translateTouched(overrides.get(node.id)), + componentPropertyReferences: node.componentPropertyReferences }; }; diff --git a/plugin-src/transformers/partials/transformText.ts b/plugin-src/transformers/partials/transformText.ts index b2ec2ae6..f8cb4eca 100644 --- a/plugin-src/transformers/partials/transformText.ts +++ b/plugin-src/transformers/partials/transformText.ts @@ -21,6 +21,7 @@ export const transformText = (node: TextNode): TextAttributes & Pick { + return node.parent?.type !== 'COMPONENT_SET'; +}; + export const transformComponentNode = async (node: ComponentNode): Promise => { components.set(node.id, { type: 'component', @@ -40,6 +44,18 @@ export const transformComponentNode = async (node: ComponentNode): Promise { + if (value.type === 'TEXT' || value.type === 'BOOLEAN') { + componentProperties.set(key, value); + } + }); + } catch (error) { + console.error('Error registering component properties', error); + } + } + return { figmaId: node.id, type: 'component', diff --git a/plugin-src/transformers/transformDocumentNode.ts b/plugin-src/transformers/transformDocumentNode.ts index b3d32c53..0b2659f2 100644 --- a/plugin-src/transformers/transformDocumentNode.ts +++ b/plugin-src/transformers/transformDocumentNode.ts @@ -1,6 +1,6 @@ import { toObject } from '@common/map'; -import { components } from '@plugin/libraries'; +import { componentProperties, components } from '@plugin/libraries'; import { processImages, processPages, @@ -27,6 +27,7 @@ export const transformDocumentNode = async (node: DocumentNode): Promise { + return node.type === 'COMPONENT_SET'; +}; + export const transformFrameNode = async ( node: FrameNode | SectionNode | ComponentSetNode ): Promise => { let frameSpecificAttributes: Partial = {}; let referencePoint: Point = { x: node.absoluteTransform[0][2], y: node.absoluteTransform[1][2] }; + if (isComponentSetNode(node)) { + try { + Object.entries(node.componentPropertyDefinitions).forEach(([key, value]) => { + if (value.type === 'TEXT' || value.type === 'BOOLEAN') { + componentProperties.set(key, value); + } + }); + } catch (error) { + console.error('Error registering component properties', error); + } + } + if (!isSectionNode(node)) { const { x, y, ...transformAndRotation } = transformRotationAndPosition(node); diff --git a/plugin-src/transformers/transformInstanceNode.ts b/plugin-src/transformers/transformInstanceNode.ts index 174009ea..d1c16489 100644 --- a/plugin-src/transformers/transformInstanceNode.ts +++ b/plugin-src/transformers/transformInstanceNode.ts @@ -17,7 +17,7 @@ import { transformStrokes } from '@plugin/transformers/partials'; -import { ComponentInstance, ComponentTextPropertyOverride } from '@ui/types'; +import { ComponentInstance } from '@ui/types'; export const transformInstanceNode = async ( node: InstanceNode @@ -30,14 +30,20 @@ export const transformInstanceNode = async ( const primaryComponent = getPrimaryComponent(mainComponent); const isOrphan = isOrphanInstance(primaryComponent); let nodeOverrides = {}; - if (!isOrphan) { - registerTextVariableOverrides(node, primaryComponent); - if (node.overrides.length > 0) { - node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields)); - } + if (!isOrphan && node.overrides.length > 0) { + node.overrides.forEach(override => overrides.set(override.id, override.overriddenFields)); nodeOverrides = transformOverrides(node); } + const fetchedOverrides = overrides.get(node.id) ?? []; + if (node.visible !== mainComponent.visible) { + fetchedOverrides.push('visible'); + } + if (node.locked !== mainComponent.locked) { + fetchedOverrides.push('locked'); + } + overrides.set(node.id, fetchedOverrides); + return { type: 'instance', name: node.name, @@ -71,57 +77,6 @@ const getPrimaryComponent = (mainComponent: ComponentNode): ComponentNode | Comp return mainComponent; }; -const getComponentTextPropertyOverrides = ( - node: InstanceNode, - primaryComponent: ComponentNode | ComponentSetNode -): ComponentTextPropertyOverride[] => { - try { - const componentPropertyDefinitions = Object.entries( - primaryComponent.componentPropertyDefinitions - ).filter(([, value]) => value.type === 'TEXT'); - - const instanceComponentProperties = new Map( - Object.entries(node.componentProperties).filter(([, value]) => value.type === 'TEXT') - ); - - return componentPropertyDefinitions - .map(([key, value]) => { - const nodeValue = instanceComponentProperties.get(key); - return { - id: key, - ...value, - value: nodeValue ? nodeValue.value : value.defaultValue - } as ComponentTextPropertyOverride; - }) - .filter(({ value, defaultValue }) => value !== defaultValue); - } catch (error) { - return []; - } -}; - -const registerTextVariableOverrides = ( - node: InstanceNode, - primaryComponent: ComponentNode | ComponentSetNode -) => { - const mergedOverridden = getComponentTextPropertyOverrides(node, primaryComponent); - - if (mergedOverridden.length > 0) { - const textNodes = node - .findChildren(child => child.type === 'TEXT') - .filter(textNode => { - const componentPropertyReference = textNode.componentPropertyReferences?.characters; - return ( - componentPropertyReference && - mergedOverridden.some(property => property.id === componentPropertyReference) - ); - }); - - textNodes.forEach(textNode => { - overrides.set(textNode.id, ['text']); - }); - } -}; - const isOrphanInstance = (primaryComponent: ComponentNode | ComponentSetNode): boolean => { return primaryComponent.parent === null || primaryComponent.remote; }; diff --git a/plugin-src/translators/index.ts b/plugin-src/translators/index.ts index 68013e02..b55b48a5 100644 --- a/plugin-src/translators/index.ts +++ b/plugin-src/translators/index.ts @@ -7,3 +7,4 @@ export * from './translateLayout'; export * from './translateRotation'; export * from './translateShadowEffects'; export * from './translateStrokes'; +export * from './translateTouched'; diff --git a/plugin-src/utils/syncAttributes.ts b/plugin-src/translators/translateTouched.ts similarity index 90% rename from plugin-src/utils/syncAttributes.ts rename to plugin-src/translators/translateTouched.ts index 7a4e99fe..d94b8e98 100644 --- a/plugin-src/utils/syncAttributes.ts +++ b/plugin-src/translators/translateTouched.ts @@ -1,10 +1,10 @@ import { SyncGroups } from '@ui/lib/types/utils/syncGroups'; -export type SyncAttributes = { +type SyncAttributes = { [key in NodeChangeProperty]: SyncGroups[]; }; -export const syncAttributes: SyncAttributes = { +const syncAttributes: SyncAttributes = { name: [':name-group'], fills: [':fill-group'], backgrounds: [':fill-group'], @@ -118,8 +118,8 @@ export const syncAttributes: SyncAttributes = { minWidth: [], minHeight: [], maxWidth: [], - maxLines: [], maxHeight: [], + maxLines: [], counterAxisSpacing: [], counterAxisAlignContent: [], openTypeFeatures: [], @@ -148,3 +148,21 @@ export const syncAttributes: SyncAttributes = { authorName: [], code: [] }; + +export const translateTouched = ( + changedProperties: NodeChangeProperty[] | undefined +): SyncGroups[] => { + const syncGroups: Set = new Set(); + + if (!changedProperties) return []; + + changedProperties.forEach(changedProperty => { + const syncGroup = syncAttributes[changedProperty]; + + if (syncGroup && syncGroup.length > 0) { + syncGroup.forEach(group => syncGroups.add(group)); + } + }); + + return Array.from(syncGroups); +}; diff --git a/ui-src/lib/types/shapes/shape.ts b/ui-src/lib/types/shapes/shape.ts index ed4ddcc0..351f0db5 100644 --- a/ui-src/lib/types/shapes/shape.ts +++ b/ui-src/lib/types/shapes/shape.ts @@ -11,6 +11,7 @@ import { Shadow } from '@ui/lib/types/utils/shadow'; import { Stroke } from '@ui/lib/types/utils/stroke'; import { SyncGroups } from '@ui/lib/types/utils/syncGroups'; import { Uuid } from '@ui/lib/types/utils/uuid'; +import { ComponentPropertyReference } from '@ui/types'; export type ShapeBaseAttributes = { id?: Uuid; @@ -74,6 +75,7 @@ export type ShapeAttributes = { blur?: Blur; growType?: GrowType; touched?: SyncGroups[]; + componentPropertyReferences?: ComponentPropertyReference; // @TODO: move to any other place }; export type ShapeGeomAttributes = { diff --git a/ui-src/lib/types/shapes/textShape.ts b/ui-src/lib/types/shapes/textShape.ts index 117aef6b..516c4ea3 100644 --- a/ui-src/lib/types/shapes/textShape.ts +++ b/ui-src/lib/types/shapes/textShape.ts @@ -16,6 +16,7 @@ export type TextShape = ShapeBaseAttributes & export type TextAttributes = { type?: 'text'; content?: TextContent; + characters?: string; // @ TODO: move to any other place }; export type TextContent = { diff --git a/ui-src/parser/creators/createArtboard.ts b/ui-src/parser/creators/createArtboard.ts index ff714b98..3ce18895 100644 --- a/ui-src/parser/creators/createArtboard.ts +++ b/ui-src/parser/creators/createArtboard.ts @@ -2,7 +2,7 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { FrameShape } from '@ui/lib/types/shapes/frameShape'; import { Uuid } from '@ui/lib/types/utils/uuid'; import { parseFigmaId } from '@ui/parser'; -import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { symbolFills, symbolStrokes, symbolTouched } from '@ui/parser/creators/symbols'; import { createItems } from '.'; @@ -16,6 +16,12 @@ export const createArtboard = ( shape.shapeRef ??= parseFigmaId(file, figmaRelatedId, true); shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.strokes = symbolStrokes(shape.strokes); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.addArtboard(shape); diff --git a/ui-src/parser/creators/createBool.ts b/ui-src/parser/creators/createBool.ts index 2ff61995..f93a8dc1 100644 --- a/ui-src/parser/creators/createBool.ts +++ b/ui-src/parser/creators/createBool.ts @@ -1,7 +1,12 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { BoolShape } from '@ui/lib/types/shapes/boolShape'; import { parseFigmaId } from '@ui/parser'; -import { symbolBoolType, symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { + symbolBoolType, + symbolFills, + symbolStrokes, + symbolTouched +} from '@ui/parser/creators/symbols'; import { createItems } from '.'; @@ -14,6 +19,12 @@ export const createBool = ( shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.strokes = symbolStrokes(shape.strokes); shape.boolType = symbolBoolType(shape.boolType); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.addBool(shape); diff --git a/ui-src/parser/creators/createCircle.ts b/ui-src/parser/creators/createCircle.ts index 2fea9018..f8a18351 100644 --- a/ui-src/parser/creators/createCircle.ts +++ b/ui-src/parser/creators/createCircle.ts @@ -1,7 +1,7 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { CircleShape } from '@ui/lib/types/shapes/circleShape'; import { parseFigmaId } from '@ui/parser'; -import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { symbolFills, symbolStrokes, symbolTouched } from '@ui/parser/creators/symbols'; export const createCircle = ( file: PenpotFile, @@ -11,6 +11,12 @@ export const createCircle = ( shape.shapeRef = parseFigmaId(file, figmaRelatedId, true); shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.strokes = symbolStrokes(shape.strokes); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.createCircle(shape); }; diff --git a/ui-src/parser/creators/createComponentInstance.ts b/ui-src/parser/creators/createComponentInstance.ts index 48aff573..2b78b056 100644 --- a/ui-src/parser/creators/createComponentInstance.ts +++ b/ui-src/parser/creators/createComponentInstance.ts @@ -9,14 +9,7 @@ let remoteFileId: Uuid | undefined = undefined; export const createComponentInstance = ( file: PenpotFile, - { - type, - mainComponentFigmaId, - figmaId, - figmaRelatedId, - isComponentRoot, - ...shape - }: ComponentInstance + { type, mainComponentFigmaId, isComponentRoot, ...shape }: ComponentInstance ) => { const uiComponent = components.get(mainComponentFigmaId) ?? createUiComponent(file, mainComponentFigmaId); @@ -25,7 +18,9 @@ export const createComponentInstance = ( return; } - shape.shapeRef = uiComponent.mainInstanceId; + if (!shape.figmaRelatedId) { + shape.shapeRef = uiComponent.mainInstanceId; + } shape.componentFile = shape.isOrphan ? getRemoteFileId(file) : file.getId(); shape.componentRoot = isComponentRoot; shape.componentId = uiComponent.componentId; diff --git a/ui-src/parser/creators/createGroup.ts b/ui-src/parser/creators/createGroup.ts index 4ac4a16c..9b0b5f63 100644 --- a/ui-src/parser/creators/createGroup.ts +++ b/ui-src/parser/creators/createGroup.ts @@ -1,6 +1,7 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { GroupShape } from '@ui/lib/types/shapes/groupShape'; import { parseFigmaId } from '@ui/parser'; +import { symbolTouched } from '@ui/parser/creators/symbols'; import { createItems } from '.'; @@ -10,6 +11,12 @@ export const createGroup = ( ) => { shape.id = parseFigmaId(file, figmaId); shape.shapeRef = parseFigmaId(file, figmaRelatedId, true); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.addGroup(shape); diff --git a/ui-src/parser/creators/createPath.ts b/ui-src/parser/creators/createPath.ts index f5848f0f..e025f079 100644 --- a/ui-src/parser/creators/createPath.ts +++ b/ui-src/parser/creators/createPath.ts @@ -1,7 +1,12 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { PathShape } from '@ui/lib/types/shapes/pathShape'; import { parseFigmaId } from '@ui/parser'; -import { symbolFills, symbolPathContent, symbolStrokes } from '@ui/parser/creators/symbols'; +import { + symbolFills, + symbolPathContent, + symbolStrokes, + symbolTouched +} from '@ui/parser/creators/symbols'; export const createPath = ( file: PenpotFile, @@ -12,6 +17,12 @@ export const createPath = ( shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.strokes = symbolStrokes(shape.strokes); shape.content = symbolPathContent(shape.content); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.createPath(shape); }; diff --git a/ui-src/parser/creators/createRectangle.ts b/ui-src/parser/creators/createRectangle.ts index f4bbb865..825420bf 100644 --- a/ui-src/parser/creators/createRectangle.ts +++ b/ui-src/parser/creators/createRectangle.ts @@ -1,7 +1,7 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { RectShape } from '@ui/lib/types/shapes/rectShape'; import { parseFigmaId } from '@ui/parser'; -import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { symbolFills, symbolStrokes, symbolTouched } from '@ui/parser/creators/symbols'; export const createRectangle = ( file: PenpotFile, @@ -11,6 +11,12 @@ export const createRectangle = ( shape.shapeRef = parseFigmaId(file, figmaRelatedId, true); shape.fills = symbolFills(shape.fillStyleId, shape.fills); shape.strokes = symbolStrokes(shape.strokes); + shape.touched = symbolTouched( + !shape.hidden, + undefined, + shape.touched, + shape.componentPropertyReferences + ); file.createRect(shape); }; diff --git a/ui-src/parser/creators/createText.ts b/ui-src/parser/creators/createText.ts index c165f473..49037071 100644 --- a/ui-src/parser/creators/createText.ts +++ b/ui-src/parser/creators/createText.ts @@ -1,16 +1,22 @@ import { PenpotFile } from '@ui/lib/types/penpotFile'; import { Paragraph, TextContent, TextNode, TextShape } from '@ui/lib/types/shapes/textShape'; import { parseFigmaId, typographies } from '@ui/parser'; -import { symbolFills, symbolStrokes } from '@ui/parser/creators/symbols'; +import { symbolFills, symbolStrokes, symbolTouched } from '@ui/parser/creators/symbols'; export const createText = ( file: PenpotFile, - { type, figmaId, figmaRelatedId, ...shape }: TextShape + { type, figmaId, figmaRelatedId, characters, ...shape }: TextShape ) => { shape.id = parseFigmaId(file, figmaId); shape.shapeRef = parseFigmaId(file, figmaRelatedId, true); shape.content = parseContent(shape.content); shape.strokes = symbolStrokes(shape.strokes); + shape.touched = symbolTouched( + !shape.hidden, + characters, + shape.touched, + shape.componentPropertyReferences + ); file.createText(shape); }; diff --git a/ui-src/parser/creators/symbols/index.ts b/ui-src/parser/creators/symbols/index.ts index 08f1e0fa..dd382291 100644 --- a/ui-src/parser/creators/symbols/index.ts +++ b/ui-src/parser/creators/symbols/index.ts @@ -2,3 +2,4 @@ export * from './symbolBoolType'; export * from './symbolFills'; export * from './symbolPathContent'; export * from './symbolStrokes'; +export * from './symbolTouched'; diff --git a/ui-src/parser/creators/symbols/symbolTouched.ts b/ui-src/parser/creators/symbols/symbolTouched.ts new file mode 100644 index 00000000..a3593c40 --- /dev/null +++ b/ui-src/parser/creators/symbols/symbolTouched.ts @@ -0,0 +1,35 @@ +import { SyncGroups } from '@ui/lib/types/utils/syncGroups'; +import { componentProperties } from '@ui/parser'; +import { ComponentPropertyReference } from '@ui/types'; + +export const symbolTouched = ( + visible: boolean | undefined, + characters: string | undefined, + touched: SyncGroups[] | undefined, + componentPropertyReferences: ComponentPropertyReference | undefined +): SyncGroups[] | undefined => { + if (!componentPropertyReferences) { + return touched; + } + + const propertyReferenceVisible = componentPropertyReferences.visible; + const propertyReferenceCharacters = componentPropertyReferences.characters; + + if ( + propertyReferenceVisible && + visible !== componentProperties.get(propertyReferenceVisible)?.defaultValue && + !touched?.includes(':visibility-group') + ) { + touched?.push(':visibility-group'); + } + + if ( + propertyReferenceCharacters && + characters !== componentProperties.get(propertyReferenceCharacters)?.defaultValue && + !touched?.includes(':content-group') + ) { + touched?.push(':content-group'); + } + + return touched; +}; diff --git a/ui-src/parser/libraries.ts b/ui-src/parser/libraries.ts index 3c91b0d9..430488c2 100644 --- a/ui-src/parser/libraries.ts +++ b/ui-src/parser/libraries.ts @@ -3,7 +3,7 @@ import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { FillStyle } from '@ui/lib/types/utils/fill'; import { ImageColor } from '@ui/lib/types/utils/imageColor'; import { Uuid } from '@ui/lib/types/utils/uuid'; -import { UiComponent } from '@ui/types'; +import { ComponentProperty, UiComponent } from '@ui/types'; export const typographies: Map = new Map(); export const images: Map = new Map(); @@ -11,3 +11,4 @@ export const identifiers: Map = new Map(); export const components: Map = new Map(); export const componentShapes: Map = new Map(); export const colors: Map = new Map(); +export const componentProperties: Map = new Map(); diff --git a/ui-src/parser/parse.ts b/ui-src/parser/parse.ts index efff7098..546dbb07 100644 --- a/ui-src/parser/parse.ts +++ b/ui-src/parser/parse.ts @@ -6,7 +6,13 @@ import { createFile } from '@ui/lib/penpot'; import { PenpotFile } from '@ui/lib/types/penpotFile'; import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { FillStyle } from '@ui/lib/types/utils/fill'; -import { colors, componentShapes, images, typographies } from '@ui/parser'; +import { + colors, + componentShapes, + images, + typographies, + componentProperties as uiComponentProperties +} from '@ui/parser'; import { buildFile } from '@ui/parser/creators'; import { PenpotDocument } from '@ui/types'; @@ -123,9 +129,11 @@ export const parse = async ({ components, images, paintStyles, - textStyles + textStyles, + componentProperties }: PenpotDocument) => { init(componentShapes, components); + init(uiComponentProperties, componentProperties); const file = createFile(name); diff --git a/ui-src/types/component.ts b/ui-src/types/component.ts index 9c5095ce..64393479 100644 --- a/ui-src/types/component.ts +++ b/ui-src/types/component.ts @@ -36,3 +36,20 @@ export type UiComponent = { mainInstanceId: Uuid; componentFigmaId: string; }; + +export type ComponentProperty = { + type: 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP' | 'VARIANT'; + defaultValue: string | boolean; + preferredValues?: { + type: 'COMPONENT' | 'COMPONENT_SET'; + key: string; + }[]; + variantOptions?: string[]; +}; + +// This type comes directly from Figma. We have it here because we need to reference it from the UI +export type ComponentPropertyReference = + | { + [nodeProperty in 'visible' | 'characters' | 'mainComponent']?: string; + } + | null; diff --git a/ui-src/types/penpotDocument.ts b/ui-src/types/penpotDocument.ts index 4057960c..c61f56fd 100644 --- a/ui-src/types/penpotDocument.ts +++ b/ui-src/types/penpotDocument.ts @@ -2,6 +2,7 @@ import { PenpotPage } from '@ui/lib/types/penpotPage'; import { ComponentShape } from '@ui/lib/types/shapes/componentShape'; import { TypographyStyle } from '@ui/lib/types/shapes/textShape'; import { FillStyle } from '@ui/lib/types/utils/fill'; +import { ComponentProperty } from '@ui/types/component'; export type PenpotDocument = { name: string; @@ -10,4 +11,5 @@ export type PenpotDocument = { images: Record; paintStyles: Record; textStyles: Record; + componentProperties: Record; };