From 186629947e552f269fa223b4d12afc87e26a0bb4 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 26 Sep 2024 14:50:48 +0200 Subject: [PATCH] feat(plugin-types): removed old method and replaced with attributes --- apps/contrast-plugin/src/plugin.ts | 12 +-- apps/e2e/src/plugins/component-library.ts | 2 +- apps/e2e/src/plugins/create-comments.ts | 6 +- apps/e2e/src/plugins/create-ruler-guides.ts | 4 +- apps/icons-plugin/src/plugin.ts | 2 +- apps/lorem-ipsum-plugin/src/plugin.ts | 2 +- apps/poc-state-plugin/src/plugin.ts | 30 +++---- apps/rename-layers-plugin/src/plugin.ts | 8 +- apps/table-plugin/src/plugin.ts | 4 +- libs/plugin-types/index.d.ts | 89 ++++++------------- libs/plugins-runtime/src/lib/api/index.ts | 33 ++----- .../src/lib/api/plugin-api.spec.ts | 44 ++++----- .../src/lib/create-plugin.spec.ts | 1 - .../src/lib/plugin-manager.spec.ts | 2 +- .../plugins-runtime/src/lib/plugin-manager.ts | 2 +- 15 files changed, 89 insertions(+), 152 deletions(-) diff --git a/apps/contrast-plugin/src/plugin.ts b/apps/contrast-plugin/src/plugin.ts index ad2cfcb..d9a8046 100644 --- a/apps/contrast-plugin/src/plugin.ts +++ b/apps/contrast-plugin/src/plugin.ts @@ -1,6 +1,6 @@ import type { PluginMessageEvent, PluginUIEvent } from './model.js'; -penpot.ui.open('CONTRAST PLUGIN', `?theme=${penpot.getTheme()}`, { +penpot.ui.open('CONTRAST PLUGIN', `?theme=${penpot.theme}`, { width: 285, height: 525, }); @@ -10,8 +10,8 @@ penpot.ui.onMessage((message) => { sendMessage({ type: 'init', content: { - theme: penpot.getTheme(), - selection: penpot.getSelectedShapes(), + theme: penpot.theme, + selection: penpot.selection, }, }); @@ -20,7 +20,7 @@ penpot.ui.onMessage((message) => { }); penpot.on('selectionchange', () => { - const shapes = penpot.getSelectedShapes(); + const shapes = penpot.selection; sendMessage({ type: 'selection', content: shapes }); initEvents(); @@ -37,7 +37,7 @@ function initEvents() { return penpot.on( 'shapechange', () => { - const shapes = penpot.getSelectedShapes(); + const shapes = penpot.selection; sendMessage({ type: 'selection', content: shapes }); }, { shapeId: shape.id } @@ -46,7 +46,7 @@ function initEvents() { } penpot.on('themechange', () => { - const theme = penpot.getTheme(); + const theme = penpot.theme; sendMessage({ type: 'theme', content: theme }); }); diff --git a/apps/e2e/src/plugins/component-library.ts b/apps/e2e/src/plugins/component-library.ts index 02fa483..4e4037b 100644 --- a/apps/e2e/src/plugins/component-library.ts +++ b/apps/e2e/src/plugins/component-library.ts @@ -3,7 +3,7 @@ export default function () { rectangle.x = penpot.viewport.center.x; rectangle.y = penpot.viewport.center.y; - const shape = penpot.getPage()?.getShapeById(rectangle.id); + const shape = penpot.currentPage?.getShapeById(rectangle.id); if (shape) { penpot.library.local.createComponent([shape]); } diff --git a/apps/e2e/src/plugins/create-comments.ts b/apps/e2e/src/plugins/create-comments.ts index 379ba7e..609b699 100644 --- a/apps/e2e/src/plugins/create-comments.ts +++ b/apps/e2e/src/plugins/create-comments.ts @@ -1,6 +1,6 @@ export default function () { async function createComment() { - const page = penpot.getPage(); + const page = penpot.currentPage; if (page) { await page.addCommentThread('Hello world!', { @@ -11,7 +11,7 @@ export default function () { } async function replyComment() { - const page = penpot.getPage(); + const page = penpot.currentPage; if (page) { const comments = await page.findCommentThreads({ @@ -23,7 +23,7 @@ export default function () { } async function deleteComment() { - const page = penpot.getPage(); + const page = penpot.currentPage; if (page) { const commentThreads = await page.findCommentThreads({ diff --git a/apps/e2e/src/plugins/create-ruler-guides.ts b/apps/e2e/src/plugins/create-ruler-guides.ts index 60d9bfa..390e7d0 100644 --- a/apps/e2e/src/plugins/create-ruler-guides.ts +++ b/apps/e2e/src/plugins/create-ruler-guides.ts @@ -1,6 +1,6 @@ export default function () { function createRulerGuides(): void { - const page = penpot.getPage(); + const page = penpot.currentPage; if (page) { page.addRulerGuide('horizontal', penpot.viewport.center.x); @@ -9,7 +9,7 @@ export default function () { } function removeRulerGuides(): void { - const page = penpot.getPage(); + const page = penpot.currentPage; if (page) { page.removeRulerGuide(page.rulerGuides[0]); diff --git a/apps/icons-plugin/src/plugin.ts b/apps/icons-plugin/src/plugin.ts index ebf3c69..c5f6bd4 100644 --- a/apps/icons-plugin/src/plugin.ts +++ b/apps/icons-plugin/src/plugin.ts @@ -1,6 +1,6 @@ import type { PluginMessageEvent, PluginUIEvent } from './model.js'; -penpot.ui.open('FEATHER ICONS PLUGIN', `?theme=${penpot.getTheme()}`, { +penpot.ui.open('FEATHER ICONS PLUGIN', `?theme=${penpot.theme}`, { width: 292, height: 540, }); diff --git a/apps/lorem-ipsum-plugin/src/plugin.ts b/apps/lorem-ipsum-plugin/src/plugin.ts index cfeffaa..3f97da9 100644 --- a/apps/lorem-ipsum-plugin/src/plugin.ts +++ b/apps/lorem-ipsum-plugin/src/plugin.ts @@ -11,7 +11,7 @@ import { generateCharacters, } from './generator.js'; -penpot.ui.open('LOREM IPSUM PLUGIN', `?theme=${penpot.getTheme()}`); +penpot.ui.open('LOREM IPSUM PLUGIN', `?theme=${penpot.theme}`); penpot.on('themechange', (theme) => { sendMessage({ type: 'theme', content: theme }); diff --git a/apps/poc-state-plugin/src/plugin.ts b/apps/poc-state-plugin/src/plugin.ts index ed8e315..97def70 100644 --- a/apps/poc-state-plugin/src/plugin.ts +++ b/apps/poc-state-plugin/src/plugin.ts @@ -52,7 +52,7 @@ penpot.ui.onMessage<{ content: string; data: unknown }>(async (message) => { }); penpot.on('pagechange', () => { - const page = penpot.getPage(); + const page = penpot.currentPage; const shapes = page?.findShapes(); penpot.ui.sendMessage({ @@ -62,7 +62,7 @@ penpot.on('pagechange', () => { }); penpot.on('filechange', () => { - const file = penpot.getFile(); + const file = penpot.currentFile; if (!file) { return; @@ -77,7 +77,7 @@ penpot.on('filechange', () => { }); penpot.on('selectionchange', () => { - const selection = penpot.getSelectedShapes(); + const selection = penpot.selection; const data: string | null = selection.length === 1 ? selection[0].getPluginData('counter') : null; const counter = data ? parseInt(data, 10) : 0; @@ -89,8 +89,8 @@ penpot.on('themechange', (theme) => { }); function init() { - const page = penpot.getPage(); - const file = penpot.getFile(); + const page = penpot.currentPage; + const file = penpot.currentFile; if (!page || !file) { return; @@ -108,7 +108,7 @@ function init() { pageId: page.id, fileId: file.id, revn: file.revn, - theme: penpot.getTheme(), + theme: penpot.theme, selection, counter, }, @@ -116,7 +116,7 @@ function init() { } function changeName(data: { id: string; name: string }) { - const shape = penpot.getPage()?.getShapeById('' + data.id); + const shape = penpot.currentPage?.getShapeById('' + data.id); if (shape) { shape.name = data.name; } @@ -140,28 +140,28 @@ function createRect() { } function moveX(data: { id: string }) { - const shape = penpot.getPage()?.getShapeById('' + data.id); + const shape = penpot.currentPage?.getShapeById('' + data.id); if (shape) { shape.x += 100; } } function moveY(data: { id: string }) { - const shape = penpot.getPage()?.getShapeById('' + data.id); + const shape = penpot.currentPage?.getShapeById('' + data.id); if (shape) { shape.y += 100; } } function resizeW(data: { id: string }) { - const shape = penpot.getPage()?.getShapeById('' + data.id); + const shape = penpot.currentPage?.getShapeById('' + data.id); if (shape) { shape.resize(shape.width * 2, shape.height); } } function resizeH(data: { id: string }) { - const shape = penpot.getPage()?.getShapeById('' + data.id); + const shape = penpot.currentPage?.getShapeById('' + data.id); if (shape) { shape.resize(shape.width, shape.height * 2); } @@ -449,7 +449,7 @@ function createMargins() { selected.addRulerGuide('vertical', width - 10); selected.addRulerGuide('horizontal', 10); selected.addRulerGuide('horizontal', height - 10); - } else { + } else if (page) { console.log('bound', penpot.viewport.bounds); const { x, y, width, height } = penpot.viewport.bounds; page.addRulerGuide('vertical', x + 100); @@ -464,7 +464,7 @@ async function addComment() { if (shape) { const content = shape.name + ' - ' + Date.now(); - const cthr = await penpot.currentPage.findCommentThreads(); + const cthr = await penpot.currentPage?.findCommentThreads(); const th = cthr && cthr[0]; if (th) { @@ -476,13 +476,13 @@ async function addComment() { } } else { console.log('Create new thread', content); - await penpot.currentPage.addCommentThread(content, shape.center); + await penpot.currentPage?.addCommentThread(content, shape.center); } } } async function exportFile() { - const data = await penpot.getFile()?.export('penpot'); + const data = await penpot.currentFile?.export('penpot'); if (data) { penpot.ui.sendMessage({ diff --git a/apps/rename-layers-plugin/src/plugin.ts b/apps/rename-layers-plugin/src/plugin.ts index 1cc4196..e1d38e6 100644 --- a/apps/rename-layers-plugin/src/plugin.ts +++ b/apps/rename-layers-plugin/src/plugin.ts @@ -1,6 +1,6 @@ import { PluginMessageEvent } from './app/model'; -penpot.ui.open('RENAME LAYER PLUGIN', `?theme=${penpot.getTheme()}`, { +penpot.ui.open('RENAME LAYER PLUGIN', `?theme=${penpot.theme}`, { width: 290, height: 550, }); @@ -55,9 +55,9 @@ penpot.ui.onMessage((message) => { }); function getShapes() { - return penpot.getSelectedShapes().length - ? penpot.getSelectedShapes() - : penpot.getPage()?.findShapes(); + return penpot.selection.length + ? penpot.selection + : penpot.currentPage?.findShapes(); } function resetSelection() { diff --git a/apps/table-plugin/src/plugin.ts b/apps/table-plugin/src/plugin.ts index f2587f0..92d7d6c 100644 --- a/apps/table-plugin/src/plugin.ts +++ b/apps/table-plugin/src/plugin.ts @@ -1,7 +1,7 @@ import { GridLayout } from '@penpot/plugin-types'; import { PluginMessageEvent, TablePluginEvent } from './app/model'; -penpot.ui.open('TABLE PLUGIN', `?theme=${penpot.getTheme()}`, { +penpot.ui.open('TABLE PLUGIN', `?theme=${penpot.theme}`, { width: 280, height: 610, }); @@ -219,7 +219,7 @@ function createFlexCell( function pluginData(message: PluginMessageEvent) { if (message.type === 'tableconfig') { const { type, options } = message.content; - const page = penpot.getPage(); + const page = penpot.currentPage; if (type === 'save') { page?.setPluginData('table-plugin', JSON.stringify(options)); diff --git a/libs/plugin-types/index.d.ts b/libs/plugin-types/index.d.ts index f6b6ed4..b9d376f 100644 --- a/libs/plugin-types/index.d.ts +++ b/libs/plugin-types/index.d.ts @@ -688,7 +688,18 @@ export interface Context { * console.log(rootShape); * ``` */ - readonly root: Shape; + readonly root: Shape | null; + /** + * Retrieves file data from the current Penpot context. Requires `content:read` permission. + * @return Returns the file data or `null` if no file is available. + * + * @example + * ```js + * const fileData = context.currentFile; + * console.log(fileData); + * ``` + */ + readonly currentFile: File | null; /** * The current page in the Penpot context. Requires `content:read` permission. * @@ -698,7 +709,7 @@ export interface Context { * console.log(currentPage); * ``` */ - readonly currentPage: Page; + readonly currentPage: Page | null; /** * The viewport settings in the Penpot context. * @@ -762,6 +773,17 @@ export interface Context { */ readonly activeUsers: ActiveUser[]; + /** + * The current theme (light or dark) in Penpot. + * + * @example + * ```js + * const currentTheme = context.theme; + * console.log(currentTheme); + * ``` + */ + readonly theme: Theme; + /** * The currently selected shapes in Penpot. Requires `content:read` permission. * @@ -773,51 +795,6 @@ export interface Context { */ selection: Shape[]; - /** - * Retrieves file data from the current Penpot context. Requires `content:read` permission. - * @return Returns the file data or `null` if no file is available. - * - * @example - * ```js - * const fileData = context.getFile(); - * console.log(fileData); - * ``` - */ - getFile(): File | null; - /** - * Retrieves page data from the current Penpot context. Requires `content:read` permission. - * @return Returns the page data or `null` if no page is available. - * - * @example - * ```js - * const pageData = context.getPage(); - * console.log(pageData); - * ``` - */ - getPage(): Page | null; - /** - * Retrieves the IDs of the currently selected elements in Penpot. Requires `content:read` permission. - * @return Returns an array of IDs representing the selected elements. - * - * @example - * ```js - * const selectedIds = context.getSelected(); - * console.log(selectedIds); - * ``` - */ - getSelected(): string[]; - /** - * Retrieves the shapes of the currently selected elements in Penpot. Requires `content:read` permission. - * @return Returns an array of shapes representing the selected elements. - * - * @example - * ```js - * const selectedShapes = context.getSelectedShapes(); - * console.log(selectedShapes); - * ``` - */ - getSelectedShapes(): Shape[]; - /** * Retrieves colors applied to the given shapes in Penpot. Requires `content:read` permission. * @return Returns an array of colors and their shape information. @@ -840,18 +817,6 @@ export interface Context { */ replaceColor(shapes: Shape[], oldColor: Color, newColor: Color): void; - /** - * Retrieves the current theme (light or dark) in Penpot. - * @return Returns the current theme. - * - * @example - * ```js - * const currentTheme = context.getTheme(); - * console.log(currentTheme); - * ``` - */ - getTheme(): Theme; - /** * Uploads media to Penpot and retrieves its image data. Requires `content:write` permission. * @param name The name of the media. @@ -2774,7 +2739,7 @@ export interface Page extends PluginData { * * @example * ```js - * const shape = penpot.getPage().getShapeById('shapeId'); + * const shape = penpot.currentPage.getShapeById('shapeId'); * ``` */ getShapeById(id: string): Shape | null; @@ -2785,7 +2750,7 @@ export interface Page extends PluginData { * @param criteria * @example * ```js - * const shapes = penpot.getPage().findShapes({ name: 'exampleName' }); + * const shapes = penpot.currentPage.findShapes({ name: 'exampleName' }); * ``` */ findShapes(criteria?: { @@ -2815,7 +2780,7 @@ export interface Page extends PluginData { * * @example * ```js - * const flow = penpot.getPage().createFlow('exampleFlow', board); + * const flow = penpot.currentPage.createFlow('exampleFlow', board); * ``` */ createFlow(name: string, board: Board): Flow; diff --git a/libs/plugins-runtime/src/lib/api/index.ts b/libs/plugins-runtime/src/lib/api/index.ts index 6f565f4..ead4b48 100644 --- a/libs/plugins-runtime/src/lib/api/index.ts +++ b/libs/plugins-runtime/src/lib/api/index.ts @@ -130,12 +130,17 @@ export function createApi( // Penpot State API - get root(): Shape { + get root(): Shape | null { checkPermission('content:read'); return plugin.context.root; }, - get currentPage(): Page { + get currentFile(): File | null { + checkPermission('content:read'); + return plugin.context.currentFile; + }, + + get currentPage(): Page | null { checkPermission('content:read'); return plugin.context.currentPage; }, @@ -178,26 +183,6 @@ export function createApi( return plugin.context.activeUsers; }, - getFile(): File | null { - checkPermission('content:read'); - return plugin.context.getFile(); - }, - - getPage(): Page | null { - checkPermission('content:read'); - return plugin.context.getPage(); - }, - - getSelected(): string[] { - checkPermission('content:read'); - return plugin.context.getSelected(); - }, - - getSelectedShapes(): Shape[] { - checkPermission('content:read'); - return plugin.context.getSelectedShapes(); - }, - shapesColors(shapes: Shape[]): (Color & ColorShapeInfo)[] { checkPermission('content:read'); return plugin.context.shapesColors(shapes); @@ -208,8 +193,8 @@ export function createApi( return plugin.context.replaceColor(shapes, oldColor, newColor); }, - getTheme(): Theme { - return plugin.context.getTheme(); + get theme(): Theme { + return plugin.context.theme; }, createBoard(): Board { diff --git a/libs/plugins-runtime/src/lib/api/plugin-api.spec.ts b/libs/plugins-runtime/src/lib/api/plugin-api.spec.ts index ae3bf71..769202b 100644 --- a/libs/plugins-runtime/src/lib/api/plugin-api.spec.ts +++ b/libs/plugins-runtime/src/lib/api/plugin-api.spec.ts @@ -1,6 +1,6 @@ import { expect, describe, vi } from 'vitest'; import { createApi } from './index.js'; -import type { File } from '@penpot/plugin-types'; +import type { File, Page, Shape } from '@penpot/plugin-types'; const mockUrl = 'http://fake.fake/'; @@ -30,11 +30,10 @@ describe('Plugin api', () => { registerListener: vi.fn(), destroyListener: vi.fn(), context: { - getFile: vi.fn(), - getPage: vi.fn(), - getSelected: vi.fn(), - getSelectedShapes: vi.fn(), - getTheme: vi.fn(() => 'dark'), + currentFile: null as File | null, + currentPage: null as Page | null, + selection: [] as Shape[], + theme: 'dark', addListener: vi.fn().mockReturnValueOnce(Symbol()), removeListener: vi.fn(), }, @@ -76,31 +75,17 @@ describe('Plugin api', () => { api.penpot.on('selectionchange', callback); }).toThrow(); }); - - it('get states', () => { - expect(() => { - api.penpot.getFile(); - }).toThrow(); - - expect(() => { - api.penpot.getPage(); - }).toThrow(); - - expect(() => { - api.penpot.getSelected(); - }).toThrow(); - }); }); it('get file state', () => { const examplePage = { name: 'test', id: '123', - }; + } as Page; - pluginManager.context.getPage.mockImplementation(() => examplePage); + pluginManager.context.currentPage = examplePage; - const pageState = api.penpot.getPage(); + const pageState = api.penpot.currentPage; expect(pageState).toEqual(examplePage); }); @@ -112,19 +97,22 @@ describe('Plugin api', () => { revn: 0, } as File; - pluginManager.context.getFile.mockImplementation(() => exampleFile); + pluginManager.context.currentFile = exampleFile; - const fileState = api.penpot.getFile(); + const fileState = api.penpot.currentFile; expect(fileState).toEqual(exampleFile); }); it('get selection', () => { - const selection = ['123']; + const selection = [ + { id: '123', name: 'test' }, + { id: 'abc', name: 'test2' }, + ] as Shape[]; - pluginManager.context.getSelected.mockImplementation(() => selection); + pluginManager.context.selection = selection; - const currentSelection = api.penpot.getSelected(); + const currentSelection = api.penpot.selection; expect(currentSelection).toEqual(selection); }); diff --git a/libs/plugins-runtime/src/lib/create-plugin.spec.ts b/libs/plugins-runtime/src/lib/create-plugin.spec.ts index b5ce200..f721e7c 100644 --- a/libs/plugins-runtime/src/lib/create-plugin.spec.ts +++ b/libs/plugins-runtime/src/lib/create-plugin.spec.ts @@ -61,7 +61,6 @@ describe('createPlugin', () => { mockContext = { addListener: vi.fn(), removeListener: vi.fn(), - getTheme: vi.fn().mockReturnValue('light'), } as unknown as Context; onCloseCallback = vi.fn(); diff --git a/libs/plugins-runtime/src/lib/plugin-manager.spec.ts b/libs/plugins-runtime/src/lib/plugin-manager.spec.ts index 18c5a5a..cd35f18 100644 --- a/libs/plugins-runtime/src/lib/plugin-manager.spec.ts +++ b/libs/plugins-runtime/src/lib/plugin-manager.spec.ts @@ -59,9 +59,9 @@ describe('createPluginManager', () => { ); mockContext = { + theme: 'light', addListener: vi.fn().mockReturnValue(Symbol()), removeListener: vi.fn(), - getTheme: vi.fn().mockReturnValue('light'), } as unknown as Context; onCloseCallback = vi.fn(); diff --git a/libs/plugins-runtime/src/lib/plugin-manager.ts b/libs/plugins-runtime/src/lib/plugin-manager.ts index 3e0b035..f935070 100644 --- a/libs/plugins-runtime/src/lib/plugin-manager.ts +++ b/libs/plugins-runtime/src/lib/plugin-manager.ts @@ -79,7 +79,7 @@ export async function createPluginManager( }; const openModal = (name: string, url: string, options?: OpenUIOptions) => { - const theme = context.getTheme() as 'light' | 'dark'; + const theme = context.theme as 'light' | 'dark'; const modalUrl = getValidUrl(manifest.host, url);