mirror of
https://github.com/penpot/penpot-exporter-figma-plugin.git
synced 2024-12-22 05:33:02 -05:00
Fix component overrides (#200)
* wip * wip * wip * wip * wip * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes
This commit is contained in:
parent
c5dd5d011e
commit
303cc833a0
26 changed files with 223 additions and 100 deletions
5
.changeset/shy-plants-argue.md
Normal file
5
.changeset/shy-plants-argue.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"penpot-exporter": minor
|
||||
---
|
||||
|
||||
Improvements in overrides management
|
|
@ -1,7 +1,9 @@
|
|||
import { ComponentShape } from '@ui/lib/types/shapes/componentShape';
|
||||
import { ComponentProperty } from '@ui/types';
|
||||
|
||||
export const textStyles: Map<string, TextStyle | undefined> = new Map();
|
||||
export const paintStyles: Map<string, PaintStyle | undefined> = new Map();
|
||||
export const overrides: Map<string, NodeChangeProperty[]> = new Map();
|
||||
export const images: Map<string, Image | null> = new Map();
|
||||
export const components: Map<string, ComponentShape> = new Map();
|
||||
export const componentProperties: Map<string, ComponentProperty> = new Map();
|
||||
|
|
|
@ -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<ShapeAttributes, 'touched' | 'componentPropertyReferences'> => {
|
||||
return {
|
||||
touched
|
||||
touched: translateTouched(overrides.get(node.id)),
|
||||
componentPropertyReferences: node.componentPropertyReferences
|
||||
};
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ export const transformText = (node: TextNode): TextAttributes & Pick<TextShape,
|
|||
]);
|
||||
|
||||
return {
|
||||
characters: node.characters,
|
||||
content: {
|
||||
type: 'root',
|
||||
verticalAlign: translateVerticalAlign(node.textAlignVertical),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { components } from '@plugin/libraries';
|
||||
import { componentProperties, components } from '@plugin/libraries';
|
||||
import {
|
||||
transformAutoLayout,
|
||||
transformBlend,
|
||||
|
@ -18,6 +18,10 @@ import {
|
|||
|
||||
import { ComponentRoot } from '@ui/types';
|
||||
|
||||
const isNonVariantComponentNode = (node: ComponentNode): boolean => {
|
||||
return node.parent?.type !== 'COMPONENT_SET';
|
||||
};
|
||||
|
||||
export const transformComponentNode = async (node: ComponentNode): Promise<ComponentRoot> => {
|
||||
components.set(node.id, {
|
||||
type: 'component',
|
||||
|
@ -40,6 +44,18 @@ export const transformComponentNode = async (node: ComponentNode): Promise<Compo
|
|||
...transformAutoLayout(node)
|
||||
});
|
||||
|
||||
if (isNonVariantComponentNode(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);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
figmaId: node.id,
|
||||
type: 'component',
|
||||
|
|
|
@ -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<PenpotD
|
|||
components: toObject(components),
|
||||
images,
|
||||
paintStyles,
|
||||
textStyles
|
||||
textStyles,
|
||||
componentProperties: toObject(componentProperties)
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { componentProperties } from '@plugin/libraries';
|
||||
import {
|
||||
transformAutoLayout,
|
||||
transformBlend,
|
||||
|
@ -23,12 +24,30 @@ const isSectionNode = (node: FrameNode | SectionNode | ComponentSetNode): node i
|
|||
return node.type === 'SECTION';
|
||||
};
|
||||
|
||||
const isComponentSetNode = (
|
||||
node: FrameNode | SectionNode | ComponentSetNode
|
||||
): node is ComponentSetNode => {
|
||||
return node.type === 'COMPONENT_SET';
|
||||
};
|
||||
|
||||
export const transformFrameNode = async (
|
||||
node: FrameNode | SectionNode | ComponentSetNode
|
||||
): Promise<FrameShape> => {
|
||||
let frameSpecificAttributes: Partial<FrameShape> = {};
|
||||
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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -7,3 +7,4 @@ export * from './translateLayout';
|
|||
export * from './translateRotation';
|
||||
export * from './translateShadowEffects';
|
||||
export * from './translateStrokes';
|
||||
export * from './translateTouched';
|
||||
|
|
|
@ -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<SyncGroups> = 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);
|
||||
};
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
if (!shape.figmaRelatedId) {
|
||||
shape.shapeRef = uiComponent.mainInstanceId;
|
||||
}
|
||||
shape.componentFile = shape.isOrphan ? getRemoteFileId(file) : file.getId();
|
||||
shape.componentRoot = isComponentRoot;
|
||||
shape.componentId = uiComponent.componentId;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -2,3 +2,4 @@ export * from './symbolBoolType';
|
|||
export * from './symbolFills';
|
||||
export * from './symbolPathContent';
|
||||
export * from './symbolStrokes';
|
||||
export * from './symbolTouched';
|
||||
|
|
35
ui-src/parser/creators/symbols/symbolTouched.ts
Normal file
35
ui-src/parser/creators/symbols/symbolTouched.ts
Normal file
|
@ -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;
|
||||
};
|
|
@ -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<string, TypographyStyle> = new Map();
|
||||
export const images: Map<string, ImageColor> = new Map();
|
||||
|
@ -11,3 +11,4 @@ export const identifiers: Map<string, Uuid> = new Map();
|
|||
export const components: Map<string, UiComponent> = new Map();
|
||||
export const componentShapes: Map<string, ComponentShape> = new Map();
|
||||
export const colors: Map<string, FillStyle> = new Map();
|
||||
export const componentProperties: Map<string, ComponentProperty> = new Map();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<string, Uint8Array>;
|
||||
paintStyles: Record<string, FillStyle>;
|
||||
textStyles: Record<string, TypographyStyle>;
|
||||
componentProperties: Record<string, ComponentProperty>;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue