diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 91ca33b..9382192 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -18,5 +18,8 @@ module.exports = { react: { version: 'detect' } + }, + rules: { + '@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }] } }; diff --git a/plugin-src/transformers/partials/index.ts b/plugin-src/transformers/partials/index.ts new file mode 100644 index 0000000..8929383 --- /dev/null +++ b/plugin-src/transformers/partials/index.ts @@ -0,0 +1,4 @@ +export * from './transformBlend'; +export * from './transformChildren'; +export * from './transformDimensionAndPosition'; +export * from './transformSceneNode'; diff --git a/plugin-src/transformers/partials/transformBlend.ts b/plugin-src/transformers/partials/transformBlend.ts new file mode 100644 index 0000000..9711a61 --- /dev/null +++ b/plugin-src/transformers/partials/transformBlend.ts @@ -0,0 +1,12 @@ +import { translateBlendMode } from '@plugin/translators'; + +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; + +export const transformBlend = ( + node: SceneNodeMixin & MinimalBlendMixin +): Partial => { + return { + blendMode: translateBlendMode(node.blendMode), + opacity: !node.visible ? 0 : node.opacity // @TODO: check this. If we use the property hidden and it's hidden, it won't export + }; +}; diff --git a/plugin-src/transformers/partials/transformChildren.ts b/plugin-src/transformers/partials/transformChildren.ts new file mode 100644 index 0000000..a3c2538 --- /dev/null +++ b/plugin-src/transformers/partials/transformChildren.ts @@ -0,0 +1,13 @@ +import { transformSceneNode } from '@plugin/transformers'; + +import { Children } from '@ui/lib/types/utils/children'; + +export const transformChildren = async ( + node: ChildrenMixin, + baseX: number = 0, + baseY: number = 0 +): Promise => { + return { + children: await Promise.all(node.children.map(child => transformSceneNode(child, baseX, baseY))) + }; +}; diff --git a/plugin-src/transformers/partials/transformDimensionAndPosition.ts b/plugin-src/transformers/partials/transformDimensionAndPosition.ts new file mode 100644 index 0000000..68e17fb --- /dev/null +++ b/plugin-src/transformers/partials/transformDimensionAndPosition.ts @@ -0,0 +1,14 @@ +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; + +export const transformDimensionAndPosition = ( + node: DimensionAndPositionMixin, + baseX: number, + baseY: number +): ShapeGeomAttributes => { + return { + x: node.x + baseX, + y: node.y + baseY, + width: node.width, + height: node.height + }; +}; diff --git a/plugin-src/transformers/partials/transformSceneNode.ts b/plugin-src/transformers/partials/transformSceneNode.ts new file mode 100644 index 0000000..f4b24a3 --- /dev/null +++ b/plugin-src/transformers/partials/transformSceneNode.ts @@ -0,0 +1,8 @@ +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; + +export const transformSceneNode = (node: SceneNodeMixin): Partial => { + return { + blocked: node.locked, + hidden: false // @TODO: check this. it won't export if we hide it + }; +}; diff --git a/plugin-src/transformers/transformEllipseNode.ts b/plugin-src/transformers/transformEllipseNode.ts index 5134ae7..8d78b93 100644 --- a/plugin-src/transformers/transformEllipseNode.ts +++ b/plugin-src/transformers/transformEllipseNode.ts @@ -1,3 +1,8 @@ +import { + transformBlend, + transformDimensionAndPosition, + transformSceneNode +} from '@plugin/transformers/partials'; import { translateFills } from '@plugin/translators'; import { CircleShape } from '@ui/lib/types/circle/circleShape'; @@ -10,10 +15,9 @@ export const transformEllipseNode = ( return { type: 'circle', name: node.name, - x: node.x + baseX, - y: node.y + baseY, - width: node.width, - height: node.height, - fills: translateFills(node.fills, node.width, node.height) + fills: translateFills(node.fills, node.width, node.height), + ...transformDimensionAndPosition(node, baseX, baseY), + ...transformSceneNode(node), + ...transformBlend(node) }; }; diff --git a/plugin-src/transformers/transformFrameNode.ts b/plugin-src/transformers/transformFrameNode.ts index 7aa8574..031e134 100644 --- a/plugin-src/transformers/transformFrameNode.ts +++ b/plugin-src/transformers/transformFrameNode.ts @@ -1,9 +1,9 @@ +import { transformDimensionAndPosition, transformSceneNode } from '@plugin/transformers/partials'; +import { transformChildren } from '@plugin/transformers/partials'; import { translateFills } from '@plugin/translators'; import { FrameShape } from '@ui/lib/types/frame/frameShape'; -import { transformSceneNode } from '.'; - export const transformFrameNode = async ( node: FrameNode, baseX: number, @@ -12,13 +12,9 @@ export const transformFrameNode = async ( return { type: 'frame', name: node.name, - x: node.x + baseX, - y: node.y + baseY, - width: node.width, - height: node.height, fills: translateFills(node.fills, node.width, node.height), - children: await Promise.all( - node.children.map(child => transformSceneNode(child, baseX + node.x, baseY + node.y)) - ) + ...(await transformChildren(node, baseX, baseY)), + ...transformDimensionAndPosition(node, baseX, baseY), + ...transformSceneNode(node) }; }; diff --git a/plugin-src/transformers/transformGroupNode.ts b/plugin-src/transformers/transformGroupNode.ts index 0925a7f..bd499e4 100644 --- a/plugin-src/transformers/transformGroupNode.ts +++ b/plugin-src/transformers/transformGroupNode.ts @@ -1,6 +1,11 @@ -import { GroupShape } from '@ui/lib/types/group/groupShape'; +import { + transformBlend, + transformDimensionAndPosition, + transformSceneNode +} from '@plugin/transformers/partials'; +import { transformChildren } from '@plugin/transformers/partials'; -import { transformSceneNode } from './transformSceneNode'; +import { GroupShape } from '@ui/lib/types/group/groupShape'; export const transformGroupNode = async ( node: GroupNode, @@ -10,6 +15,9 @@ export const transformGroupNode = async ( return { type: 'group', name: node.name, - children: await Promise.all(node.children.map(child => transformSceneNode(child, baseX, baseY))) + ...(await transformChildren(node, baseX, baseY)), + ...transformDimensionAndPosition(node, baseX, baseY), + ...transformSceneNode(node), + ...transformBlend(node) }; }; diff --git a/plugin-src/transformers/transformImageNode.ts b/plugin-src/transformers/transformImageNode.ts index 622d337..01c16c3 100644 --- a/plugin-src/transformers/transformImageNode.ts +++ b/plugin-src/transformers/transformImageNode.ts @@ -1,3 +1,4 @@ +import { transformDimensionAndPosition } from '@plugin/transformers/partials'; import { detectMimeType } from '@plugin/utils'; import { ImageShape } from '@ui/lib/types/image/imageShape'; @@ -17,14 +18,11 @@ export const transformImageNode = async ( return { type: 'image', name: node.name, - x: node.x + baseX, - y: node.y + baseY, - width: node.width, - height: node.height, metadata: { width: node.width, height: node.height }, - dataUri: dataUri + dataUri: dataUri, + ...transformDimensionAndPosition(node, baseX, baseY) }; }; diff --git a/plugin-src/transformers/transformPageNode.ts b/plugin-src/transformers/transformPageNode.ts index b995c43..c1a7e6c 100644 --- a/plugin-src/transformers/transformPageNode.ts +++ b/plugin-src/transformers/transformPageNode.ts @@ -1,10 +1,10 @@ -import { PenpotPage } from '@ui/lib/types/penpotPage'; +import { transformChildren } from '@plugin/transformers/partials'; -import { transformSceneNode } from '.'; +import { PenpotPage } from '@ui/lib/types/penpotPage'; export const transformPageNode = async (node: PageNode): Promise => { return { name: node.name, - children: await Promise.all(node.children.map(child => transformSceneNode(child))) + ...(await transformChildren(node)) }; }; diff --git a/plugin-src/transformers/transformRectangleNode.ts b/plugin-src/transformers/transformRectangleNode.ts index 9d63fb0..61c3329 100644 --- a/plugin-src/transformers/transformRectangleNode.ts +++ b/plugin-src/transformers/transformRectangleNode.ts @@ -1,3 +1,8 @@ +import { + transformBlend, + transformDimensionAndPosition, + transformSceneNode +} from '@plugin/transformers/partials'; import { translateFills } from '@plugin/translators'; import { RectShape } from '@ui/lib/types/rect/rectShape'; @@ -10,10 +15,9 @@ export const transformRectangleNode = ( return { type: 'rect', name: node.name, - x: node.x + baseX, - y: node.y + baseY, - width: node.width, - height: node.height, - fills: translateFills(node.fills, node.width, node.height) + fills: translateFills(node.fills, node.width, node.height), + ...transformDimensionAndPosition(node, baseX, baseY), + ...transformSceneNode(node), + ...transformBlend(node) }; }; diff --git a/plugin-src/transformers/transformTextNode.ts b/plugin-src/transformers/transformTextNode.ts index e699e41..c4f83cd 100644 --- a/plugin-src/transformers/transformTextNode.ts +++ b/plugin-src/transformers/transformTextNode.ts @@ -1,3 +1,8 @@ +import { + transformBlend, + transformDimensionAndPosition, + transformSceneNode +} from '@plugin/transformers/partials'; import { translateFills, translateTextDecoration, @@ -37,10 +42,6 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number): return { type: 'text', name: node.name, - x: node.x + baseX, - y: node.y + baseY, - width: node.width, - height: node.height, content: { type: 'root', children: [ @@ -61,6 +62,9 @@ export const transformTextNode = (node: TextNode, baseX: number, baseY: number): ] } ] - } + }, + ...transformDimensionAndPosition(node, baseX, baseY), + ...transformSceneNode(node), + ...transformBlend(node) }; }; diff --git a/plugin-src/translators/index.ts b/plugin-src/translators/index.ts index c238869..7e149c0 100644 --- a/plugin-src/translators/index.ts +++ b/plugin-src/translators/index.ts @@ -3,3 +3,4 @@ export * from './translateGradientLinearFill'; export * from './translateSolidFill'; export * from './translateTextDecoration'; export * from './translateTextTransform'; +export * from './translateBlendMode'; diff --git a/plugin-src/translators/translateBlendMode.ts b/plugin-src/translators/translateBlendMode.ts new file mode 100644 index 0000000..907a06a --- /dev/null +++ b/plugin-src/translators/translateBlendMode.ts @@ -0,0 +1,46 @@ +import { BlendMode as PenpotBlendMode } from '@ui/lib/types/utils/blendModes'; + +export const translateBlendMode = (blendMode: BlendMode): PenpotBlendMode => { + switch (blendMode) { + //@TODO: is not translatable in penpot, this is the closest one + case 'PASS_THROUGH': + case 'NORMAL': + return 'normal'; + //@TODO: is not translatable in penpot, this is the closest one + case 'LINEAR_BURN': + case 'DARKEN': + return 'darken'; + case 'MULTIPLY': + return 'multiply'; + case 'COLOR_BURN': + return 'color-burn'; + case 'LIGHTEN': + return 'lighten'; + case 'SCREEN': + return 'screen'; + //@TODO: is not translatable in penpot, this is the closest one + case 'LINEAR_DODGE': + case 'COLOR_DODGE': + return 'color-dodge'; + case 'OVERLAY': + return 'overlay'; + case 'SOFT_LIGHT': + return 'soft-light'; + case 'HARD_LIGHT': + return 'hard-light'; + case 'DIFFERENCE': + return 'difference'; + case 'EXCLUSION': + return 'exclusion'; + case 'HUE': + return 'hue'; + case 'SATURATION': + return 'saturation'; + case 'COLOR': + return 'color'; + case 'LUMINOSITY': + return 'luminosity'; + default: + return 'normal'; + } +}; diff --git a/ui-src/converters/createPenpotArtboard.ts b/ui-src/converters/createPenpotArtboard.ts index ac2307b..3614fd4 100644 --- a/ui-src/converters/createPenpotArtboard.ts +++ b/ui-src/converters/createPenpotArtboard.ts @@ -6,7 +6,6 @@ import { createPenpotItem } from '.'; export const createPenpotArtboard = ( file: PenpotFile, - // eslint-disable-next-line @typescript-eslint/no-unused-vars { type, children = [], ...rest }: FrameShape ) => { file.addArtboard({ diff --git a/ui-src/converters/createPenpotCircle.ts b/ui-src/converters/createPenpotCircle.ts index 6ac9ee3..0b60734 100644 --- a/ui-src/converters/createPenpotCircle.ts +++ b/ui-src/converters/createPenpotCircle.ts @@ -2,13 +2,16 @@ import { PenpotFile } from '@ui/lib/penpot'; import { CIRCLE_TYPE } from '@ui/lib/types/circle/circleAttributes'; import { CircleShape } from '@ui/lib/types/circle/circleShape'; -import { translateFillGradients } from '../translators'; +import { translateFillGradients, translateUiBlendMode } from '../translators'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const createPenpotCircle = (file: PenpotFile, { type, fills, ...rest }: CircleShape) => { +export const createPenpotCircle = ( + file: PenpotFile, + { type, fills, blendMode, ...rest }: CircleShape +) => { file.createCircle({ type: CIRCLE_TYPE, fills: translateFillGradients(fills), + blendMode: translateUiBlendMode(blendMode), ...rest }); }; diff --git a/ui-src/converters/createPenpotGroup.ts b/ui-src/converters/createPenpotGroup.ts index 36770b2..287252a 100644 --- a/ui-src/converters/createPenpotGroup.ts +++ b/ui-src/converters/createPenpotGroup.ts @@ -1,16 +1,17 @@ import { PenpotFile } from '@ui/lib/penpot'; import { GROUP_TYPE } from '@ui/lib/types/group/groupAttributes'; import { GroupShape } from '@ui/lib/types/group/groupShape'; +import { translateUiBlendMode } from '@ui/translators'; import { createPenpotItem } from '.'; export const createPenpotGroup = ( file: PenpotFile, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - { type, children = [], ...rest }: GroupShape + { type, blendMode, children = [], ...rest }: GroupShape ) => { file.addGroup({ type: GROUP_TYPE, + blendMode: translateUiBlendMode(blendMode), ...rest }); diff --git a/ui-src/converters/createPenpotImage.ts b/ui-src/converters/createPenpotImage.ts index 18d400d..bb038a6 100644 --- a/ui-src/converters/createPenpotImage.ts +++ b/ui-src/converters/createPenpotImage.ts @@ -2,7 +2,6 @@ import { PenpotFile } from '@ui/lib/penpot'; import { IMAGE_TYPE } from '@ui/lib/types/image/imageAttributes'; import { ImageShape } from '@ui/lib/types/image/imageShape'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const createPenpotImage = (file: PenpotFile, { type, ...rest }: ImageShape) => { file.createImage({ type: IMAGE_TYPE, diff --git a/ui-src/converters/createPenpotRectangle.ts b/ui-src/converters/createPenpotRectangle.ts index 63f9793..7b000e6 100644 --- a/ui-src/converters/createPenpotRectangle.ts +++ b/ui-src/converters/createPenpotRectangle.ts @@ -1,13 +1,16 @@ import { PenpotFile } from '@ui/lib/penpot'; import { RECT_TYPE } from '@ui/lib/types/rect/rectAttributes'; import { RectShape } from '@ui/lib/types/rect/rectShape'; -import { translateFillGradients } from '@ui/translators'; +import { translateFillGradients, translateUiBlendMode } from '@ui/translators'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const createPenpotRectangle = (file: PenpotFile, { type, fills, ...rest }: RectShape) => { +export const createPenpotRectangle = ( + file: PenpotFile, + { type, fills, blendMode, ...rest }: RectShape +) => { file.createRect({ type: RECT_TYPE, fills: translateFillGradients(fills), + blendMode: translateUiBlendMode(blendMode), ...rest }); }; diff --git a/ui-src/converters/createPenpotText.ts b/ui-src/converters/createPenpotText.ts index 11f11d9..3c686df 100644 --- a/ui-src/converters/createPenpotText.ts +++ b/ui-src/converters/createPenpotText.ts @@ -1,14 +1,12 @@ import { PenpotFile } from '@ui/lib/penpot'; import { TEXT_TYPE } from '@ui/lib/types/text/textAttributes'; import { TextShape } from '@ui/lib/types/text/textShape'; +import { translateUiBlendMode } from '@ui/translators'; -export const createPenpotText = ( - file: PenpotFile, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - { type, ...rest }: TextShape -) => { +export const createPenpotText = (file: PenpotFile, { type, blendMode, ...rest }: TextShape) => { file.createText({ type: TEXT_TYPE, + blendMode: translateUiBlendMode(blendMode), ...rest }); }; diff --git a/ui-src/lib/penpot.d.ts b/ui-src/lib/penpot.d.ts index d3f2725..bf0fbc7 100644 --- a/ui-src/lib/penpot.d.ts +++ b/ui-src/lib/penpot.d.ts @@ -36,8 +36,7 @@ export interface PenpotFile { // lookupShape(shapeId: string): void; // updateObject(id: string, object: any): void; // deleteObject(id: string): void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - asMap(): any; + asMap(): unknown; export(): void; } diff --git a/ui-src/lib/types/bool/boolAttributes.d.ts b/ui-src/lib/types/bool/boolAttributes.ts similarity index 73% rename from ui-src/lib/types/bool/boolAttributes.d.ts rename to ui-src/lib/types/bool/boolAttributes.ts index a2a8c88..d19e7c4 100644 --- a/ui-src/lib/types/bool/boolAttributes.d.ts +++ b/ui-src/lib/types/bool/boolAttributes.ts @@ -2,9 +2,10 @@ import { Uuid } from '@ui/lib/types/utils/uuid'; import { BoolContent } from './boolContent'; +export const BOOL_TYPE: unique symbol = Symbol.for('bool'); + export type BoolAttributes = { - id?: Uuid; - type: symbol; // bool + type: 'bool' | typeof BOOL_TYPE; shapes?: Uuid[]; boolType: string; // @TODO: in Penpot this is of type :keyword. check if it makes sense boolContent: BoolContent[]; diff --git a/ui-src/lib/types/bool/boolShape.d.ts b/ui-src/lib/types/bool/boolShape.d.ts index 1db2d84..ea440ff 100644 --- a/ui-src/lib/types/bool/boolShape.d.ts +++ b/ui-src/lib/types/bool/boolShape.d.ts @@ -1,5 +1,6 @@ -import { Shape } from '@ui/lib/types/shape'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; import { BoolAttributes } from './boolAttributes'; -export type BoolShape = Shape & BoolAttributes; +export type BoolShape = ShapeBaseAttributes & ShapeAttributes & BoolAttributes; diff --git a/ui-src/lib/types/circle/circleAttributes.ts b/ui-src/lib/types/circle/circleAttributes.ts index 330ff33..3117968 100644 --- a/ui-src/lib/types/circle/circleAttributes.ts +++ b/ui-src/lib/types/circle/circleAttributes.ts @@ -1,8 +1,5 @@ -import { Uuid } from '@ui/lib/types/utils/uuid'; - export const CIRCLE_TYPE: unique symbol = Symbol.for('circle'); export type CircleAttributes = { type: 'circle' | typeof CIRCLE_TYPE; - id?: Uuid; }; diff --git a/ui-src/lib/types/circle/circleShape.d.ts b/ui-src/lib/types/circle/circleShape.d.ts index 9c693c4..70fc92b 100644 --- a/ui-src/lib/types/circle/circleShape.d.ts +++ b/ui-src/lib/types/circle/circleShape.d.ts @@ -1,5 +1,12 @@ -import { Shape } from '@ui/lib/types/shape'; +import { LayoutChildAttributes } from '@ui/lib/types/layout/layoutChildAttributes'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { CircleAttributes } from './circleAttributes'; -export type CircleShape = Shape & CircleAttributes; +export type CircleShape = ShapeBaseAttributes & + ShapeGeomAttributes & + ShapeAttributes & + CircleAttributes & + LayoutChildAttributes; diff --git a/ui-src/lib/types/frame/frameAttributes.ts b/ui-src/lib/types/frame/frameAttributes.ts index faecdd2..d4121e3 100644 --- a/ui-src/lib/types/frame/frameAttributes.ts +++ b/ui-src/lib/types/frame/frameAttributes.ts @@ -1,13 +1,15 @@ import { Uuid } from '@ui/lib/types/utils/uuid'; +import { Fill } from '../utils/fill'; + export const FRAME_TYPE: unique symbol = Symbol.for('frame'); export type FrameAttributes = { type: 'frame' | typeof FRAME_TYPE; - id?: Uuid; shapes?: Uuid[]; fileThumbnail?: boolean; hideFillOnExport?: boolean; showContent?: boolean; hideInViewer?: boolean; + fills: Fill[]; }; diff --git a/ui-src/lib/types/frame/frameShape.d.ts b/ui-src/lib/types/frame/frameShape.d.ts index 2ffaf9e..46deebd 100644 --- a/ui-src/lib/types/frame/frameShape.d.ts +++ b/ui-src/lib/types/frame/frameShape.d.ts @@ -1,6 +1,7 @@ -import { Shape } from '@ui/lib/types/shape'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { Children } from '@ui/lib/types/utils/children'; import { FrameAttributes } from './frameAttributes'; -export type FrameShape = Shape & FrameAttributes & Children; +export type FrameShape = ShapeBaseAttributes & ShapeGeomAttributes & FrameAttributes & Children; diff --git a/ui-src/lib/types/group/groupAttributes.ts b/ui-src/lib/types/group/groupAttributes.ts index bf5a417..0e6e5fe 100644 --- a/ui-src/lib/types/group/groupAttributes.ts +++ b/ui-src/lib/types/group/groupAttributes.ts @@ -4,6 +4,5 @@ export const GROUP_TYPE: unique symbol = Symbol.for('group'); export type GroupAttributes = { type: 'group' | typeof GROUP_TYPE; - id?: Uuid; shapes?: Uuid[]; }; diff --git a/ui-src/lib/types/group/groupShape.d.ts b/ui-src/lib/types/group/groupShape.d.ts index 7234fc0..48fe4a6 100644 --- a/ui-src/lib/types/group/groupShape.d.ts +++ b/ui-src/lib/types/group/groupShape.d.ts @@ -1,6 +1,12 @@ -import { Shape } from '@ui/lib/types/shape'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { Children } from '@ui/lib/types/utils/children'; import { GroupAttributes } from './groupAttributes'; -export type GroupShape = Shape & GroupAttributes & Children; +export type GroupShape = ShapeBaseAttributes & + ShapeGeomAttributes & + ShapeAttributes & + GroupAttributes & + Children; diff --git a/ui-src/lib/types/image/imageAttributes.ts b/ui-src/lib/types/image/imageAttributes.ts index 4fffe18..7b95f75 100644 --- a/ui-src/lib/types/image/imageAttributes.ts +++ b/ui-src/lib/types/image/imageAttributes.ts @@ -3,7 +3,6 @@ import { Uuid } from '@ui/lib/types/utils/uuid'; export const IMAGE_TYPE: unique symbol = Symbol.for('image'); export type ImageAttributes = { - id?: Uuid; type: 'image' | typeof IMAGE_TYPE; dataUri?: string; metadata: { diff --git a/ui-src/lib/types/image/imageShape.d.ts b/ui-src/lib/types/image/imageShape.d.ts index 6ef9fdd..d3b5d1a 100644 --- a/ui-src/lib/types/image/imageShape.d.ts +++ b/ui-src/lib/types/image/imageShape.d.ts @@ -1,5 +1,10 @@ -import { Shape } from '@ui/lib/types/shape'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { ImageAttributes } from './imageAttributes'; -export type ImageShape = Shape & ImageAttributes; +export type ImageShape = ShapeBaseAttributes & + ShapeGeomAttributes & + ShapeAttributes & + ImageAttributes; diff --git a/ui-src/lib/types/layout/layoutChildAttributes.ts b/ui-src/lib/types/layout/layoutChildAttributes.ts new file mode 100644 index 0000000..f298f0c --- /dev/null +++ b/ui-src/lib/types/layout/layoutChildAttributes.ts @@ -0,0 +1,55 @@ +export const ITEM_MARGIN_SIMPLE_TYPE: unique symbol = Symbol.for('simple'); +export const ITEM_MARGIN_MULTIPLE_TYPE: unique symbol = Symbol.for('multiple'); +export const ITEM_HSIZING_FILL: unique symbol = Symbol.for('fill'); +export const ITEM_HSIZING_FIX: unique symbol = Symbol.for('fix'); +export const ITEM_HSIZING_AUTO: unique symbol = Symbol.for('auto'); +export const ITEM_VSIZING_FILL: unique symbol = Symbol.for('fill'); +export const ITEM_VSIZING_FIX: unique symbol = Symbol.for('fix'); +export const ITEM_VSIZING_AUTO: unique symbol = Symbol.for('auto'); +export const ITEM_ALIGN_SELF_START: unique symbol = Symbol.for('start'); +export const ITEM_ALIGN_SELF_END: unique symbol = Symbol.for('end'); +export const ITEM_ALIGN_SELF_CENTER: unique symbol = Symbol.for('center'); +export const ITEM_ALIGN_SELF_STRETCH: unique symbol = Symbol.for('stretch'); + +export type LayoutChildAttributes = { + layoutItemMarginType?: + | 'simple' + | 'multiple' + | typeof ITEM_MARGIN_SIMPLE_TYPE + | typeof ITEM_MARGIN_MULTIPLE_TYPE; + layoutItemMargin?: { + m1?: number; + m2?: number; + m3?: number; + m4?: number; + }; + layoutItemMaxH?: number; + layoutItemMinH?: number; + layoutItemMaxW?: number; + layoutItemMinW?: number; + layoutItemHSizing?: + | 'fill' + | 'fix' + | 'auto' + | typeof ITEM_HSIZING_FILL + | typeof ITEM_HSIZING_FIX + | typeof ITEM_HSIZING_AUTO; + layoutItemVSizing?: + | 'fill' + | 'fix' + | 'auto' + | typeof ITEM_VSIZING_FILL + | typeof ITEM_VSIZING_FIX + | typeof ITEM_VSIZING_AUTO; + layoutItemAlignSelf?: + | 'start' + | 'end' + | 'center' + | 'stretch' + | typeof ITEM_ALIGN_SELF_START + | typeof ITEM_ALIGN_SELF_END + | typeof ITEM_ALIGN_SELF_CENTER + | typeof ITEM_ALIGN_SELF_STRETCH; + layoutItemAbsolute?: boolean; + layoutItemZIndex?: number; +}; diff --git a/ui-src/lib/types/rect/rectAttributes.ts b/ui-src/lib/types/rect/rectAttributes.ts index 2db19ef..7f91451 100644 --- a/ui-src/lib/types/rect/rectAttributes.ts +++ b/ui-src/lib/types/rect/rectAttributes.ts @@ -1,8 +1,5 @@ -import { Uuid } from '@ui/lib/types/utils/uuid'; - export const RECT_TYPE: unique symbol = Symbol.for('rect'); export type RectAttributes = { type: 'rect' | typeof RECT_TYPE; - id?: Uuid; }; diff --git a/ui-src/lib/types/rect/rectShape.d.ts b/ui-src/lib/types/rect/rectShape.d.ts index b169150..e5c6319 100644 --- a/ui-src/lib/types/rect/rectShape.d.ts +++ b/ui-src/lib/types/rect/rectShape.d.ts @@ -1,5 +1,12 @@ -import { Shape } from '@ui/lib/types/shape'; +import { LayoutChildAttributes } from '@ui/lib/types/layout/layoutChildAttributes'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { RectAttributes } from './rectAttributes'; -export type RectShape = Shape & RectAttributes; +export type RectShape = ShapeBaseAttributes & + ShapeGeomAttributes & + ShapeAttributes & + RectAttributes & + LayoutChildAttributes; diff --git a/ui-src/lib/types/shape.d.ts b/ui-src/lib/types/shape/shapeAttributes.d.ts similarity index 85% rename from ui-src/lib/types/shape.d.ts rename to ui-src/lib/types/shape/shapeAttributes.d.ts index 89aba4d..ef07eb7 100644 --- a/ui-src/lib/types/shape.d.ts +++ b/ui-src/lib/types/shape/shapeAttributes.d.ts @@ -1,19 +1,21 @@ +import { BlendMode } from '@ui/lib/types/utils/blendModes'; import { Blur } from '@ui/lib/types/utils/blur'; import { Export } from '@ui/lib/types/utils/export'; import { Fill } from '@ui/lib/types/utils/fill'; import { Grid } from '@ui/lib/types/utils/grid'; import { Interaction } from '@ui/lib/types/utils/interaction'; -import { Matrix } from '@ui/lib/types/utils/matrix'; import { Point } from '@ui/lib/types/utils/point'; import { Selrect } from '@ui/lib/types/utils/selrect'; import { Shadow } from '@ui/lib/types/utils/shadow'; import { Stroke } from '@ui/lib/types/utils/stroke'; -export type Shape = { +export type ShapeAttributes = { name?: string; componentId?: string; componentFile?: string; componentRoot?: boolean; + mainInstance?: boolean; + remoteSynced?: boolean; shapeRef?: string; selrect?: Selrect; points?: Point[]; @@ -35,17 +37,11 @@ export type Shape = { r2?: number; r3?: number; r4?: number; - x?: number; - y?: number; - width?: number; - height?: number; opacity?: number; grids?: Grid[]; exports?: Export[]; strokes?: Stroke[]; - transform?: Matrix; - transformInverse?: Matrix; - blendMode?: string; + blendMode?: BlendMode; interactions?: Interaction[]; shadow?: Shadow[]; blur?: Blur; diff --git a/ui-src/lib/types/shape/shapeBaseAttributes.ts b/ui-src/lib/types/shape/shapeBaseAttributes.ts new file mode 100644 index 0000000..f2ec611 --- /dev/null +++ b/ui-src/lib/types/shape/shapeBaseAttributes.ts @@ -0,0 +1,47 @@ +import { Matrix } from '@ui/lib/types/utils/matrix'; +import { Point } from '@ui/lib/types/utils/point'; +import { Selrect } from '@ui/lib/types/utils/selrect'; +import { Uuid } from '@ui/lib/types/utils/uuid'; + +import { BOOL_TYPE } from '../bool/boolAttributes'; +import { CIRCLE_TYPE } from '../circle/circleAttributes'; +import { FRAME_TYPE } from '../frame/frameAttributes'; +import { GROUP_TYPE } from '../group/groupAttributes'; +import { IMAGE_TYPE } from '../image/imageAttributes'; +import { RECT_TYPE } from '../rect/rectAttributes'; +import { TEXT_TYPE } from '../text/textAttributes'; + +// @TODO: Move to its own file once we support all the shapes +export const PATH_TYPE: unique symbol = Symbol.for('path'); +export const SVG_RAW_TYPE: unique symbol = Symbol.for('svg-raw'); + +export type ShapeBaseAttributes = { + id?: Uuid; + name?: string; + type: + | 'frame' + | 'group' + | 'bool' + | 'rect' + | 'path' + | 'text' + | 'circle' + | 'svg-raw' + | 'image' + | typeof FRAME_TYPE + | typeof GROUP_TYPE + | typeof BOOL_TYPE + | typeof RECT_TYPE + | typeof PATH_TYPE + | typeof TEXT_TYPE + | typeof CIRCLE_TYPE + | typeof SVG_RAW_TYPE + | typeof IMAGE_TYPE; + selrect?: Selrect; + points?: Point[]; + transform?: Matrix; + transformInverse?: Matrix; + parentId?: Uuid; + frameId?: Uuid; + rotation?: number; +}; diff --git a/ui-src/lib/types/shape/shapeGeomAttributes.d.ts b/ui-src/lib/types/shape/shapeGeomAttributes.d.ts new file mode 100644 index 0000000..dba4ff0 --- /dev/null +++ b/ui-src/lib/types/shape/shapeGeomAttributes.d.ts @@ -0,0 +1,6 @@ +export type ShapeGeomAttributes = { + x: number; + y: number; + width: number; + height: number; +}; diff --git a/ui-src/lib/types/text/textAttributes.ts b/ui-src/lib/types/text/textAttributes.ts index dc90414..411d742 100644 --- a/ui-src/lib/types/text/textAttributes.ts +++ b/ui-src/lib/types/text/textAttributes.ts @@ -1,11 +1,8 @@ -import { Uuid } from '@ui/lib/types/utils/uuid'; - import { TextContent } from './textContent'; export const TEXT_TYPE: unique symbol = Symbol.for('text'); export type TextAttributes = { - id?: Uuid; type: 'text' | typeof TEXT_TYPE; content?: TextContent; }; diff --git a/ui-src/lib/types/text/textShape.d.ts b/ui-src/lib/types/text/textShape.d.ts index a152f7e..bde8b8c 100644 --- a/ui-src/lib/types/text/textShape.d.ts +++ b/ui-src/lib/types/text/textShape.d.ts @@ -1,5 +1,10 @@ -import { Shape } from '@ui/lib/types/shape'; +import { ShapeAttributes } from '@ui/lib/types/shape/shapeAttributes'; +import { ShapeBaseAttributes } from '@ui/lib/types/shape/shapeBaseAttributes'; +import { ShapeGeomAttributes } from '@ui/lib/types/shape/shapeGeomAttributes'; import { TextAttributes } from './textAttributes'; -export type TextShape = Shape & TextAttributes; +export type TextShape = ShapeBaseAttributes & + ShapeGeomAttributes & + ShapeAttributes & + TextAttributes; diff --git a/ui-src/lib/types/utils/blendModes.ts b/ui-src/lib/types/utils/blendModes.ts new file mode 100644 index 0000000..8f8c628 --- /dev/null +++ b/ui-src/lib/types/utils/blendModes.ts @@ -0,0 +1,50 @@ +export const BLEND_MODE_NORMAL: unique symbol = Symbol.for('normal'); +export const BLEND_MODE_DARKEN: unique symbol = Symbol.for('darken'); +export const BLEND_MODE_MULTIPLY: unique symbol = Symbol.for('multiply'); +export const BLEND_MODE_COLOR_BURN: unique symbol = Symbol.for('color-burn'); +export const BLEND_MODE_LIGHTEN: unique symbol = Symbol.for('lighten'); +export const BLEND_MODE_SCREEN: unique symbol = Symbol.for('screen'); +export const BLEND_MODE_COLOR_DODGE: unique symbol = Symbol.for('color-dodge'); +export const BLEND_MODE_OVERLAY: unique symbol = Symbol.for('overlay'); +export const BLEND_MODE_SOFT_LIGHT: unique symbol = Symbol.for('soft-light'); +export const BLEND_MODE_HARD_LIGHT: unique symbol = Symbol.for('hard-light'); +export const BLEND_MODE_DIFFERENCE: unique symbol = Symbol.for('difference'); +export const BLEND_MODE_EXCLUSION: unique symbol = Symbol.for('exclusion'); +export const BLEND_MODE_HUE: unique symbol = Symbol.for('hue'); +export const BLEND_MODE_SATURATION: unique symbol = Symbol.for('saturation'); +export const BLEND_MODE_COLOR: unique symbol = Symbol.for('color'); +export const BLEND_MODE_LUMINOSITY: unique symbol = Symbol.for('luminosity'); + +export type BlendMode = + | 'normal' + | 'darken' + | 'multiply' + | 'color-burn' + | 'lighten' + | 'screen' + | 'color-dodge' + | 'overlay' + | 'soft-light' + | 'hard-light' + | 'difference' + | 'exclusion' + | 'hue' + | 'saturation' + | 'color' + | 'luminosity' + | typeof BLEND_MODE_NORMAL + | typeof BLEND_MODE_DARKEN + | typeof BLEND_MODE_MULTIPLY + | typeof BLEND_MODE_COLOR_BURN + | typeof BLEND_MODE_LIGHTEN + | typeof BLEND_MODE_SCREEN + | typeof BLEND_MODE_COLOR_DODGE + | typeof BLEND_MODE_OVERLAY + | typeof BLEND_MODE_SOFT_LIGHT + | typeof BLEND_MODE_HARD_LIGHT + | typeof BLEND_MODE_DIFFERENCE + | typeof BLEND_MODE_EXCLUSION + | typeof BLEND_MODE_HUE + | typeof BLEND_MODE_SATURATION + | typeof BLEND_MODE_COLOR + | typeof BLEND_MODE_LUMINOSITY; diff --git a/ui-src/translators/index.ts b/ui-src/translators/index.ts index c570ed8..05c5fa2 100644 --- a/ui-src/translators/index.ts +++ b/ui-src/translators/index.ts @@ -2,3 +2,4 @@ export * from './translateFontStyle'; export * from './translateHorizontalAlign'; export * from './translateVerticalAlign'; export * from './translateFillGradients'; +export * from './translateUiBlendMode'; diff --git a/ui-src/translators/translateUiBlendMode.ts b/ui-src/translators/translateUiBlendMode.ts new file mode 100644 index 0000000..0d45cf0 --- /dev/null +++ b/ui-src/translators/translateUiBlendMode.ts @@ -0,0 +1,59 @@ +import { + BLEND_MODE_COLOR_BURN, + BLEND_MODE_COLOR_DODGE, + BLEND_MODE_DARKEN, + BLEND_MODE_DIFFERENCE, + BLEND_MODE_EXCLUSION, + BLEND_MODE_HARD_LIGHT, + BLEND_MODE_HUE, + BLEND_MODE_LIGHTEN, + BLEND_MODE_LUMINOSITY, + BLEND_MODE_MULTIPLY, + BLEND_MODE_NORMAL, + BLEND_MODE_OVERLAY, + BLEND_MODE_SATURATION, + BLEND_MODE_SCREEN, + BLEND_MODE_SOFT_LIGHT, + BlendMode +} from '@ui/lib/types/utils/blendModes'; + +export const translateUiBlendMode = (blendMode?: BlendMode): BlendMode | undefined => { + if (!blendMode) return blendMode; + + switch (blendMode) { + case 'normal': + return BLEND_MODE_NORMAL; + case 'darken': + return BLEND_MODE_DARKEN; + case 'multiply': + return BLEND_MODE_MULTIPLY; + case 'color-burn': + return BLEND_MODE_COLOR_BURN; + case 'lighten': + return BLEND_MODE_LIGHTEN; + case 'screen': + return BLEND_MODE_SCREEN; + case 'color-dodge': + return BLEND_MODE_COLOR_DODGE; + case 'overlay': + return BLEND_MODE_OVERLAY; + case 'soft-light': + return BLEND_MODE_SOFT_LIGHT; + case 'hard-light': + return BLEND_MODE_HARD_LIGHT; + case 'difference': + return BLEND_MODE_DIFFERENCE; + case 'exclusion': + return BLEND_MODE_EXCLUSION; + case 'hue': + return BLEND_MODE_HUE; + case 'saturation': + return BLEND_MODE_SATURATION; + case 'color': + return BLEND_MODE_COLOR_BURN; + case 'luminosity': + return BLEND_MODE_LUMINOSITY; + default: + return BLEND_MODE_NORMAL; + } +};