0
Fork 0
mirror of https://github.com/penpot/penpot-plugins.git synced 2025-01-21 06:02:34 -05:00

feat: support for plugin data

This commit is contained in:
alonso.torres 2024-06-06 09:36:03 +02:00 committed by Alonso Torres
parent d90e7dbcf0
commit fbee228760
5 changed files with 99 additions and 63 deletions

View file

@ -1,8 +1,20 @@
/**
* TODO PenpotPluginData
*/
export interface PenpotPluginData {
getPluginData(key: string): string;
setPluginData(key: string, value: string): void;
getPluginDataKeys(): string[];
getSharedPluginData(namespace: string, key: string): string;
setSharedPluginData(namespace: string, key: string, value: string): void;
getSharedPluginDataKeys(namespace: string): string[];
}
/**
* PenpotFile represents a file in the Penpot application.
* It includes properties for the file's identifier, name, and revision number.
*/
export interface PenpotFile {
export interface PenpotFile extends PenpotPluginData {
id: string;
name: string;
revn: number;
@ -12,7 +24,7 @@ export interface PenpotFile {
* PenpotPage represents a page in the Penpot application.
* It includes properties for the page's identifier and name, as well as methods for managing shapes on the page.
*/
export interface PenpotPage {
export interface PenpotPage extends PenpotPluginData {
/**
* The `id` property is a unique identifier for the page.
*/
@ -465,7 +477,7 @@ interface PenpotPathCommand {
/**
* TODO PenpotShapeBase
*/
export interface PenpotShapeBase {
export interface PenpotShapeBase extends PenpotPluginData {
id: string;
name: string;
x: number;
@ -635,6 +647,23 @@ export interface PenpotPath extends PenpotShapeBase {
content: Array<PenpotPathCommand>;
}
/**
* TODO PenpotTextRange
*/
export interface PenpotTextRange {
shape: PenpotText;
fontId: string | 'mixed';
fontFamily: string | 'mixed';
fontVariantId: string | 'mixed';
fontSize: string | 'mixed';
fontWeight: string | 'mixed';
fontStyle: string | 'mixed';
lineHeight: string | 'mixed';
letterSpacing: string | 'mixed';
textTransform: string | 'mixed';
}
/**
* PenpotText represents a text element in the Penpot application, extending the base shape interface.
* It includes various properties to define the text content and its styling attributes.
@ -653,6 +682,8 @@ export interface PenpotText extends PenpotShapeBase {
lineHeight: string | 'mixed';
letterSpacing: string | 'mixed';
textTransform: string | 'mixed';
getRange(start: number, end: number): PenpotTextRange;
}
/**
@ -760,7 +791,7 @@ export type PenpotTheme = 'light' | 'dark';
/**
* TODO PenpotLibraryElement
*/
export interface PenpotLibraryElement {
export interface PenpotLibraryElement extends PenpotPluginData {
readonly id: string;
readonly libraryId: string;
name: string;
@ -831,7 +862,7 @@ export interface PenpotLibraryTypography extends PenpotLibraryElement {
* applyToTextRange code
* ```
*/
applyToTextRange(shape: PenpotShape): void;
applyToTextRange(range: PenpotTextRange): void;
}
/**
@ -852,7 +883,8 @@ export interface PenpotLibraryComponent extends PenpotLibraryElement {
/**
* TODO PenpotLibrary
*/
export type PenpotLibrary = {
export interface PenpotLibrary extends PenpotPluginData {
colors: PenpotLibraryColor[];
typographies: PenpotLibraryTypography[];
components: PenpotLibraryComponent[];
@ -884,7 +916,7 @@ export type PenpotLibrary = {
* ```
*/
createComponent(shapes: PenpotShape[]): PenpotLibraryComponent;
};
}
/**
* TODO PenpotLibraryContext

View file

@ -3,10 +3,10 @@ import './lib/modal/plugin-modal';
import {
ɵloadPlugin,
setContext,
setContextBuilder,
ɵloadPluginByUrl,
} from './lib/load-plugin.js';
import * as api from './lib/api/index.js';
import type { PenpotContext } from '@penpot/plugin-types';
console.log('%c[PLUGINS] Loading plugin system', 'color: #008d7c');
@ -20,18 +20,12 @@ repairIntrinsics({
const globalThisAny$ = globalThis as any;
globalThisAny$.initPluginsRuntime = (context: PenpotContext) => {
if (context) {
console.log('%c[PLUGINS] Initialize context', 'color: #008d7c');
globalThisAny$.ɵcontext = context;
globalThis.ɵloadPlugin = ɵloadPlugin;
globalThis.ɵloadPluginByUrl = ɵloadPluginByUrl;
setContext(context);
for (const event of api.validEvents) {
context.addListener(event, api.triggerEvent.bind(null, event));
}
}
globalThisAny$.initPluginsRuntime = (
contextBuilder: (id: string) => PenpotContext
) => {
console.log('%c[PLUGINS] Initialize runtime', 'color: #008d7c');
setContextBuilder(contextBuilder);
globalThisAny$.ɵcontext = contextBuilder('TEST');
globalThis.ɵloadPlugin = ɵloadPlugin;
globalThis.ɵloadPluginByUrl = ɵloadPluginByUrl;
};

View file

@ -31,6 +31,7 @@ describe('Plugin api', () => {
};
const api = createApi(mockContext as any, {
pluginId: 'test',
name: 'test',
code: '',
host: 'http://fake.com',

View file

@ -3,19 +3,32 @@ import type { PenpotContext } from '@penpot/plugin-types';
import { createApi } from './api/index.js';
import { loadManifest, loadManifestCode } from './parse-manifest.js';
import { Manifest } from './models/manifest.model.js';
import * as api from './api/index.js';
let isLockedDown = false;
let createdApis: ReturnType<typeof createApi>[] = [];
const multiPlugin = false;
let pluginContext: PenpotContext | null = null;
export type ContextBuilder = (id: string) => PenpotContext;
export function setContext(context: PenpotContext) {
pluginContext = context;
let contextBuilder: ContextBuilder | null = null;
export function setContextBuilder(builder: ContextBuilder) {
contextBuilder = builder;
}
export const ɵloadPlugin = async function (manifest: Manifest) {
try {
const context = contextBuilder && contextBuilder(manifest.pluginId);
if (!context) {
return;
}
for (const event of api.validEvents) {
context.addListener(event, api.triggerEvent.bind(null, event));
}
const code = await loadManifestCode(manifest);
if (!isLockedDown) {
@ -29,46 +42,42 @@ export const ɵloadPlugin = async function (manifest: Manifest) {
});
}
if (pluginContext) {
const pluginApi = createApi(pluginContext, manifest);
createdApis.push(pluginApi);
const pluginApi = createApi(context, manifest);
createdApis.push(pluginApi);
const c = new Compartment({
penpot: harden(pluginApi),
fetch: harden((...args: Parameters<typeof fetch>) => {
const requestArgs: RequestInit = {
...args[1],
credentials: 'omit',
};
const c = new Compartment({
penpot: harden(pluginApi),
fetch: harden((...args: Parameters<typeof fetch>) => {
const requestArgs: RequestInit = {
...args[1],
credentials: 'omit',
};
return fetch(args[0], requestArgs);
}),
console: harden(window.console),
Math: harden(Math),
setTimeout: harden(
(...[handler, timeout]: Parameters<typeof setTimeout>) => {
return setTimeout(() => {
handler();
}, timeout);
}
),
clearTimeout: harden((id: Parameters<typeof clearTimeout>[0]) => {
clearTimeout(id);
}),
return fetch(args[0], requestArgs);
}),
console: harden(window.console),
Math: harden(Math),
setTimeout: harden(
(...[handler, timeout]: Parameters<typeof setTimeout>) => {
return setTimeout(() => {
handler();
}, timeout);
}
),
clearTimeout: harden((id: Parameters<typeof clearTimeout>[0]) => {
clearTimeout(id);
}),
});
c.evaluate(code);
const listenerId: symbol = context.addListener('finish', () => {
createdApis.forEach((pluginApi) => {
pluginApi.closePlugin();
});
c.evaluate(code);
const listenerId: symbol = pluginContext.addListener('finish', () => {
createdApis.forEach((pluginApi) => {
pluginApi.closePlugin();
});
pluginContext?.removeListener(listenerId);
});
} else {
console.error('Cannot find Penpot Context');
}
context?.removeListener(listenerId);
});
} catch (error) {
console.error(error);
}
@ -76,6 +85,5 @@ export const ɵloadPlugin = async function (manifest: Manifest) {
export const ɵloadPluginByUrl = async function (manifestUrl: string) {
const manifest = await loadManifest(manifestUrl);
ɵloadPlugin(manifest);
};

View file

@ -1,6 +1,7 @@
import { z } from 'zod';
export const manifestSchema = z.object({
pluginId: z.string(),
name: z.string(),
host: z.string().url(),
code: z.string(),