UNPKG

@mastergo/plugin-typings

Version:
2,029 lines (1,792 loc) 72.1 kB
import { Properties, PropertiesHyphen } from 'csstype'; declare global { namespace MGDSL { interface MGDSLData { /** * 版本信息,遵循SemVer规则 */ readonly version: string; /** * 框架类型 */ framework: Framework; readonly nodeMap: Record<NodeId, MGNode>; readonly localStyleMap: StyleMap; readonly fileMap: Record<FileId, MGDSLFile>; root: MGLayerNode; settings: DSLSettings; entry: FileId; /** * 预览代码时所引入模块,需要将配置模型上的依赖模块引入 */ importPath: ImportPath; importType: 'GLOBAL' | 'IMPORT'; } type ImportPath = { name: string; path: string; type: 'script' | 'style'; importRule?: 'ALL' | 'DEFAULT' | 'NAMED'; }[]; // js dsl模板 interface JSDSLData extends MGDSLData { /** * 全局样式表 */ globalStyleMap: { [classId: string]: ClassStyle; }; } interface ReactDSLData extends JSDSLData { readonly framework: 'REACT'; } interface Vue3DSLData extends JSDSLData { readonly framework: 'VUE3'; } interface Vue2DSLData extends JSDSLData { readonly framework: 'VUE2'; } interface AndroidDSLData extends MGDSLData { readonly framework: 'ANDROID'; /** * 全局样式表 */ globalStyleMap: { [classId: string]: ClassStyle; }; } interface IOSDSLData extends MGDSLData { readonly framework: 'IOS'; } type Framework = 'REACT' | 'VUE2' | 'VUE3' | 'ANDROID' | 'IOS'; type TokenName = string; type TokenVariable = string; type TokenValue = MGDSL.StyleSet[keyof MGDSL.StyleSet]; /** * 自定义样式 */ type TokenItem = TokenCommonItem | TokenTextItem | TokenEffectItem; type TokenCommonItem = { id: string; type: 'color' | 'padding' | 'border-radius' | 'border-width' | 'gap'; name: TokenName; originName: string; originAlias: string; value: TokenValue; variable: TokenVariable; /** * 是否是多段 */ isMultiple?: boolean; }; type TokenTextSubItemType = 'font' | 'fontfamily' | 'fontstyle' | 'fontsize' | 'lineheight' | 'decoration' | 'letterspacing'; type TokenTextItem = { id: string; type: 'text'; name: TokenName; originName: string; originAlias: string; variable: TokenVariable; textItems: Record<TokenTextSubItemType, TokenTextSubItem>; }; type TokenTextSubItem = { type: TokenTextSubItemType; name: TokenName; value: TokenValue; }; type TokenEffectItem = { id: string; type: 'effect'; name: TokenName; originName: string; originAlias: string; value: TokenValue; variable: TokenVariable; effectItems: Record<TokenEffectSubItemType, TokenEffectSubItem>; }; type TokenEffectSubItemType = 'shadow' | 'filter' | 'backdropfilter'; type TokenEffectSubItem = { type: TokenEffectSubItemType; name: TokenName; value: TokenValue; }; /** * TODO: 安卓自定义样式 */ type AndroidStyleItem = any; /** * 自定义样式map */ type StyleMap = { [styleId: string]: TokenItem | AndroidStyleItem; }; /** * 配置 */ interface DSLSettings { /** * 是否使用自定义样式,默认为true */ useToken: boolean; } interface ClassStyle { id: ClassId; name: string; scoped: boolean; value: StyleSet; // 伪类 pseudo?: 'HOVER' | 'ACTIVE' | 'FOCUS' | 'DISABLED'; /** * css类型 * */ type: 'group' | 'class' | 'pseudo' | 'id' | 'attribute' | 'combinators'; } type NodeId = LayerId | OperationId; type LayerId = string; type OperationId = string; type MGNode = MGLayerNode | MGOperationNode; interface MGLayerNode { type: 'LAYER'; id: LayerId; children: NodeId[]; name: string; /** * 图层在代码中的组件名 */ componentName: string; /** * 图层实际类型名称 RECTANGLE TEXT FRAME... */ layerType: NodeType; // 是否是蒙版 isMask: boolean; // 是否隐藏 isVisible: boolean; layout: NodeLayout; style: CssNodeStyle | IOSNodeStyle | AndroidNodeStyle; /** * 是否是根元素 */ isRoot: boolean; parent?: NodeId; /** * 关联的文件 */ relatedFile: FileId; /** * 是否拆分成新文件,默认false */ isNewFile?: boolean; characters: string; } type DocumentationLink = { url: string; }; interface MGComponentNode extends MGLayerNode { layerType: 'COMPONENT'; alias: string; description: string; documentationLinks: DocumentationLink[]; /** * 是组件集子组件的话则存在 */ componentSetId?: string; componentSetDescription?: string; componentSetDocumentationLinks?: DocumentationLink[]; } interface MGInstanceNode extends MGLayerNode { layerType: 'INSTANCE'; /** * 实例的主组件Layer, 这里不开通用模型就不解析 */ mainComponent?: LayerId; description: string; documentationLinks: DocumentationLink[]; componentSetDescription?: string; componentSetDocumentationLinks?: DocumentationLink[]; } interface MGCustomNode extends MGLayerNode { layerType: 'CUSTOM'; tagName?: string; props?: ComponentProp[]; imports: ImportItem[]; } interface MGTextNode extends MGLayerNode { characters: string; } type NodeType = | 'GROUP' | 'FRAME' | 'RECTANGLE' | 'TEXT' | 'LINE' | 'ELLIPSE' | 'POLYGON' | 'STAR' | 'PEN' | 'COMPONENT' | 'COMPONENTSET' | 'INSTANCE' | 'BOOLEANOPERATION' | 'SLICE' | 'CONNECTOR' | 'SECTION' | 'CUSTOM' | 'Input' | 'TABLE' | 'Select' | 'Chart' | 'TOGGLE' | 'BUTTON' | 'TREE' | 'TEXTSHAPE' /** * 图层的布局信息 */ interface NodeLayout { /** * 相对矩阵 */ matrix?: Matrix; width?: Dimension; height?: Dimension; /** * 实际在画布渲染的宽 包括阴影外描边 */ renderWidth?: Dimension; /** * 实际在画布渲染的高 包括阴影外描边 */ renderHeight?: Dimension; /** * 自动布局 */ autoLayout?: AutoLayout; overflow?: 'HIDDEN' | 'VISIBLE'; /** * 相对于父元素的布局 */ relatedLayout?: AbsoluteLayout | RelatedAutoLayout; } /** * 自动布局 */ type AutoLayout = { direction: 'COLUMN' | 'ROW'; layoutWrap: 'NO_WRAP' | 'WRAP'; // 轴距 itemSpacing: Dimension | 'AUTO'; // 交叉轴距, 只有在 layoutWrap = 'WRAP'时生效 crossAxisSpacing: Dimension | 'AUTO' | null; paddingTop: Dimension; paddingRight: Dimension; paddingBottom: Dimension; paddingLeft: Dimension; /** * 主轴对齐方式 */ mainAxisAlignItems: AlignTypes; /** * 交叉轴对齐方式 */ crossAxisAlignItems: Exclude<AlignTypes, 'SPACE_BETWEEN'>; /** * 仅当换行的时候,交叉轴的多行对齐方式 */ crossAxisAlignContent: 'AUTO' | 'SPACE_BETWEEN'; /** * 描边是否包含在布局内 */ strokesIncludedInLayout: boolean; itemReverseZIndex: boolean; }; /** * 绝对定位 */ type AbsoluteLayout = { type: 'ABSOLUTE'; bound: { left?: Dimension; right?: Dimension; top?: Dimension; bottom?: Dimension; }; /** * 包含外描边和阴影,实际渲染的bound */ renderBound: { left?: Dimension; right?: Dimension; top?: Dimension; bottom?: Dimension; }; }; /** * 相对于父元素的自动布局 */ type RelatedAutoLayout = { type: 'AUTO'; alignSelf: 'STRETCH' | 'INHERIT' | 'AUTO'; flexGrow: number; }; type Matrix = [[number, number, number], [number, number, number]]; /** * flex布局主轴 */ type AlignTypes = 'START' | 'END' | 'CENTER' | 'SPACE_BETWEEN'; /** * 尺寸单位 */ type Dimension = { type: 'PIXEL' | 'PERCENT' | 'CALC'; value: number | string; }; interface NodeStyle { /** * 和localClassMap的key保持一致 */ id: `style-${NodeId}`; type: NodeStyleType; disable?: boolean; } /** * 分段样式 */ type TextSegStyle = { start: number; end: number; textStyleId: string; textStyle: StyleSet; }; interface CssNodeStyle extends NodeStyle { /** * css类名 */ name: string; /** * UI样式 */ value: StyleSet; /** * 布局样式 */ layoutStyles: StyleSet; /** * key为属性名称 */ attributes: Record<string, AttributeItem>; /** * 行内样式 */ inlineStyles?: StyleSet; /** * 动态行内样式 */ dynamicInlineStyles?: { [key in keyof StyleSet]: string; }; /** * 文字分段样式 */ textStyles?: TextSegStyle[]; /** * 样式名数组 */ classList?: ClassId[]; /** * 标签名称 */ tag?: 'IMG' | 'DIV' | 'TEXT' | 'BUTTON' | 'INPUT' | 'SLOT' | 'SVG' | 'OPTION'; /** * 子选择器 */ subSelectors?: Array<ClassStyle>; /** * 样式token关联 */ styleTokenAlias?: { backgroundTokenId?: string; strokeColorTokenId?: string; paddingTokenId?: string; gapTokenId?: string; crossGapTokenId?: string; radiusTokenId?: string; }; } /** * STATIC 静态属性 * DYNAMIC 动态属性 * METHOD 方法 * UNBIND 只定义,但没有使用的属性 */ type Attribute = 'STATIC' | 'DYNAMIC' | 'METHOD' | 'UNBIND'; interface AttributeItem { type: Attribute; /** * 属性名 */ name: string; /** * 属性值或者是对应的函数名称 */ value: string; /** * 参数类型 */ valueType: keyof ComponentPropType; /** * 属性值的来源 */ valueSource?: 'PROPS' | 'METHODS' | 'DATA'; /** * 函数的表达式 */ expression?: string; /** * 默认值 */ defaultValue?: string | number | boolean; /** * 方法的传参 */ arguments?: string[]; } type IOSNodeStyle = NodeStyle; interface AndroidNodeStyle extends NodeStyle { /** * android样式 */ attributes: Record<string, string>; /** * 控件标签 */ // eslint-disable-next-line tag: 'View' | 'Canvas' | 'ImageView' | 'TextView' | 'EditText' | 'Button' | 'Spinner' | 'RadioButton' | 'CheckBox' | 'androidx.recyclerview.widget.RecyclerView' | 'ScrollView' | 'HorizontalScrollView' | 'androidx.constraintlayout.widget.ConstraintLayout' | 'com.example.mapplication.utils.MSvg'; /** * 关联的文件 */ subFiles: AndroidFileType[]; /** * 是否是slot */ slot: boolean; /** * 包路径 */ package: string; /** * 溢出方向 */ overflowDirection: number; effect: any; } type AndroidFileType = AndroidXMLFile | AndroidJavaFile; interface AndroidFile { name: string; type: string; path: string; } interface AndroidXMLFile extends AndroidFile { type: 'xml'; header: string; footer: string; content: AndroidXMLFileTag[]; } interface AndroidXMLFileTag { tag: string; attributes: Record<string, string>; children?: AndroidXMLFileTag[]; } interface AndroidJavaFile extends AndroidFile { type: 'java'; package: string; imports: string[]; className: string; variables: Record<string, string>; } interface AndroidKotlinFile extends AndroidFile { type: 'kotlin'; package: string; imports: string[]; className: string; variables: Record<string, string>; } interface AndroidBitmapFile extends AndroidFile { type: 'png' | 'jpeg'; imageRef: string; } interface StyleSet extends Properties<string | number>, PropertiesHyphen<string | number> {} // style-class-xx type ClassId = string; type NodeStyleType = 'VIEW' | 'SVG' | 'IMAGE' | 'TEXT' | 'INPUT' | 'BUTTON' | 'SCROLLVIEW'; type AndroidTag = { SVG: 'com.example.mapplication.utils.MSvg'; IMAGE: 'ImageView'; TEXT: 'TextView'; INPUT: 'EditText'; BUTTON: 'Button'; SELECT: 'Spinner'; RADIO: 'RadioButton'; CHECKBOX: 'CheckBox'; SCROLLVIEW: 'ScrollView'; LIST: 'androidx.recyclerview.widget.RecyclerView'; VIEW: 'androidx.constraintlayout.widget.ConstraintLayout'; }; /** * 运算符 */ type MGOperationNode = IfStatement | Iteration | Raw | TernaryExpression; /** * 条件判断 */ interface IfStatement { id: OperationId; type: 'OPERATION'; operationType: 'If_STATEMENT'; // 表达式 condition: string; consequent: { type: 'MGNode' | 'EXPRESSION'; body: MGNode | string; }; alternate: { type: 'MGNode' | 'EXPRESSION'; body: MGNode | string; }; } /** * 迭代器 */ interface Iteration { id: OperationId; type: 'OPERATION'; operationType: 'ITERATOR'; // 迭代器的变量名 variable: string; body: MGNode; // 作为key的变量名,属于迭代变量中元素上的字段 key?: string; } /** * 原始字符串 */ interface Raw { id: OperationId; type: 'OPERATION'; operationType: 'RAW'; body: string; } /** * 三目运算 */ interface TernaryExpression { id: OperationId; type: 'OPERATION'; operationType: 'TERNARY_EXPRESSION'; condition: string; trueExpression: { type: 'MGNode' | 'EXPRESSION'; body: MGNode | string; }; falseExpression: { type: 'MGNode' | 'EXPRESSION'; body: MGNode | string; }; } type ImportItem = { name: string; path: string; /** * DEFAULT: import name from 'path' * ALL: import * as name from 'path' * NAMED: import { name } from 'path' */ type: 'DEFAULT' | 'ALL'; // | 'NAMED' }; interface MGDSLFile { id: FileId; name: string; entryLayerId: LayerId; chunks: FileId[]; data: Record<string, Data>; props: Record<string, Prop>; methods: Record<string, Method>; computed: Record<string, Computed>; // 导入 imports: ImportItem[]; } type FileId = string; type ComponentPropType = { STRING: string; NUMBER: number; BOOLEAN: boolean; FUNCTION: string | MGLayerNode[]; OBJECT: Record<string, ComponentPropValue<keyof ComponentPropType>>; ARRAY: ComponentPropValue<keyof ComponentPropType>[]; SLOT: string | MGLayerNode[]; }; type ComponentPropValue<T extends keyof ComponentPropType> = { type: T; value: ComponentPropType[T]; }; type ComponentPropItem<T extends keyof ComponentPropType> = { /** * 类型 */ type: T; /** * 默认值,也可作为初始值使用 */ defaultValue?: ComponentPropType[T]; /** * 属性名,根据aliasName和originalName经过处理后的名称,用于最终的展示 */ name: string; }; type ComponentPropString = ComponentPropItem<'STRING'>; type ComponentPropNumber = ComponentPropItem<'NUMBER'>; type ComponentPropBoolean = ComponentPropItem<'BOOLEAN'>; type ComponentPropFunction = ComponentPropItem<'FUNCTION'>; type ComponentPropObject = ComponentPropItem<'OBJECT'>; type ComponentPropArray = ComponentPropItem<'ARRAY'>; type ComponentPropSlot = ComponentPropItem<'SLOT'>; type ComponentProp = | ComponentPropString | ComponentPropNumber | ComponentPropBoolean | ComponentPropFunction | ComponentPropObject | ComponentPropArray | ComponentPropSlot; interface Method { name: string; args: Array<string>; content: string; returnValue?: string; } type DSLNumber = { type: 'NUMBER'; /** * 默认值,也可作为初始值使用 */ defaultValue?: number | undefined; name: string; }; type DSLBoolean = { type: 'BOOLEAN'; defaultValue?: boolean | undefined; name: string; }; type DSLString = { type: 'STRING'; /** * 默认值,也可作为初始值使用 */ defaultValue?: string | undefined; name: string; }; type DSLFunction = { type: 'FUNCTION'; defaultValue?: string | undefined; name: string; }; type DSLArray = { type: 'ARRAY'; defaultValue?: Array<any> | undefined; name: string; }; type DSLObject = { type: 'OBJECT'; /** * 默认值,也可作为初始值使用 */ defaultValue?: { [key: string]: any }; name: string; }; type Data = DSLString | DSLNumber | DSLBoolean | DSLFunction | DSLArray | DSLObject; type Prop = DSLString | DSLNumber | DSLBoolean | DSLFunction | DSLArray | DSLObject; interface Computed { name: string; args: Array<string>; content: string; returnValue?: string; dependencies?: Array<string>; } interface CustomCode { type: 'custom'; data: { title: string; code: string; // 暂时不设置类型 type: string; }[]; } } } declare global { namespace MGTMP { type RegExpString = string; type PseudoType = 'HOVER' | 'ACTIVE' | 'FOCUS' | 'DISABLED'; /** * 工具类样式,如:.flex-1 { flex: 1 } * 通常为写死的样式,不会根据数据动态生成。当value与DSLToCode.StyleNode.value相同时,可以直接使用StyleRule.className作为DSLToCode.StyleNode.className */ type UtilityStyle = { type: 'UTILITY'; className: string; pseudo?: PseudoType; value: Properties & PropertiesHyphen; }; /** * 配置类样式,如:.bg-color { background-color: var(--bg-color) },.bg-color:hover { background-color: var(--bg-color-hover) }, * 根据token的值按配置规则动态生成的样式。 */ type ConfigStyle = { type: 'CONFIG'; prefix: string; output: (token: string, tokenNameWithoutPrefix: string) => UtilityStyle[]; }; type StyleRule = UtilityStyle | ConfigStyle; type StyleTemplate = StyleRule[]; /** * 组件属性类型 */ type ComponentPropType = { STRING: string; NUMBER: number; BOOLEAN: boolean; FUNCTION: string | MGDSL.MGLayerNode[]; OBJECT: Record<string, MGDSL.ComponentPropValue<keyof ComponentPropType>>; ARRAY: MGDSL.ComponentPropValue<keyof ComponentPropType>[]; SLOT: string | MGDSL.MGLayerNode[]; }; type GetValueType<T extends keyof ComponentPropType> = ( nodeId: MGDSL.LayerId, nodeMap: Record<MGDSL.NodeId, MGDSL.MGNode>, componentId?: string, ) => { value: ComponentPropType[T] | undefined; nodeMap: Record<string, MGDSL.MGLayerNode>; }; type ComponentPropItem<T extends keyof ComponentPropType> = { /** * 类型 */ type: T; /** * 默认值,也可作为初始值使用 */ defaultValue?: ComponentPropType[T]; /** * 该方法内部需要bridge函数支持,不适合在配置模板中使用,请尽量少的使用该函数作判断 */ getValue?: GetValueType<T>; /** * 属性名,根据aliasName和originalName经过处理后的名称,用于最终的展示 */ name: string; /** * 属性别名 */ aliasName?: string; /** * 原始名称,区别于经过处理的name */ originalName?: string; /** * 属性枚举值对应关系。一般和aliasName配合使用,根据画布图层的属性值,映射到代码中的属性值 */ aliasMap?: Record<string, ComponentPropType[T] | undefined>; /** * DSM属性枚举值对应关系 */ dsmAlias?: Record<string, string>; /** * 组件库解析时,是否将大写属性值转换为小写 */ lowerCase?: boolean; /** * 是否应用该属性 * @param aliasName 对应画布图层属性名,当前当前仅支持属性名的判断 * @param aliasMap 对应画布图层属性值 */ visible?: { aliasName: string; aliasMap?: Record<string, boolean>; }; }; /** * 组件属性类型 * 泛型没有显式指定类型时,会被推断所有生命类型,起不到约束作用 */ type ComponentPropString = ComponentPropItem<'STRING'> & { /** * 如果是string,允许已某个图层的content作为值 */ nodePath?: SlotMatchType[]; }; type ComponentPropNumber = ComponentPropItem<'NUMBER'>; type ComponentPropBoolean = ComponentPropItem<'BOOLEAN'>; type ComponentPropFunction = ComponentPropItem<'FUNCTION'>; type ComponentPropObject = ComponentPropItem<'OBJECT'>; type ComponentPropArray = ComponentPropItem<'ARRAY'>; type ComponentPropInstance = ComponentPropItem<'SLOT'> & { /** * react的INSTANCE视为Vue的SLOT效果,故这里提供nodePath属性,继续遍历图层并以此图层为属性内容 * 这里只能指向唯一图层才能向下遍历 */ nodePath?: SlotMatchType[]; ignoreClass?: boolean; }; /** * 组件的虚拟路径,如:'@/components/xxx.vue' * export default {} 为 DEFAULT * export const xxx = {} 为 xxx */ type ComponentSource = { path: string; export: 'DEFAULT' | string; }; /** * 组件属性 * @param type 属性类型 * @param name 属性名称 * @param defaultValue 属性默认值 * @param aliasName 对应设计系统的组件别名,如能匹配则根据别名生成代码 */ type ComponentProp = | ComponentPropString | ComponentPropNumber | ComponentPropBoolean | ComponentPropFunction | ComponentPropObject | ComponentPropArray | ComponentPropInstance; type ComponentData = { name: string; defaultValue: string | number | boolean; type: keyof ComponentPropType; }; type ComponentProps = { name: string; originalName?: string; defaultValue?: string | number | boolean; type: keyof ComponentPropType; }; type SlotMatchType = RegExpString | number; /** * 组件插槽 * @param name 插槽名称 * @param relateNodeNames 关联的节点名称 */ type ComponentSlot = { name: string; relateNodeNames: (SlotMatchType | SlotMatchType[])[]; ignoreClass?: boolean; } & ( | { type?: '' } | { type: 'TEXT'; } | { type: 'CUSTOM'; // 返回MGDSL数据,id可为空 getValue: GetValueType<'SLOT'>; } ); /** * 组件模板 * @param name 组件名称 * @param props 组件属性 * @param source 组件的虚拟路径 */ type ComponentOrigin = { name: string; props: ComponentProp[]; slots?: ComponentSlot[]; source: ComponentSource; ignoreRect?: boolean; }; type ComponentItem = ComponentOrigin & { id: string; matchName?: string }; // 图标库 type Icons = { /** * 组件名适配正则 */ reg: RegExpString; getValue: (node: MGDSL.MGLayerNode) => MGDSL.MGCustomNode; }; type ComponentTemplate = { // 防止组件库解析,存储对应文件id documentId: string; // 暂时作为唯一标识 name: string; /** * 组件导入类型 * GLOBAL 全局引入 * IMPORT esm引入 */ importType: 'GLOBAL' | 'IMPORT'; importPath: { name: string; importName: string; path: string; type: 'script' | 'style'; }[]; framework: 'VUE2' | 'VUE3' | 'REACT'; components: ComponentItem[]; icons?: Icons; }; } } declare global { /** * @deprecated please use mg instead */ const mastergo: PluginAPI const mg: PluginAPI const console: Console const __html__: string function setTimeout(callback: Function, timeout: number): number function clearTimeout(timeoutID: number): void function setInterval(callback: Function, timeout: number): number function clearInterval(timeoutID: number): void function requestAnimationFrame(cb: (ts: number) => void): number function cancelAnimationFrame(requestID: number): void interface Console { log(message?: any, ...optionalParams: any[]): void error(message?: any, ...optionalParams: any[]): void assert(condition?: boolean, message?: string, ...data: any[]): void info(message?: any, ...optionalParams: any[]): void warn(message?: any, ...optionalParams: any[]): void clear(): void } interface ConfirmAction { label: string type: 'primary' | 'text' action: () => void } interface PromptAction { label: string type: 'primary' | 'text' action: (value: string) => void } interface Image { readonly href: string getBytesAsync(): Promise<Uint8Array> } type ThemeColor = 'dark' | 'light' type LayoutInfo = { leftbar: number; rightbar: number; canvas: number; window: number; height: number; topbar: number; } type MGEventCallbackMap = { 'selectionchange': (selectionLayerIds: string[]) => void; 'layoutchange': (layoutInfo: LayoutInfo) => void; 'currentpagechange': (pageId: string) => void; 'themechange': (theme: ThemeColor) => void; 'drop': (event: DropEvent) => void; 'run': (command: { command: string }) => void; 'close': () => void; 'beforeReadyForDev': (sectionLayerId: string, callback: (setReady: boolean) => void) => void; } type PluginEventType = keyof MGEventCallbackMap interface PluginAPI { readonly document: DocumentNode readonly ui: UIAPI readonly themeColor: ThemeColor readonly apiVersion: string readonly documentId: number readonly pluginId: number readonly command: string readonly mixed: string | symbol readonly clientStorage: ClientStorageAPI readonly currentUser: User | null readonly viewport: ViewportAPI /** * @note only available in devMode */ readonly codegen?: CodegenAPI readonly snippetgen?: SnippetgenAPI readonly mode?: "inspect" | "design" | "codegen" | "snippetgen" closePlugin(): void on<T extends PluginEventType>(type: T, callback: MGEventCallbackMap[T]): void once<T extends PluginEventType>(type: T, callback: MGEventCallbackMap[T]): void off<T extends PluginEventType>(type?: T, callback?: MGEventCallbackMap[T]): void commitUndo(): void triggerUndo(): void showUI(html: string, options?: ShowUIOptions): void getNodeById<T extends SceneNode>(id: string): T | null getNodeByPosition(position: { x: number, y: number }): SceneNode | null createRectangle(): RectangleNode createLine(): LineNode createEllipse(): EllipseNode createPolygon(): PolygonNode createStar(): StarNode createPen(): PenNode createText(): TextNode createFrame(children?: SceneNode[]): FrameNode createComponent(children?: SceneNode[]): ComponentNode createSection(): SectionNode createPage(): PageNode createSlice(): SliceNode createConnector(): ConnectorNode createNodeFromSvgAsync(svg: string): Promise<FrameNode> combineAsVariants(nodes: ComponentNode[]): ComponentSetNode getHoverLayer(): PageNode | SceneNode /** * @deprecated * This function is deprecated, please use viewport.layoutGridVisible instead. */ showGrid(show: boolean): void group(children: SceneNode[]): GroupNode union(children: SceneNode[]): BooleanOperationNode subtract(children: SceneNode[]): BooleanOperationNode intersect(children: SceneNode[]): BooleanOperationNode exclude(children: SceneNode[]): BooleanOperationNode flatten(nodes: SceneNode[]): PenNode | null saveVersionHistoryAsync(desc: string, title?: string): Promise<void> notify(message: string, options?: NotifyOptions): NotificationHandler getStyleById(id: string): Style | null getStyleCodeById(id: string, options?: StyleCodeOptions): CodeString | null getWebStyleCodeById(id: string, options?: WebStyleCodeOptions): CodeString | null getAndroidStyleCodeById(id: string, options?: AndroidStyleCodeOptions): CodeString | null getIOSStyleCodeById(id: string, options?: IOSStyleCodeOptions): CodeString | null getTitleByFontFamilyAndStyle(fontFamily: string, fontStyle: string): FontAlias | null createFillStyle(config: CreateStyleConfig): PaintStyle createEffectStyle(config: CreateStyleConfig): EffectStyle createTextStyle(config: CreateStyleConfig): TextStyle createGridStyle(config: CreateStyleConfig): GridStyle createCornerRadiusStyle(config: CreateStyleConfig): CornerRadiusStyle createPaddingStyle(config: CreateStyleConfig): PaddingStyle createSpacingStyle(config: CreateStyleConfig): SpacingStyle /** * @deprecated please use createStrokeFillStyle instead */ createStrokeStyle(config: CreateStyleConfig): PaintStyle createStrokeFillStyle(config: CreateStyleConfig): PaintStyle createStrokeWidthStyle(config: CreateStyleConfig): StrokeWidthStyle /** * createFillStyle/createStrokeFillStyle 这些函数的聚合函数,传入不同的 type,返回对应的 style * @param layerId * @param type NodeStyleType * @param styleName * @param description optional */ createStyleByLayer<T extends NodeStyleType>(layerId: string, type: T, styleName: string, description?: string): NodeStyleReturnType<T> /** * 创建一个新的默认样式,不依赖某一个图层中的样式, * eg: createStyle('PAINT', 'New Style', 'This is a new style') * @param type styleType * @param styleName * @param description optional */ createStyle<T extends StyleType>(type: T, styleName: string, description?: string): StyleReturnType<T> /** * 创建某一个样式的副本 * @param sourceStyleId 副本的源样式id * @param type * @param styleName * @param description */ createStyleCopy<T extends StyleType = "PAINT">(sourceStyleId: string, styleName?: string, description?: string): StyleReturnType<T> getLocalPaintStyles(): PaintStyle[] getLocalEffectStyles(): EffectStyle[] getLocalTextStyles(): TextStyle[] getLocalGridStyles(): GridStyle[] getLocalStrokeWidthStyles(): StrokeWidthStyle[] getLocalCornerRadiusStyles(): CornerRadiusStyle[] getLocalPaddingStyles(): PaddingStyle[] getLocalSpacingStyles(): SpacingStyle[] listAvailableFontsAsync(): Promise<Font[]> loadFontAsync(fontName: FontName): Promise<boolean> createImage(imageData: Uint8Array, isSync?: boolean): Promise<Image> getImageByHref(href: string): Image getTeamLibraryAsync(): Promise<TeamLibrary>, importComponentByKeyAsync(ukey: string): Promise<ComponentNode>, importComponentSetByKeyAsync(ukey: string): Promise<ComponentSetNode>, importStyleByKeyAsync(ukey: string): Promise<Style>, /** * @deprecated * * This attribute is deprecated, please use getTeamLibraryAsync instead. */ teamLibrary: TeamLibrary, hexToRGBA(hex: string): RGBA RGBAToHex(rgba: RGBA): string confirm: (message: string, options: [ConfirmAction, ...ConfirmAction[]]) => void prompt: (message: string, defaultValue: string, options: [PromptAction, ...PromptAction[]]) => void } interface User { id: string | null name: string | 'Anonymous' photoUrl: string | null } interface Rect extends Readonly<Bound> { } interface NotificationHandler { cancel: () => void } interface Layout { canvas: number leftbar: number rightbar: number window: number } interface PositionOnDom { width: number height: number x: number y: number } interface ViewportAPI { center: Vector zoom: number readonly bound: Rect /** * @deprecated */ readonly layout: Layout readonly positionOnDom: PositionOnDom rulerVisible: boolean layoutGridVisible: boolean scrollAndZoomIntoView(nodes: SceneNode[]): void } interface ClientStorageAPI { getAsync(key: string): Promise<any | undefined> setAsync(key: string, value: any): Promise<void> deleteAsync(key: string): Promise<void> keysAsync(): Promise<string[]> } type ShowUIOptions = { width?: number height?: number visible?: boolean x?: number | string y?: number | string } interface ExportSettingsConstraints { type: 'SCALE' | 'WIDTH' | 'HEIGHT' value: number } interface ExportSettingsImage { readonly format: 'JPG' | 'PNG' | 'WEBP' readonly isSuffix?: boolean readonly fileName?: string readonly constraint?: ExportSettingsConstraints readonly useAbsoluteBounds?: boolean // defaults to true readonly useRenderBounds?: boolean // default to true } interface ExportSettingsSVG { readonly format: 'SVG' readonly isSuffix?: boolean readonly fileName?: string } interface ExportSettingsPDF { readonly format: 'PDF' readonly isSuffix?: string readonly fileName?: string readonly useAbsoluteBounds?: boolean // defaults to true readonly useRenderBounds?: boolean // default to true } type ExportSettings = ExportSettingsImage | ExportSettingsSVG | ExportSettingsPDF interface ExportMixin { exportSettings: ReadonlyArray<ExportSettings> export(settings?: ExportSettings): Uint8Array | string // Defaults to PNG format exportAsync(settings?: ExportSettings): Promise<Uint8Array | string> } interface NotifyOptions { position?: 'top' | 'bottom' type?: 'normal' | 'highlight' | 'error' | 'warning' | 'success' timeout?: number isLoading?: boolean } type CodeType = 'Web' | 'iOS' | 'Android' type WebCodeLang = 'css' | 'less' | 'sass' type AndroidCodeLang = 'xml' type IOSCodeLang = 'swift' type CodeLang = WebCodeLang | AndroidCodeLang | IOSCodeLang type WebCodeUnit = 'px' | 'rem' | 'rpx' type AndroidCodeUnit = 'dp' | 'dp/sp' type IOSCodeUnit = 'pt' type CodeUnit = WebCodeUnit | AndroidCodeUnit | IOSCodeUnit interface StyleCodeOptions { codeType?: CodeType codeLang?: CodeLang unit?: CodeUnit pixelRatio?: number } interface WebStyleCodeOptions { codeLang?: WebCodeLang unit?: WebCodeUnit pixelRatio?: number } interface AndroidStyleCodeOptions { pixelRatio?: number } interface IOSStyleCodeOptions { pixelRatio?: number } type CodeData = { layout?: string; style?: string; typography?: string; other?: string; } interface CodeString { type: 'CSS' | 'iOS' | 'Android' data: CodeData | '' } interface UIViewport extends Bound { readonly headerHeight: number readonly visible: boolean } interface UIAPI { show(): void hide(): void close(): void resize(width: number, height: number): void moveTo(x: number, y: number): void viewport: UIViewport postMessage(pluginMessage: any, origin?: string): void onmessage: ((pluginMessage: any, origin: string) => void) | undefined } type PublishStatus = 'UNPUBLISHED' | 'CURRENT' | 'CHANGED' interface DocumentationLink { readonly uri: string } interface PublishableMixin { description: string documentationLinks: ReadonlyArray<DocumentationLink> /** * @description 组件或者组件集的别名 */ alias: string /** * @description 是否为团队库组件/样式 */ readonly isExternal: boolean readonly ukey: string readonly publishStatus: PublishStatus } // Styles type StyleType = 'PAINT' | 'TEXT' | 'EFFECT' | 'GRID' | 'STROKE_WIDTH' | 'CORNER_RADIUS' | 'PADDING' | 'SPACING' type NodeStyleType = 'fill' | 'strokeFill' | 'strokeWidth' | 'cornerRadius' | 'padding' | 'spacing' interface BaseStyle extends Omit<PublishableMixin, 'documentationLinks'> { readonly id: string readonly type: StyleType name: string remove(): void } interface PaintStyle extends BaseStyle { type: 'PAINT' paints: ReadonlyArray<Paint> } interface StrokeWidthStyle extends BaseStyle { type: 'STROKE_WIDTH' value: StrokeWidth } interface CornerRadiusStyle extends BaseStyle { type: 'CORNER_RADIUS' value: CornerRadius } interface PaddingStyle extends BaseStyle { type: 'PADDING' value: Padding } interface SpacingStyle extends BaseStyle { type: 'SPACING' value: Spacing } interface NumValue { value: number unit: 'PIXELS' | 'PERCENT' } interface TextSegStyle { start: number end: number textStyleId: string textStyle: { fontName: FontName localizedFontName: FontName referrer: FontReferrer fontSize: number letterSpacing: LetterSpacing lineHeight: LineHeight lineHeightByPx: number textDecoration: TextDecoration textCase: TextCase fontWeight: number } fills: Paint[] fillStyleId: string } interface ListStyle { start: number end: number level: number type: 'ORDERED' | 'BULLETED' | 'NONE' } interface EffectStyle extends BaseStyle { type: 'EFFECT' effects: ReadonlyArray<Effect> } interface TextStyle extends BaseStyle { type: 'TEXT' decoration: TextDecoration fontSize: number letterSpacing: number letterSpacingUnit: NumValue['unit'] textCase: TextCase lineHeight: LineHeight fontName: FontName } interface FontAlias { title: string subtitle: string } interface GridStyle extends BaseStyle { type: 'GRID' layoutGrids: ReadonlyArray<LayoutGrid> } type Style = PaintStyle | EffectStyle | TextStyle | GridStyle | StrokeWidthStyle | CornerRadiusStyle | PaddingStyle | SpacingStyle /// ///////////////////////////////////////////////////////////////////////////// // Datatypes type Transform = [[number, number, number], [number, number, number]] interface Vector { readonly x: number readonly y: number } interface RGB { readonly r: number readonly g: number readonly b: number } interface RGBA { readonly r: number readonly g: number readonly b: number readonly a: number } interface FontName { readonly family: string readonly style: string } type TextCase = 'ORIGINAL' | 'UPPER' | 'LOWER' | 'TITLE'; type TextDecoration = 'NONE' | 'UNDERLINE' | 'STRIKETHROUGH' interface ShadowEffect { readonly type: 'DROP_SHADOW' | 'INNER_SHADOW' readonly color: RGBA // Effect的 x, y; readonly offset: Vector readonly spread: number readonly radius: number readonly isVisible: boolean readonly blendMode: BlendMode readonly showShadowBehindNode: boolean readonly isEffectShow: boolean } interface BlurEffect { readonly type: 'LAYER_BLUR' | 'BACKGROUND_BLUR' readonly radius: number readonly isVisible: boolean readonly blendMode: BlendMode } type Effect = ShadowEffect | BlurEffect // 待确认 type ConstraintType = 'START' | 'END' | 'STARTANDEND' | 'CENTER' | 'SCALE' interface Constraints { readonly horizontal: ConstraintType readonly vertical: ConstraintType } interface ColorStop { readonly position: number readonly color: RGBA } interface SolidPaint { readonly type: 'SOLID' readonly color: RGBA readonly isVisible?: boolean /** * It always be 1 when type is 'SOLID', please modify the alpha field in color instead. * 纯色模式下alpha始终为1, 请设置color中的alpha. */ readonly alpha?: number readonly blendMode?: BlendMode readonly name?: string } interface GradientPaint { readonly type: | 'GRADIENT_LINEAR' | 'GRADIENT_RADIAL' | 'GRADIENT_ANGULAR' | 'GRADIENT_DIAMOND' readonly transform: Transform readonly gradientStops: ReadonlyArray<ColorStop> readonly gradientHandlePositions?: [{ x: number, y: number }, { x: number, y: number }]; readonly isVisible?: boolean readonly alpha?: number readonly blendMode?: BlendMode readonly name?: string } interface ImageFilters { exposure?: number contrast?: number saturation?: number temperature?: number tint?: number highlights?: number shadows?: number hue?: number } interface ImagePaint { readonly type: 'IMAGE' readonly imageRef: string readonly scaleMode?: 'FILL' | 'TILE' | 'STRETCH' | 'FIT' | 'CROP' readonly filters?: ImageFilters readonly isVisible?: boolean readonly alpha?: number readonly blendMode?: BlendMode readonly name?: string readonly ratio?: number readonly rotation?: number } type Paint = SolidPaint | GradientPaint | ImagePaint type CSSWidthSetter = number | [number, number] | [number, number, number] | [number, number, number, number] interface StrokeWidth { width: CSSWidthSetter, } interface Padding { padding: CSSWidthSetter, } interface Spacing { spacing: CSSWidthSetter, } interface CornerRadius { cornerRadius: CSSWidthSetter, } type WindingRule = 'Nonzero' | 'Evenodd' // 待确定 interface VectorVertex { readonly x: number readonly y: number readonly strokeCap?: StrokeCap readonly cornerRadius?: number } // 待确定 interface VectorRegion { readonly windingRule: WindingRule readonly loops: ReadonlyArray<VectorPaths> } interface VectorCtrl { x: number y: number } type LetterSpacing = { readonly value: number readonly unit: 'PIXELS' | 'PERCENT' } type LineHeight = | { readonly value: number readonly unit: 'PIXELS' | 'PERCENT' } | { readonly unit: 'AUTO' } type BlendMode = | 'NORMAL' | 'DARKEN' | 'MULTIPLY' | 'COLOR_BURN' | 'LIGHTEN' | 'SCREEN' | 'COLOR_DODGE' | 'OVERLAY' | 'SOFT_LIGHT' | 'HARD_LIGHT' | 'DIFFERENCE' | 'EXCLUSION' | 'HUE' | 'SATURATION' | 'COLOR' | 'LUMINOSITY' | 'PLUS_DARKER' | 'PLUS_LIGHTER' | 'PASS_THROUGH' type FontReferrer = 'team' | 'org' | 'local' | 'official' interface Font { fontName: FontName localizedFontName: FontName referrer: FontReferrer } /// ///////////////////////////////////////////////////////////////////////////// // Mixins interface BaseNodeMixin { readonly id: string readonly parent: (BaseNode & ChildrenMixin) | null name: string removed: boolean remove(): void getPluginData(key: string): string setPluginData(key: string, value: string): void getPluginDataKeys(): string[] removePluginData(key: string): void clearPluginData(): void getSharedPluginData(namespace: string, key: string): string setSharedPluginData(namespace: string, key: string, value: string): void getSharedPluginDataKeys(namespace: string): string[] removeSharedPluginData(namespace: string, key: string): void clearSharedPluginData(namespace: string): void } interface SceneNodeMixin { isVisible: boolean isLocked: boolean readonly attachedConnectors: ConnectorNode[] componentPropertyReferences: { isVisible?: string, characters?: string, mainComponent?: string } | null slotInfo: { slotName: string; slotAlias: string } | null } interface ChildrenMixin<ChildrenNode = SceneNode> { readonly children: ReadonlyArray<ChildrenNode> appendChild(child: SceneNode): void insertChild(index: number, child: SceneNode): void findChildren( callback?: (node: SceneNode) => boolean ): ReadonlyArray<SceneNode> findChild(callback: (node: SceneNode) => boolean): SceneNode | null findAll(callback?: (node: SceneNode) => boolean): ReadonlyArray<SceneNode> findOne(callback: (node: SceneNode) => boolean): SceneNode | null findAllWithCriteria<T extends NodeType[]>(criteria: { types: T }): Array<{ type: T[number] } & SceneNode> } interface ConstraintMixin { constraints: Constraints } interface Bound { x: number y: number width: number height: number } type ScaleCenter = 'TOPLEFT' | 'TOP' | 'TOPRIGHT' | 'LEFT' | 'CENTER' | 'RIGHT' | 'BOTTOMLEFT' | 'BOTTOM' | 'BOTTOMRIGHT' interface ScaleOption { scaleCenter?: ScaleCenter } interface LayoutMixin { absoluteTransform: Transform relativeTransform: Transform readonly absoluteRenderBounds: Bound | null readonly absoluteBoundingBox: Bound bound: Bound x: number y: number width: number height: number minWidth: number | null maxWidth: number | null minHeight: number | null maxHeight: number | null rotation: number // In degrees constrainProportions: boolean layoutPositioning: 'AUTO' | 'ABSOLUTE' // applicable only inside auto-layout frames alignSelf: 'STRETCH' | 'INHERIT' // applicable only inside auto-layout frames flexGrow: 0 | 1 // applicable only inside auto-layout frames rescale(scale: number, scaleOption?: ScaleOption): void scaleFactor: number // The default value is 1 flip(direction: 'VERTICAL' | 'HORIZONTAL'): void } interface BlendMixin { opacity: number blendMode: BlendMode isMask: boolean isMaskOutline: boolean isMaskVisible: boolean effects: ReadonlyArray<Effect> effectStyleId: string } type StrokeCap = 'NONE' | 'ROUND' | 'SQUARE' | 'LINE_ARROW' | 'TRIANGLE_ARROW' | 'ROUND_ARROW' | 'RING' | 'DIAMOND' | 'LINE' type StrokeJoin = 'MITER' | 'BEVEL' | 'ROUND' type StrokeAlign = 'CENTER' | 'INSIDE' | 'OUTSIDE' type DashCap = 'NONE' | 'ROUND' | 'SQUARE' type StrokeStyle = 'SOLID' | 'DASH' | 'CUSTOM' type ConnectorStrokeCap = StrokeCap interface ConnectorEndpointPosition { readonly position: { x: number; y: number } } interface ConnectorEndpointConnected { readonly position: { x: number; y: number } readonly endpointNodeId: string readonly magnet: 'TOP' | 'LEFT' | 'BOTTOM' | 'RIGHT' } type ConnectorEndpoint = | ConnectorEndpointPosition | ConnectorEndpointConnected interface GeometryMixin { fills: ReadonlyArray<Paint> strokes: ReadonlyArray<Paint> strokeWeight: number strokeAlign: StrokeAlign strokeCap: StrokeCap strokeJoin: StrokeJoin strokeStyle: StrokeStyle dashCap: DashCap strokeDashes: ReadonlyArray<number> fillStyleId: string /** * @deprecated please use strokePaintStyleId instead */ strokeStyleId: string strokeFillStyleId: string strokeWidthStyleId: string paddingStyleId: string spacingStyleId: string cornerRadiusStyleId: string /** * You have to ensure the layer has stroke before invoking this method. * 在调用接口之前需要确保layer有描边. */ outlineStroke(): SceneNode | null } interface RectangleStrokeWeightMixin { strokeTopWeight: number strokeLeftWeight: number strokeBottomWeight: number strokeRightWeight: number } interface CornerMixin { cornerSmooth: number cornerRadius: number | PluginAPI['mixed'] topLeftRadius: number topRightRadius: number bottomLeftRadius: number bottomRightRadius: number } interface DefaultShapeMixin extends BaseNodeMixin, SceneNodeMixin, BlendMixin, GeometryMixin, LayoutMixin, ReactionMixin, ExportMixin { } interface DefaultContainerMixin extends BaseNodeMixin, ContainerMixin, ReactionMixin, SceneNodeMixin, ChildrenMixin, BlendMixin, CornerMixin, ConstraintMixin, LayoutMixin, ExportMixin { } interface ContainerMixin { expanded: boolean } interface AutoLayout { flexMode: 'NONE' | 'HORIZONTAL' | 'VERTICAL' flexWrap: 'WRAP' | 'NO_WRAP' itemSpacing: number mainAxisAlignItems: 'FLEX_START' | 'FLEX_END' | 'CENTER' | 'SPACING_BETWEEN' crossAxisAlignItems: 'FLEX_START' | 'FLEX_END' | 'CENTER' mainAxisSizingMode: 'FIXED' | 'AUTO' crossAxisSizingMode: 'FIXED' | 'AUTO' crossAxisAlignContent: 'AUTO' | 'SPACE_BETWEEN' crossAxisSpacing: number | null strokesIncludedInLayout: boolean itemReverseZIndex: boolean paddingTop: number paddingRight: number paddingBottom: number paddingLeft: number } interface RowsColsLayoutGrid { readonly gridType: "ROWS" | "COLUMNS" readonly alignment: "LEFT" | "RIGHT" | "STRETCH" | "CENTER" readonly gutterSize: number readonly count: number readonly sectionSize?: number | null readonly offset?: number readonly isVisible?: boolean readonly color?: RGBA readonly id?: string readonly name?: string } interface GridLayoutGrid { readonly gridType: "GRID" readonly sectionSize: number readonly isVisible?: boolean readonly color?: RGBA readonly id?: string readonly name?: string } type LayoutGrid = RowsColsLayoutGrid | GridLayoutGrid interface FrameContainerMixin extends AutoLayout { clipsContent: boolean layoutGrids: ReadonlyArray<LayoutGrid> gridStyleId: string overflowDirection: OverflowDirection } type OverflowDirection = "NONE" | "HORIZONTAL" | "VERTICAL" | "BOTH" interface ReactionMixin { reactions: ReadonlyArray<Reaction> } interface OpaqueNodeMixin extends BaseNodeMixin, SceneNodeMixin, ExportMixin { readonly absoluteTransform: Transform readonly relativeTransform: Transform readonly absoluteRenderBounds: Bound | null readonly absoluteBoundingBox: Bound x: number y: number readonly width: number readonly height: number readonly bound: Bound } interface MinimalBlendMixin { opacity: number blendMode: BlendMode } interface MinimalStrokesMixin { strokes: ReadonlyArray<Paint> strokeStyleId: string strokeWeight: number strokeJoin: StrokeJoin strokeAlign: StrokeAlign strokeStyle: StrokeStyle strokeCap: StrokeCap strokeDashes: ReadonlyArray<number> dashCap: DashCap } interface MinimalFillsMixin { fills: ReadonlyArray<Paint> fillStyleId: string } /// ///////////////////////////////////////////////////////////////////////////// // Nodes interface DocumentNode { readonly type: 'DOCUMENT' readonly id: string name: string currentPage: PageNode readonly children: Read