From cc7f055dfc2baf8724f901db3bd24cff9966e50b Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Mon, 6 Apr 2026 14:40:19 +0300 Subject: [PATCH] Format --- packages/core/src/canvas/node-edit-overlay.ts | 2 +- packages/core/src/color/okhcl.ts | 74 +++++++++--- packages/core/src/design-jsx/renderer.ts | 5 +- packages/core/src/editor/clipboard.ts | 4 +- packages/core/src/editor/color-space.ts | 2 +- packages/core/src/editor/create.ts | 4 +- packages/core/src/editor/pages.ts | 2 +- packages/core/src/editor/types.ts | 2 +- packages/core/src/editor/undo.ts | 2 +- packages/core/src/figma-api/index.ts | 10 +- packages/core/src/figma-api/proxy.ts | 33 +++--- packages/core/src/geometry.ts | 6 +- packages/core/src/icons/render.ts | 2 +- packages/core/src/io/formats.ts | 1 - packages/core/src/io/formats/fig/export.ts | 6 +- packages/core/src/io/formats/jsx/export.ts | 2 +- packages/core/src/io/formats/pen/read.ts | 13 +-- .../core/src/io/formats/raster/headless.ts | 1 - packages/core/src/io/formats/raster/render.ts | 2 +- packages/core/src/io/formats/svg/defs.ts | 1 - packages/core/src/io/formats/svg/export.ts | 7 +- packages/core/src/io/formats/svg/paths.ts | 7 +- packages/core/src/io/types.ts | 2 +- packages/core/src/kiwi/convert.ts | 8 +- packages/core/src/kiwi/node-export.ts | 6 +- .../src/lint/rules/effect-style-required.ts | 12 +- packages/core/src/lint/rules/min-text-size.ts | 13 ++- .../src/lint/rules/no-hardcoded-colors.ts | 28 ++++- .../core/src/lint/rules/no-mixed-styles.ts | 12 +- .../src/lint/rules/text-style-required.ts | 12 +- packages/core/src/scene-graph/snap.ts | 2 +- packages/core/src/text/direction.ts | 7 +- packages/core/src/text/editor.ts | 9 +- packages/core/src/tools/create.ts | 2 +- packages/vue/src/ColorPicker/model.ts | 17 ++- packages/vue/src/controls/useExport.ts | 4 +- packages/vue/src/controls/useLayout.ts | 26 ++++- packages/vue/src/controls/useOkHCL.ts | 10 +- packages/vue/src/locales/zh-CN.json | 2 +- src/components/ColorInput.vue | 17 ++- src/components/ColorPickerPanel.vue | 107 +++++++++++++++--- src/components/PickerSlider.vue | 9 +- src/components/ZoomDropdown.vue | 5 +- src/components/ui/AppSelect.vue | 7 +- src/components/ui/picker-slider.ts | 12 +- src/composables/use-collab.ts | 4 +- src/utils/toast.ts | 10 +- 47 files changed, 372 insertions(+), 159 deletions(-) diff --git a/packages/core/src/canvas/node-edit-overlay.ts b/packages/core/src/canvas/node-edit-overlay.ts index cfd664960..c851755eb 100644 --- a/packages/core/src/canvas/node-edit-overlay.ts +++ b/packages/core/src/canvas/node-edit-overlay.ts @@ -1,6 +1,6 @@ -import { computeAccurateBounds } from '../vector/bezier' import { PEN_HANDLE_RADIUS, PEN_VERTEX_RADIUS } from '../constants' import { vectorNetworkToPath } from '../vector' +import { computeAccurateBounds } from '../vector/bezier' import type { VectorVertex, VectorSegment, VectorRegion, SceneGraph } from '../scene-graph' import type { Vector } from '../types' diff --git a/packages/core/src/color/okhcl.ts b/packages/core/src/color/okhcl.ts index 6141ca3ac..45db7a35c 100644 --- a/packages/core/src/color/okhcl.ts +++ b/packages/core/src/color/okhcl.ts @@ -1,7 +1,7 @@ import { converter, toGamut } from 'culori' -import { normalizeColor } from './' import { copyFill, copyStroke } from '../scene-graph/copy' +import { normalizeColor } from './' import type { SceneNode } from '../scene-graph' import type { Color } from '../types' @@ -111,7 +111,11 @@ export function parseOkHCLPayload(value: string): OkHCLPayload | null { } } -function createOkHCLPayload(kind: 'fill' | 'stroke', index: number, color: OkHCLColor): OkHCLPayload { +function createOkHCLPayload( + kind: 'fill' | 'stroke', + index: number, + color: OkHCLColor +): OkHCLPayload { return { version: 1, kind, @@ -120,7 +124,11 @@ function createOkHCLPayload(kind: 'fill' | 'stroke', index: number, color: OkHCL } } -function filterOkHCLPayloads(entries: string[], kind?: 'fill' | 'stroke', index?: number): string[] { +function filterOkHCLPayloads( + entries: string[], + kind?: 'fill' | 'stroke', + index?: number +): string[] { return entries.filter((entry) => { const payload = parseOkHCLPayload(entry) if (!payload) return true @@ -129,7 +137,11 @@ function filterOkHCLPayloads(entries: string[], kind?: 'fill' | 'stroke', index? }) } -export function setNodeFillOkHCL(node: SceneNode, index: number, color: OkHCLColor): Partial { +export function setNodeFillOkHCL( + node: SceneNode, + index: number, + color: OkHCLColor +): Partial { const fills = node.fills.map(copyFill) if (index < 0 || index >= fills.length) throw new Error(`Fill ${index} not found`) const fill = fills[index] @@ -140,7 +152,11 @@ export function setNodeFillOkHCL(node: SceneNode, index: number, color: OkHCLCol opacity: rgba.a } - const payloads = filterOkHCLPayloads(node.pluginData.map((entry) => entry.value), 'fill', index) + const payloads = filterOkHCLPayloads( + node.pluginData.map((entry) => entry.value), + 'fill', + index + ) payloads.push(serializeOkHCLPayload(createOkHCLPayload('fill', index, color))) return { @@ -149,7 +165,11 @@ export function setNodeFillOkHCL(node: SceneNode, index: number, color: OkHCLCol } } -export function setNodeStrokeOkHCL(node: SceneNode, index: number, color: OkHCLColor): Partial { +export function setNodeStrokeOkHCL( + node: SceneNode, + index: number, + color: OkHCLColor +): Partial { const strokes = node.strokes.map(copyStroke) if (index < 0 || index >= strokes.length) throw new Error(`Stroke ${index} not found`) const stroke = strokes[index] @@ -160,7 +180,11 @@ export function setNodeStrokeOkHCL(node: SceneNode, index: number, color: OkHCLC opacity: rgba.a } - const payloads = filterOkHCLPayloads(node.pluginData.map((entry) => entry.value), 'stroke', index) + const payloads = filterOkHCLPayloads( + node.pluginData.map((entry) => entry.value), + 'stroke', + index + ) payloads.push(serializeOkHCLPayload(createOkHCLPayload('stroke', index, color))) return { @@ -170,16 +194,32 @@ export function setNodeStrokeOkHCL(node: SceneNode, index: number, color: OkHCLC } export function clearNodeFillOkHCL(node: SceneNode, index: number): Partial { - const okhclValues = filterOkHCLPayloads(node.pluginData.map((entry) => entry.value), 'fill', index) + const okhclValues = filterOkHCLPayloads( + node.pluginData.map((entry) => entry.value), + 'fill', + index + ) return { - pluginData: okhclValues.map((value) => ({ pluginId: 'open-pencil', key: OKHCL_PLUGIN_KEY, value })) + pluginData: okhclValues.map((value) => ({ + pluginId: 'open-pencil', + key: OKHCL_PLUGIN_KEY, + value + })) } } export function clearNodeStrokeOkHCL(node: SceneNode, index: number): Partial { - const okhclValues = filterOkHCLPayloads(node.pluginData.map((entry) => entry.value), 'stroke', index) + const okhclValues = filterOkHCLPayloads( + node.pluginData.map((entry) => entry.value), + 'stroke', + index + ) return { - pluginData: okhclValues.map((value) => ({ pluginId: 'open-pencil', key: OKHCL_PLUGIN_KEY, value })) + pluginData: okhclValues.map((value) => ({ + pluginId: 'open-pencil', + key: OKHCL_PLUGIN_KEY, + value + })) } } @@ -191,9 +231,17 @@ export function getNodeOkHCLPayloads(node: SceneNode): OkHCLPayload[] { } export function getFillOkHCL(node: SceneNode, index: number): OkHCLPayload | null { - return getNodeOkHCLPayloads(node).find((payload) => payload.kind === 'fill' && payload.index === index) ?? null + return ( + getNodeOkHCLPayloads(node).find( + (payload) => payload.kind === 'fill' && payload.index === index + ) ?? null + ) } export function getStrokeOkHCL(node: SceneNode, index: number): OkHCLPayload | null { - return getNodeOkHCLPayloads(node).find((payload) => payload.kind === 'stroke' && payload.index === index) ?? null + return ( + getNodeOkHCLPayloads(node).find( + (payload) => payload.kind === 'stroke' && payload.index === index + ) ?? null + ) } diff --git a/packages/core/src/design-jsx/renderer.ts b/packages/core/src/design-jsx/renderer.ts index 8e089347a..4277165de 100644 --- a/packages/core/src/design-jsx/renderer.ts +++ b/packages/core/src/design-jsx/renderer.ts @@ -1,7 +1,7 @@ import { parseColor, colorToFill } from '../color' import { TRANSPARENT } from '../constants' -import { createIconFromPaths } from '../icons/render' import { fetchIcons } from '../icons' +import { createIconFromPaths } from '../icons/render' import { computeAllLayouts } from '../layout' import { isTreeNode } from './tree' @@ -405,7 +405,8 @@ function applyLayoutOverrides( applyAutoLayoutSizing(o, props, w, h) } - o.layoutDirection = parseDirection(props.flow ?? (!isText ? props.dir : undefined)) ?? o.layoutDirection + o.layoutDirection = + parseDirection(props.flow ?? (!isText ? props.dir : undefined)) ?? o.layoutDirection if (props.gap !== undefined) o.itemSpacing = props.gap as number diff --git a/packages/core/src/editor/clipboard.ts b/packages/core/src/editor/clipboard.ts index b194b1255..e565e785f 100644 --- a/packages/core/src/editor/clipboard.ts +++ b/packages/core/src/editor/clipboard.ts @@ -1,10 +1,10 @@ import { buildFigmaClipboardHTML, importClipboardNodes, parseFigmaClipboard } from '../clipboard' +import { selectionToJSX } from '../design-jsx' import { computeImageHash } from '../figma-api' -import { collectFontKeys } from '../text/fonts' import { computeBounds } from '../geometry' import { renderNodesToSVG } from '../io/formats/svg' import { computeAllLayouts } from '../layout' -import { selectionToJSX } from '../design-jsx' +import { collectFontKeys } from '../text/fonts' import type { Fill, SceneGraph, SceneNode } from '../scene-graph' import type { Vector } from '../types' diff --git a/packages/core/src/editor/color-space.ts b/packages/core/src/editor/color-space.ts index 108d2566b..81fb8be1a 100644 --- a/packages/core/src/editor/color-space.ts +++ b/packages/core/src/editor/color-space.ts @@ -1,6 +1,6 @@ -import { copyEffects, copyFill, copyStyleRuns, copyStroke } from '../scene-graph/copy' import { resolveOkHCLForPreview } from '../color/management' import { rgbaToOkHCL } from '../color/okhcl' +import { copyEffects, copyFill, copyStyleRuns, copyStroke } from '../scene-graph/copy' import type { DocumentColorSpace, SceneNode } from '../scene-graph' import type { EditorContext } from './types' diff --git a/packages/core/src/editor/create.ts b/packages/core/src/editor/create.ts index 74c4a19cd..9e5d2fb53 100644 --- a/packages/core/src/editor/create.ts +++ b/packages/core/src/editor/create.ts @@ -1,10 +1,10 @@ import { prefetchFigmaSchema } from '../clipboard' import { CANVAS_BG_COLOR, IS_BROWSER } from '../constants' -import { loadFont as defaultLoadFont } from '../text/fonts' import { computeAllLayouts, computeLayout, setTextMeasurer } from '../layout' import { SceneGraph } from '../scene-graph' -import { TextEditor } from '../text/editor' import { UndoManager } from '../scene-graph/undo' +import { TextEditor } from '../text/editor' +import { loadFont as defaultLoadFont } from '../text/fonts' import { createAlignmentActions } from './alignment' import { createClipboardActions } from './clipboard' import { createColorSpaceActions } from './color-space' diff --git a/packages/core/src/editor/pages.ts b/packages/core/src/editor/pages.ts index a3dad3de7..71004c518 100644 --- a/packages/core/src/editor/pages.ts +++ b/packages/core/src/editor/pages.ts @@ -1,6 +1,6 @@ import { CANVAS_BG_COLOR } from '../constants' -import { collectFontKeys } from '../text/fonts' import { computeAllLayouts } from '../layout' +import { collectFontKeys } from '../text/fonts' import type { Color } from '../types' import type { EditorContext } from './types' diff --git a/packages/core/src/editor/types.ts b/packages/core/src/editor/types.ts index 35d421cfd..964f093b1 100644 --- a/packages/core/src/editor/types.ts +++ b/packages/core/src/editor/types.ts @@ -1,9 +1,9 @@ import type { SkiaRenderer } from '../canvas/renderer' import type { SceneGraph, VectorSegment, VectorVertex } from '../scene-graph' import type { SnapGuide } from '../scene-graph/snap' +import type { UndoManager } from '../scene-graph/undo' import type { TextEditor } from '../text/editor' import type { Color, Rect, Vector } from '../types' -import type { UndoManager } from '../scene-graph/undo' import type { CanvasKit } from 'canvaskit-wasm' export type Tool = diff --git a/packages/core/src/editor/undo.ts b/packages/core/src/editor/undo.ts index 3c0036450..b69acce67 100644 --- a/packages/core/src/editor/undo.ts +++ b/packages/core/src/editor/undo.ts @@ -1,8 +1,8 @@ import { computeAllLayouts } from '../layout' import type { SceneNode } from '../scene-graph' -import type { Rect, Vector } from '../types' import type { UndoEntry } from '../scene-graph/undo' +import type { Rect, Vector } from '../types' import type { EditorContext } from './types' export function createUndoActions(ctx: EditorContext) { diff --git a/packages/core/src/figma-api/index.ts b/packages/core/src/figma-api/index.ts index 2ce1ed76b..600578d1e 100644 --- a/packages/core/src/figma-api/index.ts +++ b/packages/core/src/figma-api/index.ts @@ -1,13 +1,7 @@ import { IS_BROWSER } from '../constants' -import { copyFills, copyStrokes, copyEffects } from '../scene-graph/copy' -import { - FigmaNodeProxy, - INTERNAL_ID, - MIXED, - type FigmaFontName, - type NodeProxyHost -} from './proxy' import { computeBounds } from '../geometry' +import { copyFills, copyStrokes, copyEffects } from '../scene-graph/copy' +import { FigmaNodeProxy, INTERNAL_ID, MIXED, type FigmaFontName, type NodeProxyHost } from './proxy' import type { RasterExportFormat } from '../io/formats/raster' import type { diff --git a/packages/core/src/figma-api/proxy.ts b/packages/core/src/figma-api/proxy.ts index ae8c48e51..9d0f7c891 100644 --- a/packages/core/src/figma-api/proxy.ts +++ b/packages/core/src/figma-api/proxy.ts @@ -1,8 +1,9 @@ import { normalizeColor } from '../color' +import { getFillOkHCL, getStrokeOkHCL, setNodeFillOkHCL, setNodeStrokeOkHCL } from '../color/okhcl' import { copyFills, copyStrokes, copyEffects } from '../scene-graph/copy' import { FONT_WEIGHT_NAMES } from '../text/fonts' -import { getFillOkHCL, getStrokeOkHCL, setNodeFillOkHCL, setNodeStrokeOkHCL } from '../color/okhcl' +import type { OkHCLColor, OkHCLPayload } from '../color/okhcl' /* eslint-disable max-lines -- Figma Plugin API proxy; FigmaAPI already in separate file */ import type { SceneGraph, @@ -14,7 +15,6 @@ import type { LayoutMode } from '../scene-graph' import type { Rect } from '../types' -import type { OkHCLColor, OkHCLPayload } from '../color/okhcl' const MIXED = Symbol('mixed') @@ -961,9 +961,11 @@ export class FigmaNodeProxy { // --- Plugin data --- getPluginData(key: string): string { - return this._raw().pluginData.find( - (entry) => entry.pluginId === OPEN_PENCIL_PLUGIN_DATA_NAMESPACE && entry.key === key - )?.value ?? '' + return ( + this._raw().pluginData.find( + (entry) => entry.pluginId === OPEN_PENCIL_PLUGIN_DATA_NAMESPACE && entry.key === key + )?.value ?? '' + ) } setPluginData(key: string, value: string): void { @@ -978,15 +980,17 @@ export class FigmaNodeProxy { } getPluginDataKeys(): string[] { - return this._raw().pluginData - .filter((entry) => entry.pluginId === OPEN_PENCIL_PLUGIN_DATA_NAMESPACE) + return this._raw() + .pluginData.filter((entry) => entry.pluginId === OPEN_PENCIL_PLUGIN_DATA_NAMESPACE) .map((entry) => entry.key) } getSharedPluginData(namespace: string, key: string): string { - return this._raw().sharedPluginData.find( - (entry) => entry.namespace === namespace && entry.key === key - )?.value ?? '' + return ( + this._raw().sharedPluginData.find( + (entry) => entry.namespace === namespace && entry.key === key + )?.value ?? '' + ) } setSharedPluginData(namespace: string, key: string, value: string): void { @@ -1001,8 +1005,8 @@ export class FigmaNodeProxy { } getSharedPluginDataKeys(namespace: string): string[] { - return this._raw().sharedPluginData - .filter((entry) => entry.namespace === namespace) + return this._raw() + .sharedPluginData.filter((entry) => entry.namespace === namespace) .map((entry) => entry.key) } @@ -1019,7 +1023,10 @@ export class FigmaNodeProxy { } setStrokeOkHCL(color: OkHCLColor, index = 0): void { - this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], setNodeStrokeOkHCL(this._raw(), index, color)) + this[INTERNAL_GRAPH].updateNode( + this[INTERNAL_ID], + setNodeStrokeOkHCL(this._raw(), index, color) + ) } // --- Serialization --- diff --git a/packages/core/src/geometry.ts b/packages/core/src/geometry.ts index c86a7404e..65f1abac9 100644 --- a/packages/core/src/geometry.ts +++ b/packages/core/src/geometry.ts @@ -102,7 +102,11 @@ function effectOverflow(effects?: Effect[]) { for (const effect of effects ?? []) { if (!effect.visible) continue - if (effect.type !== 'DROP_SHADOW' && effect.type !== 'LAYER_BLUR' && effect.type !== 'FOREGROUND_BLUR') { + if ( + effect.type !== 'DROP_SHADOW' && + effect.type !== 'LAYER_BLUR' && + effect.type !== 'FOREGROUND_BLUR' + ) { continue } const blurSpread = effect.radius + effect.spread diff --git a/packages/core/src/icons/render.ts b/packages/core/src/icons/render.ts index 88e015902..db83a53f3 100644 --- a/packages/core/src/icons/render.ts +++ b/packages/core/src/icons/render.ts @@ -1,8 +1,8 @@ import { parseColor } from '../color' -import type { IconData } from './' import type { SceneGraph, SceneNode, Stroke } from '../scene-graph' import type { Color } from '../types' +import type { IconData } from './' const STROKE_CAP_MAP: Record = { butt: 'NONE', diff --git a/packages/core/src/io/formats.ts b/packages/core/src/io/formats.ts index 1da85571e..b6db8e55f 100644 --- a/packages/core/src/io/formats.ts +++ b/packages/core/src/io/formats.ts @@ -1,5 +1,4 @@ import { sceneNodeToJSX, selectionToJSX } from '../design-jsx' - import { exportFigFile, parseFigFile } from './formats/fig' import { parsePenFile } from './formats/pen' import { headlessRenderNodes, renderNodesToImage, type RasterExportFormat } from './formats/raster' diff --git a/packages/core/src/io/formats/fig/export.ts b/packages/core/src/io/formats/fig/export.ts index 3269c0e41..d3b4e6d0b 100644 --- a/packages/core/src/io/formats/fig/export.ts +++ b/packages/core/src/io/formats/fig/export.ts @@ -1,8 +1,6 @@ import { deflateSync } from 'fflate' import { CANVAS_BG_COLOR, IS_BROWSER, IS_TAURI } from '../../../constants' -import { compressFigDataSync } from './compress' -import { renderThumbnail } from '../raster' import { initCodec, getCompiledSchema, getSchemaBytes } from '../../../kiwi/codec' import { stringToGuid } from '../../../kiwi/convert' import { @@ -13,9 +11,11 @@ import { makeDocumentNodeChange, makeCanvasNodeChange } from '../../../kiwi/serialize' +import { renderThumbnail } from '../raster' +import { compressFigDataSync } from './compress' -import type { NodeChange } from '../../../kiwi/codec' import type { SkiaRenderer } from '../../../canvas' +import type { NodeChange } from '../../../kiwi/codec' import type { SceneGraph, VariableValue } from '../../../scene-graph' import type { GUID } from '../../../types' import type { CanvasKit } from 'canvaskit-wasm' diff --git a/packages/core/src/io/formats/jsx/export.ts b/packages/core/src/io/formats/jsx/export.ts index 59a1d658f..6c0e73973 100644 --- a/packages/core/src/io/formats/jsx/export.ts +++ b/packages/core/src/io/formats/jsx/export.ts @@ -1,7 +1,6 @@ /* eslint-disable max-lines -- JSX export formats share helpers and node walking logic */ import { colorToHex8, colorToCSSCompact } from '../../../color' import { DEFAULT_FONT_FAMILY } from '../../../constants' -import { resolveNodeTextDirection } from '../../../text/direction' import { pxToSpacing, colorToTwClass, @@ -10,6 +9,7 @@ import { borderRadiusToTw, opacityToTw } from '../../../design-jsx/tailwind' +import { resolveNodeTextDirection } from '../../../text/direction' import type { SceneGraph, diff --git a/packages/core/src/io/formats/pen/read.ts b/packages/core/src/io/formats/pen/read.ts index cf8503e4f..922c9b3c3 100644 --- a/packages/core/src/io/formats/pen/read.ts +++ b/packages/core/src/io/formats/pen/read.ts @@ -1,4 +1,7 @@ +import { SceneGraph } from '../../../scene-graph' import { copyEffects, copyFills, copyStrokes } from '../../../scene-graph/copy' +import { populateInstanceChildren } from '../../../scene-graph/instances' +import { parseSVGPath } from '../svg/parse-path' import { applyCornerRadius, applyPadding, @@ -20,16 +23,8 @@ import { type PenNode, type VarContext } from './convert' -import { parseSVGPath } from '../svg/parse-path' -import { SceneGraph } from '../../../scene-graph' -import { populateInstanceChildren } from '../../../scene-graph/instances' -import type { - LayoutMode, - LayoutSizing, - SceneNode, - VectorNetwork -} from '../../../scene-graph' +import type { LayoutMode, LayoutSizing, SceneNode, VectorNetwork } from '../../../scene-graph' function scaleVectorNetwork(vn: VectorNetwork, targetW: number, targetH: number): void { if (vn.vertices.length === 0) return diff --git a/packages/core/src/io/formats/raster/headless.ts b/packages/core/src/io/formats/raster/headless.ts index d439adc19..a9d5444aa 100644 --- a/packages/core/src/io/formats/raster/headless.ts +++ b/packages/core/src/io/formats/raster/headless.ts @@ -1,5 +1,4 @@ import { SkiaRenderer } from '../../../canvas' - import { renderNodesToImage, renderThumbnail, type ExportFormat } from './render' import type { SceneGraph } from '../../../scene-graph' diff --git a/packages/core/src/io/formats/raster/render.ts b/packages/core/src/io/formats/raster/render.ts index 70c3e59b7..ae0a80f79 100644 --- a/packages/core/src/io/formats/raster/render.ts +++ b/packages/core/src/io/formats/raster/render.ts @@ -1,8 +1,8 @@ import { computeVisualBounds } from '../../../geometry' import { extractExportGraph } from '../../subgraph' -import type { RenderColorSpace } from '../../../color/management' import type { SkiaRenderer } from '../../../canvas' +import type { RenderColorSpace } from '../../../color/management' import type { SceneGraph } from '../../../scene-graph' import type { CanvasKit, Canvas } from 'canvaskit-wasm' diff --git a/packages/core/src/io/formats/svg/defs.ts b/packages/core/src/io/formats/svg/defs.ts index 25766862f..692f3f597 100644 --- a/packages/core/src/io/formats/svg/defs.ts +++ b/packages/core/src/io/formats/svg/defs.ts @@ -1,6 +1,5 @@ import { colorToHex } from '../../../color' import { colorToDisplayCss, getDefaultRenderColorSpace } from '../../../color/management' - import { svg, type SVGNode } from './node' import { round } from './paths' diff --git a/packages/core/src/io/formats/svg/export.ts b/packages/core/src/io/formats/svg/export.ts index 7b0c43925..8b3ca69f6 100644 --- a/packages/core/src/io/formats/svg/export.ts +++ b/packages/core/src/io/formats/svg/export.ts @@ -1,6 +1,5 @@ -import { computeContentBounds } from '../raster' - import { resolveNodeTextDirection } from '../../../text/direction' +import { computeContentBounds } from '../raster' import { nextDefId, formatColor, @@ -24,8 +23,6 @@ export { geometryBlobToSVGPath, vectorNetworkToSVGPaths } from './paths' import { svg, renderSVGNode } from './node' -import type { SVGExportContext } from './defs' -import type { SVGNode } from './node' import type { SceneGraph, SceneNode, @@ -33,6 +30,8 @@ import type { Stroke, CharacterStyleOverride } from '../../../scene-graph' +import type { SVGExportContext } from './defs' +import type { SVGNode } from './node' // --- Node rendering --- diff --git a/packages/core/src/io/formats/svg/paths.ts b/packages/core/src/io/formats/svg/paths.ts index 8cbe66a97..d4cb05901 100644 --- a/packages/core/src/io/formats/svg/paths.ts +++ b/packages/core/src/io/formats/svg/paths.ts @@ -1,9 +1,4 @@ -import type { - SceneNode, - VectorNetwork, - VectorSegment, - VectorVertex -} from '../../../scene-graph' +import type { SceneNode, VectorNetwork, VectorSegment, VectorVertex } from '../../../scene-graph' const CMD_CLOSE = 0 const CMD_MOVE_TO = 1 diff --git a/packages/core/src/io/types.ts b/packages/core/src/io/types.ts index 47b4836d5..49ec19788 100644 --- a/packages/core/src/io/types.ts +++ b/packages/core/src/io/types.ts @@ -1,6 +1,6 @@ +import type { SkiaRenderer } from '../canvas' import type { RenderColorSpace } from '../color/management' import type { JSXFormat } from '../design-jsx' -import type { SkiaRenderer } from '../canvas' import type { SceneGraph } from '../scene-graph' import type { RasterExportFormat } from './formats/raster' import type { CanvasKit } from 'canvaskit-wasm' diff --git a/packages/core/src/kiwi/convert.ts b/packages/core/src/kiwi/convert.ts index b7aa98ede..d498585ef 100644 --- a/packages/core/src/kiwi/convert.ts +++ b/packages/core/src/kiwi/convert.ts @@ -620,8 +620,9 @@ function convertTextProps( styleRuns: importStyleRuns(nc), textTruncation: (nc.textTruncation as string) === 'ENDING' ? 'ENDING' : 'DISABLED', textDirection: - (getOpenPencilPluginValue(nc, TEXT_DIRECTION_PLUGIN_KEY) as SceneNode['textDirection'] | null) || - 'AUTO' + (getOpenPencilPluginValue(nc, TEXT_DIRECTION_PLUGIN_KEY) as + | SceneNode['textDirection'] + | null) || 'AUTO' } } @@ -680,8 +681,7 @@ function convertLayoutProps( layoutDirection: (getOpenPencilPluginValue(nc, LAYOUT_DIRECTION_PLUGIN_KEY) as | SceneNode['layoutDirection'] - | null) || - 'AUTO' + | null) || 'AUTO' } } diff --git a/packages/core/src/kiwi/node-export.ts b/packages/core/src/kiwi/node-export.ts index 91ad2976a..0e03cd1b8 100644 --- a/packages/core/src/kiwi/node-export.ts +++ b/packages/core/src/kiwi/node-export.ts @@ -53,7 +53,11 @@ function createStrokePaints(context: SceneNodeToKiwiContext, node: SceneNode): P })) } -function applyNodeVisualProps(context: SceneNodeToKiwiContext, node: SceneNode, nc: KiwiNodeChange): void { +function applyNodeVisualProps( + context: SceneNodeToKiwiContext, + node: SceneNode, + nc: KiwiNodeChange +): void { if (node.independentStrokeWeights) { nc.borderStrokeWeightsIndependent = true nc.borderTopWeight = node.borderTopWeight diff --git a/packages/core/src/lint/rules/effect-style-required.ts b/packages/core/src/lint/rules/effect-style-required.ts index 6b759a064..16e59ae7c 100644 --- a/packages/core/src/lint/rules/effect-style-required.ts +++ b/packages/core/src/lint/rules/effect-style-required.ts @@ -1,10 +1,18 @@ import { defineRule } from '../rule' export default defineRule({ - meta: { id: 'effect-style-required', category: 'design-tokens', description: 'Effects should use shared effect presets or tokens' }, + meta: { + id: 'effect-style-required', + category: 'design-tokens', + description: 'Effects should use shared effect presets or tokens' + }, check(node, context) { const visibleEffects = node.effects.filter((effect) => effect.visible) if (visibleEffects.length === 0) return - context.report({ node, message: `Effect without shared style: ${visibleEffects.map((effect) => `${effect.type} ${effect.radius}px`).join(', ')}`, suggest: 'Extract reusable shadows and blurs into shared presets or variables' }) + context.report({ + node, + message: `Effect without shared style: ${visibleEffects.map((effect) => `${effect.type} ${effect.radius}px`).join(', ')}`, + suggest: 'Extract reusable shadows and blurs into shared presets or variables' + }) } }) diff --git a/packages/core/src/lint/rules/min-text-size.ts b/packages/core/src/lint/rules/min-text-size.ts index ec5964456..a23701183 100644 --- a/packages/core/src/lint/rules/min-text-size.ts +++ b/packages/core/src/lint/rules/min-text-size.ts @@ -1,11 +1,20 @@ import { defineRule } from '../rule' export default defineRule({ - meta: { id: 'min-text-size', category: 'accessibility', description: 'Text should be large enough to be readable (minimum 12px)' }, + meta: { + id: 'min-text-size', + category: 'accessibility', + description: 'Text should be large enough to be readable (minimum 12px)' + }, match: ['TEXT'], check(node, context) { const config = context.getConfig() as { minSize?: number } | undefined const minSize = config?.minSize ?? 12 - if (node.fontSize < minSize) context.report({ node, message: `Text size ${node.fontSize}px is below minimum ${minSize}px`, suggest: `Increase to at least ${minSize}px for readability` }) + if (node.fontSize < minSize) + context.report({ + node, + message: `Text size ${node.fontSize}px is below minimum ${minSize}px`, + suggest: `Increase to at least ${minSize}px for readability` + }) } }) diff --git a/packages/core/src/lint/rules/no-hardcoded-colors.ts b/packages/core/src/lint/rules/no-hardcoded-colors.ts index f095d8435..d42ac7d3b 100644 --- a/packages/core/src/lint/rules/no-hardcoded-colors.ts +++ b/packages/core/src/lint/rules/no-hardcoded-colors.ts @@ -1,13 +1,33 @@ import { defineRule } from '../rule' export default defineRule({ - meta: { id: 'no-hardcoded-colors', category: 'design-tokens', description: 'Colors should use variables instead of hardcoded values' }, - match: ['RECTANGLE','ELLIPSE','FRAME','TEXT','VECTOR','LINE','POLYGON','STAR','COMPONENT','INSTANCE'], + meta: { + id: 'no-hardcoded-colors', + category: 'design-tokens', + description: 'Colors should use variables instead of hardcoded values' + }, + match: [ + 'RECTANGLE', + 'ELLIPSE', + 'FRAME', + 'TEXT', + 'VECTOR', + 'LINE', + 'POLYGON', + 'STAR', + 'COMPONENT', + 'INSTANCE' + ], check(node, context) { const checkPaints = (paints: typeof node.fills, field: 'fills' | 'strokes') => { for (const paint of paints) { - if (paint.type !== 'SOLID' || !paint.visible || !paint.color || node.boundVariables[field]) continue - context.report({ node, message: `Hardcoded ${field === 'fills' ? 'fill' : 'stroke'} color detected`, suggest: 'Bind this color to a design variable for consistency' }) + if (paint.type !== 'SOLID' || !paint.visible || !paint.color || node.boundVariables[field]) + continue + context.report({ + node, + message: `Hardcoded ${field === 'fills' ? 'fill' : 'stroke'} color detected`, + suggest: 'Bind this color to a design variable for consistency' + }) } } checkPaints(node.fills, 'fills') diff --git a/packages/core/src/lint/rules/no-mixed-styles.ts b/packages/core/src/lint/rules/no-mixed-styles.ts index 5e98ac3df..77d123ee2 100644 --- a/packages/core/src/lint/rules/no-mixed-styles.ts +++ b/packages/core/src/lint/rules/no-mixed-styles.ts @@ -1,11 +1,19 @@ import { defineRule } from '../rule' export default defineRule({ - meta: { id: 'no-mixed-styles', category: 'typography', description: 'Text layers should not mix multiple styles in one node' }, + meta: { + id: 'no-mixed-styles', + category: 'typography', + description: 'Text layers should not mix multiple styles in one node' + }, match: ['TEXT'], check(node, context) { if (node.text.length > 1 && node.styleRunCount > 0) { - context.report({ node, message: 'Text layer has mixed font styles', suggest: 'Split into separate text layers or unify the text style' }) + context.report({ + node, + message: 'Text layer has mixed font styles', + suggest: 'Split into separate text layers or unify the text style' + }) } } }) diff --git a/packages/core/src/lint/rules/text-style-required.ts b/packages/core/src/lint/rules/text-style-required.ts index 92080f7ae..8a93a38b6 100644 --- a/packages/core/src/lint/rules/text-style-required.ts +++ b/packages/core/src/lint/rules/text-style-required.ts @@ -1,11 +1,19 @@ import { defineRule } from '../rule' export default defineRule({ - meta: { id: 'text-style-required', category: 'typography', description: 'Text layers should use shared typography tokens or styles' }, + meta: { + id: 'text-style-required', + category: 'typography', + description: 'Text layers should use shared typography tokens or styles' + }, match: ['TEXT'], check(node, context) { if (node.text.length <= 2) return if (node.boundVariables.fontSize || node.boundVariables.fontFamily) return - context.report({ node, message: 'Text layer without typography variable bindings', suggest: 'Bind font size or font family to a shared text token when possible' }) + context.report({ + node, + message: 'Text layer without typography variable bindings', + suggest: 'Bind font size or font family to a shared text token when possible' + }) } }) diff --git a/packages/core/src/scene-graph/snap.ts b/packages/core/src/scene-graph/snap.ts index 065229064..9defb0d45 100644 --- a/packages/core/src/scene-graph/snap.ts +++ b/packages/core/src/scene-graph/snap.ts @@ -1,7 +1,7 @@ import { rotatedBBox } from '../geometry' -import type { SceneNode } from './' import type { Rect } from '../types' +import type { SceneNode } from './' const SNAP_THRESHOLD = 5 diff --git a/packages/core/src/text/direction.ts b/packages/core/src/text/direction.ts index 40e2b749d..2e7110303 100644 --- a/packages/core/src/text/direction.ts +++ b/packages/core/src/text/direction.ts @@ -1,6 +1,7 @@ import type { LayoutDirection, SceneNode, TextDirection } from '../scene-graph' -const RTL_CHAR_RE = /\p{Script=Arabic}|\p{Script=Hebrew}|\p{Script=Syriac}|\p{Script=Thaana}|\p{Script=Nko}|\p{Script=Adlam}/u +const RTL_CHAR_RE = + /\p{Script=Arabic}|\p{Script=Hebrew}|\p{Script=Syriac}|\p{Script=Thaana}|\p{Script=Nko}|\p{Script=Adlam}/u const LTR_CHAR_RE = /\p{Script=Latin}|\p{Script=Cyrillic}|\p{Script=Greek}/u export function detectTextDirection(text: string): Exclude { @@ -18,7 +19,9 @@ export function resolveTextDirection( return direction === 'AUTO' ? detectTextDirection(text) : direction } -export function resolveNodeTextDirection(node: Pick): 'LTR' | 'RTL' { +export function resolveNodeTextDirection( + node: Pick +): 'LTR' | 'RTL' { return resolveTextDirection(node.textDirection, node.text) } diff --git a/packages/core/src/text/editor.ts b/packages/core/src/text/editor.ts index 4c0f1e25a..424a1120c 100644 --- a/packages/core/src/text/editor.ts +++ b/packages/core/src/text/editor.ts @@ -1,5 +1,6 @@ -import type { SkiaRenderer } from '../canvas' import { resolveNodeTextDirection } from './direction' + +import type { SkiaRenderer } from '../canvas' import type { SceneNode } from '../scene-graph' import type { Rect } from '../types' import type { CanvasKit, Paragraph } from 'canvaskit-wasm' @@ -258,8 +259,7 @@ export class TextEditor { if (lineNum < 0) return const metrics = s.paragraph.getLineMetricsAt(lineNum) if (!metrics) return - s.cursor = - s.textDirection === 'RTL' ? metrics.endExcludingWhitespaces : metrics.startIndex + s.cursor = s.textDirection === 'RTL' ? metrics.endExcludingWhitespaces : metrics.startIndex } moveToLineEnd(extend = false): void { @@ -270,8 +270,7 @@ export class TextEditor { if (lineNum < 0) return const metrics = s.paragraph.getLineMetricsAt(lineNum) if (!metrics) return - s.cursor = - s.textDirection === 'RTL' ? metrics.startIndex : metrics.endExcludingWhitespaces + s.cursor = s.textDirection === 'RTL' ? metrics.startIndex : metrics.endExcludingWhitespaces } moveWordLeft(extend = false): void { diff --git a/packages/core/src/tools/create.ts b/packages/core/src/tools/create.ts index 9d337ad2b..32e827b3a 100644 --- a/packages/core/src/tools/create.ts +++ b/packages/core/src/tools/create.ts @@ -1,6 +1,6 @@ import { parseColor } from '../color' -import { createIconFromPaths } from '../icons/render' import { fetchIcons, searchIconsBatch } from '../icons' +import { createIconFromPaths } from '../icons/render' import { defineTool, nodeSummary } from './schema' import type { FigmaNodeProxy } from '../figma-api' diff --git a/packages/vue/src/ColorPicker/model.ts b/packages/vue/src/ColorPicker/model.ts index 61a637e5f..8b19b47fd 100644 --- a/packages/vue/src/ColorPicker/model.ts +++ b/packages/vue/src/ColorPicker/model.ts @@ -91,7 +91,11 @@ export function updateRGBChannel(color: Color, channel: 'r' | 'g' | 'b', value25 } } -export function updateHSLChannel(model: ColorPickerModel, channel: 'h' | 's' | 'l', value: number): Color { +export function updateHSLChannel( + model: ColorPickerModel, + channel: 'h' | 's' | 'l', + value: number +): Color { const next = { ...model.hsl, [channel]: channel === 'h' ? value : clampPercent(value) @@ -106,7 +110,11 @@ export function updateHSLChannel(model: ColorPickerModel, channel: 'h' | 's' | ' return rekaToAppColor(next) } -export function updateHSBChannel(model: ColorPickerModel, channel: 'h' | 's' | 'b', value: number): Color { +export function updateHSBChannel( + model: ColorPickerModel, + channel: 'h' | 's' | 'b', + value: number +): Color { return rekaToAppColor({ ...model.hsb, [channel]: channel === 'h' ? value : clampPercent(value) @@ -132,10 +140,7 @@ export function createOkHCLSliderPreviewModel(color: OkHCLColor): OkHCLSliderPre okhclHue: okhclToRGBA({ ...color, c: Math.max(color.c, OKHCL_HUE_PREVIEW_MIN_CHROMA), - l: - color.l <= 0 || color.l >= 1 - ? OKHCL_HUE_PREVIEW_FALLBACK_LIGHTNESS - : color.l + l: color.l <= 0 || color.l >= 1 ? OKHCL_HUE_PREVIEW_FALLBACK_LIGHTNESS : color.l }), okhclChroma: okhclToRGBA(color), okhclLightness: okhclToRGBA(color) diff --git a/packages/vue/src/controls/useExport.ts b/packages/vue/src/controls/useExport.ts index 909db436c..31cff1c9b 100644 --- a/packages/vue/src/controls/useExport.ts +++ b/packages/vue/src/controls/useExport.ts @@ -51,7 +51,9 @@ export function useExport() { hasSelection.value ? 'selection' : 'page' ) const activeName = computed(() => - activeTarget.value === 'selection' ? (selectedNodeName.value ?? 'Export') : currentPageName.value + activeTarget.value === 'selection' + ? (selectedNodeName.value ?? 'Export') + : currentPageName.value ) const activeSettings = computed(() => activeTarget.value === 'selection' ? selectionSettings.value : pageSettings.value diff --git a/packages/vue/src/controls/useLayout.ts b/packages/vue/src/controls/useLayout.ts index 7ac5695a2..06bdb0394 100644 --- a/packages/vue/src/controls/useLayout.ts +++ b/packages/vue/src/controls/useLayout.ts @@ -1,10 +1,16 @@ import { computed, ref } from 'vue' import { useEditor } from '@open-pencil/vue/context/editorContext' -import { useSceneComputed } from '@open-pencil/vue/internal/useSceneComputed' import { useI18n } from '@open-pencil/vue/i18n' +import { useSceneComputed } from '@open-pencil/vue/internal/useSceneComputed' -import type { SceneNode, LayoutSizing, LayoutAlign, LayoutCounterAlign, GridTrack } from '@open-pencil/core' +import type { + SceneNode, + LayoutSizing, + LayoutAlign, + LayoutCounterAlign, + GridTrack +} from '@open-pencil/core' type AlignCell = { primary: LayoutAlign; counter: LayoutCounterAlign } @@ -51,7 +57,9 @@ export function useLayout() { const { panels } = useI18n() const node = useSceneComputed(() => editor.getSelectedNode() ?? null) - const layoutDirection = computed(() => node.value?.layoutDirection ?? 'AUTO') + const layoutDirection = computed( + () => node.value?.layoutDirection ?? 'AUTO' + ) const isInAutoLayout = computed(() => { const n = node.value @@ -87,7 +95,8 @@ export function useLayout() { { value: 'FIXED', label: panels.value.sizingFixed } ] if (isFlex.value) options.push({ value: 'HUG', label: panels.value.sizingHug }) - if (isInAutoLayout.value || isFlex.value) options.push({ value: 'FILL', label: panels.value.sizingFill }) + if (isInAutoLayout.value || isFlex.value) + options.push({ value: 'FILL', label: panels.value.sizingFill }) return options }) @@ -96,7 +105,8 @@ export function useLayout() { { value: 'FIXED', label: panels.value.sizingFixed } ] if (isFlex.value) options.push({ value: 'HUG', label: panels.value.sizingHug }) - if (isInAutoLayout.value || isFlex.value) options.push({ value: 'FILL', label: panels.value.sizingFill }) + if (isInAutoLayout.value || isFlex.value) + options.push({ value: 'FILL', label: panels.value.sizingFill }) return options }) @@ -184,7 +194,11 @@ export function useLayout() { function setLayoutDirection(direction: SceneNode['layoutDirection']) { if (!node.value) return - editor.updateNodeWithUndo(node.value.id, { layoutDirection: direction }, 'Change layout direction') + editor.updateNodeWithUndo( + node.value.id, + { layoutDirection: direction }, + 'Change layout direction' + ) } function updateGridTrack( diff --git a/packages/vue/src/controls/useOkHCL.ts b/packages/vue/src/controls/useOkHCL.ts index ac7dd43ce..a7c82db30 100644 --- a/packages/vue/src/controls/useOkHCL.ts +++ b/packages/vue/src/controls/useOkHCL.ts @@ -22,18 +22,22 @@ export function useOkHCL() { } function getFillOkHCLColor(node: SceneNode | null, index: number): OkHCLColor | null { - return node ? getFillOkHCL(node, index)?.color ?? null : null + return node ? (getFillOkHCL(node, index)?.color ?? null) : null } function getStrokeOkHCLColor(node: SceneNode | null, index: number): OkHCLColor | null { - return node ? getStrokeOkHCL(node, index)?.color ?? null : null + return node ? (getStrokeOkHCL(node, index)?.color ?? null) : null } function ensureFillOkHCL(node: SceneNode, index: number) { const color = getFillOkHCLColor(node, index) ?? rgbaToOkHCL(node.fills[index]?.color ?? { r: 0, g: 0, b: 0, a: 1 }) - editor.updateNodeWithUndo(node.id, setNodeFillOkHCL(node, index, color), 'Update fill color model') + editor.updateNodeWithUndo( + node.id, + setNodeFillOkHCL(node, index, color), + 'Update fill color model' + ) } function ensureStrokeOkHCL(node: SceneNode, index: number) { diff --git a/packages/vue/src/locales/zh-CN.json b/packages/vue/src/locales/zh-CN.json index 2d24d326a..df01690e7 100644 --- a/packages/vue/src/locales/zh-CN.json +++ b/packages/vue/src/locales/zh-CN.json @@ -199,4 +199,4 @@ "noResults": "无结果", "share": "分享" } -} \ No newline at end of file +} diff --git a/src/components/ColorInput.vue b/src/components/ColorInput.vue index 842c61358..b3377bb70 100644 --- a/src/components/ColorInput.vue +++ b/src/components/ColorInput.vue @@ -6,7 +6,11 @@ import ColorPicker from './ColorPicker.vue' import type { Color } from '@open-pencil/core' import type { OkHCLControls } from '@open-pencil/vue/ColorPicker/types' -const { editable = false, color, okhcl = null } = defineProps<{ +const { + editable = false, + color, + okhcl = null +} = defineProps<{ color: Color editable?: boolean okhcl?: OkHCLControls | null @@ -15,8 +19,15 @@ const emit = defineEmits<{ update: [color: Color] }>()