From 1f17f489023d47b316b67e10eb48e89c06037506 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Wed, 7 Feb 2024 21:36:23 +0100 Subject: [PATCH 01/32] feat(vectorizer): Simplify and move into worker --- .vscode/launch.json | 15 ++ packages/vectorizer/esbuild/config.mjs | 9 +- packages/vectorizer/package.json | 2 +- packages/vectorizer/src/commands.ts | 155 +++++++++++++++++ packages/vectorizer/src/constants.ts | 16 +- packages/vectorizer/src/enableFeatures.ts | 28 --- packages/vectorizer/src/plugin.ts | 87 ++++++---- .../vectorizer/src/processVectorization.ts | 163 ------------------ .../src/{registerComponents.ts => ui.ts} | 30 ++-- packages/vectorizer/src/utils.ts | 62 ++++--- packages/vectorizer/src/worker.ts | 15 ++ yarn.lock | 4 +- 12 files changed, 312 insertions(+), 274 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 packages/vectorizer/src/commands.ts delete mode 100644 packages/vectorizer/src/enableFeatures.ts delete mode 100644 packages/vectorizer/src/processVectorization.ts rename packages/vectorizer/src/{registerComponents.ts => ui.ts} (75%) create mode 100644 packages/vectorizer/src/worker.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a14d56e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/packages/vectorizer/esbuild/config.mjs b/packages/vectorizer/esbuild/config.mjs index e60ac60..6f1d7ed 100644 --- a/packages/vectorizer/esbuild/config.mjs +++ b/packages/vectorizer/esbuild/config.mjs @@ -14,17 +14,18 @@ console.log( const configs = [ { - entryPoints: ['src/index.ts'], + entryPoints: ['src/index.ts', "src/worker.ts"], define: { PLUGIN_VERSION: `"${packageJson.version}"` }, minify: true, bundle: true, sourcemap: true, - external: ['@cesdk/cesdk-js', 'lodash', "node:path", "fs", "url"], - platform: 'browser', + external: ['@cesdk/cesdk-js'], + platform: 'node', format: 'esm', - outfile: 'dist/index.mjs', + outdir: 'dist', + outExtension: { '.js': '.mjs' }, plugins: [ { name: 'reporter', diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index e23dc4a..766e52e 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -64,7 +64,7 @@ "@cesdk/cesdk-js": "~1.20.0" }, "dependencies": { - "@imgly/vectorizer": "^0.1.0-rc4", + "@imgly/vectorizer": "../vectorizer/packages/js", "lodash": "^4.17.21" } } diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts new file mode 100644 index 0000000..6962984 --- /dev/null +++ b/packages/vectorizer/src/commands.ts @@ -0,0 +1,155 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; + +import { + getPluginMetadata, + isMetadataConsistent, + recoverInitialImageData, + setPluginMetadata +} from './utils'; + + +const runInWorker = (uri: string) => new Promise((resolve, reject) => { + const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); + worker.postMessage({data: uri}) + worker.onmessage = (e: MessageEvent) => { + const msg = e.data + if (msg.error) { + reject (msg.error) + return; + } + resolve(new Blob([msg.data])) + // when done terminate + worker.terminate() + } + +}) + + + /** + * Apply the vectorization process to the image. + */ + + /** + * Triggers the vectiorize process. + */ + export async function command( + cesdk: CreativeEditorSDK, + blockId: number + ) { + const engine = cesdk.engine; // the only function that needs the ui is the upload function + const blockApi = cesdk.engine.block; + if (!blockApi.hasFill(blockId)) + throw new Error('Block has no fill to vectorize'); + + const fillId = blockApi.getFill(blockId); + + // Get the current image URI and source set as initial values. + const initialSourceSet = blockApi.getSourceSet( + fillId, + 'fill/image/sourceSet' + ); + const initialImageFileURI = blockApi.getString( + fillId, + 'fill/image/imageFileURI' + ); + const initialPreviewFileURI = blockApi.getString( + fillId, + 'fill/image/previewFileURI' + ); + + + const uriToProcess = + // Source sets have priority in the engine + initialSourceSet.length > 0 + ? // Choose the highest resolution image in the source set + initialSourceSet.sort( + (a, b) => b.width * b.height - a.height * a.width + )[0].uri + : initialImageFileURI; + + if (uriToProcess === undefined || uriToProcess === '') + return; // We shall return early if the uri is not defined or invalid + + + + try { + // Clear values in the engine to trigger the loading spinner + +9 + blockApi.setString(fillId, 'fill/image/imageFileURI', ''); + blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); + // ensure we show the last image while processsing. Some images don't have the preview set + if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { + blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); + } + const metadata = getPluginMetadata(engine, blockId); + setPluginMetadata(engine, blockId, { + ...metadata, + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSING' + }); + + const vectorized: Blob = await runInWorker(uriToProcess) + + if ( + getPluginMetadata(cesdk.engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(cesdk, blockId) + ) + return; + + const pathname = new URL(uriToProcess).pathname; + const parts = pathname.split('/'); + const filename = parts[parts.length - 1]; + + const uploadedAssets = await cesdk.unstable_upload( + new File([vectorized], filename, { type: vectorized.type }), + () => { + // TODO Delegate process to UI component + } + ); + + // Check for externally changed state while we were uploading and + // do not proceed if the state was reset. + if ( + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(cesdk, blockId) + ) + return; + + const url = uploadedAssets.meta?.uri; + if (url == null) { + throw new Error('Could not upload vectorized image'); + } + + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED_TOGGLE_ON', + processedAsset: url + }); + blockApi.setString(fillId, 'fill/image/imageFileURI', url); + // Finally, create an undo step + cesdk.engine.editor.addUndoStep(); + } catch (error) { + if (cesdk.engine.block.isValid(blockId)) { + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'ERROR' + }); + + recoverInitialImageData(cesdk, blockId); + } + // eslint-disable-next-line no-console + console.error(error); + } + } diff --git a/packages/vectorizer/src/constants.ts b/packages/vectorizer/src/constants.ts index 241c544..0f5afca 100644 --- a/packages/vectorizer/src/constants.ts +++ b/packages/vectorizer/src/constants.ts @@ -1,10 +1,10 @@ export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; -export const CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; -export const CANVAS_MENU_COMPONENT_BUTTON_ID = `${CANVAS_MENU_COMPONENT_ID}.button`; -export const FEATURE_ID = `${PLUGIN_ID}.feature`; -export const I18N_ID = "plugin.vectorizer.vectorize" -export const I18N_TRANSLATIONS = { - en: { [I18N_ID]: 'Vectorize' }, - de: { [I18N_ID]: 'Vektorisieren' } +export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; +export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; +export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; +export const PLUGIN_I18N_ID = `plugin.${PLUGIN_ID}.vectorize` +export const PLUGIN_I18N_TRANSLATIONS = { + en: { [PLUGIN_I18N_ID]: 'Vectorize' }, + de: { [PLUGIN_I18N_ID]: 'Vektorisieren' } } -export const ICON = '@imgly/icons/Vectorize' \ No newline at end of file +export const PLUGIN_ICON = '@imgly/icons/Vectorize' \ No newline at end of file diff --git a/packages/vectorizer/src/enableFeatures.ts b/packages/vectorizer/src/enableFeatures.ts deleted file mode 100644 index eaa865b..0000000 --- a/packages/vectorizer/src/enableFeatures.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -import { FEATURE_ID } from './constants'; -/** - * Defines the feature that determines in which context (on which block) - * background removal is allowed/enabled. - */ -export function enableFeatures(cesdk: CreativeEditorSDK) { - cesdk.feature.unstable_enable(FEATURE_ID, ({ engine }) => { - const selectedIds = engine.block.findAllSelected(); - if (selectedIds.length !== 1) { - return false; - } - const [selectedId] = selectedIds; - - if (cesdk.engine.block.hasFill(selectedId)) { - const fillId = cesdk.engine.block.getFill(selectedId); - const fillType = cesdk.engine.block.getType(fillId); - - if (fillType !== '//ly.img.ubq/fill/image') { - return false; - } - return true - - } - - return false; - }); -} diff --git a/packages/vectorizer/src/plugin.ts b/packages/vectorizer/src/plugin.ts index 709041e..21ab4f5 100644 --- a/packages/vectorizer/src/plugin.ts +++ b/packages/vectorizer/src/plugin.ts @@ -1,9 +1,10 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; + +import { PLUGIN_FEATURE_ID, PLUGIN_ID } from './constants'; + +import { command } from './commands'; +import { registerComponents } from './ui'; -import { FEATURE_ID, PLUGIN_ID } from './constants'; -import { enableFeatures } from './enableFeatures'; -import { processVectorization } from './processVectorization'; -import { registerComponents } from './registerComponents'; import { clearPluginMetadata, fixDuplicateMetadata, @@ -12,34 +13,36 @@ import { isMetadataConsistent } from './utils'; -export interface PluginConfiguration {} +export interface PluginConfiguration { } export default (pluginConfiguration: PluginConfiguration = {}) => { return { - initialize() {}, + initialize(engine: CreativeEngine) { + engine.event.subscribe([], async (events) => { + events + .filter((e) => engine.block.isValid(e.block) && engine.block.hasMetadata(e.block, PLUGIN_ID)) + .forEach((e) => { + const id = e.block; + if (e.type === 'Created') { + const metadata = getPluginMetadata(engine, id); + if (isDuplicate(engine, id, metadata)) { + fixDuplicateMetadata(engine, id); + } + } + }); + }); + }, - update() {}, + update() { + + }, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { cesdk.engine.event.subscribe([], async (events) => { - events.forEach((e) => { - const id = e.block; - if ( - !cesdk.engine.block.isValid(id) || - !cesdk.engine.block.hasMetadata(id, PLUGIN_ID) - ) { - return; - } - - if (e.type === 'Created') { - const metadata = getPluginMetadata(cesdk, id); - if (isDuplicate(cesdk, id, metadata)) { - fixDuplicateMetadata(cesdk, id); - } - } else if (e.type === 'Updated') { - handleUpdateEvent(cesdk, id); - } - }); + events + .filter((e) => cesdk.engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) + .filter((e) => e.type === 'Updated') + .forEach((e) => { handleUpdateEvent(cesdk, e.block); }); }); registerComponents(cesdk); @@ -53,16 +56,16 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { * updated. */ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { - const metadata = getPluginMetadata(cesdk, blockId); + const metadata = getPluginMetadata(cesdk.engine, blockId); switch (metadata.status) { case 'PENDING': { if ( - cesdk.feature.unstable_isEnabled(FEATURE_ID, { + cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { engine: cesdk.engine }) ) { - processVectorization(cesdk, blockId); + command(cesdk, blockId); } break; } @@ -71,7 +74,7 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { case 'PROCESSED_TOGGLE_OFF': case 'PROCESSED_TOGGLE_ON': { if (!isMetadataConsistent(cesdk, blockId)) { - clearPluginMetadata(cesdk, blockId); + clearPluginMetadata(cesdk.engine, blockId); } break; } @@ -81,3 +84,27 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { } } } + + +export function enableFeatures(cesdk: CreativeEditorSDK) { + cesdk.feature.unstable_enable(PLUGIN_FEATURE_ID, ({ engine }) => { + const selectedIds = engine.block.findAllSelected(); + if (selectedIds.length !== 1) { + return false; + } + const [selectedId] = selectedIds; + + if (cesdk.engine.block.hasFill(selectedId)) { + const fillId = cesdk.engine.block.getFill(selectedId); + const fillType = cesdk.engine.block.getType(fillId); + + if (fillType !== '//ly.img.ubq/fill/image') { + return false; + } + return true + + } + + return false; + }); +} diff --git a/packages/vectorizer/src/processVectorization.ts b/packages/vectorizer/src/processVectorization.ts deleted file mode 100644 index 3ea414a..0000000 --- a/packages/vectorizer/src/processVectorization.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -import { imageToSvg } from '@imgly/vectorizer'; - -import { - getPluginMetadata, - isMetadataConsistent, - recoverInitialImageData, - setPluginMetadata -} from './utils'; - -class Scheduler { - #queue?: Promise = undefined - - async schedule(task: () => Promise): Promise { - if (this.#queue === undefined) { - this.#queue = task() - } else { - this.#queue = this.#queue.then(async () => { - return await task() - }) - } - return this.#queue - } -} - -let scheduler = new Scheduler() - - -/** - * Apply the vectorization process to the image. - */ -async function vectorize(uri: string): Promise { - const blob = await fetch(uri).then((res) => res.blob()) - const outBlob = await scheduler.schedule(async () => await imageToSvg(blob)); - return outBlob; -} - -/** - * Triggers the vectiorize process. - */ -export async function processVectorization( - cesdk: CreativeEditorSDK, - blockId: number -) { - const blockApi = cesdk.engine.block; - if (!blockApi.hasFill(blockId)) - throw new Error('Block has no fill to vectorize'); - - const fillId = blockApi.getFill(blockId); - - // Get the current image URI and source set as initial values. - const initialSourceSet = blockApi.getSourceSet( - fillId, - 'fill/image/sourceSet' - ); - const initialImageFileURI = blockApi.getString( - fillId, - 'fill/image/imageFileURI' - ); - const initialPreviewFileURI = blockApi.getString( - fillId, - 'fill/image/previewFileURI' - ); - - - const uriToProcess = - // Source sets have priority in the engine - initialSourceSet.length > 0 - ? // Choose the highest resolution image in the source set - initialSourceSet.sort( - (a, b) => b.width * b.height - a.height * a.width - )[0].uri - : initialImageFileURI; - - if (uriToProcess === undefined || uriToProcess === '') - return; // We shall return early if the uri is not defined or invalid - - - - try { - // Clear values in the engine to trigger the loading spinner - +9 - blockApi.setString(fillId, 'fill/image/imageFileURI', ''); - blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); - // ensure we show the last image while processsing. Some images don't have the preview set - if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { - blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); - } - const metadata = getPluginMetadata(cesdk, blockId); - setPluginMetadata(cesdk, blockId, { - ...metadata, - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSING' - }); - - // Creating the mask from the highest resolution image - const vectorized = await vectorize(uriToProcess); - - // Check for externally changed state while we were uploading and - // do not proceed if the state was reset. - if ( - getPluginMetadata(cesdk, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(cesdk, blockId) - ) - return; - - const pathname = new URL(uriToProcess).pathname; - const parts = pathname.split('/'); - const filename = parts[parts.length - 1]; - - const uploadedAssets = await cesdk.unstable_upload( - new File([vectorized], filename, { type: vectorized.type }), - () => { - // TODO Delegate process to UI component - } - ); - - // Check for externally changed state while we were uploading and - // do not proceed if the state was reset. - if ( - getPluginMetadata(cesdk, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(cesdk, blockId) - ) - return; - - const url = uploadedAssets.meta?.uri; - if (url == null) { - throw new Error('Could not upload vectorized image'); - } - - setPluginMetadata(cesdk, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSED_TOGGLE_ON', - processedAsset: url - }); - blockApi.setString(fillId, 'fill/image/imageFileURI', url); - // Finally, create an undo step - cesdk.engine.editor.addUndoStep(); - } catch (error) { - if (cesdk.engine.block.isValid(blockId)) { - setPluginMetadata(cesdk, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'ERROR' - }); - - recoverInitialImageData(cesdk, blockId); - } - // eslint-disable-next-line no-console - console.error(error); - } -} diff --git a/packages/vectorizer/src/registerComponents.ts b/packages/vectorizer/src/ui.ts similarity index 75% rename from packages/vectorizer/src/registerComponents.ts rename to packages/vectorizer/src/ui.ts index e05622f..3c4ddf3 100644 --- a/packages/vectorizer/src/registerComponents.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,12 +1,12 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; import { - CANVAS_MENU_COMPONENT_BUTTON_ID, - CANVAS_MENU_COMPONENT_ID, - FEATURE_ID, - I18N_ID, - I18N_TRANSLATIONS, - ICON + PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, + PLUGIN_CANVAS_MENU_COMPONENT_ID, + PLUGIN_FEATURE_ID, + PLUGIN_I18N_ID, + PLUGIN_I18N_TRANSLATIONS, + PLUGIN_ICON } from './constants'; import { getPluginMetadata, @@ -18,17 +18,17 @@ import { * Registers the components that can be used to vectorize a block. */ export function registerComponents(cesdk: CreativeEditorSDK) { - cesdk.setTranslations(I18N_TRANSLATIONS); + cesdk.setTranslations(PLUGIN_I18N_TRANSLATIONS); // Always prepend the registered component to the canvas menu order. cesdk.ui.unstable_setCanvasMenuOrder([ - CANVAS_MENU_COMPONENT_ID, + PLUGIN_CANVAS_MENU_COMPONENT_ID, ...cesdk.ui.unstable_getCanvasMenuOrder() ]); cesdk.ui.unstable_registerComponent( - CANVAS_MENU_COMPONENT_ID, + PLUGIN_CANVAS_MENU_COMPONENT_ID, ({ builder: { Button }, engine }) => { if ( - !cesdk.feature.unstable_isEnabled(FEATURE_ID, { + !cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { engine }) ) { @@ -47,7 +47,7 @@ export function registerComponents(cesdk: CreativeEditorSDK) { const hasNoValidFill = !(sourceSet.length > 0 || fileUri !== '') - const metadata = getPluginMetadata(cesdk, id); + const metadata = getPluginMetadata(cesdk.engine, id); const isActive = false // metadata.status === 'PROCESSED_TOGGLE_ON'; const isLoading = metadata.status === 'PROCESSING'; @@ -61,15 +61,15 @@ export function registerComponents(cesdk: CreativeEditorSDK) { loadingProgress = (current / total) * 100; } - Button(CANVAS_MENU_COMPONENT_BUTTON_ID, { - label: I18N_ID, - icon: ICON, + Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { + label: PLUGIN_I18N_ID, + icon: PLUGIN_ICON, isActive, isLoading, isDisabled, loadingProgress, onClick: () => { - setPluginMetadata(cesdk, id, { + setPluginMetadata(cesdk.engine, id, { status: 'PENDING' }); } diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils.ts index 26f621e..dcfd4b0 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -1,4 +1,4 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import isEqual from 'lodash/isEqual'; import { PLUGIN_ID } from './constants'; @@ -13,11 +13,11 @@ import { * Sets the metadata for the plugin state. */ export function setPluginMetadata( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, id: number, metadata: PluginMetadata ) { - cesdk.engine.block.setMetadata(id, PLUGIN_ID, JSON.stringify(metadata)); + engine.block.setMetadata(id, PLUGIN_ID, JSON.stringify(metadata)); } /** @@ -25,11 +25,11 @@ export function setPluginMetadata( * is set on the given block, it will return an IDLE state. */ export function getPluginMetadata( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, id: number ): PluginMetadata { - if (cesdk.engine.block.hasMetadata(id, PLUGIN_ID)) { - return JSON.parse(cesdk.engine.block.getMetadata(id, PLUGIN_ID)); + if (engine.block.hasMetadata(id, PLUGIN_ID)) { + return JSON.parse(engine.block.getMetadata(id, PLUGIN_ID)); } else { return { status: 'IDLE' @@ -40,9 +40,9 @@ export function getPluginMetadata( /** * If plugin metadata is set, it will be cleared. */ -export function clearPluginMetadata(cesdk: CreativeEditorSDK, id: number) { - if (cesdk.engine.block.hasMetadata(id, PLUGIN_ID)) { - cesdk.engine.block.removeMetadata(id, PLUGIN_ID); +export function clearPluginMetadata(engine: CreativeEngine, id: number) { + if (engine.block.hasMetadata(id, PLUGIN_ID)) { + engine.block.removeMetadata(id, PLUGIN_ID); } } @@ -51,11 +51,11 @@ export function clearPluginMetadata(cesdk: CreativeEditorSDK, id: number) { * In that case the plugin state is still valid, but blockId and fillId have changed. */ export function isDuplicate( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, blockId: number, metadata: PluginMetadata ): boolean { - if (!cesdk.engine.block.isValid(blockId)) return false; + if (!engine.block.isValid(blockId)) return false; if ( metadata.status === 'IDLE' || metadata.status === 'PENDING' || @@ -63,8 +63,8 @@ export function isDuplicate( ) return false; - if (!cesdk.engine.block.hasFill(blockId)) return false; - const fillId = cesdk.engine.block.getFill(blockId); + if (!engine.block.hasFill(blockId)) return false; + const fillId = engine.block.getFill(blockId); // It cannot be a duplicate if the blockId or fillId are the same if (metadata.blockId === blockId || metadata.fillId === fillId) return false; @@ -79,18 +79,18 @@ export function isDuplicate( * Please note: Call this method only on duplicates (see isDuplicate). */ export function fixDuplicateMetadata( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, blockId: number ) { - const fillId = cesdk.engine.block.getFill(blockId); - const metadata = getPluginMetadata(cesdk, blockId); + const fillId = engine.block.getFill(blockId); + const metadata = getPluginMetadata(engine, blockId); if ( metadata.status === 'IDLE' || metadata.status === 'PENDING' || metadata.status === 'ERROR' ) return; - setPluginMetadata(cesdk, blockId, { + setPluginMetadata(engine, blockId, { ...metadata, blockId, fillId @@ -110,7 +110,7 @@ export function isMetadataConsistent( // In case the block was removed, we just abort and mark it // as reset by returning true if (!cesdk.engine.block.isValid(blockId)) return false; - const metadata = getPluginMetadata(cesdk, blockId); + const metadata = getPluginMetadata(cesdk.engine, blockId); if (metadata.status === 'IDLE' || metadata.status === 'PENDING') return true; if (!cesdk.engine.block.hasFill(blockId)) return false; @@ -190,10 +190,10 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore) const fillId = blockApi.getFill(blockId); - const metadata = getPluginMetadata(cesdk, blockId); + const metadata = getPluginMetadata(cesdk.engine, blockId); if (metadata.status === 'PROCESSED_TOGGLE_OFF') { - setPluginMetadata(cesdk, blockId, { + setPluginMetadata(cesdk.engine, blockId, { ...metadata, status: 'PROCESSED_TOGGLE_ON' }); @@ -215,7 +215,7 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { cesdk.engine.editor.addUndoStep(); } else if (metadata.status === 'PROCESSED_TOGGLE_ON') { - setPluginMetadata(cesdk, blockId, { + setPluginMetadata(cesdk.engine, blockId, { ...metadata, status: 'PROCESSED_TOGGLE_OFF' }); @@ -245,7 +245,7 @@ export function recoverInitialImageData( const blockApi = cesdk.engine.block; if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore) - const metadata = getPluginMetadata(cesdk, blockId); + const metadata = getPluginMetadata(cesdk.engine, blockId); if (metadata.status === 'PENDING' || metadata.status === 'IDLE') { return; @@ -296,3 +296,21 @@ function getValidFill( return fillId; } + + + + +export class Scheduler { + #queue?: Promise = undefined + + async schedule(task: () => Promise): Promise { + if (this.#queue === undefined) { + this.#queue = task() + } else { + this.#queue = this.#queue.then(async () => { + return await task() + }) + } + return this.#queue + } +} \ No newline at end of file diff --git a/packages/vectorizer/src/worker.ts b/packages/vectorizer/src/worker.ts new file mode 100644 index 0000000..bab111c --- /dev/null +++ b/packages/vectorizer/src/worker.ts @@ -0,0 +1,15 @@ +import { imageToSvg } from '@imgly/vectorizer'; + +self.onmessage = function (e) { + const uriToProcess = e.data.data; + fetch(uriToProcess) + .then(res => res.blob()) + .then(blob => imageToSvg(blob)) + .then(blob => blob.arrayBuffer()) + .then(blob => { + postMessage({data: blob}); + }) + .catch(err => { + postMessage({error: err}); + }) +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 03fef94..441a2b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -409,10 +409,8 @@ onnxruntime-web "~1.17.0" zod "~3.21.0" -"@imgly/vectorizer@^0.1.0-rc4": +"@imgly/vectorizer@../vectorizer/packages/js": version "0.1.0-rc4" - resolved "https://registry.yarnpkg.com/@imgly/vectorizer/-/vectorizer-0.1.0-rc4.tgz#cd654fdffb834023426f6e07e4dce37b3b4cbcee" - integrity sha512-xR4wAZ6TkyEdY6v81SqD063WwR4JWlPAu1scqohmV3pUEJMs/2N5qNz7cTW9jf5NAZeoJO68kbm+Q0fN6riVTA== dependencies: "@types/lodash" "^4.14.195" "@types/node" "^20.3.1" From 1a986b1d22f8279d2d200dc251c8bf133dabde14 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Wed, 7 Feb 2024 21:55:32 +0100 Subject: [PATCH 02/32] feat(vectorizer): Simplify and move into worker #2 --- packages/vectorizer/src/commands.ts | 21 ++++++----- packages/vectorizer/src/plugin.ts | 12 +++--- packages/vectorizer/src/types.ts | 3 ++ packages/vectorizer/src/utils.ts | 48 ++++++++++++------------ packages/vectorizer/src/worker.shared.ts | 5 +++ packages/vectorizer/src/worker.ts | 40 ++++++++++++++------ 6 files changed, 78 insertions(+), 51 deletions(-) create mode 100644 packages/vectorizer/src/worker.shared.ts diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts index 6962984..cd45779 100644 --- a/packages/vectorizer/src/commands.ts +++ b/packages/vectorizer/src/commands.ts @@ -7,11 +7,12 @@ import { setPluginMetadata } from './utils'; +import type { MessageBody } from "./worker.shared"; const runInWorker = (uri: string) => new Promise((resolve, reject) => { const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); worker.postMessage({data: uri}) - worker.onmessage = (e: MessageEvent) => { + worker.onmessage = (e: MessageEvent) => { const msg = e.data if (msg.error) { reject (msg.error) @@ -36,8 +37,9 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { cesdk: CreativeEditorSDK, blockId: number ) { + const uploader = cesdk.unstable_upload.bind(cesdk) const engine = cesdk.engine; // the only function that needs the ui is the upload function - const blockApi = cesdk.engine.block; + const blockApi = engine.block; if (!blockApi.hasFill(blockId)) throw new Error('Block has no fill to vectorize'); @@ -74,7 +76,6 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { try { // Clear values in the engine to trigger the loading spinner - +9 blockApi.setString(fillId, 'fill/image/imageFileURI', ''); blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); // ensure we show the last image while processsing. Some images don't have the preview set @@ -95,8 +96,8 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { const vectorized: Blob = await runInWorker(uriToProcess) if ( - getPluginMetadata(cesdk.engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(cesdk, blockId) + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(engine, blockId) ) return; @@ -104,7 +105,7 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { const parts = pathname.split('/'); const filename = parts[parts.length - 1]; - const uploadedAssets = await cesdk.unstable_upload( + const uploadedAssets = await uploader( new File([vectorized], filename, { type: vectorized.type }), () => { // TODO Delegate process to UI component @@ -115,7 +116,7 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { // do not proceed if the state was reset. if ( getPluginMetadata(engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(cesdk, blockId) + !isMetadataConsistent(engine, blockId) ) return; @@ -135,9 +136,9 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { }); blockApi.setString(fillId, 'fill/image/imageFileURI', url); // Finally, create an undo step - cesdk.engine.editor.addUndoStep(); + engine.editor.addUndoStep(); } catch (error) { - if (cesdk.engine.block.isValid(blockId)) { + if (engine.block.isValid(blockId)) { setPluginMetadata(engine, blockId, { version: PLUGIN_VERSION, initialSourceSet, @@ -147,7 +148,7 @@ const runInWorker = (uri: string) => new Promise((resolve, reject) => { status: 'ERROR' }); - recoverInitialImageData(cesdk, blockId); + recoverInitialImageData(engine, blockId); } // eslint-disable-next-line no-console console.error(error); diff --git a/packages/vectorizer/src/plugin.ts b/packages/vectorizer/src/plugin.ts index 21ab4f5..87bc78f 100644 --- a/packages/vectorizer/src/plugin.ts +++ b/packages/vectorizer/src/plugin.ts @@ -13,7 +13,9 @@ import { isMetadataConsistent } from './utils'; -export interface PluginConfiguration { } +export interface PluginConfiguration { + // uploader ? +} export default (pluginConfiguration: PluginConfiguration = {}) => { return { @@ -73,7 +75,7 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { case 'PROCESSING': case 'PROCESSED_TOGGLE_OFF': case 'PROCESSED_TOGGLE_ON': { - if (!isMetadataConsistent(cesdk, blockId)) { + if (!isMetadataConsistent(cesdk.engine, blockId)) { clearPluginMetadata(cesdk.engine, blockId); } break; @@ -94,9 +96,9 @@ export function enableFeatures(cesdk: CreativeEditorSDK) { } const [selectedId] = selectedIds; - if (cesdk.engine.block.hasFill(selectedId)) { - const fillId = cesdk.engine.block.getFill(selectedId); - const fillType = cesdk.engine.block.getType(fillId); + if (engine.block.hasFill(selectedId)) { + const fillId = engine.block.getFill(selectedId); + const fillType = engine.block.getType(fillId); if (fillType !== '//ly.img.ubq/fill/image') { return false; diff --git a/packages/vectorizer/src/types.ts b/packages/vectorizer/src/types.ts index f286dcc..3ab31cb 100644 --- a/packages/vectorizer/src/types.ts +++ b/packages/vectorizer/src/types.ts @@ -50,3 +50,6 @@ export type PluginMetadata = | PluginStatusPending | PluginStatusProcessing | PluginStatusProcessed; + + + diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils.ts index dcfd4b0..e0b33a8 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -104,26 +104,26 @@ export function fixDuplicateMetadata( * @returns true if the metadata is consistent, false otherwise */ export function isMetadataConsistent( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, blockId: number ): boolean { // In case the block was removed, we just abort and mark it // as reset by returning true - if (!cesdk.engine.block.isValid(blockId)) return false; - const metadata = getPluginMetadata(cesdk.engine, blockId); + if (!engine.block.isValid(blockId)) return false; + const metadata = getPluginMetadata(engine, blockId); if (metadata.status === 'IDLE' || metadata.status === 'PENDING') return true; - if (!cesdk.engine.block.hasFill(blockId)) return false; - const fillId = cesdk.engine.block.getFill(blockId); + if (!engine.block.hasFill(blockId)) return false; + const fillId = engine.block.getFill(blockId); if (fillId == null) return false; if (blockId !== metadata.blockId || fillId !== metadata.fillId) return false; - const sourceSet = cesdk.engine.block.getSourceSet( + const sourceSet = engine.block.getSourceSet( fillId, 'fill/image/sourceSet' ); - const imageFileURI = cesdk.engine.block.getString( + const imageFileURI = engine.block.getString( fillId, 'fill/image/imageFileURI' ); @@ -185,15 +185,15 @@ export function isMetadataConsistent( * in the state "PROCESSED_TOGGLE_OFF" or "PROCESSED_TOGGLE_ON". Otherwise do * nothing. */ -export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { - const blockApi = cesdk.engine.block; +export function toggleProcessedData(engine: CreativeEngine, blockId: number) { + const blockApi = engine.block; if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore) const fillId = blockApi.getFill(blockId); - const metadata = getPluginMetadata(cesdk.engine, blockId); + const metadata = getPluginMetadata(engine, blockId); if (metadata.status === 'PROCESSED_TOGGLE_OFF') { - setPluginMetadata(cesdk.engine, blockId, { + setPluginMetadata(engine, blockId, { ...metadata, status: 'PROCESSED_TOGGLE_ON' }); @@ -213,9 +213,9 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { ); } - cesdk.engine.editor.addUndoStep(); + engine.editor.addUndoStep(); } else if (metadata.status === 'PROCESSED_TOGGLE_ON') { - setPluginMetadata(cesdk.engine, blockId, { + setPluginMetadata(engine, blockId, { ...metadata, status: 'PROCESSED_TOGGLE_OFF' }); @@ -230,7 +230,7 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { 'fill/image/sourceSet', metadata.initialSourceSet ); - cesdk.engine.editor.addUndoStep(); + engine.editor.addUndoStep(); } } @@ -239,13 +239,13 @@ export function toggleProcessedData(cesdk: CreativeEditorSDK, blockId: number) { * state as before the process was started. */ export function recoverInitialImageData( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, blockId: number ) { - const blockApi = cesdk.engine.block; + const blockApi = engine.block; if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore) - const metadata = getPluginMetadata(cesdk.engine, blockId); + const metadata = getPluginMetadata(engine, blockId); if (metadata.status === 'PENDING' || metadata.status === 'IDLE') { return; @@ -254,18 +254,18 @@ export function recoverInitialImageData( const initialSourceSet = metadata.initialSourceSet; const initialImageFileURI = metadata.initialImageFileURI; - const fillId = getValidFill(cesdk, blockId, metadata); + const fillId = getValidFill(engine, blockId, metadata); if (fillId == null) return; if (initialImageFileURI) { - cesdk.engine.block.setString( + engine.block.setString( fillId, 'fill/image/imageFileURI', initialImageFileURI ); } if (initialSourceSet.length > 0) { - cesdk.engine.block.setSourceSet( + engine.block.setSourceSet( fillId, 'fill/image/sourceSet', initialSourceSet @@ -278,18 +278,18 @@ export function recoverInitialImageData( * vectorizing. Returns undefined otherwise. */ function getValidFill( - cesdk: CreativeEditorSDK, + engine: CreativeEngine, blockId: number, metadata: PluginStatusProcessing | PluginStatusError | PluginStatusProcessed ): number | undefined { if ( - !cesdk.engine.block.isValid(blockId) || - !cesdk.engine.block.hasFill(blockId) || + !engine.block.isValid(blockId) || + !engine.block.hasFill(blockId) || blockId !== metadata.blockId ) { return undefined; } - const fillId = cesdk.engine.block.getFill(blockId); + const fillId = engine.block.getFill(blockId); if (fillId !== metadata.fillId) { return undefined; } diff --git a/packages/vectorizer/src/worker.shared.ts b/packages/vectorizer/src/worker.shared.ts new file mode 100644 index 0000000..ef2b8e2 --- /dev/null +++ b/packages/vectorizer/src/worker.shared.ts @@ -0,0 +1,5 @@ +export interface MessageBody { + method?: string, + data?: any; + error?: Error +} \ No newline at end of file diff --git a/packages/vectorizer/src/worker.ts b/packages/vectorizer/src/worker.ts index bab111c..1e1a507 100644 --- a/packages/vectorizer/src/worker.ts +++ b/packages/vectorizer/src/worker.ts @@ -1,15 +1,31 @@ import { imageToSvg } from '@imgly/vectorizer'; +import type { MessageBody } from "./worker.shared"; -self.onmessage = function (e) { - const uriToProcess = e.data.data; - fetch(uriToProcess) - .then(res => res.blob()) - .then(blob => imageToSvg(blob)) - .then(blob => blob.arrayBuffer()) - .then(blob => { - postMessage({data: blob}); - }) - .catch(err => { - postMessage({error: err}); - }) + +self.onmessage = function (e: MessageEvent) { + const msg = e.data; + + + const data = msg.data ?? {} + const method = msg.method ?? '' // default to empty string + switch (method) { + case "health": { + postMessage({ data: 'ok' }) + break; + } + case "imageToSvg": + default: { + const uriToProcess = data; + fetch(uriToProcess) + .then(res => res.blob()) + .then(blob => imageToSvg(blob)) + .then(blob => blob.arrayBuffer()) + .then(blob => { + postMessage({ data: blob }); + }) + .catch(err => { + postMessage({ error: err }); + }) + } + } } \ No newline at end of file From cfff8f41482ba060dd2085029ed301ec14ca5173 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Wed, 7 Feb 2024 22:41:16 +0100 Subject: [PATCH 03/32] feat(vectorizer): Simplify and move into worker #3 --- packages/vectorizer/src/actions.ts | 147 +++++++++++++++++++++ packages/vectorizer/src/commands.ts | 156 ----------------------- packages/vectorizer/src/constants.ts | 6 +- packages/vectorizer/src/plugin.ts | 58 ++++----- packages/vectorizer/src/types.ts | 5 +- packages/vectorizer/src/ui.ts | 19 +-- packages/vectorizer/src/utils.ts | 91 ++++--------- packages/vectorizer/src/worker.shared.ts | 19 ++- packages/vectorizer/src/worker.ts | 1 - 9 files changed, 234 insertions(+), 268 deletions(-) create mode 100644 packages/vectorizer/src/actions.ts delete mode 100644 packages/vectorizer/src/commands.ts diff --git a/packages/vectorizer/src/actions.ts b/packages/vectorizer/src/actions.ts new file mode 100644 index 0000000..d4605e8 --- /dev/null +++ b/packages/vectorizer/src/actions.ts @@ -0,0 +1,147 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; + +import { + getPluginMetadata, + isMetadataConsistent, + recoverInitialImageData, + setPluginMetadata +} from './utils'; + +import { PLUGIN_FEATURE_ID } from './constants'; + +import { runInWorker } from './worker.shared'; +/** + * Apply the vectorization process to the image. + */ + +/** + * Triggers the vectiorize process. + */ +export async function vectorizeAction( + cesdk: CreativeEditorSDK, + params: { blockId: number } +) { + const {blockId} = params; + + + const isFeatureEnabled = cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { + engine: cesdk.engine + }) + if (!isFeatureEnabled) return; + const uploader = cesdk.unstable_upload.bind(cesdk) + const engine = cesdk.engine; // the only function that needs the ui is the upload function + const blockApi = engine.block; + if (!blockApi.hasFill(blockId)) + throw new Error('Block has no fill to vectorize'); + + const fillId = blockApi.getFill(blockId); + + // Get the current image URI and source set as initial values. + const initialSourceSet = blockApi.getSourceSet( + fillId, + 'fill/image/sourceSet' + ); + const initialImageFileURI = blockApi.getString( + fillId, + 'fill/image/imageFileURI' + ); + const initialPreviewFileURI = blockApi.getString( + fillId, + 'fill/image/previewFileURI' + ); + + + const uriToProcess = + // Source sets have priority in the engine + initialSourceSet.length > 0 + ? // Choose the highest resolution image in the source set + initialSourceSet.sort( + (a, b) => b.width * b.height - a.height * a.width + )[0].uri + : initialImageFileURI; + + if (uriToProcess === undefined || uriToProcess === '') + return; // We shall return early if the uri is not defined or invalid + + + + try { + // Clear values in the engine to trigger the loading spinner + blockApi.setString(fillId, 'fill/image/imageFileURI', ''); + blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); + // ensure we show the last image while processsing. Some images don't have the preview set + if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { + blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); + } + const metadata = getPluginMetadata(engine, blockId); + setPluginMetadata(engine, blockId, { + ...metadata, + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSING' + }); + + const vectorized: Blob = await runInWorker(uriToProcess) + + if ( + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(engine, blockId) + ) + return; + + const pathname = new URL(uriToProcess).pathname; + const parts = pathname.split('/'); + const filename = parts[parts.length - 1]; + + const uploadedAssets = await uploader( + new File([vectorized], filename, { type: vectorized.type }), + () => { + // TODO Delegate process to UI component + } + ); + + // Check for externally changed state while we were uploading and + // do not proceed if the state was reset. + if ( + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(engine, blockId) + ) + return; + + const url = uploadedAssets.meta?.uri; + if (url == null) { + throw new Error('Could not upload vectorized image'); + } + + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + processedAsset: url + }); + blockApi.setString(fillId, 'fill/image/imageFileURI', url); + // Finally, create an undo step + engine.editor.addUndoStep(); + } catch (error) { + if (engine.block.isValid(blockId)) { + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'ERROR' + }); + + recoverInitialImageData(engine, blockId); + } + // eslint-disable-next-line no-console + console.error(error); + } +} diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts deleted file mode 100644 index cd45779..0000000 --- a/packages/vectorizer/src/commands.ts +++ /dev/null @@ -1,156 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; - -import { - getPluginMetadata, - isMetadataConsistent, - recoverInitialImageData, - setPluginMetadata -} from './utils'; - -import type { MessageBody } from "./worker.shared"; - -const runInWorker = (uri: string) => new Promise((resolve, reject) => { - const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); - worker.postMessage({data: uri}) - worker.onmessage = (e: MessageEvent) => { - const msg = e.data - if (msg.error) { - reject (msg.error) - return; - } - resolve(new Blob([msg.data])) - // when done terminate - worker.terminate() - } - -}) - - - /** - * Apply the vectorization process to the image. - */ - - /** - * Triggers the vectiorize process. - */ - export async function command( - cesdk: CreativeEditorSDK, - blockId: number - ) { - const uploader = cesdk.unstable_upload.bind(cesdk) - const engine = cesdk.engine; // the only function that needs the ui is the upload function - const blockApi = engine.block; - if (!blockApi.hasFill(blockId)) - throw new Error('Block has no fill to vectorize'); - - const fillId = blockApi.getFill(blockId); - - // Get the current image URI and source set as initial values. - const initialSourceSet = blockApi.getSourceSet( - fillId, - 'fill/image/sourceSet' - ); - const initialImageFileURI = blockApi.getString( - fillId, - 'fill/image/imageFileURI' - ); - const initialPreviewFileURI = blockApi.getString( - fillId, - 'fill/image/previewFileURI' - ); - - - const uriToProcess = - // Source sets have priority in the engine - initialSourceSet.length > 0 - ? // Choose the highest resolution image in the source set - initialSourceSet.sort( - (a, b) => b.width * b.height - a.height * a.width - )[0].uri - : initialImageFileURI; - - if (uriToProcess === undefined || uriToProcess === '') - return; // We shall return early if the uri is not defined or invalid - - - - try { - // Clear values in the engine to trigger the loading spinner - blockApi.setString(fillId, 'fill/image/imageFileURI', ''); - blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); - // ensure we show the last image while processsing. Some images don't have the preview set - if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { - blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); - } - const metadata = getPluginMetadata(engine, blockId); - setPluginMetadata(engine, blockId, { - ...metadata, - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSING' - }); - - const vectorized: Blob = await runInWorker(uriToProcess) - - if ( - getPluginMetadata(engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(engine, blockId) - ) - return; - - const pathname = new URL(uriToProcess).pathname; - const parts = pathname.split('/'); - const filename = parts[parts.length - 1]; - - const uploadedAssets = await uploader( - new File([vectorized], filename, { type: vectorized.type }), - () => { - // TODO Delegate process to UI component - } - ); - - // Check for externally changed state while we were uploading and - // do not proceed if the state was reset. - if ( - getPluginMetadata(engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(engine, blockId) - ) - return; - - const url = uploadedAssets.meta?.uri; - if (url == null) { - throw new Error('Could not upload vectorized image'); - } - - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSED_TOGGLE_ON', - processedAsset: url - }); - blockApi.setString(fillId, 'fill/image/imageFileURI', url); - // Finally, create an undo step - engine.editor.addUndoStep(); - } catch (error) { - if (engine.block.isValid(blockId)) { - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'ERROR' - }); - - recoverInitialImageData(engine, blockId); - } - // eslint-disable-next-line no-console - console.error(error); - } - } diff --git a/packages/vectorizer/src/constants.ts b/packages/vectorizer/src/constants.ts index 0f5afca..20a36f9 100644 --- a/packages/vectorizer/src/constants.ts +++ b/packages/vectorizer/src/constants.ts @@ -2,9 +2,9 @@ export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; -export const PLUGIN_I18N_ID = `plugin.${PLUGIN_ID}.vectorize` +export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` export const PLUGIN_I18N_TRANSLATIONS = { - en: { [PLUGIN_I18N_ID]: 'Vectorize' }, - de: { [PLUGIN_I18N_ID]: 'Vektorisieren' } + en: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Vectorize' }, + de: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Vektorisieren' } } export const PLUGIN_ICON = '@imgly/icons/Vectorize' \ No newline at end of file diff --git a/packages/vectorizer/src/plugin.ts b/packages/vectorizer/src/plugin.ts index 87bc78f..2933295 100644 --- a/packages/vectorizer/src/plugin.ts +++ b/packages/vectorizer/src/plugin.ts @@ -1,19 +1,20 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -import { PLUGIN_FEATURE_ID, PLUGIN_ID } from './constants'; +import { PLUGIN_FEATURE_ID, PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './constants'; -import { command } from './commands'; -import { registerComponents } from './ui'; +import { registerUIComponents } from './ui'; import { clearPluginMetadata, fixDuplicateMetadata, getPluginMetadata, isDuplicate, - isMetadataConsistent + isMetadataConsistent, + registerAction } from './utils'; +import { vectorizeAction } from './actions'; -export interface PluginConfiguration { +export interface PluginConfiguration { // uploader ? } @@ -34,11 +35,6 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { }); }); }, - - update() { - - }, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { cesdk.engine.event.subscribe([], async (events) => { events @@ -47,9 +43,23 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { .forEach((e) => { handleUpdateEvent(cesdk, e.block); }); }); - registerComponents(cesdk); + + registerAction( + cesdk.engine, + PLUGIN_ACTION_VECTORIZE_LABEL, + async (params: any) => await vectorizeAction(cesdk, params) + ); + + registerUIComponents(cesdk); + + // this is unclear to me. Should it be with the ui components? enableFeatures(cesdk); - } + }, + + update() { + + }, + }; }; @@ -61,25 +71,14 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { const metadata = getPluginMetadata(cesdk.engine, blockId); switch (metadata.status) { - case 'PENDING': { - if ( - cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { - engine: cesdk.engine - }) - ) { - command(cesdk, blockId); - } - break; - } case 'PROCESSING': - case 'PROCESSED_TOGGLE_OFF': - case 'PROCESSED_TOGGLE_ON': { - if (!isMetadataConsistent(cesdk.engine, blockId)) { - clearPluginMetadata(cesdk.engine, blockId); + case 'PROCESSED':{ + if (!isMetadataConsistent(cesdk.engine, blockId)) { + clearPluginMetadata(cesdk.engine, blockId); + } + break; } - break; - } default: { // We do not care about other states @@ -87,7 +86,7 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { } } - +// semantics are unclear when reading the function export function enableFeatures(cesdk: CreativeEditorSDK) { cesdk.feature.unstable_enable(PLUGIN_FEATURE_ID, ({ engine }) => { const selectedIds = engine.block.findAllSelected(); @@ -110,3 +109,4 @@ export function enableFeatures(cesdk: CreativeEditorSDK) { return false; }); } + diff --git a/packages/vectorizer/src/types.ts b/packages/vectorizer/src/types.ts index 3ab31cb..9ef5ece 100644 --- a/packages/vectorizer/src/types.ts +++ b/packages/vectorizer/src/types.ts @@ -1,7 +1,7 @@ import { type Source } from '@cesdk/cesdk-js'; export type PluginStatusIdle = { status: 'IDLE' }; -export type PluginStatusPending = { status: 'PENDING' }; +// export type PluginStatusPending = { status: 'PENDING' }; export type PluginStatusProcessing = { version: string; @@ -22,7 +22,7 @@ export type PluginStatusProcessing = { export type PluginStatusProcessed = { version: string; - status: 'PROCESSED_TOGGLE_ON' | 'PROCESSED_TOGGLE_OFF'; + status: 'PROCESSED' initialImageFileURI: string; initialSourceSet: Source[]; @@ -47,7 +47,6 @@ export type PluginStatusError = { export type PluginMetadata = | PluginStatusIdle | PluginStatusError - | PluginStatusPending | PluginStatusProcessing | PluginStatusProcessed; diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 3c4ddf3..6c40e1a 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -4,20 +4,19 @@ import { PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, PLUGIN_CANVAS_MENU_COMPONENT_ID, PLUGIN_FEATURE_ID, - PLUGIN_I18N_ID, + PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_I18N_TRANSLATIONS, PLUGIN_ICON } from './constants'; import { + executeAction, getPluginMetadata, - setPluginMetadata, - toggleProcessedData } from './utils'; /** * Registers the components that can be used to vectorize a block. */ -export function registerComponents(cesdk: CreativeEditorSDK) { +export function registerUIComponents(cesdk: CreativeEditorSDK) { cesdk.setTranslations(PLUGIN_I18N_TRANSLATIONS); // Always prepend the registered component to the canvas menu order. cesdk.ui.unstable_setCanvasMenuOrder([ @@ -52,8 +51,8 @@ export function registerComponents(cesdk: CreativeEditorSDK) { const isActive = false // metadata.status === 'PROCESSED_TOGGLE_ON'; const isLoading = metadata.status === 'PROCESSING'; - const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; - const isDisabled = hasNoValidFill || isPendingOrProcessing + // const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; + const isDisabled = hasNoValidFill || isLoading let loadingProgress: number | undefined; if (isLoading && metadata.progress) { @@ -62,17 +61,13 @@ export function registerComponents(cesdk: CreativeEditorSDK) { } Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { - label: PLUGIN_I18N_ID, + label: PLUGIN_ACTION_VECTORIZE_LABEL, icon: PLUGIN_ICON, isActive, isLoading, isDisabled, loadingProgress, - onClick: () => { - setPluginMetadata(cesdk.engine, id, { - status: 'PENDING' - }); - } + onClick: () => executeAction(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id }) }); } ); diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils.ts index e0b33a8..bbe9970 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -58,7 +58,7 @@ export function isDuplicate( if (!engine.block.isValid(blockId)) return false; if ( metadata.status === 'IDLE' || - metadata.status === 'PENDING' || + // metadata.status === 'PENDING' || metadata.status === 'ERROR' ) return false; @@ -86,7 +86,7 @@ export function fixDuplicateMetadata( const metadata = getPluginMetadata(engine, blockId); if ( metadata.status === 'IDLE' || - metadata.status === 'PENDING' || + // metadata.status === 'PENDING' || metadata.status === 'ERROR' ) return; @@ -111,7 +111,9 @@ export function isMetadataConsistent( // as reset by returning true if (!engine.block.isValid(blockId)) return false; const metadata = getPluginMetadata(engine, blockId); - if (metadata.status === 'IDLE' || metadata.status === 'PENDING') return true; + if (metadata.status === 'IDLE' + // || metadata.status === 'PENDING' + ) return true; if (!engine.block.hasFill(blockId)) return false; const fillId = engine.block.getFill(blockId); @@ -145,8 +147,7 @@ export function isMetadataConsistent( // If we have already processed the image, we need to check if the source set // we need to check against both source sets, the removed and the initial if ( - metadata.status === 'PROCESSED_TOGGLE_OFF' || - metadata.status === 'PROCESSED_TOGGLE_ON' + metadata.status === 'PROCESSED' ) { const processedAsset = metadata.processedAsset; if ( @@ -161,10 +162,7 @@ export function isMetadataConsistent( } } } else { - if ( - metadata.status === 'PROCESSED_TOGGLE_OFF' || - metadata.status === 'PROCESSED_TOGGLE_ON' - ) { + if (metadata.status === 'PROCESSED') { if ( imageFileURI !== metadata.initialImageFileURI && imageFileURI !== metadata.processedAsset @@ -180,59 +178,6 @@ export function isMetadataConsistent( return true; } -/** - * Toggle between the vectorized image and the original image if either - * in the state "PROCESSED_TOGGLE_OFF" or "PROCESSED_TOGGLE_ON". Otherwise do - * nothing. - */ -export function toggleProcessedData(engine: CreativeEngine, blockId: number) { - const blockApi = engine.block; - if (!blockApi.hasFill(blockId)) return; // Nothing to recover (no fill anymore) - const fillId = blockApi.getFill(blockId); - - const metadata = getPluginMetadata(engine, blockId); - - if (metadata.status === 'PROCESSED_TOGGLE_OFF') { - setPluginMetadata(engine, blockId, { - ...metadata, - status: 'PROCESSED_TOGGLE_ON' - }); - - if (typeof metadata.processedAsset === 'string') { - blockApi.setString( - fillId, - 'fill/image/imageFileURI', - metadata.processedAsset - ); - blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); - } else { - blockApi.setSourceSet( - fillId, - 'fill/image/sourceSet', - metadata.processedAsset - ); - } - - engine.editor.addUndoStep(); - } else if (metadata.status === 'PROCESSED_TOGGLE_ON') { - setPluginMetadata(engine, blockId, { - ...metadata, - status: 'PROCESSED_TOGGLE_OFF' - }); - - blockApi.setString( - fillId, - 'fill/image/imageFileURI', - metadata.initialImageFileURI - ); - blockApi.setSourceSet( - fillId, - 'fill/image/sourceSet', - metadata.initialSourceSet - ); - engine.editor.addUndoStep(); - } -} /** * Recover the initial values to avoid the loading spinner and have the same @@ -247,7 +192,9 @@ export function recoverInitialImageData( const metadata = getPluginMetadata(engine, blockId); - if (metadata.status === 'PENDING' || metadata.status === 'IDLE') { + if ( + // metadata.status === 'PENDING' || + metadata.status === 'IDLE') { return; } @@ -299,6 +246,7 @@ function getValidFill( +// These don't belong here export class Scheduler { #queue?: Promise = undefined @@ -313,4 +261,21 @@ export class Scheduler { } return this.#queue } +} + + + + +type ActionType = (params: any) => Promise; +const actions: Map = new Map(); + +export function registerAction(engine: CreativeEngine, label: string, callback: (params: any) => Promise) { + actions.set(label, callback); +} + +export async function executeAction(label: string, params: any) { + const action = actions.get(label); + if (action) { + await action(params); + } } \ No newline at end of file diff --git a/packages/vectorizer/src/worker.shared.ts b/packages/vectorizer/src/worker.shared.ts index ef2b8e2..a202083 100644 --- a/packages/vectorizer/src/worker.shared.ts +++ b/packages/vectorizer/src/worker.shared.ts @@ -2,4 +2,21 @@ export interface MessageBody { method?: string, data?: any; error?: Error -} \ No newline at end of file +} + + +export const runInWorker = (uri: string) => new Promise((resolve, reject) => { + const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); + worker.postMessage({ data: uri }) + worker.onmessage = (e: MessageEvent) => { + const msg = e.data + if (msg.error) { + reject(msg.error) + return; + } + resolve(new Blob([msg.data])) + // when done terminate + worker.terminate() + } + +}) diff --git a/packages/vectorizer/src/worker.ts b/packages/vectorizer/src/worker.ts index 1e1a507..3b32bc4 100644 --- a/packages/vectorizer/src/worker.ts +++ b/packages/vectorizer/src/worker.ts @@ -19,7 +19,6 @@ self.onmessage = function (e: MessageEvent) { fetch(uriToProcess) .then(res => res.blob()) .then(blob => imageToSvg(blob)) - .then(blob => blob.arrayBuffer()) .then(blob => { postMessage({ data: blob }); }) From af309e9418f9abe9a8d9fce3d8faf1e3876547d6 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Thu, 8 Feb 2024 16:59:14 +0100 Subject: [PATCH 04/32] feat(vectorizer): Added support for multiselection --- packages/vectorizer/src/actions.ts | 31 +++++--- packages/vectorizer/src/index.ts | 2 +- .../src/{constants.ts => manifest.ts} | 0 packages/vectorizer/src/plugin.ts | 35 ++++------ packages/vectorizer/src/ui.ts | 70 +++++++++++-------- packages/vectorizer/src/utils.ts | 27 ++++++- 6 files changed, 99 insertions(+), 66 deletions(-) rename packages/vectorizer/src/{constants.ts => manifest.ts} (100%) diff --git a/packages/vectorizer/src/actions.ts b/packages/vectorizer/src/actions.ts index d4605e8..34e3e65 100644 --- a/packages/vectorizer/src/actions.ts +++ b/packages/vectorizer/src/actions.ts @@ -2,13 +2,12 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; import { getPluginMetadata, + isBlockSupported, isMetadataConsistent, recoverInitialImageData, setPluginMetadata } from './utils'; -import { PLUGIN_FEATURE_ID } from './constants'; - import { runInWorker } from './worker.shared'; /** * Apply the vectorization process to the image. @@ -19,18 +18,26 @@ import { runInWorker } from './worker.shared'; */ export async function vectorizeAction( cesdk: CreativeEditorSDK, - params: { blockId: number } + params: { blockId: number } ) { - const {blockId} = params; - - - const isFeatureEnabled = cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { - engine: cesdk.engine - }) - if (!isFeatureEnabled) return; const uploader = cesdk.unstable_upload.bind(cesdk) const engine = cesdk.engine; // the only function that needs the ui is the upload function const blockApi = engine.block; + + let { blockId } = params?? {}; + if (blockId === undefined) { + const selected = engine.block.findAllSelected() + if (selected.length !== 1) { + return; + } + blockId = selected[0]; + } + const isValid = engine.block.isValid(blockId) + if (!isValid) return + + if (!isBlockSupported(engine, blockId)) return; + + if (!blockApi.hasFill(blockId)) throw new Error('Block has no fill to vectorize'); @@ -111,7 +118,7 @@ export async function vectorizeAction( ) return; - const url = uploadedAssets.meta?.uri; + const url = uploadedAssets.meta?.uri;; if (url == null) { throw new Error('Could not upload vectorized image'); } @@ -125,9 +132,11 @@ export async function vectorizeAction( status: 'PROCESSED', processedAsset: url }); + blockApi.setString(fillId, 'fill/image/imageFileURI', url); // Finally, create an undo step engine.editor.addUndoStep(); + } catch (error) { if (engine.block.isValid(blockId)) { setPluginMetadata(engine, blockId, { diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index a24e34c..973be5e 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -1,6 +1,6 @@ import plugin, { type PluginConfiguration } from './plugin'; -import { PLUGIN_ID } from './constants'; +import { PLUGIN_ID } from './manifest'; const Plugin = (pluginConfiguration?: PluginConfiguration) => ({ name: PLUGIN_ID, diff --git a/packages/vectorizer/src/constants.ts b/packages/vectorizer/src/manifest.ts similarity index 100% rename from packages/vectorizer/src/constants.ts rename to packages/vectorizer/src/manifest.ts diff --git a/packages/vectorizer/src/plugin.ts b/packages/vectorizer/src/plugin.ts index 2933295..c7ea60e 100644 --- a/packages/vectorizer/src/plugin.ts +++ b/packages/vectorizer/src/plugin.ts @@ -1,6 +1,6 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -import { PLUGIN_FEATURE_ID, PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './constants'; +import { PLUGIN_FEATURE_ID, PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest'; import { registerUIComponents } from './ui'; @@ -8,6 +8,7 @@ import { clearPluginMetadata, fixDuplicateMetadata, getPluginMetadata, + isBlockSupported, isDuplicate, isMetadataConsistent, registerAction @@ -73,12 +74,12 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { switch (metadata.status) { case 'PROCESSING': - case 'PROCESSED':{ - if (!isMetadataConsistent(cesdk.engine, blockId)) { - clearPluginMetadata(cesdk.engine, blockId); - } - break; + case 'PROCESSED': { + if (!isMetadataConsistent(cesdk.engine, blockId)) { + clearPluginMetadata(cesdk.engine, blockId); } + break; + } default: { // We do not care about other states @@ -90,23 +91,13 @@ async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { export function enableFeatures(cesdk: CreativeEditorSDK) { cesdk.feature.unstable_enable(PLUGIN_FEATURE_ID, ({ engine }) => { const selectedIds = engine.block.findAllSelected(); - if (selectedIds.length !== 1) { - return false; - } - const [selectedId] = selectedIds; - - if (engine.block.hasFill(selectedId)) { - const fillId = engine.block.getFill(selectedId); - const fillType = engine.block.getType(fillId); - - if (fillType !== '//ly.img.ubq/fill/image') { - return false; - } - return true - - } + if (selectedIds.length === 0) return false; - return false; + // multiselection case + const allBlocksSupportPlugin = selectedIds + .map((id) => isBlockSupported(engine, id)) + .reduce((val, acc) => val && acc, true); + return allBlocksSupportPlugin }); } diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 6c40e1a..2d6a672 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -7,7 +7,7 @@ import { PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_I18N_TRANSLATIONS, PLUGIN_ICON -} from './constants'; +} from './manifest'; import { executeAction, getPluginMetadata, @@ -26,48 +26,58 @@ export function registerUIComponents(cesdk: CreativeEditorSDK) { cesdk.ui.unstable_registerComponent( PLUGIN_CANVAS_MENU_COMPONENT_ID, ({ builder: { Button }, engine }) => { - if ( - !cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { - engine - }) - ) { - return; - } - - const [id] = engine.block.findAllSelected(); - if (!cesdk.engine.block.hasFill(id)) return; + + // @DanielHauschildt This should better have [blockIds] as a parameter + if (!cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { engine })) { return; } - const fillId = cesdk.engine.block.getFill(id); - const fileUri = engine.block.getString(fillId, 'fill/image/imageFileURI'); - const sourceSet = engine.block.getSourceSet( - fillId, - 'fill/image/sourceSet' - ); + const selected = engine.block.findAllSelected(); - const hasNoValidFill = !(sourceSet.length > 0 || fileUri !== '') + const actions: Array<() => void> = [] - const metadata = getPluginMetadata(cesdk.engine, id); + let anyIsLoading = false + let anyHasValidFill = false + let allCurrentProgress = 0 + let allTotalProgress = 0 + for (const id of selected) { + if (!cesdk.engine.block.hasFill(id)) return; + const fillId = cesdk.engine.block.getFill(id); + const fileUri = engine.block.getString(fillId, 'fill/image/imageFileURI'); + const sourceSet = engine.block.getSourceSet( + fillId, + 'fill/image/sourceSet' + ); - const isActive = false // metadata.status === 'PROCESSED_TOGGLE_ON'; - const isLoading = metadata.status === 'PROCESSING'; + const metadata = getPluginMetadata(cesdk.engine, id); - // const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; - const isDisabled = hasNoValidFill || isLoading - let loadingProgress: number | undefined; - if (isLoading && metadata.progress) { - const { current, total } = metadata.progress; - loadingProgress = (current / total) * 100; + const isLoading = metadata.status === 'PROCESSING'; + anyIsLoading ||= isLoading; + if (isLoading && metadata.progress) { + const { current, total } = metadata.progress; + allTotalProgress += total + allCurrentProgress += current + } + const hasValidFill = (sourceSet.length > 0 || fileUri !== '')// const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; + anyHasValidFill ||= hasValidFill; + actions.push(() => executeAction(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) + } + const isDisabled = anyIsLoading || !anyHasValidFill; + + const loadingProgress = 0 // (allCurrentProgress / allTotalProgress) * 100; + console.log('actions', actions) + console.log('anyIsLoading', anyIsLoading) + console.log('isDisabled', isDisabled) + Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { label: PLUGIN_ACTION_VECTORIZE_LABEL, icon: PLUGIN_ICON, - isActive, - isLoading, + isActive: false, + isLoading: anyIsLoading, isDisabled, loadingProgress, - onClick: () => executeAction(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id }) + onClick: () => actions.map(action => action()) }); } ); diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils.ts index bbe9970..278d74c 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -1,7 +1,7 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import isEqual from 'lodash/isEqual'; -import { PLUGIN_ID } from './constants'; +import { PLUGIN_ID } from './manifest'; import { PluginMetadata, PluginStatusError, @@ -9,6 +9,26 @@ import { PluginStatusProcessing } from './types'; + +/** + * Checks if a block is supported by the given CreativeEngine. + * @param engine - The CreativeEngine instance. + * @param blockId - The ID of the block to check. + * @returns A boolean indicating whether the block is supported or not. + */ +export const isBlockSupported = (engine: CreativeEngine, blockId: number) => { + if (engine.block.hasFill(blockId)) { + const fillId = engine.block.getFill(blockId); + const fillType = engine.block.getType(fillId); + if (fillType !== '//ly.img.ubq/fill/image') { + return false; + } + return true + } + + return false; +} + /** * Sets the metadata for the plugin state. */ @@ -270,6 +290,7 @@ type ActionType = (params: any) => Promise; const actions: Map = new Map(); export function registerAction(engine: CreativeEngine, label: string, callback: (params: any) => Promise) { + engine actions.set(label, callback); } @@ -278,4 +299,6 @@ export async function executeAction(label: string, params: any) { if (action) { await action(params); } -} \ No newline at end of file +} +// @ts-ignore +globalThis.cesdk_actions = actions; // for debugging \ No newline at end of file From cf00db38eb01172db1c1e69ace8a5e540fbfe9fd Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 9 Feb 2024 20:27:23 +0100 Subject: [PATCH 05/32] chore: Build working --- examples/web/package.json | 7 +- examples/web/src/App.tsx | 46 +- examples/web/vite.config.ts | 11 + examples/web/vite/logger.js | 14 + package.json | 4 +- .../background-removal/esbuild/config.mjs | 10 +- packages/vectorizer/esbuild/config.mjs | 7 +- packages/vectorizer/package.json | 15 +- packages/vectorizer/src/actions.ts | 103 ++- packages/vectorizer/src/cesdk+utils.ts | 37 + packages/vectorizer/src/manifest.ts | 3 +- packages/vectorizer/src/types.ts | 2 - packages/vectorizer/src/ui.ts | 10 +- packages/vectorizer/src/utils.ts | 8 +- packages/vectorizer/src/worker.shared.ts | 3 +- packages/vectorizer/src/worker.ts | 31 +- packages/vectorizer/tsconfig.json | 2 +- packages/vectorizer/types/actions.d.ts | 10 + packages/vectorizer/types/cesdk+utils.d.ts | 3 + packages/vectorizer/types/index.d.ts | 11 + packages/vectorizer/types/manifest.d.ts | 11 + packages/vectorizer/types/plugin.d.ts | 12 + packages/vectorizer/types/types.d.ts | 34 + packages/vectorizer/types/ui.d.ts | 5 + packages/vectorizer/types/utils.d.ts | 52 ++ packages/vectorizer/types/worker.d.ts | 1 + packages/vectorizer/types/worker.shared.d.ts | 6 + turbo.json | 2 +- yarn.lock | 643 +++++++++++++++++- 29 files changed, 987 insertions(+), 116 deletions(-) create mode 100644 examples/web/vite/logger.js create mode 100644 packages/vectorizer/src/cesdk+utils.ts create mode 100644 packages/vectorizer/types/actions.d.ts create mode 100644 packages/vectorizer/types/cesdk+utils.d.ts create mode 100644 packages/vectorizer/types/index.d.ts create mode 100644 packages/vectorizer/types/manifest.d.ts create mode 100644 packages/vectorizer/types/plugin.d.ts create mode 100644 packages/vectorizer/types/types.d.ts create mode 100644 packages/vectorizer/types/ui.d.ts create mode 100644 packages/vectorizer/types/utils.d.ts create mode 100644 packages/vectorizer/types/worker.d.ts create mode 100644 packages/vectorizer/types/worker.shared.d.ts diff --git a/examples/web/package.json b/examples/web/package.json index 5e38457..296a8a5 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -5,10 +5,13 @@ "type": "module", "scripts": { "dev": "vite --clearScreen=false", - "build": "tsc && vite build" + "build": "tsc && vite build", + "preview": "vite preview" }, "dependencies": { "@cesdk/cesdk-js": "^1.20.0", + "@imgly/plugin-background-removal-web": "*", + "@imgly/plugin-vectorizer-web": "*", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -22,6 +25,6 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", "typescript": "^5.2.2", - "vite": "^5.0.8" + "vite": "^5.1.1" } } diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 5505297..483a4ea 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -1,32 +1,44 @@ import { useRef } from "react"; -import CreativeEditorSDK from "@cesdk/cesdk-js"; +import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; import addPlugins from "./addPlugins"; function App() { const cesdk = useRef(); + const config: Configuration = { + license: import.meta.env.VITE_CESDK_LICENSE_KEY, + callbacks: { onUpload: "local" }, + // devMode: true, + theme: "dark", + role: 'Creator', + ui:{ + elements: { + view: "default" + } + } + } + return (
{ if (domElement != null) { - CreativeEditorSDK.create(domElement, { - license: import.meta.env.VITE_CESDK_LICENSE_KEY, - callbacks: { onUpload: "local" }, - }).then(async (instance) => { - // @ts-ignore - window.cesdk = instance; - cesdk.current = instance; + CreativeEditorSDK + .create(domElement, config) + .then(async (instance) => { + // @ts-ignore + window.cesdk = instance; + cesdk.current = instance; - // Do something with the instance of CreativeEditor SDK, for example: - // Populate the asset library with default / demo asset sources. - await Promise.all([ - instance.addDefaultAssetSources(), - instance.addDemoAssetSources({ sceneMode: "Design" }), - addPlugins(instance), - ]); - await instance.createDesignScene(); - }); + // Do something with the instance of CreativeEditor SDK, for example: + // Populate the asset library with default / demo asset sources. + await Promise.all([ + instance.addDefaultAssetSources(), + instance.addDemoAssetSources({ sceneMode: "Design" }), + addPlugins(instance), + ]); + await instance.createDesignScene(); + }); } else if (cesdk.current != null) { cesdk.current.dispose(); } diff --git a/examples/web/vite.config.ts b/examples/web/vite.config.ts index 7fd700f..fd1f8a2 100644 --- a/examples/web/vite.config.ts +++ b/examples/web/vite.config.ts @@ -1,13 +1,24 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; +import { createLogger } from "./vite/logger"; + + // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], + build: { + chunkSizeWarningLimit: 4096 + }, + worker: { + format: "es" // Default was "iife" but then import.meta.url for importing worker does not worker + }, server: { headers: { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp", }, }, + customLogger: createLogger() }); + diff --git a/examples/web/vite/logger.js b/examples/web/vite/logger.js new file mode 100644 index 0000000..7eda5a3 --- /dev/null +++ b/examples/web/vite/logger.js @@ -0,0 +1,14 @@ +import { createLogger as createViteLogger } from "vite"; + + +export const createLogger = () => { + // We create a custom logger in order to filter messages that are persistent + const logger = createViteLogger(); + const originalWarning = logger.warn; + + logger.warn = (msg, options) => { + if (msg.includes('[plugin:vite:resolve]')) return; + originalWarning(msg, options); + }; + return logger; +} \ No newline at end of file diff --git a/package.json b/package.json index af70b89..859014b 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "name": "imgly-plugins", "version": "0.0.0", "workspaces": [ - "packages/*", - "examples/*" + "examples/*", + "packages/*" ], "scripts": { "build": "turbo run build --force", diff --git a/packages/background-removal/esbuild/config.mjs b/packages/background-removal/esbuild/config.mjs index 43cf4fa..cfc780d 100644 --- a/packages/background-removal/esbuild/config.mjs +++ b/packages/background-removal/esbuild/config.mjs @@ -7,6 +7,12 @@ const packageJson = JSON.parse( await readFile(new URL('../package.json', import.meta.url)) ); +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) + +const externals = [...dependencies, ...peerDependencies] + + console.log( chalk.yellow('Building version: '), chalk.green(packageJson.version) @@ -21,8 +27,8 @@ const configs = [ minify: true, bundle: true, sourcemap: true, - external: ['@imgly/background-removal', '@cesdk/cesdk-js', 'lodash'], - platform: 'browser', + external: externals, + platform: 'node', format: 'esm', outfile: 'dist/index.mjs', plugins: [ diff --git a/packages/vectorizer/esbuild/config.mjs b/packages/vectorizer/esbuild/config.mjs index 6f1d7ed..37b437c 100644 --- a/packages/vectorizer/esbuild/config.mjs +++ b/packages/vectorizer/esbuild/config.mjs @@ -7,6 +7,11 @@ const packageJson = JSON.parse( await readFile(new URL('../package.json', import.meta.url)) ); + +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) +const externals = [...dependencies, ...peerDependencies] + console.log( chalk.yellow('Building version: '), chalk.green(packageJson.version) @@ -21,7 +26,7 @@ const configs = [ minify: true, bundle: true, sourcemap: true, - external: ['@cesdk/cesdk-js'], + external: externals, platform: 'node', format: 'esm', outdir: 'dist', diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 766e52e..61644be 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -23,11 +23,11 @@ }, "source": "./src/index.ts", "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", + "types": "./types/index.d.ts", "exports": { ".": { "import": "./dist/index.mjs", - "types": "./dist/index.d.ts" + "types": "./types/index.d.ts" } }, "homepage": "https://img.ly/products/creative-sdk", @@ -36,15 +36,16 @@ "README.md", "CHANGELOG.md", "dist/", + "types/", "bin/" ], "scripts": { "start": "npm run watch", - "clean": "npx rimraf dist", - "build": "npm run clean && node scripts/build.mjs && yarn run types:create", - "dev": "npm run clean && node scripts/watch.mjs", - "publish:latest": "npm run build && npm publish --tag latest --access public", - "publish:next": "npm run build && npm publish --tag next --access public", + "clean": "npx rimraf dist && npx rimraf types", + "build": "node scripts/build.mjs && yarn run types:create", + "dev": "node scripts/watch.mjs", + "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", + "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", diff --git a/packages/vectorizer/src/actions.ts b/packages/vectorizer/src/actions.ts index 34e3e65..3864e47 100644 --- a/packages/vectorizer/src/actions.ts +++ b/packages/vectorizer/src/actions.ts @@ -9,6 +9,7 @@ import { } from './utils'; import { runInWorker } from './worker.shared'; +import { createVectorPathBlocks } from './cesdk+utils'; /** * Apply the vectorization process to the image. */ @@ -18,13 +19,13 @@ import { runInWorker } from './worker.shared'; */ export async function vectorizeAction( cesdk: CreativeEditorSDK, - params: { blockId: number } + params: { blockId: number } ) { const uploader = cesdk.unstable_upload.bind(cesdk) const engine = cesdk.engine; // the only function that needs the ui is the upload function const blockApi = engine.block; - let { blockId } = params?? {}; + let { blockId } = params ?? {}; if (blockId === undefined) { const selected = engine.block.findAllSelected() if (selected.length !== 1) { @@ -99,41 +100,79 @@ export async function vectorizeAction( ) return; - const pathname = new URL(uriToProcess).pathname; - const parts = pathname.split('/'); - const filename = parts[parts.length - 1]; - const uploadedAssets = await uploader( - new File([vectorized], filename, { type: vectorized.type }), - () => { - // TODO Delegate process to UI component + if (vectorized.type.length === 0 || vectorized.type === 'image/svg+xml') { + const pathname = new URL(uriToProcess).pathname; + const parts = pathname.split('/'); + const filename = parts[parts.length - 1]; + + const uploadedAssets = await uploader( + new File([vectorized], filename, { type: vectorized.type }), + () => { + // TODO Delegate process to UI component + } + ); + + // Check for externally changed state while we were uploading and + // do not proceed if the state was reset. + if ( + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(engine, blockId) + ) + return; + + const url = uploadedAssets.meta?.uri;; + if (url == null) { + throw new Error('Could not upload vectorized image'); } - ); - // Check for externally changed state while we were uploading and - // do not proceed if the state was reset. - if ( - getPluginMetadata(engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(engine, blockId) - ) - return; + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + // processedAsset: url + }); - const url = uploadedAssets.meta?.uri;; - if (url == null) { - throw new Error('Could not upload vectorized image'); - } + blockApi.setString(fillId, 'fill/image/imageFileURI', url); + } else if (vectorized.type === 'application/json') { + const json = await vectorized.text() + const blocks = JSON.parse(json) + const groupId = createVectorPathBlocks(engine, blocks) + const parentId = engine.block.getParent(blockId)! + engine.block.appendChild(parentId, groupId); + + + const origWidth = engine.block.getFrameWidth(blockId) + const origHeight = engine.block.getFrameHeight(blockId) + const origRotation = engine.block.getRotation(blockId) + const origX = engine.block.getPositionX(blockId) + const origY = engine.block.getPositionY(blockId) + const groupWidth = engine.block.getFrameWidth(groupId) + const groupHeight = engine.block.getFrameHeight(groupId) + engine.block.setPositionX(groupId, origX) + engine.block.setPositionY(groupId, origY) + engine.block.setRotation(groupId, origRotation) + engine.block.scale(groupId, origWidth / groupWidth) + //remove original block + engine.block.destroy(blockId) + + // must be assigned to a scene to work... why? + + + blockApi.setString(fillId, 'fill/image/imageFileURI', initialImageFileURI); - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSED', - processedAsset: url - }); - - blockApi.setString(fillId, 'fill/image/imageFileURI', url); + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + }); + } // Finally, create an undo step engine.editor.addUndoStep(); diff --git a/packages/vectorizer/src/cesdk+utils.ts b/packages/vectorizer/src/cesdk+utils.ts new file mode 100644 index 0000000..61945cb --- /dev/null +++ b/packages/vectorizer/src/cesdk+utils.ts @@ -0,0 +1,37 @@ +import { CreativeEngine } from "@cesdk/cesdk-js"; + +export const createVectorPathBlocks = (engine: CreativeEngine, blocks: any[]) => { + const blockIds = blocks.map((block: any) => { + const id = createVectorPathBlock( + engine, block + ) + + return id + }) + + return engine.block.group(blockIds); +} + + +export const createVectorPathBlock = (engine: CreativeEngine, block: any) => { + + const path = block.shape.path + const color = block.fill.color + const blockId = engine.block.create("//ly.img.ubq/graphic"); + engine.block.setKind(blockId, "shape"); + const shape = engine.block.createShape("//ly.img.ubq/shape/vector_path"); + engine.block.setShape(blockId, shape); + + engine.block.setString(shape, "vector_path/path", path); + engine.block.setFloat(shape, "vector_path/width", block.transform.width); + engine.block.setFloat(shape, "vector_path/height", block.transform.height); + + const fill = engine.block.createFill("color"); + engine.block.setColor(fill, "fill/color/value", { r: color[0], g: color[1], b: color[2], a: color[3] }); + engine.block.setFill(blockId, fill); + engine.block.setFloat(blockId, "width", block.transform.width); + engine.block.setFloat(blockId, "height", block.transform.height); + engine.block.setPositionX(blockId, block.transform.x) + engine.block.setPositionY(blockId, block.transform.y) + return blockId; +} diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index 20a36f9..fc13d0d 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -4,7 +4,6 @@ export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMP export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` export const PLUGIN_I18N_TRANSLATIONS = { - en: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Vectorize' }, - de: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Vektorisieren' } + en: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vector' } } export const PLUGIN_ICON = '@imgly/icons/Vectorize' \ No newline at end of file diff --git a/packages/vectorizer/src/types.ts b/packages/vectorizer/src/types.ts index 9ef5ece..8f09444 100644 --- a/packages/vectorizer/src/types.ts +++ b/packages/vectorizer/src/types.ts @@ -29,8 +29,6 @@ export type PluginStatusProcessed = { blockId: number; fillId: number; - - processedAsset: string | Source[]; }; export type PluginStatusError = { diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 2d6a672..fabf579 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -26,7 +26,7 @@ export function registerUIComponents(cesdk: CreativeEditorSDK) { cesdk.ui.unstable_registerComponent( PLUGIN_CANVAS_MENU_COMPONENT_ID, ({ builder: { Button }, engine }) => { - + // @DanielHauschildt This should better have [blockIds] as a parameter if (!cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { engine })) { return; } @@ -60,15 +60,13 @@ export function registerUIComponents(cesdk: CreativeEditorSDK) { const hasValidFill = (sourceSet.length > 0 || fileUri !== '')// const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; anyHasValidFill ||= hasValidFill; actions.push(() => executeAction(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) - + } const isDisabled = anyIsLoading || !anyHasValidFill; - const loadingProgress = 0 // (allCurrentProgress / allTotalProgress) * 100; - console.log('actions', actions) - console.log('anyIsLoading', anyIsLoading) - console.log('isDisabled', isDisabled) + const loadingProgress = 0;// (allCurrentProgress / allTotalProgress) * 100; + // console.log((allCurrentProgress / allTotalProgress) * 100) Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { label: PLUGIN_ACTION_VECTORIZE_LABEL, diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils.ts index 278d74c..2fe9940 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -169,9 +169,9 @@ export function isMetadataConsistent( if ( metadata.status === 'PROCESSED' ) { - const processedAsset = metadata.processedAsset; + // const processedAsset = metadata.processedAsset; if ( - !isEqual(sourceSet, processedAsset) && + // !isEqual(sourceSet, processedAsset) && !isEqual(sourceSet, initialSourceSet) ) { return false; @@ -184,8 +184,8 @@ export function isMetadataConsistent( } else { if (metadata.status === 'PROCESSED') { if ( - imageFileURI !== metadata.initialImageFileURI && - imageFileURI !== metadata.processedAsset + imageFileURI !== metadata.initialImageFileURI + // &&imageFileURI !== metadata.processedAsset ) { return false; } diff --git a/packages/vectorizer/src/worker.shared.ts b/packages/vectorizer/src/worker.shared.ts index a202083..cb59d09 100644 --- a/packages/vectorizer/src/worker.shared.ts +++ b/packages/vectorizer/src/worker.shared.ts @@ -3,6 +3,7 @@ export interface MessageBody { data?: any; error?: Error } +// export const runInWorker = (uri: string) => new Promise((resolve, reject) => { @@ -14,7 +15,7 @@ export const runInWorker = (uri: string) => new Promise((resolve, reject) reject(msg.error) return; } - resolve(new Blob([msg.data])) + resolve(msg.data) // when done terminate worker.terminate() } diff --git a/packages/vectorizer/src/worker.ts b/packages/vectorizer/src/worker.ts index 3b32bc4..c1f8a05 100644 --- a/packages/vectorizer/src/worker.ts +++ b/packages/vectorizer/src/worker.ts @@ -1,12 +1,10 @@ -import { imageToSvg } from '@imgly/vectorizer'; -import type { MessageBody } from "./worker.shared"; - - -self.onmessage = function (e: MessageEvent) { - const msg = e.data; +import type { MessageBody } from "./worker.shared"; +import * as vectorizer from '@imgly/vectorizer'; - const data = msg.data ?? {} +self.onmessage = async function (e: MessageEvent) { + const msg = e.data;0 + const data = msg.data ?? {} const method = msg.method ?? '' // default to empty string switch (method) { case "health": { @@ -16,15 +14,16 @@ self.onmessage = function (e: MessageEvent) { case "imageToSvg": default: { const uriToProcess = data; - fetch(uriToProcess) - .then(res => res.blob()) - .then(blob => imageToSvg(blob)) - .then(blob => { - postMessage({ data: blob }); - }) - .catch(err => { - postMessage({ error: err }); - }) + try { + const res = await fetch(uriToProcess) + const blob = await res.blob() + // const svg = await vectorizer.imageToSvg(blob) + // postMessage({ data: svg }); + const json = await vectorizer.imageToJson(blob) + postMessage({ data: json }); + } catch (err) { + postMessage({ error: err }); + } } } } \ No newline at end of file diff --git a/packages/vectorizer/tsconfig.json b/packages/vectorizer/tsconfig.json index eb78ece..47d465c 100644 --- a/packages/vectorizer/tsconfig.json +++ b/packages/vectorizer/tsconfig.json @@ -8,7 +8,7 @@ "isolatedModules": true, "esModuleInterop": true, "declaration": true, - "declarationDir": "dist/", + "declarationDir": "types/", "skipLibCheck": true }, "include": ["src/**/*", "esbuild/global.d.ts"], diff --git a/packages/vectorizer/types/actions.d.ts b/packages/vectorizer/types/actions.d.ts new file mode 100644 index 0000000..846f990 --- /dev/null +++ b/packages/vectorizer/types/actions.d.ts @@ -0,0 +1,10 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +/** + * Apply the vectorization process to the image. + */ +/** + * Triggers the vectiorize process. + */ +export declare function vectorizeAction(cesdk: CreativeEditorSDK, params: { + blockId: number; +}): Promise; diff --git a/packages/vectorizer/types/cesdk+utils.d.ts b/packages/vectorizer/types/cesdk+utils.d.ts new file mode 100644 index 0000000..bb1aa1d --- /dev/null +++ b/packages/vectorizer/types/cesdk+utils.d.ts @@ -0,0 +1,3 @@ +import { CreativeEngine } from "@cesdk/cesdk-js"; +export declare const createVectorPathBlocks: (engine: CreativeEngine, blocks: any[]) => number; +export declare const createVectorPathBlock: (engine: CreativeEngine, block: any) => number; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts new file mode 100644 index 0000000..c8f1c82 --- /dev/null +++ b/packages/vectorizer/types/index.d.ts @@ -0,0 +1,11 @@ +import { type PluginConfiguration } from './plugin'; +declare const Plugin: (pluginConfiguration?: PluginConfiguration) => { + initialize(engine: import("@cesdk/cesdk-js").CreativeEngine): void; + initializeUserInterface({ cesdk }: { + cesdk: import("@cesdk/cesdk-js").default; + }): void; + update(): void; + name: string; + version: string; +}; +export default Plugin; diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts new file mode 100644 index 0000000..1ff734b --- /dev/null +++ b/packages/vectorizer/types/manifest.d.ts @@ -0,0 +1,11 @@ +export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_CANVAS_MENU_COMPONENT_ID = "@imgly/plugin-vectorizer-web.canvasMenu"; +export declare const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = "@imgly/plugin-vectorizer-web.canvasMenu.button"; +export declare const PLUGIN_FEATURE_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; +export declare const PLUGIN_I18N_TRANSLATIONS: { + en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; +}; +export declare const PLUGIN_ICON = "@imgly/icons/Vectorize"; diff --git a/packages/vectorizer/types/plugin.d.ts b/packages/vectorizer/types/plugin.d.ts new file mode 100644 index 0000000..53dc685 --- /dev/null +++ b/packages/vectorizer/types/plugin.d.ts @@ -0,0 +1,12 @@ +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; +export interface PluginConfiguration { +} +declare const _default: (pluginConfiguration?: PluginConfiguration) => { + initialize(engine: CreativeEngine): void; + initializeUserInterface({ cesdk }: { + cesdk: CreativeEditorSDK; + }): void; + update(): void; +}; +export default _default; +export declare function enableFeatures(cesdk: CreativeEditorSDK): void; diff --git a/packages/vectorizer/types/types.d.ts b/packages/vectorizer/types/types.d.ts new file mode 100644 index 0000000..c00d57f --- /dev/null +++ b/packages/vectorizer/types/types.d.ts @@ -0,0 +1,34 @@ +import { type Source } from '@cesdk/cesdk-js'; +export type PluginStatusIdle = { + status: 'IDLE'; +}; +export type PluginStatusProcessing = { + version: string; + status: 'PROCESSING'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; + progress?: { + key: string; + current: number; + total: number; + }; +}; +export type PluginStatusProcessed = { + version: string; + status: 'PROCESSED'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; +}; +export type PluginStatusError = { + version: string; + status: 'ERROR'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; +}; +export type PluginMetadata = PluginStatusIdle | PluginStatusError | PluginStatusProcessing | PluginStatusProcessed; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts new file mode 100644 index 0000000..23aa594 --- /dev/null +++ b/packages/vectorizer/types/ui.d.ts @@ -0,0 +1,5 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +/** + * Registers the components that can be used to vectorize a block. + */ +export declare function registerUIComponents(cesdk: CreativeEditorSDK): void; diff --git a/packages/vectorizer/types/utils.d.ts b/packages/vectorizer/types/utils.d.ts new file mode 100644 index 0000000..18d9e45 --- /dev/null +++ b/packages/vectorizer/types/utils.d.ts @@ -0,0 +1,52 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; +import { PluginMetadata } from './types'; +/** + * Checks if a block is supported by the given CreativeEngine. + * @param engine - The CreativeEngine instance. + * @param blockId - The ID of the block to check. + * @returns A boolean indicating whether the block is supported or not. + */ +export declare const isBlockSupported: (engine: CreativeEngine, blockId: number) => boolean; +/** + * Sets the metadata for the plugin state. + */ +export declare function setPluginMetadata(engine: CreativeEngine, id: number, metadata: PluginMetadata): void; +/** + * Returns the current metadata for the plugin state. If no metadata + * is set on the given block, it will return an IDLE state. + */ +export declare function getPluginMetadata(engine: CreativeEngine, id: number): PluginMetadata; +/** + * If plugin metadata is set, it will be cleared. + */ +export declare function clearPluginMetadata(engine: CreativeEngine, id: number): void; +/** + * Detect if the block has been duplicated with processed or processing state. + * In that case the plugin state is still valid, but blockId and fillId have changed. + */ +export declare function isDuplicate(engine: CreativeEngine, blockId: number, metadata: PluginMetadata): boolean; +/** + * Fixes the metadata if the block has been duplicated, i.e. the blockId and + * fillId will be updated to the current block/fill. + * + * Please note: Call this method only on duplicates (see isDuplicate). + */ +export declare function fixDuplicateMetadata(engine: CreativeEngine, blockId: number): void; +/** + * Check if the image has a consisten metadata state. A inconsistent state is + * caused by outside changes of the fill data. + * + * @returns true if the metadata is consistent, false otherwise + */ +export declare function isMetadataConsistent(engine: CreativeEngine, blockId: number): boolean; +/** + * Recover the initial values to avoid the loading spinner and have the same + * state as before the process was started. + */ +export declare function recoverInitialImageData(engine: CreativeEngine, blockId: number): void; +export declare class Scheduler { + #private; + schedule(task: () => Promise): Promise; +} +export declare function registerAction(engine: CreativeEngine, label: string, callback: (params: any) => Promise): void; +export declare function executeAction(label: string, params: any): Promise; diff --git a/packages/vectorizer/types/worker.d.ts b/packages/vectorizer/types/worker.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/packages/vectorizer/types/worker.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/vectorizer/types/worker.shared.d.ts b/packages/vectorizer/types/worker.shared.d.ts new file mode 100644 index 0000000..68f6a33 --- /dev/null +++ b/packages/vectorizer/types/worker.shared.d.ts @@ -0,0 +1,6 @@ +export interface MessageBody { + method?: string; + data?: any; + error?: Error; +} +export declare const runInWorker: (uri: string) => Promise; diff --git a/turbo.json b/turbo.json index 55d300a..cf7f347 100644 --- a/turbo.json +++ b/turbo.json @@ -3,7 +3,7 @@ "pipeline": { "build": { "dependsOn": ["^build"], - "outputs": ["dist/**"] + "outputs": ["dist/**", "types/**"] }, "dev": { "cache": false, diff --git a/yarn.lock b/yarn.lock index 441a2b2..5a4ddeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -410,7 +410,7 @@ zod "~3.21.0" "@imgly/vectorizer@../vectorizer/packages/js": - version "0.1.0-rc4" + version "0.1.0-rc6" dependencies: "@types/lodash" "^4.14.195" "@types/node" "^20.3.1" @@ -458,7 +458,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -723,6 +723,24 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@rollup/plugin-inject@^5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz#616f3a73fe075765f91c5bec90176608bed277a3" + integrity sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg== + dependencies: + "@rollup/pluginutils" "^5.0.1" + estree-walker "^2.0.2" + magic-string "^0.30.3" + +"@rollup/pluginutils@^5.0.1": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" + integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + "@rollup/rollup-android-arm-eabi@4.9.6": version "4.9.6" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" @@ -878,7 +896,7 @@ dependencies: "@babel/types" "^7.20.7" -"@types/estree@1.0.5": +"@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -1242,6 +1260,27 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + ast-types-flow@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" @@ -1276,6 +1315,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + bin-links@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.3.tgz#9e4a3c5900830aee3d7f52178b65e01dcdde64a5" @@ -1291,6 +1335,16 @@ binary-extensions@^2.2.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1313,6 +1367,79 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-resolve@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" + integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ== + dependencies: + resolve "^1.17.0" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" + integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.4" + inherits "^2.0.4" + parse-asn1 "^5.1.6" + readable-stream "^3.6.2" + safe-buffer "^5.2.1" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + browserslist@^4.22.2: version "4.22.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" @@ -1323,6 +1450,24 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + builtins@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -1348,7 +1493,7 @@ cacache@^18.0.0, cacache@^18.0.2: tar "^6.1.11" unique-filename "^3.0.0" -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== @@ -1407,6 +1552,14 @@ cidr-regex@4.0.3: dependencies: ip-regex "^5.0.0" +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1515,16 +1668,62 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" @@ -1534,6 +1733,23 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -1606,11 +1822,28 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + diff@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -1632,6 +1865,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +domain-browser@^4.22.0: + version "4.23.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.23.0.tgz#427ebb91efcb070f05cffdfb8a4e9a6c25f8c94b" + integrity sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA== + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -1642,6 +1880,19 @@ electron-to-chromium@^1.4.648: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.657.tgz#8a07ee3faa552976970843a80a1c94088ea59c9a" integrity sha512-On2ymeleg6QbRuDk7wNgDdXtNqlJLM2w4Agx1D/RiTmItiL+a9oq5p7HUa2ZtkAtGBe/kil2dq/7rPfkbe0r5w== +elliptic@^6.5.3, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -2037,11 +2288,29 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + execa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -2392,6 +2661,23 @@ has-unicode@^2.0.1: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + hasown@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" @@ -2399,6 +2685,15 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" @@ -2419,6 +2714,11 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + https-proxy-agent@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" @@ -2439,6 +2739,11 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore-walk@^6.0.4: version "6.0.4" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" @@ -2487,7 +2792,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2539,6 +2844,14 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -2617,7 +2930,7 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-generator-function@^1.0.10: +is-generator-function@^1.0.10, is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -2641,6 +2954,14 @@ is-map@^2.0.1: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== +is-nan@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -2702,7 +3023,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.3, is-typed-array@^1.1.9: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -2744,6 +3065,11 @@ isexe@^3.1.1: resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== +isomorphic-timers-promises@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz#e4137c24dbc54892de8abae3a4b5c1ffff381598" + integrity sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ== + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -3038,6 +3364,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +magic-string@^0.30.3: + version "0.30.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" + integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + make-fetch-happen@^13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" @@ -3055,6 +3388,15 @@ make-fetch-happen@^13.0.0: promise-retry "^2.0.1" ssri "^10.0.0" +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -3073,11 +3415,29 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -3238,6 +3598,39 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-stdlib-browser@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz#5ddcfdf4063b88fb282979a1aa6ddab9728d5e4c" + integrity sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg== + dependencies: + assert "^2.0.0" + browser-resolve "^2.0.0" + browserify-zlib "^0.2.0" + buffer "^5.7.1" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + create-require "^1.1.1" + crypto-browserify "^3.11.0" + domain-browser "^4.22.0" + events "^3.0.0" + https-browserify "^1.0.0" + isomorphic-timers-promises "^1.0.1" + os-browserify "^0.3.0" + path-browserify "^1.0.1" + pkg-dir "^5.0.0" + process "^0.11.10" + punycode "^1.4.1" + querystring-es3 "^0.2.1" + readable-stream "^3.6.0" + stream-browserify "^3.0.0" + stream-http "^3.2.0" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.1" + url "^0.11.0" + util "^0.12.4" + vm-browserify "^1.0.1" + nopt@^7.0.0, nopt@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" @@ -3435,6 +3828,14 @@ object-inspect@^1.13.1: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -3539,6 +3940,11 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -3603,6 +4009,11 @@ pacote@^17.0.0, pacote@^17.0.4, pacote@^17.0.6: ssri "^10.0.0" tar "^6.1.11" +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" @@ -3610,6 +4021,17 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-asn1@^5.0.0, parse-asn1@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + parse-conflict-json@^3.0.0, parse-conflict-json@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c" @@ -3619,6 +4041,11 @@ parse-conflict-json@^3.0.0, parse-conflict-json@^3.0.1: just-diff "^6.0.0" just-diff-apply "^5.2.0" +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -3652,6 +4079,17 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -3667,6 +4105,13 @@ picomatch@^3.0.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-3.0.1.tgz#817033161def55ec9638567a2f3bbc876b3e7516" integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + platform@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" @@ -3680,10 +4125,10 @@ postcss-selector-parser@^6.0.10: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss@^8.4.32: - version "8.4.34" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.34.tgz#563276e86b4ff20dfa5eed0d394d4c53853b2051" - integrity sha512-4eLTO36woPSocqZ1zIrFD2K1v6wH7pY1uBh0JIM2KKfrVtGvPFiAku6aNOP0W1Wr9qwnaCsF0Z+CrVnryB2A8Q== +postcss@^8.4.35: + version "8.4.35" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" + integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== dependencies: nanoid "^3.3.7" picocolors "^1.0.0" @@ -3722,6 +4167,11 @@ proc-log@^3.0.0: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + promise-all-reject-late@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2" @@ -3779,6 +4229,18 @@ protobufjs@^7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -3787,6 +4249,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" @@ -3797,11 +4264,38 @@ qrcode-terminal@^0.12.0: resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== +qs@^6.11.2: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + +querystring-es3@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -3857,6 +4351,15 @@ read@^2.0.0, read@^2.1.0: dependencies: mute-stream "~1.0.0" +readable-stream@^3.5.0, readable-stream@^3.6.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + reflect.getprototypeof@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" @@ -3894,7 +4397,7 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.22.4: +resolve@^1.17.0, resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -3929,6 +4432,14 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + rollup@^4.2.0: version "4.9.6" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" @@ -3975,6 +4486,11 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" @@ -3984,7 +4500,7 @@ safe-regex-test@^1.0.0: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -4034,6 +4550,19 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -4153,6 +4682,24 @@ ssri@^10.0.0, ssri@^10.0.5: dependencies: minipass "^7.0.3" +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-http@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4222,6 +4769,13 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -4306,6 +4860,13 @@ text-table@^0.2.0, text-table@~0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + tiny-relative-date@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" @@ -4358,6 +4919,11 @@ tslog@^4.9.2: resolved "https://registry.npmjs.org/tslog/-/tslog-4.9.2.tgz" integrity sha512-wBM+LRJoNl34Bdu8mYEFxpvmOUedpNUwMNQB/NcuPIZKwdDde6xLHUev3bBjXQU7gdurX++X/YE7gLH8eXYsiQ== +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + tuf-js@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.2.0.tgz#4daaa8620ba7545501d04dfa933c98abbcc959b9" @@ -4509,11 +5075,30 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.2: +url@^0.11.0: + version "0.11.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" + integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== + dependencies: + punycode "^1.4.1" + qs "^6.11.2" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.12.4, util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -4529,17 +5114,30 @@ validate-npm-package-name@^5.0.0: dependencies: builtins "^5.0.0" -vite@^5.0.8: - version "5.0.12" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47" - integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w== +vite-plugin-node-polyfills@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.20.0.tgz#10660ad7002dffc02e3857ff24efc99628f1b15a" + integrity sha512-15pGD3r/9eOATLQLLOaWdRgav/bBjCLnBvdhi0kD3YA57ncTExI0qdvwW8L1arlk75XiEz41vz3Fn92Z8LgUcQ== + dependencies: + "@rollup/plugin-inject" "^5.0.5" + node-stdlib-browser "^1.2.0" + +vite@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.1.tgz#294e39b199d669981efc7e0261b14f78ec80819e" + integrity sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg== dependencies: esbuild "^0.19.3" - postcss "^8.4.32" + postcss "^8.4.35" rollup "^4.2.0" optionalDependencies: fsevents "~2.3.3" +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + walk-up-path@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" @@ -4591,7 +5189,7 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.9: +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.2, which-typed-array@^1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== @@ -4663,6 +5261,11 @@ write-file-atomic@^5.0.0, write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" From b3a8791ff26fa6b0c2e75556ecf0ed095c4735a1 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 9 Feb 2024 20:38:10 +0100 Subject: [PATCH 06/32] fix(vectorizer): Updated lib to npm --- .gitignore | 1 + packages/vectorizer/package.json | 2 +- yarn.lock | 629 +------------------------------ 3 files changed, 16 insertions(+), 616 deletions(-) diff --git a/.gitignore b/.gitignore index 7469b03..30e7267 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ examples/*/dist yarn-error.log .turbo +.vercel diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 61644be..572ec7c 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -65,7 +65,7 @@ "@cesdk/cesdk-js": "~1.20.0" }, "dependencies": { - "@imgly/vectorizer": "../vectorizer/packages/js", + "@imgly/vectorizer": "~0.1.0-rc.6", "lodash": "^4.17.21" } } diff --git a/yarn.lock b/yarn.lock index 5a4ddeb..4a4dfa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -409,8 +409,10 @@ onnxruntime-web "~1.17.0" zod "~3.21.0" -"@imgly/vectorizer@../vectorizer/packages/js": - version "0.1.0-rc6" +"@imgly/vectorizer@~0.1.0-rc.6": + version "0.1.0-rc0" + resolved "https://registry.yarnpkg.com/@imgly/vectorizer/-/vectorizer-0.1.0-rc0.tgz#61fe4001a93bf486d654fa0a40e9e2b41778e356" + integrity sha512-PpJaATDiqR021xDZjGR3wAJ/dU8mk4/2iLtP9WjzpdqvJ78sKtqThhsTZfe7eZMN1MdM9+0ZcSKqZolstBLGLA== dependencies: "@types/lodash" "^4.14.195" "@types/node" "^20.3.1" @@ -458,7 +460,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -723,24 +725,6 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@rollup/plugin-inject@^5.0.5": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz#616f3a73fe075765f91c5bec90176608bed277a3" - integrity sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - estree-walker "^2.0.2" - magic-string "^0.30.3" - -"@rollup/pluginutils@^5.0.1": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" - integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^2.3.1" - "@rollup/rollup-android-arm-eabi@4.9.6": version "4.9.6" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" @@ -896,7 +880,7 @@ dependencies: "@babel/types" "^7.20.7" -"@types/estree@1.0.5", "@types/estree@^1.0.0": +"@types/estree@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -1260,27 +1244,6 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -assert@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" - integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== - dependencies: - call-bind "^1.0.2" - is-nan "^1.3.2" - object-is "^1.1.5" - object.assign "^4.1.4" - util "^0.12.5" - ast-types-flow@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" @@ -1315,11 +1278,6 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - bin-links@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.3.tgz#9e4a3c5900830aee3d7f52178b65e01dcdde64a5" @@ -1335,16 +1293,6 @@ binary-extensions@^2.2.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1367,79 +1315,6 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browser-resolve@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" - integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ== - dependencies: - resolve "^1.17.0" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" - integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== - dependencies: - bn.js "^5.2.1" - browserify-rsa "^4.1.0" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.4" - inherits "^2.0.4" - parse-asn1 "^5.1.6" - readable-stream "^3.6.2" - safe-buffer "^5.2.1" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - browserslist@^4.22.2: version "4.22.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" @@ -1450,24 +1325,6 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - -buffer@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== - builtins@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -1493,7 +1350,7 @@ cacache@^18.0.0, cacache@^18.0.2: tar "^6.1.11" unique-filename "^3.0.0" -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== @@ -1552,14 +1409,6 @@ cidr-regex@4.0.3: dependencies: ip-regex "^5.0.0" -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1668,62 +1517,16 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -create-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" @@ -1733,23 +1536,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -1822,28 +1608,11 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -des.js@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" - integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - diff@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -1865,11 +1634,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -domain-browser@^4.22.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.23.0.tgz#427ebb91efcb070f05cffdfb8a4e9a6c25f8c94b" - integrity sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA== - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -1880,19 +1644,6 @@ electron-to-chromium@^1.4.648: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.657.tgz#8a07ee3faa552976970843a80a1c94088ea59c9a" integrity sha512-On2ymeleg6QbRuDk7wNgDdXtNqlJLM2w4Agx1D/RiTmItiL+a9oq5p7HUa2ZtkAtGBe/kil2dq/7rPfkbe0r5w== -elliptic@^6.5.3, elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -2288,29 +2039,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - esutils@^2.0.2: version "2.0.3" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -events@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - execa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -2661,23 +2394,6 @@ has-unicode@^2.0.1: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - hasown@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" @@ -2685,15 +2401,6 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" @@ -2714,11 +2421,6 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== - https-proxy-agent@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" @@ -2739,11 +2441,6 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - ignore-walk@^6.0.4: version "6.0.4" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-6.0.4.tgz#89950be94b4f522225eb63a13c56badb639190e9" @@ -2792,7 +2489,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: +inherits@2: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2844,14 +2541,6 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -2930,7 +2619,7 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-generator-function@^1.0.10, is-generator-function@^1.0.7: +is-generator-function@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -2954,14 +2643,6 @@ is-map@^2.0.1: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== -is-nan@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -3023,7 +2704,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -3065,11 +2746,6 @@ isexe@^3.1.1: resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== -isomorphic-timers-promises@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz#e4137c24dbc54892de8abae3a4b5c1ffff381598" - integrity sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ== - iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -3364,13 +3040,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -magic-string@^0.30.3: - version "0.30.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" - integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - make-fetch-happen@^13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" @@ -3388,15 +3057,6 @@ make-fetch-happen@^13.0.0: promise-retry "^2.0.1" ssri "^10.0.0" -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -3415,29 +3075,11 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -3598,39 +3240,6 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -node-stdlib-browser@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz#5ddcfdf4063b88fb282979a1aa6ddab9728d5e4c" - integrity sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg== - dependencies: - assert "^2.0.0" - browser-resolve "^2.0.0" - browserify-zlib "^0.2.0" - buffer "^5.7.1" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - create-require "^1.1.1" - crypto-browserify "^3.11.0" - domain-browser "^4.22.0" - events "^3.0.0" - https-browserify "^1.0.0" - isomorphic-timers-promises "^1.0.1" - os-browserify "^0.3.0" - path-browserify "^1.0.1" - pkg-dir "^5.0.0" - process "^0.11.10" - punycode "^1.4.1" - querystring-es3 "^0.2.1" - readable-stream "^3.6.0" - stream-browserify "^3.0.0" - stream-http "^3.2.0" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.1" - url "^0.11.0" - util "^0.12.4" - vm-browserify "^1.0.1" - nopt@^7.0.0, nopt@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" @@ -3828,14 +3437,6 @@ object-inspect@^1.13.1: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -3940,11 +3541,6 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -4009,11 +3605,6 @@ pacote@^17.0.0, pacote@^17.0.4, pacote@^17.0.6: ssri "^10.0.0" tar "^6.1.11" -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" @@ -4021,17 +3612,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-asn1@^5.0.0, parse-asn1@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - parse-conflict-json@^3.0.0, parse-conflict-json@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c" @@ -4041,11 +3621,6 @@ parse-conflict-json@^3.0.0, parse-conflict-json@^3.0.1: just-diff "^6.0.0" just-diff-apply "^5.2.0" -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -4079,17 +3654,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -4105,13 +3669,6 @@ picomatch@^3.0.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-3.0.1.tgz#817033161def55ec9638567a2f3bbc876b3e7516" integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - platform@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" @@ -4167,11 +3724,6 @@ proc-log@^3.0.0: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - promise-all-reject-late@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2" @@ -4229,18 +3781,6 @@ protobufjs@^7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -4249,11 +3789,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" @@ -4264,38 +3799,11 @@ qrcode-terminal@^0.12.0: resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ== -qs@^6.11.2: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" - -querystring-es3@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -4351,15 +3859,6 @@ read@^2.0.0, read@^2.1.0: dependencies: mute-stream "~1.0.0" -readable-stream@^3.5.0, readable-stream@^3.6.0, readable-stream@^3.6.2: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - reflect.getprototypeof@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" @@ -4397,7 +3896,7 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.17.0, resolve@^1.22.4: +resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -4432,14 +3931,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - rollup@^4.2.0: version "4.9.6" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" @@ -4486,11 +3977,6 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-regex-test@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" @@ -4500,7 +3986,7 @@ safe-regex-test@^1.0.0: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -4550,19 +4036,6 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -4682,24 +4155,6 @@ ssri@^10.0.0, ssri@^10.0.5: dependencies: minipass "^7.0.3" -stream-browserify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" - integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== - dependencies: - inherits "~2.0.4" - readable-stream "^3.5.0" - -stream-http@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" - integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.4" - readable-stream "^3.6.0" - xtend "^4.0.2" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4769,13 +4224,6 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -4860,13 +4308,6 @@ text-table@^0.2.0, text-table@~0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - tiny-relative-date@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" @@ -4919,11 +4360,6 @@ tslog@^4.9.2: resolved "https://registry.npmjs.org/tslog/-/tslog-4.9.2.tgz" integrity sha512-wBM+LRJoNl34Bdu8mYEFxpvmOUedpNUwMNQB/NcuPIZKwdDde6xLHUev3bBjXQU7gdurX++X/YE7gLH8eXYsiQ== -tty-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" - integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== - tuf-js@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.2.0.tgz#4daaa8620ba7545501d04dfa933c98abbcc959b9" @@ -5075,30 +4511,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url@^0.11.0: - version "0.11.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" - integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== - dependencies: - punycode "^1.4.1" - qs "^6.11.2" - -util-deprecate@^1.0.1, util-deprecate@^1.0.2: +util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.4, util@^0.12.5: - version "0.12.5" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" - integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - which-typed-array "^1.1.2" - validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -5114,14 +4531,6 @@ validate-npm-package-name@^5.0.0: dependencies: builtins "^5.0.0" -vite-plugin-node-polyfills@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.20.0.tgz#10660ad7002dffc02e3857ff24efc99628f1b15a" - integrity sha512-15pGD3r/9eOATLQLLOaWdRgav/bBjCLnBvdhi0kD3YA57ncTExI0qdvwW8L1arlk75XiEz41vz3Fn92Z8LgUcQ== - dependencies: - "@rollup/plugin-inject" "^5.0.5" - node-stdlib-browser "^1.2.0" - vite@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.1.tgz#294e39b199d669981efc7e0261b14f78ec80819e" @@ -5133,11 +4542,6 @@ vite@^5.1.1: optionalDependencies: fsevents "~2.3.3" -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - walk-up-path@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" @@ -5189,7 +4593,7 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.2, which-typed-array@^1.1.9: +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== @@ -5261,11 +4665,6 @@ write-file-atomic@^5.0.0, write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" From 8a828e9be609840fa01dc848e1768449ec7dda70 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 9 Feb 2024 20:41:50 +0100 Subject: [PATCH 07/32] fix(vectorizer): Updated lib to npm --- packages/vectorizer/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 572ec7c..86ec7b5 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -65,7 +65,7 @@ "@cesdk/cesdk-js": "~1.20.0" }, "dependencies": { - "@imgly/vectorizer": "~0.1.0-rc.6", + "@imgly/vectorizer": "~0.1.0-rc6", "lodash": "^4.17.21" } } diff --git a/yarn.lock b/yarn.lock index 4a4dfa0..b02c2b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -409,10 +409,10 @@ onnxruntime-web "~1.17.0" zod "~3.21.0" -"@imgly/vectorizer@~0.1.0-rc.6": - version "0.1.0-rc0" - resolved "https://registry.yarnpkg.com/@imgly/vectorizer/-/vectorizer-0.1.0-rc0.tgz#61fe4001a93bf486d654fa0a40e9e2b41778e356" - integrity sha512-PpJaATDiqR021xDZjGR3wAJ/dU8mk4/2iLtP9WjzpdqvJ78sKtqThhsTZfe7eZMN1MdM9+0ZcSKqZolstBLGLA== +"@imgly/vectorizer@~0.1.0-rc6": + version "0.1.0-rc6" + resolved "https://registry.yarnpkg.com/@imgly/vectorizer/-/vectorizer-0.1.0-rc6.tgz#509bec4e78d2654e4e3413c19e6e462d9bc62c7f" + integrity sha512-Q3QbRfB74wHZFB/TojJOJsSOAR8ZkV/mLXD8AztcTrwG1dVOPYfrcsrqbFLnHNz7XSxB8xCvSzdZOtylgXXugg== dependencies: "@types/lodash" "^4.14.195" "@types/node" "^20.3.1" From 941767e7cecabd670630ee77840f6b91180cc8a7 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 9 Feb 2024 20:50:35 +0100 Subject: [PATCH 08/32] chore: Added vercel headers --- vercel.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..8381922 --- /dev/null +++ b/vercel.json @@ -0,0 +1,17 @@ +{ + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "Cross-Origin-Opener-Policy", + "value": "same-origin" + }, + { + "key": "Cross-Origin-Embedder-Policy", + "value": "require-corp" + } + ] + } + ] +} \ No newline at end of file From 1ebb0a078143a4248b36b4605c0a3124d87a6da2 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 9 Feb 2024 20:51:22 +0100 Subject: [PATCH 09/32] chore: Added vercel headers --- vercel.json => examples/web/vercel.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vercel.json => examples/web/vercel.json (100%) diff --git a/vercel.json b/examples/web/vercel.json similarity index 100% rename from vercel.json rename to examples/web/vercel.json From 4f11aba1ab6d240432993f4ea09427e761f2e8d7 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sun, 11 Feb 2024 01:32:30 +0100 Subject: [PATCH 10/32] wip: simplification and generalization --- TODO.md | 5 + examples/web/package.json | 1 + examples/web/src/App.tsx | 92 ++++-- examples/web/src/CommandPalette.tsx | 191 ++++++++++++ examples/web/src/addPlugins.ts | 11 +- .../web/{vercel.json => vercel.json.disabled} | 0 examples/web/vite.config.ts | 3 +- packages/vectorizer/STRUCTURE.md | 1 + packages/vectorizer/TODO.md | 0 packages/vectorizer/package.json | 4 +- .../src/{actions.ts => commands.ts} | 114 ++++--- packages/vectorizer/src/i18n.ts | 5 + packages/vectorizer/src/index.ts | 127 +++++++- packages/vectorizer/src/manifest.ts | 21 +- packages/vectorizer/src/plugin.ts | 103 ------ packages/vectorizer/src/ui.ts | 97 +++--- .../vectorizer/src/{ => utils}/cesdk+utils.ts | 4 +- packages/vectorizer/src/utils/constants.ts | 8 + packages/vectorizer/src/utils/polyfills.ts | 31 ++ packages/vectorizer/src/{ => utils}/types.ts | 0 packages/vectorizer/src/{ => utils}/utils.ts | 33 +- .../src/{ => utils}/worker.shared.ts | 9 +- packages/vectorizer/src/worker.ts | 47 +-- packages/vectorizer/types/actions.d.ts | 15 +- packages/vectorizer/types/commands.d.ts | 7 + packages/vectorizer/types/i18n.d.ts | 15 + packages/vectorizer/types/index.d.ts | 19 +- packages/vectorizer/types/manifest.d.ts | 16 +- packages/vectorizer/types/manitfest.d.ts | 9 + .../vectorizer/types/proposal/actions.d.ts | 7 + packages/vectorizer/types/proposal/i18n.d.ts | 15 + .../vectorizer/types/proposal/manitfest.d.ts | 6 + packages/vectorizer/types/proposal/ui.d.ts | 4 + .../vectorizer/types/proposal/worker.d.ts | 1 + packages/vectorizer/types/ui.d.ts | 9 +- packages/vectorizer/types/utils.d.ts | 2 +- .../vectorizer/types/utils/cesdk+utils.d.ts | 3 + .../vectorizer/types/utils/constants.d.ts | 6 + .../vectorizer/types/utils/polyfills.d.ts | 12 + packages/vectorizer/types/utils/supports.d.ts | 0 packages/vectorizer/types/utils/types.d.ts | 34 ++ packages/vectorizer/types/utils/utils.d.ts | 50 +++ .../vectorizer/types/utils/worker.shared.d.ts | 6 + yarn.lock | 293 +++++++++++++++++- 44 files changed, 1097 insertions(+), 339 deletions(-) create mode 100644 TODO.md create mode 100644 examples/web/src/CommandPalette.tsx rename examples/web/{vercel.json => vercel.json.disabled} (100%) create mode 100644 packages/vectorizer/STRUCTURE.md create mode 100644 packages/vectorizer/TODO.md rename packages/vectorizer/src/{actions.ts => commands.ts} (65%) create mode 100644 packages/vectorizer/src/i18n.ts delete mode 100644 packages/vectorizer/src/plugin.ts rename packages/vectorizer/src/{ => utils}/cesdk+utils.ts (97%) create mode 100644 packages/vectorizer/src/utils/constants.ts create mode 100644 packages/vectorizer/src/utils/polyfills.ts rename packages/vectorizer/src/{ => utils}/types.ts (100%) rename packages/vectorizer/src/{ => utils}/utils.ts (93%) rename packages/vectorizer/src/{ => utils}/worker.shared.ts (62%) create mode 100644 packages/vectorizer/types/commands.d.ts create mode 100644 packages/vectorizer/types/i18n.d.ts create mode 100644 packages/vectorizer/types/manitfest.d.ts create mode 100644 packages/vectorizer/types/proposal/actions.d.ts create mode 100644 packages/vectorizer/types/proposal/i18n.d.ts create mode 100644 packages/vectorizer/types/proposal/manitfest.d.ts create mode 100644 packages/vectorizer/types/proposal/ui.d.ts create mode 100644 packages/vectorizer/types/proposal/worker.d.ts create mode 100644 packages/vectorizer/types/utils/cesdk+utils.d.ts create mode 100644 packages/vectorizer/types/utils/constants.d.ts create mode 100644 packages/vectorizer/types/utils/polyfills.d.ts create mode 100644 packages/vectorizer/types/utils/supports.d.ts create mode 100644 packages/vectorizer/types/utils/types.d.ts create mode 100644 packages/vectorizer/types/utils/utils.d.ts create mode 100644 packages/vectorizer/types/utils/worker.shared.d.ts diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..cea5d94 --- /dev/null +++ b/TODO.md @@ -0,0 +1,5 @@ +- ? How can I list all plugins that are active +- ? How can I deactivate a plugin +- ? we should pass the PluginContext with seperate `{engine?: ImglyEngine, editor?: ImglyEditor, ui?: ImglyUI` + +- `feature.isEnabled` should be feature.isEnabledFor(blockId) -> test for multiple blockIds at once diff --git a/examples/web/package.json b/examples/web/package.json index 296a8a5..65353aa 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -13,6 +13,7 @@ "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer-web": "*", "react": "^18.2.0", + "react-cmdk": "^1.3.9", "react-dom": "^18.2.0" }, "devDependencies": { diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 483a4ea..bf44e1c 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -1,49 +1,83 @@ import { useRef } from "react"; import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; +import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; +import VectorizerPlugin, { Manifest as VectorizerManifest } from '@imgly/plugin-vectorizer-web'; + +import { ActionsMenu } from "./CommandPalette" + +const plugins = [VectorizerPlugin(), BackgroundRemovalPlugin()] + -import addPlugins from "./addPlugins"; function App() { const cesdk = useRef(); const config: Configuration = { license: import.meta.env.VITE_CESDK_LICENSE_KEY, - callbacks: { onUpload: "local" }, + callbacks: { + onUpload: "local", + onDownload: "download", + onSave: (s) => { + console.log("Save", s); + return Promise.resolve(); + }, + onExport: (blobs, options) => { + // why does this only export 1 page + console.log("Export", blobs, options); + return Promise.resolve(); + }, + onLoad: "upload", + }, // devMode: true, theme: "dark", role: 'Creator', - ui:{ + + ui: { + hide: false, elements: { - view: "default" + view: "advanced", + navigation: { + title: "IMG.LY Plugin Sandbox", + action: { + save: true, + load: true, + export: true, + share: true, + } + } } } } + return ( -
{ - if (domElement != null) { - CreativeEditorSDK - .create(domElement, config) - .then(async (instance) => { - // @ts-ignore - window.cesdk = instance; - cesdk.current = instance; - - // Do something with the instance of CreativeEditor SDK, for example: - // Populate the asset library with default / demo asset sources. - await Promise.all([ - instance.addDefaultAssetSources(), - instance.addDemoAssetSources({ sceneMode: "Design" }), - addPlugins(instance), - ]); - await instance.createDesignScene(); - }); - } else if (cesdk.current != null) { - cesdk.current.dispose(); - } - }} - >
+ <> + +
{ + if (domElement != null) { + CreativeEditorSDK + .create(domElement, config) + .then(async (instance) => { + // @ts-ignore + window.cesdk = instance; + cesdk.current = instance; + + // Do something with the instance of CreativeEditor SDK, for example: + // Populate the asset library with default / demo asset sources. + await Promise.all([ + instance.addDefaultAssetSources(), + instance.addDemoAssetSources({ sceneMode: "Design" }), + plugins.map(plugin => cesdk?.current?.unstable_addPlugin(plugin)) + ]); + await instance.createDesignScene(); + }); + } else if (cesdk.current != null) { + cesdk.current.dispose(); + } + }} + >
+ ); } diff --git a/examples/web/src/CommandPalette.tsx b/examples/web/src/CommandPalette.tsx new file mode 100644 index 0000000..4252e57 --- /dev/null +++ b/examples/web/src/CommandPalette.tsx @@ -0,0 +1,191 @@ +import "react-cmdk/dist/cmdk.css"; +import CommandPalette, { filterItems, getItemIndex } from "react-cmdk"; +import { useState, useEffect, RefObject } from "react"; +import CreativeEditorSDK from "@cesdk/cesdk-js"; + +// https://github.com/albingroen/react-cmdk +export const ActionsMenu = (params: { cesdkRef: RefObject, actions: Array }) => { + const [page, _setPage] = useState<"root">("root"); + const [search, setSearch] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const { cesdkRef } = params + + if (!(cesdkRef)) return + const cesdk = cesdkRef?.current + + useEffect(() => { + function handleKeyDown(e: KeyboardEvent) { + if ( + (navigator?.platform?.toLowerCase().includes("mac") + ? e.metaKey + : e.ctrlKey) && + e.key === "k" + ) { + e.preventDefault(); + e.stopPropagation(); + + setIsOpen((currentValue) => { + return !currentValue; + }); + } + } + + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + + const filteredItems = filterItems( + [ + { + heading: "Debug", + id: "debug", + items: [ + { + id: "info", + children: "Info", + showType: false, + onClick: () => { + console.log("Clicked on projects") + console.log("Cesdk ref", cesdkRef ?? "No ref") + }, + }, + { + id: "duplicate", + children: "Duplicate Selected Blocks", + showType: false, + onClick: () => { + const selected = cesdk!.engine.block.findAllSelected() ?? [] + selected.map((id: any) => { + cesdk!.engine.block.setSelected(id, false) + const dupId = cesdk!.engine.block.duplicate(id) + cesdk!.engine.block.setSelected(dupId, true) + }) + }, + }, + { + id: "delete", + children: "Delete Selected Blocks", + showType: false, + onClick: () => { + const selected = cesdk!.engine.block.findAllSelected() ?? [] + selected.map((id: any) => { + + cesdk!.engine.block.destroy(id) + }) + }, + } + , + { + id: "saveToClipboard", + children: "Save to Clipboard", + showType: false, + onClick: async () => { + const selected = cesdk!.engine.block.findAllSelected() ?? [] + const dump = await cesdk!.engine.block.saveToString(selected) + // console.info(dump) + navigator.clipboard.writeText(dump); + }, + }, + { + id: "loadFromClipboard", + children: "Load from Clipboard", + showType: false, + onClick: async () => { + // @ts-ignore + const status = await navigator.permissions.query({ name: 'clipboard-read' }) + console.log("Clipboard read status", status.state) + const dump = await navigator.clipboard.readText() + const blockIds = await cesdk!.engine.block.loadFromString(dump) + const parentId = cesdk!.engine.scene.getCurrentPage() + if (!parentId || !blockIds) { + console.error("No parent or block id") + return + } + blockIds.map((blockId: any) => { + cesdk!.engine.block.appendChild(parentId, blockId) + }) + + + }, + } + ], + }, + { + heading: "Export", + id: "export", + items: [ + { + id: "exportPngToClipboard", + children: "Export PNG to Clipboard", + showType: false, + onClick: async () => { + // await navigator.permissions.query({ name: 'clipboard-write' }) + const selected = cesdk!.engine.block.findAllSelected() ?? [] + if (selected.length !== 1) return + + // most browser can only do on1 + const items = await Promise.all(selected.map(async (id: number) => { + // @ts-ignore + const dump = await cesdk!.engine.block.export(id, "image/png") + return new ClipboardItem({ "image/png": dump }, { presentationStyle: "attachment" }) + })) + navigator.clipboard.write(items) + }, + }, + ] + }, + { + heading: "Plugin", + id: "plugin", + items: params.actions.map(action => { + return { + id: action.id, + children: action.id, + showType: false, + onClick: () => { + // @ts-ignore + const act = window.cesdk_actions.get(action.id) + act?.() + } + } + }) + } + ], + search + ); + + return ( + + + {filteredItems.length ? ( + filteredItems.map((list) => ( + + {list.items.map(({ id, ...rest }) => ( + + ))} + + )) + ) : ( + + )} + + + + ); +}; + +/// helper + diff --git a/examples/web/src/addPlugins.ts b/examples/web/src/addPlugins.ts index 305a42f..a08ada0 100644 --- a/examples/web/src/addPlugins.ts +++ b/examples/web/src/addPlugins.ts @@ -1,12 +1,17 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import CreativeEditorSDK from '@cesdk/cesdk-js'; import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; +const plugins = [VectorizerPlugin(), BackgroundRemovalPlugin()] + + async function addPlugins(cesdk: CreativeEditorSDK) { try { - cesdk.unstable_addPlugin(VectorizerPlugin()); - cesdk.unstable_addPlugin(BackgroundRemovalPlugin()); + plugins.map(cesdk.unstable_addPlugin.bind(cesdk)) + + + } catch (error) { console.error('Could not add all plugins: ', error); } diff --git a/examples/web/vercel.json b/examples/web/vercel.json.disabled similarity index 100% rename from examples/web/vercel.json rename to examples/web/vercel.json.disabled diff --git a/examples/web/vite.config.ts b/examples/web/vite.config.ts index fd1f8a2..0129c15 100644 --- a/examples/web/vite.config.ts +++ b/examples/web/vite.config.ts @@ -8,7 +8,8 @@ import { createLogger } from "./vite/logger"; export default defineConfig({ plugins: [react()], build: { - chunkSizeWarningLimit: 4096 + chunkSizeWarningLimit: 4096, + sourcemap: true }, worker: { format: "es" // Default was "iife" but then import.meta.url for importing worker does not worker diff --git a/packages/vectorizer/STRUCTURE.md b/packages/vectorizer/STRUCTURE.md new file mode 100644 index 0000000..13b1472 --- /dev/null +++ b/packages/vectorizer/STRUCTURE.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vectorizer/TODO.md b/packages/vectorizer/TODO.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 86ec7b5..89bfd4c 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -42,8 +42,8 @@ "scripts": { "start": "npm run watch", "clean": "npx rimraf dist && npx rimraf types", - "build": "node scripts/build.mjs && yarn run types:create", - "dev": "node scripts/watch.mjs", + "build": "yarn run types:create && node scripts/build.mjs", + "dev": "yarn run types:create && node scripts/watch.mjs", "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", diff --git a/packages/vectorizer/src/actions.ts b/packages/vectorizer/src/commands.ts similarity index 65% rename from packages/vectorizer/src/actions.ts rename to packages/vectorizer/src/commands.ts index 3864e47..fda9ba7 100644 --- a/packages/vectorizer/src/actions.ts +++ b/packages/vectorizer/src/commands.ts @@ -1,26 +1,19 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import { PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants'; + import { getPluginMetadata, isBlockSupported, isMetadataConsistent, recoverInitialImageData, setPluginMetadata -} from './utils'; - -import { runInWorker } from './worker.shared'; -import { createVectorPathBlocks } from './cesdk+utils'; -/** - * Apply the vectorization process to the image. - */ - -/** - * Triggers the vectiorize process. - */ -export async function vectorizeAction( - cesdk: CreativeEditorSDK, - params: { blockId: number } -) { +} from './utils/utils'; + +import { runInWorker } from './utils/worker.shared'; +import { createVectorPathBlocks } from './utils/cesdk+utils'; + +const vectorize = async (cesdk: CreativeEditorSDK, params: { blockId: number }) => { const uploader = cesdk.unstable_upload.bind(cesdk) const engine = cesdk.engine; // the only function that needs the ui is the upload function const blockApi = engine.block; @@ -44,6 +37,7 @@ export async function vectorizeAction( const fillId = blockApi.getFill(blockId); + // Get the current image URI and source set as initial values. const initialSourceSet = blockApi.getSourceSet( fillId, @@ -75,11 +69,17 @@ export async function vectorizeAction( try { // Clear values in the engine to trigger the loading spinner + // @ts-ignore + const blob = await engine.block.export(blockId, "image/png"); + + // go into busy state blockApi.setString(fillId, 'fill/image/imageFileURI', ''); blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); // ensure we show the last image while processsing. Some images don't have the preview set if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); + + } const metadata = getPluginMetadata(engine, blockId); setPluginMetadata(engine, blockId, { @@ -92,13 +92,22 @@ export async function vectorizeAction( status: 'PROCESSING' }); - const vectorized: Blob = await runInWorker(uriToProcess) + const vectorized: Blob = await runInWorker(blob) if ( getPluginMetadata(engine, blockId).status !== 'PROCESSING' || !isMetadataConsistent(engine, blockId) - ) - return; + )return; + if (engine.block.isValid(blockId)) { + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + }); + } if (vectorized.type.length === 0 || vectorized.type === 'image/svg+xml') { @@ -126,6 +135,11 @@ export async function vectorizeAction( throw new Error('Could not upload vectorized image'); } + // Workaround Processing is done, restore state of the initial block + blockApi.setSourceSet(fillId, 'fill/image/sourceSet', initialSourceSet); + blockApi.setString(fillId, 'fill/image/imageFileURI', initialImageFileURI); + blockApi.setString(fillId, 'fill/image/previewFileURI', initialPreviewFileURI); + setPluginMetadata(engine, blockId, { version: PLUGIN_VERSION, initialSourceSet, @@ -133,45 +147,49 @@ export async function vectorizeAction( blockId, fillId, status: 'PROCESSED', - // processedAsset: url }); blockApi.setString(fillId, 'fill/image/imageFileURI', url); } else if (vectorized.type === 'application/json') { + const json = await vectorized.text() const blocks = JSON.parse(json) - const groupId = createVectorPathBlocks(engine, blocks) - const parentId = engine.block.getParent(blockId)! - engine.block.appendChild(parentId, groupId); - + const blockIds = createVectorPathBlocks(engine, blocks) - const origWidth = engine.block.getFrameWidth(blockId) - const origHeight = engine.block.getFrameHeight(blockId) const origRotation = engine.block.getRotation(blockId) const origX = engine.block.getPositionX(blockId) const origY = engine.block.getPositionY(blockId) - const groupWidth = engine.block.getFrameWidth(groupId) - const groupHeight = engine.block.getFrameHeight(groupId) - engine.block.setPositionX(groupId, origX) - engine.block.setPositionY(groupId, origY) - engine.block.setRotation(groupId, origRotation) - engine.block.scale(groupId, origWidth / groupWidth) - //remove original block - engine.block.destroy(blockId) - - // must be assigned to a scene to work... why? - - - blockApi.setString(fillId, 'fill/image/imageFileURI', initialImageFileURI); - - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSED', - }); + const origSelected = engine.block.isSelected(blockId) + switch (engine.block.getType(blockId)) { + case "//ly.img.ubq/page": + { + const parentId = blockId; + const containerId = engine.block.group(blockIds); + engine.block.appendChild(parentId, containerId); + const scale = engine.block.getFrameWidth(blockId) / engine.block.getFrameWidth(containerId) + engine.block.setPositionX(containerId, origX) + engine.block.setPositionY(containerId, origY) + engine.block.setRotation(containerId, origRotation) + engine.block.scale(containerId, scale) + engine.block.setFillEnabled(parentId, false) + engine.block.setSelected(containerId, origSelected) + break; + } + case "//ly.img.ubq/graphic": + default: { // replace the current block with the a new group of the vectors + const parentId = engine.block.getParent(blockId)! + const containerId = engine.block.group(blockIds); + engine.block.appendChild(parentId, containerId); + const scale = engine.block.getFrameWidth(blockId) / engine.block.getFrameWidth(containerId) + engine.block.setPositionX(containerId, origX) + engine.block.setPositionY(containerId, origY) + engine.block.setRotation(containerId, origRotation) + engine.block.scale(containerId, scale) + engine.block.destroy(blockId) + engine.block.setSelected(containerId, origSelected) + break; + } + } } // Finally, create an undo step engine.editor.addUndoStep(); @@ -193,3 +211,5 @@ export async function vectorizeAction( console.error(error); } } + +export default { [PLUGIN_ACTION_VECTORIZE_LABEL]: vectorize } diff --git a/packages/vectorizer/src/i18n.ts b/packages/vectorizer/src/i18n.ts new file mode 100644 index 0000000..ee99b0d --- /dev/null +++ b/packages/vectorizer/src/i18n.ts @@ -0,0 +1,5 @@ +import { PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants' + +export const en = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vector' } +export const de = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Wandle in Vector' } +export default { de, en }; \ No newline at end of file diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index 973be5e..8af3fdb 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -1,11 +1,122 @@ -import plugin, { type PluginConfiguration } from './plugin'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -import { PLUGIN_ID } from './manifest'; +import ui from './ui'; +import commands from './commands'; +import i18n from './i18n'; +import Manifest from './manifest'; -const Plugin = (pluginConfiguration?: PluginConfiguration) => ({ - name: PLUGIN_ID, - version: PLUGIN_VERSION, - ...plugin(pluginConfiguration) -}); +import { PLUGIN_ID } from './utils/constants'; +import { PLUGIN_CANVAS_MENU_COMPONENT_ID } from './utils/constants'; +import { polyfillEngineWithCommands, CreativeEngineWithPolyfills } from './utils/polyfills'; +import { + clearPluginMetadata, + fixDuplicateMetadata, + getPluginMetadata, + isDuplicate, + isMetadataConsistent +} from './utils/utils'; -export default Plugin; + +export interface PluginConfiguration { + // uploader ? +} + + + +export { Manifest }; + +export default (pluginConfiguration: PluginConfiguration = {}) => { + return { + id: PLUGIN_ID, + version: PLUGIN_VERSION, + initialize(engine: CreativeEngineWithPolyfills) { + polyfillEngineWithCommands(engine); + console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") + engine.event.subscribe([], async (events) => { + events + .filter((e) => engine.block.isValid(e.block) && engine.block.hasMetadata(e.block, PLUGIN_ID)) + .forEach((e) => { + const id = e.block; + if (e.type === 'Created') { + const metadata = getPluginMetadata(engine, id); + if (isDuplicate(engine, id, metadata)) { + fixDuplicateMetadata(engine, id); + } + } + }); + }); + }, + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + const engine = cesdk.engine as CreativeEngineWithPolyfills; + polyfillEngineWithCommands(engine); + console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") + + engine.event.subscribe([], async (events) => { + events + .filter((e) => engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) + .filter((e) => e.type === 'Updated') + .forEach((e) => { handleUpdateEvent(cesdk, e.block); }); + }); + + + console.info("Registering plugin actions") + Object.keys(commands).forEach((action) => { + console.info(`Registering action: ${action}`) + // @ts-ignore + const func = commands[action]; + engine.polyfill_commands?.registerCommand( + action, + async (params: any) => await func(cesdk, params) + ); + }) + + console.info("Registering plugin I18N translations") + cesdk.setTranslations(i18n); + + console.info("Registering plugin UI components") + Object.keys(ui).forEach((componentId) => { + console.info(`Registering component: ${componentId}`) + // @ts-ignore + const component = ui[componentId] + cesdk.ui.unstable_registerComponent(componentId, component); + }) + + + + // Always prepend the registered component to the canvas menu order. + console.info("Changing canvas menu order") + cesdk.ui.unstable_setCanvasMenuOrder([ + PLUGIN_CANVAS_MENU_COMPONENT_ID, + ...cesdk.ui.unstable_getCanvasMenuOrder() + ]); + }, + + update() { + + }, + + }; +}; + +/** + * Handle every possible state of the vectorization state if the block was + * updated. + */ +async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { + const metadata = getPluginMetadata(cesdk.engine, blockId); + + switch (metadata.status) { + + case 'PROCESSING': + case 'PROCESSED': { + if (!isMetadataConsistent(cesdk.engine, blockId)) { + clearPluginMetadata(cesdk.engine, blockId); + } + break; + } + + default: { + // We do not care about other states + } + } +} diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index fc13d0d..f32117d 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -1,9 +1,12 @@ -export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; -export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; -export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; -export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; -export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` -export const PLUGIN_I18N_TRANSLATIONS = { - en: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vector' } -} -export const PLUGIN_ICON = '@imgly/icons/Vectorize' \ No newline at end of file +import { PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants'; + +export default { + id: PLUGIN_ID, + contributes: { + actions: [ + { + id: PLUGIN_ACTION_VECTORIZE_LABEL, + } + ] + } +} \ No newline at end of file diff --git a/packages/vectorizer/src/plugin.ts b/packages/vectorizer/src/plugin.ts deleted file mode 100644 index c7ea60e..0000000 --- a/packages/vectorizer/src/plugin.ts +++ /dev/null @@ -1,103 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; - -import { PLUGIN_FEATURE_ID, PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest'; - -import { registerUIComponents } from './ui'; - -import { - clearPluginMetadata, - fixDuplicateMetadata, - getPluginMetadata, - isBlockSupported, - isDuplicate, - isMetadataConsistent, - registerAction -} from './utils'; -import { vectorizeAction } from './actions'; - -export interface PluginConfiguration { - // uploader ? -} - -export default (pluginConfiguration: PluginConfiguration = {}) => { - return { - initialize(engine: CreativeEngine) { - engine.event.subscribe([], async (events) => { - events - .filter((e) => engine.block.isValid(e.block) && engine.block.hasMetadata(e.block, PLUGIN_ID)) - .forEach((e) => { - const id = e.block; - if (e.type === 'Created') { - const metadata = getPluginMetadata(engine, id); - if (isDuplicate(engine, id, metadata)) { - fixDuplicateMetadata(engine, id); - } - } - }); - }); - }, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - cesdk.engine.event.subscribe([], async (events) => { - events - .filter((e) => cesdk.engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) - .filter((e) => e.type === 'Updated') - .forEach((e) => { handleUpdateEvent(cesdk, e.block); }); - }); - - - registerAction( - cesdk.engine, - PLUGIN_ACTION_VECTORIZE_LABEL, - async (params: any) => await vectorizeAction(cesdk, params) - ); - - registerUIComponents(cesdk); - - // this is unclear to me. Should it be with the ui components? - enableFeatures(cesdk); - }, - - update() { - - }, - - }; -}; - -/** - * Handle every possible state of the vectorization state if the block was - * updated. - */ -async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { - const metadata = getPluginMetadata(cesdk.engine, blockId); - - switch (metadata.status) { - - case 'PROCESSING': - case 'PROCESSED': { - if (!isMetadataConsistent(cesdk.engine, blockId)) { - clearPluginMetadata(cesdk.engine, blockId); - } - break; - } - - default: { - // We do not care about other states - } - } -} - -// semantics are unclear when reading the function -export function enableFeatures(cesdk: CreativeEditorSDK) { - cesdk.feature.unstable_enable(PLUGIN_FEATURE_ID, ({ engine }) => { - const selectedIds = engine.block.findAllSelected(); - if (selectedIds.length === 0) return false; - - // multiselection case - const allBlocksSupportPlugin = selectedIds - .map((id) => isBlockSupported(engine, id)) - .reduce((val, acc) => val && acc, true); - return allBlocksSupportPlugin - }); -} - diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index fabf579..49472cd 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,82 +1,65 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import { CreativeEngine } from '@cesdk/cesdk-js'; import { - PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, - PLUGIN_CANVAS_MENU_COMPONENT_ID, - PLUGIN_FEATURE_ID, - PLUGIN_ACTION_VECTORIZE_LABEL, - PLUGIN_I18N_TRANSLATIONS, - PLUGIN_ICON -} from './manifest'; -import { - executeAction, - getPluginMetadata, -} from './utils'; - -/** - * Registers the components that can be used to vectorize a block. - */ -export function registerUIComponents(cesdk: CreativeEditorSDK) { - cesdk.setTranslations(PLUGIN_I18N_TRANSLATIONS); - // Always prepend the registered component to the canvas menu order. - cesdk.ui.unstable_setCanvasMenuOrder([ + PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, PLUGIN_CANVAS_MENU_COMPONENT_ID, - ...cesdk.ui.unstable_getCanvasMenuOrder() - ]); - cesdk.ui.unstable_registerComponent( - PLUGIN_CANVAS_MENU_COMPONENT_ID, - ({ builder: { Button }, engine }) => { + PLUGIN_ACTION_VECTORIZE_LABEL, + PLUGIN_ICON +} from './utils/constants'; + +import { + getPluginMetadata, + isBlockSupported, +} from './utils/utils'; +import { CreativeEngineWithPolyfills } from './utils/polyfills'; - // @DanielHauschildt This should better have [blockIds] as a parameter - if (!cesdk.feature.unstable_isEnabled(PLUGIN_FEATURE_ID, { engine })) { return; } +const button = (params: any) => { + const engine = params.engine! as CreativeEngineWithPolyfills + const builder = params.builder! - const selected = engine.block.findAllSelected(); + const selected = engine.block.findAllSelected(); + const isAnyBlockSupported = selected + .reduce((val, acc) => val || isBlockSupported(engine, acc), false) + if (!isAnyBlockSupported) return; - const actions: Array<() => void> = [] + const actions: Array<() => void> = [] - let anyIsLoading = false - let anyHasValidFill = false - let allCurrentProgress = 0 - let allTotalProgress = 0 - for (const id of selected) { - if (!cesdk.engine.block.hasFill(id)) return; - const fillId = cesdk.engine.block.getFill(id); - const fileUri = engine.block.getString(fillId, 'fill/image/imageFileURI'); - const sourceSet = engine.block.getSourceSet( - fillId, - 'fill/image/sourceSet' - ); + let anyIsLoading = false - const metadata = getPluginMetadata(cesdk.engine, id); + let allCurrentProgress = 0 + let allTotalProgress = 1 + for (const id of selected) { + if (!engine.block.hasFill(id)) return; + const metadata = getPluginMetadata(engine, id); const isLoading = metadata.status === 'PROCESSING'; anyIsLoading ||= isLoading; if (isLoading && metadata.progress) { - const { current, total } = metadata.progress; - allTotalProgress += total - allCurrentProgress += current + const { current, total } = metadata.progress; + allTotalProgress += total + allCurrentProgress += current } - const hasValidFill = (sourceSet.length > 0 || fileUri !== '')// const isPendingOrProcessing = metadata.status === 'PENDING' || metadata.status === 'PROCESSING'; - anyHasValidFill ||= hasValidFill; - actions.push(() => executeAction(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) - } + actions.push(() => engine.polyfill_commands?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) + } - const isDisabled = anyIsLoading || !anyHasValidFill; + - const loadingProgress = 0;// (allCurrentProgress / allTotalProgress) * 100; - // console.log((allCurrentProgress / allTotalProgress) * 100) + const loadingProgress = undefined + // console.log((allCurrentProgress / allTotalProgress) * 100) - Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { + builder.Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { label: PLUGIN_ACTION_VECTORIZE_LABEL, icon: PLUGIN_ICON, isActive: false, isLoading: anyIsLoading, - isDisabled, + isDisabled: anyIsLoading, loadingProgress, onClick: () => actions.map(action => action()) - }); - } - ); + }); } + +export default { + [PLUGIN_CANVAS_MENU_COMPONENT_ID]: button +} // end of export default diff --git a/packages/vectorizer/src/cesdk+utils.ts b/packages/vectorizer/src/utils/cesdk+utils.ts similarity index 97% rename from packages/vectorizer/src/cesdk+utils.ts rename to packages/vectorizer/src/utils/cesdk+utils.ts index 61945cb..82fcf7f 100644 --- a/packages/vectorizer/src/cesdk+utils.ts +++ b/packages/vectorizer/src/utils/cesdk+utils.ts @@ -8,8 +8,8 @@ export const createVectorPathBlocks = (engine: CreativeEngine, blocks: any[]) => return id }) - - return engine.block.group(blockIds); + + return blockIds } diff --git a/packages/vectorizer/src/utils/constants.ts b/packages/vectorizer/src/utils/constants.ts new file mode 100644 index 0000000..8933166 --- /dev/null +++ b/packages/vectorizer/src/utils/constants.ts @@ -0,0 +1,8 @@ +export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; +export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; +export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; +export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; +export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` +export const PLUGIN_ICON = '@imgly/icons/Vectorize' + + diff --git a/packages/vectorizer/src/utils/polyfills.ts b/packages/vectorizer/src/utils/polyfills.ts new file mode 100644 index 0000000..399a757 --- /dev/null +++ b/packages/vectorizer/src/utils/polyfills.ts @@ -0,0 +1,31 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; + +export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; + +export type CommandType = (params: any) => Promise; + +export class Commands { + #engine: CreativeEngineWithPolyfills + #entries = new Map() + constructor(engine: CreativeEngineWithPolyfills) { + this.#engine = engine; + } + registerCommand(label: string, callback: (params: any) => Promise) { + this.#entries.set(label, callback); + } + async executeCommand(label: string, params: any) { + const command = this.#entries.get(label); + if (command) { + await command(params); + } else { + throw new Error(`Command ${label} not found`); + } + } + +} +export function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills) { + //polyfill + if (!engine.polyfill_commands) { + engine.polyfill_commands = new Commands(engine); + } +} \ No newline at end of file diff --git a/packages/vectorizer/src/types.ts b/packages/vectorizer/src/utils/types.ts similarity index 100% rename from packages/vectorizer/src/types.ts rename to packages/vectorizer/src/utils/types.ts diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils/utils.ts similarity index 93% rename from packages/vectorizer/src/utils.ts rename to packages/vectorizer/src/utils/utils.ts index 2fe9940..ad1dd0a 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils/utils.ts @@ -1,7 +1,7 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import isEqual from 'lodash/isEqual'; -import { PLUGIN_ID } from './manifest'; +import { PLUGIN_ID } from './constants'; import { PluginMetadata, PluginStatusError, @@ -17,6 +17,10 @@ import { * @returns A boolean indicating whether the block is supported or not. */ export const isBlockSupported = (engine: CreativeEngine, blockId: number) => { + const blockType = engine.block.getType(blockId); + if (blockType === "//ly.img.ubq/page") return false; // There is some bug with the page block + return true; + if (engine.block.hasFill(blockId)) { const fillId = engine.block.getFill(blockId); const fillType = engine.block.getType(fillId); @@ -284,21 +288,12 @@ export class Scheduler { } - - -type ActionType = (params: any) => Promise; -const actions: Map = new Map(); - -export function registerAction(engine: CreativeEngine, label: string, callback: (params: any) => Promise) { - engine - actions.set(label, callback); -} - -export async function executeAction(label: string, params: any) { - const action = actions.get(label); - if (action) { - await action(params); - } -} -// @ts-ignore -globalThis.cesdk_actions = actions; // for debugging \ No newline at end of file +/** + * Generates a unique filename. + * @returns A string representing the unique filename. + */ +export function generateUniqueFilename(): string { + const timestamp = Date.now(); + const randomString = Math.random().toString(36).substring(2, 8); + return `${timestamp}_${randomString}`; +} \ No newline at end of file diff --git a/packages/vectorizer/src/worker.shared.ts b/packages/vectorizer/src/utils/worker.shared.ts similarity index 62% rename from packages/vectorizer/src/worker.shared.ts rename to packages/vectorizer/src/utils/worker.shared.ts index cb59d09..fa09338 100644 --- a/packages/vectorizer/src/worker.shared.ts +++ b/packages/vectorizer/src/utils/worker.shared.ts @@ -1,14 +1,15 @@ export interface MessageBody { - method?: string, + method: 'health' | 'imageToJson' | 'imageToSvg' data?: any; error?: Error } -// -export const runInWorker = (uri: string) => new Promise((resolve, reject) => { + +export const runInWorker = (blob: Blob) => new Promise((resolve, reject) => { const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); - worker.postMessage({ data: uri }) + const msg: MessageBody = { method: "imageToJson", data: blob } + worker.postMessage(msg) worker.onmessage = (e: MessageEvent) => { const msg = e.data if (msg.error) { diff --git a/packages/vectorizer/src/worker.ts b/packages/vectorizer/src/worker.ts index c1f8a05..8fd1eab 100644 --- a/packages/vectorizer/src/worker.ts +++ b/packages/vectorizer/src/worker.ts @@ -1,29 +1,34 @@ -import type { MessageBody } from "./worker.shared"; +import type { MessageBody } from "./utils/worker.shared"; import * as vectorizer from '@imgly/vectorizer'; self.onmessage = async function (e: MessageEvent) { - const msg = e.data;0 - const data = msg.data ?? {} - const method = msg.method ?? '' // default to empty string - switch (method) { - case "health": { - postMessage({ data: 'ok' }) - break; - } - case "imageToSvg": - default: { - const uriToProcess = data; - try { - const res = await fetch(uriToProcess) - const blob = await res.blob() - // const svg = await vectorizer.imageToSvg(blob) - // postMessage({ data: svg }); - const json = await vectorizer.imageToJson(blob) - postMessage({ data: json }); - } catch (err) { - postMessage({ error: err }); + try { + const msg = e.data; 0 + const data = msg.data ?? {} + const method = msg.method ?? '' // default to empty string + switch (method) { + case "health": { + postMessage({ data: 'ok' }) + break; } + case "imageToJson": + { + const json = await vectorizer.imageToJson(data) + postMessage({ data: json }); + break; + } + case "imageToSvg": + { + const svg = await vectorizer.imageToSvg(data) + postMessage({ data: svg }); + + break; + } + default: + postMessage({ error: new Error("Unknown method") }); } + } catch (err) { + postMessage({ error: err }); } } \ No newline at end of file diff --git a/packages/vectorizer/types/actions.d.ts b/packages/vectorizer/types/actions.d.ts index 846f990..03d9ba2 100644 --- a/packages/vectorizer/types/actions.d.ts +++ b/packages/vectorizer/types/actions.d.ts @@ -1,10 +1,7 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; -/** - * Apply the vectorization process to the image. - */ -/** - * Triggers the vectiorize process. - */ -export declare function vectorizeAction(cesdk: CreativeEditorSDK, params: { - blockId: number; -}): Promise; +declare const _default: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { + blockId: number; + }) => Promise; +}; +export default _default; diff --git a/packages/vectorizer/types/commands.d.ts b/packages/vectorizer/types/commands.d.ts new file mode 100644 index 0000000..03d9ba2 --- /dev/null +++ b/packages/vectorizer/types/commands.d.ts @@ -0,0 +1,7 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +declare const _default: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { + blockId: number; + }) => Promise; +}; +export default _default; diff --git a/packages/vectorizer/types/i18n.d.ts b/packages/vectorizer/types/i18n.d.ts new file mode 100644 index 0000000..c1327c7 --- /dev/null +++ b/packages/vectorizer/types/i18n.d.ts @@ -0,0 +1,15 @@ +export declare const en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; +}; +export declare const de: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; +}; +declare const _default: { + de: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; + en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; +}; +export default _default; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index c8f1c82..86eedf9 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -1,11 +1,16 @@ -import { type PluginConfiguration } from './plugin'; -declare const Plugin: (pluginConfiguration?: PluginConfiguration) => { - initialize(engine: import("@cesdk/cesdk-js").CreativeEngine): void; +import CreativeEditorSDK from '@cesdk/cesdk-js'; +import Manifest from './manifest'; +import { CreativeEngineWithPolyfills } from './utils/polyfills'; +export interface PluginConfiguration { +} +export { Manifest }; +declare const _default: (pluginConfiguration?: PluginConfiguration) => { + id: string; + version: string; + initialize(engine: CreativeEngineWithPolyfills): void; initializeUserInterface({ cesdk }: { - cesdk: import("@cesdk/cesdk-js").default; + cesdk: CreativeEditorSDK; }): void; update(): void; - name: string; - version: string; }; -export default Plugin; +export default _default; diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts index 1ff734b..c4400b4 100644 --- a/packages/vectorizer/types/manifest.d.ts +++ b/packages/vectorizer/types/manifest.d.ts @@ -1,11 +1,9 @@ -export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; -export declare const PLUGIN_CANVAS_MENU_COMPONENT_ID = "@imgly/plugin-vectorizer-web.canvasMenu"; -export declare const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = "@imgly/plugin-vectorizer-web.canvasMenu.button"; -export declare const PLUGIN_FEATURE_ID = "@imgly/plugin-vectorizer-web"; -export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; -export declare const PLUGIN_I18N_TRANSLATIONS: { - en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; +declare const _default: { + id: string; + contributes: { + actions: { + id: string; + }[]; }; }; -export declare const PLUGIN_ICON = "@imgly/icons/Vectorize"; +export default _default; diff --git a/packages/vectorizer/types/manitfest.d.ts b/packages/vectorizer/types/manitfest.d.ts new file mode 100644 index 0000000..c4400b4 --- /dev/null +++ b/packages/vectorizer/types/manitfest.d.ts @@ -0,0 +1,9 @@ +declare const _default: { + id: string; + contributes: { + actions: { + id: string; + }[]; + }; +}; +export default _default; diff --git a/packages/vectorizer/types/proposal/actions.d.ts b/packages/vectorizer/types/proposal/actions.d.ts new file mode 100644 index 0000000..03d9ba2 --- /dev/null +++ b/packages/vectorizer/types/proposal/actions.d.ts @@ -0,0 +1,7 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +declare const _default: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { + blockId: number; + }) => Promise; +}; +export default _default; diff --git a/packages/vectorizer/types/proposal/i18n.d.ts b/packages/vectorizer/types/proposal/i18n.d.ts new file mode 100644 index 0000000..c1327c7 --- /dev/null +++ b/packages/vectorizer/types/proposal/i18n.d.ts @@ -0,0 +1,15 @@ +export declare const en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; +}; +export declare const de: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; +}; +declare const _default: { + de: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; + en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; +}; +export default _default; diff --git a/packages/vectorizer/types/proposal/manitfest.d.ts b/packages/vectorizer/types/proposal/manitfest.d.ts new file mode 100644 index 0000000..4c0f97c --- /dev/null +++ b/packages/vectorizer/types/proposal/manitfest.d.ts @@ -0,0 +1,6 @@ +export declare const id = "@imgly/plugin-vectorizer-web"; +export declare const contributes: { + actions: { + id: string; + }[]; +}; diff --git a/packages/vectorizer/types/proposal/ui.d.ts b/packages/vectorizer/types/proposal/ui.d.ts new file mode 100644 index 0000000..2a7467d --- /dev/null +++ b/packages/vectorizer/types/proposal/ui.d.ts @@ -0,0 +1,4 @@ +declare const _default: { + "@imgly/plugin-vectorizer-web.canvasMenu": (params: any) => void; +}; +export default _default; diff --git a/packages/vectorizer/types/proposal/worker.d.ts b/packages/vectorizer/types/proposal/worker.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/packages/vectorizer/types/proposal/worker.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts index 23aa594..2a7467d 100644 --- a/packages/vectorizer/types/ui.d.ts +++ b/packages/vectorizer/types/ui.d.ts @@ -1,5 +1,4 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -/** - * Registers the components that can be used to vectorize a block. - */ -export declare function registerUIComponents(cesdk: CreativeEditorSDK): void; +declare const _default: { + "@imgly/plugin-vectorizer-web.canvasMenu": (params: any) => void; +}; +export default _default; diff --git a/packages/vectorizer/types/utils.d.ts b/packages/vectorizer/types/utils.d.ts index 18d9e45..7a389e0 100644 --- a/packages/vectorizer/types/utils.d.ts +++ b/packages/vectorizer/types/utils.d.ts @@ -1,5 +1,5 @@ import { CreativeEngine } from '@cesdk/cesdk-js'; -import { PluginMetadata } from './types'; +import { PluginMetadata } from './utils/types'; /** * Checks if a block is supported by the given CreativeEngine. * @param engine - The CreativeEngine instance. diff --git a/packages/vectorizer/types/utils/cesdk+utils.d.ts b/packages/vectorizer/types/utils/cesdk+utils.d.ts new file mode 100644 index 0000000..bb1aa1d --- /dev/null +++ b/packages/vectorizer/types/utils/cesdk+utils.d.ts @@ -0,0 +1,3 @@ +import { CreativeEngine } from "@cesdk/cesdk-js"; +export declare const createVectorPathBlocks: (engine: CreativeEngine, blocks: any[]) => number; +export declare const createVectorPathBlock: (engine: CreativeEngine, block: any) => number; diff --git a/packages/vectorizer/types/utils/constants.d.ts b/packages/vectorizer/types/utils/constants.d.ts new file mode 100644 index 0000000..32b989f --- /dev/null +++ b/packages/vectorizer/types/utils/constants.d.ts @@ -0,0 +1,6 @@ +export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_CANVAS_MENU_COMPONENT_ID = "@imgly/plugin-vectorizer-web.canvasMenu"; +export declare const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = "@imgly/plugin-vectorizer-web.canvasMenu.button"; +export declare const PLUGIN_FEATURE_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; +export declare const PLUGIN_ICON = "@imgly/icons/Vectorize"; diff --git a/packages/vectorizer/types/utils/polyfills.d.ts b/packages/vectorizer/types/utils/polyfills.d.ts new file mode 100644 index 0000000..ad9669b --- /dev/null +++ b/packages/vectorizer/types/utils/polyfills.d.ts @@ -0,0 +1,12 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; +export type CreativeEngineWithPolyfills = CreativeEngine & { + polyfill_commands?: Commands; +}; +export type CommandType = (params: any) => Promise; +export declare class Commands { + #private; + constructor(engine: CreativeEngineWithPolyfills); + registerCommand(label: string, callback: (params: any) => Promise): void; + executeCommand(label: string, params: any): Promise; +} +export declare function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills): void; diff --git a/packages/vectorizer/types/utils/supports.d.ts b/packages/vectorizer/types/utils/supports.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/types/utils/types.d.ts b/packages/vectorizer/types/utils/types.d.ts new file mode 100644 index 0000000..c00d57f --- /dev/null +++ b/packages/vectorizer/types/utils/types.d.ts @@ -0,0 +1,34 @@ +import { type Source } from '@cesdk/cesdk-js'; +export type PluginStatusIdle = { + status: 'IDLE'; +}; +export type PluginStatusProcessing = { + version: string; + status: 'PROCESSING'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; + progress?: { + key: string; + current: number; + total: number; + }; +}; +export type PluginStatusProcessed = { + version: string; + status: 'PROCESSED'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; +}; +export type PluginStatusError = { + version: string; + status: 'ERROR'; + initialImageFileURI: string; + initialSourceSet: Source[]; + blockId: number; + fillId: number; +}; +export type PluginMetadata = PluginStatusIdle | PluginStatusError | PluginStatusProcessing | PluginStatusProcessed; diff --git a/packages/vectorizer/types/utils/utils.d.ts b/packages/vectorizer/types/utils/utils.d.ts new file mode 100644 index 0000000..5afc33d --- /dev/null +++ b/packages/vectorizer/types/utils/utils.d.ts @@ -0,0 +1,50 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; +import { PluginMetadata } from './types'; +/** + * Checks if a block is supported by the given CreativeEngine. + * @param engine - The CreativeEngine instance. + * @param blockId - The ID of the block to check. + * @returns A boolean indicating whether the block is supported or not. + */ +export declare const isBlockSupported: (engine: CreativeEngine, blockId: number) => boolean; +/** + * Sets the metadata for the plugin state. + */ +export declare function setPluginMetadata(engine: CreativeEngine, id: number, metadata: PluginMetadata): void; +/** + * Returns the current metadata for the plugin state. If no metadata + * is set on the given block, it will return an IDLE state. + */ +export declare function getPluginMetadata(engine: CreativeEngine, id: number): PluginMetadata; +/** + * If plugin metadata is set, it will be cleared. + */ +export declare function clearPluginMetadata(engine: CreativeEngine, id: number): void; +/** + * Detect if the block has been duplicated with processed or processing state. + * In that case the plugin state is still valid, but blockId and fillId have changed. + */ +export declare function isDuplicate(engine: CreativeEngine, blockId: number, metadata: PluginMetadata): boolean; +/** + * Fixes the metadata if the block has been duplicated, i.e. the blockId and + * fillId will be updated to the current block/fill. + * + * Please note: Call this method only on duplicates (see isDuplicate). + */ +export declare function fixDuplicateMetadata(engine: CreativeEngine, blockId: number): void; +/** + * Check if the image has a consisten metadata state. A inconsistent state is + * caused by outside changes of the fill data. + * + * @returns true if the metadata is consistent, false otherwise + */ +export declare function isMetadataConsistent(engine: CreativeEngine, blockId: number): boolean; +/** + * Recover the initial values to avoid the loading spinner and have the same + * state as before the process was started. + */ +export declare function recoverInitialImageData(engine: CreativeEngine, blockId: number): void; +export declare class Scheduler { + #private; + schedule(task: () => Promise): Promise; +} diff --git a/packages/vectorizer/types/utils/worker.shared.d.ts b/packages/vectorizer/types/utils/worker.shared.d.ts new file mode 100644 index 0000000..4f39759 --- /dev/null +++ b/packages/vectorizer/types/utils/worker.shared.d.ts @@ -0,0 +1,6 @@ +export interface MessageBody { + method: 'health' | 'imageToJson' | 'imageToSvg'; + data?: any; + error?: Error; +} +export declare const runInWorker: (uri: string) => Promise; diff --git a/yarn.lock b/yarn.lock index b02c2b9..930c7f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -377,6 +377,19 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz" integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== +"@headlessui/react@^1.6.4": + version "1.7.18" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.18.tgz#30af4634d2215b2ca1aa29d07f33d02bea82d9d7" + integrity sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ== + dependencies: + "@tanstack/react-virtual" "^3.0.0-beta.60" + client-only "^0.0.1" + +"@heroicons/react@^2.0.13": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.1.tgz#422deb80c4d6caf3371aec6f4bee8361a354dc13" + integrity sha512-JyyN9Lo66kirbCMuMMRPtJxtKJoIsXKS569ebHGGRKbl8s4CtUfLnyKJxteA+vIKySocO4s1SkTkGS4xtG/yEA== + "@humanwhocodes/config-array@^0.11.13": version "0.11.14" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" @@ -460,6 +473,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" @@ -834,6 +855,18 @@ "@sigstore/core" "^0.2.0" "@sigstore/protobuf-specs" "^0.2.1" +"@tanstack/react-virtual@^3.0.0-beta.60": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.0.4.tgz#32a90aa6faa2eeebb5f4ca561d26bae9f3435e45" + integrity sha512-tiqKW/e2MJVCr7/pRUXulpkyxllaOclkHNfhKTo4pmHjJIqnhMfwIjc1Q1R0Un3PI3kQywywu/791c8z9u0qeA== + dependencies: + "@tanstack/virtual-core" "3.0.0" + +"@tanstack/virtual-core@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz#637bee36f0cabf96a1d436887c90f138a7e9378b" + integrity sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg== + "@tufjs/canonical-json@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" @@ -885,6 +918,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -1067,7 +1105,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: +acorn@^8.8.2, acorn@^8.9.0: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== @@ -1293,6 +1331,11 @@ binary-extensions@^2.2.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1325,6 +1368,11 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + builtins@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -1365,6 +1413,14 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + caniuse-lite@^1.0.30001580: version "1.0.30001584" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz#5e3ea0625d048d5467670051687655b1f7bf7dfd" @@ -1409,6 +1465,13 @@ cidr-regex@4.0.3: dependencies: ip-regex "^5.0.0" +clean-css@^5.2.2: + version "5.3.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" + integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg== + dependencies: + source-map "~0.6.0" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1431,6 +1494,11 @@ cli-table3@^0.6.3: optionalDependencies: "@colors/colors" "1.5.0" +client-only@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + cliui@^8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" @@ -1487,6 +1555,16 @@ columnify@^1.6.0: strip-ansi "^6.0.1" wcwidth "^1.0.0" +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + common-ancestor-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7" @@ -1536,6 +1614,22 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-what@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -1634,6 +1728,51 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -1668,6 +1807,11 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -2401,6 +2545,11 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.1.tgz#9985fcb2700467fecf7f33a4d4874e30680b5322" @@ -2408,6 +2557,40 @@ hosted-git-info@^7.0.0, hosted-git-info@^7.0.1: dependencies: lru-cache "^10.0.1" +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-webpack-plugin@^5.5.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0" + integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -3004,7 +3187,7 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.21, lodash@~4.17.0: +lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3021,6 +3204,13 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": version "10.2.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" @@ -3219,6 +3409,14 @@ negotiator@^0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + node-gyp@^10.0.0, node-gyp@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" @@ -3427,6 +3625,13 @@ npmlog@^7.0.1: gauge "^5.0.0" set-blocking "^2.0.0" +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -3605,6 +3810,14 @@ pacote@^17.0.0, pacote@^17.0.4, pacote@^17.0.6: ssri "^10.0.0" tar "^6.1.11" +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" @@ -3621,6 +3834,14 @@ parse-conflict-json@^3.0.0, parse-conflict-json@^3.0.1: just-diff "^6.0.0" just-diff-apply "^5.2.0" +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -3706,6 +3927,14 @@ prettier@^2.8.5: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + pretty-quick@^3.1.3: version "3.3.1" resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-3.3.1.tgz#cfde97fec77a8d201a0e0c9c71d9990e12587ee2" @@ -3804,6 +4033,15 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +react-cmdk@^1.3.9: + version "1.3.9" + resolved "https://registry.yarnpkg.com/react-cmdk/-/react-cmdk-1.3.9.tgz#77123f5120a47e35a517a8176550e96731667654" + integrity sha512-MSVmAQZ9iqY7hO3r++XP6yWSHzGfMDGMvY3qlDT8k5RiWoRFwO1CGPlsWzhvcUbPilErzsMKK7uB4McEcX4B6g== + dependencies: + "@headlessui/react" "^1.6.4" + "@heroicons/react" "^2.0.13" + html-webpack-plugin "^5.5.0" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -3886,6 +4124,22 @@ regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: define-properties "^1.2.0" set-function-name "^2.0.0" +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" @@ -4117,6 +4371,19 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + spawn-command@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" @@ -4291,6 +4558,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tapable@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tar@^6.1.11, tar@^6.1.2, tar@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" @@ -4303,6 +4575,16 @@ tar@^6.1.11, tar@^6.1.2, tar@^6.2.0: mkdirp "^1.0.3" yallist "^4.0.0" +terser@^5.10.0: + version "5.27.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.27.0.tgz#70108689d9ab25fef61c4e93e808e9fd092bf20c" + integrity sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" @@ -4350,7 +4632,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.1.0, tslib@^2.6.2: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -4516,6 +4798,11 @@ util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== + validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From 4cddfea6c37b0e92e40c80655bb0480c66c10c01 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sun, 11 Feb 2024 01:53:29 +0100 Subject: [PATCH 11/32] wip: simplification and generalization #2 --- packages/vectorizer/src/commands.ts | 1 + packages/vectorizer/src/index.ts | 15 ++++---- packages/vectorizer/src/ui.ts | 43 +++++----------------- packages/vectorizer/src/utils/constants.ts | 2 +- packages/vectorizer/src/utils/utils.ts | 2 +- 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts index fda9ba7..ebe9246 100644 --- a/packages/vectorizer/src/commands.ts +++ b/packages/vectorizer/src/commands.ts @@ -160,6 +160,7 @@ const vectorize = async (cesdk: CreativeEditorSDK, params: { blockId: number }) const origX = engine.block.getPositionX(blockId) const origY = engine.block.getPositionY(blockId) const origSelected = engine.block.isSelected(blockId) + switch (engine.block.getType(blockId)) { case "//ly.img.ubq/page": { diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index 8af3fdb..aafe740 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -21,8 +21,6 @@ export interface PluginConfiguration { // uploader ? } - - export { Manifest }; export default (pluginConfiguration: PluginConfiguration = {}) => { @@ -30,6 +28,10 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { id: PLUGIN_ID, version: PLUGIN_VERSION, initialize(engine: CreativeEngineWithPolyfills) { + + }, + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + const engine = cesdk.engine as CreativeEngineWithPolyfills; polyfillEngineWithCommands(engine); console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") engine.event.subscribe([], async (events) => { @@ -45,10 +47,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { } }); }); - }, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - const engine = cesdk.engine as CreativeEngineWithPolyfills; - polyfillEngineWithCommands(engine); + console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") engine.event.subscribe([], async (events) => { @@ -81,8 +80,6 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { cesdk.ui.unstable_registerComponent(componentId, component); }) - - // Always prepend the registered component to the canvas menu order. console.info("Changing canvas menu order") cesdk.ui.unstable_setCanvasMenuOrder([ @@ -91,6 +88,8 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { ]); }, + + // maybe this should be just engint.event.onUpdate() update() { }, diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 49472cd..a183974 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,7 +1,5 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; - import { - PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, + PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_CANVAS_MENU_COMPONENT_ID, PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_ICON @@ -18,45 +16,24 @@ const button = (params: any) => { const builder = params.builder! const selected = engine.block.findAllSelected(); - const isAnyBlockSupported = selected - .reduce((val, acc) => val || isBlockSupported(engine, acc), false) - if (!isAnyBlockSupported) return; - - const actions: Array<() => void> = [] - - let anyIsLoading = false - - let allCurrentProgress = 0 - let allTotalProgress = 1 + const candidates = selected.filter(id => isBlockSupported(engine, id)) + if (candidates.length === 0) return; - - for (const id of selected) { - if (!engine.block.hasFill(id)) return; + let isLoading = candidates.some(id => { const metadata = getPluginMetadata(engine, id); - const isLoading = metadata.status === 'PROCESSING'; - anyIsLoading ||= isLoading; - if (isLoading && metadata.progress) { - const { current, total } = metadata.progress; - allTotalProgress += total - allCurrentProgress += current - } - - actions.push(() => engine.polyfill_commands?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) - } - + return metadata.status === 'PROCESSING' + }) - const loadingProgress = undefined - // console.log((allCurrentProgress / allTotalProgress) * 100) - builder.Button(PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID, { + builder.Button(PLUGIN_COMPONENT_BUTTON_ID, { label: PLUGIN_ACTION_VECTORIZE_LABEL, icon: PLUGIN_ICON, isActive: false, - isLoading: anyIsLoading, - isDisabled: anyIsLoading, + isLoading: isLoading, + isDisabled: isLoading, loadingProgress, - onClick: () => actions.map(action => action()) + onClick: () => candidates.forEach(id => engine.polyfill_commands?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) }); } diff --git a/packages/vectorizer/src/utils/constants.ts b/packages/vectorizer/src/utils/constants.ts index 8933166..2bf91fb 100644 --- a/packages/vectorizer/src/utils/constants.ts +++ b/packages/vectorizer/src/utils/constants.ts @@ -1,6 +1,6 @@ export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; -export const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; +export const PLUGIN_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` export const PLUGIN_ICON = '@imgly/icons/Vectorize' diff --git a/packages/vectorizer/src/utils/utils.ts b/packages/vectorizer/src/utils/utils.ts index ad1dd0a..d0c914d 100644 --- a/packages/vectorizer/src/utils/utils.ts +++ b/packages/vectorizer/src/utils/utils.ts @@ -19,8 +19,8 @@ import { export const isBlockSupported = (engine: CreativeEngine, blockId: number) => { const blockType = engine.block.getType(blockId); if (blockType === "//ly.img.ubq/page") return false; // There is some bug with the page block - return true; + if (engine.block.hasFill(blockId)) { const fillId = engine.block.getFill(blockId); const fillType = engine.block.getType(fillId); From 5289b4a1cce42fc87699eb8d136fc7e47470b58a Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 10:07:01 +0100 Subject: [PATCH 12/32] wip: Polyfill experiements --- TODO.md | 18 +- examples/web/package.json | 3 +- examples/web/src/App.tsx | 49 ++- examples/web/src/CommandPalette.tsx | 24 +- examples/web/src/addPlugins.ts | 8 +- package.json | 5 +- packages/background-removal/package.json | 3 +- .../src/registerComponents.ts | 1 + packages/polyfill-commands/LICENSE.md | 1 + packages/polyfill-commands/README.md | 40 +++ packages/polyfill-commands/STRUCTURE.md | 1 + .../TODO.md} | 0 packages/polyfill-commands/esbuild/config.mjs | 58 ++++ .../polyfill-commands/esbuild/global.d.ts | 3 + packages/polyfill-commands/package.json | 66 ++++ packages/polyfill-commands/scripts/build.mjs | 5 + packages/polyfill-commands/scripts/watch.mjs | 19 ++ packages/polyfill-commands/src/index.ts | 33 ++ packages/polyfill-commands/src/manifest.ts | 4 + .../polyfill-commands/src/utils/polyfills.ts | 31 ++ packages/polyfill-commands/src/worker.ts | 0 packages/polyfill-commands/tsconfig.json | 16 + .../types/index.d.ts} | 8 +- .../polyfill-commands/types/manifest.d.ts | 4 + .../types/utils/polyfills.d.ts | 12 + packages/polyfill-commands/types/worker.d.ts | 0 packages/vectorizer/package.json | 6 +- packages/vectorizer/src/commands.ts | 301 +++++++++--------- packages/vectorizer/src/defaults.ts | 0 packages/vectorizer/src/i18n.ts | 2 +- packages/vectorizer/src/index.ts | 81 +++-- packages/vectorizer/src/manifest.ts | 14 +- packages/vectorizer/src/ui.ts | 30 +- packages/vectorizer/src/{utils => }/utils.ts | 19 +- packages/vectorizer/src/utils/constants.ts | 8 - packages/vectorizer/src/utils/polyfills.ts | 8 +- .../vectorizer/src/utils/worker.shared.ts | 5 +- packages/vectorizer/types/actions.d.ts | 7 - packages/vectorizer/types/cesdk+utils.d.ts | 3 - packages/vectorizer/types/commands.d.ts | 2 +- packages/vectorizer/types/defaults.d.ts | 0 packages/vectorizer/types/manifest.d.ts | 8 +- packages/vectorizer/types/manitfest.d.ts | 9 - .../vectorizer/types/proposal/actions.d.ts | 7 - packages/vectorizer/types/proposal/i18n.d.ts | 15 - .../vectorizer/types/proposal/manitfest.d.ts | 6 - packages/vectorizer/types/proposal/ui.d.ts | 4 - .../vectorizer/types/proposal/worker.d.ts | 1 - packages/vectorizer/types/types.d.ts | 34 -- packages/vectorizer/types/ui.d.ts | 2 +- packages/vectorizer/types/utils.d.ts | 8 +- .../vectorizer/types/utils/cesdk+utils.d.ts | 2 +- .../vectorizer/types/utils/constants.d.ts | 4 +- .../vectorizer/types/utils/polyfills.d.ts | 2 +- packages/vectorizer/types/utils/utils.d.ts | 6 + .../vectorizer/types/utils/worker.shared.d.ts | 2 +- packages/vectorizer/types/worker.shared.d.ts | 6 - yarn.lock | 7 +- 58 files changed, 643 insertions(+), 378 deletions(-) create mode 100644 packages/polyfill-commands/LICENSE.md create mode 100644 packages/polyfill-commands/README.md create mode 100644 packages/polyfill-commands/STRUCTURE.md rename packages/{vectorizer/types/utils/supports.d.ts => polyfill-commands/TODO.md} (100%) create mode 100644 packages/polyfill-commands/esbuild/config.mjs create mode 100644 packages/polyfill-commands/esbuild/global.d.ts create mode 100644 packages/polyfill-commands/package.json create mode 100644 packages/polyfill-commands/scripts/build.mjs create mode 100644 packages/polyfill-commands/scripts/watch.mjs create mode 100644 packages/polyfill-commands/src/index.ts create mode 100644 packages/polyfill-commands/src/manifest.ts create mode 100644 packages/polyfill-commands/src/utils/polyfills.ts create mode 100644 packages/polyfill-commands/src/worker.ts create mode 100644 packages/polyfill-commands/tsconfig.json rename packages/{vectorizer/types/plugin.d.ts => polyfill-commands/types/index.d.ts} (52%) create mode 100644 packages/polyfill-commands/types/manifest.d.ts create mode 100644 packages/polyfill-commands/types/utils/polyfills.d.ts create mode 100644 packages/polyfill-commands/types/worker.d.ts create mode 100644 packages/vectorizer/src/defaults.ts rename packages/vectorizer/src/{utils => }/utils.ts (94%) delete mode 100644 packages/vectorizer/src/utils/constants.ts delete mode 100644 packages/vectorizer/types/actions.d.ts delete mode 100644 packages/vectorizer/types/cesdk+utils.d.ts create mode 100644 packages/vectorizer/types/defaults.d.ts delete mode 100644 packages/vectorizer/types/manitfest.d.ts delete mode 100644 packages/vectorizer/types/proposal/actions.d.ts delete mode 100644 packages/vectorizer/types/proposal/i18n.d.ts delete mode 100644 packages/vectorizer/types/proposal/manitfest.d.ts delete mode 100644 packages/vectorizer/types/proposal/ui.d.ts delete mode 100644 packages/vectorizer/types/proposal/worker.d.ts delete mode 100644 packages/vectorizer/types/types.d.ts delete mode 100644 packages/vectorizer/types/worker.shared.d.ts diff --git a/TODO.md b/TODO.md index cea5d94..eda1223 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,13 @@ -- ? How can I list all plugins that are active -- ? How can I deactivate a plugin -- ? we should pass the PluginContext with seperate `{engine?: ImglyEngine, editor?: ImglyEditor, ui?: ImglyUI` - -- `feature.isEnabled` should be feature.isEnabledFor(blockId) -> test for multiple blockIds at once +- [ ] How can I list all plugins that are active +- [ ] How can I deactivate a plugin later completely? `enableFeatures`, but this must be per "command". A plugin might contribute multiple features? +- [ ] we should pass the PluginContext with separate `imgly: {engine?: ImglyEngine, editor?: ImglyEditor, ui?: ImglyUI` +- [ ] We can already establish the name 'imgly" for the PLUGINS +- [ ] `unstable_getCanvasMenuOrder` should maybe be called `unstable_getCanvasMenuEntries` +- [ ] `unstable_setCanvasMenuOrder` should maybe be called `unstable_setCanvasMenuEntries` +- [ ] `unstable_enableFeatures` what is it used for. the button is not displayed when I check it internally +- [ ] `unstable_enableFeatures` should get the blocks it should evaluate it for. It's not always the selected ones in every scenario. +- [ ] `enable_features` could probably better be named `enableFeatureInContext()` +- [ ] What is the intention of the `builder.Button` first parameter, where is the id used later? +- [ ] (Exkurs) How can I change the type of a block to another. E.g. Change a Graphic Block into a Group Block for Vectorizer and the ID should stay the same and all properties that are relevant. "Turn into" +- [ ] The separation of ui and engine is sometimes too hard to use. I propose not to make it dependent on initUI and init. But more like lifecycles in general and always pass {ui?, engine, editor} +- [ ] `upload` should maybe be part of the asset sources and/or part of engine diff --git a/examples/web/package.json b/examples/web/package.json index 65353aa..bba735c 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -14,7 +14,8 @@ "@imgly/plugin-vectorizer-web": "*", "react": "^18.2.0", "react-cmdk": "^1.3.9", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "share-api-polyfill": "^1.1.1" }, "devDependencies": { "@types/react": "^18.2.43", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index bf44e1c..e459b7d 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -3,27 +3,52 @@ import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin, { Manifest as VectorizerManifest } from '@imgly/plugin-vectorizer-web'; -import { ActionsMenu } from "./CommandPalette" +import { CommandPalette } from "./CommandPalette" +import 'share-api-polyfill'; const plugins = [VectorizerPlugin(), BackgroundRemovalPlugin()] +function downloadBlob(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + link.click(); + URL.revokeObjectURL(url); +} + +const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string, pages?: number[] }) => { + const postfix = options.mimeType.split("/")[1] + const pageIds = options.pages ?? [] + blobs.forEach((blob, index) => { + const pageId = pageIds[index] + let pageName = `page-${index}` + if (pageId) { + const name = cesdk.engine.block.getName(pageId) + pageName = name?.length ? name : pageName + } + const filename = `${pageName}.${postfix}`; + downloadBlob(blob, filename); + }) + return Promise.resolve(); +} function App() { const cesdk = useRef(); const config: Configuration = { license: import.meta.env.VITE_CESDK_LICENSE_KEY, - callbacks: { + callbacks: { onUpload: "local", onDownload: "download", - onSave: (s) => { - console.log("Save", s); - return Promise.resolve(); - }, - onExport: (blobs, options) => { - // why does this only export 1 page - console.log("Export", blobs, options); - return Promise.resolve(); + onSave: async (str: string) => { + // improve + return downloadBlocks(cesdk.current!, [new Blob([str])], { mimeType: 'application/imgly' }) + }, + + onExport: async (blobs, options) => { + return downloadBlocks(cesdk.current!, blobs, { mimeType: options.mimeType, pages: options.pages }) + }, onLoad: "upload", }, @@ -41,7 +66,7 @@ function App() { save: true, load: true, export: true, - share: true, + // share: true, } } } @@ -51,7 +76,7 @@ function App() { return ( <> - +
{ diff --git a/examples/web/src/CommandPalette.tsx b/examples/web/src/CommandPalette.tsx index 4252e57..e33087c 100644 --- a/examples/web/src/CommandPalette.tsx +++ b/examples/web/src/CommandPalette.tsx @@ -1,10 +1,10 @@ import "react-cmdk/dist/cmdk.css"; -import CommandPalette, { filterItems, getItemIndex } from "react-cmdk"; +import CMDK , { filterItems, getItemIndex } from "react-cmdk"; import { useState, useEffect, RefObject } from "react"; import CreativeEditorSDK from "@cesdk/cesdk-js"; // https://github.com/albingroen/react-cmdk -export const ActionsMenu = (params: { cesdkRef: RefObject, actions: Array }) => { +export const CommandPalette = (params: { cesdkRef: RefObject, actions: Array }) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); const [isOpen, setIsOpen] = useState(false); @@ -138,8 +138,8 @@ export const ActionsMenu = (params: { cesdkRef: RefObject { return { id: action.id, @@ -158,32 +158,32 @@ export const ActionsMenu = (params: { cesdkRef: RefObject - + {filteredItems.length ? ( filteredItems.map((list) => ( - + {list.items.map(({ id, ...rest }) => ( - ))} - + )) ) : ( - + )} - + - + ); }; diff --git a/examples/web/src/addPlugins.ts b/examples/web/src/addPlugins.ts index a08ada0..31af477 100644 --- a/examples/web/src/addPlugins.ts +++ b/examples/web/src/addPlugins.ts @@ -1,10 +1,12 @@ import CreativeEditorSDK from '@cesdk/cesdk-js'; - +// import PolyfillCommandsPlugin from "@imgly/plugin-polyfill-commands" import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; -const plugins = [VectorizerPlugin(), BackgroundRemovalPlugin()] - +const plugins = [ + // PolyfillCommandsPlugin(), + VectorizerPlugin(), + BackgroundRemovalPlugin()] async function addPlugins(cesdk: CreativeEditorSDK) { try { diff --git a/package.json b/package.json index 859014b..f18858a 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,9 @@ "name": "imgly-plugins", "version": "0.0.0", "workspaces": [ - "examples/*", - "packages/*" + "examples/web", + "packages/background-removal", + "packages/vectorizer" ], "scripts": { "build": "turbo run build --force", diff --git a/packages/background-removal/package.json b/packages/background-removal/package.json index f27f946..f9ee4f7 100644 --- a/packages/background-removal/package.json +++ b/packages/background-removal/package.json @@ -14,7 +14,7 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/imgly/plugin-background-removal-web.git" + "url": "git+https://github.com/imgly/plugins.git" }, "license": "SEE LICENSE IN LICENSE.md", "author": { @@ -57,7 +57,6 @@ "types:create": "tsc --emitDeclarationOnly" }, "devDependencies": { - "@cesdk/cesdk-js": "~1.20.0", "@types/ndarray": "^1.0.14", "chalk": "^5.3.0", "concurrently": "^8.2.2", diff --git a/packages/background-removal/src/registerComponents.ts b/packages/background-removal/src/registerComponents.ts index ac4039b..a0821bd 100644 --- a/packages/background-removal/src/registerComponents.ts +++ b/packages/background-removal/src/registerComponents.ts @@ -36,6 +36,7 @@ export function registerComponents(cesdk: CreativeEditorSDK) { return; } + // Why is that needed. The feature enable should already handle that const [id] = engine.block.findAllSelected(); if (!cesdk.engine.block.hasFill(id)) return; diff --git a/packages/polyfill-commands/LICENSE.md b/packages/polyfill-commands/LICENSE.md new file mode 100644 index 0000000..a099036 --- /dev/null +++ b/packages/polyfill-commands/LICENSE.md @@ -0,0 +1 @@ +TBD diff --git a/packages/polyfill-commands/README.md b/packages/polyfill-commands/README.md new file mode 100644 index 0000000..e4197b5 --- /dev/null +++ b/packages/polyfill-commands/README.md @@ -0,0 +1,40 @@ +# IMG.LY CE.SDK Plugin Vectorizer + +This plugin introduces a vectorizer for the CE.SDK editor. + +## Installation + +You can install the plugin via npm or yarn. Use the following commands to install the package: + +``` +yarn add @imgly/plugin-vectorizer-web +npm install @imgly/plugin-vectorizer-web +``` + +## Usage + +Adding the plugin to CE.SDK will automatically add a vectorizer +canvas menu entry for every block with an image fill. + +```typescript +import CreativeEditorSDK from '@cesdk/cesdk-js'; +import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; + +const config = { + license: '', + callbacks: { + // Please note that the vectorizer plugin depends on an correctly + // configured upload. 'local' will work for local testing, but in + // production you will need something stable. Please take a look at: + // https://img.ly/docs/cesdk/ui/guides/upload-images/ + onUpload: 'local' + } +}; + +const cesdk = await CreativeEditorSDK.create(container, config); +await cesdk.addDefaultAssetSources(), + await cesdk.addDemoAssetSources({ sceneMode: 'Design' }), + await cesdk.unstable_addPlugin(VectorizerPlugin()); + +await cesdk.createDesignScene(); +``` diff --git a/packages/polyfill-commands/STRUCTURE.md b/packages/polyfill-commands/STRUCTURE.md new file mode 100644 index 0000000..13b1472 --- /dev/null +++ b/packages/polyfill-commands/STRUCTURE.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vectorizer/types/utils/supports.d.ts b/packages/polyfill-commands/TODO.md similarity index 100% rename from packages/vectorizer/types/utils/supports.d.ts rename to packages/polyfill-commands/TODO.md diff --git a/packages/polyfill-commands/esbuild/config.mjs b/packages/polyfill-commands/esbuild/config.mjs new file mode 100644 index 0000000..37b437c --- /dev/null +++ b/packages/polyfill-commands/esbuild/config.mjs @@ -0,0 +1,58 @@ +import chalk from 'chalk'; +import { readFile } from 'fs/promises'; + +// import packageJson from '../package.json' assert { type: 'json' }; +// Avoid the Experimental Feature warning when using the above. +const packageJson = JSON.parse( + await readFile(new URL('../package.json', import.meta.url)) +); + + +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) +const externals = [...dependencies, ...peerDependencies] + +console.log( + chalk.yellow('Building version: '), + chalk.green(packageJson.version) +); + +const configs = [ + { + entryPoints: ['src/index.ts', "src/worker.ts"], + define: { + PLUGIN_VERSION: `"${packageJson.version}"` + }, + minify: true, + bundle: true, + sourcemap: true, + external: externals, + platform: 'node', + format: 'esm', + outdir: 'dist', + outExtension: { '.js': '.mjs' }, + plugins: [ + { + name: 'reporter', + setup(build) { + build.onEnd((result) => { + console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] Build ${ + result.errors.length + ? chalk.red('failed') + : chalk.green('succeeded') + }` + ); + }); + } + } + ] + } +]; + +export default configs; diff --git a/packages/polyfill-commands/esbuild/global.d.ts b/packages/polyfill-commands/esbuild/global.d.ts new file mode 100644 index 0000000..de80fd8 --- /dev/null +++ b/packages/polyfill-commands/esbuild/global.d.ts @@ -0,0 +1,3 @@ +// These constants here are added by the base esbuild config + +declare const PLUGIN_VERSION: string; diff --git a/packages/polyfill-commands/package.json b/packages/polyfill-commands/package.json new file mode 100644 index 0000000..f07b6cc --- /dev/null +++ b/packages/polyfill-commands/package.json @@ -0,0 +1,66 @@ +{ + "name": "@imgly/plugin-polyfill-commands", + "version": "0.1.0", + "description": "Polyfill for Commands plugin for the CE.SDK editor", + "keywords": [ + "CE.SDK", + "plugin", + "polyfill" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/imgly/plugins.git" + }, + "license": "SEE LICENSE IN LICENSE.md", + "author": { + "name": "IMG.LY GmbH", + "email": "support@img.ly", + "url": "https://img.ly" + }, + "bugs": { + "email": "support@img.ly" + }, + "source": "./src/index.ts", + "module": "./dist/index.mjs", + "types": "./types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./types/index.d.ts" + } + }, + "homepage": "https://img.ly", + "files": [ + "LICENSE.md", + "README.md", + "CHANGELOG.md", + "dist/", + "types/", + "bin/" + ], + "scripts": { + "start": "npm run watch", + "clean": "npx rimraf dist && npx rimraf types", + "build": "yarn run types:create && node scripts/build.mjs", + "dev": "yarn run types:create && node scripts/watch.mjs", + "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", + "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", + "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", + "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", + "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", + "check:type": "tsc --noEmit", + "types:create": "tsc --emitDeclarationOnly" + }, + "devDependencies": { + "chalk": "^5.3.0", + "concurrently": "^8.2.2", + "esbuild": "^0.19.11", + "eslint": "^8.51.0", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "@cesdk/cesdk-js": "~1.20.0" + }, + "dependencies": { + } +} diff --git a/packages/polyfill-commands/scripts/build.mjs b/packages/polyfill-commands/scripts/build.mjs new file mode 100644 index 0000000..13d12e1 --- /dev/null +++ b/packages/polyfill-commands/scripts/build.mjs @@ -0,0 +1,5 @@ +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +await Promise.all(configs.map(async (config) => await esbuild.build(config))); diff --git a/packages/polyfill-commands/scripts/watch.mjs b/packages/polyfill-commands/scripts/watch.mjs new file mode 100644 index 0000000..15dbb21 --- /dev/null +++ b/packages/polyfill-commands/scripts/watch.mjs @@ -0,0 +1,19 @@ +import chalk from 'chalk'; +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] ${chalk.green('Watching...')}` +); + +const contexts = await Promise.all( + configs.map((config) => esbuild.context(config)) +); + +await Promise.any(contexts.map((ctx) => ctx.watch())); diff --git a/packages/polyfill-commands/src/index.ts b/packages/polyfill-commands/src/index.ts new file mode 100644 index 0000000..3aed9fb --- /dev/null +++ b/packages/polyfill-commands/src/index.ts @@ -0,0 +1,33 @@ +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; + +import Manifest from './manifest'; + + +import { polyfillEngineWithCommands, CreativeEngineWithPolyfills } from './utils/polyfills'; + + +export interface PluginConfiguration { + // uploader ? +} + +export { Manifest }; + +export default (pluginConfiguration: PluginConfiguration = {}) => { + return { + initialize(engine: CreativeEngineWithPolyfills) { + + }, + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + const engine = cesdk.engine as CreativeEngineWithPolyfills; + polyfillEngineWithCommands(engine); + + }, + + + // maybe this should be just engint.event.onUpdate() + update() { + + }, + + }; +}; diff --git a/packages/polyfill-commands/src/manifest.ts b/packages/polyfill-commands/src/manifest.ts new file mode 100644 index 0000000..0972d63 --- /dev/null +++ b/packages/polyfill-commands/src/manifest.ts @@ -0,0 +1,4 @@ +export default { + id: "@imgly/polyfill-commands", + +} \ No newline at end of file diff --git a/packages/polyfill-commands/src/utils/polyfills.ts b/packages/polyfill-commands/src/utils/polyfills.ts new file mode 100644 index 0000000..399a757 --- /dev/null +++ b/packages/polyfill-commands/src/utils/polyfills.ts @@ -0,0 +1,31 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; + +export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; + +export type CommandType = (params: any) => Promise; + +export class Commands { + #engine: CreativeEngineWithPolyfills + #entries = new Map() + constructor(engine: CreativeEngineWithPolyfills) { + this.#engine = engine; + } + registerCommand(label: string, callback: (params: any) => Promise) { + this.#entries.set(label, callback); + } + async executeCommand(label: string, params: any) { + const command = this.#entries.get(label); + if (command) { + await command(params); + } else { + throw new Error(`Command ${label} not found`); + } + } + +} +export function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills) { + //polyfill + if (!engine.polyfill_commands) { + engine.polyfill_commands = new Commands(engine); + } +} \ No newline at end of file diff --git a/packages/polyfill-commands/src/worker.ts b/packages/polyfill-commands/src/worker.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/polyfill-commands/tsconfig.json b/packages/polyfill-commands/tsconfig.json new file mode 100644 index 0000000..47d465c --- /dev/null +++ b/packages/polyfill-commands/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es2017", + "module": "es2020", + "lib": ["es2018", "dom"], + "moduleResolution": "node", + "isolatedModules": true, + "esModuleInterop": true, + "declaration": true, + "declarationDir": "types/", + "skipLibCheck": true + }, + "include": ["src/**/*", "esbuild/global.d.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/vectorizer/types/plugin.d.ts b/packages/polyfill-commands/types/index.d.ts similarity index 52% rename from packages/vectorizer/types/plugin.d.ts rename to packages/polyfill-commands/types/index.d.ts index 53dc685..7e77099 100644 --- a/packages/vectorizer/types/plugin.d.ts +++ b/packages/polyfill-commands/types/index.d.ts @@ -1,12 +1,14 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; +import CreativeEditorSDK from '@cesdk/cesdk-js'; +import Manifest from './manifest'; +import { CreativeEngineWithPolyfills } from './utils/polyfills'; export interface PluginConfiguration { } +export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { - initialize(engine: CreativeEngine): void; + initialize(engine: CreativeEngineWithPolyfills): void; initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; update(): void; }; export default _default; -export declare function enableFeatures(cesdk: CreativeEditorSDK): void; diff --git a/packages/polyfill-commands/types/manifest.d.ts b/packages/polyfill-commands/types/manifest.d.ts new file mode 100644 index 0000000..e1ead83 --- /dev/null +++ b/packages/polyfill-commands/types/manifest.d.ts @@ -0,0 +1,4 @@ +declare const _default: { + id: string; +}; +export default _default; diff --git a/packages/polyfill-commands/types/utils/polyfills.d.ts b/packages/polyfill-commands/types/utils/polyfills.d.ts new file mode 100644 index 0000000..ad9669b --- /dev/null +++ b/packages/polyfill-commands/types/utils/polyfills.d.ts @@ -0,0 +1,12 @@ +import { CreativeEngine } from '@cesdk/cesdk-js'; +export type CreativeEngineWithPolyfills = CreativeEngine & { + polyfill_commands?: Commands; +}; +export type CommandType = (params: any) => Promise; +export declare class Commands { + #private; + constructor(engine: CreativeEngineWithPolyfills); + registerCommand(label: string, callback: (params: any) => Promise): void; + executeCommand(label: string, params: any): Promise; +} +export declare function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills): void; diff --git a/packages/polyfill-commands/types/worker.d.ts b/packages/polyfill-commands/types/worker.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 89bfd4c..30cfcef 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -10,7 +10,7 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/imgly/plugin-vectorizer-web.git" + "url": "git+https://github.com/imgly/plugins.git" }, "license": "SEE LICENSE IN LICENSE.md", "author": { @@ -30,7 +30,7 @@ "types": "./types/index.d.ts" } }, - "homepage": "https://img.ly/products/creative-sdk", + "homepage": "https://img.ly", "files": [ "LICENSE.md", "README.md", @@ -53,8 +53,6 @@ "types:create": "tsc --emitDeclarationOnly" }, "devDependencies": { - "@cesdk/cesdk-js": "~1.20.0", - "@types/ndarray": "^1.0.14", "chalk": "^5.3.0", "concurrently": "^8.2.2", "esbuild": "^0.19.11", diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts index ebe9246..3f08b4a 100644 --- a/packages/vectorizer/src/commands.ts +++ b/packages/vectorizer/src/commands.ts @@ -1,6 +1,7 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; -import { PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants'; +import { PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest'; + import { getPluginMetadata, @@ -8,163 +9,163 @@ import { isMetadataConsistent, recoverInitialImageData, setPluginMetadata -} from './utils/utils'; + +} from './utils'; import { runInWorker } from './utils/worker.shared'; import { createVectorPathBlocks } from './utils/cesdk+utils'; -const vectorize = async (cesdk: CreativeEditorSDK, params: { blockId: number }) => { + +// FIXME: The vectorize technically does not need image fills, it can vectorize every block by rendering the block and then processing the image +const vectorize = async (cesdk: CreativeEditorSDK, params: { blockIds?: number[] }) => { const uploader = cesdk.unstable_upload.bind(cesdk) const engine = cesdk.engine; // the only function that needs the ui is the upload function const blockApi = engine.block; - let { blockId } = params ?? {}; - if (blockId === undefined) { - const selected = engine.block.findAllSelected() - if (selected.length !== 1) { - return; - } - blockId = selected[0]; - } - const isValid = engine.block.isValid(blockId) - if (!isValid) return - - if (!isBlockSupported(engine, blockId)) return; + // this shouldn't be necessay here + const blockIds = params.blockIds ?? engine.block.findAllSelected(); + blockIds.forEach(async blockId => { + // this should happen before already and only be called if the feature is enabled for a certain block + if (!isBlockSupported(engine, blockId)) return; - if (!blockApi.hasFill(blockId)) - throw new Error('Block has no fill to vectorize'); - const fillId = blockApi.getFill(blockId); + if (!blockApi.hasFill(blockId)) + throw new Error('Block has no fill to vectorize'); + const fillId = blockApi.getFill(blockId); - // Get the current image URI and source set as initial values. - const initialSourceSet = blockApi.getSourceSet( - fillId, - 'fill/image/sourceSet' - ); - const initialImageFileURI = blockApi.getString( - fillId, - 'fill/image/imageFileURI' - ); - const initialPreviewFileURI = blockApi.getString( - fillId, - 'fill/image/previewFileURI' - ); + // FIXME: Tis is only needed to tell the engin that we are processing something and it cannot export or save the scene file. + // Practicalle, we are not using the images directly but render the visible part of the block and then process this image + // Get the current image URI and source set as initial values. + const initialSourceSet = blockApi.getSourceSet(fillId, 'fill/image/sourceSet'); + const initialImageFileURI = blockApi.getString(fillId, 'fill/image/imageFileURI'); + const initialPreviewFileURI = blockApi.getString(fillId, 'fill/image/previewFileURI'); - const uriToProcess = - // Source sets have priority in the engine - initialSourceSet.length > 0 - ? // Choose the highest resolution image in the source set - initialSourceSet.sort( - (a, b) => b.width * b.height - a.height * a.width - )[0].uri - : initialImageFileURI; + const uriToProcess = + // Source sets have priority in the engine + initialSourceSet.length > 0 + ? // Choose the highest resolution image in the source set + initialSourceSet.sort( + (a, b) => b.width * b.height - a.height * a.width + )[0].uri + : initialImageFileURI; - if (uriToProcess === undefined || uriToProcess === '') - return; // We shall return early if the uri is not defined or invalid + if (uriToProcess === undefined || uriToProcess === '') + return; // We shall return early if the uri is not defined or invalid + try { + // Clear values in the engine to trigger the loading spinner + // @ts-ignore + const blob = await engine.block.export(blockId, "image/png"); + // go into busy state + blockApi.setString(fillId, 'fill/image/imageFileURI', ''); + blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); + // ensure we show the last image while processsing. Some images don't have the preview set + if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { + blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); + } - try { - // Clear values in the engine to trigger the loading spinner - // @ts-ignore - const blob = await engine.block.export(blockId, "image/png"); - - // go into busy state - blockApi.setString(fillId, 'fill/image/imageFileURI', ''); - blockApi.setSourceSet(fillId, 'fill/image/sourceSet', []); - // ensure we show the last image while processsing. Some images don't have the preview set - if (initialPreviewFileURI === undefined || initialPreviewFileURI === '') { - blockApi.setString(fillId, 'fill/image/previewFileURI', uriToProcess); - - - } - const metadata = getPluginMetadata(engine, blockId); - setPluginMetadata(engine, blockId, { - ...metadata, - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSING' - }); - - const vectorized: Blob = await runInWorker(blob) - - if ( - getPluginMetadata(engine, blockId).status !== 'PROCESSING' || - !isMetadataConsistent(engine, blockId) - )return; - if (engine.block.isValid(blockId)) { + const metadata = getPluginMetadata(engine, blockId); setPluginMetadata(engine, blockId, { + ...metadata, version: PLUGIN_VERSION, initialSourceSet, initialImageFileURI, blockId, fillId, - status: 'PROCESSED', + status: 'PROCESSING' }); - } - - if (vectorized.type.length === 0 || vectorized.type === 'image/svg+xml') { - const pathname = new URL(uriToProcess).pathname; - const parts = pathname.split('/'); - const filename = parts[parts.length - 1]; + const vectorized: Blob = await runInWorker(blob) - const uploadedAssets = await uploader( - new File([vectorized], filename, { type: vectorized.type }), - () => { - // TODO Delegate process to UI component - } - ); - - // Check for externally changed state while we were uploading and - // do not proceed if the state was reset. if ( getPluginMetadata(engine, blockId).status !== 'PROCESSING' || !isMetadataConsistent(engine, blockId) - ) - return; - - const url = uploadedAssets.meta?.uri;; - if (url == null) { - throw new Error('Could not upload vectorized image'); + ) return; + if (engine.block.isValid(blockId)) { + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + }); } - // Workaround Processing is done, restore state of the initial block - blockApi.setSourceSet(fillId, 'fill/image/sourceSet', initialSourceSet); - blockApi.setString(fillId, 'fill/image/imageFileURI', initialImageFileURI); - blockApi.setString(fillId, 'fill/image/previewFileURI', initialPreviewFileURI); - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'PROCESSED', - }); + if (vectorized.type.length === 0 || vectorized.type === 'image/svg+xml') { + const pathname = new URL(uriToProcess).pathname; + const parts = pathname.split('/'); + const filename = parts[parts.length - 1]; - blockApi.setString(fillId, 'fill/image/imageFileURI', url); - } else if (vectorized.type === 'application/json') { - - const json = await vectorized.text() - const blocks = JSON.parse(json) - const blockIds = createVectorPathBlocks(engine, blocks) - - const origRotation = engine.block.getRotation(blockId) - const origX = engine.block.getPositionX(blockId) - const origY = engine.block.getPositionY(blockId) - const origSelected = engine.block.isSelected(blockId) - - switch (engine.block.getType(blockId)) { - case "//ly.img.ubq/page": - { - const parentId = blockId; + const uploadedAssets = await uploader( + new File([vectorized], filename, { type: vectorized.type }), + () => { + // TODO Delegate process to UI component + } + ); + + // Check for externally changed state while we were uploading and + // do not proceed if the state was reset. + if ( + getPluginMetadata(engine, blockId).status !== 'PROCESSING' || + !isMetadataConsistent(engine, blockId) + ) + return; + + const url = uploadedAssets.meta?.uri;; + if (url == null) { + throw new Error('Could not upload vectorized image'); + } + + // Workaround Processing is done, restore state of the initial block + blockApi.setSourceSet(fillId, 'fill/image/sourceSet', initialSourceSet); + blockApi.setString(fillId, 'fill/image/imageFileURI', initialImageFileURI); + blockApi.setString(fillId, 'fill/image/previewFileURI', initialPreviewFileURI); + + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'PROCESSED', + }); + + blockApi.setString(fillId, 'fill/image/imageFileURI', url); + } else if (vectorized.type === 'application/json') { + + const json = await vectorized.text() + const blocks = JSON.parse(json) + const blockIds = createVectorPathBlocks(engine, blocks) + + const origRotation = engine.block.getRotation(blockId) + const origX = engine.block.getPositionX(blockId) + const origY = engine.block.getPositionY(blockId) + const origSelected = engine.block.isSelected(blockId) + + switch (engine.block.getType(blockId)) { + case "//ly.img.ubq/page": + { + const parentId = blockId; + const containerId = engine.block.group(blockIds); + engine.block.appendChild(parentId, containerId); + const scale = engine.block.getFrameWidth(blockId) / engine.block.getFrameWidth(containerId) + engine.block.setPositionX(containerId, origX) + engine.block.setPositionY(containerId, origY) + engine.block.setRotation(containerId, origRotation) + engine.block.scale(containerId, scale) + engine.block.setFillEnabled(parentId, false) + engine.block.setSelected(containerId, origSelected) + break; + } + case "//ly.img.ubq/graphic": + default: { // replace the current block with the a new group of the vectors + const parentId = engine.block.getParent(blockId)! const containerId = engine.block.group(blockIds); engine.block.appendChild(parentId, containerId); const scale = engine.block.getFrameWidth(blockId) / engine.block.getFrameWidth(containerId) @@ -172,45 +173,33 @@ const vectorize = async (cesdk: CreativeEditorSDK, params: { blockId: number }) engine.block.setPositionY(containerId, origY) engine.block.setRotation(containerId, origRotation) engine.block.scale(containerId, scale) - engine.block.setFillEnabled(parentId, false) + engine.block.destroy(blockId) engine.block.setSelected(containerId, origSelected) break; } - case "//ly.img.ubq/graphic": - default: { // replace the current block with the a new group of the vectors - const parentId = engine.block.getParent(blockId)! - const containerId = engine.block.group(blockIds); - engine.block.appendChild(parentId, containerId); - const scale = engine.block.getFrameWidth(blockId) / engine.block.getFrameWidth(containerId) - engine.block.setPositionX(containerId, origX) - engine.block.setPositionY(containerId, origY) - engine.block.setRotation(containerId, origRotation) - engine.block.scale(containerId, scale) - engine.block.destroy(blockId) - engine.block.setSelected(containerId, origSelected) - break; } } + // Finally, create an undo step + engine.editor.addUndoStep(); + + } catch (error) { + if (engine.block.isValid(blockId)) { + setPluginMetadata(engine, blockId, { + version: PLUGIN_VERSION, + initialSourceSet, + initialImageFileURI, + blockId, + fillId, + status: 'ERROR' + }); + + recoverInitialImageData(engine, blockId); + } + // eslint-disable-next-line no-console + console.error(error); } - // Finally, create an undo step - engine.editor.addUndoStep(); - - } catch (error) { - if (engine.block.isValid(blockId)) { - setPluginMetadata(engine, blockId, { - version: PLUGIN_VERSION, - initialSourceSet, - initialImageFileURI, - blockId, - fillId, - status: 'ERROR' - }); - - recoverInitialImageData(engine, blockId); - } - // eslint-disable-next-line no-console - console.error(error); - } + }) } + export default { [PLUGIN_ACTION_VECTORIZE_LABEL]: vectorize } diff --git a/packages/vectorizer/src/defaults.ts b/packages/vectorizer/src/defaults.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/src/i18n.ts b/packages/vectorizer/src/i18n.ts index ee99b0d..90b5033 100644 --- a/packages/vectorizer/src/i18n.ts +++ b/packages/vectorizer/src/i18n.ts @@ -1,4 +1,4 @@ -import { PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants' +import { PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest' export const en = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vector' } export const de = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Wandle in Vector' } diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index aafe740..1d12e3b 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -3,18 +3,17 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import ui from './ui'; import commands from './commands'; import i18n from './i18n'; -import Manifest from './manifest'; +import Manifest, { PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_ID } from './manifest'; -import { PLUGIN_ID } from './utils/constants'; -import { PLUGIN_CANVAS_MENU_COMPONENT_ID } from './utils/constants'; import { polyfillEngineWithCommands, CreativeEngineWithPolyfills } from './utils/polyfills'; import { clearPluginMetadata, fixDuplicateMetadata, getPluginMetadata, isDuplicate, - isMetadataConsistent -} from './utils/utils'; + isMetadataConsistent, + areBlocksSupported +} from './utils'; export interface PluginConfiguration { @@ -28,36 +27,43 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { id: PLUGIN_ID, version: PLUGIN_VERSION, initialize(engine: CreativeEngineWithPolyfills) { - + // it is unclear for a user which one to call and what happens and if we have to put code in both or just one + // we should have a clear separation of concerns + // also maybe better naming + // onInitEngine + // onInitUI }, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - const engine = cesdk.engine as CreativeEngineWithPolyfills; - polyfillEngineWithCommands(engine); - console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") + // This should move into a seperate plugin + const engine = polyfillEngineWithCommands(cesdk.engine); + if (!engine.polyfill_commands) { + console.error("Polyfill engine.commands not available!") + return; + } + + console.log("Subscribing to events"); engine.event.subscribe([], async (events) => { events - .filter((e) => engine.block.isValid(e.block) && engine.block.hasMetadata(e.block, PLUGIN_ID)) - .forEach((e) => { - const id = e.block; - if (e.type === 'Created') { - const metadata = getPluginMetadata(engine, id); - if (isDuplicate(engine, id, metadata)) { - fixDuplicateMetadata(engine, id); + .filter(({ block: blockId }) => engine.block.isValid(blockId) && engine.block.hasMetadata(blockId, PLUGIN_ID)) + .forEach(({ type, block: blockId }) => { + if (type === 'Created') { + const metadata = getPluginMetadata(engine, blockId); + if (isDuplicate(engine, blockId, metadata)) { + fixDuplicateMetadata(engine, blockId); } } }); }); - console.log("checking if engine has polyfill_commands", engine.polyfill_commands? "yes": "no") + console.log("checking if engine has polyfill_commands", engine.polyfill_commands ? "yes" : "no") engine.event.subscribe([], async (events) => { events - .filter((e) => engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) - .filter((e) => e.type === 'Updated') - .forEach((e) => { handleUpdateEvent(cesdk, e.block); }); + .filter(e => engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) + .filter(e => e.type === 'Updated') + .forEach(e => handleUpdateEvent(engine, e.block)) }); - console.info("Registering plugin actions") Object.keys(commands).forEach((action) => { console.info(`Registering action: ${action}`) @@ -80,16 +86,29 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { cesdk.ui.unstable_registerComponent(componentId, component); }) - // Always prepend the registered component to the canvas menu order. + // DEFAULTS + // define what blocks the component button is enabled for + // WHERE IS THIS USED? AND HOW DOES IT WORK? It seems the button is shown no matter what. + console.info("Enabling plugin component button for supported blocks") + cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, (context: any) => { + return areBlocksSupported(engine, engine.block.findAllSelected()) + }) + + cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, false); + cesdk.feature.unstable_enable(PLUGIN_ID, false); + cesdk.feature.unstable_enable(PLUGIN_ACTION_VECTORIZE_LABEL, false); + + console.info("Changing canvas menu order") - cesdk.ui.unstable_setCanvasMenuOrder([ - PLUGIN_CANVAS_MENU_COMPONENT_ID, + const canvasMenuEntries = [ + PLUGIN_COMPONENT_BUTTON_ID, ...cesdk.ui.unstable_getCanvasMenuOrder() - ]); + ] + cesdk.ui.unstable_setCanvasMenuOrder(canvasMenuEntries); }, - // maybe this should be just engint.event.onUpdate() + // maybe this should be just engine.event.onUpdate() update() { }, @@ -101,15 +120,13 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { * Handle every possible state of the vectorization state if the block was * updated. */ -async function handleUpdateEvent(cesdk: CreativeEditorSDK, blockId: number) { - const metadata = getPluginMetadata(cesdk.engine, blockId); - +async function handleUpdateEvent(engine: CreativeEngine, blockId: number) { + const metadata = getPluginMetadata(engine, blockId); switch (metadata.status) { - case 'PROCESSING': case 'PROCESSED': { - if (!isMetadataConsistent(cesdk.engine, blockId)) { - clearPluginMetadata(cesdk.engine, blockId); + if (!isMetadataConsistent(engine, blockId)) { + clearPluginMetadata(engine, blockId); } break; } diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index f32117d..7407bbb 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -1,9 +1,19 @@ -import { PLUGIN_ID, PLUGIN_ACTION_VECTORIZE_LABEL } from './utils/constants'; +export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; +export const PLUGIN_COMPONENT_BUTTON_ID = `component.${PLUGIN_ID}.button`; +export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` + + export default { id: PLUGIN_ID, + contributes: { - actions: [ + ui: [ + { + id: PLUGIN_COMPONENT_BUTTON_ID, // not sure will + } + ], + commands: [ { id: PLUGIN_ACTION_VECTORIZE_LABEL, } diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index a183974..9b93931 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,42 +1,40 @@ import { PLUGIN_COMPONENT_BUTTON_ID, - PLUGIN_CANVAS_MENU_COMPONENT_ID, - PLUGIN_ACTION_VECTORIZE_LABEL, - PLUGIN_ICON -} from './utils/constants'; + PLUGIN_ACTION_VECTORIZE_LABEL +} from './manifest'; import { getPluginMetadata, isBlockSupported, -} from './utils/utils'; +} from './utils'; import { CreativeEngineWithPolyfills } from './utils/polyfills'; const button = (params: any) => { const engine = params.engine! as CreativeEngineWithPolyfills const builder = params.builder! + // the button might need the ids it is shown for + // the isSupported const selected = engine.block.findAllSelected(); const candidates = selected.filter(id => isBlockSupported(engine, id)) if (candidates.length === 0) return; - let isLoading = candidates.some(id => { - const metadata = getPluginMetadata(engine, id); - return metadata.status === 'PROCESSING' - }) - - const loadingProgress = undefined + let isLoading = candidates.some(id => getPluginMetadata(engine, id).status === 'PROCESSING') - builder.Button(PLUGIN_COMPONENT_BUTTON_ID, { + // @maerch: Why do we need the Button ID here? + builder.Button("DO I NEED THIS", { label: PLUGIN_ACTION_VECTORIZE_LABEL, - icon: PLUGIN_ICON, + icon: '@imgly/icons/Vectorize', isActive: false, isLoading: isLoading, isDisabled: isLoading, - loadingProgress, - onClick: () => candidates.forEach(id => engine.polyfill_commands?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockId: id })) + loadingProgress: undefined, // creates infinite spinner + onClick: () => engine + .polyfill_commands + ?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockIds: candidates }) }); } export default { - [PLUGIN_CANVAS_MENU_COMPONENT_ID]: button + [PLUGIN_COMPONENT_BUTTON_ID]: button } // end of export default diff --git a/packages/vectorizer/src/utils/utils.ts b/packages/vectorizer/src/utils.ts similarity index 94% rename from packages/vectorizer/src/utils/utils.ts rename to packages/vectorizer/src/utils.ts index d0c914d..14e682b 100644 --- a/packages/vectorizer/src/utils/utils.ts +++ b/packages/vectorizer/src/utils.ts @@ -1,15 +1,18 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; +import { CreativeEngine } from '@cesdk/cesdk-js'; import isEqual from 'lodash/isEqual'; -import { PLUGIN_ID } from './constants'; +import { PLUGIN_ID } from './manifest'; import { PluginMetadata, PluginStatusError, PluginStatusProcessed, PluginStatusProcessing -} from './types'; +} from './utils/types'; +export const areBlocksSupported = (engine: CreativeEngine, blockIds: number[]) => { + return blockIds.some(id => isBlockSupported(engine, id)) +} /** * Checks if a block is supported by the given CreativeEngine. * @param engine - The CreativeEngine instance. @@ -17,9 +20,9 @@ import { * @returns A boolean indicating whether the block is supported or not. */ export const isBlockSupported = (engine: CreativeEngine, blockId: number) => { + if (!engine.block.isValid(blockId)) return false; const blockType = engine.block.getType(blockId); if (blockType === "//ly.img.ubq/page") return false; // There is some bug with the page block - if (engine.block.hasFill(blockId)) { const fillId = engine.block.getFill(blockId); @@ -80,11 +83,7 @@ export function isDuplicate( metadata: PluginMetadata ): boolean { if (!engine.block.isValid(blockId)) return false; - if ( - metadata.status === 'IDLE' || - // metadata.status === 'PENDING' || - metadata.status === 'ERROR' - ) + if (metadata.status === 'IDLE' || metadata.status === 'ERROR') return false; if (!engine.block.hasFill(blockId)) return false; @@ -188,7 +187,7 @@ export function isMetadataConsistent( } else { if (metadata.status === 'PROCESSED') { if ( - imageFileURI !== metadata.initialImageFileURI + imageFileURI !== metadata.initialImageFileURI // &&imageFileURI !== metadata.processedAsset ) { return false; diff --git a/packages/vectorizer/src/utils/constants.ts b/packages/vectorizer/src/utils/constants.ts deleted file mode 100644 index 2bf91fb..0000000 --- a/packages/vectorizer/src/utils/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; -export const PLUGIN_CANVAS_MENU_COMPONENT_ID = `${PLUGIN_ID}.canvasMenu`; -export const PLUGIN_COMPONENT_BUTTON_ID = `${PLUGIN_CANVAS_MENU_COMPONENT_ID}.button`; -export const PLUGIN_FEATURE_ID = `${PLUGIN_ID}`; -export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` -export const PLUGIN_ICON = '@imgly/icons/Vectorize' - - diff --git a/packages/vectorizer/src/utils/polyfills.ts b/packages/vectorizer/src/utils/polyfills.ts index 399a757..4d33237 100644 --- a/packages/vectorizer/src/utils/polyfills.ts +++ b/packages/vectorizer/src/utils/polyfills.ts @@ -23,9 +23,11 @@ export class Commands { } } -export function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills) { +export function polyfillEngineWithCommands(engine: CreativeEngine) { + const polyfilled = engine as CreativeEngineWithPolyfills; //polyfill - if (!engine.polyfill_commands) { - engine.polyfill_commands = new Commands(engine); + if (!polyfilled.polyfill_commands ) { + polyfilled.polyfill_commands = new Commands(engine); } + return polyfilled } \ No newline at end of file diff --git a/packages/vectorizer/src/utils/worker.shared.ts b/packages/vectorizer/src/utils/worker.shared.ts index fa09338..c270865 100644 --- a/packages/vectorizer/src/utils/worker.shared.ts +++ b/packages/vectorizer/src/utils/worker.shared.ts @@ -4,11 +4,12 @@ export interface MessageBody { error?: Error } - - +const TIMEOUT_DEFAULT = 10000 +// we need a timeout export const runInWorker = (blob: Blob) => new Promise((resolve, reject) => { const worker = new Worker(new URL('./worker', import.meta.url), { type: 'module' }); const msg: MessageBody = { method: "imageToJson", data: blob } + setTimeout(() => reject(new Error("Timeout")), TIMEOUT_DEFAULT); worker.postMessage(msg) worker.onmessage = (e: MessageEvent) => { const msg = e.data diff --git a/packages/vectorizer/types/actions.d.ts b/packages/vectorizer/types/actions.d.ts deleted file mode 100644 index 03d9ba2..0000000 --- a/packages/vectorizer/types/actions.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -declare const _default: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { - blockId: number; - }) => Promise; -}; -export default _default; diff --git a/packages/vectorizer/types/cesdk+utils.d.ts b/packages/vectorizer/types/cesdk+utils.d.ts deleted file mode 100644 index bb1aa1d..0000000 --- a/packages/vectorizer/types/cesdk+utils.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { CreativeEngine } from "@cesdk/cesdk-js"; -export declare const createVectorPathBlocks: (engine: CreativeEngine, blocks: any[]) => number; -export declare const createVectorPathBlock: (engine: CreativeEngine, block: any) => number; diff --git a/packages/vectorizer/types/commands.d.ts b/packages/vectorizer/types/commands.d.ts index 03d9ba2..5075718 100644 --- a/packages/vectorizer/types/commands.d.ts +++ b/packages/vectorizer/types/commands.d.ts @@ -1,7 +1,7 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; declare const _default: { "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { - blockId: number; + blockIds?: number[] | undefined; }) => Promise; }; export default _default; diff --git a/packages/vectorizer/types/defaults.d.ts b/packages/vectorizer/types/defaults.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts index c4400b4..74d1f84 100644 --- a/packages/vectorizer/types/manifest.d.ts +++ b/packages/vectorizer/types/manifest.d.ts @@ -1,7 +1,13 @@ +export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.@imgly/plugin-vectorizer-web.button"; +export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; declare const _default: { id: string; contributes: { - actions: { + ui: { + id: string; + }[]; + commands: { id: string; }[]; }; diff --git a/packages/vectorizer/types/manitfest.d.ts b/packages/vectorizer/types/manitfest.d.ts deleted file mode 100644 index c4400b4..0000000 --- a/packages/vectorizer/types/manitfest.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -declare const _default: { - id: string; - contributes: { - actions: { - id: string; - }[]; - }; -}; -export default _default; diff --git a/packages/vectorizer/types/proposal/actions.d.ts b/packages/vectorizer/types/proposal/actions.d.ts deleted file mode 100644 index 03d9ba2..0000000 --- a/packages/vectorizer/types/proposal/actions.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -declare const _default: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { - blockId: number; - }) => Promise; -}; -export default _default; diff --git a/packages/vectorizer/types/proposal/i18n.d.ts b/packages/vectorizer/types/proposal/i18n.d.ts deleted file mode 100644 index c1327c7..0000000 --- a/packages/vectorizer/types/proposal/i18n.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export declare const en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; -}; -export declare const de: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; -}; -declare const _default: { - de: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; - }; - en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; - }; -}; -export default _default; diff --git a/packages/vectorizer/types/proposal/manitfest.d.ts b/packages/vectorizer/types/proposal/manitfest.d.ts deleted file mode 100644 index 4c0f97c..0000000 --- a/packages/vectorizer/types/proposal/manitfest.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export declare const id = "@imgly/plugin-vectorizer-web"; -export declare const contributes: { - actions: { - id: string; - }[]; -}; diff --git a/packages/vectorizer/types/proposal/ui.d.ts b/packages/vectorizer/types/proposal/ui.d.ts deleted file mode 100644 index 2a7467d..0000000 --- a/packages/vectorizer/types/proposal/ui.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const _default: { - "@imgly/plugin-vectorizer-web.canvasMenu": (params: any) => void; -}; -export default _default; diff --git a/packages/vectorizer/types/proposal/worker.d.ts b/packages/vectorizer/types/proposal/worker.d.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/packages/vectorizer/types/proposal/worker.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/packages/vectorizer/types/types.d.ts b/packages/vectorizer/types/types.d.ts deleted file mode 100644 index c00d57f..0000000 --- a/packages/vectorizer/types/types.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { type Source } from '@cesdk/cesdk-js'; -export type PluginStatusIdle = { - status: 'IDLE'; -}; -export type PluginStatusProcessing = { - version: string; - status: 'PROCESSING'; - initialImageFileURI: string; - initialSourceSet: Source[]; - blockId: number; - fillId: number; - progress?: { - key: string; - current: number; - total: number; - }; -}; -export type PluginStatusProcessed = { - version: string; - status: 'PROCESSED'; - initialImageFileURI: string; - initialSourceSet: Source[]; - blockId: number; - fillId: number; -}; -export type PluginStatusError = { - version: string; - status: 'ERROR'; - initialImageFileURI: string; - initialSourceSet: Source[]; - blockId: number; - fillId: number; -}; -export type PluginMetadata = PluginStatusIdle | PluginStatusError | PluginStatusProcessing | PluginStatusProcessed; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts index 2a7467d..4746d3f 100644 --- a/packages/vectorizer/types/ui.d.ts +++ b/packages/vectorizer/types/ui.d.ts @@ -1,4 +1,4 @@ declare const _default: { - "@imgly/plugin-vectorizer-web.canvasMenu": (params: any) => void; + "component.@imgly/plugin-vectorizer-web.button": (params: any) => void; }; export default _default; diff --git a/packages/vectorizer/types/utils.d.ts b/packages/vectorizer/types/utils.d.ts index 7a389e0..4a58386 100644 --- a/packages/vectorizer/types/utils.d.ts +++ b/packages/vectorizer/types/utils.d.ts @@ -1,5 +1,6 @@ import { CreativeEngine } from '@cesdk/cesdk-js'; import { PluginMetadata } from './utils/types'; +export declare const areBlocksSupported: (engine: CreativeEngine, blockIds: number[]) => boolean; /** * Checks if a block is supported by the given CreativeEngine. * @param engine - The CreativeEngine instance. @@ -48,5 +49,8 @@ export declare class Scheduler { #private; schedule(task: () => Promise): Promise; } -export declare function registerAction(engine: CreativeEngine, label: string, callback: (params: any) => Promise): void; -export declare function executeAction(label: string, params: any): Promise; +/** + * Generates a unique filename. + * @returns A string representing the unique filename. + */ +export declare function generateUniqueFilename(): string; diff --git a/packages/vectorizer/types/utils/cesdk+utils.d.ts b/packages/vectorizer/types/utils/cesdk+utils.d.ts index bb1aa1d..a5b5a9e 100644 --- a/packages/vectorizer/types/utils/cesdk+utils.d.ts +++ b/packages/vectorizer/types/utils/cesdk+utils.d.ts @@ -1,3 +1,3 @@ import { CreativeEngine } from "@cesdk/cesdk-js"; -export declare const createVectorPathBlocks: (engine: CreativeEngine, blocks: any[]) => number; +export declare const createVectorPathBlocks: (engine: CreativeEngine, blocks: any[]) => number[]; export declare const createVectorPathBlock: (engine: CreativeEngine, block: any) => number; diff --git a/packages/vectorizer/types/utils/constants.d.ts b/packages/vectorizer/types/utils/constants.d.ts index 32b989f..ddad552 100644 --- a/packages/vectorizer/types/utils/constants.d.ts +++ b/packages/vectorizer/types/utils/constants.d.ts @@ -1,6 +1,4 @@ export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; -export declare const PLUGIN_CANVAS_MENU_COMPONENT_ID = "@imgly/plugin-vectorizer-web.canvasMenu"; -export declare const PLUGIN_CANVAS_MENU_COMPONENT_BUTTON_ID = "@imgly/plugin-vectorizer-web.canvasMenu.button"; -export declare const PLUGIN_FEATURE_ID = "@imgly/plugin-vectorizer-web"; +export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.@imgly/plugin-vectorizer-web.button"; export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; export declare const PLUGIN_ICON = "@imgly/icons/Vectorize"; diff --git a/packages/vectorizer/types/utils/polyfills.d.ts b/packages/vectorizer/types/utils/polyfills.d.ts index ad9669b..99db4ec 100644 --- a/packages/vectorizer/types/utils/polyfills.d.ts +++ b/packages/vectorizer/types/utils/polyfills.d.ts @@ -9,4 +9,4 @@ export declare class Commands { registerCommand(label: string, callback: (params: any) => Promise): void; executeCommand(label: string, params: any): Promise; } -export declare function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills): void; +export declare function polyfillEngineWithCommands(engine: CreativeEngine): CreativeEngineWithPolyfills; diff --git a/packages/vectorizer/types/utils/utils.d.ts b/packages/vectorizer/types/utils/utils.d.ts index 5afc33d..2166d3f 100644 --- a/packages/vectorizer/types/utils/utils.d.ts +++ b/packages/vectorizer/types/utils/utils.d.ts @@ -1,5 +1,6 @@ import { CreativeEngine } from '@cesdk/cesdk-js'; import { PluginMetadata } from './types'; +export declare const areBlocksSupported: (engine: CreativeEngine, blockIds: number[]) => boolean; /** * Checks if a block is supported by the given CreativeEngine. * @param engine - The CreativeEngine instance. @@ -48,3 +49,8 @@ export declare class Scheduler { #private; schedule(task: () => Promise): Promise; } +/** + * Generates a unique filename. + * @returns A string representing the unique filename. + */ +export declare function generateUniqueFilename(): string; diff --git a/packages/vectorizer/types/utils/worker.shared.d.ts b/packages/vectorizer/types/utils/worker.shared.d.ts index 4f39759..bf21f38 100644 --- a/packages/vectorizer/types/utils/worker.shared.d.ts +++ b/packages/vectorizer/types/utils/worker.shared.d.ts @@ -3,4 +3,4 @@ export interface MessageBody { data?: any; error?: Error; } -export declare const runInWorker: (uri: string) => Promise; +export declare const runInWorker: (blob: Blob) => Promise; diff --git a/packages/vectorizer/types/worker.shared.d.ts b/packages/vectorizer/types/worker.shared.d.ts deleted file mode 100644 index 68f6a33..0000000 --- a/packages/vectorizer/types/worker.shared.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface MessageBody { - method?: string; - data?: any; - error?: Error; -} -export declare const runInWorker: (uri: string) => Promise; diff --git a/yarn.lock b/yarn.lock index 930c7f5..2ae2cbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -220,7 +220,7 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@cesdk/cesdk-js@^1.20.0", "@cesdk/cesdk-js@~1.20.0": +"@cesdk/cesdk-js@^1.20.0": version "1.20.0" resolved "https://registry.npmjs.org/@cesdk/cesdk-js/-/cesdk-js-1.20.0.tgz" integrity sha512-vKDcnv5z5TZe1PcgvZagJ7QXVyijeTnkwPCJJFj/Uxcsef9GvLrzOVIYqPC0gqZuDlfHpADPsGAV+pZaZg8+eg== @@ -4290,6 +4290,11 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +share-api-polyfill@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/share-api-polyfill/-/share-api-polyfill-1.1.1.tgz#373bacac2f02828a3ee1bd7d9a2b72c60580080e" + integrity sha512-5GxXomFRth4lBpHWN136cxpv8KOo+uutljXqgO1RsptDQ5X1raRQWqLi+LoWZ/h02/TgV1STJwuMXcP/0b1vpQ== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" From e6639f8a2b150a06bed6314c3d87fb80ec548249 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 10:07:17 +0100 Subject: [PATCH 13/32] fix: removed obsolte types --- .../vectorizer/types/utils/constants.d.ts | 4 -- packages/vectorizer/types/utils/utils.d.ts | 56 ------------------- 2 files changed, 60 deletions(-) delete mode 100644 packages/vectorizer/types/utils/constants.d.ts delete mode 100644 packages/vectorizer/types/utils/utils.d.ts diff --git a/packages/vectorizer/types/utils/constants.d.ts b/packages/vectorizer/types/utils/constants.d.ts deleted file mode 100644 index ddad552..0000000 --- a/packages/vectorizer/types/utils/constants.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; -export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.@imgly/plugin-vectorizer-web.button"; -export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; -export declare const PLUGIN_ICON = "@imgly/icons/Vectorize"; diff --git a/packages/vectorizer/types/utils/utils.d.ts b/packages/vectorizer/types/utils/utils.d.ts deleted file mode 100644 index 2166d3f..0000000 --- a/packages/vectorizer/types/utils/utils.d.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; -import { PluginMetadata } from './types'; -export declare const areBlocksSupported: (engine: CreativeEngine, blockIds: number[]) => boolean; -/** - * Checks if a block is supported by the given CreativeEngine. - * @param engine - The CreativeEngine instance. - * @param blockId - The ID of the block to check. - * @returns A boolean indicating whether the block is supported or not. - */ -export declare const isBlockSupported: (engine: CreativeEngine, blockId: number) => boolean; -/** - * Sets the metadata for the plugin state. - */ -export declare function setPluginMetadata(engine: CreativeEngine, id: number, metadata: PluginMetadata): void; -/** - * Returns the current metadata for the plugin state. If no metadata - * is set on the given block, it will return an IDLE state. - */ -export declare function getPluginMetadata(engine: CreativeEngine, id: number): PluginMetadata; -/** - * If plugin metadata is set, it will be cleared. - */ -export declare function clearPluginMetadata(engine: CreativeEngine, id: number): void; -/** - * Detect if the block has been duplicated with processed or processing state. - * In that case the plugin state is still valid, but blockId and fillId have changed. - */ -export declare function isDuplicate(engine: CreativeEngine, blockId: number, metadata: PluginMetadata): boolean; -/** - * Fixes the metadata if the block has been duplicated, i.e. the blockId and - * fillId will be updated to the current block/fill. - * - * Please note: Call this method only on duplicates (see isDuplicate). - */ -export declare function fixDuplicateMetadata(engine: CreativeEngine, blockId: number): void; -/** - * Check if the image has a consisten metadata state. A inconsistent state is - * caused by outside changes of the fill data. - * - * @returns true if the metadata is consistent, false otherwise - */ -export declare function isMetadataConsistent(engine: CreativeEngine, blockId: number): boolean; -/** - * Recover the initial values to avoid the loading spinner and have the same - * state as before the process was started. - */ -export declare function recoverInitialImageData(engine: CreativeEngine, blockId: number): void; -export declare class Scheduler { - #private; - schedule(task: () => Promise): Promise; -} -/** - * Generates a unique filename. - * @returns A string representing the unique filename. - */ -export declare function generateUniqueFilename(): string; From edf8783b0ccd231853e7c76a6906c6c9f3179fb6 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 10:08:52 +0100 Subject: [PATCH 14/32] chore: Added list of (potential) plugins --- LIST_OF_PLUGINS.md | 184 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 LIST_OF_PLUGINS.md diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md new file mode 100644 index 0000000..8c435a8 --- /dev/null +++ b/LIST_OF_PLUGINS.md @@ -0,0 +1,184 @@ +# Commands + +- [ ] Useful + - [ ] Background removal + - [ ] Segment everything: Sam based auto segmenter + - [ ] Bake image + - [ ] Upscale image + + +- [ ] Convert to + - [ ] Convert to Vector + - [ ] Convert to Bitmap + + + +- [ ] Turn into // Rethink Semantics This should change existing blocks without loss of date + - [ ] Turn into Image: Turns a block into a graphics block with the image as fill, + - [ ] Turn into Vector + - [ ] Turn into Graphics + + - [ ] Turn into Group + - [ ] Turn into Page + + +- [ ] Zoom + - [ ] Fit Page + - [ ] Fit Selection + - [ ] Zoom to 100% + +- [ ] Block Lifecylce + - [ ] Duplicate Selected + - [ ] Delete Selected + + - [ ] Copy Selected + - [ ] Paste Selected + - [ ] Group Selected + - [ ] Frame Selected + + - [ ] Merge Selected (Union Boolean Op) + - [ ] Subtract Selected (Difference Boolean Op) + - [ ] Intersect Selected + - [ ] Exclude Selected + +- [ ] Copy Properties: Copies them only onces + - [ ] Copy Transform Properties to {Selected, Clipboard} + - [ ] Copy Position Properties to {Selected, Clipboard} + - [ ] Copy Rotation Properties to {Selected, Clipboard} + - [ ] Copy Size (Width, Height) Properties to {Selected, Clipboard} + - [ ] Copy Fill Content to {Selected, Clipboard} + - [ ] Copy Text Content to {Selected, Clipboard} + - [ ] Copy Appearance Properties to {Selected, Clipboard} + - [ ] Copy Stroke Properties to {Selected, Clipboard} + - [ ] Copy Adjustment properties to {Selected, Clipboard} + - [ ] Copy Filter Properties to {Selected, Clipboard} + +- [ ] Sync Properties: Sync keeps them sync and updates both in a two way fassion + - [ ] Sync Transform Properties to {Selected, Clipboard} + - [ ] Sync Position Properties to {Selected, Clipboard} + - [ ] Sync Rotation Properties to {Selected, Clipboard} + - [ ] Sync Size (Width, Height) Properties to {Selected, Clipboard} + - [ ] Sync Fill Content to {Selected, Clipboard} + - [ ] Sync Text Content to {Selected, Clipboard} + - [ ] Sync Appearance Properties to {Selected, Clipboard} + - [ ] Sync Stroke Properties to {Selected, Clipboard} + - [ ] Sync Adjustment properties to {Selected, Clipboard} + - [ ] Sync Filter Properties to {Selected, Clipboard} + + +- [ ] Block Editing + - [ ] Auto-Crop Image + - [ ] Adjust Image + - [ ] Apply Filter + - [ ] Apply Blur + - [ ] Apply Effect + +- [ ] Create New Block + - [ ] Create New Graphic + - [ ] Create New Text + - [ ] Create New Shape + + - [ ] Create New Group from Selection + - [ ] Create New Page from Selection + - [ ] Create new Scene from Selection + + +- [ ] Add from Library + - [ ] Add Image from Library + - [ ] Add Text from Library + - [ ] Add Sticker from Library + + + +- [ ] Replace /Change + - [ ] Replace Image + - [ ] Replace Shape + - [ ] Replace Font + - [ ] Replace Text + + - [ ] Change Fill to Image + - [ ] Change Fill to Video + - [ ] Change Fill to Color + - [ ] Change Fill to Gradient + + +- [ ] Add: Open the libraries and choose + - [ ] Add ${List all Asset Libraries} + +- [ ] Save As + - [ ] Save {Scene, Selected} As {SVG, PNG, JPEG, PDF, Component} to {Clipboard, File, Console, S3, Asset Library} + + +- [ ] Share to + - [ ] Share to Zapier + - [ ] Share to LinkedIn + - [ ] Share to Twitter/X + - [ ] + +- [ ] Auto-(mation) + - [ ] Auto-crop + - [ ] Auto-Adjust + +- [ ] Text + - [ ] Summarize Text + - [ ] Translate Text to {en,de} + - [ ] Correct Text Spelling + +- [ ] Effects + - [ ] Custom effect + +- [ ] Generators + - [ ] QR Code + - [ ] Map + - [ ] AI Image + - [ ] Star Rating + +- [ ] Uploader + - [ ] upload to S3 + - [ ] upload to localStorage + - [ ] ... +- [ ] Importer + - [ ] SVG Importer + +- [ ] Layouting + - [ ] Auto-Resize Parent: Parent block always resizes to the child block automatically + - [ ] Layout all in group in stack + +- [ ] Solutions + - [ ] Studio: Loads all plugins for a studio solution + - [ ] Photo + - [ ] Video + + +## Asset Sources / Libraries +- [ ] Assets + - [ ] Giphy + - [ ] Unsplkash + - [ ] Getty + - [ ] Soundstripe + - [ ] Pexels + - [ ] Demo Images + - [ ] ... +- [ ] Designer + - [ ] Component Library + + +- [ ] Experimental/Fun + +- [ ] Import/Upload + - [ ] Import Design File + - [ ] Import Asset + + +- [ ] Editor Functionality + - [ ] Component Library + - [ ] CommandPalette + - [ ] Layerlist + - [ ] Metadata Editor + + + +## Debugging +- [ ] Debugging + - [ ] CommandPalette + - [ ] {Print, Save,, Meta \ No newline at end of file From 5f22833120b27c408fa633e64789d42a42fc1b44 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 17:37:54 +0100 Subject: [PATCH 15/32] feat: Polyfill Plugin --- LIST_OF_PLUGINS.md | 2 +- examples/web/package.json | 4 +- examples/web/src/main.tsx | 2 +- examples/web/src/{ => plugins}/addPlugins.ts | 13 ++-- examples/web/src/{ => ui}/App.tsx | 33 ++--------- examples/web/src/{ => ui}/CommandPalette.tsx | 0 examples/web/src/utils/utils.ts | 27 +++++++++ package.json | 2 + .../LICENSE.md | 0 .../README.md | 0 .../STRUCTURE.md | 0 .../TODO.md | 0 .../esbuild/config.mjs | 0 .../esbuild/global.d.ts | 0 .../package.json | 2 +- .../scripts/build.mjs | 0 .../scripts/watch.mjs | 0 packages/commands-polyfill/src/index.ts | 59 +++++++++++++++++++ .../src/manifest.ts | 0 .../src/worker.ts | 0 .../tsconfig.json | 0 .../types/index.d.ts | 5 +- .../types/manifest.d.ts | 0 .../types/utils/polyfills.d.ts | 6 +- .../types/worker.d.ts | 0 packages/polyfill-commands/src/index.ts | 33 ----------- .../polyfill-commands/src/utils/polyfills.ts | 31 ---------- packages/vectorizer/src/index.ts | 42 +++++++------ packages/vectorizer/src/ui.ts | 53 +++++++++-------- packages/vectorizer/src/utils/polyfills.ts | 33 ----------- packages/vectorizer/src/utils/types.ts | 2 +- packages/vectorizer/types/index.d.ts | 5 +- packages/vectorizer/types/ui.d.ts | 3 +- packages/vectorizer/types/utils/commands.d.ts | 7 +++ turbo.json | 4 ++ yarn.lock | 5 -- 36 files changed, 179 insertions(+), 194 deletions(-) rename examples/web/src/{ => plugins}/addPlugins.ts (73%) rename examples/web/src/{ => ui}/App.tsx (67%) rename examples/web/src/{ => ui}/CommandPalette.tsx (100%) create mode 100644 examples/web/src/utils/utils.ts rename packages/{polyfill-commands => commands-polyfill}/LICENSE.md (100%) rename packages/{polyfill-commands => commands-polyfill}/README.md (100%) rename packages/{polyfill-commands => commands-polyfill}/STRUCTURE.md (100%) rename packages/{polyfill-commands => commands-polyfill}/TODO.md (100%) rename packages/{polyfill-commands => commands-polyfill}/esbuild/config.mjs (100%) rename packages/{polyfill-commands => commands-polyfill}/esbuild/global.d.ts (100%) rename packages/{polyfill-commands => commands-polyfill}/package.json (97%) rename packages/{polyfill-commands => commands-polyfill}/scripts/build.mjs (100%) rename packages/{polyfill-commands => commands-polyfill}/scripts/watch.mjs (100%) create mode 100644 packages/commands-polyfill/src/index.ts rename packages/{polyfill-commands => commands-polyfill}/src/manifest.ts (100%) rename packages/{polyfill-commands => commands-polyfill}/src/worker.ts (100%) rename packages/{polyfill-commands => commands-polyfill}/tsconfig.json (100%) rename packages/{polyfill-commands => commands-polyfill}/types/index.d.ts (63%) rename packages/{polyfill-commands => commands-polyfill}/types/manifest.d.ts (100%) rename packages/{polyfill-commands => commands-polyfill}/types/utils/polyfills.d.ts (63%) rename packages/{polyfill-commands => commands-polyfill}/types/worker.d.ts (100%) delete mode 100644 packages/polyfill-commands/src/index.ts delete mode 100644 packages/polyfill-commands/src/utils/polyfills.ts delete mode 100644 packages/vectorizer/src/utils/polyfills.ts create mode 100644 packages/vectorizer/types/utils/commands.d.ts diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md index 8c435a8..cd285bd 100644 --- a/LIST_OF_PLUGINS.md +++ b/LIST_OF_PLUGINS.md @@ -11,7 +11,7 @@ - [ ] Convert to Vector - [ ] Convert to Bitmap - +- [ ] Vector on Path: Convert any shape and bind to path. How do we keep the original block? - [ ] Turn into // Rethink Semantics This should change existing blocks without loss of date - [ ] Turn into Image: Turns a block into a graphics block with the image as fill, diff --git a/examples/web/package.json b/examples/web/package.json index bba735c..9624e52 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -10,12 +10,12 @@ }, "dependencies": { "@cesdk/cesdk-js": "^1.20.0", + "@imgly/plugin-commands-polyfill": "*", "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer-web": "*", "react": "^18.2.0", "react-cmdk": "^1.3.9", - "react-dom": "^18.2.0", - "share-api-polyfill": "^1.1.1" + "react-dom": "^18.2.0" }, "devDependencies": { "@types/react": "^18.2.43", diff --git a/examples/web/src/main.tsx b/examples/web/src/main.tsx index e63eef4..0466645 100644 --- a/examples/web/src/main.tsx +++ b/examples/web/src/main.tsx @@ -1,6 +1,6 @@ import React from 'react' import ReactDOM from 'react-dom/client' -import App from './App.tsx' +import App from './ui/App.tsx' ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/examples/web/src/addPlugins.ts b/examples/web/src/plugins/addPlugins.ts similarity index 73% rename from examples/web/src/addPlugins.ts rename to examples/web/src/plugins/addPlugins.ts index 31af477..7d29487 100644 --- a/examples/web/src/addPlugins.ts +++ b/examples/web/src/plugins/addPlugins.ts @@ -1,19 +1,22 @@ import CreativeEditorSDK from '@cesdk/cesdk-js'; -// import PolyfillCommandsPlugin from "@imgly/plugin-polyfill-commands" +import PolyfillCommandsPlugin from "@imgly/plugin-commands-polyfill" import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; const plugins = [ - // PolyfillCommandsPlugin(), + PolyfillCommandsPlugin(), VectorizerPlugin(), - BackgroundRemovalPlugin()] + // BackgroundRemovalPlugin() +] async function addPlugins(cesdk: CreativeEditorSDK) { try { + // @ts-ignore plugins.map(cesdk.unstable_addPlugin.bind(cesdk)) + + - - + } catch (error) { console.error('Could not add all plugins: ', error); } diff --git a/examples/web/src/App.tsx b/examples/web/src/ui/App.tsx similarity index 67% rename from examples/web/src/App.tsx rename to examples/web/src/ui/App.tsx index e459b7d..8ba2a05 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/ui/App.tsx @@ -4,34 +4,9 @@ import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin, { Manifest as VectorizerManifest } from '@imgly/plugin-vectorizer-web'; import { CommandPalette } from "./CommandPalette" -import 'share-api-polyfill'; +import { downloadBlocks } from "../utils/utils"; -const plugins = [VectorizerPlugin(), BackgroundRemovalPlugin()] -function downloadBlob(blob: Blob, filename: string) { - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = filename; - link.click(); - URL.revokeObjectURL(url); -} - -const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string, pages?: number[] }) => { - const postfix = options.mimeType.split("/")[1] - const pageIds = options.pages ?? [] - - blobs.forEach((blob, index) => { - const pageId = pageIds[index] - let pageName = `page-${index}` - if (pageId) { - const name = cesdk.engine.block.getName(pageId) - pageName = name?.length ? name : pageName - } - const filename = `${pageName}.${postfix}`; - downloadBlob(blob, filename); - }) - return Promise.resolve(); -} +import addPlugins from "../plugins/addPlugins"; function App() { @@ -76,7 +51,7 @@ function App() { return ( <> - + {/* */}
{ @@ -93,7 +68,7 @@ function App() { await Promise.all([ instance.addDefaultAssetSources(), instance.addDemoAssetSources({ sceneMode: "Design" }), - plugins.map(plugin => cesdk?.current?.unstable_addPlugin(plugin)) + addPlugins(instance) ]); await instance.createDesignScene(); }); diff --git a/examples/web/src/CommandPalette.tsx b/examples/web/src/ui/CommandPalette.tsx similarity index 100% rename from examples/web/src/CommandPalette.tsx rename to examples/web/src/ui/CommandPalette.tsx diff --git a/examples/web/src/utils/utils.ts b/examples/web/src/utils/utils.ts new file mode 100644 index 0000000..bf38140 --- /dev/null +++ b/examples/web/src/utils/utils.ts @@ -0,0 +1,27 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; + + +export function downloadBlob(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + link.click(); + URL.revokeObjectURL(url); +} +export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { + const postfix = options.mimeType.split("/")[1]; + const pageIds = options.pages ?? []; + + blobs.forEach((blob, index) => { + const pageId = pageIds[index]; + let pageName = `page-${index}`; + if (pageId) { + const name = cesdk.engine.block.getName(pageId); + pageName = name?.length ? name : pageName; + } + const filename = `${pageName}.${postfix}`; + downloadBlob(blob, filename); + }); + return Promise.resolve(); +}; diff --git a/package.json b/package.json index f18858a..cb2e16b 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,10 @@ "version": "0.0.0", "workspaces": [ "examples/web", + "packages/commands-polyfill", "packages/background-removal", "packages/vectorizer" + ], "scripts": { "build": "turbo run build --force", diff --git a/packages/polyfill-commands/LICENSE.md b/packages/commands-polyfill/LICENSE.md similarity index 100% rename from packages/polyfill-commands/LICENSE.md rename to packages/commands-polyfill/LICENSE.md diff --git a/packages/polyfill-commands/README.md b/packages/commands-polyfill/README.md similarity index 100% rename from packages/polyfill-commands/README.md rename to packages/commands-polyfill/README.md diff --git a/packages/polyfill-commands/STRUCTURE.md b/packages/commands-polyfill/STRUCTURE.md similarity index 100% rename from packages/polyfill-commands/STRUCTURE.md rename to packages/commands-polyfill/STRUCTURE.md diff --git a/packages/polyfill-commands/TODO.md b/packages/commands-polyfill/TODO.md similarity index 100% rename from packages/polyfill-commands/TODO.md rename to packages/commands-polyfill/TODO.md diff --git a/packages/polyfill-commands/esbuild/config.mjs b/packages/commands-polyfill/esbuild/config.mjs similarity index 100% rename from packages/polyfill-commands/esbuild/config.mjs rename to packages/commands-polyfill/esbuild/config.mjs diff --git a/packages/polyfill-commands/esbuild/global.d.ts b/packages/commands-polyfill/esbuild/global.d.ts similarity index 100% rename from packages/polyfill-commands/esbuild/global.d.ts rename to packages/commands-polyfill/esbuild/global.d.ts diff --git a/packages/polyfill-commands/package.json b/packages/commands-polyfill/package.json similarity index 97% rename from packages/polyfill-commands/package.json rename to packages/commands-polyfill/package.json index f07b6cc..904311c 100644 --- a/packages/polyfill-commands/package.json +++ b/packages/commands-polyfill/package.json @@ -1,5 +1,5 @@ { - "name": "@imgly/plugin-polyfill-commands", + "name": "@imgly/plugin-commands-polyfill", "version": "0.1.0", "description": "Polyfill for Commands plugin for the CE.SDK editor", "keywords": [ diff --git a/packages/polyfill-commands/scripts/build.mjs b/packages/commands-polyfill/scripts/build.mjs similarity index 100% rename from packages/polyfill-commands/scripts/build.mjs rename to packages/commands-polyfill/scripts/build.mjs diff --git a/packages/polyfill-commands/scripts/watch.mjs b/packages/commands-polyfill/scripts/watch.mjs similarity index 100% rename from packages/polyfill-commands/scripts/watch.mjs rename to packages/commands-polyfill/scripts/watch.mjs diff --git a/packages/commands-polyfill/src/index.ts b/packages/commands-polyfill/src/index.ts new file mode 100644 index 0000000..e926b42 --- /dev/null +++ b/packages/commands-polyfill/src/index.ts @@ -0,0 +1,59 @@ +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; + +import Manifest from './manifest'; + + +export interface PluginConfiguration { + // uploader ? +} + +export { Manifest }; + +export default (pluginConfiguration: PluginConfiguration = {}) => { + return { + initialize(engine: CreativeEngine) { + + + }, + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + polyfillWithCommands(cesdk); + }, + + // maybe this should be just engint.event.onUpdate() + update() { + + }, + + }; +}; + + + +export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; + +export type CommandType = (params: any) => Promise; + +export class Commands { + #entries = new Map() + constructor(sdk: CreativeEditorSDK) { + } + registerCommand(label: string, callback: (params: any) => Promise) { + this.#entries.set(label, callback); + } + async executeCommand(label: string, params: any) { + const command = this.#entries.get(label); + if (command) { + await command(params); + } else { + throw new Error(`Command ${label} not found`); + } + } + +} +export function polyfillWithCommands(sdk: CreativeEditorSDK) { + // @ts-ignore + if (!sdk.engine.polyfill_commands) { + // @ts-ignore + sdk.engine.polyfill_commands = new Commands(); + } +} \ No newline at end of file diff --git a/packages/polyfill-commands/src/manifest.ts b/packages/commands-polyfill/src/manifest.ts similarity index 100% rename from packages/polyfill-commands/src/manifest.ts rename to packages/commands-polyfill/src/manifest.ts diff --git a/packages/polyfill-commands/src/worker.ts b/packages/commands-polyfill/src/worker.ts similarity index 100% rename from packages/polyfill-commands/src/worker.ts rename to packages/commands-polyfill/src/worker.ts diff --git a/packages/polyfill-commands/tsconfig.json b/packages/commands-polyfill/tsconfig.json similarity index 100% rename from packages/polyfill-commands/tsconfig.json rename to packages/commands-polyfill/tsconfig.json diff --git a/packages/polyfill-commands/types/index.d.ts b/packages/commands-polyfill/types/index.d.ts similarity index 63% rename from packages/polyfill-commands/types/index.d.ts rename to packages/commands-polyfill/types/index.d.ts index 7e77099..48946cc 100644 --- a/packages/polyfill-commands/types/index.d.ts +++ b/packages/commands-polyfill/types/index.d.ts @@ -1,11 +1,10 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import Manifest from './manifest'; -import { CreativeEngineWithPolyfills } from './utils/polyfills'; export interface PluginConfiguration { } export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { - initialize(engine: CreativeEngineWithPolyfills): void; + initialize(engine: CreativeEngine): void; initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; diff --git a/packages/polyfill-commands/types/manifest.d.ts b/packages/commands-polyfill/types/manifest.d.ts similarity index 100% rename from packages/polyfill-commands/types/manifest.d.ts rename to packages/commands-polyfill/types/manifest.d.ts diff --git a/packages/polyfill-commands/types/utils/polyfills.d.ts b/packages/commands-polyfill/types/utils/polyfills.d.ts similarity index 63% rename from packages/polyfill-commands/types/utils/polyfills.d.ts rename to packages/commands-polyfill/types/utils/polyfills.d.ts index ad9669b..af78ae7 100644 --- a/packages/polyfill-commands/types/utils/polyfills.d.ts +++ b/packages/commands-polyfill/types/utils/polyfills.d.ts @@ -1,12 +1,12 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands; }; export type CommandType = (params: any) => Promise; export declare class Commands { #private; - constructor(engine: CreativeEngineWithPolyfills); + constructor(sdk: CreativeEditorSDK); registerCommand(label: string, callback: (params: any) => Promise): void; executeCommand(label: string, params: any): Promise; } -export declare function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills): void; +export declare function polyfillWithCommands(sdk: CreativeEditorSDK): void; diff --git a/packages/polyfill-commands/types/worker.d.ts b/packages/commands-polyfill/types/worker.d.ts similarity index 100% rename from packages/polyfill-commands/types/worker.d.ts rename to packages/commands-polyfill/types/worker.d.ts diff --git a/packages/polyfill-commands/src/index.ts b/packages/polyfill-commands/src/index.ts deleted file mode 100644 index 3aed9fb..0000000 --- a/packages/polyfill-commands/src/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; - -import Manifest from './manifest'; - - -import { polyfillEngineWithCommands, CreativeEngineWithPolyfills } from './utils/polyfills'; - - -export interface PluginConfiguration { - // uploader ? -} - -export { Manifest }; - -export default (pluginConfiguration: PluginConfiguration = {}) => { - return { - initialize(engine: CreativeEngineWithPolyfills) { - - }, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - const engine = cesdk.engine as CreativeEngineWithPolyfills; - polyfillEngineWithCommands(engine); - - }, - - - // maybe this should be just engint.event.onUpdate() - update() { - - }, - - }; -}; diff --git a/packages/polyfill-commands/src/utils/polyfills.ts b/packages/polyfill-commands/src/utils/polyfills.ts deleted file mode 100644 index 399a757..0000000 --- a/packages/polyfill-commands/src/utils/polyfills.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; - -export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; - -export type CommandType = (params: any) => Promise; - -export class Commands { - #engine: CreativeEngineWithPolyfills - #entries = new Map() - constructor(engine: CreativeEngineWithPolyfills) { - this.#engine = engine; - } - registerCommand(label: string, callback: (params: any) => Promise) { - this.#entries.set(label, callback); - } - async executeCommand(label: string, params: any) { - const command = this.#entries.get(label); - if (command) { - await command(params); - } else { - throw new Error(`Command ${label} not found`); - } - } - -} -export function polyfillEngineWithCommands(engine: CreativeEngineWithPolyfills) { - //polyfill - if (!engine.polyfill_commands) { - engine.polyfill_commands = new Commands(engine); - } -} \ No newline at end of file diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index 1d12e3b..e3813f6 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -5,7 +5,8 @@ import commands from './commands'; import i18n from './i18n'; import Manifest, { PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_ID } from './manifest'; -import { polyfillEngineWithCommands, CreativeEngineWithPolyfills } from './utils/polyfills'; + + import { clearPluginMetadata, fixDuplicateMetadata, @@ -26,7 +27,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { return { id: PLUGIN_ID, version: PLUGIN_VERSION, - initialize(engine: CreativeEngineWithPolyfills) { + initialize(engine: CreativeEngine) { // it is unclear for a user which one to call and what happens and if we have to put code in both or just one // we should have a clear separation of concerns // also maybe better naming @@ -34,10 +35,13 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { // onInitUI }, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + console.log(cesdk) // This should move into a seperate plugin - const engine = polyfillEngineWithCommands(cesdk.engine); - if (!engine.polyfill_commands) { - console.error("Polyfill engine.commands not available!") + // const engine = polyfillEngineWithCommands(cesdk.engine); + const engine = cesdk.engine; + // @ts-ignore + if (!cesdk.engine.polyfill_commands) { + console.error("Polyfill engine.engine.polyfill_commands not available!") return; } @@ -55,7 +59,8 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { }); }); - console.log("checking if engine has polyfill_commands", engine.polyfill_commands ? "yes" : "no") + //@ts-ignore + console.log("checking if engine has polyfill_commands", cesdk.engine.polyfill_commands ? "yes" : "no") engine.event.subscribe([], async (events) => { events @@ -64,13 +69,14 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { .forEach(e => handleUpdateEvent(engine, e.block)) }); - console.info("Registering plugin actions") - Object.keys(commands).forEach((action) => { - console.info(`Registering action: ${action}`) + console.info("Registering plugin command") + Object.keys(commands).forEach((command) => { + console.info(`Registering action: ${command}`) // @ts-ignore - const func = commands[action]; - engine.polyfill_commands?.registerCommand( - action, + const func = commands[command]; + // @ts-ignore + cesdk.engine.polyfill_commands?.registerCommand( + command, async (params: any) => await func(cesdk, params) ); }) @@ -78,11 +84,13 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { console.info("Registering plugin I18N translations") cesdk.setTranslations(i18n); + console.info("Registering plugin UI components") - Object.keys(ui).forEach((componentId) => { - console.info(`Registering component: ${componentId}`) + const components = ui(cesdk) + + Object.keys(components).forEach((componentId) => { // @ts-ignore - const component = ui[componentId] + const component = components[componentId] cesdk.ui.unstable_registerComponent(componentId, component); }) @@ -93,11 +101,11 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, (context: any) => { return areBlocksSupported(engine, engine.block.findAllSelected()) }) - + cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, false); cesdk.feature.unstable_enable(PLUGIN_ID, false); cesdk.feature.unstable_enable(PLUGIN_ACTION_VECTORIZE_LABEL, false); - + console.info("Changing canvas menu order") const canvasMenuEntries = [ diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 9b93931..80e8550 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,3 +1,4 @@ +import CreativeEditorSDK from '@cesdk/cesdk-js'; import { PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_ACTION_VECTORIZE_LABEL @@ -7,34 +8,36 @@ import { getPluginMetadata, isBlockSupported, } from './utils'; -import { CreativeEngineWithPolyfills } from './utils/polyfills'; -const button = (params: any) => { - const engine = params.engine! as CreativeEngineWithPolyfills - const builder = params.builder! - // the button might need the ids it is shown for - // the isSupported - const selected = engine.block.findAllSelected(); - const candidates = selected.filter(id => isBlockSupported(engine, id)) - if (candidates.length === 0) return; +// I need cesdk atm +export default (cesdk: CreativeEditorSDK) => { + // @maerch: Shouldn't the params include "cesdk" and not engine? + const button = (params: any) => { + const builder = params.builder! - let isLoading = candidates.some(id => getPluginMetadata(engine, id).status === 'PROCESSING') + // the button might need the ids it is shown for + // the isSupported + const selected = cesdk.engine.block.findAllSelected(); + const candidates = selected.filter((id: number) => isBlockSupported(cesdk.engine, id)) + if (candidates.length === 0) return; - // @maerch: Why do we need the Button ID here? - builder.Button("DO I NEED THIS", { - label: PLUGIN_ACTION_VECTORIZE_LABEL, - icon: '@imgly/icons/Vectorize', - isActive: false, - isLoading: isLoading, - isDisabled: isLoading, - loadingProgress: undefined, // creates infinite spinner - onClick: () => engine - .polyfill_commands - ?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockIds: candidates }) - }); -} + let isLoading = candidates.some((id: number) => getPluginMetadata(cesdk.engine, id).status === 'PROCESSING') -export default { - [PLUGIN_COMPONENT_BUTTON_ID]: button + // @maerch: Why do we need the Button ID here? + builder.Button("DO I NEED THIS", { + label: PLUGIN_ACTION_VECTORIZE_LABEL, + icon: '@imgly/icons/Vectorize', + isActive: false, + isLoading: isLoading, + isDisabled: isLoading, + loadingProgress: undefined, // creates infinite spinner + onClick: () => cesdk + // @ts-ignore + .engine.polyfill_commands + ?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockIds: candidates }) + }); + } + + return { [PLUGIN_COMPONENT_BUTTON_ID]: button } } // end of export default diff --git a/packages/vectorizer/src/utils/polyfills.ts b/packages/vectorizer/src/utils/polyfills.ts deleted file mode 100644 index 4d33237..0000000 --- a/packages/vectorizer/src/utils/polyfills.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; - -export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; - -export type CommandType = (params: any) => Promise; - -export class Commands { - #engine: CreativeEngineWithPolyfills - #entries = new Map() - constructor(engine: CreativeEngineWithPolyfills) { - this.#engine = engine; - } - registerCommand(label: string, callback: (params: any) => Promise) { - this.#entries.set(label, callback); - } - async executeCommand(label: string, params: any) { - const command = this.#entries.get(label); - if (command) { - await command(params); - } else { - throw new Error(`Command ${label} not found`); - } - } - -} -export function polyfillEngineWithCommands(engine: CreativeEngine) { - const polyfilled = engine as CreativeEngineWithPolyfills; - //polyfill - if (!polyfilled.polyfill_commands ) { - polyfilled.polyfill_commands = new Commands(engine); - } - return polyfilled -} \ No newline at end of file diff --git a/packages/vectorizer/src/utils/types.ts b/packages/vectorizer/src/utils/types.ts index 8f09444..657f9de 100644 --- a/packages/vectorizer/src/utils/types.ts +++ b/packages/vectorizer/src/utils/types.ts @@ -1,4 +1,4 @@ -import { type Source } from '@cesdk/cesdk-js'; +import { type Source, type CreativeEngine } from '@cesdk/cesdk-js'; export type PluginStatusIdle = { status: 'IDLE' }; // export type PluginStatusPending = { status: 'PENDING' }; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index 86eedf9..54d391d 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -1,13 +1,12 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import Manifest from './manifest'; -import { CreativeEngineWithPolyfills } from './utils/polyfills'; export interface PluginConfiguration { } export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { id: string; version: string; - initialize(engine: CreativeEngineWithPolyfills): void; + initialize(engine: CreativeEngine): void; initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts index 4746d3f..ad890fe 100644 --- a/packages/vectorizer/types/ui.d.ts +++ b/packages/vectorizer/types/ui.d.ts @@ -1,4 +1,5 @@ -declare const _default: { +import CreativeEditorSDK from '@cesdk/cesdk-js'; +declare const _default: (cesdk: CreativeEditorSDK) => { "component.@imgly/plugin-vectorizer-web.button": (params: any) => void; }; export default _default; diff --git a/packages/vectorizer/types/utils/commands.d.ts b/packages/vectorizer/types/utils/commands.d.ts new file mode 100644 index 0000000..5075718 --- /dev/null +++ b/packages/vectorizer/types/utils/commands.d.ts @@ -0,0 +1,7 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +declare const _default: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { + blockIds?: number[] | undefined; + }) => Promise; +}; +export default _default; diff --git a/turbo.json b/turbo.json index cf7f347..b126bc6 100644 --- a/turbo.json +++ b/turbo.json @@ -12,6 +12,10 @@ "dev:types": { "cache": false, "persistent": true + }, + "check:pretty": { + "cache": false, + "persistent": true } } } diff --git a/yarn.lock b/yarn.lock index 2ae2cbb..5b66b66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4290,11 +4290,6 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" -share-api-polyfill@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/share-api-polyfill/-/share-api-polyfill-1.1.1.tgz#373bacac2f02828a3ee1bd7d9a2b72c60580080e" - integrity sha512-5GxXomFRth4lBpHWN136cxpv8KOo+uutljXqgO1RsptDQ5X1raRQWqLi+LoWZ/h02/TgV1STJwuMXcP/0b1vpQ== - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" From 94645a72ac499939e8542d8ac1121a472083374c Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 17:41:05 +0100 Subject: [PATCH 16/32] feat: Polyfill Plugin --- packages/commands-polyfill/src/index.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/commands-polyfill/src/index.ts b/packages/commands-polyfill/src/index.ts index e926b42..73958d7 100644 --- a/packages/commands-polyfill/src/index.ts +++ b/packages/commands-polyfill/src/index.ts @@ -9,21 +9,11 @@ export interface PluginConfiguration { export { Manifest }; -export default (pluginConfiguration: PluginConfiguration = {}) => { +export default () => { return { - initialize(engine: CreativeEngine) { - - - }, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { polyfillWithCommands(cesdk); - }, - - // maybe this should be just engint.event.onUpdate() - update() { - - }, - + } }; }; @@ -35,11 +25,11 @@ export type CommandType = (params: any) => Promise; export class Commands { #entries = new Map() - constructor(sdk: CreativeEditorSDK) { - } + registerCommand(label: string, callback: (params: any) => Promise) { this.#entries.set(label, callback); } + async executeCommand(label: string, params: any) { const command = this.#entries.get(label); if (command) { From 6855ffc84812bf0a4040140e3e085cceeb7e7e6e Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 17:41:24 +0100 Subject: [PATCH 17/32] fix: Readded background removal --- examples/web/src/plugins/addPlugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/web/src/plugins/addPlugins.ts b/examples/web/src/plugins/addPlugins.ts index 7d29487..b233095 100644 --- a/examples/web/src/plugins/addPlugins.ts +++ b/examples/web/src/plugins/addPlugins.ts @@ -6,7 +6,7 @@ import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; const plugins = [ PolyfillCommandsPlugin(), VectorizerPlugin(), - // BackgroundRemovalPlugin() + BackgroundRemovalPlugin() ] async function addPlugins(cesdk: CreativeEditorSDK) { From 589a4da7c9640ba34a440ee387564739ef78d419 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 17:43:10 +0100 Subject: [PATCH 18/32] fix: Build --- examples/web/src/ui/App.tsx | 2 +- examples/web/src/ui/CommandPalette.tsx | 34 ++++++++++----------- packages/commands-polyfill/types/index.d.ts | 14 +++++++-- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/examples/web/src/ui/App.tsx b/examples/web/src/ui/App.tsx index 8ba2a05..cc3ab35 100644 --- a/examples/web/src/ui/App.tsx +++ b/examples/web/src/ui/App.tsx @@ -51,7 +51,7 @@ function App() { return ( <> - {/* */} +
{ diff --git a/examples/web/src/ui/CommandPalette.tsx b/examples/web/src/ui/CommandPalette.tsx index e33087c..b11968f 100644 --- a/examples/web/src/ui/CommandPalette.tsx +++ b/examples/web/src/ui/CommandPalette.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, RefObject } from "react"; import CreativeEditorSDK from "@cesdk/cesdk-js"; // https://github.com/albingroen/react-cmdk -export const CommandPalette = (params: { cesdkRef: RefObject, actions: Array }) => { +export const CommandPalette = (params: { cesdkRef: RefObject}) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); const [isOpen, setIsOpen] = useState(false); @@ -137,22 +137,22 @@ export const CommandPalette = (params: { cesdkRef: RefObject { - return { - id: action.id, - children: action.id, - showType: false, - onClick: () => { - // @ts-ignore - const act = window.cesdk_actions.get(action.id) - act?.() - } - } - }) - } + // { + // heading: "Turn into...", + // id: "turnInto", + // items: params.actions.map(action => { + // return { + // id: action.id, + // children: action.id, + // showType: false, + // onClick: () => { + // // @ts-ignore + // const act = window.cesdk_actions.get(action.id) + // act?.() + // } + // } + // }) + // } ], search ); diff --git a/packages/commands-polyfill/types/index.d.ts b/packages/commands-polyfill/types/index.d.ts index 48946cc..5a79216 100644 --- a/packages/commands-polyfill/types/index.d.ts +++ b/packages/commands-polyfill/types/index.d.ts @@ -3,11 +3,19 @@ import Manifest from './manifest'; export interface PluginConfiguration { } export { Manifest }; -declare const _default: (pluginConfiguration?: PluginConfiguration) => { - initialize(engine: CreativeEngine): void; +declare const _default: () => { initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; - update(): void; }; export default _default; +export type CreativeEngineWithPolyfills = CreativeEngine & { + polyfill_commands?: Commands; +}; +export type CommandType = (params: any) => Promise; +export declare class Commands { + #private; + registerCommand(label: string, callback: (params: any) => Promise): void; + executeCommand(label: string, params: any): Promise; +} +export declare function polyfillWithCommands(sdk: CreativeEditorSDK): void; From 6ba69d43e2c64434cb6307ed0ae3c4a1c6eae436 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Mon, 12 Feb 2024 22:16:33 +0100 Subject: [PATCH 19/32] feat: Refactored app to make use of Commandpalette --- LIST_OF_PLUGINS.md | 8 +- examples/web/src/ui/App.tsx | 87 ++++++++----- examples/web/src/ui/CommandPalette.tsx | 132 ++------------------ examples/web/src/ui/CreativeEditorSDK.tsx | 45 +++++++ packages/commands-polyfill/src/index.ts | 10 +- packages/commands-polyfill/types/index.d.ts | 7 +- packages/vectorizer/src/i18n.ts | 5 - packages/vectorizer/src/index.ts | 4 +- packages/vectorizer/src/manifest.ts | 14 ++- packages/vectorizer/types/manifest.d.ts | 10 ++ 10 files changed, 150 insertions(+), 172 deletions(-) create mode 100644 examples/web/src/ui/CreativeEditorSDK.tsx delete mode 100644 packages/vectorizer/src/i18n.ts diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md index cd285bd..6ecc7a8 100644 --- a/LIST_OF_PLUGINS.md +++ b/LIST_OF_PLUGINS.md @@ -181,4 +181,10 @@ ## Debugging - [ ] Debugging - [ ] CommandPalette - - [ ] {Print, Save,, Meta \ No newline at end of file + - [ ] {Print, Save,, Meta} + + + + +## Other +- [ ] Reduce colors to 1...n diff --git a/examples/web/src/ui/App.tsx b/examples/web/src/ui/App.tsx index cc3ab35..68963dd 100644 --- a/examples/web/src/ui/App.tsx +++ b/examples/web/src/ui/App.tsx @@ -1,16 +1,22 @@ -import { useRef } from "react"; -import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; -import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; -import VectorizerPlugin, { Manifest as VectorizerManifest } from '@imgly/plugin-vectorizer-web'; +import { useRef, useState } from "react"; +import { type WithCommands } from "@imgly/plugin-commands-polyfill"; import { CommandPalette } from "./CommandPalette" import { downloadBlocks } from "../utils/utils"; import addPlugins from "../plugins/addPlugins"; +import CreativeEditorSDKComponent from "./CreativeEditorSDK"; +import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; + +declare global { + interface Window { cesdk: WithCommands } +} function App() { - const cesdk = useRef(); + const cesdkRef = useRef>(); + const [commandItems, setCommandItems] = useState>([]) + const config: Configuration = { license: import.meta.env.VITE_CESDK_LICENSE_KEY, callbacks: { @@ -18,11 +24,11 @@ function App() { onDownload: "download", onSave: async (str: string) => { // improve - return downloadBlocks(cesdk.current!, [new Blob([str])], { mimeType: 'application/imgly' }) + return downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }) }, onExport: async (blobs, options) => { - return downloadBlocks(cesdk.current!, blobs, { mimeType: options.mimeType, pages: options.pages }) + return downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }) }, onLoad: "upload", @@ -49,36 +55,51 @@ function App() { } + return ( <> - -
{ - if (domElement != null) { - CreativeEditorSDK - .create(domElement, config) - .then(async (instance) => { - // @ts-ignore - window.cesdk = instance; - cesdk.current = instance; - - // Do something with the instance of CreativeEditor SDK, for example: - // Populate the asset library with default / demo asset sources. - await Promise.all([ - instance.addDefaultAssetSources(), - instance.addDemoAssetSources({ sceneMode: "Design" }), - addPlugins(instance) - ]); - await instance.createDesignScene(); - }); - } else if (cesdk.current != null) { - cesdk.current.dispose(); - } - }} - >
+ + { + + cesdk = cesdk as WithCommands; + await Promise.all([ + cesdk.addDefaultAssetSources(), + cesdk.addDemoAssetSources({ sceneMode: "Design" }), + addPlugins(cesdk) + ]); + await cesdk.createDesignScene(); + + // window.cesdk = cesdk as WithCommands; + window.cesdk = cesdkRef.current = cesdk as WithCommands; + const commandItems = generateCommandItems(cesdk as WithCommands) + setCommandItems(commandItems) + + + }} /> ); } export default App; + + + + +const generateCommandItems = (cesdk: WithCommands): Array => { + return cesdk + .engine + .polyfill_commands + .listCommands() + .map((cmdId: string) => { + + const titel = cmdId + return { + id: cmdId, + children: titel, + showType: true, + onClick: async () => { + await cesdk.engine.polyfill_commands.executeCommand(cmdId, {}) + } + } + }) +} \ No newline at end of file diff --git a/examples/web/src/ui/CommandPalette.tsx b/examples/web/src/ui/CommandPalette.tsx index b11968f..747961e 100644 --- a/examples/web/src/ui/CommandPalette.tsx +++ b/examples/web/src/ui/CommandPalette.tsx @@ -1,18 +1,16 @@ import "react-cmdk/dist/cmdk.css"; -import CMDK , { filterItems, getItemIndex } from "react-cmdk"; -import { useState, useEffect, RefObject } from "react"; -import CreativeEditorSDK from "@cesdk/cesdk-js"; +import CMDK, { filterItems, getItemIndex } from "react-cmdk"; +import { useState, useEffect } from "react"; + // https://github.com/albingroen/react-cmdk -export const CommandPalette = (params: { cesdkRef: RefObject}) => { +export const CommandPalette = (params: { items: Array }) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); const [isOpen, setIsOpen] = useState(false); - const { cesdkRef } = params - - if (!(cesdkRef)) return - const cesdk = cesdkRef?.current + const { items } = params + // debugger useEffect(() => { function handleKeyDown(e: KeyboardEvent) { if ( @@ -37,122 +35,14 @@ export const CommandPalette = (params: { cesdkRef: RefObject { - console.log("Clicked on projects") - console.log("Cesdk ref", cesdkRef ?? "No ref") - }, - }, - { - id: "duplicate", - children: "Duplicate Selected Blocks", - showType: false, - onClick: () => { - const selected = cesdk!.engine.block.findAllSelected() ?? [] - selected.map((id: any) => { - cesdk!.engine.block.setSelected(id, false) - const dupId = cesdk!.engine.block.duplicate(id) - cesdk!.engine.block.setSelected(dupId, true) - }) - }, - }, - { - id: "delete", - children: "Delete Selected Blocks", - showType: false, - onClick: () => { - const selected = cesdk!.engine.block.findAllSelected() ?? [] - selected.map((id: any) => { - - cesdk!.engine.block.destroy(id) - }) - }, - } - , - { - id: "saveToClipboard", - children: "Save to Clipboard", - showType: false, - onClick: async () => { - const selected = cesdk!.engine.block.findAllSelected() ?? [] - const dump = await cesdk!.engine.block.saveToString(selected) - // console.info(dump) - navigator.clipboard.writeText(dump); - }, - }, - { - id: "loadFromClipboard", - children: "Load from Clipboard", - showType: false, - onClick: async () => { - // @ts-ignore - const status = await navigator.permissions.query({ name: 'clipboard-read' }) - console.log("Clipboard read status", status.state) - const dump = await navigator.clipboard.readText() - const blockIds = await cesdk!.engine.block.loadFromString(dump) - const parentId = cesdk!.engine.scene.getCurrentPage() - if (!parentId || !blockIds) { - console.error("No parent or block id") - return - } - blockIds.map((blockId: any) => { - cesdk!.engine.block.appendChild(parentId, blockId) - }) - - - }, - } - ], - }, - { - heading: "Export", - id: "export", - items: [ - { - id: "exportPngToClipboard", - children: "Export PNG to Clipboard", - showType: false, - onClick: async () => { - // await navigator.permissions.query({ name: 'clipboard-write' }) - const selected = cesdk!.engine.block.findAllSelected() ?? [] - if (selected.length !== 1) return - - // most browser can only do on1 - const items = await Promise.all(selected.map(async (id: number) => { - // @ts-ignore - const dump = await cesdk!.engine.block.export(id, "image/png") - return new ClipboardItem({ "image/png": dump }, { presentationStyle: "attachment" }) - })) - navigator.clipboard.write(items) - }, - }, - ] - }, - // { - // heading: "Turn into...", - // id: "turnInto", - // items: params.actions.map(action => { - // return { - // id: action.id, - // children: action.id, - // showType: false, - // onClick: () => { - // // @ts-ignore - // const act = window.cesdk_actions.get(action.id) - // act?.() - // } - // } - // }) - // } + heading: undefined, + id: "turnInto", + items: items?? [] + } ], search ); diff --git a/examples/web/src/ui/CreativeEditorSDK.tsx b/examples/web/src/ui/CreativeEditorSDK.tsx new file mode 100644 index 0000000..aab1d05 --- /dev/null +++ b/examples/web/src/ui/CreativeEditorSDK.tsx @@ -0,0 +1,45 @@ +import { useRef, useState, useEffect } from "react"; +import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; + + + +type Props = { + config: Configuration, callback: (cesdk: CreativeEditorSDK) => Promise +} +export default function CreativeEditorSDKComponent(props: Props) { + const cesdk_container = useRef(null); + + const [_, setCesdk] = useState(); + + useEffect(() => { + if (!cesdk_container.current) return; + + let cleanedUp = false; + let instance: CreativeEditorSDK; + CreativeEditorSDK + .create(cesdk_container.current, props.config) + .then( + async (instance) => { + if (cleanedUp) { + instance.dispose(); + return; + } + setCesdk(instance); + await props.callback(instance); + } + ); + + return () => { + cleanedUp = true; + instance?.dispose(); + setCesdk(undefined); + };; + }, [cesdk_container]); + + return ( +
+ ); +} \ No newline at end of file diff --git a/packages/commands-polyfill/src/index.ts b/packages/commands-polyfill/src/index.ts index 73958d7..c425153 100644 --- a/packages/commands-polyfill/src/index.ts +++ b/packages/commands-polyfill/src/index.ts @@ -18,18 +18,20 @@ export default () => { }; - -export type CreativeEngineWithPolyfills = CreativeEngine & { polyfill_commands?: Commands }; +export type WithCommands = T & { engine: CreativeEngine & { polyfill_commands: Commands } }; export type CommandType = (params: any) => Promise; export class Commands { #entries = new Map() - + + listCommands() { + return Array.from(this.#entries.keys()); + } registerCommand(label: string, callback: (params: any) => Promise) { this.#entries.set(label, callback); } - + async executeCommand(label: string, params: any) { const command = this.#entries.get(label); if (command) { diff --git a/packages/commands-polyfill/types/index.d.ts b/packages/commands-polyfill/types/index.d.ts index 5a79216..9aee2a0 100644 --- a/packages/commands-polyfill/types/index.d.ts +++ b/packages/commands-polyfill/types/index.d.ts @@ -9,12 +9,15 @@ declare const _default: () => { }): void; }; export default _default; -export type CreativeEngineWithPolyfills = CreativeEngine & { - polyfill_commands?: Commands; +export type WithCommands = T & { + engine: CreativeEngine & { + polyfill_commands: Commands; + }; }; export type CommandType = (params: any) => Promise; export declare class Commands { #private; + listCommands(): string[]; registerCommand(label: string, callback: (params: any) => Promise): void; executeCommand(label: string, params: any): Promise; } diff --git a/packages/vectorizer/src/i18n.ts b/packages/vectorizer/src/i18n.ts deleted file mode 100644 index 90b5033..0000000 --- a/packages/vectorizer/src/i18n.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest' - -export const en = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vector' } -export const de = { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Wandle in Vector' } -export default { de, en }; \ No newline at end of file diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index e3813f6..383abac 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -2,7 +2,6 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import ui from './ui'; import commands from './commands'; -import i18n from './i18n'; import Manifest, { PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_ID } from './manifest'; @@ -35,7 +34,6 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { // onInitUI }, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - console.log(cesdk) // This should move into a seperate plugin // const engine = polyfillEngineWithCommands(cesdk.engine); const engine = cesdk.engine; @@ -82,7 +80,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { }) console.info("Registering plugin I18N translations") - cesdk.setTranslations(i18n); + cesdk.setTranslations(Manifest.contributes.i18n); console.info("Registering plugin UI components") diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index 7407bbb..480692a 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -3,10 +3,9 @@ export const PLUGIN_COMPONENT_BUTTON_ID = `component.${PLUGIN_ID}.button`; export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` - export default { id: PLUGIN_ID, - + titel: "", contributes: { ui: [ { @@ -16,7 +15,16 @@ export default { commands: [ { id: PLUGIN_ACTION_VECTORIZE_LABEL, + titel: "Turn into Vectorpath", // default titel, use i18n ti + } + ], + i18n: { + en: { + [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vectorpaths' + }, + de: { + [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Wandle in Vectorpfade' } - ] + } } } \ No newline at end of file diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts index 74d1f84..41897ca 100644 --- a/packages/vectorizer/types/manifest.d.ts +++ b/packages/vectorizer/types/manifest.d.ts @@ -3,13 +3,23 @@ export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.@imgly/plugin-vecto export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; declare const _default: { id: string; + titel: string; contributes: { ui: { id: string; }[]; commands: { id: string; + titel: string; }[]; + i18n: { + en: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; + de: { + "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + }; + }; }; }; export default _default; From 12b5a4910126ceffdeed2e495c4ffc9f337f5885 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Tue, 13 Feb 2024 19:37:09 +0100 Subject: [PATCH 20/32] wip: Added lot's of commands --- LIST_OF_PLUGINS.md | 8 +- TODO.md | 19 ++ examples/web/package.json | 3 +- examples/web/src/App.tsx | 169 ++++++++++++++++++ .../src/{ui => components}/CommandPalette.tsx | 2 +- .../{ui => components}/CreativeEditorSDK.tsx | 18 +- examples/web/src/main.tsx | 2 +- examples/web/src/plugins/addPlugins.ts | 25 --- .../web/src/plugins/imgly-commands/debug.ts | 135 ++++++++++++++ .../web/src/plugins/imgly-commands/export.ts | 54 ++++++ .../src/plugins/imgly-commands/lifecycle.ts | 30 ++++ .../src/plugins/imgly-commands/turn_into.ts | 0 examples/web/src/ui/App.tsx | 105 ----------- examples/web/src/ui/commandPaletteButton.ts | 0 examples/web/src/utils/cesdk.ts | 18 ++ .../web/src/utils/{utils.ts => download.ts} | 2 + examples/web/src/utils/flatten.ts | 46 +++++ packages/vectorizer/src/index.ts | 3 +- packages/vectorizer/src/manifest.ts | 18 +- packages/vectorizer/types/commands.d.ts | 2 +- packages/vectorizer/types/index.d.ts | 24 ++- packages/vectorizer/types/manifest.d.ts | 19 +- packages/vectorizer/types/ui.d.ts | 2 +- 23 files changed, 536 insertions(+), 168 deletions(-) create mode 100644 examples/web/src/App.tsx rename examples/web/src/{ui => components}/CommandPalette.tsx (96%) rename examples/web/src/{ui => components}/CreativeEditorSDK.tsx (69%) delete mode 100644 examples/web/src/plugins/addPlugins.ts create mode 100644 examples/web/src/plugins/imgly-commands/debug.ts create mode 100644 examples/web/src/plugins/imgly-commands/export.ts create mode 100644 examples/web/src/plugins/imgly-commands/lifecycle.ts create mode 100644 examples/web/src/plugins/imgly-commands/turn_into.ts delete mode 100644 examples/web/src/ui/App.tsx create mode 100644 examples/web/src/ui/commandPaletteButton.ts create mode 100644 examples/web/src/utils/cesdk.ts rename examples/web/src/utils/{utils.ts => download.ts} (99%) create mode 100644 examples/web/src/utils/flatten.ts diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md index 6ecc7a8..c38378c 100644 --- a/LIST_OF_PLUGINS.md +++ b/LIST_OF_PLUGINS.md @@ -28,8 +28,8 @@ - [ ] Zoom to 100% - [ ] Block Lifecylce - - [ ] Duplicate Selected - - [ ] Delete Selected + - [x] Duplicate Selected + - [x] Delete Selected - [ ] Copy Selected - [ ] Paste Selected @@ -180,7 +180,8 @@ ## Debugging - [ ] Debugging - - [ ] CommandPalette + - [x] CommandPalette + - [ ] Print Metadata - [ ] {Print, Save,, Meta} @@ -188,3 +189,4 @@ ## Other - [ ] Reduce colors to 1...n +- [ ] Subtitel STR colors \ No newline at end of file diff --git a/TODO.md b/TODO.md index eda1223..b1d9ab2 100644 --- a/TODO.md +++ b/TODO.md @@ -11,3 +11,22 @@ - [ ] (Exkurs) How can I change the type of a block to another. E.g. Change a Graphic Block into a Group Block for Vectorizer and the ID should stay the same and all properties that are relevant. "Turn into" - [ ] The separation of ui and engine is sometimes too hard to use. I propose not to make it dependent on initUI and init. But more like lifecycles in general and always pass {ui?, engine, editor} - [ ] `upload` should maybe be part of the asset sources and/or part of engine + +- [ ] `listPanels` function is missing to know which panels exists and are registers +- [ ] `registerComponents` should get `cesdk` and not only `engine` +- [ ] **Naming correction** + - [ ] IMGLY = { ui: IMGLYUI, engine: IMGLYEngine } + - [ ] CESDK = { ui: CESDKUI, engine: CESDKEngine } + - Get rid of high level functions maybe +- [ ] SDK should use dynamic import internally to save space and also not load on non supported platforms +- [ ] Commands should be define as should be `func params {context: {engine, ui}, params: any}` +- [ ] `hasMetadata` should be `hasMetaDataKey` because it's referring to an entry or item not if the whole metadata is existing +- [ ] `lifetime/unsubscribe` is totally missing from plugin apu. E.g. VSCode offers a `subscribe` to register all that need to be called when the plugin is `unloaded` + + +- [ ] Clarify semantics of `label`, `titel`, and `id` + - [ ] Label is used for translation +- it's `block.export` but not `scene.export` as I would expect +- `pages` should have design units +- `pages` should have their type e.g. video vs static +- `docuements` are just groups and as such leverage multi-editing \ No newline at end of file diff --git a/examples/web/package.json b/examples/web/package.json index 9624e52..d43726c 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -10,9 +10,10 @@ }, "dependencies": { "@cesdk/cesdk-js": "^1.20.0", - "@imgly/plugin-commands-polyfill": "*", "@imgly/plugin-background-removal-web": "*", + "@imgly/plugin-commands-polyfill": "*", "@imgly/plugin-vectorizer-web": "*", + "lodash": "^4.17.21", "react": "^18.2.0", "react-cmdk": "^1.3.9", "react-dom": "^18.2.0" diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx new file mode 100644 index 0000000..1c260ef --- /dev/null +++ b/examples/web/src/App.tsx @@ -0,0 +1,169 @@ +import { useRef, useState } from "react"; +import CreativeEditorSDKComponent from "./components/CreativeEditorSDK"; +import CreativeEditorSDK, { Configuration} from "@cesdk/cesdk-js"; + +// React UI Components +import { CommandPalette } from "./components/CommandPalette" +// Utils +import { downloadBlocks } from "./utils/download"; + +// IMGLY Plugins +import PolyfillCommandsPlugin, { WithCommands } from "@imgly/plugin-commands-polyfill" +import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; +import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; +// IMGLY Commands +import { registerLifecycleCommands } from "./plugins/imgly-commands/lifecycle"; +import { registerDebugCommands } from "./plugins/imgly-commands/debug"; +import { registerExportCommands } from "./plugins/imgly-commands/export"; + + +declare global { + interface Window { cesdk: WithCommands } +} + + +function App() { + const cesdkRef = useRef>(); + const [commandItems, setCommandItems] = useState>([]) + const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false) + + + const commandPaletteButton = (params: { builder: any }) => { + params + .builder! + .Button("plugin.imgly.commandpalette.id", { + label: "plugin.imgly.commandpalette.label", + icon: undefined, + isActive: isCommandPaletteOpen, + isLoading: false, + isDisabled: isCommandPaletteOpen, + loadingProgress: undefined, // creates infinite spinner + onClick: () => { + debugger + setIsCommandPaletteOpen(true) + } + }); + } + + const [config, setConfig] = useState( + { + "license": import.meta.env.VITE_CESDK_LICENSE_KEY, + "callbacks.onUpload": "local", + "callbacks.onDownload": "download", + "callbacks.onSave": async (str: string) => downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }), + "callbacks.onExport": async (blobs: Array, options: any) => downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }), + "callbacks.onLoad": "upload", + + // devMode: true, + "theme": "dark", + "role": 'Creator', + "ui.hide": false, + "ui.elements.view": "advanced", + "ui.elements.navigation.action.save": true, + "ui.elements.navigation.action.load": true, + "ui.elements.navigation.action.export": true, + }) + + + const initCallback = async (_cesdk: CreativeEditorSDK) => { + const cesdk = _cesdk as WithCommands; + window.cesdk = cesdkRef.current = cesdk + // Register Plguins + await Promise.all([ + cesdk.addDefaultAssetSources(), + cesdk.addDemoAssetSources({ sceneMode: "Design" }), + cesdk.unstable_addPlugin(PolyfillCommandsPlugin()), + cesdk.unstable_addPlugin(VectorizerPlugin()), + cesdk.unstable_addPlugin(BackgroundRemovalPlugin()), + ]); + + // Commands -> Move to plugins + registerLifecycleCommands(cesdk) + registerDebugCommands(cesdk) + registerExportCommands(cesdk) + + // Ui components + cesdk.ui.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); + "plugin.imgly.commandpalette2" + cesdk.setTranslations({ en: { "plugin.imgly.commandpalette.label": ">" } }) + // Canvas Menu + const canvasMenuItems = cesdk.ui.unstable_getCanvasMenuOrder() + console.log("Canvas Menu Items", canvasMenuItems) + const newCanvasMenuItems = ["plugin.imgly.commandpalette", ...canvasMenuItems]; + cesdk.ui.unstable_setCanvasMenuOrder(newCanvasMenuItems) + + + // Init Scene Programatically + + await cesdk.createDesignScene(); + cesdk.engine.scene.setDesignUnit("Pixel"); // + + + // react components + + const commandItems = generateCommandItemsfromCESDK(cesdk) + const customItems = [ + { + id: "ui.theme.light", + children: "UI: Switch to Light Theme", + showType: true, + onClick: async () => { + setConfig((current: Configuration) => { + console.log(current) + return { + ...current, + theme: "light", + "ui.hide": true + } + }) + } + }, + { + id: "ui.theme.dark", + children: "UI: Switch to Dark Theme", + showType: true, + onClick: async () => { + setConfig((current) => { + return { + ...current, + theme: "dark" + } + }) + } + } + ] + const allCommands = [...commandItems, ...customItems] + setCommandItems(allCommands) + } + + + return ( + <> + + + + + ); +} + +const generateCommandItemsfromCESDK = (cesdk: WithCommands): Array => { + return cesdk + .engine + .polyfill_commands + .listCommands() + .map((cmdId: string) => { + const titel = cmdId // this comes from the metadata + return { + id: cmdId, + children: titel, + showType: true, + onClick: async () => { + await cesdk.engine.polyfill_commands.executeCommand(cmdId, {}) + } + } + }) +} + + + +export default App; diff --git a/examples/web/src/ui/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx similarity index 96% rename from examples/web/src/ui/CommandPalette.tsx rename to examples/web/src/components/CommandPalette.tsx index 747961e..d91f55e 100644 --- a/examples/web/src/ui/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -4,7 +4,7 @@ import { useState, useEffect } from "react"; // https://github.com/albingroen/react-cmdk -export const CommandPalette = (params: { items: Array }) => { +export const CommandPalette = (params: { items: Array, isOpen: boolean }) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); const [isOpen, setIsOpen] = useState(false); diff --git a/examples/web/src/ui/CreativeEditorSDK.tsx b/examples/web/src/components/CreativeEditorSDK.tsx similarity index 69% rename from examples/web/src/ui/CreativeEditorSDK.tsx rename to examples/web/src/components/CreativeEditorSDK.tsx index aab1d05..a05a62d 100644 --- a/examples/web/src/ui/CreativeEditorSDK.tsx +++ b/examples/web/src/components/CreativeEditorSDK.tsx @@ -1,29 +1,31 @@ import { useRef, useState, useEffect } from "react"; import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; - - +import { unflatten } from "../utils/flatten"; type Props = { config: Configuration, callback: (cesdk: CreativeEditorSDK) => Promise } export default function CreativeEditorSDKComponent(props: Props) { const cesdk_container = useRef(null); + // console.log("Properties", props.config) const [_, setCesdk] = useState(); useEffect(() => { + console.log("Use effect", props.config) + console.log("Container", cesdk_container.current) if (!cesdk_container.current) return; - + console.log("Creating CESDK instance") let cleanedUp = false; let instance: CreativeEditorSDK; CreativeEditorSDK - .create(cesdk_container.current, props.config) - .then( - async (instance) => { + .create(cesdk_container.current, unflatten(props.config)) + .then(async (instance) => { if (cleanedUp) { instance.dispose(); return; } + console.log("Created CESDK instance") setCesdk(instance); await props.callback(instance); } @@ -33,8 +35,8 @@ export default function CreativeEditorSDKComponent(props: Props) { cleanedUp = true; instance?.dispose(); setCesdk(undefined); - };; - }, [cesdk_container]); + }; + }, [cesdk_container, props.config]); return (
diff --git a/examples/web/src/plugins/addPlugins.ts b/examples/web/src/plugins/addPlugins.ts deleted file mode 100644 index b233095..0000000 --- a/examples/web/src/plugins/addPlugins.ts +++ /dev/null @@ -1,25 +0,0 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; -import PolyfillCommandsPlugin from "@imgly/plugin-commands-polyfill" -import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; -import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; - -const plugins = [ - PolyfillCommandsPlugin(), - VectorizerPlugin(), - BackgroundRemovalPlugin() -] - -async function addPlugins(cesdk: CreativeEditorSDK) { - try { - // @ts-ignore - plugins.map(cesdk.unstable_addPlugin.bind(cesdk)) - - - - - } catch (error) { - console.error('Could not add all plugins: ', error); - } -} - -export default addPlugins; diff --git a/examples/web/src/plugins/imgly-commands/debug.ts b/examples/web/src/plugins/imgly-commands/debug.ts new file mode 100644 index 0000000..502afb6 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/debug.ts @@ -0,0 +1,135 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; +import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import { readPropValue } from "../../utils/cesdk"; + + +export const registerDebugCommands = (cesdk: WithCommands) => { + const { asset, block, variable, editor, scene} = cesdk.engine + const commands = cesdk.engine.polyfill_commands + + commands.registerCommand("debug.console.log.metadata", async (params: { blockIds?: number[] }) => { + const blockIds = params.blockIds ?? block.findAllSelected() + + blockIds.forEach((id: number) => { + const keys = block.findAllMetadata(id) + if (keys.length === 0) { + console.debug("No metadata found for block", id) + return + } + keys.forEach((key: string) => { + const metadata = block.getMetadata(id, key) + const obj = JSON.parse(metadata) + console.debug(key, obj) + }) + }) + }) + + commands.registerCommand("debug.console.clear.metadata", async (params: { blockIds?: number[] }) => { + const blockIds = params.blockIds ?? block.findAllSelected() + blockIds.forEach((id: number) => { + block.findAllMetadata(id) + .forEach((key: string) => { + block.setMetadata(id, key, "") + }) + }) + }) + + commands.registerCommand("debug.console.print.block_properties", async (params: { blockIds?: number[] }) => { + const blockIds = params.blockIds ?? block.findAllSelected() + + blockIds.forEach((id: number) => { + const props = block.findAllProperties(id) + const propDefinition = new Map() + props.forEach((propKey: string) => { + if (!block.isPropertyReadable(propKey)) return; + const propType = block.getPropertyType(propKey) + const propValue = readPropValue(cesdk, id, propKey, propType) + propDefinition.set(propKey, { type: propType, value: propValue }) + + }) + + console.debug("Properties for block", id, propDefinition) + }) + }) + + + + commands.registerCommand("debug.console.print.fill_properties", async (params: { blockIds?: number[] }) => { + const blockIds = params.blockIds ?? block.findAllSelected() + blockIds.forEach((bId: number) => { + const fId = block.getFill(bId) + if (!block.isValid(fId)) { + console.debug("No fill found for block", bId) + return + }; + + const props = block.findAllProperties(fId) + const propDefinition = new Map() + props.forEach((propKey: string) => { + console.debug("Reading propKey", propKey) + if (!block.isPropertyReadable(propKey)) return; + + const propType = block.getPropertyType(propKey) + const propValue = readPropValue(cesdk, fId, propKey, propType) + propDefinition.set(propKey, { type: propType, value: propValue }) + + }) + + console.debug("Fill properties for block", bId, propDefinition) + }) + }) + + + + commands.registerCommand("debug.console.print.assets", async (_params: { blockIds?: number[] }) => { + // const blockIds = params.blockIds ?? block.findAllSelected() + + const entries = asset.findAllSources() + const definition = new Map() + entries.forEach((key: string) => { + const types = asset.getSupportedMimeTypes(key) + const groups = variable.getString(key) + definition.set(key, { types, groups }) + }) + console.debug("Assets", definition) + }) + + + commands.registerCommand("debug.console.print.variables", async (_params: { blockIds?: number[] }) => { + const vars = variable.findAll() + const definition = new Map() + vars.forEach((key: string) => { + const value = variable.getString(key) + + definition.set(key, { type: "String", value: value }) + }) + console.debug("Variables", definition) + + }) + + + commands.registerCommand("debug.console.print.settings", async (_params: { blockIds?: number[] }) => { + const entries = editor.findAllSettings() + const definition = new Map() + entries.forEach((key: string) => { + const type = editor.getSettingType(key) + const value = undefined; //editor.getSettingValue(key) + definition.set(key, { type, value }) + }) + console.debug("Settings", definition) + + }) + + + + commands.registerCommand("debug.console.print.scene", async (_params: { blockIds?: number[] }) => { + console.debug("Settings", { + designUnit: scene.getDesignUnit(), + mode: scene.getMode(), + }) + + }) + + + +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/export.ts b/examples/web/src/plugins/imgly-commands/export.ts new file mode 100644 index 0000000..7e5aca6 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/export.ts @@ -0,0 +1,54 @@ +import CreativeEditorSDK, { CreativeEngine, MimeType } from "@cesdk/cesdk-js"; +import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import { downloadBlob } from "../../utils/download"; + +export const registerExportCommands = (cesdk: WithCommands) => { + + const { block, scene } = cesdk.engine + const commands = cesdk.engine.polyfill_commands + + const types = ["image/png", "image/jpeg", "image/webp", "image/x-tga", "application/pdf", "application/octet-stream"] + + types.forEach((mimeType: string) => { + const [_, extension] = mimeType.split("/") + commands.registerCommand(`export.selected.as.${extension}`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + const engine = cesdk.engine + blockIds.forEach(async (bId: number) => { + const blob = await engine.block.export(bId, mimeType as MimeType) + downloadBlob(blob, `block-${bId}.${extension}`) + }) + }) + }) + + commands.registerCommand(`export.selected.as.scene`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + blockIds.forEach(async (bId: number) => { + const blob = new Blob([await block.saveToString([bId])], { type: "application/x-cesdk" }) + downloadBlob(blob, `block-${bId}.cesdk`) + }) + }) + + commands.registerCommand(`export.selected.as.json`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + + blockIds.forEach(async (bId: number) => { + const str = await block.saveToString([bId]); + const base64 = str.substring(4) + const json = atob(base64) + const blob = new Blob([json], { type: "application/json" }) + downloadBlob(blob, `block-${bId}.json`) + }) + }) + +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/lifecycle.ts b/examples/web/src/plugins/imgly-commands/lifecycle.ts new file mode 100644 index 0000000..f4566b6 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/lifecycle.ts @@ -0,0 +1,30 @@ +import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import CreativeEditorSDK from "@cesdk/cesdk-js"; + +export const registerLifecycleCommands = (cesdk: WithCommands) => { + const block = cesdk.engine.block; + const commands = cesdk.engine.polyfill_commands; + + commands.registerCommand("lifecycle.delete", async (params: { blockIds?: number[]; }) => { + const blockIds = params.blockIds ?? block.findAllSelected(); + blockIds.forEach((id: number) => { + console.log("deleting block", id) + block.isValid(id) && block.destroy(id) + }); + }); + + commands.registerCommand("lifecycle.duplicate", async (params: { blockIds?: number[]; }) => { + const blockIds = params.blockIds ?? block.findAllSelected(); + blockIds.forEach((id: number) => { + block.isValid(id); + const newBlock = block.duplicate(id); + const parent = block.getParent(id); + if (parent && block.isValid(parent)) { + block.appendChild(parent, newBlock); + } + block.setSelected(newBlock, true); + block.setSelected(id, false); + }); + }); + +}; diff --git a/examples/web/src/plugins/imgly-commands/turn_into.ts b/examples/web/src/plugins/imgly-commands/turn_into.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/web/src/ui/App.tsx b/examples/web/src/ui/App.tsx deleted file mode 100644 index 68963dd..0000000 --- a/examples/web/src/ui/App.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useRef, useState } from "react"; - -import { type WithCommands } from "@imgly/plugin-commands-polyfill"; -import { CommandPalette } from "./CommandPalette" -import { downloadBlocks } from "../utils/utils"; - -import addPlugins from "../plugins/addPlugins"; -import CreativeEditorSDKComponent from "./CreativeEditorSDK"; -import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; - -declare global { - interface Window { cesdk: WithCommands } -} - - -function App() { - const cesdkRef = useRef>(); - const [commandItems, setCommandItems] = useState>([]) - - const config: Configuration = { - license: import.meta.env.VITE_CESDK_LICENSE_KEY, - callbacks: { - onUpload: "local", - onDownload: "download", - onSave: async (str: string) => { - // improve - return downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }) - }, - - onExport: async (blobs, options) => { - return downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }) - - }, - onLoad: "upload", - }, - // devMode: true, - theme: "dark", - role: 'Creator', - - ui: { - hide: false, - elements: { - view: "advanced", - navigation: { - title: "IMG.LY Plugin Sandbox", - action: { - save: true, - load: true, - export: true, - // share: true, - } - } - } - } - } - - - - return ( - <> - - { - - cesdk = cesdk as WithCommands; - await Promise.all([ - cesdk.addDefaultAssetSources(), - cesdk.addDemoAssetSources({ sceneMode: "Design" }), - addPlugins(cesdk) - ]); - await cesdk.createDesignScene(); - - // window.cesdk = cesdk as WithCommands; - window.cesdk = cesdkRef.current = cesdk as WithCommands; - const commandItems = generateCommandItems(cesdk as WithCommands) - setCommandItems(commandItems) - - - }} /> - - ); -} - -export default App; - - - - -const generateCommandItems = (cesdk: WithCommands): Array => { - return cesdk - .engine - .polyfill_commands - .listCommands() - .map((cmdId: string) => { - - const titel = cmdId - return { - id: cmdId, - children: titel, - showType: true, - onClick: async () => { - await cesdk.engine.polyfill_commands.executeCommand(cmdId, {}) - } - } - }) -} \ No newline at end of file diff --git a/examples/web/src/ui/commandPaletteButton.ts b/examples/web/src/ui/commandPaletteButton.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/web/src/utils/cesdk.ts b/examples/web/src/utils/cesdk.ts new file mode 100644 index 0000000..44df8e1 --- /dev/null +++ b/examples/web/src/utils/cesdk.ts @@ -0,0 +1,18 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; + + +export const readPropValue = (cesdk: CreativeEditorSDK, id: number, propKey: string, propType: string) => { + try { + switch (propType.toLowerCase()) { + case "string": return cesdk.engine.block.getString(id, propKey); + case "float": return cesdk.engine.block.getFloat(id, propKey); + case "double": return cesdk.engine.block.getDouble(id, propKey); + case "color": return cesdk.engine.block.getColor(id, propKey); + case "bool": return cesdk.engine.block.getBool(id, propKey); + case "enum": return cesdk.engine.block.getEnum(id, propKey); + } + } catch(e){ + console.warn("Error reading property value: ", e); + } + return undefined; +}; diff --git a/examples/web/src/utils/utils.ts b/examples/web/src/utils/download.ts similarity index 99% rename from examples/web/src/utils/utils.ts rename to examples/web/src/utils/download.ts index bf38140..5f41fbe 100644 --- a/examples/web/src/utils/utils.ts +++ b/examples/web/src/utils/download.ts @@ -25,3 +25,5 @@ export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: }); return Promise.resolve(); }; + + diff --git a/examples/web/src/utils/flatten.ts b/examples/web/src/utils/flatten.ts new file mode 100644 index 0000000..03dfe56 --- /dev/null +++ b/examples/web/src/utils/flatten.ts @@ -0,0 +1,46 @@ +export function flatten(obj: any, prefix = ''): any { + const flattened = {}; + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const propName = prefix ? `${prefix}.${key}` : key; + + if (typeof obj[key] === 'object' && obj[key] !== null) { + Object.assign(flattened, flatten(obj[key], propName)); + } else { + // @ts-ignore + flattened[propName] = obj[key]; + } + } + } + + return flattened; +} + + +export function unflatten(obj: any): any { + const unflattened = {}; + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const value = obj[key]; + const keys = key.split('.'); + + let currentObj = unflattened; + for (let i = 0; i < keys.length - 1; i++) { + const nestedKey = keys[i]; + if (!currentObj.hasOwnProperty(nestedKey)) { + // @ts-ignore + currentObj[nestedKey] = {}; + } + // @ts-ignore + currentObj = currentObj[nestedKey]; + } + + // @ts-ignore + currentObj[keys[keys.length - 1]] = value; + } + } + + return unflattened; +} \ No newline at end of file diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index 383abac..dffd860 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -24,8 +24,7 @@ export { Manifest }; export default (pluginConfiguration: PluginConfiguration = {}) => { return { - id: PLUGIN_ID, - version: PLUGIN_VERSION, + manifest: Manifest, initialize(engine: CreativeEngine) { // it is unclear for a user which one to call and what happens and if we have to put code in both or just one // we should have a clear separation of concerns diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index 480692a..349d612 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -1,23 +1,23 @@ -export const PLUGIN_ID = '@imgly/plugin-vectorizer-web'; +export const PLUGIN_ID = 'imgly/plugin-vectorizer-web'; export const PLUGIN_COMPONENT_BUTTON_ID = `component.${PLUGIN_ID}.button`; export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` export default { id: PLUGIN_ID, - titel: "", + publisher: "IMG.LY", contributes: { - ui: [ + ui: [ { - id: PLUGIN_COMPONENT_BUTTON_ID, // not sure will + id: PLUGIN_COMPONENT_BUTTON_ID, } ], - commands: [ - { - id: PLUGIN_ACTION_VECTORIZE_LABEL, - titel: "Turn into Vectorpath", // default titel, use i18n ti + commands: { + // maybe we don't need the manifest after all? + [PLUGIN_ACTION_VECTORIZE_LABEL]: { + title: "Turn into Vectorpath", //default when no translation is given } - ], + }, i18n: { en: { [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vectorpaths' diff --git a/packages/vectorizer/types/commands.d.ts b/packages/vectorizer/types/commands.d.ts index 5075718..045fcd5 100644 --- a/packages/vectorizer/types/commands.d.ts +++ b/packages/vectorizer/types/commands.d.ts @@ -1,6 +1,6 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; declare const _default: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { + "plugin.imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { blockIds?: number[] | undefined; }) => Promise; }; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index 54d391d..38264e7 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -4,8 +4,28 @@ export interface PluginConfiguration { } export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { - id: string; - version: string; + manifest: { + id: string; + publisher: string; + contributes: { + ui: { + id: string; + }[]; + commands: { + "plugin.imgly/plugin-vectorizer-web.vectorize": { + title: string; + }; + }; + i18n: { + en: { + "plugin.imgly/plugin-vectorizer-web.vectorize": string; + }; + de: { + "plugin.imgly/plugin-vectorizer-web.vectorize": string; + }; + }; + }; + }; initialize(engine: CreativeEngine): void; initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts index 41897ca..cea58ce 100644 --- a/packages/vectorizer/types/manifest.d.ts +++ b/packages/vectorizer/types/manifest.d.ts @@ -1,23 +1,24 @@ -export declare const PLUGIN_ID = "@imgly/plugin-vectorizer-web"; -export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.@imgly/plugin-vectorizer-web.button"; -export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.@imgly/plugin-vectorizer-web.vectorize"; +export declare const PLUGIN_ID = "imgly/plugin-vectorizer-web"; +export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.imgly/plugin-vectorizer-web.button"; +export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.imgly/plugin-vectorizer-web.vectorize"; declare const _default: { id: string; - titel: string; + publisher: string; contributes: { ui: { id: string; }[]; commands: { - id: string; - titel: string; - }[]; + "plugin.imgly/plugin-vectorizer-web.vectorize": { + title: string; + }; + }; i18n: { en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + "plugin.imgly/plugin-vectorizer-web.vectorize": string; }; de: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; + "plugin.imgly/plugin-vectorizer-web.vectorize": string; }; }; }; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts index ad890fe..b24e1b2 100644 --- a/packages/vectorizer/types/ui.d.ts +++ b/packages/vectorizer/types/ui.d.ts @@ -1,5 +1,5 @@ import CreativeEditorSDK from '@cesdk/cesdk-js'; declare const _default: (cesdk: CreativeEditorSDK) => { - "component.@imgly/plugin-vectorizer-web.button": (params: any) => void; + "component.imgly/plugin-vectorizer-web.button": (params: any) => void; }; export default _default; From 52c52c57d8d5e130b5f41c2573f2a5e246ffa60a Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Tue, 13 Feb 2024 21:09:38 +0100 Subject: [PATCH 21/32] chore: Refactored into plugin --- LIST_OF_PLUGINS.md | 4 +- examples/web/src/App.tsx | 47 +++++++++------- .../web/src/components/CreativeEditorSDK.tsx | 27 +++++----- .../imgly-commands/commands/clipboard.ts | 54 +++++++++++++++++++ .../imgly-commands/{ => commands}/debug.ts | 18 +++---- .../imgly-commands/{ => commands}/export.ts | 12 ++--- .../{ => commands}/lifecycle.ts | 7 +-- .../{ => commands}/turn_into.ts | 0 .../web/src/plugins/imgly-commands/index.ts | 49 +++++++++++++++++ .../translations/translations.ts | 31 +++++++++++ examples/web/src/ui/commandPaletteButton.ts | 0 examples/web/src/utils/i18n.ts | 27 ++++++++++ packages/vectorizer/src/index.ts | 23 ++++---- packages/vectorizer/types/index.d.ts | 48 +++++++++-------- 14 files changed, 262 insertions(+), 85 deletions(-) create mode 100644 examples/web/src/plugins/imgly-commands/commands/clipboard.ts rename examples/web/src/plugins/imgly-commands/{ => commands}/debug.ts (82%) rename examples/web/src/plugins/imgly-commands/{ => commands}/export.ts (74%) rename examples/web/src/plugins/imgly-commands/{ => commands}/lifecycle.ts (79%) rename examples/web/src/plugins/imgly-commands/{ => commands}/turn_into.ts (100%) create mode 100644 examples/web/src/plugins/imgly-commands/index.ts create mode 100644 examples/web/src/plugins/imgly-commands/translations/translations.ts delete mode 100644 examples/web/src/ui/commandPaletteButton.ts create mode 100644 examples/web/src/utils/i18n.ts diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md index c38378c..8f9cd4b 100644 --- a/LIST_OF_PLUGINS.md +++ b/LIST_OF_PLUGINS.md @@ -105,8 +105,8 @@ - [ ] Add: Open the libraries and choose - [ ] Add ${List all Asset Libraries} -- [ ] Save As - - [ ] Save {Scene, Selected} As {SVG, PNG, JPEG, PDF, Component} to {Clipboard, File, Console, S3, Asset Library} +- [x] Save As + - [x] Save {Scene, Selected} As {SVG, PNG, JPEG, PDF, Component} to {Clipboard, File, Console, S3, Asset Library} - [ ] Share to diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 1c260ef..c69462e 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -11,10 +11,13 @@ import { downloadBlocks } from "./utils/download"; import PolyfillCommandsPlugin, { WithCommands } from "@imgly/plugin-commands-polyfill" import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; -// IMGLY Commands -import { registerLifecycleCommands } from "./plugins/imgly-commands/lifecycle"; -import { registerDebugCommands } from "./plugins/imgly-commands/debug"; -import { registerExportCommands } from "./plugins/imgly-commands/export"; +import ImglyCommandsPlugin from "./plugins/imgly-commands"; + + +// i18n fake +import i18n from "./utils/i18n"; +import translations from "./plugins/imgly-commands/translations/translations"; +i18n.setTranslations(translations) declare global { @@ -53,7 +56,6 @@ function App() { "callbacks.onSave": async (str: string) => downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }), "callbacks.onExport": async (blobs: Array, options: any) => downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }), "callbacks.onLoad": "upload", - // devMode: true, "theme": "dark", "role": 'Creator', @@ -68,19 +70,32 @@ function App() { const initCallback = async (_cesdk: CreativeEditorSDK) => { const cesdk = _cesdk as WithCommands; window.cesdk = cesdkRef.current = cesdk + + + // Init Scene Programatically + await cesdk.createDesignScene(); + cesdk.engine.scene.setDesignUnit("Pixel"); // + + // Plugins + + const polyfillCommandsPlugin = PolyfillCommandsPlugin() + const vectorizerPlugin = VectorizerPlugin() + const backgroundRemovalPlugin = BackgroundRemovalPlugin() + const imglyCommandsPlugin = ImglyCommandsPlugin() + // Workaround and we need to find a better way. Probably we need to have i18n be part of the sdk + i18n.setTranslations(vectorizerPlugin.contributes.i18n) + // Register Plguins await Promise.all([ cesdk.addDefaultAssetSources(), cesdk.addDemoAssetSources({ sceneMode: "Design" }), - cesdk.unstable_addPlugin(PolyfillCommandsPlugin()), - cesdk.unstable_addPlugin(VectorizerPlugin()), - cesdk.unstable_addPlugin(BackgroundRemovalPlugin()), + cesdk.unstable_addPlugin(polyfillCommandsPlugin), + cesdk.unstable_addPlugin(imglyCommandsPlugin), + cesdk.unstable_addPlugin(vectorizerPlugin), + cesdk.unstable_addPlugin(backgroundRemovalPlugin), ]); - // Commands -> Move to plugins - registerLifecycleCommands(cesdk) - registerDebugCommands(cesdk) - registerExportCommands(cesdk) + console.log("Commands", cesdk.engine.polyfill_commands.listCommands()) // Ui components cesdk.ui.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); @@ -93,11 +108,6 @@ function App() { cesdk.ui.unstable_setCanvasMenuOrder(newCanvasMenuItems) - // Init Scene Programatically - - await cesdk.createDesignScene(); - cesdk.engine.scene.setDesignUnit("Pixel"); // - // react components @@ -152,7 +162,8 @@ const generateCommandItemsfromCESDK = (cesdk: WithCommands): .polyfill_commands .listCommands() .map((cmdId: string) => { - const titel = cmdId // this comes from the metadata + const titel = i18n.t(cmdId) // this comes from the metadata + console.log(titel) return { id: cmdId, children: titel, diff --git a/examples/web/src/components/CreativeEditorSDK.tsx b/examples/web/src/components/CreativeEditorSDK.tsx index a05a62d..c07127f 100644 --- a/examples/web/src/components/CreativeEditorSDK.tsx +++ b/examples/web/src/components/CreativeEditorSDK.tsx @@ -1,5 +1,6 @@ import { useRef, useState, useEffect } from "react"; -import CreativeEditorSDK, { Configuration } from "@cesdk/cesdk-js"; +import { type Configuration } from "@cesdk/cesdk-js"; +import type CreativeEditorSDK from "@cesdk/cesdk-js"; import { unflatten } from "../utils/flatten"; type Props = { @@ -12,23 +13,21 @@ export default function CreativeEditorSDKComponent(props: Props) { const [_, setCesdk] = useState(); useEffect(() => { - console.log("Use effect", props.config) - console.log("Container", cesdk_container.current) if (!cesdk_container.current) return; - console.log("Creating CESDK instance") + let cleanedUp = false; let instance: CreativeEditorSDK; - CreativeEditorSDK - .create(cesdk_container.current, unflatten(props.config)) + import("@cesdk/cesdk-js") + .then((module) => module.default.create(cesdk_container!.current!, unflatten(props.config))) .then(async (instance) => { - if (cleanedUp) { - instance.dispose(); - return; - } - console.log("Created CESDK instance") - setCesdk(instance); - await props.callback(instance); + if (cleanedUp) { + instance.dispose(); + return; } + console.log("Created CESDK instance") + setCesdk(instance); + await props.callback(instance); + } ); return () => { @@ -44,4 +43,4 @@ export default function CreativeEditorSDKComponent(props: Props) { style={{ width: '100vw', height: '100vh' }} >
); -} \ No newline at end of file +} diff --git a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts new file mode 100644 index 0000000..6811ca7 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts @@ -0,0 +1,54 @@ +import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; +import { type WithCommands } from "@imgly/plugin-commands-polyfill"; + + + +export const registerClipboardCommands = (cesdk: WithCommands) => { + + const { block, scene } = cesdk.engine + const commands = cesdk.engine.polyfill_commands + + + commands.registerCommand(`imgly.block.clipboard.selected.as.png`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + const engine = cesdk.engine + const clipboardItems = await Promise.all(blockIds.map(async (bId: number) => { + const blob = await engine.block.export(bId, "image/png" as MimeType) + return new ClipboardItem({ + ["image/png"]: blob, + }, { presentationStyle: "attachment" }) + + })) + + await navigator.clipboard.write(clipboardItems) + }) + + commands.registerCommand(`imgly.block.clipboard.selected.as.scene`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + + const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }) + await navigator.clipboard.writeText(await blob.text()) + + }) + + commands.registerCommand(`imgly.block.clipboard.selected.as.json`, async (params: { blockIds: number[] }) => { + let blockIds = params.blockIds ?? block.findAllSelected() + if (blockIds.length === 0) { + blockIds = [scene.get()!] + } + const str = await block.saveToString(blockIds); + const base64 = str.substring(4) + const json = atob(base64) + const blob = new Blob([json], { type: "application/json" }) + await navigator.clipboard.writeText(await blob.text()) + + }) + +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/debug.ts b/examples/web/src/plugins/imgly-commands/commands/debug.ts similarity index 82% rename from examples/web/src/plugins/imgly-commands/debug.ts rename to examples/web/src/plugins/imgly-commands/commands/debug.ts index 502afb6..777e4c6 100644 --- a/examples/web/src/plugins/imgly-commands/debug.ts +++ b/examples/web/src/plugins/imgly-commands/commands/debug.ts @@ -1,13 +1,13 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; import { type WithCommands } from "@imgly/plugin-commands-polyfill"; -import { readPropValue } from "../../utils/cesdk"; +import { readPropValue } from "../../../utils/cesdk"; export const registerDebugCommands = (cesdk: WithCommands) => { const { asset, block, variable, editor, scene} = cesdk.engine const commands = cesdk.engine.polyfill_commands - commands.registerCommand("debug.console.log.metadata", async (params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.metadata", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() blockIds.forEach((id: number) => { @@ -24,7 +24,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => }) }) - commands.registerCommand("debug.console.clear.metadata", async (params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.clear.metadata", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() blockIds.forEach((id: number) => { block.findAllMetadata(id) @@ -34,7 +34,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => }) }) - commands.registerCommand("debug.console.print.block_properties", async (params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.block_properties", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() blockIds.forEach((id: number) => { @@ -54,7 +54,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => - commands.registerCommand("debug.console.print.fill_properties", async (params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.fill_properties", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() blockIds.forEach((bId: number) => { const fId = block.getFill(bId) @@ -81,7 +81,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => - commands.registerCommand("debug.console.print.assets", async (_params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.assets", async (_params: { blockIds?: number[] }) => { // const blockIds = params.blockIds ?? block.findAllSelected() const entries = asset.findAllSources() @@ -95,7 +95,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => }) - commands.registerCommand("debug.console.print.variables", async (_params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.variables", async (_params: { blockIds?: number[] }) => { const vars = variable.findAll() const definition = new Map() vars.forEach((key: string) => { @@ -108,7 +108,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => }) - commands.registerCommand("debug.console.print.settings", async (_params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.editor.settings", async (_params: { blockIds?: number[] }) => { const entries = editor.findAllSettings() const definition = new Map() entries.forEach((key: string) => { @@ -122,7 +122,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => - commands.registerCommand("debug.console.print.scene", async (_params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.scene_properties", async (_params: { blockIds?: number[] }) => { console.debug("Settings", { designUnit: scene.getDesignUnit(), mode: scene.getMode(), diff --git a/examples/web/src/plugins/imgly-commands/export.ts b/examples/web/src/plugins/imgly-commands/commands/export.ts similarity index 74% rename from examples/web/src/plugins/imgly-commands/export.ts rename to examples/web/src/plugins/imgly-commands/commands/export.ts index 7e5aca6..7f7bf5b 100644 --- a/examples/web/src/plugins/imgly-commands/export.ts +++ b/examples/web/src/plugins/imgly-commands/commands/export.ts @@ -1,8 +1,8 @@ -import CreativeEditorSDK, { CreativeEngine, MimeType } from "@cesdk/cesdk-js"; +import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; import { type WithCommands } from "@imgly/plugin-commands-polyfill"; -import { downloadBlob } from "../../utils/download"; +import { downloadBlob } from "../../../utils/download"; -export const registerExportCommands = (cesdk: WithCommands) => { +export const registerDownloadCommands = (cesdk: WithCommands) => { const { block, scene } = cesdk.engine const commands = cesdk.engine.polyfill_commands @@ -11,7 +11,7 @@ export const registerExportCommands = (cesdk: WithCommands) = types.forEach((mimeType: string) => { const [_, extension] = mimeType.split("/") - commands.registerCommand(`export.selected.as.${extension}`, async (params: { blockIds: number[] }) => { + commands.registerCommand(`imgly.block.download.selected.as.${extension}`, async (params: { blockIds: number[] }) => { let blockIds = params.blockIds ?? block.findAllSelected() if (blockIds.length === 0) { blockIds = [scene.get()!] @@ -24,7 +24,7 @@ export const registerExportCommands = (cesdk: WithCommands) = }) }) - commands.registerCommand(`export.selected.as.scene`, async (params: { blockIds: number[] }) => { + commands.registerCommand(`imgly.block.download.selected.as.scene`, async (params: { blockIds: number[] }) => { let blockIds = params.blockIds ?? block.findAllSelected() if (blockIds.length === 0) { @@ -36,7 +36,7 @@ export const registerExportCommands = (cesdk: WithCommands) = }) }) - commands.registerCommand(`export.selected.as.json`, async (params: { blockIds: number[] }) => { + commands.registerCommand(`imgly.block.download.selected.as.json`, async (params: { blockIds: number[] }) => { let blockIds = params.blockIds ?? block.findAllSelected() if (blockIds.length === 0) { blockIds = [scene.get()!] diff --git a/examples/web/src/plugins/imgly-commands/lifecycle.ts b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts similarity index 79% rename from examples/web/src/plugins/imgly-commands/lifecycle.ts rename to examples/web/src/plugins/imgly-commands/commands/lifecycle.ts index f4566b6..8b6af76 100644 --- a/examples/web/src/plugins/imgly-commands/lifecycle.ts +++ b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts @@ -1,19 +1,20 @@ import { type WithCommands } from "@imgly/plugin-commands-polyfill"; import CreativeEditorSDK from "@cesdk/cesdk-js"; + + export const registerLifecycleCommands = (cesdk: WithCommands) => { const block = cesdk.engine.block; const commands = cesdk.engine.polyfill_commands; - commands.registerCommand("lifecycle.delete", async (params: { blockIds?: number[]; }) => { + commands.registerCommand("imgly.block.lifecycle.delete", async (params: { blockIds?: number[]; }) => { const blockIds = params.blockIds ?? block.findAllSelected(); blockIds.forEach((id: number) => { - console.log("deleting block", id) block.isValid(id) && block.destroy(id) }); }); - commands.registerCommand("lifecycle.duplicate", async (params: { blockIds?: number[]; }) => { + commands.registerCommand("imgly.block.lifecycle.duplicate", async (params: { blockIds?: number[]; }) => { const blockIds = params.blockIds ?? block.findAllSelected(); blockIds.forEach((id: number) => { block.isValid(id); diff --git a/examples/web/src/plugins/imgly-commands/turn_into.ts b/examples/web/src/plugins/imgly-commands/commands/turn_into.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/turn_into.ts rename to examples/web/src/plugins/imgly-commands/commands/turn_into.ts diff --git a/examples/web/src/plugins/imgly-commands/index.ts b/examples/web/src/plugins/imgly-commands/index.ts new file mode 100644 index 0000000..3b1e492 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/index.ts @@ -0,0 +1,49 @@ +import type CreativeEditorSDK from '@cesdk/cesdk-js'; +import Translations from './translations/translations'; + +import { type WithCommands } from "@imgly/plugin-commands-polyfill" + + +// IMGLY Commands +import { registerLifecycleCommands } from "./commands/lifecycle"; +import { registerDebugCommands } from "./commands/debug"; +import { registerDownloadCommands } from "./commands/export"; +import { registerClipboardCommands } from "./commands/clipboard"; + + +const Manifest = { + id: 'plugin.imgly/plugin-commands-polyfill', + publisher: 'img.ly GmbH', + contributes: { + commands: { + "lifecycle.destroy": { + title: "Destroy" + }, + "lifecycle.duplicate": { + title: "Duplicate" + } + }, + i18n: Translations + } +}; + + +export interface PluginConfiguration { + // uploader ? +} + +export { Manifest }; + +export default () => { + return { + ...Manifest, + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + const _cesdk = cesdk as WithCommands + registerLifecycleCommands(_cesdk) + registerDebugCommands(_cesdk) + registerDownloadCommands(_cesdk) + registerClipboardCommands(_cesdk) + } + }; +}; + diff --git a/examples/web/src/plugins/imgly-commands/translations/translations.ts b/examples/web/src/plugins/imgly-commands/translations/translations.ts new file mode 100644 index 0000000..2a6216a --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/translations/translations.ts @@ -0,0 +1,31 @@ + +const en = { + "imgly.block.lifecycle.delete": "Block: Delete", + "imgly.block.lifecycle.duplicate": "Block: Duplicate", + "imgly.block.download.selected.as.png": "Block: Download selected as PNG", + "imgly.block.download.selected.as.jpeg": "Block: Download selected as JPEG", + "imgly.block.download.selected.as.webp": "Block: Download selected as WEBP", + "imgly.block.download.selected.as.x-tga": "Block: Download selected as TGA", + "imgly.block.download.selected.as.pdf": "Block: Download selected as PDF", + "imgly.block.download.selected.as.octet-stream": "Block: Download selected as RGBA8", + "imgly.block.download.selected.as.scene": "Block: Download selected as Scene", + "imgly.block.download.selected.as.json": "Block: Download selected as JSON", + "imgly.block.clipboard.selected.as.png": "Block: Copy selected as PNG to Clipboard", + "imgly.block.clipboard.selected.as.scene": "Block: Copy selected as Scene to Clipboard", + "imgly.block.clipboard.selected.as.json": "Block: Copy selected as JSON to Clipboard", + // + + "imgly.debug.clear.metadata": "Debug: Clear Metadata", + + "imgly.debug.log.metadata": "Debug: Console log Metadata", + "imgly.debug.log.block_properties": "Debug: Console log Block Properties", + "imgly.debug.log.fill_properties": "Debug: Console log Fill Properties", + "imgly.debug.log.scene_properties": "Debug: Console log Scene Properties", + "imgly.debug.log.assets": "Debug: Log Assets", + "imgly.debug.log.variables": "Debug: Log Variables", + "imgly.debug.log.editor.settings": "Debug: Log Editor Settings", +} + +export default { + en +} diff --git a/examples/web/src/ui/commandPaletteButton.ts b/examples/web/src/ui/commandPaletteButton.ts deleted file mode 100644 index e69de29..0000000 diff --git a/examples/web/src/utils/i18n.ts b/examples/web/src/utils/i18n.ts new file mode 100644 index 0000000..64f6650 --- /dev/null +++ b/examples/web/src/utils/i18n.ts @@ -0,0 +1,27 @@ +// we could polyfill them +import { merge } from 'lodash'; +import { flatten } from './flatten'; + +export class I18N { + #translations: any = {}; + #locale: string = 'en'; + + setTranslations(translations: any) { + const flattenedTranslations = flatten(translations); + this.#translations = merge(this.#translations, flattenedTranslations); + } + + translate(key: string, fallback: string | undefined = undefined) { + const lookup = this.#locale.concat('.', key); + return this.#translations[lookup] ?? fallback ?? key; + } + t = this.translate.bind(this) +} + +const i18n = new I18N(); + +export default i18n; + + + + diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index dffd860..2a1183b 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -17,14 +17,15 @@ import { export interface PluginConfiguration { - // uploader ? + logger?: { log: (message: string) => void, debug: (message: string) => void, error: (message: string) => void, trace: (message: string) => void } } export { Manifest }; export default (pluginConfiguration: PluginConfiguration = {}) => { + const logger = pluginConfiguration.logger return { - manifest: Manifest, + ...Manifest, initialize(engine: CreativeEngine) { // it is unclear for a user which one to call and what happens and if we have to put code in both or just one // we should have a clear separation of concerns @@ -38,11 +39,11 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { const engine = cesdk.engine; // @ts-ignore if (!cesdk.engine.polyfill_commands) { - console.error("Polyfill engine.engine.polyfill_commands not available!") + logger?.error("Polyfill engine.engine.polyfill_commands not available!") return; } - console.log("Subscribing to events"); + logger?.trace("Subscribing to events"); engine.event.subscribe([], async (events) => { events .filter(({ block: blockId }) => engine.block.isValid(blockId) && engine.block.hasMetadata(blockId, PLUGIN_ID)) @@ -57,7 +58,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { }); //@ts-ignore - console.log("checking if engine has polyfill_commands", cesdk.engine.polyfill_commands ? "yes" : "no") + logger?.trace("checking if engine has polyfill_commands", cesdk.engine.polyfill_commands ? "yes" : "no") engine.event.subscribe([], async (events) => { events @@ -66,9 +67,9 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { .forEach(e => handleUpdateEvent(engine, e.block)) }); - console.info("Registering plugin command") + logger?.trace("Registering plugin command") Object.keys(commands).forEach((command) => { - console.info(`Registering action: ${command}`) + logger?.trace(`Registering action: ${command}`) // @ts-ignore const func = commands[command]; // @ts-ignore @@ -78,11 +79,11 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { ); }) - console.info("Registering plugin I18N translations") + logger?.trace("Registering plugin I18N translations") cesdk.setTranslations(Manifest.contributes.i18n); - console.info("Registering plugin UI components") + logger?.trace("Registering plugin UI components") const components = ui(cesdk) Object.keys(components).forEach((componentId) => { @@ -94,7 +95,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { // DEFAULTS // define what blocks the component button is enabled for // WHERE IS THIS USED? AND HOW DOES IT WORK? It seems the button is shown no matter what. - console.info("Enabling plugin component button for supported blocks") + logger?.trace("Enabling plugin component button for supported blocks") cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, (context: any) => { return areBlocksSupported(engine, engine.block.findAllSelected()) }) @@ -104,7 +105,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { cesdk.feature.unstable_enable(PLUGIN_ACTION_VECTORIZE_LABEL, false); - console.info("Changing canvas menu order") + logger?.trace("Changing canvas menu order") const canvasMenuEntries = [ PLUGIN_COMPONENT_BUTTON_ID, ...cesdk.ui.unstable_getCanvasMenuOrder() diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index 38264e7..dc3afc1 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -1,35 +1,39 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import Manifest from './manifest'; export interface PluginConfiguration { + logger?: { + log: (message: string) => void; + debug: (message: string) => void; + error: (message: string) => void; + trace: (message: string) => void; + }; } export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { - manifest: { - id: string; - publisher: string; - contributes: { - ui: { - id: string; - }[]; - commands: { - "plugin.imgly/plugin-vectorizer-web.vectorize": { - title: string; - }; - }; - i18n: { - en: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; - }; - de: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; - }; - }; - }; - }; initialize(engine: CreativeEngine): void; initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; update(): void; + id: string; + publisher: string; + contributes: { + ui: { + id: string; + }[]; + commands: { + "plugin.imgly/plugin-vectorizer-web.vectorize": { + title: string; + }; + }; + i18n: { + en: { + "plugin.imgly/plugin-vectorizer-web.vectorize": string; + }; + de: { + "plugin.imgly/plugin-vectorizer-web.vectorize": string; + }; + }; + }; }; export default _default; From 67972505cf9bfa2b99091ad1a9fd6e7e887cc0be Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Wed, 14 Feb 2024 18:51:01 +0100 Subject: [PATCH 22/32] feat: Polyfill I18N and more commands --- LIST_OF_PLUGINS.md | 3 +- TODO.md | 18 ++++- examples/web/package.json | 3 +- examples/web/src/App.tsx | 50 ++++++------ .../web/src/components/CommandPalette.tsx | 11 +-- .../web/src/components/CreativeEditorSDK.tsx | 2 - examples/web/src/externals.ts | 0 examples/web/src/imgly.ts | 0 .../imgly-commands/commands/clipboard.ts | 6 +- .../plugins/imgly-commands/commands/debug.ts | 79 ++++++++++++++++-- .../plugins/imgly-commands/commands/export.ts | 7 +- .../imgly-commands/commands/lifecycle.ts | 39 ++++++++- .../web/src/plugins/imgly-commands/index.ts | 5 +- .../translations/translations.ts | 18 ++++- examples/web/src/utils/i18n.ts | 36 ++++----- package.json | 1 + packages/commands-polyfill/src/index.ts | 9 +-- packages/commands-polyfill/types/index.d.ts | 5 +- .../types/utils/polyfills.d.ts | 12 --- packages/i18n-polyfill/LICENSE.md | 1 + packages/i18n-polyfill/README.md | 40 ++++++++++ packages/i18n-polyfill/STRUCTURE.md | 1 + packages/i18n-polyfill/TODO.md | 0 packages/i18n-polyfill/esbuild/config.mjs | 58 ++++++++++++++ packages/i18n-polyfill/esbuild/global.d.ts | 3 + packages/i18n-polyfill/package.json | 66 +++++++++++++++ packages/i18n-polyfill/scripts/build.mjs | 5 ++ packages/i18n-polyfill/scripts/watch.mjs | 19 +++++ packages/i18n-polyfill/src/index.ts | 80 +++++++++++++++++++ packages/i18n-polyfill/src/manifest.ts | 4 + packages/i18n-polyfill/src/utils/flatten.ts | 46 +++++++++++ packages/i18n-polyfill/src/worker.ts | 0 packages/i18n-polyfill/tsconfig.json | 16 ++++ packages/i18n-polyfill/types/index.d.ts | 30 +++++++ packages/i18n-polyfill/types/manifest.d.ts | 4 + .../i18n-polyfill/types/utils/flatten.d.ts | 2 + packages/i18n-polyfill/types/worker.d.ts | 0 packages/vectorizer/src/index.ts | 11 +-- packages/vectorizer/src/manifest.ts | 7 +- packages/vectorizer/src/ui.ts | 2 +- packages/vectorizer/types/i18n.d.ts | 15 ---- packages/vectorizer/types/index.d.ts | 13 +-- packages/vectorizer/types/utils/commands.d.ts | 7 -- .../vectorizer/types/utils/polyfills.d.ts | 12 --- 44 files changed, 600 insertions(+), 146 deletions(-) create mode 100644 examples/web/src/externals.ts create mode 100644 examples/web/src/imgly.ts delete mode 100644 packages/commands-polyfill/types/utils/polyfills.d.ts create mode 100644 packages/i18n-polyfill/LICENSE.md create mode 100644 packages/i18n-polyfill/README.md create mode 100644 packages/i18n-polyfill/STRUCTURE.md create mode 100644 packages/i18n-polyfill/TODO.md create mode 100644 packages/i18n-polyfill/esbuild/config.mjs create mode 100644 packages/i18n-polyfill/esbuild/global.d.ts create mode 100644 packages/i18n-polyfill/package.json create mode 100644 packages/i18n-polyfill/scripts/build.mjs create mode 100644 packages/i18n-polyfill/scripts/watch.mjs create mode 100644 packages/i18n-polyfill/src/index.ts create mode 100644 packages/i18n-polyfill/src/manifest.ts create mode 100644 packages/i18n-polyfill/src/utils/flatten.ts create mode 100644 packages/i18n-polyfill/src/worker.ts create mode 100644 packages/i18n-polyfill/tsconfig.json create mode 100644 packages/i18n-polyfill/types/index.d.ts create mode 100644 packages/i18n-polyfill/types/manifest.d.ts create mode 100644 packages/i18n-polyfill/types/utils/flatten.d.ts create mode 100644 packages/i18n-polyfill/types/worker.d.ts delete mode 100644 packages/vectorizer/types/i18n.d.ts delete mode 100644 packages/vectorizer/types/utils/commands.d.ts delete mode 100644 packages/vectorizer/types/utils/polyfills.d.ts diff --git a/LIST_OF_PLUGINS.md b/LIST_OF_PLUGINS.md index 8f9cd4b..bcda3f4 100644 --- a/LIST_OF_PLUGINS.md +++ b/LIST_OF_PLUGINS.md @@ -189,4 +189,5 @@ ## Other - [ ] Reduce colors to 1...n -- [ ] Subtitel STR colors \ No newline at end of file +- [ ] Subtitle STR colors +- [ ] Upload scenes, Upload components \ No newline at end of file diff --git a/TODO.md b/TODO.md index b1d9ab2..77c8209 100644 --- a/TODO.md +++ b/TODO.md @@ -29,4 +29,20 @@ - it's `block.export` but not `scene.export` as I would expect - `pages` should have design units - `pages` should have their type e.g. video vs static -- `docuements` are just groups and as such leverage multi-editing \ No newline at end of file +- `docuements` are just groups and as such leverage multi-editing + + +- How to work with `scopes` and `features`. Can I define custom scopes? Do we handle scopes in `enabledFeature +- There seems to be no API like `findAllScopes()` to enumerate scopes +- Is there an option to add customs scopes. +- `isEnableFeature` should be evaluated by the UI and the commands already? +- I think scopes +- `block.ungroup(bId)` should return the Ids of the items in the group +- block has no `getScope` and `setScope` to define the hierarchies. Here is an issue when dealing with hiearchies. We need to have the same thing available as with global scopes + - Editor : Allow, Defer, Deny + - Scene: Allow, Defer, Deny + - Collection: Allow, Defer, Deny + - Element: Allow, (Defer,) Deny + + +- `getEffects` api seems unsimilar to all `findAllScopes` etc. Maybe \ No newline at end of file diff --git a/examples/web/package.json b/examples/web/package.json index d43726c..64cfeb0 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -10,8 +10,9 @@ }, "dependencies": { "@cesdk/cesdk-js": "^1.20.0", - "@imgly/plugin-background-removal-web": "*", + "@imgly/plugin-i18n-polyfill": "*", "@imgly/plugin-commands-polyfill": "*", + "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer-web": "*", "lodash": "^4.17.21", "react": "^18.2.0", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index c69462e..02a89b6 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -1,6 +1,8 @@ +// use DENO best practice and move all externals into externals.ts + import { useRef, useState } from "react"; import CreativeEditorSDKComponent from "./components/CreativeEditorSDK"; -import CreativeEditorSDK, { Configuration} from "@cesdk/cesdk-js"; +import CreativeEditorSDK_UNMODIFIED, { Configuration } from "@cesdk/cesdk-js"; // React UI Components import { CommandPalette } from "./components/CommandPalette" @@ -8,25 +10,25 @@ import { CommandPalette } from "./components/CommandPalette" import { downloadBlocks } from "./utils/download"; // IMGLY Plugins -import PolyfillCommandsPlugin, { WithCommands } from "@imgly/plugin-commands-polyfill" +import PolyFillI18NPlugin, { type I18NType } from "@imgly/plugin-i18n-polyfill" +import PolyfillCommandsPlugin, { type CommandsType } from "@imgly/plugin-commands-polyfill" +type CreativeEditorSDK = CreativeEditorSDK_UNMODIFIED & I18NType & CommandsType + +// Plugins import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; import ImglyCommandsPlugin from "./plugins/imgly-commands"; -// i18n fake -import i18n from "./utils/i18n"; -import translations from "./plugins/imgly-commands/translations/translations"; -i18n.setTranslations(translations) declare global { - interface Window { cesdk: WithCommands } + interface Window { cesdk: CreativeEditorSDK } } function App() { - const cesdkRef = useRef>(); + const cesdkRef = useRef(); const [commandItems, setCommandItems] = useState>([]) const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false) @@ -42,7 +44,6 @@ function App() { isDisabled: isCommandPaletteOpen, loadingProgress: undefined, // creates infinite spinner onClick: () => { - debugger setIsCommandPaletteOpen(true) } }); @@ -68,42 +69,42 @@ function App() { const initCallback = async (_cesdk: CreativeEditorSDK) => { - const cesdk = _cesdk as WithCommands; + const cesdk = _cesdk as CreativeEditorSDK; window.cesdk = cesdkRef.current = cesdk - + // Init Scene Programatically await cesdk.createDesignScene(); cesdk.engine.scene.setDesignUnit("Pixel"); // - + // Plugins - const polyfillCommandsPlugin = PolyfillCommandsPlugin() + const polyfillI18NPlugin = PolyFillI18NPlugin() + const polyfillCommandsPlugin = PolyfillCommandsPlugin() const vectorizerPlugin = VectorizerPlugin() const backgroundRemovalPlugin = BackgroundRemovalPlugin() const imglyCommandsPlugin = ImglyCommandsPlugin() - // Workaround and we need to find a better way. Probably we need to have i18n be part of the sdk - i18n.setTranslations(vectorizerPlugin.contributes.i18n) + // Register Plguins await Promise.all([ cesdk.addDefaultAssetSources(), cesdk.addDemoAssetSources({ sceneMode: "Design" }), + cesdk.unstable_addPlugin(polyfillI18NPlugin), cesdk.unstable_addPlugin(polyfillCommandsPlugin), cesdk.unstable_addPlugin(imglyCommandsPlugin), cesdk.unstable_addPlugin(vectorizerPlugin), cesdk.unstable_addPlugin(backgroundRemovalPlugin), ]); - console.log("Commands", cesdk.engine.polyfill_commands.listCommands()) + // Ui components cesdk.ui.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); "plugin.imgly.commandpalette2" - cesdk.setTranslations({ en: { "plugin.imgly.commandpalette.label": ">" } }) + cesdk.setTranslations({ en: { "plugin.imgly.commandpalette.label": "✨ Run .." } }) // Canvas Menu const canvasMenuItems = cesdk.ui.unstable_getCanvasMenuOrder() - console.log("Canvas Menu Items", canvasMenuItems) const newCanvasMenuItems = ["plugin.imgly.commandpalette", ...canvasMenuItems]; cesdk.ui.unstable_setCanvasMenuOrder(newCanvasMenuItems) @@ -119,7 +120,6 @@ function App() { showType: true, onClick: async () => { setConfig((current: Configuration) => { - console.log(current) return { ...current, theme: "light", @@ -149,27 +149,27 @@ function App() { return ( <> - + setIsCommandPaletteOpen(val)} /> ); } -const generateCommandItemsfromCESDK = (cesdk: WithCommands): Array => { +const generateCommandItemsfromCESDK = (cesdk: CreativeEditorSDK): Array => { return cesdk .engine - .polyfill_commands + .commands! .listCommands() .map((cmdId: string) => { - const titel = i18n.t(cmdId) // this comes from the metadata - console.log(titel) + const titel = cesdk.i18n!.t(cmdId) // this comes from the metadata + if (titel === undefined) throw new Error(`No translation found for command ${cmdId}`) return { id: cmdId, children: titel, showType: true, onClick: async () => { - await cesdk.engine.polyfill_commands.executeCommand(cmdId, {}) + await cesdk.engine.commands!.executeCommand(cmdId, {}) } } }) diff --git a/examples/web/src/components/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx index d91f55e..f62bfc8 100644 --- a/examples/web/src/components/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -2,12 +2,11 @@ import "react-cmdk/dist/cmdk.css"; import CMDK, { filterItems, getItemIndex } from "react-cmdk"; import { useState, useEffect } from "react"; - // https://github.com/albingroen/react-cmdk -export const CommandPalette = (params: { items: Array, isOpen: boolean }) => { +export const CommandPalette = (params: { items: Array, isOpen: boolean, setIsOpen: (val: boolean) => void }) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); - const [isOpen, setIsOpen] = useState(false); + const { isOpen, setIsOpen } = params const { items } = params // debugger @@ -22,9 +21,7 @@ export const CommandPalette = (params: { items: Array, isOpen: boolean }) = e.preventDefault(); e.stopPropagation(); - setIsOpen((currentValue) => { - return !currentValue; - }); + setIsOpen(!isOpen); } } @@ -41,7 +38,7 @@ export const CommandPalette = (params: { items: Array, isOpen: boolean }) = { heading: undefined, id: "turnInto", - items: items?? [] + items: items ?? [] } ], search diff --git a/examples/web/src/components/CreativeEditorSDK.tsx b/examples/web/src/components/CreativeEditorSDK.tsx index c07127f..7ee1c2c 100644 --- a/examples/web/src/components/CreativeEditorSDK.tsx +++ b/examples/web/src/components/CreativeEditorSDK.tsx @@ -8,7 +8,6 @@ type Props = { } export default function CreativeEditorSDKComponent(props: Props) { const cesdk_container = useRef(null); - // console.log("Properties", props.config) const [_, setCesdk] = useState(); @@ -24,7 +23,6 @@ export default function CreativeEditorSDKComponent(props: Props) { instance.dispose(); return; } - console.log("Created CESDK instance") setCesdk(instance); await props.callback(instance); } diff --git a/examples/web/src/externals.ts b/examples/web/src/externals.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/web/src/imgly.ts b/examples/web/src/imgly.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts index 6811ca7..e5a64a0 100644 --- a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts +++ b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts @@ -1,12 +1,12 @@ import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; -import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import { type CommandsType } from "@imgly/plugin-commands-polyfill"; -export const registerClipboardCommands = (cesdk: WithCommands) => { +export const registerClipboardCommands = (cesdk: CreativeEditorSDK & CommandsType) => { const { block, scene } = cesdk.engine - const commands = cesdk.engine.polyfill_commands + const commands = cesdk.engine.commands! commands.registerCommand(`imgly.block.clipboard.selected.as.png`, async (params: { blockIds: number[] }) => { diff --git a/examples/web/src/plugins/imgly-commands/commands/debug.ts b/examples/web/src/plugins/imgly-commands/commands/debug.ts index 777e4c6..eba986f 100644 --- a/examples/web/src/plugins/imgly-commands/commands/debug.ts +++ b/examples/web/src/plugins/imgly-commands/commands/debug.ts @@ -1,11 +1,11 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; -import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import { type CommandsType } from "@imgly/plugin-commands-polyfill"; import { readPropValue } from "../../../utils/cesdk"; -export const registerDebugCommands = (cesdk: WithCommands) => { - const { asset, block, variable, editor, scene} = cesdk.engine - const commands = cesdk.engine.polyfill_commands +export const registerDebugCommands = (cesdk: CreativeEditorSDK & CommandsType) => { + const { asset, block, variable, editor, scene } = cesdk.engine + const commands = cesdk.engine.commands!; commands.registerCommand("imgly.debug.log.metadata", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() @@ -54,7 +54,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => - commands.registerCommand("imgly.debug.log.fill_properties", async (params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.fill", async (params: { blockIds?: number[] }) => { const blockIds = params.blockIds ?? block.findAllSelected() blockIds.forEach((bId: number) => { const fId = block.getFill(bId) @@ -122,7 +122,7 @@ export const registerDebugCommands = (cesdk: WithCommands) => - commands.registerCommand("imgly.debug.log.scene_properties", async (_params: { blockIds?: number[] }) => { + commands.registerCommand("imgly.debug.log.scene", async (_params: { blockIds?: number[] }) => { console.debug("Settings", { designUnit: scene.getDesignUnit(), mode: scene.getMode(), @@ -130,6 +130,73 @@ export const registerDebugCommands = (cesdk: WithCommands) => }) + commands.registerCommand("imgly.debug.log.scopes", async (params: { blockIds?: number[] }) => { + // https://img.ly/docs/cesdk/engine/guides/scopes/ + const scopeNames = [ + "layer/move", + "layer/resize", + "layer/rotate", + "layer/crop", + "layer/clipping", + "layer/opacity", + "layer/blendMode", + "layer/visibility", + "appearance/adjustments", + "appearance/filter", + "appearance/effect", + "appearance/blur", + "appearance/shadow", + "lifecycle/destroy", // delete + "lifecycle/duplicate", + "editor/add", + "editor/select", + "fill/change", + "stroke/change", + "shape/change", + "text/edit", + // "text/change", // would be replace from library + "text/character" + ] + const definition = new Map() + scopeNames.forEach((scope: string) => { + const value = editor.getGlobalScope(scope) + definition.set(scope,{value}) + }) + console.debug("GlobalScopes", definition) + + const blockIds = params.blockIds ?? block.findAllSelected() + blockIds.forEach((id: number) => { + const definition = new Map() + scopeNames.forEach((scope: string) => { + const value = block.isAllowedByScope(id, scope) + definition.set(scope,{value}) + }) + console.debug("Scopes for block", id, definition) + }) + }) + + + commands.registerCommand("imgly.debug.log.effects", async (params: { blockIds?: number[] }) => { + const blockIds = params.blockIds ?? block.findAllSelected() + blockIds.forEach((id: number) => { + block.getEffects(id).forEach((eId: number) => { + const props = block.findAllProperties(eId); + let propDefinition = new Map() + props.forEach((propKey: string) => { + if (!block.isPropertyReadable(propKey)) return; + const propType = block.getPropertyType(propKey) + const propValue = readPropValue(cesdk, eId, propKey, propType) + propDefinition.set(propKey, { type: propType, value: propValue }) + + }) + + console.debug("Effect for block", id, propDefinition) + }) + + }) + + }) + } \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/export.ts b/examples/web/src/plugins/imgly-commands/commands/export.ts index 7f7bf5b..2884498 100644 --- a/examples/web/src/plugins/imgly-commands/commands/export.ts +++ b/examples/web/src/plugins/imgly-commands/commands/export.ts @@ -1,12 +1,11 @@ import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; -import { type WithCommands } from "@imgly/plugin-commands-polyfill"; +import { type CommandsType } from "@imgly/plugin-commands-polyfill"; import { downloadBlob } from "../../../utils/download"; -export const registerDownloadCommands = (cesdk: WithCommands) => { +export const registerDownloadCommands = (cesdk: CreativeEditorSDK & CommandsType) => { const { block, scene } = cesdk.engine - const commands = cesdk.engine.polyfill_commands - + const commands = cesdk.engine.commands!; const types = ["image/png", "image/jpeg", "image/webp", "image/x-tga", "application/pdf", "application/octet-stream"] types.forEach((mimeType: string) => { diff --git a/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts index 8b6af76..8559417 100644 --- a/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts +++ b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts @@ -1,11 +1,11 @@ -import { type WithCommands } from "@imgly/plugin-commands-polyfill"; -import CreativeEditorSDK from "@cesdk/cesdk-js"; +import { type CommandsType } from "@imgly/plugin-commands-polyfill"; +import CreativeEditorSDK, { BooleanOperation } from "@cesdk/cesdk-js"; -export const registerLifecycleCommands = (cesdk: WithCommands) => { +export const registerLifecycleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { const block = cesdk.engine.block; - const commands = cesdk.engine.polyfill_commands; + const commands = cesdk.engine.commands!; commands.registerCommand("imgly.block.lifecycle.delete", async (params: { blockIds?: number[]; }) => { const blockIds = params.blockIds ?? block.findAllSelected(); @@ -28,4 +28,35 @@ export const registerLifecycleCommands = (cesdk: WithCommands }); }); + commands.registerCommand("imgly.block.container.group", async (params: { blockIds?: number[]; }) => { + const blockIds = params.blockIds ?? block.findAllSelected(); + const group = block.group(blockIds); + block.setSelected(group, true); + }) + + + commands.registerCommand("imgly.block.container.ungroup", async (params: { blockIds?: number[]; }) => { + const blockIds = params.blockIds ?? block.findAllSelected(); + blockIds + .filter((id: number) => block.isValid(id) && block.getType(id) === "//ly.img.ubq/group") + .forEach((bId: number) => { + const groupChildIds = block.getChildren(bId); + block.ungroup(bId); // ungroup should return groupChildIds + groupChildIds.forEach((id: number) => block.setSelected(id, true)); + }) + + }) + + { + const combineOperations = ["Union", "Difference", "Intersection", "XOR"] + combineOperations.forEach((operation: string) => { + + commands.registerCommand(`imgly.block.combine.${operation.toLowerCase()}`, async (params: { blockIds?: number[]; }) => { + const blockIds = params.blockIds ?? block.findAllSelected(); + const newBlockId = block.combine(blockIds, operation as BooleanOperation); + block.setSelected(newBlockId, true); + }); + }) + } + }; diff --git a/examples/web/src/plugins/imgly-commands/index.ts b/examples/web/src/plugins/imgly-commands/index.ts index 3b1e492..7f06879 100644 --- a/examples/web/src/plugins/imgly-commands/index.ts +++ b/examples/web/src/plugins/imgly-commands/index.ts @@ -1,7 +1,7 @@ import type CreativeEditorSDK from '@cesdk/cesdk-js'; import Translations from './translations/translations'; -import { type WithCommands } from "@imgly/plugin-commands-polyfill" +import { type CommandsType } from "@imgly/plugin-commands-polyfill" // IMGLY Commands @@ -38,7 +38,8 @@ export default () => { return { ...Manifest, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - const _cesdk = cesdk as WithCommands + const _cesdk = cesdk as CreativeEditorSDK & CommandsType + cesdk.setTranslations(Translations); registerLifecycleCommands(_cesdk) registerDebugCommands(_cesdk) registerDownloadCommands(_cesdk) diff --git a/examples/web/src/plugins/imgly-commands/translations/translations.ts b/examples/web/src/plugins/imgly-commands/translations/translations.ts index 2a6216a..b180d11 100644 --- a/examples/web/src/plugins/imgly-commands/translations/translations.ts +++ b/examples/web/src/plugins/imgly-commands/translations/translations.ts @@ -17,13 +17,23 @@ const en = { "imgly.debug.clear.metadata": "Debug: Clear Metadata", - "imgly.debug.log.metadata": "Debug: Console log Metadata", - "imgly.debug.log.block_properties": "Debug: Console log Block Properties", - "imgly.debug.log.fill_properties": "Debug: Console log Fill Properties", - "imgly.debug.log.scene_properties": "Debug: Console log Scene Properties", + "imgly.debug.log.metadata": "Debug: Log Metadata", + "imgly.debug.log.block": "Debug: Log Block", + "imgly.debug.log.fill": "Debug: Log Fill", + "imgly.debug.log.scene": "Debug: Log Scene", + "imgly.debug.log.scopes": "Debug: Log Scopes", "imgly.debug.log.assets": "Debug: Log Assets", "imgly.debug.log.variables": "Debug: Log Variables", "imgly.debug.log.editor.settings": "Debug: Log Editor Settings", + + "imgly.block.container.group": "Container: Group", + "imgly.block.container.ungroup": "Container: Ungroup", + "imgly.block.combine.union": "Combine: Union", + "imgly.block.combine.difference": "Combine: Subtract", + "imgly.block.combine.intersection": "Combine: Intersect", + "imgly.block.combine.xor": "Combine: Exclude", + + } export default { diff --git a/examples/web/src/utils/i18n.ts b/examples/web/src/utils/i18n.ts index 64f6650..1b2e9e0 100644 --- a/examples/web/src/utils/i18n.ts +++ b/examples/web/src/utils/i18n.ts @@ -1,26 +1,26 @@ -// we could polyfill them -import { merge } from 'lodash'; -import { flatten } from './flatten'; +// // we could polyfill them +// import { merge } from 'lodash'; +// import { flatten } from './flatten'; -export class I18N { - #translations: any = {}; - #locale: string = 'en'; +// export class I18N { +// #translations: any = {}; +// #locale: string = 'en'; - setTranslations(translations: any) { - const flattenedTranslations = flatten(translations); - this.#translations = merge(this.#translations, flattenedTranslations); - } +// setTranslations(translations: any) { +// const flattenedTranslations = flatten(translations); +// this.#translations = merge(this.#translations, flattenedTranslations); +// } - translate(key: string, fallback: string | undefined = undefined) { - const lookup = this.#locale.concat('.', key); - return this.#translations[lookup] ?? fallback ?? key; - } - t = this.translate.bind(this) -} +// translate(key: string, fallback: string | undefined = undefined) { +// const lookup = this.#locale.concat('.', key); +// return this.#translations[lookup] ?? fallback ?? key; +// } +// t = this.translate.bind(this) +// } -const i18n = new I18N(); +// const i18n = new I18N(); -export default i18n; +// export default i18n; diff --git a/package.json b/package.json index cb2e16b..4d99540 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "version": "0.0.0", "workspaces": [ "examples/web", + "packages/i18n-polyfill", "packages/commands-polyfill", "packages/background-removal", "packages/vectorizer" diff --git a/packages/commands-polyfill/src/index.ts b/packages/commands-polyfill/src/index.ts index c425153..dddbe7e 100644 --- a/packages/commands-polyfill/src/index.ts +++ b/packages/commands-polyfill/src/index.ts @@ -11,14 +11,13 @@ export { Manifest }; export default () => { return { + ...Manifest, initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { polyfillWithCommands(cesdk); } }; }; - - -export type WithCommands = T & { engine: CreativeEngine & { polyfill_commands: Commands } }; +export type CommandsType = { engine: CreativeEngine & { commands?: Commands } } export type CommandType = (params: any) => Promise; @@ -44,8 +43,8 @@ export class Commands { } export function polyfillWithCommands(sdk: CreativeEditorSDK) { // @ts-ignore - if (!sdk.engine.polyfill_commands) { + if (!sdk.engine.commands) { // @ts-ignore - sdk.engine.polyfill_commands = new Commands(); + sdk.engine.commands = new Commands(); } } \ No newline at end of file diff --git a/packages/commands-polyfill/types/index.d.ts b/packages/commands-polyfill/types/index.d.ts index 9aee2a0..f0f714a 100644 --- a/packages/commands-polyfill/types/index.d.ts +++ b/packages/commands-polyfill/types/index.d.ts @@ -7,11 +7,12 @@ declare const _default: () => { initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK; }): void; + id: string; }; export default _default; -export type WithCommands = T & { +export type CommandsType = { engine: CreativeEngine & { - polyfill_commands: Commands; + commands?: Commands; }; }; export type CommandType = (params: any) => Promise; diff --git a/packages/commands-polyfill/types/utils/polyfills.d.ts b/packages/commands-polyfill/types/utils/polyfills.d.ts deleted file mode 100644 index af78ae7..0000000 --- a/packages/commands-polyfill/types/utils/polyfills.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -export type CreativeEngineWithPolyfills = CreativeEngine & { - polyfill_commands?: Commands; -}; -export type CommandType = (params: any) => Promise; -export declare class Commands { - #private; - constructor(sdk: CreativeEditorSDK); - registerCommand(label: string, callback: (params: any) => Promise): void; - executeCommand(label: string, params: any): Promise; -} -export declare function polyfillWithCommands(sdk: CreativeEditorSDK): void; diff --git a/packages/i18n-polyfill/LICENSE.md b/packages/i18n-polyfill/LICENSE.md new file mode 100644 index 0000000..a099036 --- /dev/null +++ b/packages/i18n-polyfill/LICENSE.md @@ -0,0 +1 @@ +TBD diff --git a/packages/i18n-polyfill/README.md b/packages/i18n-polyfill/README.md new file mode 100644 index 0000000..e4197b5 --- /dev/null +++ b/packages/i18n-polyfill/README.md @@ -0,0 +1,40 @@ +# IMG.LY CE.SDK Plugin Vectorizer + +This plugin introduces a vectorizer for the CE.SDK editor. + +## Installation + +You can install the plugin via npm or yarn. Use the following commands to install the package: + +``` +yarn add @imgly/plugin-vectorizer-web +npm install @imgly/plugin-vectorizer-web +``` + +## Usage + +Adding the plugin to CE.SDK will automatically add a vectorizer +canvas menu entry for every block with an image fill. + +```typescript +import CreativeEditorSDK from '@cesdk/cesdk-js'; +import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; + +const config = { + license: '', + callbacks: { + // Please note that the vectorizer plugin depends on an correctly + // configured upload. 'local' will work for local testing, but in + // production you will need something stable. Please take a look at: + // https://img.ly/docs/cesdk/ui/guides/upload-images/ + onUpload: 'local' + } +}; + +const cesdk = await CreativeEditorSDK.create(container, config); +await cesdk.addDefaultAssetSources(), + await cesdk.addDemoAssetSources({ sceneMode: 'Design' }), + await cesdk.unstable_addPlugin(VectorizerPlugin()); + +await cesdk.createDesignScene(); +``` diff --git a/packages/i18n-polyfill/STRUCTURE.md b/packages/i18n-polyfill/STRUCTURE.md new file mode 100644 index 0000000..13b1472 --- /dev/null +++ b/packages/i18n-polyfill/STRUCTURE.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/i18n-polyfill/TODO.md b/packages/i18n-polyfill/TODO.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/i18n-polyfill/esbuild/config.mjs b/packages/i18n-polyfill/esbuild/config.mjs new file mode 100644 index 0000000..37b437c --- /dev/null +++ b/packages/i18n-polyfill/esbuild/config.mjs @@ -0,0 +1,58 @@ +import chalk from 'chalk'; +import { readFile } from 'fs/promises'; + +// import packageJson from '../package.json' assert { type: 'json' }; +// Avoid the Experimental Feature warning when using the above. +const packageJson = JSON.parse( + await readFile(new URL('../package.json', import.meta.url)) +); + + +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) +const externals = [...dependencies, ...peerDependencies] + +console.log( + chalk.yellow('Building version: '), + chalk.green(packageJson.version) +); + +const configs = [ + { + entryPoints: ['src/index.ts', "src/worker.ts"], + define: { + PLUGIN_VERSION: `"${packageJson.version}"` + }, + minify: true, + bundle: true, + sourcemap: true, + external: externals, + platform: 'node', + format: 'esm', + outdir: 'dist', + outExtension: { '.js': '.mjs' }, + plugins: [ + { + name: 'reporter', + setup(build) { + build.onEnd((result) => { + console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] Build ${ + result.errors.length + ? chalk.red('failed') + : chalk.green('succeeded') + }` + ); + }); + } + } + ] + } +]; + +export default configs; diff --git a/packages/i18n-polyfill/esbuild/global.d.ts b/packages/i18n-polyfill/esbuild/global.d.ts new file mode 100644 index 0000000..de80fd8 --- /dev/null +++ b/packages/i18n-polyfill/esbuild/global.d.ts @@ -0,0 +1,3 @@ +// These constants here are added by the base esbuild config + +declare const PLUGIN_VERSION: string; diff --git a/packages/i18n-polyfill/package.json b/packages/i18n-polyfill/package.json new file mode 100644 index 0000000..c1e2a6d --- /dev/null +++ b/packages/i18n-polyfill/package.json @@ -0,0 +1,66 @@ +{ + "name": "@imgly/plugin-i18n-polyfill", + "version": "0.1.0", + "description": "Polyfill for I18N plugin for the CE.SDK editor", + "keywords": [ + "CE.SDK", + "plugin", + "polyfill" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/imgly/plugins.git" + }, + "license": "SEE LICENSE IN LICENSE.md", + "author": { + "name": "IMG.LY GmbH", + "email": "support@img.ly", + "url": "https://img.ly" + }, + "bugs": { + "email": "support@img.ly" + }, + "source": "./src/index.ts", + "module": "./dist/index.mjs", + "types": "./types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./types/index.d.ts" + } + }, + "homepage": "https://img.ly", + "files": [ + "LICENSE.md", + "README.md", + "CHANGELOG.md", + "dist/", + "types/", + "bin/" + ], + "scripts": { + "start": "npm run watch", + "clean": "npx rimraf dist && npx rimraf types", + "build": "yarn run types:create && node scripts/build.mjs", + "dev": "yarn run types:create && node scripts/watch.mjs", + "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", + "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", + "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", + "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", + "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", + "check:type": "tsc --noEmit", + "types:create": "tsc --emitDeclarationOnly" + }, + "devDependencies": { + "chalk": "^5.3.0", + "concurrently": "^8.2.2", + "esbuild": "^0.19.11", + "eslint": "^8.51.0", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "@cesdk/cesdk-js": "~1.20.0" + }, + "dependencies": { + } +} diff --git a/packages/i18n-polyfill/scripts/build.mjs b/packages/i18n-polyfill/scripts/build.mjs new file mode 100644 index 0000000..13d12e1 --- /dev/null +++ b/packages/i18n-polyfill/scripts/build.mjs @@ -0,0 +1,5 @@ +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +await Promise.all(configs.map(async (config) => await esbuild.build(config))); diff --git a/packages/i18n-polyfill/scripts/watch.mjs b/packages/i18n-polyfill/scripts/watch.mjs new file mode 100644 index 0000000..15dbb21 --- /dev/null +++ b/packages/i18n-polyfill/scripts/watch.mjs @@ -0,0 +1,19 @@ +import chalk from 'chalk'; +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] ${chalk.green('Watching...')}` +); + +const contexts = await Promise.all( + configs.map((config) => esbuild.context(config)) +); + +await Promise.any(contexts.map((ctx) => ctx.watch())); diff --git a/packages/i18n-polyfill/src/index.ts b/packages/i18n-polyfill/src/index.ts new file mode 100644 index 0000000..078b3da --- /dev/null +++ b/packages/i18n-polyfill/src/index.ts @@ -0,0 +1,80 @@ +import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; + +import Manifest from './manifest'; + + +export interface PluginConfiguration { + // uploader ? +} + +export { Manifest }; + +export default () => { + return { + initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { + polyfill(cesdk); + } + }; +}; + + + +// we could polyfill them +import { merge } from 'lodash'; +import { flatten } from './utils/flatten'; + +export class I18N { + #translations: any = {}; + #locale: string = 'en'; + + setTranslations(translations: any) { + const flattenedTranslations = flatten(translations); + this.#translations = merge(this.#translations, flattenedTranslations); + } + + translate(key: string, fallback: string | undefined = undefined) { + const lookup = this.#locale.concat('.', key); + return this.#translations[lookup] ?? fallback ?? key; + } + t = this.translate.bind(this) +} + +export interface I18N { + setTranslations: (translations: any) => void; + translate(key: string, fallback: string | undefined): string; + +} + +export type I18NType = & { i18n?: I18N } + +export type Translations = { [locale: string]: object; } + +export function polyfill(sdk: CreativeEditorSDK) { + + const Polyfill = class extends I18N { + #translations: any = {}; + #locale: string = 'en'; + #origSetTranslations = sdk.setTranslations.bind(sdk); + + constructor(params: any) { + super(); + sdk.setTranslations = this.setTranslations.bind(this); + } + setTranslations(translations: Translations) { + this.#translations = merge(this.#translations, flatten(translations)); + this.#origSetTranslations(translations); + } + + translate(key: string, fallback: string | undefined = undefined) { + const lookup = this.#locale.concat('.', key); + return this.#translations[lookup] ?? fallback ?? key; + } + t = this.translate.bind(this) + } + + // @ts-ignore + if (!sdk.i18n) { + // @ts-ignore + sdk.i18n = new Polyfill() + } +} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/manifest.ts b/packages/i18n-polyfill/src/manifest.ts new file mode 100644 index 0000000..0972d63 --- /dev/null +++ b/packages/i18n-polyfill/src/manifest.ts @@ -0,0 +1,4 @@ +export default { + id: "@imgly/polyfill-commands", + +} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/utils/flatten.ts b/packages/i18n-polyfill/src/utils/flatten.ts new file mode 100644 index 0000000..03dfe56 --- /dev/null +++ b/packages/i18n-polyfill/src/utils/flatten.ts @@ -0,0 +1,46 @@ +export function flatten(obj: any, prefix = ''): any { + const flattened = {}; + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const propName = prefix ? `${prefix}.${key}` : key; + + if (typeof obj[key] === 'object' && obj[key] !== null) { + Object.assign(flattened, flatten(obj[key], propName)); + } else { + // @ts-ignore + flattened[propName] = obj[key]; + } + } + } + + return flattened; +} + + +export function unflatten(obj: any): any { + const unflattened = {}; + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const value = obj[key]; + const keys = key.split('.'); + + let currentObj = unflattened; + for (let i = 0; i < keys.length - 1; i++) { + const nestedKey = keys[i]; + if (!currentObj.hasOwnProperty(nestedKey)) { + // @ts-ignore + currentObj[nestedKey] = {}; + } + // @ts-ignore + currentObj = currentObj[nestedKey]; + } + + // @ts-ignore + currentObj[keys[keys.length - 1]] = value; + } + } + + return unflattened; +} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/worker.ts b/packages/i18n-polyfill/src/worker.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/i18n-polyfill/tsconfig.json b/packages/i18n-polyfill/tsconfig.json new file mode 100644 index 0000000..47d465c --- /dev/null +++ b/packages/i18n-polyfill/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es2017", + "module": "es2020", + "lib": ["es2018", "dom"], + "moduleResolution": "node", + "isolatedModules": true, + "esModuleInterop": true, + "declaration": true, + "declarationDir": "types/", + "skipLibCheck": true + }, + "include": ["src/**/*", "esbuild/global.d.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/i18n-polyfill/types/index.d.ts b/packages/i18n-polyfill/types/index.d.ts new file mode 100644 index 0000000..9d428f5 --- /dev/null +++ b/packages/i18n-polyfill/types/index.d.ts @@ -0,0 +1,30 @@ +import CreativeEditorSDK from '@cesdk/cesdk-js'; +import Manifest from './manifest'; +export interface PluginConfiguration { +} +export { Manifest }; +declare const _default: () => { + initializeUserInterface({ cesdk }: { + cesdk: CreativeEditorSDK; + }): void; +}; +export default _default; +export declare class I18N { + #private; + setTranslations(translations: any): void; + t: { + (key: string, fallback?: string | undefined): any; + (key: string, fallback: string | undefined): string; + }; +} +export interface I18N { + setTranslations: (translations: any) => void; + translate(key: string, fallback: string | undefined): string; +} +export type I18NType = { + i18n?: I18N; +}; +export type Translations = { + [locale: string]: object; +}; +export declare function polyfill(sdk: CreativeEditorSDK): void; diff --git a/packages/i18n-polyfill/types/manifest.d.ts b/packages/i18n-polyfill/types/manifest.d.ts new file mode 100644 index 0000000..e1ead83 --- /dev/null +++ b/packages/i18n-polyfill/types/manifest.d.ts @@ -0,0 +1,4 @@ +declare const _default: { + id: string; +}; +export default _default; diff --git a/packages/i18n-polyfill/types/utils/flatten.d.ts b/packages/i18n-polyfill/types/utils/flatten.d.ts new file mode 100644 index 0000000..f9433a9 --- /dev/null +++ b/packages/i18n-polyfill/types/utils/flatten.d.ts @@ -0,0 +1,2 @@ +export declare function flatten(obj: any, prefix?: string): any; +export declare function unflatten(obj: any): any; diff --git a/packages/i18n-polyfill/types/worker.d.ts b/packages/i18n-polyfill/types/worker.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index 2a1183b..f184736 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -15,9 +15,10 @@ import { areBlocksSupported } from './utils'; +export interface Logger { log: (message: string) => void, debug: (message: string) => void, error: (message: string) => void, trace: (message: string) => void } export interface PluginConfiguration { - logger?: { log: (message: string) => void, debug: (message: string) => void, error: (message: string) => void, trace: (message: string) => void } + logger?: Logger } export { Manifest }; @@ -38,8 +39,8 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { // const engine = polyfillEngineWithCommands(cesdk.engine); const engine = cesdk.engine; // @ts-ignore - if (!cesdk.engine.polyfill_commands) { - logger?.error("Polyfill engine.engine.polyfill_commands not available!") + if (!cesdk.engine.commands) { + logger?.error("Polyfill engine.engine.commands not available!") return; } @@ -58,7 +59,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { }); //@ts-ignore - logger?.trace("checking if engine has polyfill_commands", cesdk.engine.polyfill_commands ? "yes" : "no") + logger?.trace("checking if engine has commands", cesdk.engine.commands ? "yes" : "no") engine.event.subscribe([], async (events) => { events @@ -73,7 +74,7 @@ export default (pluginConfiguration: PluginConfiguration = {}) => { // @ts-ignore const func = commands[command]; // @ts-ignore - cesdk.engine.polyfill_commands?.registerCommand( + cesdk.engine.commands?.registerCommand( command, async (params: any) => await func(cesdk, params) ); diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts index 349d612..63ce420 100644 --- a/packages/vectorizer/src/manifest.ts +++ b/packages/vectorizer/src/manifest.ts @@ -15,15 +15,16 @@ export default { commands: { // maybe we don't need the manifest after all? [PLUGIN_ACTION_VECTORIZE_LABEL]: { - title: "Turn into Vectorpath", //default when no translation is given + // title: "Convert into Vector", //default when no translation is given } }, i18n: { en: { - [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Turn into Vectorpaths' + [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Convert into Vectorpath' + }, de: { - [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Wandle in Vectorpfade' + [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Konvertiere in Vectorpfade' } } } diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index 80e8550..ae9bfd6 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -34,7 +34,7 @@ export default (cesdk: CreativeEditorSDK) => { loadingProgress: undefined, // creates infinite spinner onClick: () => cesdk // @ts-ignore - .engine.polyfill_commands + .engine.commands ?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockIds: candidates }) }); } diff --git a/packages/vectorizer/types/i18n.d.ts b/packages/vectorizer/types/i18n.d.ts deleted file mode 100644 index c1327c7..0000000 --- a/packages/vectorizer/types/i18n.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export declare const en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; -}; -export declare const de: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; -}; -declare const _default: { - de: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; - }; - en: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": string; - }; -}; -export default _default; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index dc3afc1..83d82cc 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -1,12 +1,13 @@ import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; import Manifest from './manifest'; +export interface Logger { + log: (message: string) => void; + debug: (message: string) => void; + error: (message: string) => void; + trace: (message: string) => void; +} export interface PluginConfiguration { - logger?: { - log: (message: string) => void; - debug: (message: string) => void; - error: (message: string) => void; - trace: (message: string) => void; - }; + logger?: Logger; } export { Manifest }; declare const _default: (pluginConfiguration?: PluginConfiguration) => { diff --git a/packages/vectorizer/types/utils/commands.d.ts b/packages/vectorizer/types/utils/commands.d.ts deleted file mode 100644 index 5075718..0000000 --- a/packages/vectorizer/types/utils/commands.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -declare const _default: { - "plugin.@imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { - blockIds?: number[] | undefined; - }) => Promise; -}; -export default _default; diff --git a/packages/vectorizer/types/utils/polyfills.d.ts b/packages/vectorizer/types/utils/polyfills.d.ts deleted file mode 100644 index 99db4ec..0000000 --- a/packages/vectorizer/types/utils/polyfills.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CreativeEngine } from '@cesdk/cesdk-js'; -export type CreativeEngineWithPolyfills = CreativeEngine & { - polyfill_commands?: Commands; -}; -export type CommandType = (params: any) => Promise; -export declare class Commands { - #private; - constructor(engine: CreativeEngineWithPolyfills); - registerCommand(label: string, callback: (params: any) => Promise): void; - executeCommand(label: string, params: any): Promise; -} -export declare function polyfillEngineWithCommands(engine: CreativeEngine): CreativeEngineWithPolyfills; From 13facdef55174da4b6430e6df54894f0f80a8af1 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Tue, 27 Feb 2024 21:27:48 +0100 Subject: [PATCH 23/32] wip --- TODO.md | 15 +- examples/imgly-components-source.zip | Bin 0 -> 1834 bytes examples/web/package.json | 3 +- examples/web/src/App.tsx | 125 +++++------ .../web/src/components/CommandPalette.tsx | 21 +- examples/web/src/{externals.ts => deps.ts} | 0 .../plugins/imgly-commands/PluginManifest.ts | 10 + .../src/plugins/imgly-commands/commands.ts | 4 + .../imgly-commands/commands/__template.ts | 3 + .../imgly-commands/commands/clipboard.ts | 78 +++---- .../imgly-commands/commands/container.ts | 107 +++++++++ .../imgly-commands/commands/copyStyle.ts | 84 ++++++++ .../plugins/imgly-commands/commands/debug.ts | 202 ----------------- .../plugins/imgly-commands/commands/export.ts | 116 ++++++---- .../plugins/imgly-commands/commands/image.ts | 24 +++ .../imgly-commands/commands/lifecycle.ts | 72 ++----- .../imgly-commands/commands/old_debug.ts | 203 ++++++++++++++++++ .../imgly-commands/commands/syncStyle.ts | 123 +++++++++++ .../imgly-commands/commands/turn_into.ts | 0 .../web/src/plugins/imgly-commands/index.ts | 67 +++--- .../translations.ts => locale/en.json} | 32 +-- .../src/plugins/imgly-commands/manifest.json | 80 +++++++ .../src/plugins/imgly-commands/types/types.ts | 5 + .../src/plugins/imgly-commands/utils/cesdk.ts | 39 ++++ examples/web/src/utils/i18n.ts | 27 --- examples/web/tsconfig.json | 2 +- package.json | 3 +- .../LICENSE.md | 0 .../README.md | 0 .../STRUCTURE.md | 0 .../{commands-polyfill => api-utils}/TODO.md | 0 .../esbuild/config.mjs | 0 .../esbuild/global.d.ts | 0 packages/api-utils/manifest.json | 11 + .../{i18n-polyfill => api-utils}/package.json | 4 +- .../scripts/build.mjs | 0 .../scripts/watch.mjs | 0 packages/api-utils/src/index.ts | 7 + packages/api-utils/src/plugin/Commands.ts | 61 ++++++ packages/api-utils/src/plugin/I18n.ts | 43 ++++ packages/api-utils/src/plugin/Logger.ts | 8 + .../api-utils/src/plugin/PluginContext.ts | 45 ++++ packages/api-utils/src/plugin/Subscribable.ts | 24 +++ .../src/utils/flatten.ts | 0 .../src/worker.ts | 0 .../tsconfig.json | 1 + packages/api-utils/types/index.d.ts | 4 + .../types/manifest.d.ts | 0 packages/api-utils/types/plugin/Commands.d.ts | 22 ++ packages/api-utils/types/plugin/I18n.d.ts | 18 ++ packages/api-utils/types/plugin/Logger.d.ts | 7 + .../api-utils/types/plugin/PluginContext.d.ts | 17 ++ .../api-utils/types/plugin/Subscribable.d.ts | 5 + .../types/utils/flatten.d.ts | 0 .../types/worker.d.ts | 0 packages/commands-polyfill/package.json | 66 ------ packages/commands-polyfill/src/index.ts | 50 ----- packages/commands-polyfill/src/manifest.ts | 4 - packages/commands-polyfill/types/index.d.ts | 25 --- packages/i18n-polyfill/LICENSE.md | 1 - packages/i18n-polyfill/README.md | 40 ---- packages/i18n-polyfill/STRUCTURE.md | 1 - packages/i18n-polyfill/TODO.md | 0 packages/i18n-polyfill/esbuild/config.mjs | 58 ----- packages/i18n-polyfill/esbuild/global.d.ts | 3 - packages/i18n-polyfill/scripts/build.mjs | 5 - packages/i18n-polyfill/scripts/watch.mjs | 19 -- packages/i18n-polyfill/src/index.ts | 80 ------- packages/i18n-polyfill/src/manifest.ts | 4 - packages/i18n-polyfill/src/worker.ts | 0 packages/i18n-polyfill/tsconfig.json | 16 -- packages/i18n-polyfill/types/index.d.ts | 30 --- packages/i18n-polyfill/types/manifest.d.ts | 4 - packages/i18n-polyfill/types/worker.d.ts | 0 packages/vectorizer/PLAYGROUND.md | 180 ++++++++++++++++ packages/vectorizer/manifest.json | 66 ++++++ packages/vectorizer/package.json | 3 +- packages/vectorizer/src/PluginManifest.ts | 16 ++ packages/vectorizer/src/activate.ts | 90 ++++++++ packages/vectorizer/src/commands.ts | 27 +-- packages/vectorizer/src/defaults.ts | 0 packages/vectorizer/src/deps.ts | 6 + packages/vectorizer/src/handler.ts | 28 +++ packages/vectorizer/src/index.ts | 137 +----------- packages/vectorizer/src/manifest.ts | 31 --- packages/vectorizer/src/ui.ts | 56 ++--- .../src/{utils.ts => utils/common.ts} | 15 +- packages/vectorizer/tsconfig.json | 3 +- packages/vectorizer/types/PluginManifest.d.ts | 69 ++++++ packages/vectorizer/types/activate.d.ts | 2 + packages/vectorizer/types/commands.d.ts | 11 +- packages/vectorizer/types/defaults.d.ts | 0 packages/vectorizer/types/deps.d.ts | 5 + packages/vectorizer/types/handler.d.ts | 6 + packages/vectorizer/types/index.d.ts | 74 +++++-- packages/vectorizer/types/manifest.d.ts | 26 --- packages/vectorizer/types/ui.d.ts | 7 +- .../types/{utils.d.ts => utils/common.d.ts} | 2 +- 98 files changed, 1786 insertions(+), 1202 deletions(-) create mode 100644 examples/imgly-components-source.zip rename examples/web/src/{externals.ts => deps.ts} (100%) create mode 100644 examples/web/src/plugins/imgly-commands/PluginManifest.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/__template.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/container.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/copyStyle.ts delete mode 100644 examples/web/src/plugins/imgly-commands/commands/debug.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/image.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/old_debug.ts create mode 100644 examples/web/src/plugins/imgly-commands/commands/syncStyle.ts delete mode 100644 examples/web/src/plugins/imgly-commands/commands/turn_into.ts rename examples/web/src/plugins/imgly-commands/{translations/translations.ts => locale/en.json} (66%) create mode 100644 examples/web/src/plugins/imgly-commands/manifest.json create mode 100644 examples/web/src/plugins/imgly-commands/types/types.ts create mode 100644 examples/web/src/plugins/imgly-commands/utils/cesdk.ts delete mode 100644 examples/web/src/utils/i18n.ts rename packages/{commands-polyfill => api-utils}/LICENSE.md (100%) rename packages/{commands-polyfill => api-utils}/README.md (100%) rename packages/{commands-polyfill => api-utils}/STRUCTURE.md (100%) rename packages/{commands-polyfill => api-utils}/TODO.md (100%) rename packages/{commands-polyfill => api-utils}/esbuild/config.mjs (100%) rename packages/{commands-polyfill => api-utils}/esbuild/global.d.ts (100%) create mode 100644 packages/api-utils/manifest.json rename packages/{i18n-polyfill => api-utils}/package.json (94%) rename packages/{commands-polyfill => api-utils}/scripts/build.mjs (100%) rename packages/{commands-polyfill => api-utils}/scripts/watch.mjs (100%) create mode 100644 packages/api-utils/src/index.ts create mode 100644 packages/api-utils/src/plugin/Commands.ts create mode 100644 packages/api-utils/src/plugin/I18n.ts create mode 100644 packages/api-utils/src/plugin/Logger.ts create mode 100644 packages/api-utils/src/plugin/PluginContext.ts create mode 100644 packages/api-utils/src/plugin/Subscribable.ts rename packages/{i18n-polyfill => api-utils}/src/utils/flatten.ts (100%) rename packages/{commands-polyfill => api-utils}/src/worker.ts (100%) rename packages/{commands-polyfill => api-utils}/tsconfig.json (92%) create mode 100644 packages/api-utils/types/index.d.ts rename packages/{commands-polyfill => api-utils}/types/manifest.d.ts (100%) create mode 100644 packages/api-utils/types/plugin/Commands.d.ts create mode 100644 packages/api-utils/types/plugin/I18n.d.ts create mode 100644 packages/api-utils/types/plugin/Logger.d.ts create mode 100644 packages/api-utils/types/plugin/PluginContext.d.ts create mode 100644 packages/api-utils/types/plugin/Subscribable.d.ts rename packages/{i18n-polyfill => api-utils}/types/utils/flatten.d.ts (100%) rename packages/{commands-polyfill => api-utils}/types/worker.d.ts (100%) delete mode 100644 packages/commands-polyfill/package.json delete mode 100644 packages/commands-polyfill/src/index.ts delete mode 100644 packages/commands-polyfill/src/manifest.ts delete mode 100644 packages/commands-polyfill/types/index.d.ts delete mode 100644 packages/i18n-polyfill/LICENSE.md delete mode 100644 packages/i18n-polyfill/README.md delete mode 100644 packages/i18n-polyfill/STRUCTURE.md delete mode 100644 packages/i18n-polyfill/TODO.md delete mode 100644 packages/i18n-polyfill/esbuild/config.mjs delete mode 100644 packages/i18n-polyfill/esbuild/global.d.ts delete mode 100644 packages/i18n-polyfill/scripts/build.mjs delete mode 100644 packages/i18n-polyfill/scripts/watch.mjs delete mode 100644 packages/i18n-polyfill/src/index.ts delete mode 100644 packages/i18n-polyfill/src/manifest.ts delete mode 100644 packages/i18n-polyfill/src/worker.ts delete mode 100644 packages/i18n-polyfill/tsconfig.json delete mode 100644 packages/i18n-polyfill/types/index.d.ts delete mode 100644 packages/i18n-polyfill/types/manifest.d.ts delete mode 100644 packages/i18n-polyfill/types/worker.d.ts create mode 100644 packages/vectorizer/PLAYGROUND.md create mode 100644 packages/vectorizer/manifest.json create mode 100644 packages/vectorizer/src/PluginManifest.ts create mode 100644 packages/vectorizer/src/activate.ts delete mode 100644 packages/vectorizer/src/defaults.ts create mode 100644 packages/vectorizer/src/deps.ts create mode 100644 packages/vectorizer/src/handler.ts delete mode 100644 packages/vectorizer/src/manifest.ts rename packages/vectorizer/src/{utils.ts => utils/common.ts} (95%) create mode 100644 packages/vectorizer/types/PluginManifest.d.ts create mode 100644 packages/vectorizer/types/activate.d.ts delete mode 100644 packages/vectorizer/types/defaults.d.ts create mode 100644 packages/vectorizer/types/deps.d.ts create mode 100644 packages/vectorizer/types/handler.d.ts delete mode 100644 packages/vectorizer/types/manifest.d.ts rename packages/vectorizer/types/{utils.d.ts => utils/common.d.ts} (98%) diff --git a/TODO.md b/TODO.md index 77c8209..12ad073 100644 --- a/TODO.md +++ b/TODO.md @@ -45,4 +45,17 @@ - Element: Allow, (Defer,) Deny -- `getEffects` api seems unsimilar to all `findAllScopes` etc. Maybe \ No newline at end of file +- `getEffects` api seems unsimilar to all `findAllScopes` etc. Maybe +- `UploadCallbackContext` not found in exports + + +- `MultiSelection` across multiple pages does not work!!! +- `Engine disposed` is logged everytime + + +- `Unsubribe` mechanism. We need to know and be able todo cleanup of commands. E.g. removeCommand and than also cleanup all dependencies +- In VSCode every register function also returns the "unsubscribe" and "free" function. + + +- `stroke/join` properties are not exposed it seems if you list all properties +- Default Stroke grey seems not a good choice as default \ No newline at end of file diff --git a/examples/imgly-components-source.zip b/examples/imgly-components-source.zip new file mode 100644 index 0000000000000000000000000000000000000000..b3462a0404efb6ebb138b771a48574977fec22e6 GIT binary patch literal 1834 zcmWIWW@Zs#0D&_z{UX2&C?Ub1z>t}no>QrtoS$2epO>0fQmk8?Us{x$svjD{%fQaa zd^VK_h(8{y6cox|NUl_ zCC?V9>sXUKU-apm2qsFMCEo1Sc&|DsTd{fgSnb*J5&Qrx21{eyxV?QS}#A7Fo~-LXO| zboP~1nx6W$t0!4)KYeS(Hie~&HeZM|U#axF%|Y?1J_k2V3-_N*oY+q1@}ExguUr`vL1eF8(~{u)K&mgfdBkF;~)E~x3POpR$lo+I$rnF-@GlA><^1B z{C;|@U3zmImR{=ZiyS0d)#61@D{!Bz4B-s~LKDxH5Uf$;>23`jJA;#&nNnm~Mc zJkgX`T%1}`3`qkmz}RU8Vi1iMONcbkzYviI4A~hNbO;-cNOG|BFi!xO7JwK;quF#e zG%){`fk55)^&2V}RiwVg`yw_up{UHCzjCvOP0-R^d0O(Y zjQ8$G4;5ASF7-)}`{pKYGL5mjagtrfzUEE3M>5_?NQq^7U7IcCdBETmi-zI616;3L z_$m)6N$g)HVA;&S@eWpLOT|d%WIH#%JMv zW3{U#HqSht9RIm{U$R`og%6GIkJdcB^Xbj)m3G?FS62M4YMvUuJNIUZUWE6psd0-l zrxyQyS>h}u7QR8gx#P?^&9G%69G_cw7d#2><+cb}FuR>;vSy&>x$p(4d)gaM7h8Pv z(|EpYo~TQVbih#`k4DDRF>*h{45ubbH5UnGlxMVu9V+!KvD|(|_EBG1U_juU-;Sa_ z)^FFTcU#?m{rTez79X7%2cBqKFE+}ExFcD6SXoi@N^8m^JD%IyI_#X4zF)BX;qMZ4 zKPgk{`SYU%_bkr*t4g0}8SVbSq)F+&huWc}W+#ia)nT^jcVm3k2}hjN-;oo*7cS9r z;@YhnKlm2zeG;y*WvO+^$}2I4KE!l&Ilb0D^lDR~`_$gNnAwXJwgkqwT)TJD%;{@d zrlFF6-nrERPYopMPSo7JG5P8>AJ;4Qw@g2GgwMw?*pAO8?2i7=A2X)Uo!K~daZ>x=Jhl*9 z@FM#OTZsX)?XBZqM%;cPy8J+R4OD_42QH`tfq^BBQNSR_6@XC7NGeYPyjj^mrn3Oy LZlFgZSwTDi9dW6` literal 0 HcmV?d00001 diff --git a/examples/web/package.json b/examples/web/package.json index 64cfeb0..b1436fa 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -10,8 +10,7 @@ }, "dependencies": { "@cesdk/cesdk-js": "^1.20.0", - "@imgly/plugin-i18n-polyfill": "*", - "@imgly/plugin-commands-polyfill": "*", + "@imgly/plugin-api-utils": "*", "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer-web": "*", "lodash": "^4.17.21", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 02a89b6..8303acf 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -2,7 +2,8 @@ import { useRef, useState } from "react"; import CreativeEditorSDKComponent from "./components/CreativeEditorSDK"; -import CreativeEditorSDK_UNMODIFIED, { Configuration } from "@cesdk/cesdk-js"; +import CreativeEditorSDK from "@cesdk/cesdk-js"; + // React UI Components import { CommandPalette } from "./components/CommandPalette" @@ -10,20 +11,17 @@ import { CommandPalette } from "./components/CommandPalette" import { downloadBlocks } from "./utils/download"; // IMGLY Plugins -import PolyFillI18NPlugin, { type I18NType } from "@imgly/plugin-i18n-polyfill" -import PolyfillCommandsPlugin, { type CommandsType } from "@imgly/plugin-commands-polyfill" -type CreativeEditorSDK = CreativeEditorSDK_UNMODIFIED & I18NType & CommandsType + // Plugins -import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; +// import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; -import ImglyCommandsPlugin from "./plugins/imgly-commands"; - - +import CommandsPlugin from "./plugins/imgly-commands"; +import { PluginContext } from "@imgly/plugin-api-utils"; declare global { - interface Window { cesdk: CreativeEditorSDK } + interface Window { imgly: PluginContext } } @@ -49,14 +47,16 @@ function App() { }); } - const [config, setConfig] = useState( + + + const [config, _setConfig] = useState( { "license": import.meta.env.VITE_CESDK_LICENSE_KEY, - "callbacks.onUpload": "local", + "callbacks.onUpload": 'local', "callbacks.onDownload": "download", "callbacks.onSave": async (str: string) => downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }), "callbacks.onExport": async (blobs: Array, options: any) => downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }), - "callbacks.onLoad": "upload", + // "callbacks.onLoad": , // devMode: true, "theme": "dark", "role": 'Creator', @@ -68,82 +68,56 @@ function App() { }) - const initCallback = async (_cesdk: CreativeEditorSDK) => { - const cesdk = _cesdk as CreativeEditorSDK; + const initCallback = async (cesdk: CreativeEditorSDK) => { + + const imgly = new PluginContext(cesdk) + // @ts-ignore window.cesdk = cesdkRef.current = cesdk + window.imgly = imgly // Init Scene Programatically await cesdk.createDesignScene(); cesdk.engine.scene.setDesignUnit("Pixel"); // + + + const vectorizerPlugin = VectorizerPlugin(imgly, {}) + const commandsPlugin = CommandsPlugin(imgly, {}) + // const backgroundRemovalPlugin = BackgroundRemovalPlugin() + + // const imglyComponentSource = ImglyComponentSource() - // Plugins - - const polyfillI18NPlugin = PolyFillI18NPlugin() - const polyfillCommandsPlugin = PolyfillCommandsPlugin() - const vectorizerPlugin = VectorizerPlugin() - const backgroundRemovalPlugin = BackgroundRemovalPlugin() - const imglyCommandsPlugin = ImglyCommandsPlugin() + // - // Register Plguins - await Promise.all([ - cesdk.addDefaultAssetSources(), - cesdk.addDemoAssetSources({ sceneMode: "Design" }), - cesdk.unstable_addPlugin(polyfillI18NPlugin), - cesdk.unstable_addPlugin(polyfillCommandsPlugin), - cesdk.unstable_addPlugin(imglyCommandsPlugin), - cesdk.unstable_addPlugin(vectorizerPlugin), - cesdk.unstable_addPlugin(backgroundRemovalPlugin), - ]); + // Register Plguins + await Promise.all([ + cesdk.addDefaultAssetSources(), + cesdk.addDemoAssetSources({ sceneMode: "Design" }), + cesdk.unstable_addPlugin(commandsPlugin), + // cesdk.unstable_addPlugin(imglyComponentSource), + cesdk.unstable_addPlugin(vectorizerPlugin), + // cesdk.unstable_addPlugin(backgroundRemovalPlugin), + ]); // Ui components - cesdk.ui.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); - "plugin.imgly.commandpalette2" - cesdk.setTranslations({ en: { "plugin.imgly.commandpalette.label": "✨ Run .." } }) + imgly.ui?.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); + + imgly.i18n.setTranslations({ en: { "plugin.imgly.commandpalette.label": "✨ Run .." } }) // Canvas Menu - const canvasMenuItems = cesdk.ui.unstable_getCanvasMenuOrder() + const canvasMenuItems = imgly.ui?.unstable_getCanvasMenuOrder() ?? [] const newCanvasMenuItems = ["plugin.imgly.commandpalette", ...canvasMenuItems]; - cesdk.ui.unstable_setCanvasMenuOrder(newCanvasMenuItems) + imgly.ui?.unstable_setCanvasMenuOrder(newCanvasMenuItems) - // react components + // Bind our react command paltte to cesdk command palettes are listen on new commands being created + imgly.commands.subscribe("register", (_label: string) => setCommandItems(generateCommandItemsfromCESDK(imgly))) + imgly.commands.subscribe("unregister", (_label: string) => setCommandItems(generateCommandItemsfromCESDK(imgly))) - const commandItems = generateCommandItemsfromCESDK(cesdk) - const customItems = [ - { - id: "ui.theme.light", - children: "UI: Switch to Light Theme", - showType: true, - onClick: async () => { - setConfig((current: Configuration) => { - return { - ...current, - theme: "light", - "ui.hide": true - } - }) - } - }, - { - id: "ui.theme.dark", - children: "UI: Switch to Dark Theme", - showType: true, - onClick: async () => { - setConfig((current) => { - return { - ...current, - theme: "dark" - } - }) - } - } - ] - const allCommands = [...commandItems, ...customItems] - setCommandItems(allCommands) + setCommandItems(generateCommandItemsfromCESDK(imgly)) } @@ -156,20 +130,23 @@ function App() { ); } -const generateCommandItemsfromCESDK = (cesdk: CreativeEditorSDK): Array => { - return cesdk - .engine +const generateCommandItemsfromCESDK = (ctx: PluginContext): Array => { + const cmds = ctx .commands! .listCommands() + + return cmds .map((cmdId: string) => { - const titel = cesdk.i18n!.t(cmdId) // this comes from the metadata + const titel = ctx.i18n.translate(cmdId) // this comes from the metadata + const desc = ctx.commands.getCommandDescription(cmdId) if (titel === undefined) throw new Error(`No translation found for command ${cmdId}`) return { id: cmdId, children: titel, + group: desc?.group || "Commands", showType: true, onClick: async () => { - await cesdk.engine.commands!.executeCommand(cmdId, {}) + await ctx.commands!.executeCommand(cmdId, {}) } } }) diff --git a/examples/web/src/components/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx index f62bfc8..7e6d55f 100644 --- a/examples/web/src/components/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -2,6 +2,8 @@ import "react-cmdk/dist/cmdk.css"; import CMDK, { filterItems, getItemIndex } from "react-cmdk"; import { useState, useEffect } from "react"; +import { groupBy } from "lodash"; + // https://github.com/albingroen/react-cmdk export const CommandPalette = (params: { items: Array, isOpen: boolean, setIsOpen: (val: boolean) => void }) => { const [page, _setPage] = useState<"root">("root"); @@ -33,17 +35,16 @@ export const CommandPalette = (params: { items: Array, isOpen: boolean, set }, []); - const filteredItems = filterItems( - [ - { - heading: undefined, - id: "turnInto", - items: items ?? [] - } - ], - search - ); + const grouped = groupBy(items,"group") + const filteredItems = filterItems(Object.keys(grouped).map((key) => { + return { + heading: key, + id: key, + items: grouped[key] ?? [] + } + }), search); + return ( + +export const PluginManifest = Manifest + diff --git a/examples/web/src/plugins/imgly-commands/commands.ts b/examples/web/src/plugins/imgly-commands/commands.ts new file mode 100644 index 0000000..c07fbee --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands.ts @@ -0,0 +1,4 @@ +export * from "./commands/lifecycle"; +export * from "./commands/export"; +export * from "./commands/image"; +export * from "./commands/container"; \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/__template.ts b/examples/web/src/plugins/imgly-commands/commands/__template.ts new file mode 100644 index 0000000..dc9d892 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/__template.ts @@ -0,0 +1,3 @@ +// @ts-ignore +const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts index e5a64a0..a0a5150 100644 --- a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts +++ b/examples/web/src/plugins/imgly-commands/commands/clipboard.ts @@ -1,54 +1,54 @@ -import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; -import { type CommandsType } from "@imgly/plugin-commands-polyfill"; +// import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; +// import { type CommandsType } from "@imgly/plugin-commands-polyfill"; -export const registerClipboardCommands = (cesdk: CreativeEditorSDK & CommandsType) => { +// export const registerClipboardCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - const { block, scene } = cesdk.engine - const commands = cesdk.engine.commands! +// const { block, scene } = cesdk.engine +// const commands = cesdk.engine.commands! - commands.registerCommand(`imgly.block.clipboard.selected.as.png`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } - const engine = cesdk.engine - const clipboardItems = await Promise.all(blockIds.map(async (bId: number) => { - const blob = await engine.block.export(bId, "image/png" as MimeType) - return new ClipboardItem({ - ["image/png"]: blob, - }, { presentationStyle: "attachment" }) +// commands.registerCommand(`imgly.block.clipboard.selected.as.png`, async (params: { blockIds: number[] }) => { +// let blockIds = params.blockIds ?? block.findAllSelected() +// if (blockIds.length === 0) { +// blockIds = [scene.get()!] +// } +// const engine = cesdk.engine +// const clipboardItems = await Promise.all(blockIds.map(async (bId: number) => { +// const blob = await engine.block.export(bId, "image/png" as MimeType) +// return new ClipboardItem({ +// ["image/png"]: blob, +// }, { presentationStyle: "attachment" }) - })) +// })) - await navigator.clipboard.write(clipboardItems) - }) +// await navigator.clipboard.write(clipboardItems) +// }) - commands.registerCommand(`imgly.block.clipboard.selected.as.scene`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() +// commands.registerCommand(`imgly.block.clipboard.selected.as.scene`, async (params: { blockIds: number[] }) => { +// let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } +// if (blockIds.length === 0) { +// blockIds = [scene.get()!] +// } - const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }) - await navigator.clipboard.writeText(await blob.text()) +// const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }) +// await navigator.clipboard.writeText(await blob.text()) - }) +// }) - commands.registerCommand(`imgly.block.clipboard.selected.as.json`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } - const str = await block.saveToString(blockIds); - const base64 = str.substring(4) - const json = atob(base64) - const blob = new Blob([json], { type: "application/json" }) - await navigator.clipboard.writeText(await blob.text()) +// commands.registerCommand(`imgly.block.clipboard.selected.as.json`, async (params: { blockIds: number[] }) => { +// let blockIds = params.blockIds ?? block.findAllSelected() +// if (blockIds.length === 0) { +// blockIds = [scene.get()!] +// } +// const str = await block.saveToString(blockIds); +// const base64 = str.substring(4) +// const json = atob(base64) +// const blob = new Blob([json], { type: "application/json" }) +// await navigator.clipboard.writeText(await blob.text()) - }) +// }) -} \ No newline at end of file +// } \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/container.ts b/examples/web/src/plugins/imgly-commands/commands/container.ts new file mode 100644 index 0000000..99a1e3d --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/container.ts @@ -0,0 +1,107 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; + +export const groupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + } = params; + if (blockIds.length < 1) return; + + const group = block.group(blockIds); + blockIds.forEach((id: number) => block.isSelected(id) && block.setSelected(id, false)); + block.setSelected(group, true); +} + + +export const ungroupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + } = params; + if (blockIds.length !== 1) return; + + const blockId = blockIds[0]; + const isSelected = block.isSelected(blockId); + if (block.getType(blockId) !== '//ly.img.ubq/group') return; + const childIds = block.getChildren(blockId); + block.ungroup(blockId); // Note – ungroup should return the IDs + childIds.forEach((id: number) => block.setSelected(id, isSelected)); + + +} +export const groupLayoutHStack = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + padding = 0 + } = params; + if (blockIds.length !== 1) return; + + const blockId = blockIds[0]; + if (block.getType(blockId) !== '//ly.img.ubq/group') return; + + const children = block.getChildren(blockId); + if (children.length === 0) return; + + let curXPos = block.getPositionX(children[0]) + let curYPos = block.getPositionY(children[0]) + children.forEach((childId: number) => { + block.setPositionY(childId, curYPos); + block.setPositionX(childId, curXPos); + const width = block.getFrameWidth(childId); + curXPos += width; + curXPos += padding; + }) +} + +export const groupLayoutVStack = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + padding = 0 + } = params; + if (blockIds.length !== 1) return; + + const blockId = blockIds[0]; + if (block.getType(blockId) !== '//ly.img.ubq/group') return; + + const children = block.getChildren(blockId); + if (children.length === 0) return; + + let curXPos = block.getPositionX(children[0]) + let curYPos = block.getPositionY(children[0]) + children.forEach((childId: number) => { + block.setPositionX(childId, curXPos); + block.setPositionY(childId, curYPos); + const height = block.getFrameHeight(childId); + curYPos += height; + curYPos += padding; + }) +} + + +export const groupLayoutCircle = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + padding = 0 + } = params; + if (blockIds.length !== 1) return; + + const blockId = blockIds[0]; + if (block.getType(blockId) !== '//ly.img.ubq/group') return; + + const children = block.getChildren(blockId); + if (children.length === 0) return; + + let curXPos = block.getPositionX(children[0]) + let curYPos = block.getPositionY(children[0]) + children.forEach((childId: number) => { + block.setPositionX(childId, curXPos); + block.setPositionY(childId, curYPos); + const height = block.getFrameHeight(childId); + curYPos += height; + curYPos += padding; + }) +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/copyStyle.ts b/examples/web/src/plugins/imgly-commands/commands/copyStyle.ts new file mode 100644 index 0000000..3c90fff --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/copyStyle.ts @@ -0,0 +1,84 @@ +// import CreativeEditorSDK from "@cesdk/cesdk-js"; +// import { type CommandsType } from "@imgly/plugin-commands-polyfill"; + +// import { readPropValue, writePropValue } from "../utils/cesdk"; + + +// // we can have much more here. What is good UX? +// // copy style to a global buffer +// // paste style from a global buffer + + + +// // all register should do an unregister, alternatively we can have lifetime + + +// export const registerCopyStyleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { + +// const { block } = cesdk.engine +// const commands = cesdk.engine.commands! + +// // do we need that if we bind commands? probably not +// type MapEntry = { type: string, value: any } + + +// const pasteTo = async (blockIds: number[], referenceValues: Map, whitelist: string[] | undefined = [], blacklist: string[] | undefined = []) => { +// blockIds = block.findAllSelected() +// blacklist = [...blacklist, "fill/solid/color"] +// blockIds.forEach((receiverBlockId: number) => { +// referenceValues.forEach((entry, key) => { +// if (whitelist && (whitelist.length !== 0) && !whitelist.includes(key)) return; +// if (blacklist && (blacklist.length !== 0) && blacklist.includes(key)) return; +// if (!block.isPropertyWritable(key)) return; +// const propType = block.getPropertyType(key) +// writePropValue(cesdk, receiverBlockId, key, entry.value, propType) +// }) +// }) +// } + +// // we could simply serialize to json for now and than apply it to the other block +// const generatedCommands: (() => void)[] = [] + +// const unregister = commands.registerCommand(`imgly.style.copy`, async (params: { blockIds: number[], whitelist: string[] | undefined, blacklist: string[] | undefined }) => { +// let { blockIds = block.findAllSelected(), whitelist = [], blacklist = [] } = params +// if (blockIds.length === 0) return; + +// generatedCommands.forEach((unregister) => unregister()) + +// blacklist = [...blacklist, "fill/solid/color"] +// const [senderBlockIds, ..._receiverBlockIds] = blockIds +// const referenceValues = new Map() +// { +// const props = block.findAllProperties(senderBlockIds) +// props.forEach((propKey: string) => { +// if (whitelist && (whitelist.length !== 0) && !whitelist.includes(propKey)) return; +// if (blacklist && (blacklist.length !== 0) && blacklist.includes(propKey)) return; +// if (!block.isPropertyReadable(propKey)) return; +// const propType = block.getPropertyType(propKey) +// const propValue = readPropValue(cesdk, senderBlockIds, propKey, propType) +// referenceValues.set(propKey, { type: propType, value: propValue }) +// generatedCommands.push( +// commands.registerCommand(`imgly.style.paste.${propKey}`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, [propKey], [])) +// ) + +// }) +// } + +// // some special commands +// generatedCommands.push( +// commands.registerCommand(`imgly.style.paste.rotation`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["rotation"], [])), +// commands.registerCommand(`imgly.style.paste.size`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["width", "height"], [])), +// commands.registerCommand(`imgly.style.paste.position`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["position/x", "position/y"], [])), +// ) + +// }) +// // we could life registe commands and also unregister based on the possibilites + +// return [unregister] +// } + + + +// // we can make sync alive + + diff --git a/examples/web/src/plugins/imgly-commands/commands/debug.ts b/examples/web/src/plugins/imgly-commands/commands/debug.ts deleted file mode 100644 index eba986f..0000000 --- a/examples/web/src/plugins/imgly-commands/commands/debug.ts +++ /dev/null @@ -1,202 +0,0 @@ -import CreativeEditorSDK from "@cesdk/cesdk-js"; -import { type CommandsType } from "@imgly/plugin-commands-polyfill"; -import { readPropValue } from "../../../utils/cesdk"; - - -export const registerDebugCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - const { asset, block, variable, editor, scene } = cesdk.engine - const commands = cesdk.engine.commands!; - - commands.registerCommand("imgly.debug.log.metadata", async (params: { blockIds?: number[] }) => { - const blockIds = params.blockIds ?? block.findAllSelected() - - blockIds.forEach((id: number) => { - const keys = block.findAllMetadata(id) - if (keys.length === 0) { - console.debug("No metadata found for block", id) - return - } - keys.forEach((key: string) => { - const metadata = block.getMetadata(id, key) - const obj = JSON.parse(metadata) - console.debug(key, obj) - }) - }) - }) - - commands.registerCommand("imgly.debug.clear.metadata", async (params: { blockIds?: number[] }) => { - const blockIds = params.blockIds ?? block.findAllSelected() - blockIds.forEach((id: number) => { - block.findAllMetadata(id) - .forEach((key: string) => { - block.setMetadata(id, key, "") - }) - }) - }) - - commands.registerCommand("imgly.debug.log.block_properties", async (params: { blockIds?: number[] }) => { - const blockIds = params.blockIds ?? block.findAllSelected() - - blockIds.forEach((id: number) => { - const props = block.findAllProperties(id) - const propDefinition = new Map() - props.forEach((propKey: string) => { - if (!block.isPropertyReadable(propKey)) return; - const propType = block.getPropertyType(propKey) - const propValue = readPropValue(cesdk, id, propKey, propType) - propDefinition.set(propKey, { type: propType, value: propValue }) - - }) - - console.debug("Properties for block", id, propDefinition) - }) - }) - - - - commands.registerCommand("imgly.debug.log.fill", async (params: { blockIds?: number[] }) => { - const blockIds = params.blockIds ?? block.findAllSelected() - blockIds.forEach((bId: number) => { - const fId = block.getFill(bId) - if (!block.isValid(fId)) { - console.debug("No fill found for block", bId) - return - }; - - const props = block.findAllProperties(fId) - const propDefinition = new Map() - props.forEach((propKey: string) => { - console.debug("Reading propKey", propKey) - if (!block.isPropertyReadable(propKey)) return; - - const propType = block.getPropertyType(propKey) - const propValue = readPropValue(cesdk, fId, propKey, propType) - propDefinition.set(propKey, { type: propType, value: propValue }) - - }) - - console.debug("Fill properties for block", bId, propDefinition) - }) - }) - - - - commands.registerCommand("imgly.debug.log.assets", async (_params: { blockIds?: number[] }) => { - // const blockIds = params.blockIds ?? block.findAllSelected() - - const entries = asset.findAllSources() - const definition = new Map() - entries.forEach((key: string) => { - const types = asset.getSupportedMimeTypes(key) - const groups = variable.getString(key) - definition.set(key, { types, groups }) - }) - console.debug("Assets", definition) - }) - - - commands.registerCommand("imgly.debug.log.variables", async (_params: { blockIds?: number[] }) => { - const vars = variable.findAll() - const definition = new Map() - vars.forEach((key: string) => { - const value = variable.getString(key) - - definition.set(key, { type: "String", value: value }) - }) - console.debug("Variables", definition) - - }) - - - commands.registerCommand("imgly.debug.log.editor.settings", async (_params: { blockIds?: number[] }) => { - const entries = editor.findAllSettings() - const definition = new Map() - entries.forEach((key: string) => { - const type = editor.getSettingType(key) - const value = undefined; //editor.getSettingValue(key) - definition.set(key, { type, value }) - }) - console.debug("Settings", definition) - - }) - - - - commands.registerCommand("imgly.debug.log.scene", async (_params: { blockIds?: number[] }) => { - console.debug("Settings", { - designUnit: scene.getDesignUnit(), - mode: scene.getMode(), - }) - - }) - - commands.registerCommand("imgly.debug.log.scopes", async (params: { blockIds?: number[] }) => { - // https://img.ly/docs/cesdk/engine/guides/scopes/ - const scopeNames = [ - "layer/move", - "layer/resize", - "layer/rotate", - "layer/crop", - "layer/clipping", - "layer/opacity", - "layer/blendMode", - "layer/visibility", - "appearance/adjustments", - "appearance/filter", - "appearance/effect", - "appearance/blur", - "appearance/shadow", - "lifecycle/destroy", // delete - "lifecycle/duplicate", - "editor/add", - "editor/select", - "fill/change", - "stroke/change", - "shape/change", - "text/edit", - // "text/change", // would be replace from library - "text/character" - ] - const definition = new Map() - scopeNames.forEach((scope: string) => { - const value = editor.getGlobalScope(scope) - definition.set(scope,{value}) - }) - console.debug("GlobalScopes", definition) - - const blockIds = params.blockIds ?? block.findAllSelected() - blockIds.forEach((id: number) => { - const definition = new Map() - scopeNames.forEach((scope: string) => { - const value = block.isAllowedByScope(id, scope) - definition.set(scope,{value}) - }) - console.debug("Scopes for block", id, definition) - }) - }) - - - - - commands.registerCommand("imgly.debug.log.effects", async (params: { blockIds?: number[] }) => { - const blockIds = params.blockIds ?? block.findAllSelected() - blockIds.forEach((id: number) => { - block.getEffects(id).forEach((eId: number) => { - const props = block.findAllProperties(eId); - let propDefinition = new Map() - props.forEach((propKey: string) => { - if (!block.isPropertyReadable(propKey)) return; - const propType = block.getPropertyType(propKey) - const propValue = readPropValue(cesdk, eId, propKey, propType) - propDefinition.set(propKey, { type: propType, value: propValue }) - - }) - - console.debug("Effect for block", id, propDefinition) - }) - - }) - - }) - -} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/export.ts b/examples/web/src/plugins/imgly-commands/commands/export.ts index 2884498..8c3ade3 100644 --- a/examples/web/src/plugins/imgly-commands/commands/export.ts +++ b/examples/web/src/plugins/imgly-commands/commands/export.ts @@ -1,53 +1,75 @@ -import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; -import { type CommandsType } from "@imgly/plugin-commands-polyfill"; +import { PluginContext } from "@imgly/plugin-api-utils"; +import { MimeType } from "@cesdk/cesdk-js"; import { downloadBlob } from "../../../utils/download"; -export const registerDownloadCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - - const { block, scene } = cesdk.engine - const commands = cesdk.engine.commands!; - const types = ["image/png", "image/jpeg", "image/webp", "image/x-tga", "application/pdf", "application/octet-stream"] - - types.forEach((mimeType: string) => { - const [_, extension] = mimeType.split("/") - commands.registerCommand(`imgly.block.download.selected.as.${extension}`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } - const engine = cesdk.engine - blockIds.forEach(async (bId: number) => { - const blob = await engine.block.export(bId, mimeType as MimeType) - downloadBlob(blob, `block-${bId}.${extension}`) - }) - }) - }) +// const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - commands.registerCommand(`imgly.block.download.selected.as.scene`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } - blockIds.forEach(async (bId: number) => { - const blob = new Blob([await block.saveToString([bId])], { type: "application/x-cesdk" }) - downloadBlob(blob, `block-${bId}.cesdk`) - }) - }) +const exportAsPngs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected(), mimeType = "image/png" as MimeType } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + + return await Promise.all(blockIds.map(async (bId: number) => { + return await block.export(bId, mimeType); + })); +}; + - commands.registerCommand(`imgly.block.download.selected.as.json`, async (params: { blockIds: number[] }) => { - let blockIds = params.blockIds ?? block.findAllSelected() - if (blockIds.length === 0) { - blockIds = [scene.get()!] - } - - blockIds.forEach(async (bId: number) => { - const str = await block.saveToString([bId]); - const base64 = str.substring(4) - const json = atob(base64) - const blob = new Blob([json], { type: "application/json" }) - downloadBlob(blob, `block-${bId}.json`) - }) +export const exportPngToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/png" as MimeType })).map((blob) => { + return new ClipboardItem({ + ["image/png"]: blob, + }, { presentationStyle: "attachment" }); }) - -} \ No newline at end of file + await navigator.clipboard.write(items); +}; + +export const exportPngToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/png" as MimeType })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.png`) }); +} + +export const exportJpegToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/jpeg" as MimeType })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.jpeg`) }); +} + +export const exportWebpToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/webp" as MimeType })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.webp`) }); +} + +export const exportPdfToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "application/pdf" as MimeType })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.pdf`) }); +} + + +export const exportRgba8ToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportAsPngs(ctx, { ...params, mimeType: "application/octet-stream" as MimeType })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.rgba8`) }); +} + + +export const exportSceneToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }); + await navigator.clipboard.writeText(await blob.text()); +}; + + +export const exportJSONToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + + const str = await block.saveToString(blockIds); + const base64 = str.substring(4); + const json = atob(base64); + const blob = new Blob([json], { type: "application/json" }); + await navigator.clipboard.writeText(await blob.text()); +}; + diff --git a/examples/web/src/plugins/imgly-commands/commands/image.ts b/examples/web/src/plugins/imgly-commands/commands/image.ts new file mode 100644 index 0000000..02e1acf --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/image.ts @@ -0,0 +1,24 @@ +import { ContentFillMode } from "@cesdk/cesdk-js" +import { PluginContext } from "@imgly/plugin-api-utils"; + +const imageFitWithMode = (ctx: PluginContext, params: { blockIds?: number[], fillMode: ContentFillMode }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected(), fillMode } = params; + blockIds.forEach((id: number) => { + if (!block.hasContentFillMode(id)) return; + block.setContentFillMode(id, fillMode) + }) +} + +export const imageFitModeCrop = async (ctx: PluginContext, params: { blockIds?: number[] }) => + imageFitWithMode(ctx, { ...params, fillMode: 'Crop' }) + + +export const imageFitModeCover = async (ctx: PluginContext, params: { blockIds?: number[] }) => + imageFitWithMode(ctx, { ...params, fillMode: 'Cover' }) + + +export const imageFitModeContain = async (ctx: PluginContext, params: { blockIds?: number[] }) => + imageFitWithMode(ctx, { ...params, fillMode: 'Contain' }) + + diff --git a/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts index 8559417..a7f2295 100644 --- a/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts +++ b/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts @@ -1,62 +1,28 @@ -import { type CommandsType } from "@imgly/plugin-commands-polyfill"; -import CreativeEditorSDK, { BooleanOperation } from "@cesdk/cesdk-js"; +import { PluginContext } from "@imgly/plugin-api-utils"; - - -export const registerLifecycleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - const block = cesdk.engine.block; - const commands = cesdk.engine.commands!; - - commands.registerCommand("imgly.block.lifecycle.delete", async (params: { blockIds?: number[]; }) => { - const blockIds = params.blockIds ?? block.findAllSelected(); +export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; blockIds.forEach((id: number) => { - block.isValid(id) && block.destroy(id) + ctx.engine.block.isValid(id) && ctx.engine.block.destroy(id) }); - }); +} - commands.registerCommand("imgly.block.lifecycle.duplicate", async (params: { blockIds?: number[]; }) => { - const blockIds = params.blockIds ?? block.findAllSelected(); +export const blockDuplicate = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; blockIds.forEach((id: number) => { - block.isValid(id); - const newBlock = block.duplicate(id); - const parent = block.getParent(id); - if (parent && block.isValid(parent)) { - block.appendChild(parent, newBlock); - } - block.setSelected(newBlock, true); - block.setSelected(id, false); + block.isValid(id); + const newBlock = block.duplicate(id); + const parent = block.getParent(id); + if (parent && block.isValid(parent)) { + block.appendChild(parent, newBlock); + } + block.setSelected(newBlock, true); // should return the previous state + block.setSelected(id, false); + }); - }); - commands.registerCommand("imgly.block.container.group", async (params: { blockIds?: number[]; }) => { - const blockIds = params.blockIds ?? block.findAllSelected(); - const group = block.group(blockIds); - block.setSelected(group, true); - }) +} - commands.registerCommand("imgly.block.container.ungroup", async (params: { blockIds?: number[]; }) => { - const blockIds = params.blockIds ?? block.findAllSelected(); - blockIds - .filter((id: number) => block.isValid(id) && block.getType(id) === "//ly.img.ubq/group") - .forEach((bId: number) => { - const groupChildIds = block.getChildren(bId); - block.ungroup(bId); // ungroup should return groupChildIds - groupChildIds.forEach((id: number) => block.setSelected(id, true)); - }) - - }) - - { - const combineOperations = ["Union", "Difference", "Intersection", "XOR"] - combineOperations.forEach((operation: string) => { - - commands.registerCommand(`imgly.block.combine.${operation.toLowerCase()}`, async (params: { blockIds?: number[]; }) => { - const blockIds = params.blockIds ?? block.findAllSelected(); - const newBlockId = block.combine(blockIds, operation as BooleanOperation); - block.setSelected(newBlockId, true); - }); - }) - } - -}; diff --git a/examples/web/src/plugins/imgly-commands/commands/old_debug.ts b/examples/web/src/plugins/imgly-commands/commands/old_debug.ts new file mode 100644 index 0000000..5b714ea --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/old_debug.ts @@ -0,0 +1,203 @@ +// import CreativeEditorSDK from "@cesdk/cesdk-js"; +// import { type CommandsType } from "@imgly/plugin-commands-polyfill"; +// import { readPropValue } from "../utils/cesdk"; + + + +// export const registerDebugCommands = (cesdk: CreativeEditorSDK & CommandsType) => { +// const { asset, block, variable, editor, scene } = cesdk.engine +// const commands = cesdk.engine.commands!; + +// commands.registerCommand("imgly.debug.log.metadata", async (params: { blockIds?: number[] }) => { +// const blockIds = params.blockIds ?? block.findAllSelected() + +// blockIds.forEach((id: number) => { +// const keys = block.findAllMetadata(id) +// if (keys.length === 0) { +// console.debug("No metadata found for block", id) +// return +// } +// keys.forEach((key: string) => { +// const metadata = block.getMetadata(id, key) +// const obj = JSON.parse(metadata) +// console.debug(key, obj) +// }) +// }) +// }) + +// commands.registerCommand("imgly.debug.clear.metadata", async (params: { blockIds?: number[] }) => { +// const blockIds = params.blockIds ?? block.findAllSelected() +// blockIds.forEach((id: number) => { +// block.findAllMetadata(id) +// .forEach((key: string) => { +// block.setMetadata(id, key, "") +// }) +// }) +// }) + +// commands.registerCommand("imgly.debug.log.block", async (params: { blockIds?: number[] }) => { +// const blockIds = params.blockIds ?? block.findAllSelected() + +// blockIds.forEach((id: number) => { +// const props = block.findAllProperties(id) +// const propDefinition = new Map() +// props.forEach((propKey: string) => { +// if (!block.isPropertyReadable(propKey)) return; +// const propType = block.getPropertyType(propKey) +// const propValue = readPropValue(cesdk, id, propKey, propType) +// propDefinition.set(propKey, { type: propType, value: propValue }) + +// }) + +// console.debug("Properties for block", id, propDefinition) +// }) +// }) + + + +// commands.registerCommand("imgly.debug.log.fill", async (params: { blockIds?: number[] }) => { +// const blockIds = params.blockIds ?? block.findAllSelected() +// blockIds.forEach((bId: number) => { +// const fId = block.getFill(bId) +// if (!block.isValid(fId)) { +// console.debug("No fill found for block", bId) +// return +// }; + +// const props = block.findAllProperties(fId) +// const propDefinition = new Map() +// props.forEach((propKey: string) => { +// console.debug("Reading propKey", propKey) +// if (!block.isPropertyReadable(propKey)) return; + +// const propType = block.getPropertyType(propKey) +// const propValue = readPropValue(cesdk, fId, propKey, propType) +// propDefinition.set(propKey, { type: propType, value: propValue }) + +// }) + +// console.debug("Fill properties for block", bId, propDefinition) +// }) +// }) + + + +// commands.registerCommand("imgly.debug.log.assets", async (_params: { blockIds?: number[] }) => { +// // const blockIds = params.blockIds ?? block.findAllSelected() + +// const entries = asset.findAllSources() +// const definition = new Map() +// entries.forEach((key: string) => { +// const types = asset.getSupportedMimeTypes(key) +// const groups = variable.getString(key) +// definition.set(key, { types, groups }) +// }) +// console.debug("Assets", definition) +// }) + + +// commands.registerCommand("imgly.debug.log.variables", async (_params: { blockIds?: number[] }) => { +// const vars = variable.findAll() +// const definition = new Map() +// vars.forEach((key: string) => { +// const value = variable.getString(key) + +// definition.set(key, { type: "String", value: value }) +// }) +// console.debug("Variables", definition) + +// }) + + +// commands.registerCommand("imgly.debug.log.editor.settings", async (_params: { blockIds?: number[] }) => { +// const entries = editor.findAllSettings() +// const definition = new Map() +// entries.forEach((key: string) => { +// const type = editor.getSettingType(key) +// const value = undefined; //editor.getSettingValue(key) +// definition.set(key, { type, value }) +// }) +// console.debug("Settings", definition) + +// }) + + + +// commands.registerCommand("imgly.debug.log.scene", async (_params: { blockIds?: number[] }) => { +// console.debug("Settings", { +// designUnit: scene.getDesignUnit(), +// mode: scene.getMode(), +// }) + +// }) + +// commands.registerCommand("imgly.debug.log.scopes", async (params: { blockIds?: number[] }) => { +// // https://img.ly/docs/cesdk/engine/guides/scopes/ +// const scopeNames = [ +// "layer/move", +// "layer/resize", +// "layer/rotate", +// "layer/crop", +// "layer/clipping", +// "layer/opacity", +// "layer/blendMode", +// "layer/visibility", +// "appearance/adjustments", +// "appearance/filter", +// "appearance/effect", +// "appearance/blur", +// "appearance/shadow", +// "lifecycle/destroy", // delete +// "lifecycle/duplicate", +// "editor/add", +// "editor/select", +// "fill/change", +// "stroke/change", +// "shape/change", +// "text/edit", +// // "text/change", // would be replace from library +// "text/character" +// ] +// const definition = new Map() +// scopeNames.forEach((scope: string) => { +// const value = editor.getGlobalScope(scope) +// definition.set(scope,{value}) +// }) +// console.debug("GlobalScopes", definition) + +// const blockIds = params.blockIds ?? block.findAllSelected() +// blockIds.forEach((id: number) => { +// const definition = new Map() +// scopeNames.forEach((scope: string) => { +// const value = block.isAllowedByScope(id, scope) +// definition.set(scope,{value}) +// }) +// console.debug("Scopes for block", id, definition) +// }) +// }) + + + + +// commands.registerCommand("imgly.debug.log.effects", async (params: { blockIds?: number[] }) => { +// const blockIds = params.blockIds ?? block.findAllSelected() +// blockIds.forEach((id: number) => { +// block.getEffects(id).forEach((eId: number) => { +// const props = block.findAllProperties(eId); +// let propDefinition = new Map() +// props.forEach((propKey: string) => { +// if (!block.isPropertyReadable(propKey)) return; +// const propType = block.getPropertyType(propKey) +// const propValue = readPropValue(cesdk, eId, propKey, propType) +// propDefinition.set(propKey, { type: propType, value: propValue }) + +// }) + +// console.debug("Effect for block", id, propDefinition) +// }) + +// }) + +// }) + +// } \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/syncStyle.ts b/examples/web/src/plugins/imgly-commands/commands/syncStyle.ts new file mode 100644 index 0000000..de8428b --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/commands/syncStyle.ts @@ -0,0 +1,123 @@ + +// // we can have much more here. What is good UX? +// // copy style to a global buffer +// // paste style from a global buffer + + + +// // all register should do an unregister, alternatively we can have lifetime + +// // This is a simple example of a command that syncs the rotation of multiple blocks +// // We would need to store the blocks that need syncing and add a dedicated sync-system / handler. That on every frame or change syncs these blocks with the same value + + +// import CreativeEditorSDK, { type BlockEvent } from "@cesdk/cesdk-js"; +// import { CommandArgs, type CommandsType } from "@imgly/plugin-commands-polyfill"; + +// import { readPropValue, writePropValue } from "../utils/cesdk"; + +// export const registerSyncStyleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { + +// const { block, event } = cesdk.engine +// const commands = cesdk.engine.commands! + + + +// const handleSyncProperties = (context: CommandArgs, properties: string[]) => { +// let { blockIds = block.findAllSelected() } = context +// if (blockIds.length <= 1) return; + +// const unsubscribe = event.subscribe(blockIds, (events: BlockEvent[]) => { +// events.forEach((event: BlockEvent) => { +// const bId = event.block; +// switch (event.type) { +// case 'Created': { +// throw new Error("Not implemented") +// break; +// } +// case 'Updated': { +// syncProperties(properties, bId, blockIds) +// break; +// } +// case "Destroyed": { +// if (blockIds.includes(bId)) { +// blockIds.splice(blockIds.indexOf(bId), 1) +// } +// if (blockIds.length === 1) { +// unsubscribe() +// } +// break; +// } +// } +// }) +// }) + + +// const syncProperties = (propertyKeys: string[], sourceId: number, destIds: number[]) => { +// if (!block.isValid(sourceId)) return + +// propertyKeys.forEach((propertyKey: string) => { +// const sourceValue = readPropValue(cesdk, sourceId, propertyKey) +// destIds.forEach((receiverBlockId: number) => { +// if (!block.isValid(receiverBlockId)) return +// if (sourceId === receiverBlockId) return; +// const receiverValue = readPropValue(cesdk, receiverBlockId, propertyKey) +// if (receiverValue === sourceValue) return; +// writePropValue(cesdk, receiverBlockId, propertyKey, sourceValue) +// }) +// }) +// } + +// commands.registerCommand(`imgly.sync.stroke`, async (context) => { +// await handleSyncProperties(context, [ +// "stroke/enabled", +// "stroke/color", +// "stroke/style", +// "stroke/width", +// "stroke/position" +// ]) +// }) + +// commands.registerCommand(`imgly.sync.shadow`, async (context) => { +// await handleSyncProperties(context, [ + +// "dropShadow/enabled", +// "dropShadow/color", +// "dropShadow/clip", +// "dropShadow/offset/x", +// "dropShadow/offset/y", +// ]) +// }) + +// commands.registerCommand(`imgly.sync.rotation`, async (context) => { +// await handleSyncProperties(context, [ +// "rotation" +// ]) +// }) + +// commands.registerCommand(`imgly.sync.width+height`, async (context) => { +// await handleSyncProperties(context, [ +// "width", +// "height" +// ]) +// }) + + +// // commands.registerCommand(`imgly.sync.effects`, async (context) => { +// // const { blockIds = block.findAllSelected() } = context + +// // blockIds.forEach((bId: number) => { +// // const eIds = block.getEffects(bId) +// // if (eIds.length === 0) return; + +// // }) +// // }) + +// // // we could life registe commands and also unregister based on the possibilites + +// return [] +// } +// } +// // we can make sync alive + + diff --git a/examples/web/src/plugins/imgly-commands/commands/turn_into.ts b/examples/web/src/plugins/imgly-commands/commands/turn_into.ts deleted file mode 100644 index e69de29..0000000 diff --git a/examples/web/src/plugins/imgly-commands/index.ts b/examples/web/src/plugins/imgly-commands/index.ts index 7f06879..6e68e08 100644 --- a/examples/web/src/plugins/imgly-commands/index.ts +++ b/examples/web/src/plugins/imgly-commands/index.ts @@ -1,49 +1,36 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -import Translations from './translations/translations'; - -import { type CommandsType } from "@imgly/plugin-commands-polyfill" - - -// IMGLY Commands -import { registerLifecycleCommands } from "./commands/lifecycle"; -import { registerDebugCommands } from "./commands/debug"; -import { registerDownloadCommands } from "./commands/export"; -import { registerClipboardCommands } from "./commands/clipboard"; - - -const Manifest = { - id: 'plugin.imgly/plugin-commands-polyfill', - publisher: 'img.ly GmbH', - contributes: { - commands: { - "lifecycle.destroy": { - title: "Destroy" - }, - "lifecycle.duplicate": { - title: "Duplicate" - } - }, - i18n: Translations - } -}; +import en from './locale/en.json'; +import { PluginContext } from '@imgly/plugin-api-utils'; + + +import { CommandImports, CommandContributions, PluginManifest } from './PluginManifest'; -export interface PluginConfiguration { - // uploader ? +export interface PluginConfiguration { } + +function registerTranslation(ctx: PluginContext, translations: { [key: string]: any } = {}) { + ctx.i18n.setTranslations(translations) +} +function registerCommands(ctx: PluginContext, imports: CommandImports) { + for (const command in imports) { + const callback = imports[command as CommandContributions] + const desc = PluginManifest.contributes.commands[command as CommandContributions]; + ctx.commands.registerCommand( + desc.id, + async (params: any) => await callback(ctx, params), + desc + ); + } } -export { Manifest }; +import * as commands from './commands' -export default () => { +export default (ctx: PluginContext, _config: PluginConfiguration) => { return { - ...Manifest, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - const _cesdk = cesdk as CreativeEditorSDK & CommandsType - cesdk.setTranslations(Translations); - registerLifecycleCommands(_cesdk) - registerDebugCommands(_cesdk) - registerDownloadCommands(_cesdk) - registerClipboardCommands(_cesdk) + async initializeUserInterface() { + //we should give manifest to the context + registerTranslation(ctx, { en }) + registerCommands(ctx, commands) + } }; }; diff --git a/examples/web/src/plugins/imgly-commands/translations/translations.ts b/examples/web/src/plugins/imgly-commands/locale/en.json similarity index 66% rename from examples/web/src/plugins/imgly-commands/translations/translations.ts rename to examples/web/src/plugins/imgly-commands/locale/en.json index b180d11..2e970c0 100644 --- a/examples/web/src/plugins/imgly-commands/translations/translations.ts +++ b/examples/web/src/plugins/imgly-commands/locale/en.json @@ -1,7 +1,19 @@ +{ + "plugin.commands.blockDelete": "Delete Block", + "plugin.commands.blockDuplicate": "Duplicate Block", + "plugin.commands.exportPngToClipboard": "Export PNG to Clipboard", + "plugin.commands.exportPngToFile": "Export PNG to File", + "plugin.commands.exportJpegToFile": "Export JPEG to File", + "plugin.commands.exportWebpToFile": "Export WEP to File", + "plugin.commands.exportPdfToFile": "Export PDF to File", + + "plugin.commands.exportSceneToClipboard": "Export Scene to Clipboard", + "plugin.commands.exportJSONToClipboard": "Export JSON to Clipboard", + + "plugin.commands.imageFitModeContain": "Set Image FitMode to Contain", + "plugin.commands.imageFitModeCrop": "Set Image FitMode to Crop", + "plugin.commands.imageFitModeCover": "Set Image FitMode to Cover", -const en = { - "imgly.block.lifecycle.delete": "Block: Delete", - "imgly.block.lifecycle.duplicate": "Block: Duplicate", "imgly.block.download.selected.as.png": "Block: Download selected as PNG", "imgly.block.download.selected.as.jpeg": "Block: Download selected as JPEG", "imgly.block.download.selected.as.webp": "Block: Download selected as WEBP", @@ -13,10 +25,7 @@ const en = { "imgly.block.clipboard.selected.as.png": "Block: Copy selected as PNG to Clipboard", "imgly.block.clipboard.selected.as.scene": "Block: Copy selected as Scene to Clipboard", "imgly.block.clipboard.selected.as.json": "Block: Copy selected as JSON to Clipboard", - // - "imgly.debug.clear.metadata": "Debug: Clear Metadata", - "imgly.debug.log.metadata": "Debug: Log Metadata", "imgly.debug.log.block": "Debug: Log Block", "imgly.debug.log.fill": "Debug: Log Fill", @@ -25,17 +34,10 @@ const en = { "imgly.debug.log.assets": "Debug: Log Assets", "imgly.debug.log.variables": "Debug: Log Variables", "imgly.debug.log.editor.settings": "Debug: Log Editor Settings", - "imgly.block.container.group": "Container: Group", "imgly.block.container.ungroup": "Container: Ungroup", "imgly.block.combine.union": "Combine: Union", "imgly.block.combine.difference": "Combine: Subtract", "imgly.block.combine.intersection": "Combine: Intersect", - "imgly.block.combine.xor": "Combine: Exclude", - - -} - -export default { - en -} + "imgly.block.combine.xor": "Combine: Exclude" +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/manifest.json b/examples/web/src/plugins/imgly-commands/manifest.json new file mode 100644 index 0000000..689ae6b --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/manifest.json @@ -0,0 +1,80 @@ +{ + "id": "plugin", + "version": "1.0.0", + "publisher": "IMG.LY GmbH", + "icon": null, + "categories": [], + "contributes": { + "commands": { + "blockDelete": { + "id": "plugin.commands.blockDelete", + "group": "lifecycle" + }, + "blockDuplicate": { + "id": "plugin.commands.blockDuplicate", + "group": "lifecycle" + }, + "exportPngToClipboard": { + "id": "plugin.commands.exportPngToClipboard", + "group": "export" + }, + "exportPngToFile": { + "id": "plugin.commands.exportPngToFile", + "group": "export" + }, + "exportJpegToFile": { + "id": "plugin.commands.exportJpegToFile", + "group": "export" + }, + "exportWebpToFile": { + "id": "plugin.commands.exportWebpToFile", + "group": "export" + }, + "exportRgba8ToFile": { + "id": "plugin.commands.exportRgba8ToFile", + "group": "export" + }, + "exportPdfToFile": { + "id": "plugin.commands.exportPdfToFile", + "group": "export" + }, + "exportSceneToClipboard": { + "id": "plugin.commands.exportSceneToClipboard", + "group": "export" + }, + "exportJSONToClipboard": { + "id": "plugin.commands.exportJSONToClipboard", + "group": "export" + }, + "imageFitModeCrop": { + "id": "plugin.commands.imageFitModeCrop", + "group": "image" + }, + "imageFitModeContain": { + "id": "plugin.commands.imageFitModeContain", + "group": "image" + }, + "imageFitModeCover": { + "id": "plugin.commands.imageFitModeCover", + "group": "image" + }, + "groupBlocks": { + "id": "plugin.commands.groupBlock", + "group": "group" + }, + "ungroupBlocks": { + "id": "plugin.commands.ungroupBlock", + "group": "group" + }, + "groupLayoutHStack": { + "id": "plugin.commands.groupLayoutHStack", + "group": "group" + }, + "groupLayoutVStack": { + "id": "plugin.commands.groupLayoutVStack", + "group": "group" + } + }, + "i18n": {} + } +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/types/types.ts b/examples/web/src/plugins/imgly-commands/types/types.ts new file mode 100644 index 0000000..a2020d3 --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/types/types.ts @@ -0,0 +1,5 @@ +export type Unsubscribe = () => void; + +export type CommandArg = { + blockIds: number[] | undefined; +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/utils/cesdk.ts b/examples/web/src/plugins/imgly-commands/utils/cesdk.ts new file mode 100644 index 0000000..d2616be --- /dev/null +++ b/examples/web/src/plugins/imgly-commands/utils/cesdk.ts @@ -0,0 +1,39 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; + + +export const readPropValue = (cesdk: CreativeEditorSDK, id: number, propKey: string, propType?: string) => { + const blacklist= ["fill/solid/color"] + if (blacklist.includes(propKey)) return undefined; + if (!propType) propType = cesdk.engine.block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return cesdk.engine.block.getString(id, propKey); + case "float": return cesdk.engine.block.getFloat(id, propKey); + case "double": return cesdk.engine.block.getDouble(id, propKey); + case "color": return cesdk.engine.block.getColor(id, propKey); + case "bool": return cesdk.engine.block.getBool(id, propKey); + case "enum": return cesdk.engine.block.getEnum(id, propKey); + } + } catch(e){ + console.warn("Error reading property value: ", e); + } + return undefined; +}; + + +export const writePropValue = (cesdk: CreativeEditorSDK, id: number, propKey: string, propValue: any,propType?: string) => { + if (!propType) propType = cesdk.engine.block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return cesdk.engine.block.setString(id, propKey, propValue); + case "float": return cesdk.engine.block.setFloat(id, propKey, propValue); + case "double": return cesdk.engine.block.setDouble(id, propKey, propValue); + case "color": return cesdk.engine.block.setColor(id, propKey, propValue); + case "bool": return cesdk.engine.block.setBool(id, propKey, propValue); + case "enum": return cesdk.engine.block.setEnum(id, propKey, propValue); + } + } catch(e){ + console.warn("Error writing property: ", propKey, propType, propValue); + } + return undefined; +}; diff --git a/examples/web/src/utils/i18n.ts b/examples/web/src/utils/i18n.ts deleted file mode 100644 index 1b2e9e0..0000000 --- a/examples/web/src/utils/i18n.ts +++ /dev/null @@ -1,27 +0,0 @@ -// // we could polyfill them -// import { merge } from 'lodash'; -// import { flatten } from './flatten'; - -// export class I18N { -// #translations: any = {}; -// #locale: string = 'en'; - -// setTranslations(translations: any) { -// const flattenedTranslations = flatten(translations); -// this.#translations = merge(this.#translations, flattenedTranslations); -// } - -// translate(key: string, fallback: string | undefined = undefined) { -// const lookup = this.#locale.concat('.', key); -// return this.#translations[lookup] ?? fallback ?? key; -// } -// t = this.translate.bind(this) -// } - -// const i18n = new I18N(); - -// export default i18n; - - - - diff --git a/examples/web/tsconfig.json b/examples/web/tsconfig.json index a7fc6fb..18c8610 100644 --- a/examples/web/tsconfig.json +++ b/examples/web/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src"], + "include": ["src", "../imgly-components-source"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/package.json b/package.json index 4d99540..c62622b 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,7 @@ "version": "0.0.0", "workspaces": [ "examples/web", - "packages/i18n-polyfill", - "packages/commands-polyfill", + "packages/api-utils", "packages/background-removal", "packages/vectorizer" diff --git a/packages/commands-polyfill/LICENSE.md b/packages/api-utils/LICENSE.md similarity index 100% rename from packages/commands-polyfill/LICENSE.md rename to packages/api-utils/LICENSE.md diff --git a/packages/commands-polyfill/README.md b/packages/api-utils/README.md similarity index 100% rename from packages/commands-polyfill/README.md rename to packages/api-utils/README.md diff --git a/packages/commands-polyfill/STRUCTURE.md b/packages/api-utils/STRUCTURE.md similarity index 100% rename from packages/commands-polyfill/STRUCTURE.md rename to packages/api-utils/STRUCTURE.md diff --git a/packages/commands-polyfill/TODO.md b/packages/api-utils/TODO.md similarity index 100% rename from packages/commands-polyfill/TODO.md rename to packages/api-utils/TODO.md diff --git a/packages/commands-polyfill/esbuild/config.mjs b/packages/api-utils/esbuild/config.mjs similarity index 100% rename from packages/commands-polyfill/esbuild/config.mjs rename to packages/api-utils/esbuild/config.mjs diff --git a/packages/commands-polyfill/esbuild/global.d.ts b/packages/api-utils/esbuild/global.d.ts similarity index 100% rename from packages/commands-polyfill/esbuild/global.d.ts rename to packages/api-utils/esbuild/global.d.ts diff --git a/packages/api-utils/manifest.json b/packages/api-utils/manifest.json new file mode 100644 index 0000000..a218d68 --- /dev/null +++ b/packages/api-utils/manifest.json @@ -0,0 +1,11 @@ +{ + "id": "pluginapi-polyfill", + "version": "0.0.1", + "publisher": "IMG.LY GmbH", + "icon": null, + "license": "MIT", + "categories": [ + "polyfill" + ], + "contributes": {} +} \ No newline at end of file diff --git a/packages/i18n-polyfill/package.json b/packages/api-utils/package.json similarity index 94% rename from packages/i18n-polyfill/package.json rename to packages/api-utils/package.json index c1e2a6d..8876a3f 100644 --- a/packages/i18n-polyfill/package.json +++ b/packages/api-utils/package.json @@ -1,7 +1,7 @@ { - "name": "@imgly/plugin-i18n-polyfill", + "name": "@imgly/plugin-api-utils", "version": "0.1.0", - "description": "Polyfill for I18N plugin for the CE.SDK editor", + "description": "Polyfill for API plugin for the CE.SDK editor", "keywords": [ "CE.SDK", "plugin", diff --git a/packages/commands-polyfill/scripts/build.mjs b/packages/api-utils/scripts/build.mjs similarity index 100% rename from packages/commands-polyfill/scripts/build.mjs rename to packages/api-utils/scripts/build.mjs diff --git a/packages/commands-polyfill/scripts/watch.mjs b/packages/api-utils/scripts/watch.mjs similarity index 100% rename from packages/commands-polyfill/scripts/watch.mjs rename to packages/api-utils/scripts/watch.mjs diff --git a/packages/api-utils/src/index.ts b/packages/api-utils/src/index.ts new file mode 100644 index 0000000..10fa530 --- /dev/null +++ b/packages/api-utils/src/index.ts @@ -0,0 +1,7 @@ +import { PluginContext } from "./plugin/PluginContext" + +export { Commands, type CommandCallback } from "./plugin/Commands" +export { I18N } from "./plugin/I18n" +export { type Logger } from "./plugin/Logger" +export { PluginContext } from "./plugin/PluginContext" + diff --git a/packages/api-utils/src/plugin/Commands.ts b/packages/api-utils/src/plugin/Commands.ts new file mode 100644 index 0000000..8beb690 --- /dev/null +++ b/packages/api-utils/src/plugin/Commands.ts @@ -0,0 +1,61 @@ +import { PluginContext } from './PluginContext'; +import { Subscribable } from './Subscribable'; + +export type CommandCallback = (ctx: PluginContext, params: any) => Promise | any; +export type CommandArgs = { blockIds?: number[]} + +export type CommandEvents = "register"| "unregister" + +export type CommandDescription = { + group?: string + args?: any, //JSONSchema + returns?: any // JSONSchema +} + +export class Commands extends Subscribable{ + #entries = new Map() + #descs = new Map() + #ctx: PluginContext; + + constructor(ctx: PluginContext) { + super() + this.#ctx = ctx + } + + listCommands() { + return Array.from(this.#entries.keys()); + } + + registerCommand(label: string, callback: CommandCallback, description: CommandDescription) { + this.#entries.set(label, callback); + this.#descs.set(label, description || {}); + this.notify("register", label) + return () => this.unregisterCommand(label) + } + + unregisterCommand(label: string) { + this.notify("unregister", label) + this.#entries.delete(label); + this.#descs.delete(label); + } + + getCommandCallback(label: string) { + return this.#entries.get(label); + } + getCommandDescription(label: string) { + return this.#descs.get(label); + } + + + async executeCommand

(cmd: string, params: P): Promise { + const command = this.#entries.get(cmd); + if (command) { + return await command(this.#ctx, params); + } else { + throw new Error(`Command ${cmd} not found`); + } + } +} + + + diff --git a/packages/api-utils/src/plugin/I18n.ts b/packages/api-utils/src/plugin/I18n.ts new file mode 100644 index 0000000..41f68a6 --- /dev/null +++ b/packages/api-utils/src/plugin/I18n.ts @@ -0,0 +1,43 @@ +import { PluginContext } from './PluginContext'; +import { Subscribable } from './Subscribable'; + + +import { merge } from 'lodash'; +import { flatten } from '../utils/flatten'; + +type Translation = Record +type Translations = { [locale: string]: Translation; } + +export class I18N extends Subscribable<"register", Translations> { + #translations: any = {}; + #locale: string = 'en'; + #ctx: PluginContext + + + constructor(ctx: PluginContext) { + super() + this.#ctx = ctx + } + + setTranslations(translations: Translations) { + this.#translations = merge(this.#translations, flatten(translations)); + this.notify("register", translations) + } + + translate(key: K, fallback: string | undefined = undefined) { + const lookup = this.#locale.concat('.', key as string); + const translation = this.#translations[lookup] + if (!translation) { + this.#ctx.logger?.warn(`Translation for key ${lookup} not found!`); + } + return translation ?? fallback ?? key; + } + + setLocale(locale: string) { + this.#locale = locale; + } + t = this.translate.bind(this) +} + + +export type I18NType = { i18n?: I18N } diff --git a/packages/api-utils/src/plugin/Logger.ts b/packages/api-utils/src/plugin/Logger.ts new file mode 100644 index 0000000..a0ee497 --- /dev/null +++ b/packages/api-utils/src/plugin/Logger.ts @@ -0,0 +1,8 @@ +export interface Logger { + log: (message: string) => void , + trace: (message: string) => void + debug: (message: string) => void, + warn: (message: string) => void, + error: (message: string) => void, + + } \ No newline at end of file diff --git a/packages/api-utils/src/plugin/PluginContext.ts b/packages/api-utils/src/plugin/PluginContext.ts new file mode 100644 index 0000000..f8230c2 --- /dev/null +++ b/packages/api-utils/src/plugin/PluginContext.ts @@ -0,0 +1,45 @@ +import { type CreativeEngine } from "@cesdk/cesdk-js"; +import CreativeEditorSDK from "@cesdk/cesdk-js"; +import { Logger } from "./Logger"; + +import { Commands } from "./Commands"; +import { I18N } from "./I18n"; + +// this is not exposed yet +type UserInterfaceAPI = typeof CreativeEditorSDK.prototype.ui; +type FeatureAPI = typeof CreativeEditorSDK.prototype.feature; + + + +type I18NContributions = { + [key: string]: string +} +type ManifestContributions = { + i18n?: I18NContributions +} +type Manifest = { + contributes: ManifestContributions +} + + +export class PluginContext { + logger?: Logger; + engine: CreativeEngine; + ui?: UserInterfaceAPI; + i18n: I18N; + commands: Commands; + feature: FeatureAPI; + constructor(cesdk: CreativeEditorSDK) { + this.engine = cesdk.engine; + this.ui = cesdk.ui; + this.i18n = new I18N(this as PluginContext) + this.commands = new Commands(this as PluginContext) + this.feature = cesdk.feature; + const _unsubscribe = this.i18n.subscribe("register", (translations) => { + cesdk.setTranslations(translations); + } ) + + } + +}; + diff --git a/packages/api-utils/src/plugin/Subscribable.ts b/packages/api-utils/src/plugin/Subscribable.ts new file mode 100644 index 0000000..cab0333 --- /dev/null +++ b/packages/api-utils/src/plugin/Subscribable.ts @@ -0,0 +1,24 @@ + +export class Subscribable { + #subscribers: Array<{ filter: E[], callback: (event: D) => void }> = [] + + subscribe(toEvent: E, callback: (label: D) => void): () => void { + const entry = { filter: [toEvent], callback } + this.#subscribers.push(entry); + return () => { + const idx = this.#subscribers.indexOf(entry); + if (idx > -1) { + this.#subscribers.splice(idx, 1); + } + } + } + + notify(event: E, data: D) { + this.#subscribers.forEach(({ filter, callback }) => { + if (filter.includes(event)) { + callback(data); + } + }) + } + +} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/utils/flatten.ts b/packages/api-utils/src/utils/flatten.ts similarity index 100% rename from packages/i18n-polyfill/src/utils/flatten.ts rename to packages/api-utils/src/utils/flatten.ts diff --git a/packages/commands-polyfill/src/worker.ts b/packages/api-utils/src/worker.ts similarity index 100% rename from packages/commands-polyfill/src/worker.ts rename to packages/api-utils/src/worker.ts diff --git a/packages/commands-polyfill/tsconfig.json b/packages/api-utils/tsconfig.json similarity index 92% rename from packages/commands-polyfill/tsconfig.json rename to packages/api-utils/tsconfig.json index 47d465c..07e826a 100644 --- a/packages/commands-polyfill/tsconfig.json +++ b/packages/api-utils/tsconfig.json @@ -5,6 +5,7 @@ "module": "es2020", "lib": ["es2018", "dom"], "moduleResolution": "node", + "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "declaration": true, diff --git a/packages/api-utils/types/index.d.ts b/packages/api-utils/types/index.d.ts new file mode 100644 index 0000000..e0c29e5 --- /dev/null +++ b/packages/api-utils/types/index.d.ts @@ -0,0 +1,4 @@ +export { Commands, type CommandCallback } from "./plugin/Commands"; +export { I18N } from "./plugin/I18n"; +export { type Logger } from "./plugin/Logger"; +export { PluginContext } from "./plugin/PluginContext"; diff --git a/packages/commands-polyfill/types/manifest.d.ts b/packages/api-utils/types/manifest.d.ts similarity index 100% rename from packages/commands-polyfill/types/manifest.d.ts rename to packages/api-utils/types/manifest.d.ts diff --git a/packages/api-utils/types/plugin/Commands.d.ts b/packages/api-utils/types/plugin/Commands.d.ts new file mode 100644 index 0000000..b14c564 --- /dev/null +++ b/packages/api-utils/types/plugin/Commands.d.ts @@ -0,0 +1,22 @@ +import { PluginContext } from './PluginContext'; +import { Subscribable } from './Subscribable'; +export type CommandCallback = (ctx: PluginContext, params: any) => Promise | any; +export type CommandArgs = { + blockIds?: number[]; +}; +export type CommandEvents = "register" | "unregister"; +export type CommandDescription = { + group?: string; + args?: any; + returns?: any; +}; +export declare class Commands extends Subscribable { + #private; + constructor(ctx: PluginContext); + listCommands(): string[]; + registerCommand(label: string, callback: CommandCallback, description: CommandDescription): () => void; + unregisterCommand(label: string): void; + getCommandCallback(label: string): CommandCallback | undefined; + getCommandDescription(label: string): CommandDescription | undefined; + executeCommand

(cmd: string, params: P): Promise; +} diff --git a/packages/api-utils/types/plugin/I18n.d.ts b/packages/api-utils/types/plugin/I18n.d.ts new file mode 100644 index 0000000..953a92c --- /dev/null +++ b/packages/api-utils/types/plugin/I18n.d.ts @@ -0,0 +1,18 @@ +import { PluginContext } from './PluginContext'; +import { Subscribable } from './Subscribable'; +type Translation = Record; +type Translations = { + [locale: string]: Translation; +}; +export declare class I18N extends Subscribable<"register", Translations> { + #private; + constructor(ctx: PluginContext); + setTranslations(translations: Translations): void; + translate(key: K, fallback?: string | undefined): any; + setLocale(locale: string): void; + t: (key: K, fallback?: string | undefined) => any; +} +export type I18NType = { + i18n?: I18N; +}; +export {}; diff --git a/packages/api-utils/types/plugin/Logger.d.ts b/packages/api-utils/types/plugin/Logger.d.ts new file mode 100644 index 0000000..27fc49a --- /dev/null +++ b/packages/api-utils/types/plugin/Logger.d.ts @@ -0,0 +1,7 @@ +export interface Logger { + log: (message: string) => void; + trace: (message: string) => void; + debug: (message: string) => void; + warn: (message: string) => void; + error: (message: string) => void; +} diff --git a/packages/api-utils/types/plugin/PluginContext.d.ts b/packages/api-utils/types/plugin/PluginContext.d.ts new file mode 100644 index 0000000..5ea39f2 --- /dev/null +++ b/packages/api-utils/types/plugin/PluginContext.d.ts @@ -0,0 +1,17 @@ +import { type CreativeEngine } from "@cesdk/cesdk-js"; +import CreativeEditorSDK from "@cesdk/cesdk-js"; +import { Logger } from "./Logger"; +import { Commands } from "./Commands"; +import { I18N } from "./I18n"; +type UserInterfaceAPI = typeof CreativeEditorSDK.prototype.ui; +type FeatureAPI = typeof CreativeEditorSDK.prototype.feature; +export declare class PluginContext { + logger?: Logger; + engine: CreativeEngine; + ui?: UserInterfaceAPI; + i18n: I18N; + commands: Commands; + feature: FeatureAPI; + constructor(cesdk: CreativeEditorSDK); +} +export {}; diff --git a/packages/api-utils/types/plugin/Subscribable.d.ts b/packages/api-utils/types/plugin/Subscribable.d.ts new file mode 100644 index 0000000..12aefba --- /dev/null +++ b/packages/api-utils/types/plugin/Subscribable.d.ts @@ -0,0 +1,5 @@ +export declare class Subscribable { + #private; + subscribe(toEvent: E, callback: (label: D) => void): () => void; + notify(event: E, data: D): void; +} diff --git a/packages/i18n-polyfill/types/utils/flatten.d.ts b/packages/api-utils/types/utils/flatten.d.ts similarity index 100% rename from packages/i18n-polyfill/types/utils/flatten.d.ts rename to packages/api-utils/types/utils/flatten.d.ts diff --git a/packages/commands-polyfill/types/worker.d.ts b/packages/api-utils/types/worker.d.ts similarity index 100% rename from packages/commands-polyfill/types/worker.d.ts rename to packages/api-utils/types/worker.d.ts diff --git a/packages/commands-polyfill/package.json b/packages/commands-polyfill/package.json deleted file mode 100644 index 904311c..0000000 --- a/packages/commands-polyfill/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@imgly/plugin-commands-polyfill", - "version": "0.1.0", - "description": "Polyfill for Commands plugin for the CE.SDK editor", - "keywords": [ - "CE.SDK", - "plugin", - "polyfill" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/imgly/plugins.git" - }, - "license": "SEE LICENSE IN LICENSE.md", - "author": { - "name": "IMG.LY GmbH", - "email": "support@img.ly", - "url": "https://img.ly" - }, - "bugs": { - "email": "support@img.ly" - }, - "source": "./src/index.ts", - "module": "./dist/index.mjs", - "types": "./types/index.d.ts", - "exports": { - ".": { - "import": "./dist/index.mjs", - "types": "./types/index.d.ts" - } - }, - "homepage": "https://img.ly", - "files": [ - "LICENSE.md", - "README.md", - "CHANGELOG.md", - "dist/", - "types/", - "bin/" - ], - "scripts": { - "start": "npm run watch", - "clean": "npx rimraf dist && npx rimraf types", - "build": "yarn run types:create && node scripts/build.mjs", - "dev": "yarn run types:create && node scripts/watch.mjs", - "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", - "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", - "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", - "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", - "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", - "check:type": "tsc --noEmit", - "types:create": "tsc --emitDeclarationOnly" - }, - "devDependencies": { - "chalk": "^5.3.0", - "concurrently": "^8.2.2", - "esbuild": "^0.19.11", - "eslint": "^8.51.0", - "typescript": "^5.3.3" - }, - "peerDependencies": { - "@cesdk/cesdk-js": "~1.20.0" - }, - "dependencies": { - } -} diff --git a/packages/commands-polyfill/src/index.ts b/packages/commands-polyfill/src/index.ts deleted file mode 100644 index dddbe7e..0000000 --- a/packages/commands-polyfill/src/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; - -import Manifest from './manifest'; - - -export interface PluginConfiguration { - // uploader ? -} - -export { Manifest }; - -export default () => { - return { - ...Manifest, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - polyfillWithCommands(cesdk); - } - }; -}; -export type CommandsType = { engine: CreativeEngine & { commands?: Commands } } - -export type CommandType = (params: any) => Promise; - -export class Commands { - #entries = new Map() - - listCommands() { - return Array.from(this.#entries.keys()); - } - registerCommand(label: string, callback: (params: any) => Promise) { - this.#entries.set(label, callback); - } - - async executeCommand(label: string, params: any) { - const command = this.#entries.get(label); - if (command) { - await command(params); - } else { - throw new Error(`Command ${label} not found`); - } - } - -} -export function polyfillWithCommands(sdk: CreativeEditorSDK) { - // @ts-ignore - if (!sdk.engine.commands) { - // @ts-ignore - sdk.engine.commands = new Commands(); - } -} \ No newline at end of file diff --git a/packages/commands-polyfill/src/manifest.ts b/packages/commands-polyfill/src/manifest.ts deleted file mode 100644 index 0972d63..0000000 --- a/packages/commands-polyfill/src/manifest.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default { - id: "@imgly/polyfill-commands", - -} \ No newline at end of file diff --git a/packages/commands-polyfill/types/index.d.ts b/packages/commands-polyfill/types/index.d.ts deleted file mode 100644 index f0f714a..0000000 --- a/packages/commands-polyfill/types/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -import Manifest from './manifest'; -export interface PluginConfiguration { -} -export { Manifest }; -declare const _default: () => { - initializeUserInterface({ cesdk }: { - cesdk: CreativeEditorSDK; - }): void; - id: string; -}; -export default _default; -export type CommandsType = { - engine: CreativeEngine & { - commands?: Commands; - }; -}; -export type CommandType = (params: any) => Promise; -export declare class Commands { - #private; - listCommands(): string[]; - registerCommand(label: string, callback: (params: any) => Promise): void; - executeCommand(label: string, params: any): Promise; -} -export declare function polyfillWithCommands(sdk: CreativeEditorSDK): void; diff --git a/packages/i18n-polyfill/LICENSE.md b/packages/i18n-polyfill/LICENSE.md deleted file mode 100644 index a099036..0000000 --- a/packages/i18n-polyfill/LICENSE.md +++ /dev/null @@ -1 +0,0 @@ -TBD diff --git a/packages/i18n-polyfill/README.md b/packages/i18n-polyfill/README.md deleted file mode 100644 index e4197b5..0000000 --- a/packages/i18n-polyfill/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# IMG.LY CE.SDK Plugin Vectorizer - -This plugin introduces a vectorizer for the CE.SDK editor. - -## Installation - -You can install the plugin via npm or yarn. Use the following commands to install the package: - -``` -yarn add @imgly/plugin-vectorizer-web -npm install @imgly/plugin-vectorizer-web -``` - -## Usage - -Adding the plugin to CE.SDK will automatically add a vectorizer -canvas menu entry for every block with an image fill. - -```typescript -import CreativeEditorSDK from '@cesdk/cesdk-js'; -import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; - -const config = { - license: '', - callbacks: { - // Please note that the vectorizer plugin depends on an correctly - // configured upload. 'local' will work for local testing, but in - // production you will need something stable. Please take a look at: - // https://img.ly/docs/cesdk/ui/guides/upload-images/ - onUpload: 'local' - } -}; - -const cesdk = await CreativeEditorSDK.create(container, config); -await cesdk.addDefaultAssetSources(), - await cesdk.addDemoAssetSources({ sceneMode: 'Design' }), - await cesdk.unstable_addPlugin(VectorizerPlugin()); - -await cesdk.createDesignScene(); -``` diff --git a/packages/i18n-polyfill/STRUCTURE.md b/packages/i18n-polyfill/STRUCTURE.md deleted file mode 100644 index 13b1472..0000000 --- a/packages/i18n-polyfill/STRUCTURE.md +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/i18n-polyfill/TODO.md b/packages/i18n-polyfill/TODO.md deleted file mode 100644 index e69de29..0000000 diff --git a/packages/i18n-polyfill/esbuild/config.mjs b/packages/i18n-polyfill/esbuild/config.mjs deleted file mode 100644 index 37b437c..0000000 --- a/packages/i18n-polyfill/esbuild/config.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import chalk from 'chalk'; -import { readFile } from 'fs/promises'; - -// import packageJson from '../package.json' assert { type: 'json' }; -// Avoid the Experimental Feature warning when using the above. -const packageJson = JSON.parse( - await readFile(new URL('../package.json', import.meta.url)) -); - - -const dependencies = Object.keys(packageJson.dependencies) -const peerDependencies = Object.keys(packageJson.peerDependencies) -const externals = [...dependencies, ...peerDependencies] - -console.log( - chalk.yellow('Building version: '), - chalk.green(packageJson.version) -); - -const configs = [ - { - entryPoints: ['src/index.ts', "src/worker.ts"], - define: { - PLUGIN_VERSION: `"${packageJson.version}"` - }, - minify: true, - bundle: true, - sourcemap: true, - external: externals, - platform: 'node', - format: 'esm', - outdir: 'dist', - outExtension: { '.js': '.mjs' }, - plugins: [ - { - name: 'reporter', - setup(build) { - build.onEnd((result) => { - console.log( - `[${new Date().toLocaleTimeString(undefined, { - hour: 'numeric', - minute: '2-digit', - second: '2-digit', - hour12: false - })}] Build ${ - result.errors.length - ? chalk.red('failed') - : chalk.green('succeeded') - }` - ); - }); - } - } - ] - } -]; - -export default configs; diff --git a/packages/i18n-polyfill/esbuild/global.d.ts b/packages/i18n-polyfill/esbuild/global.d.ts deleted file mode 100644 index de80fd8..0000000 --- a/packages/i18n-polyfill/esbuild/global.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -// These constants here are added by the base esbuild config - -declare const PLUGIN_VERSION: string; diff --git a/packages/i18n-polyfill/scripts/build.mjs b/packages/i18n-polyfill/scripts/build.mjs deleted file mode 100644 index 13d12e1..0000000 --- a/packages/i18n-polyfill/scripts/build.mjs +++ /dev/null @@ -1,5 +0,0 @@ -import * as esbuild from 'esbuild'; - -import configs from '../esbuild/config.mjs'; - -await Promise.all(configs.map(async (config) => await esbuild.build(config))); diff --git a/packages/i18n-polyfill/scripts/watch.mjs b/packages/i18n-polyfill/scripts/watch.mjs deleted file mode 100644 index 15dbb21..0000000 --- a/packages/i18n-polyfill/scripts/watch.mjs +++ /dev/null @@ -1,19 +0,0 @@ -import chalk from 'chalk'; -import * as esbuild from 'esbuild'; - -import configs from '../esbuild/config.mjs'; - -console.log( - `[${new Date().toLocaleTimeString(undefined, { - hour: 'numeric', - minute: '2-digit', - second: '2-digit', - hour12: false - })}] ${chalk.green('Watching...')}` -); - -const contexts = await Promise.all( - configs.map((config) => esbuild.context(config)) -); - -await Promise.any(contexts.map((ctx) => ctx.watch())); diff --git a/packages/i18n-polyfill/src/index.ts b/packages/i18n-polyfill/src/index.ts deleted file mode 100644 index 078b3da..0000000 --- a/packages/i18n-polyfill/src/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; - -import Manifest from './manifest'; - - -export interface PluginConfiguration { - // uploader ? -} - -export { Manifest }; - -export default () => { - return { - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - polyfill(cesdk); - } - }; -}; - - - -// we could polyfill them -import { merge } from 'lodash'; -import { flatten } from './utils/flatten'; - -export class I18N { - #translations: any = {}; - #locale: string = 'en'; - - setTranslations(translations: any) { - const flattenedTranslations = flatten(translations); - this.#translations = merge(this.#translations, flattenedTranslations); - } - - translate(key: string, fallback: string | undefined = undefined) { - const lookup = this.#locale.concat('.', key); - return this.#translations[lookup] ?? fallback ?? key; - } - t = this.translate.bind(this) -} - -export interface I18N { - setTranslations: (translations: any) => void; - translate(key: string, fallback: string | undefined): string; - -} - -export type I18NType = & { i18n?: I18N } - -export type Translations = { [locale: string]: object; } - -export function polyfill(sdk: CreativeEditorSDK) { - - const Polyfill = class extends I18N { - #translations: any = {}; - #locale: string = 'en'; - #origSetTranslations = sdk.setTranslations.bind(sdk); - - constructor(params: any) { - super(); - sdk.setTranslations = this.setTranslations.bind(this); - } - setTranslations(translations: Translations) { - this.#translations = merge(this.#translations, flatten(translations)); - this.#origSetTranslations(translations); - } - - translate(key: string, fallback: string | undefined = undefined) { - const lookup = this.#locale.concat('.', key); - return this.#translations[lookup] ?? fallback ?? key; - } - t = this.translate.bind(this) - } - - // @ts-ignore - if (!sdk.i18n) { - // @ts-ignore - sdk.i18n = new Polyfill() - } -} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/manifest.ts b/packages/i18n-polyfill/src/manifest.ts deleted file mode 100644 index 0972d63..0000000 --- a/packages/i18n-polyfill/src/manifest.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default { - id: "@imgly/polyfill-commands", - -} \ No newline at end of file diff --git a/packages/i18n-polyfill/src/worker.ts b/packages/i18n-polyfill/src/worker.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/i18n-polyfill/tsconfig.json b/packages/i18n-polyfill/tsconfig.json deleted file mode 100644 index 47d465c..0000000 --- a/packages/i18n-polyfill/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "target": "es2017", - "module": "es2020", - "lib": ["es2018", "dom"], - "moduleResolution": "node", - "isolatedModules": true, - "esModuleInterop": true, - "declaration": true, - "declarationDir": "types/", - "skipLibCheck": true - }, - "include": ["src/**/*", "esbuild/global.d.ts"], - "exclude": ["node_modules"] -} diff --git a/packages/i18n-polyfill/types/index.d.ts b/packages/i18n-polyfill/types/index.d.ts deleted file mode 100644 index 9d428f5..0000000 --- a/packages/i18n-polyfill/types/index.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; -import Manifest from './manifest'; -export interface PluginConfiguration { -} -export { Manifest }; -declare const _default: () => { - initializeUserInterface({ cesdk }: { - cesdk: CreativeEditorSDK; - }): void; -}; -export default _default; -export declare class I18N { - #private; - setTranslations(translations: any): void; - t: { - (key: string, fallback?: string | undefined): any; - (key: string, fallback: string | undefined): string; - }; -} -export interface I18N { - setTranslations: (translations: any) => void; - translate(key: string, fallback: string | undefined): string; -} -export type I18NType = { - i18n?: I18N; -}; -export type Translations = { - [locale: string]: object; -}; -export declare function polyfill(sdk: CreativeEditorSDK): void; diff --git a/packages/i18n-polyfill/types/manifest.d.ts b/packages/i18n-polyfill/types/manifest.d.ts deleted file mode 100644 index e1ead83..0000000 --- a/packages/i18n-polyfill/types/manifest.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const _default: { - id: string; -}; -export default _default; diff --git a/packages/i18n-polyfill/types/worker.d.ts b/packages/i18n-polyfill/types/worker.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/vectorizer/PLAYGROUND.md b/packages/vectorizer/PLAYGROUND.md new file mode 100644 index 0000000..f9a21fa --- /dev/null +++ b/packages/vectorizer/PLAYGROUND.md @@ -0,0 +1,180 @@ + +Define feature flags + +Feature Enabled +Feature Permissions + + + + + +```JS +// define +feature.register('featureName') +feature.unregister('featureName') + +// if the feature does not exist it always evaluates to flse +feature.setEnabled('featureName', true) +feature.setEnabled('featureName', false) +feature.setEnabled('featureName', (context) => { return true +}); + +feature.setPermission('featureName', (context) => { return true; +}) +feature.setPermission('featureName', (context) => { return true; +}) +feature.setPermission('featureName', (context) => { return true; +}) + +feature.setSupported('featureName', (context) => { return true +}) + +feature.can(featureName, context) { + if (!this.isSupported(featureName)) return; + if (!this.isAllowed(featureName)) return; + if (!this.isEnabled(featureName)) return; +} + +``` + + +```JS + // check if simd is suppored +feature.register("simd"); +feature.setEnabled("simd", (ctx) => { + if (feature.canUse("browser", ctx)) + return (typeof SIMD !== "undefined"); + }); + + +``` + +feature.isEnabled + + + +# Example share featur +```JS + +// we can register a unique identifier that has potentially dependencies to other features +feature.register("my.command", (ctx) => {}, ["fill", {"opt": { optional: true}}]) + + +// the integrator +feature.setPermission("share.dialog", (ctx) => {}) +feature.setEnabled("share.dialog", (ctx) => {}) + +// register dependecy that also need to be checked + +// can will check if the feature and the dependencies are met + +if (feature.can("my.command",ctx)) { + feature.run("my.command", args, ctx) +} + +feature + .try("my.command")? + .run(args, ctx) + +feature.wrap(func, ["feature"]) { + return () => { + // check features + return T | undefined + } +} + + +``` + + +```JS + +// only run when imgly scope img.ly arrange is set and whatever is in there evaluates to true +feature.register("vectorize", ctx => { + if (ctx.blockIds) // do some checks on the thing +}, ["imgly.arrange", "imgly.block.setPositionX"]) + + +function vectorize(image) { + +} + +export const vectorize = feature.wrap(vectorize, ["vectorize"]) + +//Vectorize will only run if feature is enabled + + +feature.setPermission("vectorize", "deny") // no one will be able to run it +feature.setEnabled("vectorize", true) + + +// checkout cancancan + +FEATURES/PERMISSIONS/SCOPES +// checkout Abilities +// results = Allow +class Abilities { + + #permission = Map() // featureName -> (func: boolean) | boolean + #enabled = Map() // featureName -> (func: boolean) | boolean + #definition = Map() // featureName -> (func: boolean) | boolean + #dependencies = Map() // featureName -> (func: boolean) | boolean + + + // all need allow, defer, deny + + can(featureName, ctx) => { + if (this.#enabled[featureName] && (!this.#enabled[featureName]?.(ctx))) return false; + if (this.#enabled[featureName] && (!this.#permission[featureName]?.(ctx)())) return false; + if (this.#enabled[featureName] && (!this.#definition[featureName]?.(ctx)())() return false; + // when decision s deferred to this feature then don't care + // when deicison is false + const deps = this.dependencies[featureName]?? [] + if (!deps.every(dep => this.isEnabled(dep, ctx))) return false + return true + } + +} + + +abilities.define("read", {blockIds} => { + if (!blockIds) +}) + +abilities.can("read", {blockIds}) + +abilities.define("block.setPositionX", ([id, value] => { + if (!id) return "deny" + // if (!value) we don't care about the value here +// can cehck wether or not to run +})) +abilities.define("block.setPositionX", ["block.arrange"]) + +// put a lock in front of setPosition +// this modifies the prototype +abilities.lock("block.setPositionX", setPosition, Block) + + +abilities.setPermission("block.setPosition") + +block.setPosition.can?(blockId) + +block.setPosition.allowed?(BlockId) + + +block.setPosition?.(blockId, value) +// check feature avaiability else use +blcok = ability.guard(block) //this will create a proxy to the object with each function being overwritten + +if (!block) return +if (!block.setPosition) return +if (!block.getPosition) return +if (!block.value) return + + +//enabled +//permission +//other + + +``` \ No newline at end of file diff --git a/packages/vectorizer/manifest.json b/packages/vectorizer/manifest.json new file mode 100644 index 0000000..a52ee74 --- /dev/null +++ b/packages/vectorizer/manifest.json @@ -0,0 +1,66 @@ +{ + "id": "vectorizer", + "version": "1.0.0", + "publisher": "IMG.LY GmbH", + "icon": "", + "license": "", + "pricing": "free", + "payment": { + "oneTime": 0, + "subscription": 0, + "usage": 0 + }, + "engines": { + "imgly": ">2.0.0" + }, + "categories": [ + "image", + "vector" + ], + "contributes": { + "ui": { + "button": { + "id": "vectorizer.ui.button", + "label": "vectorizer.ui.button" + } + }, + "commands": { + "vectorize": { + "id": "vectorizer.commands.vectorize", + "label": "vectorizer.commands.vectorize", + "args": [ + { + "type": "number", + "format": "", + "ui": "slider" + } + ], + "returns": {} + } + }, + "i18n": { + "vectorizer.commands.vectorize": "Convert into Vectorpath", + "vectorizer.commands.category": "Vectorizer", + "vectorizer.config.title": "Vectorizer", + "vectorizer.config.enabled": "Enable Vectorizer", + "vectorizer.config.enabled.description": "Enable or disable the vectorizer" + }, + "errors": { + "validationError": { + "id": "vectorizer.errors.validationError", + "message": "vectorizer.errors.validationError.message" + } + }, + "config": { + "type": "object", + "title": "vectorizer.config.titel", + "settings": { + "enabled": { + "type": "boolean", + "default": true, + "description": "vectorizer.config.settings.enabled.description" + } + } + } + } +} \ No newline at end of file diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 30cfcef..7e7c784 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -42,7 +42,7 @@ "scripts": { "start": "npm run watch", "clean": "npx rimraf dist && npx rimraf types", - "build": "yarn run types:create && node scripts/build.mjs", + "build": "yarn run clean && yarn run types:create && node scripts/build.mjs", "dev": "yarn run types:create && node scripts/watch.mjs", "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", @@ -64,6 +64,7 @@ }, "dependencies": { "@imgly/vectorizer": "~0.1.0-rc6", + "@imgly/plugin-api-utils": "*", "lodash": "^4.17.21" } } diff --git a/packages/vectorizer/src/PluginManifest.ts b/packages/vectorizer/src/PluginManifest.ts new file mode 100644 index 0000000..0477289 --- /dev/null +++ b/packages/vectorizer/src/PluginManifest.ts @@ -0,0 +1,16 @@ +import Manifest from '../manifest.json'; +type ManifestType = typeof Manifest; + +// TODO: Extend this with the builtin commands from other packages + +// Contributions + +export type I18NKeys = keyof ManifestType["contributes"]["i18n"] +export type CommandContributions = keyof ManifestType["contributes"]["commands"] +export type ErrorKeys = keyof ManifestType["contributes"]["errors"] + +export type UIComponentKeys = keyof ManifestType["contributes"]["ui"] +export type ConfigKeys = keyof ManifestType["contributes"]["config"] + +export const PluginManifest = Manifest + diff --git a/packages/vectorizer/src/activate.ts b/packages/vectorizer/src/activate.ts new file mode 100644 index 0000000..2b4a91d --- /dev/null +++ b/packages/vectorizer/src/activate.ts @@ -0,0 +1,90 @@ +import { PluginManifest, CommandContributions, UIComponentKeys } from './PluginManifest'; + +import { + fixDuplicateMetadata, + getPluginMetadata, + isDuplicate, +} from './utils/common'; + +import { PluginContext, CommandCallback } from './deps'; +import { update as handleUpdateEvent } from './handler'; + + +export async function activate(ctx: PluginContext) { + // const { engine, logger, i18n, ui, commands } = ctx + + + //@ts-ignore + ctx.logger?.trace("checking if engine has commands", cesdk.engine.commands ? "yes" : "no") + + { + ctx.logger?.trace("Registering commands") + type CommandsDef = Record + const commands: CommandsDef = await import('./commands') + + for (const command in commands) { + const callback = commands[command as CommandContributions] + const desc = PluginManifest.contributes.commands[command as CommandContributions]; + ctx.commands.registerCommand(desc.id, + async (params: any) => await callback(ctx as any, params), + desc + ); + } + } + + { + type UIComponentDefs = Record any> + const uiComponents: UIComponentDefs = await import('./ui') + + for (const key in uiComponents) { + const callback = uiComponents[key as UIComponentKeys] + + ctx.ui?.unstable_registerComponent( + PluginManifest.contributes.ui[key as UIComponentKeys].id, + (params: any) => callback(ctx, params)); + } + } + + + { + // FIXME: This should probablly be done automagically + ctx.logger?.trace("Registering I18N translations") + ctx.i18n.setTranslations({ en: PluginManifest.contributes.i18n }) + } + + + { + ctx.logger?.trace("Subscribing to events"); + const unsubscribe = ctx.engine.event.subscribe([], async (events) => { + events + .filter(e => ctx.engine.block.isValid(e.block) && ctx.engine.block.hasMetadata(e.block, PluginManifest.id)) + .filter(e => e.type === 'Updated') + .forEach(e => handleUpdateEvent(ctx.engine, e.block)) + }); + } + { + const unsubscribe = ctx.engine.event.subscribe([], async (events) => { + events + .filter(({ block: blockId }) => ctx.engine.block.isValid(blockId) && ctx.engine.block.hasMetadata(blockId, PluginManifest.id)) + .forEach(({ type, block: blockId }) => { + if (type === 'Created') { + const metadata = getPluginMetadata(ctx.engine, blockId); + if (isDuplicate(ctx.engine, blockId, metadata)) { + fixDuplicateMetadata(ctx.engine, blockId); + } + } + }); + }); + } + { + // THIS DOES not belong here maybe + ctx.logger?.trace("Defaulting canvas menu order") + const canvasMenuEntries = [ + PluginManifest.contributes.ui.button.id, + ...ctx.ui?.unstable_getCanvasMenuOrder() ?? [] + ] + ctx.ui?.unstable_setCanvasMenuOrder(canvasMenuEntries); + } +} + +// maybe this should be just engine.event.onUpdate() diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts index 3f08b4a..8de08a4 100644 --- a/packages/vectorizer/src/commands.ts +++ b/packages/vectorizer/src/commands.ts @@ -1,8 +1,3 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; - -import { PLUGIN_ACTION_VECTORIZE_LABEL } from './manifest'; - - import { getPluginMetadata, isBlockSupported, @@ -10,22 +5,24 @@ import { recoverInitialImageData, setPluginMetadata -} from './utils'; +} from './utils/common'; import { runInWorker } from './utils/worker.shared'; import { createVectorPathBlocks } from './utils/cesdk+utils'; +import { PluginContext } from './deps'; -// FIXME: The vectorize technically does not need image fills, it can vectorize every block by rendering the block and then processing the image -const vectorize = async (cesdk: CreativeEditorSDK, params: { blockIds?: number[] }) => { - const uploader = cesdk.unstable_upload.bind(cesdk) - const engine = cesdk.engine; // the only function that needs the ui is the upload function + + +export const vectorize = async (context: PluginContext, params: { blockIds?: number[] }) => { + const uploader: any = undefined; //cesdk.unstable_upload.bind(cesdk) + const {engine} = context; // the only function that needs the ui is the upload function const blockApi = engine.block; - // this shouldn't be necessay here + const blockIds = params.blockIds ?? engine.block.findAllSelected(); - blockIds.forEach(async blockId => { + blockIds.forEach(async (blockId: number) => { // this should happen before already and only be called if the feature is enabled for a certain block if (!isBlockSupported(engine, blockId)) return; @@ -48,7 +45,7 @@ const vectorize = async (cesdk: CreativeEditorSDK, params: { blockIds?: number[] initialSourceSet.length > 0 ? // Choose the highest resolution image in the source set initialSourceSet.sort( - (a, b) => b.width * b.height - a.height * a.width + (a: any, b: any) => b.width * b.height - a.height * a.width )[0].uri : initialImageFileURI; @@ -149,7 +146,7 @@ const vectorize = async (cesdk: CreativeEditorSDK, params: { blockIds?: number[] const origSelected = engine.block.isSelected(blockId) switch (engine.block.getType(blockId)) { - case "//ly.img.ubq/page": + case "//ly.img.ubq/page": // this has been disabled { const parentId = blockId; const containerId = engine.block.group(blockIds); @@ -201,5 +198,3 @@ const vectorize = async (cesdk: CreativeEditorSDK, params: { blockIds?: number[] }) } - -export default { [PLUGIN_ACTION_VECTORIZE_LABEL]: vectorize } diff --git a/packages/vectorizer/src/defaults.ts b/packages/vectorizer/src/defaults.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/vectorizer/src/deps.ts b/packages/vectorizer/src/deps.ts new file mode 100644 index 0000000..67e1b40 --- /dev/null +++ b/packages/vectorizer/src/deps.ts @@ -0,0 +1,6 @@ +import { I18NKeys } from "./PluginManifest"; +import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-api-utils'; +type PluginContext = IPluginContext; + +export { CreativeEngine } from '@cesdk/cesdk-js'; +export { type PluginContext, type CommandCallback } diff --git a/packages/vectorizer/src/handler.ts b/packages/vectorizer/src/handler.ts new file mode 100644 index 0000000..16cdf6f --- /dev/null +++ b/packages/vectorizer/src/handler.ts @@ -0,0 +1,28 @@ +import {CreativeEngine} from "@cesdk/cesdk-js"; + +import { + clearPluginMetadata, + getPluginMetadata, + isMetadataConsistent +} from './utils/common'; +/** + * Handle every possible state of the vectorization state if the block was + * updated. + */ +export async function update(engine: CreativeEngine, blockId: number) { + const metadata = getPluginMetadata(engine, blockId); + switch (metadata.status) { + case 'PROCESSING': + case 'PROCESSED': { + if (!isMetadataConsistent(engine, blockId)) { + clearPluginMetadata(engine, blockId); + } + break; + } + + default: { + // We do not care about other states + } + } + } + \ No newline at end of file diff --git a/packages/vectorizer/src/index.ts b/packages/vectorizer/src/index.ts index f184736..ffeba26 100644 --- a/packages/vectorizer/src/index.ts +++ b/packages/vectorizer/src/index.ts @@ -1,145 +1,26 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; +import Manifest from '../manifest.json'; +import { PluginContext } from "./deps"; -import ui from './ui'; -import commands from './commands'; -import Manifest, { PLUGIN_ACTION_VECTORIZE_LABEL, PLUGIN_COMPONENT_BUTTON_ID, PLUGIN_ID } from './manifest'; +import { activate } from './activate'; -import { - clearPluginMetadata, - fixDuplicateMetadata, - getPluginMetadata, - isDuplicate, - isMetadataConsistent, - areBlocksSupported -} from './utils'; - -export interface Logger { log: (message: string) => void, debug: (message: string) => void, error: (message: string) => void, trace: (message: string) => void } - export interface PluginConfiguration { - logger?: Logger + } export { Manifest }; -export default (pluginConfiguration: PluginConfiguration = {}) => { - const logger = pluginConfiguration.logger +export default (ctx: PluginContext, pluginConfiguration: PluginConfiguration) => { + return { ...Manifest, - initialize(engine: CreativeEngine) { - // it is unclear for a user which one to call and what happens and if we have to put code in both or just one - // we should have a clear separation of concerns - // also maybe better naming - // onInitEngine - // onInitUI - }, - initializeUserInterface({ cesdk }: { cesdk: CreativeEditorSDK }) { - // This should move into a seperate plugin - // const engine = polyfillEngineWithCommands(cesdk.engine); - const engine = cesdk.engine; - // @ts-ignore - if (!cesdk.engine.commands) { - logger?.error("Polyfill engine.engine.commands not available!") - return; - } - - logger?.trace("Subscribing to events"); - engine.event.subscribe([], async (events) => { - events - .filter(({ block: blockId }) => engine.block.isValid(blockId) && engine.block.hasMetadata(blockId, PLUGIN_ID)) - .forEach(({ type, block: blockId }) => { - if (type === 'Created') { - const metadata = getPluginMetadata(engine, blockId); - if (isDuplicate(engine, blockId, metadata)) { - fixDuplicateMetadata(engine, blockId); - } - } - }); - }); - - //@ts-ignore - logger?.trace("checking if engine has commands", cesdk.engine.commands ? "yes" : "no") - - engine.event.subscribe([], async (events) => { - events - .filter(e => engine.block.isValid(e.block) && cesdk.engine.block.hasMetadata(e.block, PLUGIN_ID)) - .filter(e => e.type === 'Updated') - .forEach(e => handleUpdateEvent(engine, e.block)) - }); - - logger?.trace("Registering plugin command") - Object.keys(commands).forEach((command) => { - logger?.trace(`Registering action: ${command}`) - // @ts-ignore - const func = commands[command]; - // @ts-ignore - cesdk.engine.commands?.registerCommand( - command, - async (params: any) => await func(cesdk, params) - ); - }) - - logger?.trace("Registering plugin I18N translations") - cesdk.setTranslations(Manifest.contributes.i18n); - - - logger?.trace("Registering plugin UI components") - const components = ui(cesdk) - - Object.keys(components).forEach((componentId) => { - // @ts-ignore - const component = components[componentId] - cesdk.ui.unstable_registerComponent(componentId, component); - }) - - // DEFAULTS - // define what blocks the component button is enabled for - // WHERE IS THIS USED? AND HOW DOES IT WORK? It seems the button is shown no matter what. - logger?.trace("Enabling plugin component button for supported blocks") - cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, (context: any) => { - return areBlocksSupported(engine, engine.block.findAllSelected()) - }) - - cesdk.feature.unstable_enable(PLUGIN_COMPONENT_BUTTON_ID, false); - cesdk.feature.unstable_enable(PLUGIN_ID, false); - cesdk.feature.unstable_enable(PLUGIN_ACTION_VECTORIZE_LABEL, false); - - - logger?.trace("Changing canvas menu order") - const canvasMenuEntries = [ - PLUGIN_COMPONENT_BUTTON_ID, - ...cesdk.ui.unstable_getCanvasMenuOrder() - ] - cesdk.ui.unstable_setCanvasMenuOrder(canvasMenuEntries); + async initializeUserInterface() { + return await activate(ctx) }, - // maybe this should be just engine.event.onUpdate() - update() { - - }, }; }; - -/** - * Handle every possible state of the vectorization state if the block was - * updated. - */ -async function handleUpdateEvent(engine: CreativeEngine, blockId: number) { - const metadata = getPluginMetadata(engine, blockId); - switch (metadata.status) { - case 'PROCESSING': - case 'PROCESSED': { - if (!isMetadataConsistent(engine, blockId)) { - clearPluginMetadata(engine, blockId); - } - break; - } - - default: { - // We do not care about other states - } - } -} +'' \ No newline at end of file diff --git a/packages/vectorizer/src/manifest.ts b/packages/vectorizer/src/manifest.ts deleted file mode 100644 index 63ce420..0000000 --- a/packages/vectorizer/src/manifest.ts +++ /dev/null @@ -1,31 +0,0 @@ -export const PLUGIN_ID = 'imgly/plugin-vectorizer-web'; -export const PLUGIN_COMPONENT_BUTTON_ID = `component.${PLUGIN_ID}.button`; -export const PLUGIN_ACTION_VECTORIZE_LABEL = `plugin.${PLUGIN_ID}.vectorize` - - -export default { - id: PLUGIN_ID, - publisher: "IMG.LY", - contributes: { - ui: [ - { - id: PLUGIN_COMPONENT_BUTTON_ID, - } - ], - commands: { - // maybe we don't need the manifest after all? - [PLUGIN_ACTION_VECTORIZE_LABEL]: { - // title: "Convert into Vector", //default when no translation is given - } - }, - i18n: { - en: { - [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Convert into Vectorpath' - - }, - de: { - [PLUGIN_ACTION_VECTORIZE_LABEL]: 'Konvertiere in Vectorpfade' - } - } - } -} \ No newline at end of file diff --git a/packages/vectorizer/src/ui.ts b/packages/vectorizer/src/ui.ts index ae9bfd6..abcf2b2 100644 --- a/packages/vectorizer/src/ui.ts +++ b/packages/vectorizer/src/ui.ts @@ -1,43 +1,29 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; -import { - PLUGIN_COMPONENT_BUTTON_ID, - PLUGIN_ACTION_VECTORIZE_LABEL -} from './manifest'; +import { PluginContext } from './deps'; + +import { PluginManifest } from './PluginManifest'; import { getPluginMetadata, isBlockSupported, -} from './utils'; - - -// I need cesdk atm -export default (cesdk: CreativeEditorSDK) => { - // @maerch: Shouldn't the params include "cesdk" and not engine? - const button = (params: any) => { - const builder = params.builder! +} from './utils/common'; - // the button might need the ids it is shown for - // the isSupported - const selected = cesdk.engine.block.findAllSelected(); - const candidates = selected.filter((id: number) => isBlockSupported(cesdk.engine, id)) - if (candidates.length === 0) return; - let isLoading = candidates.some((id: number) => getPluginMetadata(cesdk.engine, id).status === 'PROCESSING') +export const button = (ctx: PluginContext, params: any) => { + const builder = params.builder - // @maerch: Why do we need the Button ID here? - builder.Button("DO I NEED THIS", { - label: PLUGIN_ACTION_VECTORIZE_LABEL, - icon: '@imgly/icons/Vectorize', - isActive: false, - isLoading: isLoading, - isDisabled: isLoading, - loadingProgress: undefined, // creates infinite spinner - onClick: () => cesdk - // @ts-ignore - .engine.commands - ?.executeCommand(PLUGIN_ACTION_VECTORIZE_LABEL, { blockIds: candidates }) - }); - } + const selected = ctx.engine.block.findAllSelected(); + const candidates = selected.filter((id: number) => isBlockSupported(ctx.engine, id)) + if (candidates.length === 0) return; + const isLoading = candidates.some((id: number) => getPluginMetadata(ctx.engine, id).status === 'PROCESSING') - return { [PLUGIN_COMPONENT_BUTTON_ID]: button } -} // end of export default + // @maerch: Why do we need the Button ID here? + builder.Button(PluginManifest.contributes.ui.button.id, { + label: ctx.i18n.translate("vectorizer.commands.vectorize"), + icon: '@imgly/icons/Vectorize', + isActive: false, + isLoading: isLoading, + isDisabled: isLoading, + loadingProgress: undefined, // creates infinite spinner + onClick: () => ctx.commands.executeCommand(PluginManifest.contributes.commands.vectorize.id, { blockIds: candidates }) + }); +} diff --git a/packages/vectorizer/src/utils.ts b/packages/vectorizer/src/utils/common.ts similarity index 95% rename from packages/vectorizer/src/utils.ts rename to packages/vectorizer/src/utils/common.ts index 14e682b..9b2bd81 100644 --- a/packages/vectorizer/src/utils.ts +++ b/packages/vectorizer/src/utils/common.ts @@ -1,13 +1,14 @@ import { CreativeEngine } from '@cesdk/cesdk-js'; import isEqual from 'lodash/isEqual'; -import { PLUGIN_ID } from './manifest'; import { PluginMetadata, PluginStatusError, PluginStatusProcessed, PluginStatusProcessing -} from './utils/types'; +} from './types'; + +import { PluginManifest as manifest } from '../PluginManifest'; export const areBlocksSupported = (engine: CreativeEngine, blockIds: number[]) => { @@ -44,7 +45,7 @@ export function setPluginMetadata( id: number, metadata: PluginMetadata ) { - engine.block.setMetadata(id, PLUGIN_ID, JSON.stringify(metadata)); + engine.block.setMetadata(id, manifest.id, JSON.stringify(metadata)); } /** @@ -55,8 +56,8 @@ export function getPluginMetadata( engine: CreativeEngine, id: number ): PluginMetadata { - if (engine.block.hasMetadata(id, PLUGIN_ID)) { - return JSON.parse(engine.block.getMetadata(id, PLUGIN_ID)); + if (engine.block.hasMetadata(id, manifest.id)) { + return JSON.parse(engine.block.getMetadata(id, manifest.id)); } else { return { status: 'IDLE' @@ -68,8 +69,8 @@ export function getPluginMetadata( * If plugin metadata is set, it will be cleared. */ export function clearPluginMetadata(engine: CreativeEngine, id: number) { - if (engine.block.hasMetadata(id, PLUGIN_ID)) { - engine.block.removeMetadata(id, PLUGIN_ID); + if (engine.block.hasMetadata(id, manifest.id)) { + engine.block.removeMetadata(id, manifest.id); } } diff --git a/packages/vectorizer/tsconfig.json b/packages/vectorizer/tsconfig.json index 47d465c..445b415 100644 --- a/packages/vectorizer/tsconfig.json +++ b/packages/vectorizer/tsconfig.json @@ -5,12 +5,13 @@ "module": "es2020", "lib": ["es2018", "dom"], "moduleResolution": "node", + "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "declaration": true, "declarationDir": "types/", "skipLibCheck": true }, - "include": ["src/**/*", "esbuild/global.d.ts"], + "include": ["src/**/*", "esbuild/global.d.ts", "manifest.ts"], "exclude": ["node_modules"] } diff --git a/packages/vectorizer/types/PluginManifest.d.ts b/packages/vectorizer/types/PluginManifest.d.ts new file mode 100644 index 0000000..b723c5a --- /dev/null +++ b/packages/vectorizer/types/PluginManifest.d.ts @@ -0,0 +1,69 @@ +import Manifest from '../manifest.json'; +type ManifestType = typeof Manifest; +export type I18NKeys = keyof ManifestType["contributes"]["i18n"]; +export type CommandContributions = keyof ManifestType["contributes"]["commands"]; +export type ErrorKeys = keyof ManifestType["contributes"]["errors"]; +export type UIComponentKeys = keyof ManifestType["contributes"]["ui"]; +export type ConfigKeys = keyof ManifestType["contributes"]["config"]; +export declare const PluginManifest: { + id: string; + version: string; + publisher: string; + icon: string; + license: string; + pricing: string; + payment: { + oneTime: number; + subscription: number; + usage: number; + }; + engines: { + imgly: string; + }; + categories: string[]; + contributes: { + ui: { + button: { + id: string; + label: string; + }; + }; + commands: { + vectorize: { + id: string; + label: string; + args: { + type: string; + format: string; + ui: string; + }[]; + returns: {}; + }; + }; + i18n: { + "vectorizer.commands.vectorize": string; + "vectorizer.commands.category": string; + "vectorizer.config.title": string; + "vectorizer.config.enabled": string; + "vectorizer.config.enabled.description": string; + }; + errors: { + validationError: { + id: string; + message: string; + }; + }; + config: { + type: string; + title: string; + settings: { + enabled: { + type: string; + default: boolean; + description: string; + }; + }; + }; + }; +}; +export {}; diff --git a/packages/vectorizer/types/activate.d.ts b/packages/vectorizer/types/activate.d.ts new file mode 100644 index 0000000..2c2cf5a --- /dev/null +++ b/packages/vectorizer/types/activate.d.ts @@ -0,0 +1,2 @@ +import { PluginContext } from './deps'; +export declare function activate(ctx: PluginContext): Promise; diff --git a/packages/vectorizer/types/commands.d.ts b/packages/vectorizer/types/commands.d.ts index 045fcd5..2932810 100644 --- a/packages/vectorizer/types/commands.d.ts +++ b/packages/vectorizer/types/commands.d.ts @@ -1,7 +1,4 @@ -import type CreativeEditorSDK from '@cesdk/cesdk-js'; -declare const _default: { - "plugin.imgly/plugin-vectorizer-web.vectorize": (cesdk: CreativeEditorSDK, params: { - blockIds?: number[] | undefined; - }) => Promise; -}; -export default _default; +import { PluginContext } from './deps'; +export declare const vectorize: (context: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/vectorizer/types/defaults.d.ts b/packages/vectorizer/types/defaults.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/vectorizer/types/deps.d.ts b/packages/vectorizer/types/deps.d.ts new file mode 100644 index 0000000..6ba08aa --- /dev/null +++ b/packages/vectorizer/types/deps.d.ts @@ -0,0 +1,5 @@ +import { I18NKeys } from "./PluginManifest"; +import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-api-utils'; +type PluginContext = IPluginContext; +export { CreativeEngine } from '@cesdk/cesdk-js'; +export { type PluginContext, type CommandCallback }; diff --git a/packages/vectorizer/types/handler.d.ts b/packages/vectorizer/types/handler.d.ts new file mode 100644 index 0000000..35d222b --- /dev/null +++ b/packages/vectorizer/types/handler.d.ts @@ -0,0 +1,6 @@ +import { CreativeEngine } from "@cesdk/cesdk-js"; +/** + * Handle every possible state of the vectorization state if the block was + * updated. + */ +export declare function update(engine: CreativeEngine, blockId: number): Promise; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index 83d82cc..67e3daa 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -1,38 +1,66 @@ -import CreativeEditorSDK, { CreativeEngine } from '@cesdk/cesdk-js'; -import Manifest from './manifest'; -export interface Logger { - log: (message: string) => void; - debug: (message: string) => void; - error: (message: string) => void; - trace: (message: string) => void; -} +import Manifest from '../manifest.json'; +import { PluginContext } from "./deps"; export interface PluginConfiguration { - logger?: Logger; } export { Manifest }; -declare const _default: (pluginConfiguration?: PluginConfiguration) => { - initialize(engine: CreativeEngine): void; - initializeUserInterface({ cesdk }: { - cesdk: CreativeEditorSDK; - }): void; - update(): void; +declare const _default: (ctx: PluginContext, pluginConfiguration: PluginConfiguration) => { + initializeUserInterface(): Promise; id: string; + version: string; publisher: string; + icon: string; + license: string; + pricing: string; + payment: { + oneTime: number; + subscription: number; + usage: number; + }; + engines: { + imgly: string; + }; + categories: string[]; contributes: { ui: { - id: string; - }[]; + button: { + id: string; + label: string; + }; + }; commands: { - "plugin.imgly/plugin-vectorizer-web.vectorize": { - title: string; + vectorize: { + id: string; + label: string; + args: { + type: string; + format: string; + ui: string; + }[]; + returns: {}; }; }; i18n: { - en: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; + "vectorizer.commands.vectorize": string; + "vectorizer.commands.category": string; + "vectorizer.config.title": string; + "vectorizer.config.enabled": string; + "vectorizer.config.enabled.description": string; + }; + errors: { + validationError: { + id: string; + message: string; }; - de: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; + }; + config: { + type: string; + title: string; + settings: { + enabled: { + type: string; + default: boolean; + description: string; + }; }; }; }; diff --git a/packages/vectorizer/types/manifest.d.ts b/packages/vectorizer/types/manifest.d.ts deleted file mode 100644 index cea58ce..0000000 --- a/packages/vectorizer/types/manifest.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -export declare const PLUGIN_ID = "imgly/plugin-vectorizer-web"; -export declare const PLUGIN_COMPONENT_BUTTON_ID = "component.imgly/plugin-vectorizer-web.button"; -export declare const PLUGIN_ACTION_VECTORIZE_LABEL = "plugin.imgly/plugin-vectorizer-web.vectorize"; -declare const _default: { - id: string; - publisher: string; - contributes: { - ui: { - id: string; - }[]; - commands: { - "plugin.imgly/plugin-vectorizer-web.vectorize": { - title: string; - }; - }; - i18n: { - en: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; - }; - de: { - "plugin.imgly/plugin-vectorizer-web.vectorize": string; - }; - }; - }; -}; -export default _default; diff --git a/packages/vectorizer/types/ui.d.ts b/packages/vectorizer/types/ui.d.ts index b24e1b2..943cb1c 100644 --- a/packages/vectorizer/types/ui.d.ts +++ b/packages/vectorizer/types/ui.d.ts @@ -1,5 +1,2 @@ -import CreativeEditorSDK from '@cesdk/cesdk-js'; -declare const _default: (cesdk: CreativeEditorSDK) => { - "component.imgly/plugin-vectorizer-web.button": (params: any) => void; -}; -export default _default; +import { PluginContext } from './deps'; +export declare const button: (ctx: PluginContext, params: any) => void; diff --git a/packages/vectorizer/types/utils.d.ts b/packages/vectorizer/types/utils/common.d.ts similarity index 98% rename from packages/vectorizer/types/utils.d.ts rename to packages/vectorizer/types/utils/common.d.ts index 4a58386..2166d3f 100644 --- a/packages/vectorizer/types/utils.d.ts +++ b/packages/vectorizer/types/utils/common.d.ts @@ -1,5 +1,5 @@ import { CreativeEngine } from '@cesdk/cesdk-js'; -import { PluginMetadata } from './utils/types'; +import { PluginMetadata } from './types'; export declare const areBlocksSupported: (engine: CreativeEngine, blockIds: number[]) => boolean; /** * Checks if a block is supported by the given CreativeEngine. From ab4c77ce5531a364fe69a83939337c6ad8b79db5 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Tue, 27 Feb 2024 22:58:49 +0100 Subject: [PATCH 24/32] wip --- .../imgly-commands/commands/container.ts | 114 +++++++++++++---- .../plugins/imgly-commands/commands/export.ts | 115 ++++++++++++++---- .../web/src/plugins/imgly-commands/index.ts | 1 - .../src/plugins/imgly-commands/locale/en.json | 30 +---- .../src/plugins/imgly-commands/manifest.json | 25 +++- packages/api-utils/types/plugin/Logger.d.ts | 1 + packages/vectorizer/manifest.json | 1 + 7 files changed, 211 insertions(+), 76 deletions(-) diff --git a/examples/web/src/plugins/imgly-commands/commands/container.ts b/examples/web/src/plugins/imgly-commands/commands/container.ts index 99a1e3d..5ae330e 100644 --- a/examples/web/src/plugins/imgly-commands/commands/container.ts +++ b/examples/web/src/plugins/imgly-commands/commands/container.ts @@ -1,12 +1,14 @@ import { PluginContext } from "@imgly/plugin-api-utils"; + + export const groupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected(), } = params; if (blockIds.length < 1) return; - + const group = block.group(blockIds); blockIds.forEach((id: number) => block.isSelected(id) && block.setSelected(id, false)); block.setSelected(group, true); @@ -20,14 +22,14 @@ export const ungroupBlocks = async (ctx: PluginContext, params: { blockIds?: num blockIds = block.findAllSelected(), } = params; if (blockIds.length !== 1) return; - + const blockId = blockIds[0]; const isSelected = block.isSelected(blockId); if (block.getType(blockId) !== '//ly.img.ubq/group') return; const childIds = block.getChildren(blockId); block.ungroup(blockId); // Note – ungroup should return the IDs childIds.forEach((id: number) => block.setSelected(id, isSelected)); - + } export const groupLayoutHStack = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { @@ -36,14 +38,18 @@ export const groupLayoutHStack = async (ctx: PluginContext, params: { blockIds?: blockIds = block.findAllSelected(), padding = 0 } = params; - if (blockIds.length !== 1) return; - const blockId = blockIds[0]; - if (block.getType(blockId) !== '//ly.img.ubq/group') return; + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') + const isMultiSelection = blockIds.length > 1 + + if (!isGroup && !isMultiSelection) { + return + }; - const children = block.getChildren(blockId); + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; if (children.length === 0) return; + let curXPos = block.getPositionX(children[0]) let curYPos = block.getPositionY(children[0]) children.forEach((childId: number) => { @@ -61,12 +67,14 @@ export const groupLayoutVStack = async (ctx: PluginContext, params: { blockIds?: blockIds = block.findAllSelected(), padding = 0 } = params; - if (blockIds.length !== 1) return; + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') + const isMultiSelection = blockIds.length > 1 - const blockId = blockIds[0]; - if (block.getType(blockId) !== '//ly.img.ubq/group') return; + if (!isGroup && !isMultiSelection) { + return + }; - const children = block.getChildren(blockId); + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; if (children.length === 0) return; let curXPos = block.getPositionX(children[0]) @@ -81,27 +89,87 @@ export const groupLayoutVStack = async (ctx: PluginContext, params: { blockIds?: } -export const groupLayoutCircle = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { +export const groupLayoutMasonry = async (ctx: PluginContext, params: { blockIds?: number[], cols?: number, paddingX?: number, paddingY?: number }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected(), - padding = 0 + paddingX = 16, + paddingY = 16, + cols = 2 } = params; - if (blockIds.length !== 1) return; - const blockId = blockIds[0]; - if (block.getType(blockId) !== '//ly.img.ubq/group') return; - const children = block.getChildren(blockId); - if (children.length === 0) return; + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') + const isMultiSelection = blockIds.length > 1 + + if (!isGroup && !isMultiSelection) { + return + }; + + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; + const groupWidth = isGroup ? block.getFrameWidth(blockIds[0]) : getMultiSelectionBounds(ctx, blockIds).width; + const childWidth = groupWidth / cols - paddingX + + console.log(children) + let rowHeights = [] + for (let i = 0; i < cols; i++) { + rowHeights.push(0); + } let curXPos = block.getPositionX(children[0]) let curYPos = block.getPositionY(children[0]) children.forEach((childId: number) => { - block.setPositionX(childId, curXPos); - block.setPositionY(childId, curYPos); - const height = block.getFrameHeight(childId); - curYPos += height; - curYPos += padding; + const w = block.getFrameWidth(childId); + const h = block.getFrameHeight(childId); + const aspect = h / w; + const newWidth = childWidth + const newHeight = aspect * newWidth; + block.setWidth(childId, newWidth); + block.setHeight(childId, newHeight); + // get column with the "lowest" height + const minIndex = rowHeights.indexOf(Math.min(...rowHeights)); + console.log(minIndex, rowHeights[minIndex]) + const xPos = curXPos + minIndex * (childWidth + paddingX); + const yPos = curYPos + rowHeights[minIndex]; + rowHeights[minIndex] += newHeight + paddingY; + block.setPositionX(childId, xPos); + block.setPositionY(childId, yPos); }) +} + + +export const groupLayoutCircle = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + } = params; + const blockId = blockIds[0]; + if (blockIds.length !== 1 || block.getType(blockId) !== '//ly.img.ubq/group') { + ctx.logger?.info("Only groups are supported") + return + }; + + + + +} + + +const getMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { + + const { block } = ctx.engine; + const bounds = blockIds.map((id: number) => { + return { + x: block.getFrameX(id), + y: block.getFrameY(id), + width: block.getFrameWidth(id), + height: block.getFrameHeight(id) + } + }); + + const x = Math.min(...bounds.map(b => b.x)); + const y = Math.min(...bounds.map(b => b.y)); + const width = Math.max(...bounds.map(b => b.x + b.width)) - x; + const height = Math.max(...bounds.map(b => b.y + b.height)) - y; + return { x, y, width, height } } \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/export.ts b/examples/web/src/plugins/imgly-commands/commands/export.ts index 8c3ade3..2887d25 100644 --- a/examples/web/src/plugins/imgly-commands/commands/export.ts +++ b/examples/web/src/plugins/imgly-commands/commands/export.ts @@ -5,19 +5,39 @@ import { downloadBlob } from "../../../utils/download"; // const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { -const exportAsPngs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType }) => { +const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { const { block } = ctx.engine; - const { blockIds = block.findAllSelected(), mimeType = "image/png" as MimeType } = params; + const { + blockIds = block.findAllSelected(), + mimeType = "image/png" as MimeType, + width, + height + } = params; blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - return await Promise.all(blockIds.map(async (bId: number) => { - return await block.export(bId, mimeType); + switch (mimeType) { + case "application/x-cesdk": { + const str = await block.saveToString([bId]); + return new Blob([str], { type: mimeType }); + + } + case "application/json": { + const str = await block.saveToString([bId]); + const json = str.substring(4) + const decoded = atob(json) + return new Blob([decoded], { type: mimeType }); + + } + default: + return await block.export(bId, mimeType, {targetHeight: height, targetWidth: width}); + } + })); }; export const exportPngToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/png" as MimeType })).map((blob) => { + const items = (await exportBlockAs(ctx, { ...params, mimeType: "image/png" as MimeType })).map((blob) => { return new ClipboardItem({ ["image/png"]: blob, }, { presentationStyle: "attachment" }); @@ -25,51 +45,96 @@ export const exportPngToClipboard = async (ctx: PluginContext, params: { blockId await navigator.clipboard.write(items); }; +export const exportSceneToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/x-cesdk" })).map((blob) => { + return new ClipboardItem({ + ["text/plain"]: blob, + }, { presentationStyle: "attachment" }); + }) + await navigator.clipboard.write(items); +}; + +export const exportJsonToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/json" })).map((blob) => { + return new ClipboardItem({ + ["text/plain"]: blob, + }, { presentationStyle: "attachment" }); + }) + await navigator.clipboard.write(items); +}; + export const exportPngToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/png" as MimeType })) + const items = (await exportBlockAs(ctx, { ...params, mimeType: "image/png" as MimeType })) items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.png`) }); } export const exportJpegToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/jpeg" as MimeType })) + const items = (await exportBlockAs(ctx, { ...params, mimeType: "image/jpeg" as MimeType })) items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.jpeg`) }); } export const exportWebpToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "image/webp" as MimeType })) + const items = (await exportBlockAs(ctx, { ...params, mimeType: "image/webp" as MimeType })) items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.webp`) }); } export const exportPdfToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "application/pdf" as MimeType })) + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/pdf" as MimeType })) items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.pdf`) }); } export const exportRgba8ToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const items = (await exportAsPngs(ctx, { ...params, mimeType: "application/octet-stream" as MimeType })) + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/octet-stream" as MimeType })) items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.rgba8`) }); } -export const exportSceneToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }); - await navigator.clipboard.writeText(await blob.text()); -}; +export const exportSceneToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/x-cesdk" })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.cesdk`) }); +} -export const exportJSONToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const exportJsonToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const items = (await exportBlockAs(ctx, { ...params, mimeType: "application/json" })) + items.forEach((blob, index) => { downloadBlob(blob, `block-${index}.json`) }); +} + + + +export const exportComponentToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected() } = params; - blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - const str = await block.saveToString(blockIds); - const base64 = str.substring(4); - const json = atob(base64); - const blob = new Blob([json], { type: "application/json" }); - await navigator.clipboard.writeText(await blob.text()); -}; + const componentData = await Promise.all(blockIds.map(async (bId) => { + + const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }) + const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }) + const json = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/json" }) + // const zip = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/zip" as MimeType }) + + return { + thumbnail: thumbnail[0], + cesdk: cesdk[0], + json: json[0], + // zip: zip[0], + } + })) + + componentData.forEach((data, index) => { + const blockId = blockIds[index]; + const filename = inferBlockName(ctx, blockId) + downloadBlob(data.thumbnail, `${filename}.png`) + downloadBlob(data.cesdk, `${filename}.cesdk`) + downloadBlob(data.json, `${filename}.json`) + }); +} + +const inferBlockName = (ctx: PluginContext, blockId: number) => { + const { block } = ctx.engine; + const uuid = block.getUUID(blockId); + const name = block.getName(blockId) + return name || uuid || blockId +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/index.ts b/examples/web/src/plugins/imgly-commands/index.ts index 6e68e08..dd9a707 100644 --- a/examples/web/src/plugins/imgly-commands/index.ts +++ b/examples/web/src/plugins/imgly-commands/index.ts @@ -30,7 +30,6 @@ export default (ctx: PluginContext, _config: PluginConfiguration) => { //we should give manifest to the context registerTranslation(ctx, { en }) registerCommands(ctx, commands) - } }; }; diff --git a/examples/web/src/plugins/imgly-commands/locale/en.json b/examples/web/src/plugins/imgly-commands/locale/en.json index 2e970c0..185492f 100644 --- a/examples/web/src/plugins/imgly-commands/locale/en.json +++ b/examples/web/src/plugins/imgly-commands/locale/en.json @@ -6,38 +6,16 @@ "plugin.commands.exportJpegToFile": "Export JPEG to File", "plugin.commands.exportWebpToFile": "Export WEP to File", "plugin.commands.exportPdfToFile": "Export PDF to File", + "plugin.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", "plugin.commands.exportSceneToClipboard": "Export Scene to Clipboard", "plugin.commands.exportJSONToClipboard": "Export JSON to Clipboard", + "plugin.commands.exportSceneToFile": "Export Scene to File", + "plugin.commands.exportJSONToFile": "Export JSON to File", "plugin.commands.imageFitModeContain": "Set Image FitMode to Contain", "plugin.commands.imageFitModeCrop": "Set Image FitMode to Crop", "plugin.commands.imageFitModeCover": "Set Image FitMode to Cover", - "imgly.block.download.selected.as.png": "Block: Download selected as PNG", - "imgly.block.download.selected.as.jpeg": "Block: Download selected as JPEG", - "imgly.block.download.selected.as.webp": "Block: Download selected as WEBP", - "imgly.block.download.selected.as.x-tga": "Block: Download selected as TGA", - "imgly.block.download.selected.as.pdf": "Block: Download selected as PDF", - "imgly.block.download.selected.as.octet-stream": "Block: Download selected as RGBA8", - "imgly.block.download.selected.as.scene": "Block: Download selected as Scene", - "imgly.block.download.selected.as.json": "Block: Download selected as JSON", - "imgly.block.clipboard.selected.as.png": "Block: Copy selected as PNG to Clipboard", - "imgly.block.clipboard.selected.as.scene": "Block: Copy selected as Scene to Clipboard", - "imgly.block.clipboard.selected.as.json": "Block: Copy selected as JSON to Clipboard", - "imgly.debug.clear.metadata": "Debug: Clear Metadata", - "imgly.debug.log.metadata": "Debug: Log Metadata", - "imgly.debug.log.block": "Debug: Log Block", - "imgly.debug.log.fill": "Debug: Log Fill", - "imgly.debug.log.scene": "Debug: Log Scene", - "imgly.debug.log.scopes": "Debug: Log Scopes", - "imgly.debug.log.assets": "Debug: Log Assets", - "imgly.debug.log.variables": "Debug: Log Variables", - "imgly.debug.log.editor.settings": "Debug: Log Editor Settings", - "imgly.block.container.group": "Container: Group", - "imgly.block.container.ungroup": "Container: Ungroup", - "imgly.block.combine.union": "Combine: Union", - "imgly.block.combine.difference": "Combine: Subtract", - "imgly.block.combine.intersection": "Combine: Intersect", - "imgly.block.combine.xor": "Combine: Exclude" + "plugin.commands.exportComponentToFile": "Export Component to File" } \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/manifest.json b/examples/web/src/plugins/imgly-commands/manifest.json index 689ae6b..71ba8aa 100644 --- a/examples/web/src/plugins/imgly-commands/manifest.json +++ b/examples/web/src/plugins/imgly-commands/manifest.json @@ -38,14 +38,26 @@ "id": "plugin.commands.exportPdfToFile", "group": "export" }, + "exportSceneToFile": { + "id": "plugin.commands.exportSceneToFile", + "group": "export" + }, "exportSceneToClipboard": { "id": "plugin.commands.exportSceneToClipboard", "group": "export" }, - "exportJSONToClipboard": { + "exportJsonToClipboard": { "id": "plugin.commands.exportJSONToClipboard", "group": "export" }, + "exportJsonToFile": { + "id": "plugin.commands.exportJSONToFile", + "group": "export" + }, + "exportComponentToFile": { + "id": "plugin.commands.exportComponentToFile", + "group": "export" + }, "imageFitModeCrop": { "id": "plugin.commands.imageFitModeCrop", "group": "image" @@ -73,6 +85,17 @@ "groupLayoutVStack": { "id": "plugin.commands.groupLayoutVStack", "group": "group" + }, + "groupLayoutMasonry": { + "id": "plugin.commands.groupLayoutMasonry", + "group": "group" + }, + "groupLayoutCircle": { + "id": "plugin.commands.groupLayoutCircle", + "group": "group", + "when": { + "blockType": ["group"] + } } }, "i18n": {} diff --git a/packages/api-utils/types/plugin/Logger.d.ts b/packages/api-utils/types/plugin/Logger.d.ts index 27fc49a..5f98fd8 100644 --- a/packages/api-utils/types/plugin/Logger.d.ts +++ b/packages/api-utils/types/plugin/Logger.d.ts @@ -3,5 +3,6 @@ export interface Logger { trace: (message: string) => void; debug: (message: string) => void; warn: (message: string) => void; + info: (message: string) => void; error: (message: string) => void; } diff --git a/packages/vectorizer/manifest.json b/packages/vectorizer/manifest.json index a52ee74..d277b70 100644 --- a/packages/vectorizer/manifest.json +++ b/packages/vectorizer/manifest.json @@ -28,6 +28,7 @@ "vectorize": { "id": "vectorizer.commands.vectorize", "label": "vectorizer.commands.vectorize", + "group": "convert", "args": [ { "type": "number", From f15a1daf976e0fd485991baf1ac06b2c8df32b33 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 1 Mar 2024 18:41:25 +0100 Subject: [PATCH 25/32] wip --- examples/web/package.json | 3 +- examples/web/src/App.tsx | 13 +- .../src/plugins/imgly-commands/commands.ts | 4 - .../src/plugins/imgly-commands/utils/cesdk.ts | 39 --- examples/web/tsconfig.json | 2 +- package.json | 1 + packages/api-utils/src/plugin/Logger.ts | 1 + packages/api-utils/types/plugin/Logger.d.ts | 2 +- packages/design-batteries/esbuild/config.mjs | 58 ++++ packages/design-batteries/esbuild/global.d.ts | 3 + .../design-batteries}/manifest.json | 16 + packages/design-batteries/package.json | 69 ++++ packages/design-batteries/scripts/build.mjs | 5 + packages/design-batteries/scripts/watch.mjs | 19 ++ .../design-batteries/src}/PluginManifest.ts | 2 +- packages/design-batteries/src/commands.ts | 6 + .../src}/commands/__template.ts | 0 .../src}/commands/clipboard.ts | 0 .../src}/commands/container.ts | 6 +- .../src}/commands/copyStyle.ts | 0 .../design-batteries/src/commands/debug.ts | 0 .../design-batteries/src}/commands/export.ts | 2 +- .../design-batteries/src}/commands/image.ts | 10 +- .../src}/commands/lifecycle.ts | 0 .../design-batteries/src/commands/magic.ts | 29 ++ .../src}/commands/old_debug.ts | 0 .../src/commands/playground.ts | 307 ++++++++++++++++++ .../src}/commands/syncStyle.ts | 0 .../design-batteries/src}/index.ts | 6 +- .../design-batteries/src}/locale/en.json | 0 .../design-batteries/src}/types/types.ts | 0 packages/design-batteries/src/utils/cesdk.ts | 39 +++ .../design-batteries/src/utils/download.ts | 29 ++ packages/design-batteries/src/worker.ts | 0 packages/design-batteries/tsconfig.json | 17 + .../types/PluginManifest.d.ts | 124 +++++++ packages/design-batteries/types/commands.d.ts | 6 + .../types/commands/__template.d.ts | 3 + .../types/commands/clipboard.d.ts | 0 .../types/commands/container.d.ts | 24 ++ .../types/commands/copyStyle.d.ts | 0 .../types/commands/debug.d.ts | 0 .../types/commands/export.d.ts | 34 ++ .../types/commands/image.d.ts | 10 + .../types/commands/lifecycle.d.ts | 7 + .../types/commands/magic.d.ts | 4 + .../types/commands/old_debug.d.ts | 0 .../types/commands/playground.d.ts | 13 + .../types/commands/syncStyle.d.ts | 0 packages/design-batteries/types/index.d.ts | 7 + .../design-batteries/types/types/types.d.ts | 4 + .../design-batteries/types/utils/cesdk.d.ts | 3 + .../types/utils/download.d.ts | 6 + packages/design-batteries/types/worker.d.ts | 0 packages/vectorizer/types/PluginManifest.d.ts | 1 + packages/vectorizer/types/index.d.ts | 1 + yarn.lock | 8 +- 57 files changed, 870 insertions(+), 73 deletions(-) delete mode 100644 examples/web/src/plugins/imgly-commands/commands.ts delete mode 100644 examples/web/src/plugins/imgly-commands/utils/cesdk.ts create mode 100644 packages/design-batteries/esbuild/config.mjs create mode 100644 packages/design-batteries/esbuild/global.d.ts rename {examples/web/src/plugins/imgly-commands => packages/design-batteries}/manifest.json (86%) create mode 100644 packages/design-batteries/package.json create mode 100644 packages/design-batteries/scripts/build.mjs create mode 100644 packages/design-batteries/scripts/watch.mjs rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/PluginManifest.ts (88%) create mode 100644 packages/design-batteries/src/commands.ts rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/__template.ts (100%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/clipboard.ts (100%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/container.ts (97%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/copyStyle.ts (100%) create mode 100644 packages/design-batteries/src/commands/debug.ts rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/export.ts (99%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/image.ts (79%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/lifecycle.ts (100%) create mode 100644 packages/design-batteries/src/commands/magic.ts rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/old_debug.ts (100%) create mode 100644 packages/design-batteries/src/commands/playground.ts rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/commands/syncStyle.ts (100%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/index.ts (88%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/locale/en.json (100%) rename {examples/web/src/plugins/imgly-commands => packages/design-batteries/src}/types/types.ts (100%) create mode 100644 packages/design-batteries/src/utils/cesdk.ts create mode 100644 packages/design-batteries/src/utils/download.ts create mode 100644 packages/design-batteries/src/worker.ts create mode 100644 packages/design-batteries/tsconfig.json create mode 100644 packages/design-batteries/types/PluginManifest.d.ts create mode 100644 packages/design-batteries/types/commands.d.ts create mode 100644 packages/design-batteries/types/commands/__template.d.ts create mode 100644 packages/design-batteries/types/commands/clipboard.d.ts create mode 100644 packages/design-batteries/types/commands/container.d.ts create mode 100644 packages/design-batteries/types/commands/copyStyle.d.ts create mode 100644 packages/design-batteries/types/commands/debug.d.ts create mode 100644 packages/design-batteries/types/commands/export.d.ts create mode 100644 packages/design-batteries/types/commands/image.d.ts create mode 100644 packages/design-batteries/types/commands/lifecycle.d.ts create mode 100644 packages/design-batteries/types/commands/magic.d.ts create mode 100644 packages/design-batteries/types/commands/old_debug.d.ts create mode 100644 packages/design-batteries/types/commands/playground.d.ts create mode 100644 packages/design-batteries/types/commands/syncStyle.d.ts create mode 100644 packages/design-batteries/types/index.d.ts create mode 100644 packages/design-batteries/types/types/types.d.ts create mode 100644 packages/design-batteries/types/utils/cesdk.d.ts create mode 100644 packages/design-batteries/types/utils/download.d.ts create mode 100644 packages/design-batteries/types/worker.d.ts diff --git a/examples/web/package.json b/examples/web/package.json index b1436fa..96452d0 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -9,10 +9,11 @@ "preview": "vite preview" }, "dependencies": { - "@cesdk/cesdk-js": "^1.20.0", + "@cesdk/cesdk-js": "^1.21.0", "@imgly/plugin-api-utils": "*", "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer-web": "*", + "@imgly/plugin-design-batteries": "*", "lodash": "^4.17.21", "react": "^18.2.0", "react-cmdk": "^1.3.9", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 8303acf..e9fafb1 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -16,7 +16,7 @@ import { downloadBlocks } from "./utils/download"; // Plugins // import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; -import CommandsPlugin from "./plugins/imgly-commands"; +import DesignBatteriesPlugin from "@imgly/plugin-design-batteries"; import { PluginContext } from "@imgly/plugin-api-utils"; @@ -82,22 +82,15 @@ function App() { const vectorizerPlugin = VectorizerPlugin(imgly, {}) - const commandsPlugin = CommandsPlugin(imgly, {}) - // const backgroundRemovalPlugin = BackgroundRemovalPlugin() + const commandsPlugin = DesignBatteriesPlugin(imgly, {}) - // const imglyComponentSource = ImglyComponentSource() - - // - - // Register Plguins await Promise.all([ cesdk.addDefaultAssetSources(), cesdk.addDemoAssetSources({ sceneMode: "Design" }), cesdk.unstable_addPlugin(commandsPlugin), - // cesdk.unstable_addPlugin(imglyComponentSource), cesdk.unstable_addPlugin(vectorizerPlugin), - // cesdk.unstable_addPlugin(backgroundRemovalPlugin), + ]); diff --git a/examples/web/src/plugins/imgly-commands/commands.ts b/examples/web/src/plugins/imgly-commands/commands.ts deleted file mode 100644 index c07fbee..0000000 --- a/examples/web/src/plugins/imgly-commands/commands.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./commands/lifecycle"; -export * from "./commands/export"; -export * from "./commands/image"; -export * from "./commands/container"; \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/utils/cesdk.ts b/examples/web/src/plugins/imgly-commands/utils/cesdk.ts deleted file mode 100644 index d2616be..0000000 --- a/examples/web/src/plugins/imgly-commands/utils/cesdk.ts +++ /dev/null @@ -1,39 +0,0 @@ -import CreativeEditorSDK from "@cesdk/cesdk-js"; - - -export const readPropValue = (cesdk: CreativeEditorSDK, id: number, propKey: string, propType?: string) => { - const blacklist= ["fill/solid/color"] - if (blacklist.includes(propKey)) return undefined; - if (!propType) propType = cesdk.engine.block.getPropertyType(propKey) - try { - switch (propType.toLowerCase()) { - case "string": return cesdk.engine.block.getString(id, propKey); - case "float": return cesdk.engine.block.getFloat(id, propKey); - case "double": return cesdk.engine.block.getDouble(id, propKey); - case "color": return cesdk.engine.block.getColor(id, propKey); - case "bool": return cesdk.engine.block.getBool(id, propKey); - case "enum": return cesdk.engine.block.getEnum(id, propKey); - } - } catch(e){ - console.warn("Error reading property value: ", e); - } - return undefined; -}; - - -export const writePropValue = (cesdk: CreativeEditorSDK, id: number, propKey: string, propValue: any,propType?: string) => { - if (!propType) propType = cesdk.engine.block.getPropertyType(propKey) - try { - switch (propType.toLowerCase()) { - case "string": return cesdk.engine.block.setString(id, propKey, propValue); - case "float": return cesdk.engine.block.setFloat(id, propKey, propValue); - case "double": return cesdk.engine.block.setDouble(id, propKey, propValue); - case "color": return cesdk.engine.block.setColor(id, propKey, propValue); - case "bool": return cesdk.engine.block.setBool(id, propKey, propValue); - case "enum": return cesdk.engine.block.setEnum(id, propKey, propValue); - } - } catch(e){ - console.warn("Error writing property: ", propKey, propType, propValue); - } - return undefined; -}; diff --git a/examples/web/tsconfig.json b/examples/web/tsconfig.json index 18c8610..31f6cb1 100644 --- a/examples/web/tsconfig.json +++ b/examples/web/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src", "../imgly-components-source"], + "include": ["src", "../imgly-components-source", "../../packages/design-batteries/src/commands", "../../packages/design-batteries/src/types", "../../packages/design-batteries/src/utils", "../../packages/design-batteries/src/commands.ts", "../../packages/design-batteries/src/index.ts", "../../packages/design-batteries/src/PluginManifest.ts"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/package.json b/package.json index c62622b..6f5dd39 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "workspaces": [ "examples/web", "packages/api-utils", + "packages/design-batteries", "packages/background-removal", "packages/vectorizer" diff --git a/packages/api-utils/src/plugin/Logger.ts b/packages/api-utils/src/plugin/Logger.ts index a0ee497..03cfdd4 100644 --- a/packages/api-utils/src/plugin/Logger.ts +++ b/packages/api-utils/src/plugin/Logger.ts @@ -2,6 +2,7 @@ export interface Logger { log: (message: string) => void , trace: (message: string) => void debug: (message: string) => void, + info: (message: string) => void, warn: (message: string) => void, error: (message: string) => void, diff --git a/packages/api-utils/types/plugin/Logger.d.ts b/packages/api-utils/types/plugin/Logger.d.ts index 5f98fd8..27f1a10 100644 --- a/packages/api-utils/types/plugin/Logger.d.ts +++ b/packages/api-utils/types/plugin/Logger.d.ts @@ -2,7 +2,7 @@ export interface Logger { log: (message: string) => void; trace: (message: string) => void; debug: (message: string) => void; - warn: (message: string) => void; info: (message: string) => void; + warn: (message: string) => void; error: (message: string) => void; } diff --git a/packages/design-batteries/esbuild/config.mjs b/packages/design-batteries/esbuild/config.mjs new file mode 100644 index 0000000..37b437c --- /dev/null +++ b/packages/design-batteries/esbuild/config.mjs @@ -0,0 +1,58 @@ +import chalk from 'chalk'; +import { readFile } from 'fs/promises'; + +// import packageJson from '../package.json' assert { type: 'json' }; +// Avoid the Experimental Feature warning when using the above. +const packageJson = JSON.parse( + await readFile(new URL('../package.json', import.meta.url)) +); + + +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) +const externals = [...dependencies, ...peerDependencies] + +console.log( + chalk.yellow('Building version: '), + chalk.green(packageJson.version) +); + +const configs = [ + { + entryPoints: ['src/index.ts', "src/worker.ts"], + define: { + PLUGIN_VERSION: `"${packageJson.version}"` + }, + minify: true, + bundle: true, + sourcemap: true, + external: externals, + platform: 'node', + format: 'esm', + outdir: 'dist', + outExtension: { '.js': '.mjs' }, + plugins: [ + { + name: 'reporter', + setup(build) { + build.onEnd((result) => { + console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] Build ${ + result.errors.length + ? chalk.red('failed') + : chalk.green('succeeded') + }` + ); + }); + } + } + ] + } +]; + +export default configs; diff --git a/packages/design-batteries/esbuild/global.d.ts b/packages/design-batteries/esbuild/global.d.ts new file mode 100644 index 0000000..de80fd8 --- /dev/null +++ b/packages/design-batteries/esbuild/global.d.ts @@ -0,0 +1,3 @@ +// These constants here are added by the base esbuild config + +declare const PLUGIN_VERSION: string; diff --git a/examples/web/src/plugins/imgly-commands/manifest.json b/packages/design-batteries/manifest.json similarity index 86% rename from examples/web/src/plugins/imgly-commands/manifest.json rename to packages/design-batteries/manifest.json index 71ba8aa..b18af9e 100644 --- a/examples/web/src/plugins/imgly-commands/manifest.json +++ b/packages/design-batteries/manifest.json @@ -96,6 +96,22 @@ "when": { "blockType": ["group"] } + }, + "logCrop": { + "id": "plugin.commands.logCrop", + "group": "image" + }, + "productSetInstagram": { + "id": "plugin.commands.productSetInstagram", + "group": "product" + }, + "playground": { + "id": "plugin.commands.playground", + "group": "playground" + }, + "syncBlocks": { + "id": "plugin.commands.syncBlocks", + "group": "lifecycle" } }, "i18n": {} diff --git a/packages/design-batteries/package.json b/packages/design-batteries/package.json new file mode 100644 index 0000000..044e150 --- /dev/null +++ b/packages/design-batteries/package.json @@ -0,0 +1,69 @@ +{ + "name": "@imgly/plugin-design-batteries", + "version": "0.1.0", + "description": "Vectorizer plugin for the CE.SDK editor", + "keywords": [ + "CE.SDK", + "plugin", + "svg", + "vectorizer" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/imgly/plugins.git" + }, + "license": "SEE LICENSE IN LICENSE.md", + "author": { + "name": "IMG.LY GmbH", + "email": "support@img.ly", + "url": "https://img.ly" + }, + "bugs": { + "email": "support@img.ly" + }, + "source": "./src/index.ts", + "module": "./dist/index.mjs", + "types": "./types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./types/index.d.ts" + } + }, + "homepage": "https://img.ly", + "files": [ + "LICENSE.md", + "README.md", + "CHANGELOG.md", + "dist/", + "types/", + "bin/" + ], + "scripts": { + "start": "npm run watch", + "clean": "npx rimraf dist && npx rimraf types", + "build": "yarn run clean && yarn run types:create && node scripts/build.mjs", + "dev": "yarn run types:create && node scripts/watch.mjs", + "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", + "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", + "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", + "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", + "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", + "check:type": "tsc --noEmit", + "types:create": "tsc --emitDeclarationOnly" + }, + "devDependencies": { + "chalk": "^5.3.0", + "concurrently": "^8.2.2", + "esbuild": "^0.19.11", + "eslint": "^8.51.0", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "@cesdk/cesdk-js": "~1.21.0" + }, + "dependencies": { + "@imgly/plugin-api-utils": "*", + "lodash": "^4.17.21" + } +} diff --git a/packages/design-batteries/scripts/build.mjs b/packages/design-batteries/scripts/build.mjs new file mode 100644 index 0000000..13d12e1 --- /dev/null +++ b/packages/design-batteries/scripts/build.mjs @@ -0,0 +1,5 @@ +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +await Promise.all(configs.map(async (config) => await esbuild.build(config))); diff --git a/packages/design-batteries/scripts/watch.mjs b/packages/design-batteries/scripts/watch.mjs new file mode 100644 index 0000000..15dbb21 --- /dev/null +++ b/packages/design-batteries/scripts/watch.mjs @@ -0,0 +1,19 @@ +import chalk from 'chalk'; +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] ${chalk.green('Watching...')}` +); + +const contexts = await Promise.all( + configs.map((config) => esbuild.context(config)) +); + +await Promise.any(contexts.map((ctx) => ctx.watch())); diff --git a/examples/web/src/plugins/imgly-commands/PluginManifest.ts b/packages/design-batteries/src/PluginManifest.ts similarity index 88% rename from examples/web/src/plugins/imgly-commands/PluginManifest.ts rename to packages/design-batteries/src/PluginManifest.ts index d3117db..03f47a5 100644 --- a/examples/web/src/plugins/imgly-commands/PluginManifest.ts +++ b/packages/design-batteries/src/PluginManifest.ts @@ -1,4 +1,4 @@ -import Manifest from './manifest.json'; +import Manifest from '../manifest.json'; import { CommandCallback } from '@imgly/plugin-api-utils'; diff --git a/packages/design-batteries/src/commands.ts b/packages/design-batteries/src/commands.ts new file mode 100644 index 0000000..b951770 --- /dev/null +++ b/packages/design-batteries/src/commands.ts @@ -0,0 +1,6 @@ +export * from "./commands/lifecycle"; +export * from "./commands/export"; +export * from "./commands/image"; +export * from "./commands/container"; +export * from "./commands/magic"; +export * from "./commands/playground"; \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/__template.ts b/packages/design-batteries/src/commands/__template.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/__template.ts rename to packages/design-batteries/src/commands/__template.ts diff --git a/examples/web/src/plugins/imgly-commands/commands/clipboard.ts b/packages/design-batteries/src/commands/clipboard.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/clipboard.ts rename to packages/design-batteries/src/commands/clipboard.ts diff --git a/examples/web/src/plugins/imgly-commands/commands/container.ts b/packages/design-batteries/src/commands/container.ts similarity index 97% rename from examples/web/src/plugins/imgly-commands/commands/container.ts rename to packages/design-batteries/src/commands/container.ts index 5ae330e..bc67826 100644 --- a/examples/web/src/plugins/imgly-commands/commands/container.ts +++ b/packages/design-batteries/src/commands/container.ts @@ -1,4 +1,5 @@ import { PluginContext } from "@imgly/plugin-api-utils"; +import { toInteger, toSafeInteger } from "lodash"; @@ -91,7 +92,7 @@ export const groupLayoutVStack = async (ctx: PluginContext, params: { blockIds?: export const groupLayoutMasonry = async (ctx: PluginContext, params: { blockIds?: number[], cols?: number, paddingX?: number, paddingY?: number }) => { const { block } = ctx.engine; - const { + let { blockIds = block.findAllSelected(), paddingX = 16, paddingY = 16, @@ -99,6 +100,7 @@ export const groupLayoutMasonry = async (ctx: PluginContext, params: { blockIds? } = params; + cols = toSafeInteger(prompt("Enter the number of columns", "2")) const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') const isMultiSelection = blockIds.length > 1 @@ -111,7 +113,7 @@ export const groupLayoutMasonry = async (ctx: PluginContext, params: { blockIds? const childWidth = groupWidth / cols - paddingX console.log(children) - let rowHeights = [] + let rowHeights: Array = [] for (let i = 0; i < cols; i++) { rowHeights.push(0); } diff --git a/examples/web/src/plugins/imgly-commands/commands/copyStyle.ts b/packages/design-batteries/src/commands/copyStyle.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/copyStyle.ts rename to packages/design-batteries/src/commands/copyStyle.ts diff --git a/packages/design-batteries/src/commands/debug.ts b/packages/design-batteries/src/commands/debug.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/web/src/plugins/imgly-commands/commands/export.ts b/packages/design-batteries/src/commands/export.ts similarity index 99% rename from examples/web/src/plugins/imgly-commands/commands/export.ts rename to packages/design-batteries/src/commands/export.ts index 2887d25..4d7bd74 100644 --- a/examples/web/src/plugins/imgly-commands/commands/export.ts +++ b/packages/design-batteries/src/commands/export.ts @@ -1,6 +1,6 @@ import { PluginContext } from "@imgly/plugin-api-utils"; import { MimeType } from "@cesdk/cesdk-js"; -import { downloadBlob } from "../../../utils/download"; +import { downloadBlob } from "../utils/download"; // const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { diff --git a/examples/web/src/plugins/imgly-commands/commands/image.ts b/packages/design-batteries/src/commands/image.ts similarity index 79% rename from examples/web/src/plugins/imgly-commands/commands/image.ts rename to packages/design-batteries/src/commands/image.ts index 02e1acf..020007b 100644 --- a/examples/web/src/plugins/imgly-commands/commands/image.ts +++ b/packages/design-batteries/src/commands/image.ts @@ -13,12 +13,6 @@ const imageFitWithMode = (ctx: PluginContext, params: { blockIds?: number[], fil export const imageFitModeCrop = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Crop' }) +export const imageFitModeCover = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Cover' }) -export const imageFitModeCover = async (ctx: PluginContext, params: { blockIds?: number[] }) => - imageFitWithMode(ctx, { ...params, fillMode: 'Cover' }) - - -export const imageFitModeContain = async (ctx: PluginContext, params: { blockIds?: number[] }) => - imageFitWithMode(ctx, { ...params, fillMode: 'Contain' }) - - +export const imageFitModeContain = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Contain' }) \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/lifecycle.ts b/packages/design-batteries/src/commands/lifecycle.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/lifecycle.ts rename to packages/design-batteries/src/commands/lifecycle.ts diff --git a/packages/design-batteries/src/commands/magic.ts b/packages/design-batteries/src/commands/magic.ts new file mode 100644 index 0000000..6144f5a --- /dev/null +++ b/packages/design-batteries/src/commands/magic.ts @@ -0,0 +1,29 @@ +// https://github.com/jwagner/smartcrop.js + +import { PluginContext } from "@imgly/plugin-api-utils"; + + + +export const logCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { blockIds = ctx.engine.block.findAllSelected() } = params; + + blockIds.forEach((id: number) => { + const fillId = ctx.engine.block.getFill(id) + const isValid = ctx.engine.block.isValid(fillId) + if (!isValid) return; + + const isImageFill = ctx.engine.block.getType(fillId) === "//ly.img.ubq/fill/image" + if (!isImageFill) return; + + const x = ctx.engine.block.getCropTranslationX(id) + const y = ctx.engine.block.getCropTranslationY(id) + const scaleX = ctx.engine.block.getCropScaleX(id) + const scaleY = ctx.engine.block.getCropScaleY(id) + const fillMode = ctx.engine.block.getContentFillMode(id) + + + + console.log(x, y, scaleX, scaleY, fillMode) + }); + +} \ No newline at end of file diff --git a/examples/web/src/plugins/imgly-commands/commands/old_debug.ts b/packages/design-batteries/src/commands/old_debug.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/old_debug.ts rename to packages/design-batteries/src/commands/old_debug.ts diff --git a/packages/design-batteries/src/commands/playground.ts b/packages/design-batteries/src/commands/playground.ts new file mode 100644 index 0000000..03131ff --- /dev/null +++ b/packages/design-batteries/src/commands/playground.ts @@ -0,0 +1,307 @@ +// EXPORT AS LIBRARY +// SYNC BY NAME - two pages, same name + +import { PluginContext } from "@imgly/plugin-api-utils"; +import { readPropValue, writePropValue } from "../utils/cesdk"; +import { createElement } from "react"; +// Idea sync by name... if two have the same name, they sync + + + + +const syncProperties = (ctx: PluginContext, propertyKeys: string[], sourceId: number, destIds: number[]) => { + const { block } = ctx.engine; + if (!block.isValid(sourceId)) return + + propertyKeys.forEach((propertyKey: string) => { + const sourceValue = readPropValue(block, sourceId, propertyKey) + destIds.forEach((receiverBlockId: number) => { + if (!block.isValid(receiverBlockId)) return + if (sourceId === receiverBlockId) return; + const receiverValue = readPropValue(block, receiverBlockId, propertyKey) + if (receiverValue === sourceValue) return; + writePropValue(block, receiverBlockId, propertyKey, sourceValue) + }) + }) +} + + +// name syntax = "label=appearance(other), rotation(other)" +export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block, event } = ctx.engine; + let { blockIds = block.findAllSelected() } = params + console.log("syncBlocks", block.findAllProperties(blockIds[0])) + const properties = [ + "opacity", "blend/mode", "rotation", + 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y'] + const unsubscribe = event.subscribe(blockIds, (events) => { + events.forEach((event) => { + const bId = event.block; + switch (event.type) { + case 'Created': { + // throw new Error("Not implemented") + // break; + } + case 'Updated': { + syncProperties(ctx, properties, bId, blockIds) + break; + } + case "Destroyed": { + if (blockIds.includes(bId)) { + blockIds.splice(blockIds.indexOf(bId), 1) + } + if (blockIds.length === 1) { + unsubscribe() + } + break; + } + } + }) + }) + +} + +export const registerAndOpenCustomPanel = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { ui } = ctx; + ui.unstable_registerCustomPanel('ly.img.foo', (domElement) => { + domElement.appendChild(document.createTextNode('Hello World')); + return () => { + console.log('Apps disposer called'); + }; + }); + + ui.openPanel("ly.img.foo") + + +} + + +const products = { + "instagram_story": { + kind: "story", + resolution: { + width: "1080px", height: "1920px" + }, + }, +} + + +export const productSetInstagram = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + const resolution = products.instagram_story.resolution; + const width = parseValueWithUnit(resolution.width) + const height = parseValueWithUnit(resolution.height) + + + blockIds.forEach((id: number) => { + const widthInDu = unitToDesignUnit(width.value, width.unit, ctx) + const heightInDu = unitToDesignUnit(height.value, height.unit, ctx) + console.log(widthInDu, heightInDu) + block.setHeight(id, heightInDu) + // block.setHeightMode(id, unitToMode(height.unit)) + block.setWidth(id, widthInDu) + // block.setWidthMode(id, unitToMode(width.unit)) + }) +} + +export const playground = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block, event, scene } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + // check distance to parent edges + type Distance = { + top: number; + left: number; + centerX: number; + centerY: number; + bottom: number; + right: number; + } + type Anchors = { + top: boolean; + left: boolean; + centerX: boolean; + centerY: boolean; + bottom: boolean; + right: boolean; + } + + const calcDistance = (fromId, toId) => { + const bId = fromId + const pId = toId + const bX = block.getGlobalBoundingBoxX(bId) + const bY = block.getGlobalBoundingBoxY(bId) + + const bWidth = block.getGlobalBoundingBoxWidth(bId) + const bheight = block.getGlobalBoundingBoxHeight(bId) + const bCenterX = bX + bWidth / 2 + const bCenterY = bY + bheight / 2 + + const pX = block.getGlobalBoundingBoxX(pId) + const pY = block.getGlobalBoundingBoxY(pId) + const pWidth = block.getGlobalBoundingBoxWidth(pId) + const pheight = block.getGlobalBoundingBoxHeight(pId) + const pCenterX = pX + pWidth / 2 + const pCenterY = pY + pheight / 2 + + const left = pX - bX + const top = pY - bY + const right = pX + pWidth - bX - bWidth + const bottom = pY + pheight - bY - bheight + const centerX = bCenterX - pCenterX + const centerY = bCenterY - pCenterY + + return { left, top, centerX, centerY, right, bottom } + } + + const distances = blockIds.map((bId: number): Distance => { + return calcDistance(bId, block.getParent(bId)); + }) + + + event.subscribe(blockIds, (events) => { + events.forEach((event) => { + switch (event.type) { + case "Created": break; + case "Updated": { + const pId = block.getParent(event.block) + const dist = calcDistance(event.block, pId) + const height = block.getGlobalBoundingBoxHeight(pId) + const width = block.getGlobalBoundingBoxWidth(pId) + console.log(width, height, dist) + const distInPercent = { + top: (dist.top / height) * 100, + left: (dist.left / width) * 100, + right: (dist.right / width) * 100, + bottom: (dist.bottom / height) * 100, + centerX: (dist.centerX / width) * 100, + centerY: (dist.centerY / height) * 100, + }; + console.log(JSON.stringify(distInPercent, null, 2)); + + const threshold = 1 // percent + const anchors: Anchors = { + top: Math.abs(distInPercent.top) < threshold, + left: Math.abs(distInPercent.left) < threshold, + right: Math.abs(distInPercent.right) < threshold, + bottom: Math.abs(distInPercent.bottom) < threshold, + centerX: Math.abs(distInPercent.centerX) < threshold, + centerY: Math.abs(distInPercent.centerY) < threshold, + } + console.log(JSON.stringify(anchors, null, 2)); + break; + } + case "Destroyed": break; + } + }) + + }) + + // snap to edge with offset + + +} + + + + + + + + + + + + +// Utils + + +type ValueWithUnit = { + value: number; + unit: string; +}; + +function parseValueWithUnit(string: string | number): ValueWithUnit | null { + const isNumber = typeof string === "number" + if (isNumber) { + return { + value: string, + unit: "" + } + } + const regex = /^(\d+(?:\.\d+)?)([a-z%]*)$/i; + const match = string.match(regex); + + if (match) { + return { + value: parseFloat(match[1]), + unit: match[2], + }; + } + return null; +} + +function unitToMode(unit: string) { + switch (unit) { + case "%": return "Percent" + case "px": + case "mm": + case "in": + default: return "Absolute" + } +} + + +function unitToDesignUnit(value: number, unit: string, ctx: PluginContext) { + switch (unit) { + case "%": return value + case "px": return pixelToDesignUnit(ctx.engine, value) + case "mm": return mmToDesignUnit(ctx.engine, value) + case "in": return inToDesignUnit(ctx.engine, value) + } +} + + + + + +const inToDesignUnit = (engine, inch) => { + const sceneId = engine.scene.get()! + const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); + const dpi = engine.block.getFloat(sceneId, 'scene/dpi') + + switch (sceneUnit) { + case "Millimeter": return inch * 2.54; + case "Inch": return inch; + case "Pixel": return inch * dpi; + } + +}; + + +const mmToDesignUnit = (engine, mm) => { + const sceneId = engine.scene.get()! + const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); + const dpi = engine.block.getFloat(sceneId, 'scene/dpi') + + switch (sceneUnit) { + case "Millimeter": return mm; + case "Inch": return mm / 25.4; + case "Pixel": return mm / 25.4 * dpi; + } + +}; + + +const pixelToDesignUnit = (engine, pixel) => { + const sceneId = engine.scene.get() + const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); + const dpi = engine.block.getFloat(sceneId, 'scene/dpi') + + switch (sceneUnit) { + case "Millimeter": return pixel * 25.4 / dpi; + case "Inch": return pixel / dpi; + case "Pixel": return pixel; + } +}; diff --git a/examples/web/src/plugins/imgly-commands/commands/syncStyle.ts b/packages/design-batteries/src/commands/syncStyle.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/commands/syncStyle.ts rename to packages/design-batteries/src/commands/syncStyle.ts diff --git a/examples/web/src/plugins/imgly-commands/index.ts b/packages/design-batteries/src/index.ts similarity index 88% rename from examples/web/src/plugins/imgly-commands/index.ts rename to packages/design-batteries/src/index.ts index dd9a707..459120a 100644 --- a/examples/web/src/plugins/imgly-commands/index.ts +++ b/packages/design-batteries/src/index.ts @@ -11,11 +11,15 @@ function registerTranslation(ctx: PluginContext, translations: { [key: string]: ctx.i18n.setTranslations(translations) } function registerCommands(ctx: PluginContext, imports: CommandImports) { + for (const command in imports) { const callback = imports[command as CommandContributions] + const desc = PluginManifest.contributes.commands[command as CommandContributions]; + const id = desc?.id ?? `${PluginManifest.id}.commands.${command as string}`; + console.log(id) ctx.commands.registerCommand( - desc.id, + id, async (params: any) => await callback(ctx, params), desc ); diff --git a/examples/web/src/plugins/imgly-commands/locale/en.json b/packages/design-batteries/src/locale/en.json similarity index 100% rename from examples/web/src/plugins/imgly-commands/locale/en.json rename to packages/design-batteries/src/locale/en.json diff --git a/examples/web/src/plugins/imgly-commands/types/types.ts b/packages/design-batteries/src/types/types.ts similarity index 100% rename from examples/web/src/plugins/imgly-commands/types/types.ts rename to packages/design-batteries/src/types/types.ts diff --git a/packages/design-batteries/src/utils/cesdk.ts b/packages/design-batteries/src/utils/cesdk.ts new file mode 100644 index 0000000..5ec22ca --- /dev/null +++ b/packages/design-batteries/src/utils/cesdk.ts @@ -0,0 +1,39 @@ +import { BlockAPI } from "@cesdk/cesdk-js"; + + +export const readPropValue = (block: BlockAPI, id: number, propKey: string, propType?: string) => { + const blacklist= ["fill/solid/color"] + if (blacklist.includes(propKey)) return undefined; + if (!propType) propType = block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return block.getString(id, propKey); + case "float": return block.getFloat(id, propKey); + case "double": return block.getDouble(id, propKey); + case "color": return block.getColor(id, propKey); + case "bool": return block.getBool(id, propKey); + case "enum": return block.getEnum(id, propKey); + } + } catch(e){ + console.warn("Error reading property value: ", e); + } + return undefined; +}; + + +export const writePropValue = (block: BlockAPI, id: number, propKey: string, propValue: any,propType?: string) => { + if (!propType) propType = block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return block.setString(id, propKey, propValue); + case "float": return block.setFloat(id, propKey, propValue); + case "double": return block.setDouble(id, propKey, propValue); + case "color": return block.setColor(id, propKey, propValue); + case "bool": return block.setBool(id, propKey, propValue); + case "enum": return block.setEnum(id, propKey, propValue); + } + } catch(e){ + console.warn("Error writing property: ", propKey, propType, propValue); + } + return undefined; +}; diff --git a/packages/design-batteries/src/utils/download.ts b/packages/design-batteries/src/utils/download.ts new file mode 100644 index 0000000..5f41fbe --- /dev/null +++ b/packages/design-batteries/src/utils/download.ts @@ -0,0 +1,29 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; + + +export function downloadBlob(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + link.click(); + URL.revokeObjectURL(url); +} +export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { + const postfix = options.mimeType.split("/")[1]; + const pageIds = options.pages ?? []; + + blobs.forEach((blob, index) => { + const pageId = pageIds[index]; + let pageName = `page-${index}`; + if (pageId) { + const name = cesdk.engine.block.getName(pageId); + pageName = name?.length ? name : pageName; + } + const filename = `${pageName}.${postfix}`; + downloadBlob(blob, filename); + }); + return Promise.resolve(); +}; + + diff --git a/packages/design-batteries/src/worker.ts b/packages/design-batteries/src/worker.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/tsconfig.json b/packages/design-batteries/tsconfig.json new file mode 100644 index 0000000..0d7577f --- /dev/null +++ b/packages/design-batteries/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "strict": false, + "target": "es2017", + "module": "es2020", + "lib": ["es2018", "dom"], + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "declaration": true, + "declarationDir": "types/", + "skipLibCheck": true + }, + "include": ["src/**/*", "esbuild/global.d.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/design-batteries/types/PluginManifest.d.ts b/packages/design-batteries/types/PluginManifest.d.ts new file mode 100644 index 0000000..9987f1c --- /dev/null +++ b/packages/design-batteries/types/PluginManifest.d.ts @@ -0,0 +1,124 @@ +import Manifest from '../manifest.json'; +import { CommandCallback } from '@imgly/plugin-api-utils'; +export type Contributions = typeof Manifest; +export type CommandContributions = keyof typeof Manifest["contributes"]["commands"]; +export type CommandImports = Record; +export declare const PluginManifest: { + id: string; + version: string; + publisher: string; + icon: any; + categories: any[]; + contributes: { + commands: { + blockDelete: { + id: string; + group: string; + }; + blockDuplicate: { + id: string; + group: string; + }; + exportPngToClipboard: { + id: string; + group: string; + }; + exportPngToFile: { + id: string; + group: string; + }; + exportJpegToFile: { + id: string; + group: string; + }; + exportWebpToFile: { + id: string; + group: string; + }; + exportRgba8ToFile: { + id: string; + group: string; + }; + exportPdfToFile: { + id: string; + group: string; + }; + exportSceneToFile: { + id: string; + group: string; + }; + exportSceneToClipboard: { + id: string; + group: string; + }; + exportJsonToClipboard: { + id: string; + group: string; + }; + exportJsonToFile: { + id: string; + group: string; + }; + exportComponentToFile: { + id: string; + group: string; + }; + imageFitModeCrop: { + id: string; + group: string; + }; + imageFitModeContain: { + id: string; + group: string; + }; + imageFitModeCover: { + id: string; + group: string; + }; + groupBlocks: { + id: string; + group: string; + }; + ungroupBlocks: { + id: string; + group: string; + }; + groupLayoutHStack: { + id: string; + group: string; + }; + groupLayoutVStack: { + id: string; + group: string; + }; + groupLayoutMasonry: { + id: string; + group: string; + }; + groupLayoutCircle: { + id: string; + group: string; + when: { + blockType: string[]; + }; + }; + logCrop: { + id: string; + group: string; + }; + productSetInstagram: { + id: string; + group: string; + }; + playground: { + id: string; + group: string; + }; + syncBlocks: { + id: string; + group: string; + }; + }; + i18n: {}; + }; +}; diff --git a/packages/design-batteries/types/commands.d.ts b/packages/design-batteries/types/commands.d.ts new file mode 100644 index 0000000..82c672c --- /dev/null +++ b/packages/design-batteries/types/commands.d.ts @@ -0,0 +1,6 @@ +export * from "./commands/lifecycle"; +export * from "./commands/export"; +export * from "./commands/image"; +export * from "./commands/container"; +export * from "./commands/magic"; +export * from "./commands/playground"; diff --git a/packages/design-batteries/types/commands/__template.d.ts b/packages/design-batteries/types/commands/__template.d.ts new file mode 100644 index 0000000..5fd6f48 --- /dev/null +++ b/packages/design-batteries/types/commands/__template.d.ts @@ -0,0 +1,3 @@ +declare const __template: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/clipboard.d.ts b/packages/design-batteries/types/commands/clipboard.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/types/commands/container.d.ts b/packages/design-batteries/types/commands/container.d.ts new file mode 100644 index 0000000..bb12dc6 --- /dev/null +++ b/packages/design-batteries/types/commands/container.d.ts @@ -0,0 +1,24 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const groupBlocks: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const ungroupBlocks: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const groupLayoutHStack: (ctx: PluginContext, params: { + blockIds?: number[]; + padding?: number; +}) => Promise; +export declare const groupLayoutVStack: (ctx: PluginContext, params: { + blockIds?: number[]; + padding?: number; +}) => Promise; +export declare const groupLayoutMasonry: (ctx: PluginContext, params: { + blockIds?: number[]; + cols?: number; + paddingX?: number; + paddingY?: number; +}) => Promise; +export declare const groupLayoutCircle: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/copyStyle.d.ts b/packages/design-batteries/types/commands/copyStyle.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/types/commands/debug.d.ts b/packages/design-batteries/types/commands/debug.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/types/commands/export.d.ts b/packages/design-batteries/types/commands/export.d.ts new file mode 100644 index 0000000..e77398e --- /dev/null +++ b/packages/design-batteries/types/commands/export.d.ts @@ -0,0 +1,34 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const exportPngToClipboard: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportSceneToClipboard: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportJsonToClipboard: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportPngToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportJpegToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportWebpToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportPdfToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportRgba8ToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportSceneToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportJsonToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const exportComponentToFile: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/image.d.ts b/packages/design-batteries/types/commands/image.d.ts new file mode 100644 index 0000000..3d52777 --- /dev/null +++ b/packages/design-batteries/types/commands/image.d.ts @@ -0,0 +1,10 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const imageFitModeCrop: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const imageFitModeCover: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const imageFitModeContain: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/lifecycle.d.ts b/packages/design-batteries/types/commands/lifecycle.d.ts new file mode 100644 index 0000000..53d6692 --- /dev/null +++ b/packages/design-batteries/types/commands/lifecycle.d.ts @@ -0,0 +1,7 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const blockDelete: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const blockDuplicate: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/magic.d.ts b/packages/design-batteries/types/commands/magic.d.ts new file mode 100644 index 0000000..3045a80 --- /dev/null +++ b/packages/design-batteries/types/commands/magic.d.ts @@ -0,0 +1,4 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const logCrop: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => void; diff --git a/packages/design-batteries/types/commands/old_debug.d.ts b/packages/design-batteries/types/commands/old_debug.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/types/commands/playground.d.ts b/packages/design-batteries/types/commands/playground.d.ts new file mode 100644 index 0000000..af213b2 --- /dev/null +++ b/packages/design-batteries/types/commands/playground.d.ts @@ -0,0 +1,13 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const syncBlocks: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const registerAndOpenCustomPanel: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const productSetInstagram: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const playground: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/syncStyle.d.ts b/packages/design-batteries/types/commands/syncStyle.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/design-batteries/types/index.d.ts b/packages/design-batteries/types/index.d.ts new file mode 100644 index 0000000..b0acb9a --- /dev/null +++ b/packages/design-batteries/types/index.d.ts @@ -0,0 +1,7 @@ +import { PluginContext } from '@imgly/plugin-api-utils'; +export interface PluginConfiguration { +} +declare const _default: (ctx: PluginContext, _config: PluginConfiguration) => { + initializeUserInterface(): Promise; +}; +export default _default; diff --git a/packages/design-batteries/types/types/types.d.ts b/packages/design-batteries/types/types/types.d.ts new file mode 100644 index 0000000..3053eb1 --- /dev/null +++ b/packages/design-batteries/types/types/types.d.ts @@ -0,0 +1,4 @@ +export type Unsubscribe = () => void; +export type CommandArg = { + blockIds: number[] | undefined; +}; diff --git a/packages/design-batteries/types/utils/cesdk.d.ts b/packages/design-batteries/types/utils/cesdk.d.ts new file mode 100644 index 0000000..4fb52e8 --- /dev/null +++ b/packages/design-batteries/types/utils/cesdk.d.ts @@ -0,0 +1,3 @@ +import { BlockAPI } from "@cesdk/cesdk-js"; +export declare const readPropValue: (block: BlockAPI, id: number, propKey: string, propType?: string) => string | number | boolean | (import("@cesdk/cesdk-js").RGBAColor | import("@cesdk/cesdk-js").CMYKColor | import("@cesdk/cesdk-js").SpotColor); +export declare const writePropValue: (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => void; diff --git a/packages/design-batteries/types/utils/download.d.ts b/packages/design-batteries/types/utils/download.d.ts new file mode 100644 index 0000000..3c70083 --- /dev/null +++ b/packages/design-batteries/types/utils/download.d.ts @@ -0,0 +1,6 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; +export declare function downloadBlob(blob: Blob, filename: string): void; +export declare const downloadBlocks: (cesdk: CreativeEditorSDK, blobs: Blob[], options: { + mimeType: string; + pages?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/worker.d.ts b/packages/design-batteries/types/worker.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/vectorizer/types/PluginManifest.d.ts b/packages/vectorizer/types/PluginManifest.d.ts index b723c5a..7913e0c 100644 --- a/packages/vectorizer/types/PluginManifest.d.ts +++ b/packages/vectorizer/types/PluginManifest.d.ts @@ -32,6 +32,7 @@ export declare const PluginManifest: { vectorize: { id: string; label: string; + group: string; args: { type: string; format: string; diff --git a/packages/vectorizer/types/index.d.ts b/packages/vectorizer/types/index.d.ts index 67e3daa..0cc8e20 100644 --- a/packages/vectorizer/types/index.d.ts +++ b/packages/vectorizer/types/index.d.ts @@ -31,6 +31,7 @@ declare const _default: (ctx: PluginContext, pluginConfiguration: PluginConfigur vectorize: { id: string; label: string; + group: string; args: { type: string; format: string; diff --git a/yarn.lock b/yarn.lock index 5b66b66..88eb74c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -220,10 +220,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@cesdk/cesdk-js@^1.20.0": - version "1.20.0" - resolved "https://registry.npmjs.org/@cesdk/cesdk-js/-/cesdk-js-1.20.0.tgz" - integrity sha512-vKDcnv5z5TZe1PcgvZagJ7QXVyijeTnkwPCJJFj/Uxcsef9GvLrzOVIYqPC0gqZuDlfHpADPsGAV+pZaZg8+eg== +"@cesdk/cesdk-js@^1.21.0": + version "1.21.1" + resolved "https://registry.yarnpkg.com/@cesdk/cesdk-js/-/cesdk-js-1.21.1.tgz#b3e4d4b584d0623bae584210098244d8d874c838" + integrity sha512-TQSDHjszpITGq1jj6985r59eZwJkoUjtxcmGj+scjX+gORfAN7jfzl8xGp8gvMl7/tX7i+Xhym74A0Qrq9g6Tw== "@colors/colors@1.5.0": version "1.5.0" From 34cfd3d5b4d799d91cc5715b4b0dc621bf653887 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 1 Mar 2024 19:30:10 +0100 Subject: [PATCH 26/32] wip --- packages/design-batteries/manifest.json | 28 +--- .../design-batteries/src/commands/export.ts | 123 +++++++++++++----- .../src/commands/playground.ts | 3 +- packages/design-batteries/src/index.ts | 8 +- packages/design-batteries/src/locale/en.json | 34 ++--- .../design-batteries/src/utils/download.ts | 28 ++++ .../types/PluginManifest.d.ts | 26 ---- 7 files changed, 145 insertions(+), 105 deletions(-) diff --git a/packages/design-batteries/manifest.json b/packages/design-batteries/manifest.json index b18af9e..2b83d8b 100644 --- a/packages/design-batteries/manifest.json +++ b/packages/design-batteries/manifest.json @@ -1,5 +1,5 @@ { - "id": "plugin", + "id": "design-batteries", "version": "1.0.0", "publisher": "IMG.LY GmbH", "icon": null, @@ -7,110 +7,84 @@ "contributes": { "commands": { "blockDelete": { - "id": "plugin.commands.blockDelete", "group": "lifecycle" }, "blockDuplicate": { - "id": "plugin.commands.blockDuplicate", "group": "lifecycle" }, "exportPngToClipboard": { - "id": "plugin.commands.exportPngToClipboard", "group": "export" }, "exportPngToFile": { - "id": "plugin.commands.exportPngToFile", "group": "export" }, "exportJpegToFile": { - "id": "plugin.commands.exportJpegToFile", "group": "export" }, "exportWebpToFile": { - "id": "plugin.commands.exportWebpToFile", "group": "export" }, "exportRgba8ToFile": { - "id": "plugin.commands.exportRgba8ToFile", "group": "export" }, "exportPdfToFile": { - "id": "plugin.commands.exportPdfToFile", "group": "export" }, "exportSceneToFile": { - "id": "plugin.commands.exportSceneToFile", "group": "export" }, "exportSceneToClipboard": { - "id": "plugin.commands.exportSceneToClipboard", "group": "export" }, "exportJsonToClipboard": { - "id": "plugin.commands.exportJSONToClipboard", "group": "export" }, "exportJsonToFile": { - "id": "plugin.commands.exportJSONToFile", "group": "export" }, "exportComponentToFile": { - "id": "plugin.commands.exportComponentToFile", "group": "export" }, "imageFitModeCrop": { - "id": "plugin.commands.imageFitModeCrop", "group": "image" }, "imageFitModeContain": { - "id": "plugin.commands.imageFitModeContain", "group": "image" }, "imageFitModeCover": { - "id": "plugin.commands.imageFitModeCover", "group": "image" }, "groupBlocks": { - "id": "plugin.commands.groupBlock", "group": "group" }, "ungroupBlocks": { - "id": "plugin.commands.ungroupBlock", "group": "group" }, "groupLayoutHStack": { - "id": "plugin.commands.groupLayoutHStack", "group": "group" }, "groupLayoutVStack": { - "id": "plugin.commands.groupLayoutVStack", "group": "group" }, "groupLayoutMasonry": { - "id": "plugin.commands.groupLayoutMasonry", "group": "group" }, "groupLayoutCircle": { - "id": "plugin.commands.groupLayoutCircle", "group": "group", "when": { "blockType": ["group"] } }, "logCrop": { - "id": "plugin.commands.logCrop", "group": "image" }, "productSetInstagram": { - "id": "plugin.commands.productSetInstagram", "group": "product" }, "playground": { - "id": "plugin.commands.playground", "group": "playground" }, "syncBlocks": { - "id": "plugin.commands.syncBlocks", "group": "lifecycle" } }, diff --git a/packages/design-batteries/src/commands/export.ts b/packages/design-batteries/src/commands/export.ts index 4d7bd74..0c2957a 100644 --- a/packages/design-batteries/src/commands/export.ts +++ b/packages/design-batteries/src/commands/export.ts @@ -1,39 +1,24 @@ import { PluginContext } from "@imgly/plugin-api-utils"; import { MimeType } from "@cesdk/cesdk-js"; -import { downloadBlob } from "../utils/download"; +import { downloadBlob, loadAsBlob } from "../utils/download"; -// const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const myNewFunctionForTheEditor = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const {block, scene} = ctx.engine; + + const pId = scene.getCurrentPage() + + const bId = block.create("//ly.img.ubq/text") + block.setName(bId, "Hello World") + block.setTextColor(bId, {r: 1, g: 0, b: 0, a: 1}) + block.replaceText(bId, "Hello World") + + + block.appendChild(pId, bId) + +} -const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - mimeType = "image/png" as MimeType, - width, - height - } = params; - blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - return await Promise.all(blockIds.map(async (bId: number) => { - switch (mimeType) { - case "application/x-cesdk": { - const str = await block.saveToString([bId]); - return new Blob([str], { type: mimeType }); - - } - case "application/json": { - const str = await block.saveToString([bId]); - const json = str.substring(4) - const decoded = atob(json) - return new Blob([decoded], { type: mimeType }); - - } - default: - return await block.export(bId, mimeType, {targetHeight: height, targetWidth: width}); - } - })); -}; export const exportPngToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { @@ -127,14 +112,88 @@ export const exportComponentToFile = async (ctx: PluginContext, params: { blockI const filename = inferBlockName(ctx, blockId) downloadBlob(data.thumbnail, `${filename}.png`) downloadBlob(data.cesdk, `${filename}.cesdk`) - downloadBlob(data.json, `${filename}.json`) }); } +export const importComponent = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { engine } = ctx; + const { editor, scene, block } = engine; + + + const data = await loadAsBlob() + const str = await data.text() + const bIds = await ctx.engine.block.loadFromString(str) + + const pId = scene.getCurrentPage() + bIds.forEach((bId) => { + const name = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId) + console.log("Inserting Block", name) + block.appendChild(pId, bId) + }) + + + + + +} +export const exportComponentLibrary = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const libs = block.findByType("//ly.img.ubq/page") + const libNames = libs.map((id) => block.getName(id) || block.getUUID(id)); + + libs.forEach(async (pId, pIdx) => { + const pName = block.getName(pId) || block.getUUID(pId) + const bIds = block.getChildren(pId); + bIds.forEach(async (bId, bIdx) => { + const bName = block.getName(bId) || block.getUUID(bId); + const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }) + const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }) + const filename = `${pName}-${bName}` + downloadBlob(thumbnail[0], `${filename}.png`) + downloadBlob(cesdk[0], `${filename}.cesdk`) + }) + }) + + +} + +// Utils + const inferBlockName = (ctx: PluginContext, blockId: number) => { const { block } = ctx.engine; const uuid = block.getUUID(blockId); const name = block.getName(blockId) return name || uuid || blockId -} \ No newline at end of file +} + +const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + mimeType = "image/png" as MimeType, + width, + height + } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + return await Promise.all(blockIds.map(async (bId: number) => { + switch (mimeType) { + case "application/x-cesdk": { + const str = await block.saveToString([bId]); + return new Blob([str], { type: mimeType }); + + } + case "application/json": { + const str = await block.saveToString([bId]); + const json = str.substring(4) + const decoded = atob(json) + return new Blob([decoded], { type: mimeType }); + + } + default: + return await block.export(bId, mimeType, { targetHeight: height, targetWidth: width }); + } + + })); +}; + diff --git a/packages/design-batteries/src/commands/playground.ts b/packages/design-batteries/src/commands/playground.ts index 03131ff..3ca89b3 100644 --- a/packages/design-batteries/src/commands/playground.ts +++ b/packages/design-batteries/src/commands/playground.ts @@ -34,6 +34,7 @@ export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number const properties = [ "opacity", "blend/mode", "rotation", 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y'] + const unsubscribe = event.subscribe(blockIds, (events) => { events.forEach((event) => { const bId = event.block; @@ -71,8 +72,6 @@ export const registerAndOpenCustomPanel = async (ctx: PluginContext, params: { b }); ui.openPanel("ly.img.foo") - - } diff --git a/packages/design-batteries/src/index.ts b/packages/design-batteries/src/index.ts index 459120a..2ee2877 100644 --- a/packages/design-batteries/src/index.ts +++ b/packages/design-batteries/src/index.ts @@ -12,12 +12,16 @@ function registerTranslation(ctx: PluginContext, translations: { [key: string]: } function registerCommands(ctx: PluginContext, imports: CommandImports) { +type CommandDescription = { + id?: string, + group?: string +} + for (const command in imports) { const callback = imports[command as CommandContributions] - const desc = PluginManifest.contributes.commands[command as CommandContributions]; + const desc: CommandDescription = PluginManifest.contributes.commands[command as CommandContributions]; const id = desc?.id ?? `${PluginManifest.id}.commands.${command as string}`; - console.log(id) ctx.commands.registerCommand( id, async (params: any) => await callback(ctx, params), diff --git a/packages/design-batteries/src/locale/en.json b/packages/design-batteries/src/locale/en.json index 185492f..c533142 100644 --- a/packages/design-batteries/src/locale/en.json +++ b/packages/design-batteries/src/locale/en.json @@ -1,21 +1,23 @@ { - "plugin.commands.blockDelete": "Delete Block", - "plugin.commands.blockDuplicate": "Duplicate Block", - "plugin.commands.exportPngToClipboard": "Export PNG to Clipboard", - "plugin.commands.exportPngToFile": "Export PNG to File", - "plugin.commands.exportJpegToFile": "Export JPEG to File", - "plugin.commands.exportWebpToFile": "Export WEP to File", - "plugin.commands.exportPdfToFile": "Export PDF to File", - "plugin.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", + "design-batteries.commands.blockDelete": "Delete Block", + "design-batteries.commands.blockDuplicate": "Duplicate Block", + "design-batteries.commands.exportPngToClipboard": "Export PNG to Clipboard", + "design-batteries.commands.exportPngToFile": "Export PNG to File", + "design-batteries.commands.exportJpegToFile": "Export JPEG to File", + "design-batteries.commands.exportWebpToFile": "Export WEP to File", + "design-batteries.commands.exportPdfToFile": "Export PDF to File", + "design-batteries.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", - "plugin.commands.exportSceneToClipboard": "Export Scene to Clipboard", - "plugin.commands.exportJSONToClipboard": "Export JSON to Clipboard", - "plugin.commands.exportSceneToFile": "Export Scene to File", - "plugin.commands.exportJSONToFile": "Export JSON to File", + "design-batteries.commands.exportSceneToClipboard": "Export Scene to Clipboard", + "design-batteries.commands.exportJsonToClipboard": "Export JSON to Clipboard", + "design-batteries.commands.exportSceneToFile": "Export Scene to File", + "design-batteries.commands.exportJsonToFile": "Export JSON to File", - "plugin.commands.imageFitModeContain": "Set Image FitMode to Contain", - "plugin.commands.imageFitModeCrop": "Set Image FitMode to Crop", - "plugin.commands.imageFitModeCover": "Set Image FitMode to Cover", + "design-batteries.commands.imageFitModeContain": "Set Image FitMode to Contain", + "design-batteries.commands.imageFitModeCrop": "Set Image FitMode to Crop", + "design-batteries.commands.imageFitModeCover": "Set Image FitMode to Cover", + + "design-batteries.commands.exportComponentToFile": "Export Component to File" , + "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function" - "plugin.commands.exportComponentToFile": "Export Component to File" } \ No newline at end of file diff --git a/packages/design-batteries/src/utils/download.ts b/packages/design-batteries/src/utils/download.ts index 5f41fbe..63568d0 100644 --- a/packages/design-batteries/src/utils/download.ts +++ b/packages/design-batteries/src/utils/download.ts @@ -1,6 +1,34 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; + +export async function loadAsBlob() { + return new Promise((resolve, reject) => { + const upload = document.createElement("input"); + upload.setAttribute("type", "file"); + upload.setAttribute("accept", "*") + upload.setAttribute("style", "display: none") + upload.onchange = (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + const buffer = e.target?.result + if (buffer instanceof ArrayBuffer) { + const blob = new Blob([buffer]); + resolve(blob) + } else { + reject(new Error("Invalid buffer")) + } + } + reader.readAsArrayBuffer(file); + } + } + + upload.click() + }) +} + export function downloadBlob(blob: Blob, filename: string) { const url = URL.createObjectURL(blob); const link = document.createElement("a"); diff --git a/packages/design-batteries/types/PluginManifest.d.ts b/packages/design-batteries/types/PluginManifest.d.ts index 9987f1c..21da90d 100644 --- a/packages/design-batteries/types/PluginManifest.d.ts +++ b/packages/design-batteries/types/PluginManifest.d.ts @@ -12,110 +12,84 @@ export declare const PluginManifest: { contributes: { commands: { blockDelete: { - id: string; group: string; }; blockDuplicate: { - id: string; group: string; }; exportPngToClipboard: { - id: string; group: string; }; exportPngToFile: { - id: string; group: string; }; exportJpegToFile: { - id: string; group: string; }; exportWebpToFile: { - id: string; group: string; }; exportRgba8ToFile: { - id: string; group: string; }; exportPdfToFile: { - id: string; group: string; }; exportSceneToFile: { - id: string; group: string; }; exportSceneToClipboard: { - id: string; group: string; }; exportJsonToClipboard: { - id: string; group: string; }; exportJsonToFile: { - id: string; group: string; }; exportComponentToFile: { - id: string; group: string; }; imageFitModeCrop: { - id: string; group: string; }; imageFitModeContain: { - id: string; group: string; }; imageFitModeCover: { - id: string; group: string; }; groupBlocks: { - id: string; group: string; }; ungroupBlocks: { - id: string; group: string; }; groupLayoutHStack: { - id: string; group: string; }; groupLayoutVStack: { - id: string; group: string; }; groupLayoutMasonry: { - id: string; group: string; }; groupLayoutCircle: { - id: string; group: string; when: { blockType: string[]; }; }; logCrop: { - id: string; group: string; }; productSetInstagram: { - id: string; group: string; }; playground: { - id: string; group: string; }; syncBlocks: { - id: string; group: string; }; }; From 38875f9d0f6a73642b90606b0db600111f8de112 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Fri, 1 Mar 2024 19:41:13 +0100 Subject: [PATCH 27/32] wip --- packages/design-batteries/.gitignore | 11 +++ .../src/commands/container.ts | 2 +- .../design-batteries/src/commands/export.ts | 33 ++++----- .../src/commands/playground.ts | 73 +++++++++---------- .../types/commands/export.d.ts | 9 +++ .../types/commands/playground.d.ts | 2 +- .../types/utils/download.d.ts | 1 + 7 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 packages/design-batteries/.gitignore diff --git a/packages/design-batteries/.gitignore b/packages/design-batteries/.gitignore new file mode 100644 index 0000000..9060c20 --- /dev/null +++ b/packages/design-batteries/.gitignore @@ -0,0 +1,11 @@ +node_modules +packages/*/dist +examples/*/dist +.env.local + +.DS_Store +yarn-error.log + +.turbo +.vercel +types \ No newline at end of file diff --git a/packages/design-batteries/src/commands/container.ts b/packages/design-batteries/src/commands/container.ts index bc67826..312eda4 100644 --- a/packages/design-batteries/src/commands/container.ts +++ b/packages/design-batteries/src/commands/container.ts @@ -1,5 +1,5 @@ import { PluginContext } from "@imgly/plugin-api-utils"; -import { toInteger, toSafeInteger } from "lodash"; +import { toSafeInteger } from "lodash"; diff --git a/packages/design-batteries/src/commands/export.ts b/packages/design-batteries/src/commands/export.ts index 0c2957a..1ce70c2 100644 --- a/packages/design-batteries/src/commands/export.ts +++ b/packages/design-batteries/src/commands/export.ts @@ -3,14 +3,14 @@ import { MimeType } from "@cesdk/cesdk-js"; import { downloadBlob, loadAsBlob } from "../utils/download"; -export const myNewFunctionForTheEditor = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const {block, scene} = ctx.engine; +export const myNewFunctionForTheEditor = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + const { block, scene } = ctx.engine; - const pId = scene.getCurrentPage() + const pId = scene.getCurrentPage()! const bId = block.create("//ly.img.ubq/text") block.setName(bId, "Hello World") - block.setTextColor(bId, {r: 1, g: 0, b: 0, a: 1}) + block.setTextColor(bId, { r: 1, g: 0, b: 0, a: 1 }) block.replaceText(bId, "Hello World") @@ -115,36 +115,35 @@ export const exportComponentToFile = async (ctx: PluginContext, params: { blockI }); } -export const importComponent = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const importComponent = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { engine } = ctx; - const { editor, scene, block } = engine; - - + const { scene, block } = engine; + + const data = await loadAsBlob() - const str = await data.text() + const str = await data.text() const bIds = await ctx.engine.block.loadFromString(str) - - const pId = scene.getCurrentPage() + + const pId = scene.getCurrentPage()! bIds.forEach((bId) => { const name = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId) console.log("Inserting Block", name) block.appendChild(pId, bId) }) - - + + } -export const exportComponentLibrary = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const exportComponentLibrary = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { block } = ctx.engine; const libs = block.findByType("//ly.img.ubq/page") - const libNames = libs.map((id) => block.getName(id) || block.getUUID(id)); - libs.forEach(async (pId, pIdx) => { + libs.forEach(async (pId) => { const pName = block.getName(pId) || block.getUUID(pId) const bIds = block.getChildren(pId); - bIds.forEach(async (bId, bIdx) => { + bIds.forEach(async (bId) => { const bName = block.getName(bId) || block.getUUID(bId); const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }) const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }) diff --git a/packages/design-batteries/src/commands/playground.ts b/packages/design-batteries/src/commands/playground.ts index 3ca89b3..b647b9b 100644 --- a/packages/design-batteries/src/commands/playground.ts +++ b/packages/design-batteries/src/commands/playground.ts @@ -3,10 +3,7 @@ import { PluginContext } from "@imgly/plugin-api-utils"; import { readPropValue, writePropValue } from "../utils/cesdk"; -import { createElement } from "react"; -// Idea sync by name... if two have the same name, they sync - - +import { CreativeEngine } from "@cesdk/cesdk-js"; const syncProperties = (ctx: PluginContext, propertyKeys: string[], sourceId: number, destIds: number[]) => { @@ -34,14 +31,14 @@ export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number const properties = [ "opacity", "blend/mode", "rotation", 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y'] - + const unsubscribe = event.subscribe(blockIds, (events) => { events.forEach((event) => { const bId = event.block; switch (event.type) { case 'Created': { // throw new Error("Not implemented") - // break; + break; } case 'Updated': { syncProperties(ctx, properties, bId, blockIds) @@ -62,16 +59,16 @@ export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number } -export const registerAndOpenCustomPanel = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const registerAndOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { ui } = ctx; - ui.unstable_registerCustomPanel('ly.img.foo', (domElement) => { + ui?.unstable_registerCustomPanel('ly.img.foo', (domElement) => { domElement.appendChild(document.createTextNode('Hello World')); return () => { console.log('Apps disposer called'); }; }); - ui.openPanel("ly.img.foo") + ui?.openPanel("ly.img.foo") } @@ -91,12 +88,12 @@ export const productSetInstagram = async (ctx: PluginContext, params: { blockIds const resolution = products.instagram_story.resolution; const width = parseValueWithUnit(resolution.width) const height = parseValueWithUnit(resolution.height) - + if (!width || !height) return blockIds.forEach((id: number) => { const widthInDu = unitToDesignUnit(width.value, width.unit, ctx) const heightInDu = unitToDesignUnit(height.value, height.unit, ctx) - console.log(widthInDu, heightInDu) + if (!widthInDu || !heightInDu) return block.setHeight(id, heightInDu) // block.setHeightMode(id, unitToMode(height.unit)) block.setWidth(id, widthInDu) @@ -105,18 +102,18 @@ export const productSetInstagram = async (ctx: PluginContext, params: { blockIds } export const playground = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block, event, scene } = ctx.engine; + const { block, event } = ctx.engine; const { blockIds = block.findAllSelected() } = params; // check distance to parent edges - type Distance = { - top: number; - left: number; - centerX: number; - centerY: number; - bottom: number; - right: number; - } + // type _Distance = { + // top: number; + // left: number; + // centerX: number; + // centerY: number; + // bottom: number; + // right: number; + // } type Anchors = { top: boolean; left: boolean; @@ -126,7 +123,7 @@ export const playground = async (ctx: PluginContext, params: { blockIds?: number right: boolean; } - const calcDistance = (fromId, toId) => { + const calcDistance = (fromId: number, toId: number) => { const bId = fromId const pId = toId const bX = block.getGlobalBoundingBoxX(bId) @@ -154,9 +151,9 @@ export const playground = async (ctx: PluginContext, params: { blockIds?: number return { left, top, centerX, centerY, right, bottom } } - const distances = blockIds.map((bId: number): Distance => { - return calcDistance(bId, block.getParent(bId)); - }) + // const distances = blockIds.map((bId: number): Distance => { + // return calcDistance(bId, block.getParent(bId)); + // }) event.subscribe(blockIds, (events) => { @@ -164,7 +161,7 @@ export const playground = async (ctx: PluginContext, params: { blockIds?: number switch (event.type) { case "Created": break; case "Updated": { - const pId = block.getParent(event.block) + const pId = block.getParent(event.block)! const dist = calcDistance(event.block, pId) const height = block.getGlobalBoundingBoxHeight(pId) const width = block.getGlobalBoundingBoxWidth(pId) @@ -241,15 +238,15 @@ function parseValueWithUnit(string: string | number): ValueWithUnit | null { return null; } -function unitToMode(unit: string) { - switch (unit) { - case "%": return "Percent" - case "px": - case "mm": - case "in": - default: return "Absolute" - } -} +// function unitToMode(unit: string) { +// switch (unit) { +// case "%": return "Percent" +// case "px": +// case "mm": +// case "in": +// default: return "Absolute" +// } +// } function unitToDesignUnit(value: number, unit: string, ctx: PluginContext) { @@ -265,7 +262,7 @@ function unitToDesignUnit(value: number, unit: string, ctx: PluginContext) { -const inToDesignUnit = (engine, inch) => { +const inToDesignUnit = (engine: CreativeEngine, inch: number) => { const sceneId = engine.scene.get()! const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); const dpi = engine.block.getFloat(sceneId, 'scene/dpi') @@ -279,7 +276,7 @@ const inToDesignUnit = (engine, inch) => { }; -const mmToDesignUnit = (engine, mm) => { +const mmToDesignUnit = (engine: CreativeEngine, mm: number) => { const sceneId = engine.scene.get()! const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); const dpi = engine.block.getFloat(sceneId, 'scene/dpi') @@ -293,8 +290,8 @@ const mmToDesignUnit = (engine, mm) => { }; -const pixelToDesignUnit = (engine, pixel) => { - const sceneId = engine.scene.get() +const pixelToDesignUnit = (engine: CreativeEngine, pixel: number) => { + const sceneId = engine.scene.get()! const sceneUnit = engine.block.getEnum(sceneId, 'scene/designUnit'); const dpi = engine.block.getFloat(sceneId, 'scene/dpi') diff --git a/packages/design-batteries/types/commands/export.d.ts b/packages/design-batteries/types/commands/export.d.ts index e77398e..b6ffdfd 100644 --- a/packages/design-batteries/types/commands/export.d.ts +++ b/packages/design-batteries/types/commands/export.d.ts @@ -1,4 +1,7 @@ import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const myNewFunctionForTheEditor: (ctx: PluginContext, _params: { + blockIds?: number[]; +}) => Promise; export declare const exportPngToClipboard: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; @@ -32,3 +35,9 @@ export declare const exportJsonToFile: (ctx: PluginContext, params: { export declare const exportComponentToFile: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; +export declare const importComponent: (ctx: PluginContext, _params: { + blockIds?: number[]; +}) => Promise; +export declare const exportComponentLibrary: (ctx: PluginContext, _params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/playground.d.ts b/packages/design-batteries/types/commands/playground.d.ts index af213b2..e98beff 100644 --- a/packages/design-batteries/types/commands/playground.d.ts +++ b/packages/design-batteries/types/commands/playground.d.ts @@ -2,7 +2,7 @@ import { PluginContext } from "@imgly/plugin-api-utils"; export declare const syncBlocks: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; -export declare const registerAndOpenCustomPanel: (ctx: PluginContext, params: { +export declare const registerAndOpenCustomPanel: (ctx: PluginContext, _params: { blockIds?: number[]; }) => Promise; export declare const productSetInstagram: (ctx: PluginContext, params: { diff --git a/packages/design-batteries/types/utils/download.d.ts b/packages/design-batteries/types/utils/download.d.ts index 3c70083..b2dbcee 100644 --- a/packages/design-batteries/types/utils/download.d.ts +++ b/packages/design-batteries/types/utils/download.d.ts @@ -1,4 +1,5 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; +export declare function loadAsBlob(): Promise; export declare function downloadBlob(blob: Blob, filename: string): void; export declare const downloadBlocks: (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; From 06feae3d4607a795d26269c7c47261a18e39f9fd Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sat, 2 Mar 2024 14:55:36 +0100 Subject: [PATCH 28/32] Onto Sync --- examples/web/src/App.tsx | 37 +++-- .../web/src/components/CommandPalette.tsx | 13 +- .../web/src/components/CreativeEditorSDK.tsx | 2 +- examples/web/src/utils/download.ts | 6 +- packages/api-utils/package.json | 2 +- packages/api-utils/src/index.ts | 2 +- packages/api-utils/src/plugin/Commands.ts | 22 +-- packages/api-utils/src/plugin/I18n.ts | 33 +++- packages/api-utils/types/index.d.ts | 2 +- packages/api-utils/types/plugin/Commands.d.ts | 5 +- packages/api-utils/types/plugin/I18n.d.ts | 3 + packages/background-removal/package.json | 2 +- packages/design-batteries/manifest.json | 63 ++++---- packages/design-batteries/src/commands.ts | 9 +- .../src/commands/clipboard.ts | 54 ------- .../src/commands/components.ts | 76 ++++++++++ .../src/commands/container.ts | 143 ------------------ .../src/commands/copyStyle.ts | 84 ---------- .../design-batteries/src/commands/debug.ts | 60 ++++++++ .../design-batteries/src/commands/export.ts | 129 +--------------- .../design-batteries/src/commands/i18n.ts | 21 +++ .../design-batteries/src/commands/layout.ts | 104 +++++++++++++ .../src/commands/lifecycle.ts | 44 +++++- .../design-batteries/src/commands/magic.ts | 27 ---- .../src/commands/playground.ts | 71 ++++++--- .../design-batteries/src/commands/plugins.ts | 14 ++ .../src/commands/syncStyle.ts | 123 --------------- packages/design-batteries/src/index.ts | 56 ++++--- packages/design-batteries/src/locale/en.json | 28 +++- .../src/utils/computeBlockName.ts | 8 + .../src/utils/computeMultiSelectionBounds.ts | 20 +++ .../design-batteries/src/utils/download.ts | 7 +- .../src/utils/exportBlockAs.ts | 34 +++++ .../types/PluginManifest.d.ts | 63 ++++---- packages/design-batteries/types/commands.d.ts | 5 +- .../types/commands/clipboard.d.ts | 0 .../types/commands/container.d.ts | 17 --- .../types/commands/copyStyle.d.ts | 0 .../types/commands/debug.d.ts | 10 ++ .../types/commands/export.d.ts | 12 -- .../types/commands/lifecycle.d.ts | 15 ++ .../types/commands/magic.d.ts | 4 - .../types/commands/playground.d.ts | 2 +- .../types/commands/syncStyle.d.ts | 0 packages/design-batteries/types/index.d.ts | 1 + .../types/utils/download.d.ts | 2 +- packages/vectorizer/package.json | 2 +- packages/vectorizer/src/commands.ts | 3 - 48 files changed, 673 insertions(+), 767 deletions(-) delete mode 100644 packages/design-batteries/src/commands/clipboard.ts create mode 100644 packages/design-batteries/src/commands/components.ts delete mode 100644 packages/design-batteries/src/commands/copyStyle.ts create mode 100644 packages/design-batteries/src/commands/i18n.ts create mode 100644 packages/design-batteries/src/commands/layout.ts create mode 100644 packages/design-batteries/src/commands/plugins.ts delete mode 100644 packages/design-batteries/src/commands/syncStyle.ts create mode 100644 packages/design-batteries/src/utils/computeBlockName.ts create mode 100644 packages/design-batteries/src/utils/computeMultiSelectionBounds.ts create mode 100644 packages/design-batteries/src/utils/exportBlockAs.ts delete mode 100644 packages/design-batteries/types/commands/clipboard.d.ts delete mode 100644 packages/design-batteries/types/commands/copyStyle.d.ts delete mode 100644 packages/design-batteries/types/commands/syncStyle.d.ts diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index e9fafb1..74ae8ef 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -26,7 +26,8 @@ declare global { function App() { - const cesdkRef = useRef(); + // const cesdkRef = useRef(); + const contextRef = useRef(); const [commandItems, setCommandItems] = useState>([]) const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState(false) @@ -54,8 +55,8 @@ function App() { "license": import.meta.env.VITE_CESDK_LICENSE_KEY, "callbacks.onUpload": 'local', "callbacks.onDownload": "download", - "callbacks.onSave": async (str: string) => downloadBlocks(cesdkRef.current!, [new Blob([str])], { mimeType: 'application/imgly' }), - "callbacks.onExport": async (blobs: Array, options: any) => downloadBlocks(cesdkRef.current!, blobs, { mimeType: options.mimeType, pages: options.pages }), + "callbacks.onSave": async (str: string) => downloadBlocks(contextRef.current!.engine.block, [new Blob([str])], { mimeType: 'application/imgly' }), + "callbacks.onExport": async (blobs: Array, options: any) => downloadBlocks(contextRef.current!.engine.block, blobs, { mimeType: options.mimeType, pages: options.pages }), // "callbacks.onLoad": , // devMode: true, "theme": "dark", @@ -71,33 +72,31 @@ function App() { const initCallback = async (cesdk: CreativeEditorSDK) => { const imgly = new PluginContext(cesdk) - // @ts-ignore - window.cesdk = cesdkRef.current = cesdk window.imgly = imgly // Init Scene Programatically await cesdk.createDesignScene(); cesdk.engine.scene.setDesignUnit("Pixel"); // - - + + const vectorizerPlugin = VectorizerPlugin(imgly, {}) const commandsPlugin = DesignBatteriesPlugin(imgly, {}) - - // Register Plguins - await Promise.all([ - cesdk.addDefaultAssetSources(), - cesdk.addDemoAssetSources({ sceneMode: "Design" }), - cesdk.unstable_addPlugin(commandsPlugin), - cesdk.unstable_addPlugin(vectorizerPlugin), - - ]); + + // Register Plguins + await Promise.all([ + cesdk.addDefaultAssetSources(), + cesdk.addDemoAssetSources({ sceneMode: "Design" }), + cesdk.unstable_addPlugin(commandsPlugin), + cesdk.unstable_addPlugin(vectorizerPlugin), + + ]); // Ui components imgly.ui?.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton); - + imgly.i18n.setTranslations({ en: { "plugin.imgly.commandpalette.label": "✨ Run .." } }) // Canvas Menu const canvasMenuItems = imgly.ui?.unstable_getCanvasMenuOrder() ?? [] @@ -127,7 +126,7 @@ const generateCommandItemsfromCESDK = (ctx: PluginContext): Array => { const cmds = ctx .commands! .listCommands() - + return cmds .map((cmdId: string) => { const titel = ctx.i18n.translate(cmdId) // this comes from the metadata @@ -136,7 +135,7 @@ const generateCommandItemsfromCESDK = (ctx: PluginContext): Array => { return { id: cmdId, children: titel, - group: desc?.group || "Commands", + group: desc?.category || "Commands", showType: true, onClick: async () => { await ctx.commands!.executeCommand(cmdId, {}) diff --git a/examples/web/src/components/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx index 7e6d55f..1056073 100644 --- a/examples/web/src/components/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -2,10 +2,12 @@ import "react-cmdk/dist/cmdk.css"; import CMDK, { filterItems, getItemIndex } from "react-cmdk"; import { useState, useEffect } from "react"; + import { groupBy } from "lodash"; // https://github.com/albingroen/react-cmdk -export const CommandPalette = (params: { items: Array, isOpen: boolean, setIsOpen: (val: boolean) => void }) => { +type Params = { items: Array, isOpen: boolean, setIsOpen: (val: boolean) => void } +export const CommandPalette = (params: Params) => { const [page, _setPage] = useState<"root">("root"); const [search, setSearch] = useState(""); const { isOpen, setIsOpen } = params @@ -34,9 +36,8 @@ export const CommandPalette = (params: { items: Array, isOpen: boolean, set }; }, []); - - - const grouped = groupBy(items,"group") + + const grouped = groupBy(items, "group") const filteredItems = filterItems(Object.keys(grouped).map((key) => { return { heading: key, @@ -44,7 +45,7 @@ export const CommandPalette = (params: { items: Array, isOpen: boolean, set items: grouped[key] ?? [] } }), search); - + return ( , isOpen: boolean, set ); -}; +} /// helper diff --git a/examples/web/src/components/CreativeEditorSDK.tsx b/examples/web/src/components/CreativeEditorSDK.tsx index 7ee1c2c..35e53e4 100644 --- a/examples/web/src/components/CreativeEditorSDK.tsx +++ b/examples/web/src/components/CreativeEditorSDK.tsx @@ -38,7 +38,7 @@ export default function CreativeEditorSDKComponent(props: Props) { return (

); } diff --git a/examples/web/src/utils/download.ts b/examples/web/src/utils/download.ts index 5f41fbe..5cde074 100644 --- a/examples/web/src/utils/download.ts +++ b/examples/web/src/utils/download.ts @@ -1,4 +1,4 @@ -import CreativeEditorSDK from "@cesdk/cesdk-js"; +import { BlockAPI } from "@cesdk/cesdk-js"; export function downloadBlob(blob: Blob, filename: string) { @@ -9,7 +9,7 @@ export function downloadBlob(blob: Blob, filename: string) { link.click(); URL.revokeObjectURL(url); } -export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { +export const downloadBlocks = (block: BlockAPI, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { const postfix = options.mimeType.split("/")[1]; const pageIds = options.pages ?? []; @@ -17,7 +17,7 @@ export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: const pageId = pageIds[index]; let pageName = `page-${index}`; if (pageId) { - const name = cesdk.engine.block.getName(pageId); + const name = block.getName(pageId); pageName = name?.length ? name : pageName; } const filename = `${pageName}.${postfix}`; diff --git a/packages/api-utils/package.json b/packages/api-utils/package.json index 8876a3f..ef7af4f 100644 --- a/packages/api-utils/package.json +++ b/packages/api-utils/package.json @@ -59,7 +59,7 @@ "typescript": "^5.3.3" }, "peerDependencies": { - "@cesdk/cesdk-js": "~1.20.0" + "@cesdk/cesdk-js": "~1.21.0" }, "dependencies": { } diff --git a/packages/api-utils/src/index.ts b/packages/api-utils/src/index.ts index 10fa530..c82128a 100644 --- a/packages/api-utils/src/index.ts +++ b/packages/api-utils/src/index.ts @@ -1,6 +1,6 @@ import { PluginContext } from "./plugin/PluginContext" -export { Commands, type CommandCallback } from "./plugin/Commands" +export { Commands, type CommandCallback, type CommandDescription } from "./plugin/Commands" export { I18N } from "./plugin/I18n" export { type Logger } from "./plugin/Logger" export { PluginContext } from "./plugin/PluginContext" diff --git a/packages/api-utils/src/plugin/Commands.ts b/packages/api-utils/src/plugin/Commands.ts index 8beb690..dbf73d8 100644 --- a/packages/api-utils/src/plugin/Commands.ts +++ b/packages/api-utils/src/plugin/Commands.ts @@ -2,17 +2,18 @@ import { PluginContext } from './PluginContext'; import { Subscribable } from './Subscribable'; export type CommandCallback = (ctx: PluginContext, params: any) => Promise | any; -export type CommandArgs = { blockIds?: number[]} +export type CommandArgs = { blockIds?: number[] } -export type CommandEvents = "register"| "unregister" +export type CommandEvents = "register" | "unregister" export type CommandDescription = { - group?: string - args?: any, //JSONSchema - returns?: any // JSONSchema + id?: string, + category?: string + args?: any, //JSONSchema + returns?: any // JSONSchema } -export class Commands extends Subscribable{ +export class Commands extends Subscribable { #entries = new Map() #descs = new Map() #ctx: PluginContext; @@ -32,7 +33,7 @@ export class Commands extends Subscribable{ this.notify("register", label) return () => this.unregisterCommand(label) } - + unregisterCommand(label: string) { this.notify("unregister", label) this.#entries.delete(label); @@ -47,12 +48,15 @@ export class Commands extends Subscribable{ } - async executeCommand

(cmd: string, params: P): Promise { + async executeCommand

(cmd: string, params: P): Promise { + const command = this.#entries.get(cmd); if (command) { + + // this.#ctx.ui?.showNotification({ message: `Running command: ${cmd}`, type: "info" }) return await command(this.#ctx, params); } else { - throw new Error(`Command ${cmd} not found`); + // this.#ctx.ui?.showNotification({ message: `Command not found: ${cmd}`, type: "info" }) } } } diff --git a/packages/api-utils/src/plugin/I18n.ts b/packages/api-utils/src/plugin/I18n.ts index 41f68a6..e0681f7 100644 --- a/packages/api-utils/src/plugin/I18n.ts +++ b/packages/api-utils/src/plugin/I18n.ts @@ -8,9 +8,9 @@ import { flatten } from '../utils/flatten'; type Translation = Record type Translations = { [locale: string]: Translation; } -export class I18N extends Subscribable<"register", Translations> { +export class I18N extends Subscribable<"register", Translations> { #translations: any = {}; - #locale: string = 'en'; + #locale: string = navigator.language ?? "en"; #ctx: PluginContext @@ -18,26 +18,45 @@ export class I18N extends Subscribable<"register", super() this.#ctx = ctx } - + setTranslations(translations: Translations) { this.#translations = merge(this.#translations, flatten(translations)); this.notify("register", translations) } translate(key: K, fallback: string | undefined = undefined) { - const lookup = this.#locale.concat('.', key as string); - const translation = this.#translations[lookup] + const translation = this.findTranslation(key, this.#locale) if (!translation) { - this.#ctx.logger?.warn(`Translation for key ${lookup} not found!`); + this.#ctx.logger?.warn(`Translation in "${this.#locale}" for key ${key as string} not found!`); } return translation ?? fallback ?? key; } + findTranslation(key: K, language?: string) { + const [lang, region] = this.#locale.split('-'); + const langLookup = lang.concat('.', key as string); + const langAndRegionLookup = lang.concat('.', key as string); + return this.#translations[langAndRegionLookup] || this.#translations[langLookup] + } + + hasTranslation(key: K, language?: string): boolean { + const locale = language ?? this.#locale; + const lookup = locale.concat('.', key as string); + return !!this.findTranslation(key, language) + } + setLocale(locale: string) { this.#locale = locale; } + locale() { + return this.#locale; + } + + locales() { + return navigator.languages + } t = this.translate.bind(this) } -export type I18NType = { i18n?: I18N } +export type I18NType = { i18n?: I18N } diff --git a/packages/api-utils/types/index.d.ts b/packages/api-utils/types/index.d.ts index e0c29e5..7588cca 100644 --- a/packages/api-utils/types/index.d.ts +++ b/packages/api-utils/types/index.d.ts @@ -1,4 +1,4 @@ -export { Commands, type CommandCallback } from "./plugin/Commands"; +export { Commands, type CommandCallback, type CommandDescription } from "./plugin/Commands"; export { I18N } from "./plugin/I18n"; export { type Logger } from "./plugin/Logger"; export { PluginContext } from "./plugin/PluginContext"; diff --git a/packages/api-utils/types/plugin/Commands.d.ts b/packages/api-utils/types/plugin/Commands.d.ts index b14c564..89cc3e0 100644 --- a/packages/api-utils/types/plugin/Commands.d.ts +++ b/packages/api-utils/types/plugin/Commands.d.ts @@ -6,7 +6,8 @@ export type CommandArgs = { }; export type CommandEvents = "register" | "unregister"; export type CommandDescription = { - group?: string; + id?: string; + category?: string; args?: any; returns?: any; }; @@ -18,5 +19,5 @@ export declare class Commands extends Subscribable { unregisterCommand(label: string): void; getCommandCallback(label: string): CommandCallback | undefined; getCommandDescription(label: string): CommandDescription | undefined; - executeCommand

(cmd: string, params: P): Promise; + executeCommand

(cmd: string, params: P): Promise; } diff --git a/packages/api-utils/types/plugin/I18n.d.ts b/packages/api-utils/types/plugin/I18n.d.ts index 953a92c..2ee29d4 100644 --- a/packages/api-utils/types/plugin/I18n.d.ts +++ b/packages/api-utils/types/plugin/I18n.d.ts @@ -9,7 +9,10 @@ export declare class I18N extends Subscribable<"regis constructor(ctx: PluginContext); setTranslations(translations: Translations): void; translate(key: K, fallback?: string | undefined): any; + hasTranslation(key: K, language?: string): boolean; setLocale(locale: string): void; + locale(): string; + locales(): readonly string[]; t: (key: K, fallback?: string | undefined) => any; } export type I18NType = { diff --git a/packages/background-removal/package.json b/packages/background-removal/package.json index f9ee4f7..83d0c3e 100644 --- a/packages/background-removal/package.json +++ b/packages/background-removal/package.json @@ -65,7 +65,7 @@ "typescript": "^5.3.3" }, "peerDependencies": { - "@cesdk/cesdk-js": "~1.20.0" + "@cesdk/cesdk-js": "~1.21.0" }, "dependencies": { "@imgly/background-removal": "~1.4", diff --git a/packages/design-batteries/manifest.json b/packages/design-batteries/manifest.json index 2b83d8b..7d1a974 100644 --- a/packages/design-batteries/manifest.json +++ b/packages/design-batteries/manifest.json @@ -7,85 +7,76 @@ "contributes": { "commands": { "blockDelete": { - "group": "lifecycle" + "category": "lifecycle" }, "blockDuplicate": { - "group": "lifecycle" + "category": "lifecycle" }, "exportPngToClipboard": { - "group": "export" + "category": "export" }, "exportPngToFile": { - "group": "export" + "category": "export" }, "exportJpegToFile": { - "group": "export" + "category": "export" }, "exportWebpToFile": { - "group": "export" + "category": "export" }, "exportRgba8ToFile": { - "group": "export" + "category": "export" }, "exportPdfToFile": { - "group": "export" + "category": "export" }, "exportSceneToFile": { - "group": "export" + "category": "export" }, "exportSceneToClipboard": { - "group": "export" + "category": "export" }, "exportJsonToClipboard": { - "group": "export" + "category": "export" }, "exportJsonToFile": { - "group": "export" + "category": "export" }, "exportComponentToFile": { - "group": "export" + "category": "export" }, "imageFitModeCrop": { - "group": "image" + "category": "image" }, "imageFitModeContain": { - "group": "image" + "category": "image" }, "imageFitModeCover": { - "group": "image" + "category": "image" }, "groupBlocks": { - "group": "group" + "category": "category" }, "ungroupBlocks": { - "group": "group" + "category": "category" }, - "groupLayoutHStack": { - "group": "group" + "layoutHorizontally": { + "category": "layout" }, - "groupLayoutVStack": { - "group": "group" + "layoutVertically": { + "category": "layout" }, - "groupLayoutMasonry": { - "group": "group" - }, - "groupLayoutCircle": { - "group": "group", - "when": { - "blockType": ["group"] - } - }, - "logCrop": { - "group": "image" + "layoutMasonry": { + "category": "layout" }, "productSetInstagram": { - "group": "product" + "category": "product" }, "playground": { - "group": "playground" + "category": "playground" }, "syncBlocks": { - "group": "lifecycle" + "category": "lifecycle" } }, "i18n": {} diff --git a/packages/design-batteries/src/commands.ts b/packages/design-batteries/src/commands.ts index b951770..929c58a 100644 --- a/packages/design-batteries/src/commands.ts +++ b/packages/design-batteries/src/commands.ts @@ -2,5 +2,10 @@ export * from "./commands/lifecycle"; export * from "./commands/export"; export * from "./commands/image"; export * from "./commands/container"; -export * from "./commands/magic"; -export * from "./commands/playground"; \ No newline at end of file +export * from "./commands/layout"; +// export * from "./commands/magic"; +export * from "./commands/debug"; +export * from "./commands/plugins"; +export * from "./commands/components"; +export * from "./commands/playground"; +export * from "./commands/i18n"; \ No newline at end of file diff --git a/packages/design-batteries/src/commands/clipboard.ts b/packages/design-batteries/src/commands/clipboard.ts deleted file mode 100644 index a0a5150..0000000 --- a/packages/design-batteries/src/commands/clipboard.ts +++ /dev/null @@ -1,54 +0,0 @@ -// import CreativeEditorSDK, { type MimeType } from "@cesdk/cesdk-js"; -// import { type CommandsType } from "@imgly/plugin-commands-polyfill"; - - - -// export const registerClipboardCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - -// const { block, scene } = cesdk.engine -// const commands = cesdk.engine.commands! - - -// commands.registerCommand(`imgly.block.clipboard.selected.as.png`, async (params: { blockIds: number[] }) => { -// let blockIds = params.blockIds ?? block.findAllSelected() -// if (blockIds.length === 0) { -// blockIds = [scene.get()!] -// } -// const engine = cesdk.engine -// const clipboardItems = await Promise.all(blockIds.map(async (bId: number) => { -// const blob = await engine.block.export(bId, "image/png" as MimeType) -// return new ClipboardItem({ -// ["image/png"]: blob, -// }, { presentationStyle: "attachment" }) - -// })) - -// await navigator.clipboard.write(clipboardItems) -// }) - -// commands.registerCommand(`imgly.block.clipboard.selected.as.scene`, async (params: { blockIds: number[] }) => { -// let blockIds = params.blockIds ?? block.findAllSelected() - -// if (blockIds.length === 0) { -// blockIds = [scene.get()!] -// } - -// const blob = new Blob([await block.saveToString(blockIds)], { type: "application/x-cesdk" }) -// await navigator.clipboard.writeText(await blob.text()) - -// }) - -// commands.registerCommand(`imgly.block.clipboard.selected.as.json`, async (params: { blockIds: number[] }) => { -// let blockIds = params.blockIds ?? block.findAllSelected() -// if (blockIds.length === 0) { -// blockIds = [scene.get()!] -// } -// const str = await block.saveToString(blockIds); -// const base64 = str.substring(4) -// const json = atob(base64) -// const blob = new Blob([json], { type: "application/json" }) -// await navigator.clipboard.writeText(await blob.text()) - -// }) - -// } \ No newline at end of file diff --git a/packages/design-batteries/src/commands/components.ts b/packages/design-batteries/src/commands/components.ts new file mode 100644 index 0000000..4454086 --- /dev/null +++ b/packages/design-batteries/src/commands/components.ts @@ -0,0 +1,76 @@ +import { MimeType } from "@cesdk/cesdk-js"; +import { PluginContext } from "@imgly/plugin-api-utils"; +import { downloadBlob, loadAsBlob } from "../utils/download"; + +import { inferBlockName } from "../utils/computeBlockName"; +import { exportBlockAs } from "../utils/exportBlockAs"; + +export const exportComponentToFile = async (ctx: PluginContext, params: { blockIds?: number[]; }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + const componentData = await Promise.all(blockIds.map(async (bId) => { + + const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }); + const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }); + const json = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/json" }); + // const zip = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/zip" as MimeType }) + return { + thumbnail: thumbnail[0], + cesdk: cesdk[0], + json: json[0], + // zip: zip[0], + }; + })); + + componentData.forEach((data, index) => { + const blockId = blockIds[index]; + const filename = inferBlockName(ctx.engine.block, blockId); + downloadBlob(data.thumbnail, `${filename}.png`); + downloadBlob(data.cesdk, `${filename}.cesdk`); + }); +}; + +export const importComponent = async (ctx: PluginContext, _params: { blockIds?: number[]; }) => { + const { engine } = ctx; + const { scene, block } = engine; + + + const data = await loadAsBlob(); + const str = await data.text(); + const bIds = await ctx.engine.block.loadFromString(str); + + const pId = scene.getCurrentPage()!; + bIds.forEach((bId) => { + const name = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId); + console.log("Inserting Block", name); + block.appendChild(pId, bId); + }); + + + + + +}; +export const exportComponentLibrary = async (ctx: PluginContext, _params: { blockIds?: number[]; }) => { + const { block } = ctx.engine; + const libs = block.findByType("//ly.img.ubq/page"); + + libs.forEach(async (pId) => { + const pName = block.getName(pId) || block.getUUID(pId); + const bIds = block.getChildren(pId); + bIds.forEach(async (bId) => { + const bName = block.getName(bId) || block.getUUID(bId); + const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }); + const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }); + const filename = `${pName}-${bName}`; + downloadBlob(thumbnail[0], `${filename}.png`); + downloadBlob(cesdk[0], `${filename}.cesdk`); + }); + }); + + +}; + + + diff --git a/packages/design-batteries/src/commands/container.ts b/packages/design-batteries/src/commands/container.ts index 312eda4..c77452b 100644 --- a/packages/design-batteries/src/commands/container.ts +++ b/packages/design-batteries/src/commands/container.ts @@ -1,6 +1,4 @@ import { PluginContext } from "@imgly/plugin-api-utils"; -import { toSafeInteger } from "lodash"; - export const groupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { @@ -33,145 +31,4 @@ export const ungroupBlocks = async (ctx: PluginContext, params: { blockIds?: num } -export const groupLayoutHStack = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - padding = 0 - } = params; - - const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') - const isMultiSelection = blockIds.length > 1 - - if (!isGroup && !isMultiSelection) { - return - }; - - const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; - if (children.length === 0) return; - - - let curXPos = block.getPositionX(children[0]) - let curYPos = block.getPositionY(children[0]) - children.forEach((childId: number) => { - block.setPositionY(childId, curYPos); - block.setPositionX(childId, curXPos); - const width = block.getFrameWidth(childId); - curXPos += width; - curXPos += padding; - }) -} - -export const groupLayoutVStack = async (ctx: PluginContext, params: { blockIds?: number[], padding?: number }) => { - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - padding = 0 - } = params; - const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') - const isMultiSelection = blockIds.length > 1 - - if (!isGroup && !isMultiSelection) { - return - }; - - const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; - if (children.length === 0) return; - - let curXPos = block.getPositionX(children[0]) - let curYPos = block.getPositionY(children[0]) - children.forEach((childId: number) => { - block.setPositionX(childId, curXPos); - block.setPositionY(childId, curYPos); - const height = block.getFrameHeight(childId); - curYPos += height; - curYPos += padding; - }) -} - - -export const groupLayoutMasonry = async (ctx: PluginContext, params: { blockIds?: number[], cols?: number, paddingX?: number, paddingY?: number }) => { - const { block } = ctx.engine; - let { - blockIds = block.findAllSelected(), - paddingX = 16, - paddingY = 16, - cols = 2 - } = params; - - - cols = toSafeInteger(prompt("Enter the number of columns", "2")) - const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group') - const isMultiSelection = blockIds.length > 1 - - if (!isGroup && !isMultiSelection) { - return - }; - - const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; - const groupWidth = isGroup ? block.getFrameWidth(blockIds[0]) : getMultiSelectionBounds(ctx, blockIds).width; - const childWidth = groupWidth / cols - paddingX - - console.log(children) - let rowHeights: Array = [] - for (let i = 0; i < cols; i++) { - rowHeights.push(0); - } - - let curXPos = block.getPositionX(children[0]) - let curYPos = block.getPositionY(children[0]) - children.forEach((childId: number) => { - const w = block.getFrameWidth(childId); - const h = block.getFrameHeight(childId); - const aspect = h / w; - const newWidth = childWidth - const newHeight = aspect * newWidth; - block.setWidth(childId, newWidth); - block.setHeight(childId, newHeight); - // get column with the "lowest" height - const minIndex = rowHeights.indexOf(Math.min(...rowHeights)); - console.log(minIndex, rowHeights[minIndex]) - const xPos = curXPos + minIndex * (childWidth + paddingX); - const yPos = curYPos + rowHeights[minIndex]; - rowHeights[minIndex] += newHeight + paddingY; - block.setPositionX(childId, xPos); - block.setPositionY(childId, yPos); - }) -} - - -export const groupLayoutCircle = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - } = params; - const blockId = blockIds[0]; - if (blockIds.length !== 1 || block.getType(blockId) !== '//ly.img.ubq/group') { - ctx.logger?.info("Only groups are supported") - return - }; - - - - -} - - -const getMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { - - const { block } = ctx.engine; - const bounds = blockIds.map((id: number) => { - return { - x: block.getFrameX(id), - y: block.getFrameY(id), - width: block.getFrameWidth(id), - height: block.getFrameHeight(id) - } - }); - const x = Math.min(...bounds.map(b => b.x)); - const y = Math.min(...bounds.map(b => b.y)); - const width = Math.max(...bounds.map(b => b.x + b.width)) - x; - const height = Math.max(...bounds.map(b => b.y + b.height)) - y; - return { x, y, width, height } -} \ No newline at end of file diff --git a/packages/design-batteries/src/commands/copyStyle.ts b/packages/design-batteries/src/commands/copyStyle.ts deleted file mode 100644 index 3c90fff..0000000 --- a/packages/design-batteries/src/commands/copyStyle.ts +++ /dev/null @@ -1,84 +0,0 @@ -// import CreativeEditorSDK from "@cesdk/cesdk-js"; -// import { type CommandsType } from "@imgly/plugin-commands-polyfill"; - -// import { readPropValue, writePropValue } from "../utils/cesdk"; - - -// // we can have much more here. What is good UX? -// // copy style to a global buffer -// // paste style from a global buffer - - - -// // all register should do an unregister, alternatively we can have lifetime - - -// export const registerCopyStyleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - -// const { block } = cesdk.engine -// const commands = cesdk.engine.commands! - -// // do we need that if we bind commands? probably not -// type MapEntry = { type: string, value: any } - - -// const pasteTo = async (blockIds: number[], referenceValues: Map, whitelist: string[] | undefined = [], blacklist: string[] | undefined = []) => { -// blockIds = block.findAllSelected() -// blacklist = [...blacklist, "fill/solid/color"] -// blockIds.forEach((receiverBlockId: number) => { -// referenceValues.forEach((entry, key) => { -// if (whitelist && (whitelist.length !== 0) && !whitelist.includes(key)) return; -// if (blacklist && (blacklist.length !== 0) && blacklist.includes(key)) return; -// if (!block.isPropertyWritable(key)) return; -// const propType = block.getPropertyType(key) -// writePropValue(cesdk, receiverBlockId, key, entry.value, propType) -// }) -// }) -// } - -// // we could simply serialize to json for now and than apply it to the other block -// const generatedCommands: (() => void)[] = [] - -// const unregister = commands.registerCommand(`imgly.style.copy`, async (params: { blockIds: number[], whitelist: string[] | undefined, blacklist: string[] | undefined }) => { -// let { blockIds = block.findAllSelected(), whitelist = [], blacklist = [] } = params -// if (blockIds.length === 0) return; - -// generatedCommands.forEach((unregister) => unregister()) - -// blacklist = [...blacklist, "fill/solid/color"] -// const [senderBlockIds, ..._receiverBlockIds] = blockIds -// const referenceValues = new Map() -// { -// const props = block.findAllProperties(senderBlockIds) -// props.forEach((propKey: string) => { -// if (whitelist && (whitelist.length !== 0) && !whitelist.includes(propKey)) return; -// if (blacklist && (blacklist.length !== 0) && blacklist.includes(propKey)) return; -// if (!block.isPropertyReadable(propKey)) return; -// const propType = block.getPropertyType(propKey) -// const propValue = readPropValue(cesdk, senderBlockIds, propKey, propType) -// referenceValues.set(propKey, { type: propType, value: propValue }) -// generatedCommands.push( -// commands.registerCommand(`imgly.style.paste.${propKey}`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, [propKey], [])) -// ) - -// }) -// } - -// // some special commands -// generatedCommands.push( -// commands.registerCommand(`imgly.style.paste.rotation`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["rotation"], [])), -// commands.registerCommand(`imgly.style.paste.size`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["width", "height"], [])), -// commands.registerCommand(`imgly.style.paste.position`, async (params: { blockIds: number[] }) => await pasteTo(params.blockIds, referenceValues, ["position/x", "position/y"], [])), -// ) - -// }) -// // we could life registe commands and also unregister based on the possibilites - -// return [unregister] -// } - - - -// // we can make sync alive - - diff --git a/packages/design-batteries/src/commands/debug.ts b/packages/design-batteries/src/commands/debug.ts index e69de29..6047a15 100644 --- a/packages/design-batteries/src/commands/debug.ts +++ b/packages/design-batteries/src/commands/debug.ts @@ -0,0 +1,60 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +import { readPropValue } from "../utils/cesdk"; + +export const debugLogBlockProperties = async (ctx: PluginContext, params: { blockIds: number[] }) => { + const { block, scene } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((bId: number) => { + const props = block.findAllProperties(bId) + const propDefinition = new Map() + props.forEach((propKey: string) => { + if (!block.isPropertyReadable(propKey)) return; + const propType = block.getPropertyType(propKey) + const propValue = readPropValue(block, bId, propKey, propType) + propDefinition.set(propKey, { type: propType, value: propValue }) + }) + console.debug("Properties for block", bId, propDefinition) + }) +} + +export const debugLogBlockCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((id: number) => { + const x = block.getCropTranslationX(id) + const y = block.getCropTranslationY(id) + const scaleX = block.getCropScaleX(id) + const scaleY = block.getCropScaleY(id) + const fillMode = block.getContentFillMode(id) + const crop = { + x, y, scaleX, scaleY, fillMode + } + console.debug("Crop for block", id, crop) + }); + +} + + + +export const debugLogBlockMetadata = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + + blockIds.forEach((id: number) => { + const keys = block.findAllMetadata(id) + if (keys.length === 0) { + console.debug("No metadata for block", id) + return + } + const map = new Map() + keys.forEach((key: string) => { + const metadata = block.getMetadata(id, key) + const obj = JSON.parse(metadata) + map.set(key, obj) + }) + console.debug("Metadata for block", id, map) + }) +} diff --git a/packages/design-batteries/src/commands/export.ts b/packages/design-batteries/src/commands/export.ts index 1ce70c2..9193322 100644 --- a/packages/design-batteries/src/commands/export.ts +++ b/packages/design-batteries/src/commands/export.ts @@ -1,23 +1,7 @@ import { PluginContext } from "@imgly/plugin-api-utils"; import { MimeType } from "@cesdk/cesdk-js"; -import { downloadBlob, loadAsBlob } from "../utils/download"; - - -export const myNewFunctionForTheEditor = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { - const { block, scene } = ctx.engine; - - const pId = scene.getCurrentPage()! - - const bId = block.create("//ly.img.ubq/text") - block.setName(bId, "Hello World") - block.setTextColor(bId, { r: 1, g: 0, b: 0, a: 1 }) - block.replaceText(bId, "Hello World") - - - block.appendChild(pId, bId) - -} - +import { downloadBlob } from "../utils/download"; +import { exportBlockAs } from "../utils/exportBlockAs"; @@ -87,112 +71,3 @@ export const exportJsonToFile = async (ctx: PluginContext, params: { blockIds?: } - -export const exportComponentToFile = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - - const componentData = await Promise.all(blockIds.map(async (bId) => { - - const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }) - const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }) - const json = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/json" }) - // const zip = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/zip" as MimeType }) - - return { - thumbnail: thumbnail[0], - cesdk: cesdk[0], - json: json[0], - // zip: zip[0], - } - })) - - componentData.forEach((data, index) => { - const blockId = blockIds[index]; - const filename = inferBlockName(ctx, blockId) - downloadBlob(data.thumbnail, `${filename}.png`) - downloadBlob(data.cesdk, `${filename}.cesdk`) - }); -} - -export const importComponent = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { - const { engine } = ctx; - const { scene, block } = engine; - - - const data = await loadAsBlob() - const str = await data.text() - const bIds = await ctx.engine.block.loadFromString(str) - - const pId = scene.getCurrentPage()! - bIds.forEach((bId) => { - const name = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId) - console.log("Inserting Block", name) - block.appendChild(pId, bId) - }) - - - - - -} -export const exportComponentLibrary = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const libs = block.findByType("//ly.img.ubq/page") - - libs.forEach(async (pId) => { - const pName = block.getName(pId) || block.getUUID(pId) - const bIds = block.getChildren(pId); - bIds.forEach(async (bId) => { - const bName = block.getName(bId) || block.getUUID(bId); - const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }) - const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }) - const filename = `${pName}-${bName}` - downloadBlob(thumbnail[0], `${filename}.png`) - downloadBlob(cesdk[0], `${filename}.cesdk`) - }) - }) - - -} - -// Utils - - -const inferBlockName = (ctx: PluginContext, blockId: number) => { - const { block } = ctx.engine; - const uuid = block.getUUID(blockId); - const name = block.getName(blockId) - return name || uuid || blockId -} - -const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - mimeType = "image/png" as MimeType, - width, - height - } = params; - blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - return await Promise.all(blockIds.map(async (bId: number) => { - switch (mimeType) { - case "application/x-cesdk": { - const str = await block.saveToString([bId]); - return new Blob([str], { type: mimeType }); - - } - case "application/json": { - const str = await block.saveToString([bId]); - const json = str.substring(4) - const decoded = atob(json) - return new Blob([decoded], { type: mimeType }); - - } - default: - return await block.export(bId, mimeType, { targetHeight: height, targetWidth: width }); - } - - })); -}; - diff --git a/packages/design-batteries/src/commands/i18n.ts b/packages/design-batteries/src/commands/i18n.ts new file mode 100644 index 0000000..a4203b4 --- /dev/null +++ b/packages/design-batteries/src/commands/i18n.ts @@ -0,0 +1,21 @@ + +import { downloadBlob } from "../utils/download"; +import { PluginContext } from "@imgly/plugin-api-utils"; // Add this import statement + +export const i18nDownloadMissingCommandTranslations = (ctx: PluginContext) => { + const { i18n, commands } = ctx; + + const missingCommandTranslations = commands.listCommands().map((cmd) => { + if (!i18n.hasTranslation(cmd)) { + return [cmd, cmd.split(".").pop()] + } + else null + }).filter(Boolean) + + if (missingCommandTranslations.length > 0) { + const ob = Object.fromEntries(missingCommandTranslations) + const json = JSON.stringify(ob, null, 2) + const blob = new Blob([json], { type: "application/json" }) + downloadBlob(blob, `${i18n.locale()}.json`) + } +} \ No newline at end of file diff --git a/packages/design-batteries/src/commands/layout.ts b/packages/design-batteries/src/commands/layout.ts new file mode 100644 index 0000000..554e3a1 --- /dev/null +++ b/packages/design-batteries/src/commands/layout.ts @@ -0,0 +1,104 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +import { toSafeInteger } from "lodash"; +import { computeMultiSelectionBounds } from "../utils/computeMultiSelectionBounds"; + +export const layoutHorizontally = async (ctx: PluginContext, params: { blockIds?: number[]; padding?: number; }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), padding = 0 + } = params; + + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group'); + const isMultiSelection = blockIds.length > 1; + + if (!isGroup && !isMultiSelection) { + return; + }; + + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; + if (children.length === 0) return; + + + let curXPos = block.getPositionX(children[0]); + let curYPos = block.getPositionY(children[0]); + children.forEach((childId: number) => { + block.setPositionY(childId, curYPos); + block.setPositionX(childId, curXPos); + const width = block.getFrameWidth(childId); + curXPos += width; + curXPos += padding; + }); +}; + +export const layoutVertically = async (ctx: PluginContext, params: { blockIds?: number[]; padding?: number; }) => { + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), padding = 0 + } = params; + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group'); + const isMultiSelection = blockIds.length > 1; + + if (!isGroup && !isMultiSelection) { + return; + }; + + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; + if (children.length === 0) return; + + let curXPos = block.getPositionX(children[0]); + let curYPos = block.getPositionY(children[0]); + children.forEach((childId: number) => { + block.setPositionX(childId, curXPos); + block.setPositionY(childId, curYPos); + const height = block.getFrameHeight(childId); + curYPos += height; + curYPos += padding; + }); +}; + + +export const layoutMasonry = async (ctx: PluginContext, params: { blockIds?: number[]; cols?: number; paddingX?: number; paddingY?: number; }) => { + const { block } = ctx.engine; + let { + blockIds = block.findAllSelected(), paddingX = 16, paddingY = 16, cols = 2 + } = params; + + + cols = toSafeInteger(prompt("Enter the number of columns", "2")); + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) !== '//ly.img.ubq/group'); + const isMultiSelection = blockIds.length > 1; + + if (!isGroup && !isMultiSelection) { + return; + }; + + const children = isGroup ? block.getChildren(blockIds[0]) : blockIds; + const groupWidth = isGroup ? block.getFrameWidth(blockIds[0]) : computeMultiSelectionBounds(ctx, blockIds).width; + const childWidth = groupWidth / cols - paddingX; + + console.log(children); + let rowHeights: Array = []; + for (let i = 0; i < cols; i++) { + rowHeights.push(0); + } + + let curXPos = block.getPositionX(children[0]); + let curYPos = block.getPositionY(children[0]); + children.forEach((childId: number) => { + const w = block.getFrameWidth(childId); + const h = block.getFrameHeight(childId); + const aspect = h / w; + const newWidth = childWidth; + const newHeight = aspect * newWidth; + block.setWidth(childId, newWidth); + block.setHeight(childId, newHeight); + // get column with the "lowest" height + const minIndex = rowHeights.indexOf(Math.min(...rowHeights)); + console.log(minIndex, rowHeights[minIndex]); + const xPos = curXPos + minIndex * (childWidth + paddingX); + const yPos = curYPos + rowHeights[minIndex]; + rowHeights[minIndex] += newHeight + paddingY; + block.setPositionX(childId, xPos); + block.setPositionY(childId, yPos); + }); +}; diff --git a/packages/design-batteries/src/commands/lifecycle.ts b/packages/design-batteries/src/commands/lifecycle.ts index a7f2295..3b8ddd5 100644 --- a/packages/design-batteries/src/commands/lifecycle.ts +++ b/packages/design-batteries/src/commands/lifecycle.ts @@ -20,9 +20,51 @@ export const blockDuplicate = async (ctx: PluginContext, params: { blockIds?: nu } block.setSelected(newBlock, true); // should return the previous state block.setSelected(id, false); - + }); +} + +export const blockRename = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.isValid(id); + const name = block.getName(id) + const newName = prompt("Block name", name); + if (newName) { + block.setName(id, newName); + } + }); +} +export const blockBringForward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.bringForward(id); + }); } +export const blockSendBackward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.sendBackward(id); + }); +} + +export const blockBringToFront = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.bringToFront(id); + }); +} +export const blockSendToBack = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.sendToBack(id); + }) +} diff --git a/packages/design-batteries/src/commands/magic.ts b/packages/design-batteries/src/commands/magic.ts index 6144f5a..b885a08 100644 --- a/packages/design-batteries/src/commands/magic.ts +++ b/packages/design-batteries/src/commands/magic.ts @@ -1,29 +1,2 @@ // https://github.com/jwagner/smartcrop.js -import { PluginContext } from "@imgly/plugin-api-utils"; - - - -export const logCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { blockIds = ctx.engine.block.findAllSelected() } = params; - - blockIds.forEach((id: number) => { - const fillId = ctx.engine.block.getFill(id) - const isValid = ctx.engine.block.isValid(fillId) - if (!isValid) return; - - const isImageFill = ctx.engine.block.getType(fillId) === "//ly.img.ubq/fill/image" - if (!isImageFill) return; - - const x = ctx.engine.block.getCropTranslationX(id) - const y = ctx.engine.block.getCropTranslationY(id) - const scaleX = ctx.engine.block.getCropScaleX(id) - const scaleY = ctx.engine.block.getCropScaleY(id) - const fillMode = ctx.engine.block.getContentFillMode(id) - - - - console.log(x, y, scaleX, scaleY, fillMode) - }); - -} \ No newline at end of file diff --git a/packages/design-batteries/src/commands/playground.ts b/packages/design-batteries/src/commands/playground.ts index b647b9b..9701ef2 100644 --- a/packages/design-batteries/src/commands/playground.ts +++ b/packages/design-batteries/src/commands/playground.ts @@ -5,11 +5,35 @@ import { PluginContext } from "@imgly/plugin-api-utils"; import { readPropValue, writePropValue } from "../utils/cesdk"; import { CreativeEngine } from "@cesdk/cesdk-js"; - -const syncProperties = (ctx: PluginContext, propertyKeys: string[], sourceId: number, destIds: number[]) => { +const propKeys = [ + 'alwaysOnBottom', + 'alwaysOnTop', + 'blend/mode', 'blur/enabled', 'clipped', + // 'contentFill/mode', + // 'transformLocked', + // 'crop/rotation', 'crop/scaleRatio', 'crop/scaleX', 'crop/scaleY', 'crop/translationX', 'crop/translationY', + // 'position/x', 'position/x/mode', 'position/y', 'position/y/mode', 'rotation', + 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y', + 'fill/enabled', + 'opacity', + 'placeholder/enabled', + 'playback/duration', 'playback/timeOffset', + 'stroke/color', 'stroke/cornerGeometry', 'stroke/enabled', 'stroke/position', 'stroke/style', 'stroke/width', + 'visible'] + + +const syncBlockProperties = (ctx: PluginContext, sourceId: number, destIds: number[], whiteList?: string[], blackList?: string[]) => { const { block } = ctx.engine; if (!block.isValid(sourceId)) return + const propertyKeys = block.findAllProperties(sourceId) + .filter((key: string) => block.isPropertyReadable(key)) + .filter((key: string) => { + if (whiteList && !whiteList.includes(key)) return false + if (blackList && blackList.includes(key)) return false + return true + }) + propertyKeys.forEach((propertyKey: string) => { const sourceValue = readPropValue(block, sourceId, propertyKey) destIds.forEach((receiverBlockId: number) => { @@ -24,13 +48,16 @@ const syncProperties = (ctx: PluginContext, propertyKeys: string[], sourceId: nu // name syntax = "label=appearance(other), rotation(other)" -export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const syncBlockAppearance = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block, event } = ctx.engine; let { blockIds = block.findAllSelected() } = params console.log("syncBlocks", block.findAllProperties(blockIds[0])) - const properties = [ - "opacity", "blend/mode", "rotation", - 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y'] + const propWhiteList = propKeys + const propBlackList = [] + // better would be to add a meta data + // const sync = { + // appearance: true + // } const unsubscribe = event.subscribe(blockIds, (events) => { events.forEach((event) => { @@ -41,7 +68,7 @@ export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number break; } case 'Updated': { - syncProperties(ctx, properties, bId, blockIds) + syncBlockProperties(ctx, bId, blockIds, propWhiteList, propBlackList) break; } case "Destroyed": { @@ -59,17 +86,6 @@ export const syncBlocks = async (ctx: PluginContext, params: { blockIds?: number } -export const registerAndOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { - const { ui } = ctx; - ui?.unstable_registerCustomPanel('ly.img.foo', (domElement) => { - domElement.appendChild(document.createTextNode('Hello World')); - return () => { - console.log('Apps disposer called'); - }; - }); - - ui?.openPanel("ly.img.foo") -} const products = { @@ -81,6 +97,25 @@ const products = { }, } +export const myNewFunctionForTheEditor = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + const { block, scene } = ctx.engine; + + const pId = scene.getCurrentPage()! + + const bId = block.create("//ly.img.ubq/text") + block.setName(bId, "Hello World") + block.setTextColor(bId, { r: 1, g: 0, b: 0, a: 1 }) + block.replaceText(bId, "Hello World") + + + block.appendChild(pId, bId) + +} + + + + + export const productSetInstagram = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; diff --git a/packages/design-batteries/src/commands/plugins.ts b/packages/design-batteries/src/commands/plugins.ts new file mode 100644 index 0000000..feee9a6 --- /dev/null +++ b/packages/design-batteries/src/commands/plugins.ts @@ -0,0 +1,14 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; + +export const pluginRegisterAndOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + const { ui } = ctx; + ui?.unstable_registerCustomPanel('ly.img.foo', (domElement) => { + domElement.appendChild(document.createTextNode('Hello World')); + return () => { + console.log('Apps disposer called'); + }; + }); + + ui?.openPanel("ly.img.foo") +} + diff --git a/packages/design-batteries/src/commands/syncStyle.ts b/packages/design-batteries/src/commands/syncStyle.ts deleted file mode 100644 index de8428b..0000000 --- a/packages/design-batteries/src/commands/syncStyle.ts +++ /dev/null @@ -1,123 +0,0 @@ - -// // we can have much more here. What is good UX? -// // copy style to a global buffer -// // paste style from a global buffer - - - -// // all register should do an unregister, alternatively we can have lifetime - -// // This is a simple example of a command that syncs the rotation of multiple blocks -// // We would need to store the blocks that need syncing and add a dedicated sync-system / handler. That on every frame or change syncs these blocks with the same value - - -// import CreativeEditorSDK, { type BlockEvent } from "@cesdk/cesdk-js"; -// import { CommandArgs, type CommandsType } from "@imgly/plugin-commands-polyfill"; - -// import { readPropValue, writePropValue } from "../utils/cesdk"; - -// export const registerSyncStyleCommands = (cesdk: CreativeEditorSDK & CommandsType) => { - -// const { block, event } = cesdk.engine -// const commands = cesdk.engine.commands! - - - -// const handleSyncProperties = (context: CommandArgs, properties: string[]) => { -// let { blockIds = block.findAllSelected() } = context -// if (blockIds.length <= 1) return; - -// const unsubscribe = event.subscribe(blockIds, (events: BlockEvent[]) => { -// events.forEach((event: BlockEvent) => { -// const bId = event.block; -// switch (event.type) { -// case 'Created': { -// throw new Error("Not implemented") -// break; -// } -// case 'Updated': { -// syncProperties(properties, bId, blockIds) -// break; -// } -// case "Destroyed": { -// if (blockIds.includes(bId)) { -// blockIds.splice(blockIds.indexOf(bId), 1) -// } -// if (blockIds.length === 1) { -// unsubscribe() -// } -// break; -// } -// } -// }) -// }) - - -// const syncProperties = (propertyKeys: string[], sourceId: number, destIds: number[]) => { -// if (!block.isValid(sourceId)) return - -// propertyKeys.forEach((propertyKey: string) => { -// const sourceValue = readPropValue(cesdk, sourceId, propertyKey) -// destIds.forEach((receiverBlockId: number) => { -// if (!block.isValid(receiverBlockId)) return -// if (sourceId === receiverBlockId) return; -// const receiverValue = readPropValue(cesdk, receiverBlockId, propertyKey) -// if (receiverValue === sourceValue) return; -// writePropValue(cesdk, receiverBlockId, propertyKey, sourceValue) -// }) -// }) -// } - -// commands.registerCommand(`imgly.sync.stroke`, async (context) => { -// await handleSyncProperties(context, [ -// "stroke/enabled", -// "stroke/color", -// "stroke/style", -// "stroke/width", -// "stroke/position" -// ]) -// }) - -// commands.registerCommand(`imgly.sync.shadow`, async (context) => { -// await handleSyncProperties(context, [ - -// "dropShadow/enabled", -// "dropShadow/color", -// "dropShadow/clip", -// "dropShadow/offset/x", -// "dropShadow/offset/y", -// ]) -// }) - -// commands.registerCommand(`imgly.sync.rotation`, async (context) => { -// await handleSyncProperties(context, [ -// "rotation" -// ]) -// }) - -// commands.registerCommand(`imgly.sync.width+height`, async (context) => { -// await handleSyncProperties(context, [ -// "width", -// "height" -// ]) -// }) - - -// // commands.registerCommand(`imgly.sync.effects`, async (context) => { -// // const { blockIds = block.findAllSelected() } = context - -// // blockIds.forEach((bId: number) => { -// // const eIds = block.getEffects(bId) -// // if (eIds.length === 0) return; - -// // }) -// // }) - -// // // we could life registe commands and also unregister based on the possibilites - -// return [] -// } -// } -// // we can make sync alive - - diff --git a/packages/design-batteries/src/index.ts b/packages/design-batteries/src/index.ts index 2ee2877..5ebc957 100644 --- a/packages/design-batteries/src/index.ts +++ b/packages/design-batteries/src/index.ts @@ -1,43 +1,65 @@ -import en from './locale/en.json'; -import { PluginContext } from '@imgly/plugin-api-utils'; + +import { PluginContext, CommandDescription } from '@imgly/plugin-api-utils'; import { CommandImports, CommandContributions, PluginManifest } from './PluginManifest'; export interface PluginConfiguration { } -function registerTranslation(ctx: PluginContext, translations: { [key: string]: any } = {}) { +const registerTranslation = (ctx: PluginContext, translations: { [key: string]: any } = {}) => { ctx.i18n.setTranslations(translations) } -function registerCommands(ctx: PluginContext, imports: CommandImports) { - -type CommandDescription = { - id?: string, - group?: string -} +const registerCommands = (ctx: PluginContext, imports: CommandImports) => { for (const command in imports) { const callback = imports[command as CommandContributions] - - const desc: CommandDescription = PluginManifest.contributes.commands[command as CommandContributions]; - const id = desc?.id ?? `${PluginManifest.id}.commands.${command as string}`; + + let desc: CommandDescription = PluginManifest.contributes.commands[command as CommandContributions]; + desc ??= {}; + desc.id ??= `${PluginManifest.id}.commands.${command as string}`; + const [category, name] = (command as string).split("_") + desc.category ??= name ? category : "Commands"; ctx.commands.registerCommand( - id, + desc.id, async (params: any) => await callback(ctx, params), desc ); } } -import * as commands from './commands' +const loadTranslation = async (ctx: PluginContext, locales: readonly string[] = ctx.i18n.locales()) => { + const translations = await Promise.all(locales.map(async (locale) => { + try { + const translations = await import(`./locale/${locale}.json`) + return { [locale]: translations.default } + } catch (e) { + // when loading of the file fails + return { [locale]: {} } + } + })) + + translations.forEach((t) => registerTranslation(ctx, t)) +} + + +const loadCommands = async (ctx: PluginContext) => { + const commands = await import("./commands") + await registerCommands(ctx, commands) +} + + +export const activate = async (ctx: PluginContext) => { + const doValidateI18n = true; + await loadTranslation(ctx) + await loadCommands(ctx) +} + export default (ctx: PluginContext, _config: PluginConfiguration) => { return { async initializeUserInterface() { - //we should give manifest to the context - registerTranslation(ctx, { en }) - registerCommands(ctx, commands) + await activate(ctx) } }; }; diff --git a/packages/design-batteries/src/locale/en.json b/packages/design-batteries/src/locale/en.json index c533142..4c95f58 100644 --- a/packages/design-batteries/src/locale/en.json +++ b/packages/design-batteries/src/locale/en.json @@ -7,17 +7,33 @@ "design-batteries.commands.exportWebpToFile": "Export WEP to File", "design-batteries.commands.exportPdfToFile": "Export PDF to File", "design-batteries.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", - "design-batteries.commands.exportSceneToClipboard": "Export Scene to Clipboard", "design-batteries.commands.exportJsonToClipboard": "Export JSON to Clipboard", "design-batteries.commands.exportSceneToFile": "Export Scene to File", "design-batteries.commands.exportJsonToFile": "Export JSON to File", - "design-batteries.commands.imageFitModeContain": "Set Image FitMode to Contain", "design-batteries.commands.imageFitModeCrop": "Set Image FitMode to Crop", "design-batteries.commands.imageFitModeCover": "Set Image FitMode to Cover", - - "design-batteries.commands.exportComponentToFile": "Export Component to File" , - "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function" - + "design-batteries.commands.exportComponentToFile": "Export Component to File", + "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function", + "design-batteries.commands.blockBringForward": "blockBringForward", + "design-batteries.commands.blockBringToFront": "blockBringToFront", + "design-batteries.commands.blockRename": "blockRename", + "design-batteries.commands.blockSendBackward": "blockSendBackward", + "design-batteries.commands.blockSendToBack": "blockSendToBack", + "design-batteries.commands.debugLogBlockCrop": "debugLogBlockCrop", + "design-batteries.commands.debugLogBlockMetadata": "debugLogBlockMetadata", + "design-batteries.commands.debugLogBlockProperties": "debugLogBlockProperties", + "design-batteries.commands.exportComponentLibrary": "exportComponentLibrary", + "design-batteries.commands.groupBlocks": "groupBlocks", + "design-batteries.commands.i18nDownloadMissingCommandTranslations": "i18nDownloadMissingCommandTranslations", + "design-batteries.commands.importComponent": "importComponent", + "design-batteries.commands.layoutHorizontally": "layoutHorizontally", + "design-batteries.commands.layoutMasonry": "layoutMasonry", + "design-batteries.commands.layoutVertically": "layoutVertically", + "design-batteries.commands.playground": "playground", + "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "pluginRegisterAndOpenCustomPanel", + "design-batteries.commands.productSetInstagram": "productSetInstagram", + "design-batteries.commands.syncBlocks": "syncBlocks", + "design-batteries.commands.ungroupBlocks": "ungroupBlocks" } \ No newline at end of file diff --git a/packages/design-batteries/src/utils/computeBlockName.ts b/packages/design-batteries/src/utils/computeBlockName.ts new file mode 100644 index 0000000..a730434 --- /dev/null +++ b/packages/design-batteries/src/utils/computeBlockName.ts @@ -0,0 +1,8 @@ +import { BlockAPI } from "@cesdk/cesdk-js"; + +export const inferBlockName = (block: BlockAPI, blockId: number) => { + + const uuid = block.getUUID(blockId); + const name = block.getName(blockId) + return name || uuid || blockId +} \ No newline at end of file diff --git a/packages/design-batteries/src/utils/computeMultiSelectionBounds.ts b/packages/design-batteries/src/utils/computeMultiSelectionBounds.ts new file mode 100644 index 0000000..8346e69 --- /dev/null +++ b/packages/design-batteries/src/utils/computeMultiSelectionBounds.ts @@ -0,0 +1,20 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; + +export const computeMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { + + const { block } = ctx.engine; + const bounds = blockIds.map((id: number) => { + return { + x: block.getFrameX(id), + y: block.getFrameY(id), + width: block.getFrameWidth(id), + height: block.getFrameHeight(id) + }; + }); + + const x = Math.min(...bounds.map(b => b.x)); + const y = Math.min(...bounds.map(b => b.y)); + const width = Math.max(...bounds.map(b => b.x + b.width)) - x; + const height = Math.max(...bounds.map(b => b.y + b.height)) - y; + return { x, y, width, height }; +}; diff --git a/packages/design-batteries/src/utils/download.ts b/packages/design-batteries/src/utils/download.ts index 63568d0..f83c9c5 100644 --- a/packages/design-batteries/src/utils/download.ts +++ b/packages/design-batteries/src/utils/download.ts @@ -2,11 +2,11 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; -export async function loadAsBlob() { +export async function loadAsBlob(filter: string = "*") { return new Promise((resolve, reject) => { const upload = document.createElement("input"); upload.setAttribute("type", "file"); - upload.setAttribute("accept", "*") + upload.setAttribute("accept", filter) upload.setAttribute("style", "display: none") upload.onchange = (e) => { const file = (e.target as HTMLInputElement).files?.[0]; @@ -16,8 +16,10 @@ export async function loadAsBlob() { const buffer = e.target?.result if (buffer instanceof ArrayBuffer) { const blob = new Blob([buffer]); + upload.remove() resolve(blob) } else { + upload.remove() reject(new Error("Invalid buffer")) } } @@ -35,6 +37,7 @@ export function downloadBlob(blob: Blob, filename: string) { link.href = url; link.download = filename; link.click(); + link.remove(); URL.revokeObjectURL(url); } export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { diff --git a/packages/design-batteries/src/utils/exportBlockAs.ts b/packages/design-batteries/src/utils/exportBlockAs.ts new file mode 100644 index 0000000..e03c623 --- /dev/null +++ b/packages/design-batteries/src/utils/exportBlockAs.ts @@ -0,0 +1,34 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +import { type MimeType } from "@cesdk/cesdk-js"; + +export const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { + + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + mimeType = "image/png" as MimeType, + width, + height + } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + return await Promise.all(blockIds.map(async (bId: number) => { + switch (mimeType) { + case "application/x-cesdk": { + const str = await block.saveToString([bId]); + return new Blob([str], { type: mimeType }); + + } + case "application/json": { + const str = await block.saveToString([bId]); + const json = str.substring(4) + const decoded = atob(json) + return new Blob([decoded], { type: mimeType }); + + } + default: + return await block.export(bId, mimeType, { targetHeight: height, targetWidth: width }); + } + + })); +}; + diff --git a/packages/design-batteries/types/PluginManifest.d.ts b/packages/design-batteries/types/PluginManifest.d.ts index 21da90d..666f2f0 100644 --- a/packages/design-batteries/types/PluginManifest.d.ts +++ b/packages/design-batteries/types/PluginManifest.d.ts @@ -12,85 +12,76 @@ export declare const PluginManifest: { contributes: { commands: { blockDelete: { - group: string; + category: string; }; blockDuplicate: { - group: string; + category: string; }; exportPngToClipboard: { - group: string; + category: string; }; exportPngToFile: { - group: string; + category: string; }; exportJpegToFile: { - group: string; + category: string; }; exportWebpToFile: { - group: string; + category: string; }; exportRgba8ToFile: { - group: string; + category: string; }; exportPdfToFile: { - group: string; + category: string; }; exportSceneToFile: { - group: string; + category: string; }; exportSceneToClipboard: { - group: string; + category: string; }; exportJsonToClipboard: { - group: string; + category: string; }; exportJsonToFile: { - group: string; + category: string; }; exportComponentToFile: { - group: string; + category: string; }; imageFitModeCrop: { - group: string; + category: string; }; imageFitModeContain: { - group: string; + category: string; }; imageFitModeCover: { - group: string; + category: string; }; groupBlocks: { - group: string; + category: string; }; ungroupBlocks: { - group: string; + category: string; }; - groupLayoutHStack: { - group: string; + layoutHorizontally: { + category: string; }; - groupLayoutVStack: { - group: string; + layoutVertically: { + category: string; }; - groupLayoutMasonry: { - group: string; - }; - groupLayoutCircle: { - group: string; - when: { - blockType: string[]; - }; - }; - logCrop: { - group: string; + layoutMasonry: { + category: string; }; productSetInstagram: { - group: string; + category: string; }; playground: { - group: string; + category: string; }; syncBlocks: { - group: string; + category: string; }; }; i18n: {}; diff --git a/packages/design-batteries/types/commands.d.ts b/packages/design-batteries/types/commands.d.ts index 82c672c..8b284b6 100644 --- a/packages/design-batteries/types/commands.d.ts +++ b/packages/design-batteries/types/commands.d.ts @@ -2,5 +2,8 @@ export * from "./commands/lifecycle"; export * from "./commands/export"; export * from "./commands/image"; export * from "./commands/container"; -export * from "./commands/magic"; +export * from "./commands/layout"; +export * from "./commands/debug"; +export * from "./commands/plugins"; +export * from "./commands/components"; export * from "./commands/playground"; diff --git a/packages/design-batteries/types/commands/clipboard.d.ts b/packages/design-batteries/types/commands/clipboard.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/design-batteries/types/commands/container.d.ts b/packages/design-batteries/types/commands/container.d.ts index bb12dc6..5716765 100644 --- a/packages/design-batteries/types/commands/container.d.ts +++ b/packages/design-batteries/types/commands/container.d.ts @@ -5,20 +5,3 @@ export declare const groupBlocks: (ctx: PluginContext, params: { export declare const ungroupBlocks: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; -export declare const groupLayoutHStack: (ctx: PluginContext, params: { - blockIds?: number[]; - padding?: number; -}) => Promise; -export declare const groupLayoutVStack: (ctx: PluginContext, params: { - blockIds?: number[]; - padding?: number; -}) => Promise; -export declare const groupLayoutMasonry: (ctx: PluginContext, params: { - blockIds?: number[]; - cols?: number; - paddingX?: number; - paddingY?: number; -}) => Promise; -export declare const groupLayoutCircle: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/copyStyle.d.ts b/packages/design-batteries/types/commands/copyStyle.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/design-batteries/types/commands/debug.d.ts b/packages/design-batteries/types/commands/debug.d.ts index e69de29..851fb56 100644 --- a/packages/design-batteries/types/commands/debug.d.ts +++ b/packages/design-batteries/types/commands/debug.d.ts @@ -0,0 +1,10 @@ +import { PluginContext } from "@imgly/plugin-api-utils"; +export declare const debugLogBlockProperties: (ctx: PluginContext, params: { + blockIds: number[]; +}) => Promise; +export declare const debugLogBlockCrop: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => void; +export declare const debugLogBlockMetadata: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/export.d.ts b/packages/design-batteries/types/commands/export.d.ts index b6ffdfd..b717165 100644 --- a/packages/design-batteries/types/commands/export.d.ts +++ b/packages/design-batteries/types/commands/export.d.ts @@ -1,7 +1,4 @@ import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const myNewFunctionForTheEditor: (ctx: PluginContext, _params: { - blockIds?: number[]; -}) => Promise; export declare const exportPngToClipboard: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; @@ -32,12 +29,3 @@ export declare const exportSceneToFile: (ctx: PluginContext, params: { export declare const exportJsonToFile: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; -export declare const exportComponentToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const importComponent: (ctx: PluginContext, _params: { - blockIds?: number[]; -}) => Promise; -export declare const exportComponentLibrary: (ctx: PluginContext, _params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/lifecycle.d.ts b/packages/design-batteries/types/commands/lifecycle.d.ts index 53d6692..b3b0399 100644 --- a/packages/design-batteries/types/commands/lifecycle.d.ts +++ b/packages/design-batteries/types/commands/lifecycle.d.ts @@ -5,3 +5,18 @@ export declare const blockDelete: (ctx: PluginContext, params: { export declare const blockDuplicate: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; +export declare const blockRename: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const blockBringForward: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const blockSendBackward: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const blockBringToFront: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; +export declare const blockSendToBack: (ctx: PluginContext, params: { + blockIds?: number[]; +}) => Promise; diff --git a/packages/design-batteries/types/commands/magic.d.ts b/packages/design-batteries/types/commands/magic.d.ts index 3045a80..e69de29 100644 --- a/packages/design-batteries/types/commands/magic.d.ts +++ b/packages/design-batteries/types/commands/magic.d.ts @@ -1,4 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const logCrop: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => void; diff --git a/packages/design-batteries/types/commands/playground.d.ts b/packages/design-batteries/types/commands/playground.d.ts index e98beff..b501812 100644 --- a/packages/design-batteries/types/commands/playground.d.ts +++ b/packages/design-batteries/types/commands/playground.d.ts @@ -2,7 +2,7 @@ import { PluginContext } from "@imgly/plugin-api-utils"; export declare const syncBlocks: (ctx: PluginContext, params: { blockIds?: number[]; }) => Promise; -export declare const registerAndOpenCustomPanel: (ctx: PluginContext, _params: { +export declare const myNewFunctionForTheEditor: (ctx: PluginContext, _params: { blockIds?: number[]; }) => Promise; export declare const productSetInstagram: (ctx: PluginContext, params: { diff --git a/packages/design-batteries/types/commands/syncStyle.d.ts b/packages/design-batteries/types/commands/syncStyle.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/design-batteries/types/index.d.ts b/packages/design-batteries/types/index.d.ts index b0acb9a..d18dfa5 100644 --- a/packages/design-batteries/types/index.d.ts +++ b/packages/design-batteries/types/index.d.ts @@ -1,6 +1,7 @@ import { PluginContext } from '@imgly/plugin-api-utils'; export interface PluginConfiguration { } +export declare const activate: (ctx: PluginContext) => Promise; declare const _default: (ctx: PluginContext, _config: PluginConfiguration) => { initializeUserInterface(): Promise; }; diff --git a/packages/design-batteries/types/utils/download.d.ts b/packages/design-batteries/types/utils/download.d.ts index b2dbcee..644b997 100644 --- a/packages/design-batteries/types/utils/download.d.ts +++ b/packages/design-batteries/types/utils/download.d.ts @@ -1,5 +1,5 @@ import CreativeEditorSDK from "@cesdk/cesdk-js"; -export declare function loadAsBlob(): Promise; +export declare function loadAsBlob(filter?: string): Promise; export declare function downloadBlob(blob: Blob, filename: string): void; export declare const downloadBlocks: (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; diff --git a/packages/vectorizer/package.json b/packages/vectorizer/package.json index 7e7c784..ccb299f 100644 --- a/packages/vectorizer/package.json +++ b/packages/vectorizer/package.json @@ -60,7 +60,7 @@ "typescript": "^5.3.3" }, "peerDependencies": { - "@cesdk/cesdk-js": "~1.20.0" + "@cesdk/cesdk-js": "~1.21.0" }, "dependencies": { "@imgly/vectorizer": "~0.1.0-rc6", diff --git a/packages/vectorizer/src/commands.ts b/packages/vectorizer/src/commands.ts index 8de08a4..6676f50 100644 --- a/packages/vectorizer/src/commands.ts +++ b/packages/vectorizer/src/commands.ts @@ -11,9 +11,6 @@ import { runInWorker } from './utils/worker.shared'; import { createVectorPathBlocks } from './utils/cesdk+utils'; import { PluginContext } from './deps'; - - - export const vectorize = async (context: PluginContext, params: { blockIds?: number[] }) => { const uploader: any = undefined; //cesdk.unstable_upload.bind(cesdk) const {engine} = context; // the only function that needs the ui is the upload function From 8f50f7dd0aa0b72df34b2387a61465ef7b5985aa Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sun, 3 Mar 2024 09:04:13 +0100 Subject: [PATCH 29/32] wip: Improved naming --- CONVENTIONS.md | 6 + examples/web/package.json | 6 +- examples/web/src/App.tsx | 6 +- .../web/src/components/CommandPalette.tsx | 2 +- examples/web/tsconfig.json | 2 +- package.json | 6 +- packages/design-batteries/src/commands.ts | 11 -- .../design-batteries/src/commands/debug.ts | 60 -------- .../design-batteries/src/commands/i18n.ts | 21 --- .../design-batteries/src/commands/magic.ts | 2 - packages/design-batteries/src/locale/en.json | 39 ----- packages/design-batteries/src/types/types.ts | 5 - .../types/PluginManifest.d.ts | 89 ----------- packages/design-batteries/types/commands.d.ts | 9 -- .../types/commands/__template.d.ts | 3 - .../types/commands/container.d.ts | 7 - .../types/commands/debug.d.ts | 10 -- .../types/commands/export.d.ts | 31 ---- .../types/commands/image.d.ts | 10 -- .../types/commands/lifecycle.d.ts | 22 --- .../types/commands/magic.d.ts | 0 .../types/commands/old_debug.d.ts | 0 .../types/commands/playground.d.ts | 13 -- packages/design-batteries/types/index.d.ts | 8 - .../design-batteries/types/types/types.d.ts | 4 - .../design-batteries/types/utils/cesdk.d.ts | 3 - .../types/utils/download.d.ts | 7 - packages/design-batteries/types/worker.d.ts | 0 .../{api-utils => plugin-core}/LICENSE.md | 0 packages/{api-utils => plugin-core}/README.md | 6 +- .../{api-utils => plugin-core}/STRUCTURE.md | 0 packages/{api-utils => plugin-core}/TODO.md | 0 .../esbuild/config.mjs | 0 .../esbuild/global.d.ts | 0 .../{api-utils => plugin-core}/manifest.json | 0 .../{api-utils => plugin-core}/package.json | 2 +- .../scripts/build.mjs | 0 .../scripts/watch.mjs | 0 .../{api-utils => plugin-core}/src/index.ts | 0 .../src/plugin/Commands.ts | 0 .../src/plugin/I18n.ts | 0 .../src/plugin/Logger.ts | 0 .../src/plugin/PluginContext.ts | 0 .../src/plugin/Subscribable.ts | 0 .../src/utils/flatten.ts | 0 .../{api-utils => plugin-core}/src/worker.ts | 0 .../{api-utils => plugin-core}/tsconfig.json | 0 .../types/index.d.ts | 0 .../types/manifest.d.ts | 0 .../types/plugin/Commands.d.ts | 0 .../types/plugin/I18n.d.ts | 1 + .../types/plugin/Logger.d.ts | 0 .../types/plugin/PluginContext.d.ts | 0 .../types/plugin/Subscribable.d.ts | 0 .../types/utils/flatten.d.ts | 0 .../types/worker.d.ts | 0 .../.gitignore | 0 .../esbuild/config.mjs | 0 .../esbuild/global.d.ts | 0 .../manifest.json | 54 +++---- .../package.json | 4 +- .../scripts/build.mjs | 0 .../scripts/watch.mjs | 0 .../src/PluginManifest.ts | 2 +- .../src/commands/__template.ts | 0 .../src/commands/components.ts | 6 +- .../src/commands/container.ts | 8 +- .../src/commands/debug.ts | 140 ++++++++++++++++++ .../src/commands/export.ts | 2 +- .../src/commands/i18n.ts | 21 +++ .../src/commands/image.ts | 2 +- .../src/commands/index.ts | 15 ++ .../src/commands/layout.ts | 2 +- .../src/commands/lifecycle.ts | 2 +- .../src/commands/old_debug.ts | 0 .../src/commands/panels.ts | 61 ++++++++ .../src/commands/playground.ts | 17 ++- .../src/commands/plugins.ts | 2 +- .../src/commands/replicate.io.ts | 91 ++++++++++++ .../src/index.ts | 23 ++- .../src/locale/de.json | 39 +++++ .../src/locale/en.json | 39 +++++ .../src/panels/index.ts | 1 + .../src/panels/layers.ts | 19 +++ .../src/utils/cesdk.ts | 8 +- .../src/utils/computeBlockName.ts | 0 .../src/utils/computeMultiSelectionBounds.ts | 2 +- .../src/utils/download.ts | 0 .../src/utils/exportBlockAs.ts | 2 +- .../src/worker.ts | 0 .../tsconfig.json | 0 .../LICENSE.md | 0 .../PLAYGROUND.md | 0 .../README.md | 6 +- .../STRUCTURE.md | 0 .../{vectorizer => plugin-vectorizer}/TODO.md | 0 .../esbuild/config.mjs | 0 .../esbuild/global.d.ts | 0 .../manifest.json | 0 .../package.json | 4 +- .../scripts/build.mjs | 0 .../scripts/watch.mjs | 0 .../src/PluginManifest.ts | 0 .../src/activate.ts | 0 .../src/commands.ts | 0 .../src/deps.ts | 2 +- .../src/handler.ts | 0 .../src/index.ts | 0 .../src/ui.ts | 0 .../src/utils/cesdk+utils.ts | 0 .../src/utils/common.ts | 0 .../src/utils/types.ts | 0 .../src/utils/worker.shared.ts | 0 .../src/worker.ts | 0 .../tsconfig.json | 0 .../types/PluginManifest.d.ts | 0 .../types/activate.d.ts | 0 .../types/commands.d.ts | 0 .../types/deps.d.ts | 2 +- .../types/handler.d.ts | 0 .../types/index.d.ts | 0 .../types/ui.d.ts | 0 .../types/utils/cesdk+utils.d.ts | 0 .../types/utils/common.d.ts | 0 .../types/utils/types.d.ts | 0 .../types/utils/worker.shared.d.ts | 0 .../types/worker.d.ts | 0 127 files changed, 531 insertions(+), 436 deletions(-) create mode 100644 CONVENTIONS.md delete mode 100644 packages/design-batteries/src/commands.ts delete mode 100644 packages/design-batteries/src/commands/debug.ts delete mode 100644 packages/design-batteries/src/commands/i18n.ts delete mode 100644 packages/design-batteries/src/commands/magic.ts delete mode 100644 packages/design-batteries/src/locale/en.json delete mode 100644 packages/design-batteries/src/types/types.ts delete mode 100644 packages/design-batteries/types/PluginManifest.d.ts delete mode 100644 packages/design-batteries/types/commands.d.ts delete mode 100644 packages/design-batteries/types/commands/__template.d.ts delete mode 100644 packages/design-batteries/types/commands/container.d.ts delete mode 100644 packages/design-batteries/types/commands/debug.d.ts delete mode 100644 packages/design-batteries/types/commands/export.d.ts delete mode 100644 packages/design-batteries/types/commands/image.d.ts delete mode 100644 packages/design-batteries/types/commands/lifecycle.d.ts delete mode 100644 packages/design-batteries/types/commands/magic.d.ts delete mode 100644 packages/design-batteries/types/commands/old_debug.d.ts delete mode 100644 packages/design-batteries/types/commands/playground.d.ts delete mode 100644 packages/design-batteries/types/index.d.ts delete mode 100644 packages/design-batteries/types/types/types.d.ts delete mode 100644 packages/design-batteries/types/utils/cesdk.d.ts delete mode 100644 packages/design-batteries/types/utils/download.d.ts delete mode 100644 packages/design-batteries/types/worker.d.ts rename packages/{api-utils => plugin-core}/LICENSE.md (100%) rename packages/{api-utils => plugin-core}/README.md (88%) rename packages/{api-utils => plugin-core}/STRUCTURE.md (100%) rename packages/{api-utils => plugin-core}/TODO.md (100%) rename packages/{api-utils => plugin-core}/esbuild/config.mjs (100%) rename packages/{api-utils => plugin-core}/esbuild/global.d.ts (100%) rename packages/{api-utils => plugin-core}/manifest.json (100%) rename packages/{api-utils => plugin-core}/package.json (97%) rename packages/{api-utils => plugin-core}/scripts/build.mjs (100%) rename packages/{api-utils => plugin-core}/scripts/watch.mjs (100%) rename packages/{api-utils => plugin-core}/src/index.ts (100%) rename packages/{api-utils => plugin-core}/src/plugin/Commands.ts (100%) rename packages/{api-utils => plugin-core}/src/plugin/I18n.ts (100%) rename packages/{api-utils => plugin-core}/src/plugin/Logger.ts (100%) rename packages/{api-utils => plugin-core}/src/plugin/PluginContext.ts (100%) rename packages/{api-utils => plugin-core}/src/plugin/Subscribable.ts (100%) rename packages/{api-utils => plugin-core}/src/utils/flatten.ts (100%) rename packages/{api-utils => plugin-core}/src/worker.ts (100%) rename packages/{api-utils => plugin-core}/tsconfig.json (100%) rename packages/{api-utils => plugin-core}/types/index.d.ts (100%) rename packages/{api-utils => plugin-core}/types/manifest.d.ts (100%) rename packages/{api-utils => plugin-core}/types/plugin/Commands.d.ts (100%) rename packages/{api-utils => plugin-core}/types/plugin/I18n.d.ts (94%) rename packages/{api-utils => plugin-core}/types/plugin/Logger.d.ts (100%) rename packages/{api-utils => plugin-core}/types/plugin/PluginContext.d.ts (100%) rename packages/{api-utils => plugin-core}/types/plugin/Subscribable.d.ts (100%) rename packages/{api-utils => plugin-core}/types/utils/flatten.d.ts (100%) rename packages/{api-utils => plugin-core}/types/worker.d.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/.gitignore (100%) rename packages/{design-batteries => plugin-design-essentials}/esbuild/config.mjs (100%) rename packages/{design-batteries => plugin-design-essentials}/esbuild/global.d.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/manifest.json (87%) rename packages/{design-batteries => plugin-design-essentials}/package.json (95%) rename packages/{design-batteries => plugin-design-essentials}/scripts/build.mjs (100%) rename packages/{design-batteries => plugin-design-essentials}/scripts/watch.mjs (100%) rename packages/{design-batteries => plugin-design-essentials}/src/PluginManifest.ts (83%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/__template.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/components.ts (89%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/container.ts (76%) create mode 100644 packages/plugin-design-essentials/src/commands/debug.ts rename packages/{design-batteries => plugin-design-essentials}/src/commands/export.ts (98%) create mode 100644 packages/plugin-design-essentials/src/commands/i18n.ts rename packages/{design-batteries => plugin-design-essentials}/src/commands/image.ts (93%) create mode 100644 packages/plugin-design-essentials/src/commands/index.ts rename packages/{design-batteries => plugin-design-essentials}/src/commands/layout.ts (98%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/lifecycle.ts (97%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/old_debug.ts (100%) create mode 100644 packages/plugin-design-essentials/src/commands/panels.ts rename packages/{design-batteries => plugin-design-essentials}/src/commands/playground.ts (97%) rename packages/{design-batteries => plugin-design-essentials}/src/commands/plugins.ts (87%) create mode 100644 packages/plugin-design-essentials/src/commands/replicate.io.ts rename packages/{design-batteries => plugin-design-essentials}/src/index.ts (76%) create mode 100644 packages/plugin-design-essentials/src/locale/de.json create mode 100644 packages/plugin-design-essentials/src/locale/en.json create mode 100644 packages/plugin-design-essentials/src/panels/index.ts create mode 100644 packages/plugin-design-essentials/src/panels/layers.ts rename packages/{design-batteries => plugin-design-essentials}/src/utils/cesdk.ts (90%) rename packages/{design-batteries => plugin-design-essentials}/src/utils/computeBlockName.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/src/utils/computeMultiSelectionBounds.ts (91%) rename packages/{design-batteries => plugin-design-essentials}/src/utils/download.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/src/utils/exportBlockAs.ts (95%) rename packages/{design-batteries => plugin-design-essentials}/src/worker.ts (100%) rename packages/{design-batteries => plugin-design-essentials}/tsconfig.json (100%) rename packages/{vectorizer => plugin-vectorizer}/LICENSE.md (100%) rename packages/{vectorizer => plugin-vectorizer}/PLAYGROUND.md (100%) rename packages/{vectorizer => plugin-vectorizer}/README.md (88%) rename packages/{vectorizer => plugin-vectorizer}/STRUCTURE.md (100%) rename packages/{vectorizer => plugin-vectorizer}/TODO.md (100%) rename packages/{vectorizer => plugin-vectorizer}/esbuild/config.mjs (100%) rename packages/{vectorizer => plugin-vectorizer}/esbuild/global.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/manifest.json (100%) rename packages/{vectorizer => plugin-vectorizer}/package.json (96%) rename packages/{vectorizer => plugin-vectorizer}/scripts/build.mjs (100%) rename packages/{vectorizer => plugin-vectorizer}/scripts/watch.mjs (100%) rename packages/{vectorizer => plugin-vectorizer}/src/PluginManifest.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/activate.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/commands.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/deps.ts (88%) rename packages/{vectorizer => plugin-vectorizer}/src/handler.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/index.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/ui.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/utils/cesdk+utils.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/utils/common.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/utils/types.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/utils/worker.shared.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/src/worker.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/tsconfig.json (100%) rename packages/{vectorizer => plugin-vectorizer}/types/PluginManifest.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/activate.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/commands.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/deps.d.ts (88%) rename packages/{vectorizer => plugin-vectorizer}/types/handler.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/index.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/ui.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/utils/cesdk+utils.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/utils/common.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/utils/types.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/utils/worker.shared.d.ts (100%) rename packages/{vectorizer => plugin-vectorizer}/types/worker.d.ts (100%) diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 0000000..17de935 --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,6 @@ +## Conventions + +- all exports from `commands.ts` are treated and registered as commands. The `id` is autogenerated from `${manifest.id}.commands.${exportname} +- commands can be categorized by `_`. As such `block_bringToFront` belong to category `block` +- id and category can also be manually overwritten in the `manifest` +- translation keys are the id of the command. use `en.json` \ No newline at end of file diff --git a/examples/web/package.json b/examples/web/package.json index 96452d0..571a654 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -10,10 +10,10 @@ }, "dependencies": { "@cesdk/cesdk-js": "^1.21.0", - "@imgly/plugin-api-utils": "*", + "@imgly/plugin-core": "*", "@imgly/plugin-background-removal-web": "*", - "@imgly/plugin-vectorizer-web": "*", - "@imgly/plugin-design-batteries": "*", + "@imgly/plugin-vectorizer": "*", + "@imgly/plugin-design-essentials": "*", "lodash": "^4.17.21", "react": "^18.2.0", "react-cmdk": "^1.3.9", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 74ae8ef..ad6e453 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -15,9 +15,9 @@ import { downloadBlocks } from "./utils/download"; // Plugins // import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; -import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; -import DesignBatteriesPlugin from "@imgly/plugin-design-batteries"; -import { PluginContext } from "@imgly/plugin-api-utils"; +import VectorizerPlugin from '@imgly/plugin-vectorizer'; +import DesignBatteriesPlugin from "@imgly/plugin-design-essentials"; +import { PluginContext } from "@imgly/plugin-core"; declare global { diff --git a/examples/web/src/components/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx index 1056073..1681c82 100644 --- a/examples/web/src/components/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -17,7 +17,7 @@ export const CommandPalette = (params: Params) => { useEffect(() => { function handleKeyDown(e: KeyboardEvent) { if ( - (navigator?.platform?.toLowerCase().includes("mac") + (navigator?.userAgent?.toLowerCase().includes("mac") ? e.metaKey : e.ctrlKey) && e.key === "k" diff --git a/examples/web/tsconfig.json b/examples/web/tsconfig.json index 31f6cb1..3d69b79 100644 --- a/examples/web/tsconfig.json +++ b/examples/web/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src", "../imgly-components-source", "../../packages/design-batteries/src/commands", "../../packages/design-batteries/src/types", "../../packages/design-batteries/src/utils", "../../packages/design-batteries/src/commands.ts", "../../packages/design-batteries/src/index.ts", "../../packages/design-batteries/src/PluginManifest.ts"], + "include": ["src", "../imgly-components-source", "../../packages/design-batteries/src/commands", "../../packages/design-batteries/src/types", "../../packages/design-batteries/src/utils", "../../packages/design-batteries/src/commands/index.ts", "../../packages/design-batteries/src/index.ts", "../../packages/design-batteries/src/PluginManifest.ts"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/package.json b/package.json index 6f5dd39..33d059c 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "version": "0.0.0", "workspaces": [ "examples/web", - "packages/api-utils", - "packages/design-batteries", + "packages/plugin-core", + "packages/plugin-design-essentials", "packages/background-removal", - "packages/vectorizer" + "packages/plugin-vectorizer" ], "scripts": { diff --git a/packages/design-batteries/src/commands.ts b/packages/design-batteries/src/commands.ts deleted file mode 100644 index 929c58a..0000000 --- a/packages/design-batteries/src/commands.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from "./commands/lifecycle"; -export * from "./commands/export"; -export * from "./commands/image"; -export * from "./commands/container"; -export * from "./commands/layout"; -// export * from "./commands/magic"; -export * from "./commands/debug"; -export * from "./commands/plugins"; -export * from "./commands/components"; -export * from "./commands/playground"; -export * from "./commands/i18n"; \ No newline at end of file diff --git a/packages/design-batteries/src/commands/debug.ts b/packages/design-batteries/src/commands/debug.ts deleted file mode 100644 index 6047a15..0000000 --- a/packages/design-batteries/src/commands/debug.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -import { readPropValue } from "../utils/cesdk"; - -export const debugLogBlockProperties = async (ctx: PluginContext, params: { blockIds: number[] }) => { - const { block, scene } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - - blockIds.forEach((bId: number) => { - const props = block.findAllProperties(bId) - const propDefinition = new Map() - props.forEach((propKey: string) => { - if (!block.isPropertyReadable(propKey)) return; - const propType = block.getPropertyType(propKey) - const propValue = readPropValue(block, bId, propKey, propType) - propDefinition.set(propKey, { type: propType, value: propValue }) - }) - console.debug("Properties for block", bId, propDefinition) - }) -} - -export const debugLogBlockCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - - blockIds.forEach((id: number) => { - const x = block.getCropTranslationX(id) - const y = block.getCropTranslationY(id) - const scaleX = block.getCropScaleX(id) - const scaleY = block.getCropScaleY(id) - const fillMode = block.getContentFillMode(id) - const crop = { - x, y, scaleX, scaleY, fillMode - } - console.debug("Crop for block", id, crop) - }); - -} - - - -export const debugLogBlockMetadata = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - - - blockIds.forEach((id: number) => { - const keys = block.findAllMetadata(id) - if (keys.length === 0) { - console.debug("No metadata for block", id) - return - } - const map = new Map() - keys.forEach((key: string) => { - const metadata = block.getMetadata(id, key) - const obj = JSON.parse(metadata) - map.set(key, obj) - }) - console.debug("Metadata for block", id, map) - }) -} diff --git a/packages/design-batteries/src/commands/i18n.ts b/packages/design-batteries/src/commands/i18n.ts deleted file mode 100644 index a4203b4..0000000 --- a/packages/design-batteries/src/commands/i18n.ts +++ /dev/null @@ -1,21 +0,0 @@ - -import { downloadBlob } from "../utils/download"; -import { PluginContext } from "@imgly/plugin-api-utils"; // Add this import statement - -export const i18nDownloadMissingCommandTranslations = (ctx: PluginContext) => { - const { i18n, commands } = ctx; - - const missingCommandTranslations = commands.listCommands().map((cmd) => { - if (!i18n.hasTranslation(cmd)) { - return [cmd, cmd.split(".").pop()] - } - else null - }).filter(Boolean) - - if (missingCommandTranslations.length > 0) { - const ob = Object.fromEntries(missingCommandTranslations) - const json = JSON.stringify(ob, null, 2) - const blob = new Blob([json], { type: "application/json" }) - downloadBlob(blob, `${i18n.locale()}.json`) - } -} \ No newline at end of file diff --git a/packages/design-batteries/src/commands/magic.ts b/packages/design-batteries/src/commands/magic.ts deleted file mode 100644 index b885a08..0000000 --- a/packages/design-batteries/src/commands/magic.ts +++ /dev/null @@ -1,2 +0,0 @@ -// https://github.com/jwagner/smartcrop.js - diff --git a/packages/design-batteries/src/locale/en.json b/packages/design-batteries/src/locale/en.json deleted file mode 100644 index 4c95f58..0000000 --- a/packages/design-batteries/src/locale/en.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "design-batteries.commands.blockDelete": "Delete Block", - "design-batteries.commands.blockDuplicate": "Duplicate Block", - "design-batteries.commands.exportPngToClipboard": "Export PNG to Clipboard", - "design-batteries.commands.exportPngToFile": "Export PNG to File", - "design-batteries.commands.exportJpegToFile": "Export JPEG to File", - "design-batteries.commands.exportWebpToFile": "Export WEP to File", - "design-batteries.commands.exportPdfToFile": "Export PDF to File", - "design-batteries.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", - "design-batteries.commands.exportSceneToClipboard": "Export Scene to Clipboard", - "design-batteries.commands.exportJsonToClipboard": "Export JSON to Clipboard", - "design-batteries.commands.exportSceneToFile": "Export Scene to File", - "design-batteries.commands.exportJsonToFile": "Export JSON to File", - "design-batteries.commands.imageFitModeContain": "Set Image FitMode to Contain", - "design-batteries.commands.imageFitModeCrop": "Set Image FitMode to Crop", - "design-batteries.commands.imageFitModeCover": "Set Image FitMode to Cover", - "design-batteries.commands.exportComponentToFile": "Export Component to File", - "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function", - "design-batteries.commands.blockBringForward": "blockBringForward", - "design-batteries.commands.blockBringToFront": "blockBringToFront", - "design-batteries.commands.blockRename": "blockRename", - "design-batteries.commands.blockSendBackward": "blockSendBackward", - "design-batteries.commands.blockSendToBack": "blockSendToBack", - "design-batteries.commands.debugLogBlockCrop": "debugLogBlockCrop", - "design-batteries.commands.debugLogBlockMetadata": "debugLogBlockMetadata", - "design-batteries.commands.debugLogBlockProperties": "debugLogBlockProperties", - "design-batteries.commands.exportComponentLibrary": "exportComponentLibrary", - "design-batteries.commands.groupBlocks": "groupBlocks", - "design-batteries.commands.i18nDownloadMissingCommandTranslations": "i18nDownloadMissingCommandTranslations", - "design-batteries.commands.importComponent": "importComponent", - "design-batteries.commands.layoutHorizontally": "layoutHorizontally", - "design-batteries.commands.layoutMasonry": "layoutMasonry", - "design-batteries.commands.layoutVertically": "layoutVertically", - "design-batteries.commands.playground": "playground", - "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "pluginRegisterAndOpenCustomPanel", - "design-batteries.commands.productSetInstagram": "productSetInstagram", - "design-batteries.commands.syncBlocks": "syncBlocks", - "design-batteries.commands.ungroupBlocks": "ungroupBlocks" -} \ No newline at end of file diff --git a/packages/design-batteries/src/types/types.ts b/packages/design-batteries/src/types/types.ts deleted file mode 100644 index a2020d3..0000000 --- a/packages/design-batteries/src/types/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type Unsubscribe = () => void; - -export type CommandArg = { - blockIds: number[] | undefined; -} \ No newline at end of file diff --git a/packages/design-batteries/types/PluginManifest.d.ts b/packages/design-batteries/types/PluginManifest.d.ts deleted file mode 100644 index 666f2f0..0000000 --- a/packages/design-batteries/types/PluginManifest.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -import Manifest from '../manifest.json'; -import { CommandCallback } from '@imgly/plugin-api-utils'; -export type Contributions = typeof Manifest; -export type CommandContributions = keyof typeof Manifest["contributes"]["commands"]; -export type CommandImports = Record; -export declare const PluginManifest: { - id: string; - version: string; - publisher: string; - icon: any; - categories: any[]; - contributes: { - commands: { - blockDelete: { - category: string; - }; - blockDuplicate: { - category: string; - }; - exportPngToClipboard: { - category: string; - }; - exportPngToFile: { - category: string; - }; - exportJpegToFile: { - category: string; - }; - exportWebpToFile: { - category: string; - }; - exportRgba8ToFile: { - category: string; - }; - exportPdfToFile: { - category: string; - }; - exportSceneToFile: { - category: string; - }; - exportSceneToClipboard: { - category: string; - }; - exportJsonToClipboard: { - category: string; - }; - exportJsonToFile: { - category: string; - }; - exportComponentToFile: { - category: string; - }; - imageFitModeCrop: { - category: string; - }; - imageFitModeContain: { - category: string; - }; - imageFitModeCover: { - category: string; - }; - groupBlocks: { - category: string; - }; - ungroupBlocks: { - category: string; - }; - layoutHorizontally: { - category: string; - }; - layoutVertically: { - category: string; - }; - layoutMasonry: { - category: string; - }; - productSetInstagram: { - category: string; - }; - playground: { - category: string; - }; - syncBlocks: { - category: string; - }; - }; - i18n: {}; - }; -}; diff --git a/packages/design-batteries/types/commands.d.ts b/packages/design-batteries/types/commands.d.ts deleted file mode 100644 index 8b284b6..0000000 --- a/packages/design-batteries/types/commands.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./commands/lifecycle"; -export * from "./commands/export"; -export * from "./commands/image"; -export * from "./commands/container"; -export * from "./commands/layout"; -export * from "./commands/debug"; -export * from "./commands/plugins"; -export * from "./commands/components"; -export * from "./commands/playground"; diff --git a/packages/design-batteries/types/commands/__template.d.ts b/packages/design-batteries/types/commands/__template.d.ts deleted file mode 100644 index 5fd6f48..0000000 --- a/packages/design-batteries/types/commands/__template.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare const __template: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/container.d.ts b/packages/design-batteries/types/commands/container.d.ts deleted file mode 100644 index 5716765..0000000 --- a/packages/design-batteries/types/commands/container.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const groupBlocks: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const ungroupBlocks: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/debug.d.ts b/packages/design-batteries/types/commands/debug.d.ts deleted file mode 100644 index 851fb56..0000000 --- a/packages/design-batteries/types/commands/debug.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const debugLogBlockProperties: (ctx: PluginContext, params: { - blockIds: number[]; -}) => Promise; -export declare const debugLogBlockCrop: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => void; -export declare const debugLogBlockMetadata: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/export.d.ts b/packages/design-batteries/types/commands/export.d.ts deleted file mode 100644 index b717165..0000000 --- a/packages/design-batteries/types/commands/export.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const exportPngToClipboard: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportSceneToClipboard: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportJsonToClipboard: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportPngToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportJpegToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportWebpToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportPdfToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportRgba8ToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportSceneToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const exportJsonToFile: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/image.d.ts b/packages/design-batteries/types/commands/image.d.ts deleted file mode 100644 index 3d52777..0000000 --- a/packages/design-batteries/types/commands/image.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const imageFitModeCrop: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const imageFitModeCover: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const imageFitModeContain: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/lifecycle.d.ts b/packages/design-batteries/types/commands/lifecycle.d.ts deleted file mode 100644 index b3b0399..0000000 --- a/packages/design-batteries/types/commands/lifecycle.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const blockDelete: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockDuplicate: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockRename: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockBringForward: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockSendBackward: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockBringToFront: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const blockSendToBack: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/commands/magic.d.ts b/packages/design-batteries/types/commands/magic.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/design-batteries/types/commands/old_debug.d.ts b/packages/design-batteries/types/commands/old_debug.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/design-batteries/types/commands/playground.d.ts b/packages/design-batteries/types/commands/playground.d.ts deleted file mode 100644 index b501812..0000000 --- a/packages/design-batteries/types/commands/playground.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; -export declare const syncBlocks: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const myNewFunctionForTheEditor: (ctx: PluginContext, _params: { - blockIds?: number[]; -}) => Promise; -export declare const productSetInstagram: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; -export declare const playground: (ctx: PluginContext, params: { - blockIds?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/index.d.ts b/packages/design-batteries/types/index.d.ts deleted file mode 100644 index d18dfa5..0000000 --- a/packages/design-batteries/types/index.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PluginContext } from '@imgly/plugin-api-utils'; -export interface PluginConfiguration { -} -export declare const activate: (ctx: PluginContext) => Promise; -declare const _default: (ctx: PluginContext, _config: PluginConfiguration) => { - initializeUserInterface(): Promise; -}; -export default _default; diff --git a/packages/design-batteries/types/types/types.d.ts b/packages/design-batteries/types/types/types.d.ts deleted file mode 100644 index 3053eb1..0000000 --- a/packages/design-batteries/types/types/types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Unsubscribe = () => void; -export type CommandArg = { - blockIds: number[] | undefined; -}; diff --git a/packages/design-batteries/types/utils/cesdk.d.ts b/packages/design-batteries/types/utils/cesdk.d.ts deleted file mode 100644 index 4fb52e8..0000000 --- a/packages/design-batteries/types/utils/cesdk.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BlockAPI } from "@cesdk/cesdk-js"; -export declare const readPropValue: (block: BlockAPI, id: number, propKey: string, propType?: string) => string | number | boolean | (import("@cesdk/cesdk-js").RGBAColor | import("@cesdk/cesdk-js").CMYKColor | import("@cesdk/cesdk-js").SpotColor); -export declare const writePropValue: (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => void; diff --git a/packages/design-batteries/types/utils/download.d.ts b/packages/design-batteries/types/utils/download.d.ts deleted file mode 100644 index 644b997..0000000 --- a/packages/design-batteries/types/utils/download.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import CreativeEditorSDK from "@cesdk/cesdk-js"; -export declare function loadAsBlob(filter?: string): Promise; -export declare function downloadBlob(blob: Blob, filename: string): void; -export declare const downloadBlocks: (cesdk: CreativeEditorSDK, blobs: Blob[], options: { - mimeType: string; - pages?: number[]; -}) => Promise; diff --git a/packages/design-batteries/types/worker.d.ts b/packages/design-batteries/types/worker.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/api-utils/LICENSE.md b/packages/plugin-core/LICENSE.md similarity index 100% rename from packages/api-utils/LICENSE.md rename to packages/plugin-core/LICENSE.md diff --git a/packages/api-utils/README.md b/packages/plugin-core/README.md similarity index 88% rename from packages/api-utils/README.md rename to packages/plugin-core/README.md index e4197b5..6acc73e 100644 --- a/packages/api-utils/README.md +++ b/packages/plugin-core/README.md @@ -7,8 +7,8 @@ This plugin introduces a vectorizer for the CE.SDK editor. You can install the plugin via npm or yarn. Use the following commands to install the package: ``` -yarn add @imgly/plugin-vectorizer-web -npm install @imgly/plugin-vectorizer-web +yarn add @imgly/plugin-vectorizer +npm install @imgly/plugin-vectorizer ``` ## Usage @@ -18,7 +18,7 @@ canvas menu entry for every block with an image fill. ```typescript import CreativeEditorSDK from '@cesdk/cesdk-js'; -import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; +import VectorizerPlugin from '@imgly/plugin-vectorizer'; const config = { license: '', diff --git a/packages/api-utils/STRUCTURE.md b/packages/plugin-core/STRUCTURE.md similarity index 100% rename from packages/api-utils/STRUCTURE.md rename to packages/plugin-core/STRUCTURE.md diff --git a/packages/api-utils/TODO.md b/packages/plugin-core/TODO.md similarity index 100% rename from packages/api-utils/TODO.md rename to packages/plugin-core/TODO.md diff --git a/packages/api-utils/esbuild/config.mjs b/packages/plugin-core/esbuild/config.mjs similarity index 100% rename from packages/api-utils/esbuild/config.mjs rename to packages/plugin-core/esbuild/config.mjs diff --git a/packages/api-utils/esbuild/global.d.ts b/packages/plugin-core/esbuild/global.d.ts similarity index 100% rename from packages/api-utils/esbuild/global.d.ts rename to packages/plugin-core/esbuild/global.d.ts diff --git a/packages/api-utils/manifest.json b/packages/plugin-core/manifest.json similarity index 100% rename from packages/api-utils/manifest.json rename to packages/plugin-core/manifest.json diff --git a/packages/api-utils/package.json b/packages/plugin-core/package.json similarity index 97% rename from packages/api-utils/package.json rename to packages/plugin-core/package.json index ef7af4f..84a7ad7 100644 --- a/packages/api-utils/package.json +++ b/packages/plugin-core/package.json @@ -1,5 +1,5 @@ { - "name": "@imgly/plugin-api-utils", + "name": "@imgly/plugin-core", "version": "0.1.0", "description": "Polyfill for API plugin for the CE.SDK editor", "keywords": [ diff --git a/packages/api-utils/scripts/build.mjs b/packages/plugin-core/scripts/build.mjs similarity index 100% rename from packages/api-utils/scripts/build.mjs rename to packages/plugin-core/scripts/build.mjs diff --git a/packages/api-utils/scripts/watch.mjs b/packages/plugin-core/scripts/watch.mjs similarity index 100% rename from packages/api-utils/scripts/watch.mjs rename to packages/plugin-core/scripts/watch.mjs diff --git a/packages/api-utils/src/index.ts b/packages/plugin-core/src/index.ts similarity index 100% rename from packages/api-utils/src/index.ts rename to packages/plugin-core/src/index.ts diff --git a/packages/api-utils/src/plugin/Commands.ts b/packages/plugin-core/src/plugin/Commands.ts similarity index 100% rename from packages/api-utils/src/plugin/Commands.ts rename to packages/plugin-core/src/plugin/Commands.ts diff --git a/packages/api-utils/src/plugin/I18n.ts b/packages/plugin-core/src/plugin/I18n.ts similarity index 100% rename from packages/api-utils/src/plugin/I18n.ts rename to packages/plugin-core/src/plugin/I18n.ts diff --git a/packages/api-utils/src/plugin/Logger.ts b/packages/plugin-core/src/plugin/Logger.ts similarity index 100% rename from packages/api-utils/src/plugin/Logger.ts rename to packages/plugin-core/src/plugin/Logger.ts diff --git a/packages/api-utils/src/plugin/PluginContext.ts b/packages/plugin-core/src/plugin/PluginContext.ts similarity index 100% rename from packages/api-utils/src/plugin/PluginContext.ts rename to packages/plugin-core/src/plugin/PluginContext.ts diff --git a/packages/api-utils/src/plugin/Subscribable.ts b/packages/plugin-core/src/plugin/Subscribable.ts similarity index 100% rename from packages/api-utils/src/plugin/Subscribable.ts rename to packages/plugin-core/src/plugin/Subscribable.ts diff --git a/packages/api-utils/src/utils/flatten.ts b/packages/plugin-core/src/utils/flatten.ts similarity index 100% rename from packages/api-utils/src/utils/flatten.ts rename to packages/plugin-core/src/utils/flatten.ts diff --git a/packages/api-utils/src/worker.ts b/packages/plugin-core/src/worker.ts similarity index 100% rename from packages/api-utils/src/worker.ts rename to packages/plugin-core/src/worker.ts diff --git a/packages/api-utils/tsconfig.json b/packages/plugin-core/tsconfig.json similarity index 100% rename from packages/api-utils/tsconfig.json rename to packages/plugin-core/tsconfig.json diff --git a/packages/api-utils/types/index.d.ts b/packages/plugin-core/types/index.d.ts similarity index 100% rename from packages/api-utils/types/index.d.ts rename to packages/plugin-core/types/index.d.ts diff --git a/packages/api-utils/types/manifest.d.ts b/packages/plugin-core/types/manifest.d.ts similarity index 100% rename from packages/api-utils/types/manifest.d.ts rename to packages/plugin-core/types/manifest.d.ts diff --git a/packages/api-utils/types/plugin/Commands.d.ts b/packages/plugin-core/types/plugin/Commands.d.ts similarity index 100% rename from packages/api-utils/types/plugin/Commands.d.ts rename to packages/plugin-core/types/plugin/Commands.d.ts diff --git a/packages/api-utils/types/plugin/I18n.d.ts b/packages/plugin-core/types/plugin/I18n.d.ts similarity index 94% rename from packages/api-utils/types/plugin/I18n.d.ts rename to packages/plugin-core/types/plugin/I18n.d.ts index 2ee29d4..ba0b245 100644 --- a/packages/api-utils/types/plugin/I18n.d.ts +++ b/packages/plugin-core/types/plugin/I18n.d.ts @@ -9,6 +9,7 @@ export declare class I18N extends Subscribable<"regis constructor(ctx: PluginContext); setTranslations(translations: Translations): void; translate(key: K, fallback?: string | undefined): any; + findTranslation(key: K, language?: string): any; hasTranslation(key: K, language?: string): boolean; setLocale(locale: string): void; locale(): string; diff --git a/packages/api-utils/types/plugin/Logger.d.ts b/packages/plugin-core/types/plugin/Logger.d.ts similarity index 100% rename from packages/api-utils/types/plugin/Logger.d.ts rename to packages/plugin-core/types/plugin/Logger.d.ts diff --git a/packages/api-utils/types/plugin/PluginContext.d.ts b/packages/plugin-core/types/plugin/PluginContext.d.ts similarity index 100% rename from packages/api-utils/types/plugin/PluginContext.d.ts rename to packages/plugin-core/types/plugin/PluginContext.d.ts diff --git a/packages/api-utils/types/plugin/Subscribable.d.ts b/packages/plugin-core/types/plugin/Subscribable.d.ts similarity index 100% rename from packages/api-utils/types/plugin/Subscribable.d.ts rename to packages/plugin-core/types/plugin/Subscribable.d.ts diff --git a/packages/api-utils/types/utils/flatten.d.ts b/packages/plugin-core/types/utils/flatten.d.ts similarity index 100% rename from packages/api-utils/types/utils/flatten.d.ts rename to packages/plugin-core/types/utils/flatten.d.ts diff --git a/packages/api-utils/types/worker.d.ts b/packages/plugin-core/types/worker.d.ts similarity index 100% rename from packages/api-utils/types/worker.d.ts rename to packages/plugin-core/types/worker.d.ts diff --git a/packages/design-batteries/.gitignore b/packages/plugin-design-essentials/.gitignore similarity index 100% rename from packages/design-batteries/.gitignore rename to packages/plugin-design-essentials/.gitignore diff --git a/packages/design-batteries/esbuild/config.mjs b/packages/plugin-design-essentials/esbuild/config.mjs similarity index 100% rename from packages/design-batteries/esbuild/config.mjs rename to packages/plugin-design-essentials/esbuild/config.mjs diff --git a/packages/design-batteries/esbuild/global.d.ts b/packages/plugin-design-essentials/esbuild/global.d.ts similarity index 100% rename from packages/design-batteries/esbuild/global.d.ts rename to packages/plugin-design-essentials/esbuild/global.d.ts diff --git a/packages/design-batteries/manifest.json b/packages/plugin-design-essentials/manifest.json similarity index 87% rename from packages/design-batteries/manifest.json rename to packages/plugin-design-essentials/manifest.json index 7d1a974..3a887eb 100644 --- a/packages/design-batteries/manifest.json +++ b/packages/plugin-design-essentials/manifest.json @@ -7,46 +7,49 @@ "contributes": { "commands": { "blockDelete": { - "category": "lifecycle" + "category": "block" }, "blockDuplicate": { - "category": "lifecycle" + "category": "block" }, - "exportPngToClipboard": { - "category": "export" + "blockGroup": { + "category": "block" }, - "exportPngToFile": { + "blockUngroup": { + "category": "block" + }, + "exportComponentToFile": { "category": "export" }, - "exportJpegToFile": { + "exportJsonToClipboard": { "category": "export" }, - "exportWebpToFile": { + "exportJsonToFile": { "category": "export" }, - "exportRgba8ToFile": { + "exportJpegToFile": { "category": "export" }, "exportPdfToFile": { "category": "export" }, - "exportSceneToFile": { + "exportPngToClipboard": { "category": "export" }, - "exportSceneToClipboard": { + "exportPngToFile": { "category": "export" }, - "exportJsonToClipboard": { + "exportRgba8ToFile": { "category": "export" }, - "exportJsonToFile": { + "exportSceneToClipboard": { "category": "export" }, - "exportComponentToFile": { + "exportSceneToFile": { "category": "export" }, - "imageFitModeCrop": { - "category": "image" + "exportWebpToFile": { + "category": "export" }, "imageFitModeContain": { "category": "image" @@ -54,29 +57,26 @@ "imageFitModeCover": { "category": "image" }, - "groupBlocks": { - "category": "category" - }, - "ungroupBlocks": { - "category": "category" + "imageFitModeCrop": { + "category": "image" }, "layoutHorizontally": { "category": "layout" }, - "layoutVertically": { - "category": "layout" - }, "layoutMasonry": { "category": "layout" }, - "productSetInstagram": { - "category": "product" + "layoutVertically": { + "category": "layout" }, "playground": { "category": "playground" }, - "syncBlocks": { - "category": "lifecycle" + "productSetInstagram": { + "category": "product" + }, + "syncBlockAppearance": { + "category": "sync" } }, "i18n": {} diff --git a/packages/design-batteries/package.json b/packages/plugin-design-essentials/package.json similarity index 95% rename from packages/design-batteries/package.json rename to packages/plugin-design-essentials/package.json index 044e150..c034b02 100644 --- a/packages/design-batteries/package.json +++ b/packages/plugin-design-essentials/package.json @@ -1,5 +1,5 @@ { - "name": "@imgly/plugin-design-batteries", + "name": "@imgly/plugin-design-essentials", "version": "0.1.0", "description": "Vectorizer plugin for the CE.SDK editor", "keywords": [ @@ -63,7 +63,7 @@ "@cesdk/cesdk-js": "~1.21.0" }, "dependencies": { - "@imgly/plugin-api-utils": "*", + "@imgly/plugin-core": "*", "lodash": "^4.17.21" } } diff --git a/packages/design-batteries/scripts/build.mjs b/packages/plugin-design-essentials/scripts/build.mjs similarity index 100% rename from packages/design-batteries/scripts/build.mjs rename to packages/plugin-design-essentials/scripts/build.mjs diff --git a/packages/design-batteries/scripts/watch.mjs b/packages/plugin-design-essentials/scripts/watch.mjs similarity index 100% rename from packages/design-batteries/scripts/watch.mjs rename to packages/plugin-design-essentials/scripts/watch.mjs diff --git a/packages/design-batteries/src/PluginManifest.ts b/packages/plugin-design-essentials/src/PluginManifest.ts similarity index 83% rename from packages/design-batteries/src/PluginManifest.ts rename to packages/plugin-design-essentials/src/PluginManifest.ts index 03f47a5..4eb5576 100644 --- a/packages/design-batteries/src/PluginManifest.ts +++ b/packages/plugin-design-essentials/src/PluginManifest.ts @@ -1,5 +1,5 @@ import Manifest from '../manifest.json'; -import { CommandCallback } from '@imgly/plugin-api-utils'; +import { CommandCallback } from '../../plugin-core/types'; export type Contributions = typeof Manifest;["contributes"] diff --git a/packages/design-batteries/src/commands/__template.ts b/packages/plugin-design-essentials/src/commands/__template.ts similarity index 100% rename from packages/design-batteries/src/commands/__template.ts rename to packages/plugin-design-essentials/src/commands/__template.ts diff --git a/packages/design-batteries/src/commands/components.ts b/packages/plugin-design-essentials/src/commands/components.ts similarity index 89% rename from packages/design-batteries/src/commands/components.ts rename to packages/plugin-design-essentials/src/commands/components.ts index 4454086..81c187e 100644 --- a/packages/design-batteries/src/commands/components.ts +++ b/packages/plugin-design-essentials/src/commands/components.ts @@ -1,5 +1,5 @@ import { MimeType } from "@cesdk/cesdk-js"; -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; import { downloadBlob, loadAsBlob } from "../utils/download"; import { inferBlockName } from "../utils/computeBlockName"; @@ -13,12 +13,10 @@ export const exportComponentToFile = async (ctx: PluginContext, params: { blockI const thumbnail = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "image/png" as MimeType, width: 256, height: 256 }); const cesdk = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/x-cesdk" }); - const json = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/json" }); - // const zip = await exportBlockAs(ctx, { blockIds: [bId], mimeType: "application/zip" as MimeType }) return { thumbnail: thumbnail[0], cesdk: cesdk[0], - json: json[0], + // zip: zip[0], }; })); diff --git a/packages/design-batteries/src/commands/container.ts b/packages/plugin-design-essentials/src/commands/container.ts similarity index 76% rename from packages/design-batteries/src/commands/container.ts rename to packages/plugin-design-essentials/src/commands/container.ts index c77452b..7a980e3 100644 --- a/packages/design-batteries/src/commands/container.ts +++ b/packages/plugin-design-essentials/src/commands/container.ts @@ -1,7 +1,7 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; -export const groupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const blockGroup = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected(), @@ -14,7 +14,7 @@ export const groupBlocks = async (ctx: PluginContext, params: { blockIds?: numbe } -export const ungroupBlocks = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +export const blockUngroup = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { @@ -28,7 +28,5 @@ export const ungroupBlocks = async (ctx: PluginContext, params: { blockIds?: num const childIds = block.getChildren(blockId); block.ungroup(blockId); // Note – ungroup should return the IDs childIds.forEach((id: number) => block.setSelected(id, isSelected)); - - } diff --git a/packages/plugin-design-essentials/src/commands/debug.ts b/packages/plugin-design-essentials/src/commands/debug.ts new file mode 100644 index 0000000..d72dfe6 --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/debug.ts @@ -0,0 +1,140 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { readPropValue } from "../utils/cesdk"; + +export const debugLogBlockProperties = async (ctx: PluginContext, params: { blockIds: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((bId: number) => { + const props = block.findAllProperties(bId) + const propDefinition = new Map() + props.forEach((propKey: string) => { + if (!block.isPropertyReadable(propKey)) return; + const propType = block.getPropertyType(propKey) + const propValue = readPropValue(block, bId, propKey, propType) + propDefinition.set(propKey, propValue) + }) + console.debug("Properties for block", bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) + }) +} + +export const debugLogBlockCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((id: number) => { + const x = block.getCropTranslationX(id) + const y = block.getCropTranslationY(id) + const scaleX = block.getCropScaleX(id) + const scaleY = block.getCropScaleY(id) + const fillMode = block.getContentFillMode(id) + const crop = { + x, y, scaleX, scaleY, fillMode + } + console.debug("Crop for block", id, JSON.stringify(crop, null, 2)) + }); + +} + +export const debugLogBlockMetadata = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + + blockIds.forEach((id: number) => { + const keys = block.findAllMetadata(id) + if (keys.length === 0) { + console.debug("No metadata for block", id) + return + } + const map = new Map() + keys.forEach((key: string) => { + const metadata = block.getMetadata(id, key) + const obj = JSON.parse(metadata) + map.set(key, obj) + }) + console.debug("Metadata for block", id, JSON.stringify(Object.fromEntries(map.entries()), null, 2)) + }) + +} + +export const debugLogBlockFill = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((bId: number) => { + const fId = block.getFill(bId) + const fillType = block.getType(fId) + + const props = block.findAllProperties(fId); + + const propDefinition = new Map() + props.forEach((propKey: string) => { + + if (!block.isPropertyReadable(propKey)) return; + const propValue = readPropValue(block, fId, propKey) + propDefinition.set(propKey, propValue) + }) + console.debug("Fill for block", bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) + }); +} + + + + +export const debugLogBlockEffects = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((bId: number) => { + const eIds = block.getEffects(bId) + + eIds.forEach((eId: number) => { + const props = block.findAllProperties(eId); + + const propDefinition = new Map() + props.forEach((propKey: string) => { + + if (!block.isPropertyReadable(propKey)) return; + const propValue = readPropValue(block, eId, propKey) + propDefinition.set(propKey, propValue) + }) + console.debug(`Effects ${eId} for block`, bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) + }) + + + }); +} + + + +export const debugLogBlockBlur = (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((bId: number) => { + if (!block.hasBlur(bId)) { + console.log("No blur for block", bId) + return + }; + const eId = block.getBlur(bId) + if (!block.isValid(eId)) { // that is an error source + console.log("No valid blur for block", bId) + return + }; + + const props = block.findAllProperties(eId); + + const propDefinition = new Map() + props.forEach((propKey: string) => { + + if (!block.isPropertyReadable(propKey)) return; + const propValue = readPropValue(block, eId, propKey) + propDefinition.set(propKey, propValue) + + + }) + console.debug(`Blur for block`, bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) + + }); +} diff --git a/packages/design-batteries/src/commands/export.ts b/packages/plugin-design-essentials/src/commands/export.ts similarity index 98% rename from packages/design-batteries/src/commands/export.ts rename to packages/plugin-design-essentials/src/commands/export.ts index 9193322..733ec19 100644 --- a/packages/design-batteries/src/commands/export.ts +++ b/packages/plugin-design-essentials/src/commands/export.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; import { MimeType } from "@cesdk/cesdk-js"; import { downloadBlob } from "../utils/download"; import { exportBlockAs } from "../utils/exportBlockAs"; diff --git a/packages/plugin-design-essentials/src/commands/i18n.ts b/packages/plugin-design-essentials/src/commands/i18n.ts new file mode 100644 index 0000000..86d43f2 --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/i18n.ts @@ -0,0 +1,21 @@ + +import { downloadBlob } from "../utils/download"; +import { PluginContext } from "../../../plugin-core/types"; // Add this import statement + +export const i18nDownloadMissingCommandTranslations = (ctx: PluginContext) => { + const { i18n, commands } = ctx; + + const missingCommandTranslations: [string, string][] = commands + .listCommands() + .map((cmd: string): [string, string] | null => { + return i18n.hasTranslation(cmd) ? null : [cmd, cmd.split(".").pop()]; + }) + .filter(Boolean) as [string, string][]; + + if (missingCommandTranslations.length > 0) { + const ob = Object.fromEntries(missingCommandTranslations); + const json = JSON.stringify(ob, null, 2); + const blob = new Blob([json], { type: "application/json" }); + downloadBlob(blob, `${i18n.locale()}.json`); + } +} \ No newline at end of file diff --git a/packages/design-batteries/src/commands/image.ts b/packages/plugin-design-essentials/src/commands/image.ts similarity index 93% rename from packages/design-batteries/src/commands/image.ts rename to packages/plugin-design-essentials/src/commands/image.ts index 020007b..c369fe6 100644 --- a/packages/design-batteries/src/commands/image.ts +++ b/packages/plugin-design-essentials/src/commands/image.ts @@ -1,5 +1,5 @@ import { ContentFillMode } from "@cesdk/cesdk-js" -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; const imageFitWithMode = (ctx: PluginContext, params: { blockIds?: number[], fillMode: ContentFillMode }) => { const { block } = ctx.engine; diff --git a/packages/plugin-design-essentials/src/commands/index.ts b/packages/plugin-design-essentials/src/commands/index.ts new file mode 100644 index 0000000..0ad4ccd --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/index.ts @@ -0,0 +1,15 @@ +export * from "./lifecycle"; +export * from "./export"; +export * from "./image"; +export * from "./container"; +export * from "./layout"; + +export * from "./debug"; +export * from "./plugins"; +export * from "./components"; +export * from "./playground"; +export * from "./i18n"; +export * from "./panels"; + + +export * from "./replicate.io"; \ No newline at end of file diff --git a/packages/design-batteries/src/commands/layout.ts b/packages/plugin-design-essentials/src/commands/layout.ts similarity index 98% rename from packages/design-batteries/src/commands/layout.ts rename to packages/plugin-design-essentials/src/commands/layout.ts index 554e3a1..a548320 100644 --- a/packages/design-batteries/src/commands/layout.ts +++ b/packages/plugin-design-essentials/src/commands/layout.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; import { toSafeInteger } from "lodash"; import { computeMultiSelectionBounds } from "../utils/computeMultiSelectionBounds"; diff --git a/packages/design-batteries/src/commands/lifecycle.ts b/packages/plugin-design-essentials/src/commands/lifecycle.ts similarity index 97% rename from packages/design-batteries/src/commands/lifecycle.ts rename to packages/plugin-design-essentials/src/commands/lifecycle.ts index 3b8ddd5..c7bc9a4 100644 --- a/packages/design-batteries/src/commands/lifecycle.ts +++ b/packages/plugin-design-essentials/src/commands/lifecycle.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; diff --git a/packages/design-batteries/src/commands/old_debug.ts b/packages/plugin-design-essentials/src/commands/old_debug.ts similarity index 100% rename from packages/design-batteries/src/commands/old_debug.ts rename to packages/plugin-design-essentials/src/commands/old_debug.ts diff --git a/packages/plugin-design-essentials/src/commands/panels.ts b/packages/plugin-design-essentials/src/commands/panels.ts new file mode 100644 index 0000000..3da6b3e --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/panels.ts @@ -0,0 +1,61 @@ +import { PluginContext } from '@imgly/plugin-core' + +const panelIds = [ + '//ly.img.panel/settings', + + '//ly.img.panel/inspector', + '//ly.img.panel/inspector/placeholderSettings', + + '//ly.img.panel/assetLibrary', + '//ly.img.panel/assetLibrary.replace', + + '//ly.img.panel/inspector/image/adjustments', + '//ly.img.panel/inspector/image/filters', + '//ly.img.panel/inspector/image/effects', + '//ly.img.panel/inspector/image/blurs', + + '//ly.img.panel/inspector/crop', + '//ly.img.panel/inspector/adjustments', + '//ly.img.panel/inspector/filters', + '//ly.img.panel/inspector/effects', + '//ly.img.panel/inspector/blur', + '//ly.img.panel/inspector/trim', + '//ly.img.panel/inspector/fill', + '//ly.img.panel/inspector/fill/color', + '//ly.img.panel/inspector/text/properties', + '//ly.img.panel/inspector/stroke/properties', + '//ly.img.panel/inspector/stroke/color', + '//ly.img.panel/inspector/shadow', + '//ly.img.panel/inspector/shadow/color', + '//ly.img.panel/inspector/transform', + '//ly.img.panel/inspector/editColor', + '//ly.img.panel/inspector/colorLibrary', + ]; + +export const panelSettingsOpen = async (ctx: PluginContext) => { + const { ui } = ctx; + ui?.openPanel("//ly.img.panel/settings") +} + +export const panelSettingsClose = async (ctx: PluginContext) => { + const { ui } = ctx; + ui?.closePanel("//ly.img.panel/settings") +} + + + +// export const panelInspectorOpen = async (ctx: PluginContext) => { +// const { ui } = ctx; +// ui?.openPanel("//ly.img.panel/inspector") +// } + +// export const panelInspectorClose = async (ctx: PluginContext) => { +// const { ui } = ctx; +// ui?.closePanel("//ly.img.panel/inspector") +// } + + +// export const panelAssetLibraryOpen = async (ctx: PluginContext) => { +// const { ui } = ctx; +// ui?.openPanel("//ly.img.panel/asset-library") +// } diff --git a/packages/design-batteries/src/commands/playground.ts b/packages/plugin-design-essentials/src/commands/playground.ts similarity index 97% rename from packages/design-batteries/src/commands/playground.ts rename to packages/plugin-design-essentials/src/commands/playground.ts index 9701ef2..ed7606e 100644 --- a/packages/design-batteries/src/commands/playground.ts +++ b/packages/plugin-design-essentials/src/commands/playground.ts @@ -1,12 +1,12 @@ // EXPORT AS LIBRARY // SYNC BY NAME - two pages, same name -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; import { readPropValue, writePropValue } from "../utils/cesdk"; import { CreativeEngine } from "@cesdk/cesdk-js"; const propKeys = [ - 'alwaysOnBottom', + 'alwaysOnBottom', 'alwaysOnTop', 'blend/mode', 'blur/enabled', 'clipped', // 'contentFill/mode', @@ -15,8 +15,8 @@ const propKeys = [ // 'position/x', 'position/x/mode', 'position/y', 'position/y/mode', 'rotation', 'dropShadow/blurRadius/x', 'dropShadow/blurRadius/y', 'dropShadow/clip', 'dropShadow/color', 'dropShadow/enabled', 'dropShadow/offset/x', 'dropShadow/offset/y', 'fill/enabled', - 'opacity', - 'placeholder/enabled', + 'opacity', + 'placeholder/enabled', 'playback/duration', 'playback/timeOffset', 'stroke/color', 'stroke/cornerGeometry', 'stroke/enabled', 'stroke/position', 'stroke/style', 'stroke/width', 'visible'] @@ -47,16 +47,18 @@ const syncBlockProperties = (ctx: PluginContext, sourceId: number, destIds: numb } + // name syntax = "label=appearance(other), rotation(other)" export const syncBlockAppearance = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block, event } = ctx.engine; let { blockIds = block.findAllSelected() } = params console.log("syncBlocks", block.findAllProperties(blockIds[0])) - const propWhiteList = propKeys - const propBlackList = [] + const propWhiteList: string[] = propKeys + const propBlackList: string[] = [] // better would be to add a meta data // const sync = { - // appearance: true + // uuid: // appearance: + // } const unsubscribe = event.subscribe(blockIds, (events) => { @@ -83,7 +85,6 @@ export const syncBlockAppearance = async (ctx: PluginContext, params: { blockIds } }) }) - } diff --git a/packages/design-batteries/src/commands/plugins.ts b/packages/plugin-design-essentials/src/commands/plugins.ts similarity index 87% rename from packages/design-batteries/src/commands/plugins.ts rename to packages/plugin-design-essentials/src/commands/plugins.ts index feee9a6..8cfa726 100644 --- a/packages/design-batteries/src/commands/plugins.ts +++ b/packages/plugin-design-essentials/src/commands/plugins.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; export const pluginRegisterAndOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { ui } = ctx; diff --git a/packages/plugin-design-essentials/src/commands/replicate.io.ts b/packages/plugin-design-essentials/src/commands/replicate.io.ts new file mode 100644 index 0000000..251cf3d --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/replicate.io.ts @@ -0,0 +1,91 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { downloadBlob } from "../utils/download"; + + +// https://replicate.com/stability-ai/stable-diffusion-img2img?prediction=63trbdrbookprhnq3eoap6iwz4 +// https://replicate.com/pharmapsychotic/clip-interrogator + + + + +// https://replicate.com/mistralai/mixtral-8x7b-instruct-v0.1 +const REPLICATE_API_TOKEN = "r8_Y7Qt7U8vkF8QBVDJ9RvWTQNuebwVLBp2qvvBT" + + +export const callReplicate = async (ctx: PluginContext, params: { blockIds?: number[]; }) => { + const data = { + "version": "39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b", + "input": { + "width": 768, + "height": 768, + "prompt": "An astronaut riding a rainbow unicorn, cinematic, dramatic", + "refine": "expert_ensemble_refiner", + "scheduler": "K_EULER", + "lora_scale": 0.6, + "num_outputs": 1, + "guidance_scale": 7.5, + "apply_watermark": false, + "high_noise_frac": 0.8, + "negative_prompt": "", + "prompt_strength": 0.8, + "num_inference_steps": 25 + } + } + + + + const url = proxy("https://api.replicate.com/v1/predictions") + const res = await fetch(url, { + method: 'POST', + // mode: "no-cors", + headers, + body: JSON.stringify(data) + }) + + + const json = await res.json() + + const images = await waitForReplicate(json) + + images.forEach((image: Blob, index: number) => { + const filename = `replicate-${index}.png` + downloadBlob(image, filename) + }) + +} + +const headers = { + "Content-Type": 'application/json', + "Authorization": `Token ${REPLICATE_API_TOKEN}` +} + +const proxy = (url: string) => 'https://corsproxy.io/?' + encodeURIComponent(url); + +const waitForReplicate = async (json: any): Promise => { + return new Promise((resolve, reject) => { + const interval = 1000 + const timeout = setInterval(async () => { + // console.log("Checking status") + const url = proxy(json.urls.get) + const statusRes = await fetch(url, { headers }) + const statusJson = await statusRes.json() + // console.log(statusJson) + if (statusJson.error) { + clearInterval(timeout) + reject(statusJson.error) + } + if (statusJson.status === "succeeded") { + clearInterval(timeout) + // console.log("Success") + // console.log("Metrics", statusJson.metrics) + const { output } = statusJson + const images = await Promise.all(output.map(async (o: string) => { + const image = await fetch(proxy(o), { headers }) + return image.blob() + })) + resolve(images) + + } + }, interval) + }) +} \ No newline at end of file diff --git a/packages/design-batteries/src/index.ts b/packages/plugin-design-essentials/src/index.ts similarity index 76% rename from packages/design-batteries/src/index.ts rename to packages/plugin-design-essentials/src/index.ts index 5ebc957..6cf2ead 100644 --- a/packages/design-batteries/src/index.ts +++ b/packages/plugin-design-essentials/src/index.ts @@ -1,6 +1,6 @@ -import { PluginContext, CommandDescription } from '@imgly/plugin-api-utils'; +import { PluginContext, CommandDescription } from '../../plugin-core/types'; import { CommandImports, CommandContributions, PluginManifest } from './PluginManifest'; @@ -49,10 +49,29 @@ const loadCommands = async (ctx: PluginContext) => { } +const registerPanels = async (ctx: PluginContext, panels: any) => { + for (const panel in panels) { + const id = `${PluginManifest.id}.panels.${panel}` + // ctx.ui?.unstable_registerPanel(panel, ({ builder: any }) => { + // return panels[panel](ctx, builder) + + // }) + } + +} + +const loadPanels = async (ctx: PluginContext) => { + const panels = await import("./panels/layers") + await registerPanels(ctx, panels) +} + + + export const activate = async (ctx: PluginContext) => { - const doValidateI18n = true; + await loadTranslation(ctx) await loadCommands(ctx) + await loadPanels(ctx) } diff --git a/packages/plugin-design-essentials/src/locale/de.json b/packages/plugin-design-essentials/src/locale/de.json new file mode 100644 index 0000000..74992c7 --- /dev/null +++ b/packages/plugin-design-essentials/src/locale/de.json @@ -0,0 +1,39 @@ +{ + "design-batteries.commands.blockBringForward": "Block nach vorne bringen", + "design-batteries.commands.blockBringToFront": "Block ganz nach vorne bringen", + "design-batteries.commands.blockDelete": "Block löschen", + "design-batteries.commands.blockDuplicate": "Block duplizieren", + "design-batteries.commands.blockRename": "Block umbenennen", + "design-batteries.commands.blockSendBackward": "Block nach hinten senden", + "design-batteries.commands.blockSendToBack": "Block ganz nach hinten senden", + "design-batteries.commands.blockGroup": "Blöcke gruppieren", + "design-batteries.commands.blockUngroup": "Blöcke aufheben", + "design-batteries.commands.debugLogBlockCrop": "Debug-Log für Block zuschneiden", + "design-batteries.commands.debugLogBlockMetadata": "Debug-Log für Block-Metadaten", + "design-batteries.commands.debugLogBlockProperties": "Debug-Log für Block-Eigenschaften", + "design-batteries.commands.exportComponentLibrary": "Komponentenbibliothek exportieren", + "design-batteries.commands.exportComponentToFile": "Komponente in Datei exportieren", + "design-batteries.commands.exportJsonToClipboard": "JSON in Zwischenablage exportieren", + "design-batteries.commands.exportJsonToFile": "JSON in Datei exportieren", + "design-batteries.commands.exportJpegToFile": "JPEG in Datei exportieren", + "design-batteries.commands.exportPdfToFile": "PDF in Datei exportieren", + "design-batteries.commands.exportPngToClipboard": "PNG in Zwischenablage exportieren", + "design-batteries.commands.exportPngToFile": "PNG in Datei exportieren", + "design-batteries.commands.exportRgba8ToFile": "Rohes RGBA8 in Datei exportieren", + "design-batteries.commands.exportSceneToClipboard": "Szene in Zwischenablage exportieren", + "design-batteries.commands.exportSceneToFile": "Szene in Datei exportieren", + "design-batteries.commands.exportWebpToFile": "WEBP in Datei exportieren", + "design-batteries.commands.i18nDownloadMissingCommandTranslations": "Fehlende Befehlsübersetzungen herunterladen", + "design-batteries.commands.imageFitModeContain": "Bildanpassungsmodus auf Enthalten setzen", + "design-batteries.commands.imageFitModeCrop": "Bildanpassungsmodus auf Zuschneiden setzen", + "design-batteries.commands.imageFitModeCover": "Bildanpassungsmodus auf Abdecken setzen", + "design-batteries.commands.importComponent": "Komponente importieren", + "design-batteries.commands.layoutHorizontally": "Horizontal anordnen", + "design-batteries.commands.layoutMasonry": "Mauerwerk anordnen", + "design-batteries.commands.layoutVertically": "Vertikal anordnen", + "design-batteries.commands.myNewFunctionForTheEditor": "Super tolle Funktion", + "design-batteries.commands.playground": "Spielplatz", + "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "Benutzerdefiniertes Panel registrieren und öffnen", + "design-batteries.commands.productSetInstagram": "Instagram-Produkt festlegen", + "design-batteries.commands.syncBlocks": "Blöcke synchronisieren" +} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/locale/en.json b/packages/plugin-design-essentials/src/locale/en.json new file mode 100644 index 0000000..09c4f5e --- /dev/null +++ b/packages/plugin-design-essentials/src/locale/en.json @@ -0,0 +1,39 @@ +{ + "design-batteries.commands.blockBringForward": "Bring Block Forward", + "design-batteries.commands.blockBringToFront": "Bring Block to Front", + "design-batteries.commands.blockDelete": "Delete Block", + "design-batteries.commands.blockDuplicate": "Duplicate Block", + "design-batteries.commands.blockRename": "Rename Block", + "design-batteries.commands.blockSendBackward": "Send Block Backward", + "design-batteries.commands.blockSendToBack": "Send Block to Back", + "design-batteries.commands.blockGroup": "Group Blocks", + "design-batteries.commands.blockUngroup": "Ungroup Blocks", + "design-batteries.commands.debugLogBlockCrop": "Debug Log Block Crop", + "design-batteries.commands.debugLogBlockMetadata": "Debug Log Block Metadata", + "design-batteries.commands.debugLogBlockProperties": "Debug Log Block Properties", + "design-batteries.commands.exportComponentLibrary": "Export Component Library", + "design-batteries.commands.exportComponentToFile": "Export Component to File", + "design-batteries.commands.exportJsonToClipboard": "Export JSON to Clipboard", + "design-batteries.commands.exportJsonToFile": "Export JSON to File", + "design-batteries.commands.exportJpegToFile": "Export JPEG to File", + "design-batteries.commands.exportPdfToFile": "Export PDF to File", + "design-batteries.commands.exportPngToClipboard": "Export PNG to Clipboard", + "design-batteries.commands.exportPngToFile": "Export PNG to File", + "design-batteries.commands.exportRgba8ToFile": "Export Raw RGBA8 to File", + "design-batteries.commands.exportSceneToClipboard": "Export Scene to Clipboard", + "design-batteries.commands.exportSceneToFile": "Export Scene to File", + "design-batteries.commands.exportWebpToFile": "Export WEBP to File", + "design-batteries.commands.i18nDownloadMissingCommandTranslations": "Download Missing Command Translations", + "design-batteries.commands.imageFitModeContain": "Set Image Fit Mode to Contain", + "design-batteries.commands.imageFitModeCrop": "Set Image Fit Mode to Crop", + "design-batteries.commands.imageFitModeCover": "Set Image Fit Mode to Cover", + "design-batteries.commands.importComponent": "Import Component", + "design-batteries.commands.layoutHorizontally": "Layout Horizontally", + "design-batteries.commands.layoutMasonry": "Layout Masonry", + "design-batteries.commands.layoutVertically": "Layout Vertically", + "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function", + "design-batteries.commands.playground": "Playground", + "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "Register and Open Custom Panel", + "design-batteries.commands.productSetInstagram": "Set Instagram Product", + "design-batteries.commands.syncBlocks": "Sync Blocks" +} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/panels/index.ts b/packages/plugin-design-essentials/src/panels/index.ts new file mode 100644 index 0000000..f3d498e --- /dev/null +++ b/packages/plugin-design-essentials/src/panels/index.ts @@ -0,0 +1 @@ +export * from "./layers"; \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/panels/layers.ts b/packages/plugin-design-essentials/src/panels/layers.ts new file mode 100644 index 0000000..094c6a7 --- /dev/null +++ b/packages/plugin-design-essentials/src/panels/layers.ts @@ -0,0 +1,19 @@ +import { PluginContext } from '@imgly/plugin-core'; + + +export const layerList = async (ctx: PluginContext, builder: any, params: any) => { + const { block } = ctx.engine; + const { Button, Section, Separator } = builder; + const blockIds = block.findAllSelected(); + + Section('layer.section', { + title: 'Layers', + children: () => + blockIds.forEach((bId: number) => + Button(bId.toString(), { + label: block.getName(bId) || block.getUUID(bId).toString(), + onClick: () => block.select(bId) + })) + }); + +} diff --git a/packages/design-batteries/src/utils/cesdk.ts b/packages/plugin-design-essentials/src/utils/cesdk.ts similarity index 90% rename from packages/design-batteries/src/utils/cesdk.ts rename to packages/plugin-design-essentials/src/utils/cesdk.ts index 5ec22ca..b8169c3 100644 --- a/packages/design-batteries/src/utils/cesdk.ts +++ b/packages/plugin-design-essentials/src/utils/cesdk.ts @@ -2,7 +2,7 @@ import { BlockAPI } from "@cesdk/cesdk-js"; export const readPropValue = (block: BlockAPI, id: number, propKey: string, propType?: string) => { - const blacklist= ["fill/solid/color"] + const blacklist = ["fill/solid/color", "fill/image/sourceSet"] if (blacklist.includes(propKey)) return undefined; if (!propType) propType = block.getPropertyType(propKey) try { @@ -14,14 +14,14 @@ export const readPropValue = (block: BlockAPI, id: number, propKey: string, prop case "bool": return block.getBool(id, propKey); case "enum": return block.getEnum(id, propKey); } - } catch(e){ + } catch (e) { console.warn("Error reading property value: ", e); } return undefined; }; -export const writePropValue = (block: BlockAPI, id: number, propKey: string, propValue: any,propType?: string) => { +export const writePropValue = (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => { if (!propType) propType = block.getPropertyType(propKey) try { switch (propType.toLowerCase()) { @@ -32,7 +32,7 @@ export const writePropValue = (block: BlockAPI, id: number, propKey: string, pro case "bool": return block.setBool(id, propKey, propValue); case "enum": return block.setEnum(id, propKey, propValue); } - } catch(e){ + } catch (e) { console.warn("Error writing property: ", propKey, propType, propValue); } return undefined; diff --git a/packages/design-batteries/src/utils/computeBlockName.ts b/packages/plugin-design-essentials/src/utils/computeBlockName.ts similarity index 100% rename from packages/design-batteries/src/utils/computeBlockName.ts rename to packages/plugin-design-essentials/src/utils/computeBlockName.ts diff --git a/packages/design-batteries/src/utils/computeMultiSelectionBounds.ts b/packages/plugin-design-essentials/src/utils/computeMultiSelectionBounds.ts similarity index 91% rename from packages/design-batteries/src/utils/computeMultiSelectionBounds.ts rename to packages/plugin-design-essentials/src/utils/computeMultiSelectionBounds.ts index 8346e69..d529d12 100644 --- a/packages/design-batteries/src/utils/computeMultiSelectionBounds.ts +++ b/packages/plugin-design-essentials/src/utils/computeMultiSelectionBounds.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; export const computeMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { diff --git a/packages/design-batteries/src/utils/download.ts b/packages/plugin-design-essentials/src/utils/download.ts similarity index 100% rename from packages/design-batteries/src/utils/download.ts rename to packages/plugin-design-essentials/src/utils/download.ts diff --git a/packages/design-batteries/src/utils/exportBlockAs.ts b/packages/plugin-design-essentials/src/utils/exportBlockAs.ts similarity index 95% rename from packages/design-batteries/src/utils/exportBlockAs.ts rename to packages/plugin-design-essentials/src/utils/exportBlockAs.ts index e03c623..3185100 100644 --- a/packages/design-batteries/src/utils/exportBlockAs.ts +++ b/packages/plugin-design-essentials/src/utils/exportBlockAs.ts @@ -1,4 +1,4 @@ -import { PluginContext } from "@imgly/plugin-api-utils"; +import { PluginContext } from "../../../plugin-core/types"; import { type MimeType } from "@cesdk/cesdk-js"; export const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { diff --git a/packages/design-batteries/src/worker.ts b/packages/plugin-design-essentials/src/worker.ts similarity index 100% rename from packages/design-batteries/src/worker.ts rename to packages/plugin-design-essentials/src/worker.ts diff --git a/packages/design-batteries/tsconfig.json b/packages/plugin-design-essentials/tsconfig.json similarity index 100% rename from packages/design-batteries/tsconfig.json rename to packages/plugin-design-essentials/tsconfig.json diff --git a/packages/vectorizer/LICENSE.md b/packages/plugin-vectorizer/LICENSE.md similarity index 100% rename from packages/vectorizer/LICENSE.md rename to packages/plugin-vectorizer/LICENSE.md diff --git a/packages/vectorizer/PLAYGROUND.md b/packages/plugin-vectorizer/PLAYGROUND.md similarity index 100% rename from packages/vectorizer/PLAYGROUND.md rename to packages/plugin-vectorizer/PLAYGROUND.md diff --git a/packages/vectorizer/README.md b/packages/plugin-vectorizer/README.md similarity index 88% rename from packages/vectorizer/README.md rename to packages/plugin-vectorizer/README.md index e4197b5..6acc73e 100644 --- a/packages/vectorizer/README.md +++ b/packages/plugin-vectorizer/README.md @@ -7,8 +7,8 @@ This plugin introduces a vectorizer for the CE.SDK editor. You can install the plugin via npm or yarn. Use the following commands to install the package: ``` -yarn add @imgly/plugin-vectorizer-web -npm install @imgly/plugin-vectorizer-web +yarn add @imgly/plugin-vectorizer +npm install @imgly/plugin-vectorizer ``` ## Usage @@ -18,7 +18,7 @@ canvas menu entry for every block with an image fill. ```typescript import CreativeEditorSDK from '@cesdk/cesdk-js'; -import VectorizerPlugin from '@imgly/plugin-vectorizer-web'; +import VectorizerPlugin from '@imgly/plugin-vectorizer'; const config = { license: '', diff --git a/packages/vectorizer/STRUCTURE.md b/packages/plugin-vectorizer/STRUCTURE.md similarity index 100% rename from packages/vectorizer/STRUCTURE.md rename to packages/plugin-vectorizer/STRUCTURE.md diff --git a/packages/vectorizer/TODO.md b/packages/plugin-vectorizer/TODO.md similarity index 100% rename from packages/vectorizer/TODO.md rename to packages/plugin-vectorizer/TODO.md diff --git a/packages/vectorizer/esbuild/config.mjs b/packages/plugin-vectorizer/esbuild/config.mjs similarity index 100% rename from packages/vectorizer/esbuild/config.mjs rename to packages/plugin-vectorizer/esbuild/config.mjs diff --git a/packages/vectorizer/esbuild/global.d.ts b/packages/plugin-vectorizer/esbuild/global.d.ts similarity index 100% rename from packages/vectorizer/esbuild/global.d.ts rename to packages/plugin-vectorizer/esbuild/global.d.ts diff --git a/packages/vectorizer/manifest.json b/packages/plugin-vectorizer/manifest.json similarity index 100% rename from packages/vectorizer/manifest.json rename to packages/plugin-vectorizer/manifest.json diff --git a/packages/vectorizer/package.json b/packages/plugin-vectorizer/package.json similarity index 96% rename from packages/vectorizer/package.json rename to packages/plugin-vectorizer/package.json index ccb299f..6ac69e3 100644 --- a/packages/vectorizer/package.json +++ b/packages/plugin-vectorizer/package.json @@ -1,5 +1,5 @@ { - "name": "@imgly/plugin-vectorizer-web", + "name": "@imgly/plugin-vectorizer", "version": "0.1.0", "description": "Vectorizer plugin for the CE.SDK editor", "keywords": [ @@ -64,7 +64,7 @@ }, "dependencies": { "@imgly/vectorizer": "~0.1.0-rc6", - "@imgly/plugin-api-utils": "*", + "@imgly/plugin-core": "*", "lodash": "^4.17.21" } } diff --git a/packages/vectorizer/scripts/build.mjs b/packages/plugin-vectorizer/scripts/build.mjs similarity index 100% rename from packages/vectorizer/scripts/build.mjs rename to packages/plugin-vectorizer/scripts/build.mjs diff --git a/packages/vectorizer/scripts/watch.mjs b/packages/plugin-vectorizer/scripts/watch.mjs similarity index 100% rename from packages/vectorizer/scripts/watch.mjs rename to packages/plugin-vectorizer/scripts/watch.mjs diff --git a/packages/vectorizer/src/PluginManifest.ts b/packages/plugin-vectorizer/src/PluginManifest.ts similarity index 100% rename from packages/vectorizer/src/PluginManifest.ts rename to packages/plugin-vectorizer/src/PluginManifest.ts diff --git a/packages/vectorizer/src/activate.ts b/packages/plugin-vectorizer/src/activate.ts similarity index 100% rename from packages/vectorizer/src/activate.ts rename to packages/plugin-vectorizer/src/activate.ts diff --git a/packages/vectorizer/src/commands.ts b/packages/plugin-vectorizer/src/commands.ts similarity index 100% rename from packages/vectorizer/src/commands.ts rename to packages/plugin-vectorizer/src/commands.ts diff --git a/packages/vectorizer/src/deps.ts b/packages/plugin-vectorizer/src/deps.ts similarity index 88% rename from packages/vectorizer/src/deps.ts rename to packages/plugin-vectorizer/src/deps.ts index 67e1b40..e72ca92 100644 --- a/packages/vectorizer/src/deps.ts +++ b/packages/plugin-vectorizer/src/deps.ts @@ -1,5 +1,5 @@ import { I18NKeys } from "./PluginManifest"; -import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-api-utils'; +import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-core'; type PluginContext = IPluginContext; export { CreativeEngine } from '@cesdk/cesdk-js'; diff --git a/packages/vectorizer/src/handler.ts b/packages/plugin-vectorizer/src/handler.ts similarity index 100% rename from packages/vectorizer/src/handler.ts rename to packages/plugin-vectorizer/src/handler.ts diff --git a/packages/vectorizer/src/index.ts b/packages/plugin-vectorizer/src/index.ts similarity index 100% rename from packages/vectorizer/src/index.ts rename to packages/plugin-vectorizer/src/index.ts diff --git a/packages/vectorizer/src/ui.ts b/packages/plugin-vectorizer/src/ui.ts similarity index 100% rename from packages/vectorizer/src/ui.ts rename to packages/plugin-vectorizer/src/ui.ts diff --git a/packages/vectorizer/src/utils/cesdk+utils.ts b/packages/plugin-vectorizer/src/utils/cesdk+utils.ts similarity index 100% rename from packages/vectorizer/src/utils/cesdk+utils.ts rename to packages/plugin-vectorizer/src/utils/cesdk+utils.ts diff --git a/packages/vectorizer/src/utils/common.ts b/packages/plugin-vectorizer/src/utils/common.ts similarity index 100% rename from packages/vectorizer/src/utils/common.ts rename to packages/plugin-vectorizer/src/utils/common.ts diff --git a/packages/vectorizer/src/utils/types.ts b/packages/plugin-vectorizer/src/utils/types.ts similarity index 100% rename from packages/vectorizer/src/utils/types.ts rename to packages/plugin-vectorizer/src/utils/types.ts diff --git a/packages/vectorizer/src/utils/worker.shared.ts b/packages/plugin-vectorizer/src/utils/worker.shared.ts similarity index 100% rename from packages/vectorizer/src/utils/worker.shared.ts rename to packages/plugin-vectorizer/src/utils/worker.shared.ts diff --git a/packages/vectorizer/src/worker.ts b/packages/plugin-vectorizer/src/worker.ts similarity index 100% rename from packages/vectorizer/src/worker.ts rename to packages/plugin-vectorizer/src/worker.ts diff --git a/packages/vectorizer/tsconfig.json b/packages/plugin-vectorizer/tsconfig.json similarity index 100% rename from packages/vectorizer/tsconfig.json rename to packages/plugin-vectorizer/tsconfig.json diff --git a/packages/vectorizer/types/PluginManifest.d.ts b/packages/plugin-vectorizer/types/PluginManifest.d.ts similarity index 100% rename from packages/vectorizer/types/PluginManifest.d.ts rename to packages/plugin-vectorizer/types/PluginManifest.d.ts diff --git a/packages/vectorizer/types/activate.d.ts b/packages/plugin-vectorizer/types/activate.d.ts similarity index 100% rename from packages/vectorizer/types/activate.d.ts rename to packages/plugin-vectorizer/types/activate.d.ts diff --git a/packages/vectorizer/types/commands.d.ts b/packages/plugin-vectorizer/types/commands.d.ts similarity index 100% rename from packages/vectorizer/types/commands.d.ts rename to packages/plugin-vectorizer/types/commands.d.ts diff --git a/packages/vectorizer/types/deps.d.ts b/packages/plugin-vectorizer/types/deps.d.ts similarity index 88% rename from packages/vectorizer/types/deps.d.ts rename to packages/plugin-vectorizer/types/deps.d.ts index 6ba08aa..54a2b05 100644 --- a/packages/vectorizer/types/deps.d.ts +++ b/packages/plugin-vectorizer/types/deps.d.ts @@ -1,5 +1,5 @@ import { I18NKeys } from "./PluginManifest"; -import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-api-utils'; +import { type PluginContext as IPluginContext, CommandCallback } from '../../plugin-core/types'; type PluginContext = IPluginContext; export { CreativeEngine } from '@cesdk/cesdk-js'; export { type PluginContext, type CommandCallback }; diff --git a/packages/vectorizer/types/handler.d.ts b/packages/plugin-vectorizer/types/handler.d.ts similarity index 100% rename from packages/vectorizer/types/handler.d.ts rename to packages/plugin-vectorizer/types/handler.d.ts diff --git a/packages/vectorizer/types/index.d.ts b/packages/plugin-vectorizer/types/index.d.ts similarity index 100% rename from packages/vectorizer/types/index.d.ts rename to packages/plugin-vectorizer/types/index.d.ts diff --git a/packages/vectorizer/types/ui.d.ts b/packages/plugin-vectorizer/types/ui.d.ts similarity index 100% rename from packages/vectorizer/types/ui.d.ts rename to packages/plugin-vectorizer/types/ui.d.ts diff --git a/packages/vectorizer/types/utils/cesdk+utils.d.ts b/packages/plugin-vectorizer/types/utils/cesdk+utils.d.ts similarity index 100% rename from packages/vectorizer/types/utils/cesdk+utils.d.ts rename to packages/plugin-vectorizer/types/utils/cesdk+utils.d.ts diff --git a/packages/vectorizer/types/utils/common.d.ts b/packages/plugin-vectorizer/types/utils/common.d.ts similarity index 100% rename from packages/vectorizer/types/utils/common.d.ts rename to packages/plugin-vectorizer/types/utils/common.d.ts diff --git a/packages/vectorizer/types/utils/types.d.ts b/packages/plugin-vectorizer/types/utils/types.d.ts similarity index 100% rename from packages/vectorizer/types/utils/types.d.ts rename to packages/plugin-vectorizer/types/utils/types.d.ts diff --git a/packages/vectorizer/types/utils/worker.shared.d.ts b/packages/plugin-vectorizer/types/utils/worker.shared.d.ts similarity index 100% rename from packages/vectorizer/types/utils/worker.shared.d.ts rename to packages/plugin-vectorizer/types/utils/worker.shared.d.ts diff --git a/packages/vectorizer/types/worker.d.ts b/packages/plugin-vectorizer/types/worker.d.ts similarity index 100% rename from packages/vectorizer/types/worker.d.ts rename to packages/plugin-vectorizer/types/worker.d.ts From 4a8e47bcdca5ec49c3bf3a5882ffd91a4182ec5a Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sun, 3 Mar 2024 19:27:42 +0100 Subject: [PATCH 30/32] wip --- examples/web/src/App.tsx | 64 ++++++- .../web/src/components/CommandPalette.tsx | 33 +++- .../src/commands/__template.ts | 6 +- .../src/commands/block.ts | 149 +++++++++++++++++ .../src/commands/components.ts | 15 +- .../src/commands/debug.ts | 34 +++- .../src/commands/image.ts | 10 +- .../src/commands/import.ts | 2 + .../src/commands/index.ts | 4 +- .../src/commands/lifecycle.ts | 70 -------- .../src/commands/playground.ts | 8 +- .../src/commands/plugins.ts | 10 +- .../src/commands/replicate.io.ts | 156 +++++++++++++----- .../src/commands/turnInto.ts | 24 +++ .../plugin-design-essentials/src/index.ts | 5 +- .../src/locale/de.json | 39 ----- .../src/locale/en.json | 19 ++- .../src/panels/index.ts | 2 +- .../src/panels/layers.ts | 30 ++-- .../src/utils/cesdk.ts | 4 +- .../src/utils/getTransform.ts | 12 ++ .../src/utils/setTransform.ts | 10 ++ .../src/utils/turnBlockInto.ts | 37 +++++ packages/plugin-vectorizer/src/activate.ts | 18 +- packages/plugin-vectorizer/types/deps.d.ts | 2 +- 25 files changed, 539 insertions(+), 224 deletions(-) create mode 100644 packages/plugin-design-essentials/src/commands/block.ts create mode 100644 packages/plugin-design-essentials/src/commands/import.ts delete mode 100644 packages/plugin-design-essentials/src/commands/lifecycle.ts create mode 100644 packages/plugin-design-essentials/src/commands/turnInto.ts delete mode 100644 packages/plugin-design-essentials/src/locale/de.json create mode 100644 packages/plugin-design-essentials/src/utils/getTransform.ts create mode 100644 packages/plugin-design-essentials/src/utils/setTransform.ts create mode 100644 packages/plugin-design-essentials/src/utils/turnBlockInto.ts diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index ad6e453..464ee26 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -106,10 +106,16 @@ function App() { // Bind our react command paltte to cesdk command palettes are listen on new commands being created - imgly.commands.subscribe("register", (_label: string) => setCommandItems(generateCommandItemsfromCESDK(imgly))) - imgly.commands.subscribe("unregister", (_label: string) => setCommandItems(generateCommandItemsfromCESDK(imgly))) + imgly.engine.event.subscribe([], (events) => { + events + .forEach(_ => { + setCommandItems(generateItems(imgly)) + }) + }) + imgly.commands.subscribe("register", (_label: string) => setCommandItems(generateItems(imgly))) + imgly.commands.subscribe("unregister", (_label: string) => setCommandItems(generateItems(imgly))) - setCommandItems(generateCommandItemsfromCESDK(imgly)) + setCommandItems(generateItems(imgly)) } @@ -122,11 +128,56 @@ function App() { ); } -const generateCommandItemsfromCESDK = (ctx: PluginContext): Array => { +const generateItems = (ctx: PluginContext) => { + return [...generateBlockHierarchy(ctx), ...generateCommandItems(ctx), ...generateProperyItems(ctx)] +} + +const generateBlockHierarchy = (ctx: PluginContext) => { + const blocks = ctx.engine.block.findAll() + + return blocks.map((bId: number) => { + const titel = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId).toString() + return { + id: bId, + children: titel, + kind: "block", + group: "Hierarchy", + showType: false, + onClick: () => ctx.engine.block.select(bId) + } + }) +} + +const generateProperyItems = (ctx: PluginContext) => { + const { block } = ctx.engine + const bIds = block.findAllSelected() + const bId = bIds[0] + if (!bId) return [] // for now + + const props = bIds.flatMap((bId: number) => block.findAllProperties(bId)) + const uniqueProps = Array.from(new Set(props)) + + return uniqueProps.map((p) => { + const titel = p + const value = 42 + + return { + id: bId, + children: titel, + kind: "property", + group: "Properties", + showType: false, + onClick: () => prompt(`Change ${p} to`, value.toString()) + } + }) +} + + +const generateCommandItems = (ctx: PluginContext): Array => { const cmds = ctx .commands! .listCommands() - + return cmds .map((cmdId: string) => { const titel = ctx.i18n.translate(cmdId) // this comes from the metadata @@ -135,8 +186,9 @@ const generateCommandItemsfromCESDK = (ctx: PluginContext): Array => { return { id: cmdId, children: titel, + kind: "command", group: desc?.category || "Commands", - showType: true, + showType: false, onClick: async () => { await ctx.commands!.executeCommand(cmdId, {}) } diff --git a/examples/web/src/components/CommandPalette.tsx b/examples/web/src/components/CommandPalette.tsx index 1681c82..63d86a5 100644 --- a/examples/web/src/components/CommandPalette.tsx +++ b/examples/web/src/components/CommandPalette.tsx @@ -3,17 +3,22 @@ import CMDK, { filterItems, getItemIndex } from "react-cmdk"; import { useState, useEffect } from "react"; +const CommandPrefix = "!" +const BlockPrefix = "#" +const PropertyPrefix = "@" + import { groupBy } from "lodash"; // https://github.com/albingroen/react-cmdk type Params = { items: Array, isOpen: boolean, setIsOpen: (val: boolean) => void } export const CommandPalette = (params: Params) => { const [page, _setPage] = useState<"root">("root"); - const [search, setSearch] = useState(""); + const [search, setSearch] = useState(CommandPrefix); const { isOpen, setIsOpen } = params const { items } = params - // debugger + + useEffect(() => { function handleKeyDown(e: KeyboardEvent) { if ( @@ -36,15 +41,35 @@ export const CommandPalette = (params: Params) => { }; }, []); + // Support prefixes - const grouped = groupBy(items, "group") + let refinedSearch = search + let refinedItems = items + + if (search.startsWith(CommandPrefix)) { + refinedSearch = search.substring(CommandPrefix.length).trim() + refinedItems = items.filter((item) => item.kind === "command") + } + else if (search.startsWith(BlockPrefix)) { + refinedSearch = search.substring(BlockPrefix.length).trim() + refinedItems = items.filter((item) => item.kind === "block") + } + + else if (search.startsWith(PropertyPrefix)) { + refinedSearch = search.substring(PropertyPrefix.length).trim() + refinedItems = items.filter((item) => item.kind === "property") + } else { + refinedItems = items.filter((item) => item.kind === "command") + } + + const grouped = groupBy(refinedItems, "group") const filteredItems = filterItems(Object.keys(grouped).map((key) => { return { heading: key, id: key, items: grouped[key] ?? [] } - }), search); + }), refinedSearch, { filterOnListHeading: true}); return ( { -} \ No newline at end of file +// // @ts-ignore +// const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +// } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/block.ts b/packages/plugin-design-essentials/src/commands/block.ts new file mode 100644 index 0000000..5f79fc0 --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/block.ts @@ -0,0 +1,149 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { ary, create } from "lodash"; +import { setTransform } from "../utils/setTransform"; +import { turnBlockInto } from "../utils/turnBlockInto"; + +export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + ctx.engine.block.isValid(id) && ctx.engine.block.destroy(id) + }); +} + +export const blockDuplicate = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.isValid(id); + const newBlock = block.duplicate(id); + const parent = block.getParent(id); + if (parent && block.isValid(parent)) { + block.appendChild(parent, newBlock); + } + block.setSelected(newBlock, true); // should return the previous state + block.setSelected(id, false); + + }); +} + + +export const blockRename = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.isValid(id); + const name = block.getName(id) + const newName = prompt("Block name", name); + if (newName) { + block.setName(id, newName); + } + }); +} +export const blockBringForward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.bringForward(id); + }); +} + +export const blockSendBackward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.sendBackward(id); + }); +} + +export const blockBringToFront = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.bringToFront(id); + }); +} + +export const blockSendToBack = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + block.sendToBack(id); + }) +} + + +export const blockCreateGraphic = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + + const { block, scene } = ctx.engine; + // const { blockIds = block.findAllSelected() } = params; + const setTransform = (blockId: number, transform: any) => { + const { x, y, width, height } = transform + x && block.setPositionX(bId, x) + y && block.setPositionY(bId, y) + width && block.setWidth(bId, width) + height && block.setHeight(bId, height) + } + const pId = scene.getCurrentPage() ?? scene.get()! + + const bId = createDefaultBlockByType(ctx, "graphic") + const width = block.getFrameWidth(pId) / 2.0 + const height = block.getFrameHeight(pId) / 2.0 + const x = width - width / 2.0 + const y = height - height / 2.0 + setTransform(bId, { x, y, width, height }) + block.appendChild(pId, bId); + block.setSelected(bId, true) +} + + +export const blockCreateText = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + const { block, scene } = ctx.engine; + // const { blockIds = block.findAllSelected() } = params; + + const pId = scene.getCurrentPage() ?? scene.get()! + + const bId = createDefaultBlockByType(ctx, "text") + + const width = block.getFrameWidth(pId) / 2.0 + const height = block.getFrameHeight(pId) / 2.0 + const x = width - width / 2.0 + const y = height - height / 2.0 + setTransform(ctx, bId, { x, y, width, height }) + block.appendChild(pId, bId); + block.setSelected(bId, true) +} + + + +// UTILS + +export const createDefaultBlockByType = (ctx: PluginContext, type: string) => { + const { block } = ctx.engine; + switch (type) { + + case "graphic": { + const bId = block.create("graphic") + const sId = block.createShape("rect") + const fId = block.createFill("//ly.img.ubq/fill/image") + block.setShape(bId, sId) + block.setFill(bId, fId) + block.setName(bId, type.toUpperCase()) + return bId + } + case "page": { + const bId = block.create("page") + block.setName(bId, type.toUpperCase()) + return bId + } + case "text": { + const bId = block.create("graphic") + block.replaceText(bId, "Hello World") + block.setName(bId, type.toUpperCase()) + return bId + } + default: throw new Error("Invalid type") + } +} + + diff --git a/packages/plugin-design-essentials/src/commands/components.ts b/packages/plugin-design-essentials/src/commands/components.ts index 81c187e..7b47648 100644 --- a/packages/plugin-design-essentials/src/commands/components.ts +++ b/packages/plugin-design-essentials/src/commands/components.ts @@ -33,7 +33,6 @@ export const importComponent = async (ctx: PluginContext, _params: { blockIds?: const { engine } = ctx; const { scene, block } = engine; - const data = await loadAsBlob(); const str = await data.text(); const bIds = await ctx.engine.block.loadFromString(str); @@ -41,8 +40,20 @@ export const importComponent = async (ctx: PluginContext, _params: { blockIds?: const pId = scene.getCurrentPage()!; bIds.forEach((bId) => { const name = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId); + const type = ctx.engine.block.getType(bId); + const isGroup = type === "//ly.img.ubq/group"; console.log("Inserting Block", name); - block.appendChild(pId, bId); + console.log("Block Type", type); + if (isGroup) { // // ugly workaround for groups after loading. How does duplicate work? + const childIds = block.getChildren(bId); + block.ungroup(bId) + childIds.forEach((childId) => { + block.appendChild(pId, childId); + }) + block.group(childIds); + } else{ + block.appendChild(pId, bId); + } }); diff --git a/packages/plugin-design-essentials/src/commands/debug.ts b/packages/plugin-design-essentials/src/commands/debug.ts index d72dfe6..4c19623 100644 --- a/packages/plugin-design-essentials/src/commands/debug.ts +++ b/packages/plugin-design-essentials/src/commands/debug.ts @@ -1,5 +1,5 @@ import { PluginContext } from "@imgly/plugin-core"; -import { readPropValue } from "../utils/cesdk"; +import { readBlockProperty } from "../utils/cesdk"; export const debugLogBlockProperties = async (ctx: PluginContext, params: { blockIds: number[] }) => { const { block } = ctx.engine; @@ -11,7 +11,7 @@ export const debugLogBlockProperties = async (ctx: PluginContext, params: { bloc props.forEach((propKey: string) => { if (!block.isPropertyReadable(propKey)) return; const propType = block.getPropertyType(propKey) - const propValue = readPropValue(block, bId, propKey, propType) + const propValue = readBlockProperty(block, bId, propKey, propType) propDefinition.set(propKey, propValue) }) console.debug("Properties for block", bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) @@ -72,16 +72,13 @@ export const debugLogBlockFill = (ctx: PluginContext, params: { blockIds?: numbe props.forEach((propKey: string) => { if (!block.isPropertyReadable(propKey)) return; - const propValue = readPropValue(block, fId, propKey) + const propValue = readBlockProperty(block, fId, propKey) propDefinition.set(propKey, propValue) }) console.debug("Fill for block", bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) }); } - - - export const debugLogBlockEffects = (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected() } = params; @@ -96,7 +93,7 @@ export const debugLogBlockEffects = (ctx: PluginContext, params: { blockIds?: nu props.forEach((propKey: string) => { if (!block.isPropertyReadable(propKey)) return; - const propValue = readPropValue(block, eId, propKey) + const propValue = readBlockProperty(block, eId, propKey) propDefinition.set(propKey, propValue) }) console.debug(`Effects ${eId} for block`, bId, JSON.stringify(Object.fromEntries(propDefinition.entries()), null, 2)) @@ -129,7 +126,7 @@ export const debugLogBlockBlur = (ctx: PluginContext, params: { blockIds?: numbe props.forEach((propKey: string) => { if (!block.isPropertyReadable(propKey)) return; - const propValue = readPropValue(block, eId, propKey) + const propValue = readBlockProperty(block, eId, propKey) propDefinition.set(propKey, propValue) @@ -138,3 +135,24 @@ export const debugLogBlockBlur = (ctx: PluginContext, params: { blockIds?: numbe }); } + +export const debugLogSceneHierarchy = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block, scene } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + const sId = scene.get()! + + const blockInfo = (bId: number) => { + const name = block.getName(bId) || block.getUUID(bId).toString() + const type = block.getType(bId) + const cIds = block.getChildren(bId) + const children = cIds.map(blockInfo) + const hierarchy = {name, type, id: bId, children} + return hierarchy + } + + const hierarchy = blockInfo(sId); + console.debug("Scene Hierarchy", JSON.stringify(hierarchy, null, 2)) + + + +} diff --git a/packages/plugin-design-essentials/src/commands/image.ts b/packages/plugin-design-essentials/src/commands/image.ts index c369fe6..bb89625 100644 --- a/packages/plugin-design-essentials/src/commands/image.ts +++ b/packages/plugin-design-essentials/src/commands/image.ts @@ -1,5 +1,6 @@ +import { PluginContext } from "@imgly/plugin-core"; import { ContentFillMode } from "@cesdk/cesdk-js" -import { PluginContext } from "../../../plugin-core/types"; + const imageFitWithMode = (ctx: PluginContext, params: { blockIds?: number[], fillMode: ContentFillMode }) => { const { block } = ctx.engine; @@ -10,9 +11,6 @@ const imageFitWithMode = (ctx: PluginContext, params: { blockIds?: number[], fil }) } -export const imageFitModeCrop = async (ctx: PluginContext, params: { blockIds?: number[] }) => - imageFitWithMode(ctx, { ...params, fillMode: 'Crop' }) - +export const imageFitModeCrop = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Crop' }) export const imageFitModeCover = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Cover' }) - -export const imageFitModeContain = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Contain' }) \ No newline at end of file +export const imageFitModeContain = async (ctx: PluginContext, params: { blockIds?: number[] }) => imageFitWithMode(ctx, { ...params, fillMode: 'Contain' }) diff --git a/packages/plugin-design-essentials/src/commands/import.ts b/packages/plugin-design-essentials/src/commands/import.ts new file mode 100644 index 0000000..67a14bd --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/import.ts @@ -0,0 +1,2 @@ +// .txt, .cesdk, .png, .jpg, .jpeg, .webp, .pdf, +// .csv ... generate a new page from each row and replace the content of the blocks with the values from the row \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/index.ts b/packages/plugin-design-essentials/src/commands/index.ts index 0ad4ccd..8b05885 100644 --- a/packages/plugin-design-essentials/src/commands/index.ts +++ b/packages/plugin-design-essentials/src/commands/index.ts @@ -1,4 +1,4 @@ -export * from "./lifecycle"; +export * from "./block"; export * from "./export"; export * from "./image"; export * from "./container"; @@ -10,6 +10,6 @@ export * from "./components"; export * from "./playground"; export * from "./i18n"; export * from "./panels"; - +export * from "./turnInto"; export * from "./replicate.io"; \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/lifecycle.ts b/packages/plugin-design-essentials/src/commands/lifecycle.ts deleted file mode 100644 index c7bc9a4..0000000 --- a/packages/plugin-design-essentials/src/commands/lifecycle.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { PluginContext } from "../../../plugin-core/types"; - -export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - ctx.engine.block.isValid(id) && ctx.engine.block.destroy(id) - }); -} - -export const blockDuplicate = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.isValid(id); - const newBlock = block.duplicate(id); - const parent = block.getParent(id); - if (parent && block.isValid(parent)) { - block.appendChild(parent, newBlock); - } - block.setSelected(newBlock, true); // should return the previous state - block.setSelected(id, false); - - }); -} - - -export const blockRename = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.isValid(id); - const name = block.getName(id) - const newName = prompt("Block name", name); - if (newName) { - block.setName(id, newName); - } - }); -} -export const blockBringForward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.bringForward(id); - }); -} - -export const blockSendBackward = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.sendBackward(id); - }); -} - -export const blockBringToFront = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.bringToFront(id); - }); -} - -export const blockSendToBack = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - block.sendToBack(id); - }) -} diff --git a/packages/plugin-design-essentials/src/commands/playground.ts b/packages/plugin-design-essentials/src/commands/playground.ts index ed7606e..79bf1e7 100644 --- a/packages/plugin-design-essentials/src/commands/playground.ts +++ b/packages/plugin-design-essentials/src/commands/playground.ts @@ -2,7 +2,7 @@ // SYNC BY NAME - two pages, same name import { PluginContext } from "../../../plugin-core/types"; -import { readPropValue, writePropValue } from "../utils/cesdk"; +import { readBlockProperty, setBlockProperty } from "../utils/cesdk"; import { CreativeEngine } from "@cesdk/cesdk-js"; const propKeys = [ @@ -35,13 +35,13 @@ const syncBlockProperties = (ctx: PluginContext, sourceId: number, destIds: numb }) propertyKeys.forEach((propertyKey: string) => { - const sourceValue = readPropValue(block, sourceId, propertyKey) + const sourceValue = readBlockProperty(block, sourceId, propertyKey) destIds.forEach((receiverBlockId: number) => { if (!block.isValid(receiverBlockId)) return if (sourceId === receiverBlockId) return; - const receiverValue = readPropValue(block, receiverBlockId, propertyKey) + const receiverValue = readBlockProperty(block, receiverBlockId, propertyKey) if (receiverValue === sourceValue) return; - writePropValue(block, receiverBlockId, propertyKey, sourceValue) + setBlockProperty(block, receiverBlockId, propertyKey, sourceValue) }) }) } diff --git a/packages/plugin-design-essentials/src/commands/plugins.ts b/packages/plugin-design-essentials/src/commands/plugins.ts index 8cfa726..1947e37 100644 --- a/packages/plugin-design-essentials/src/commands/plugins.ts +++ b/packages/plugin-design-essentials/src/commands/plugins.ts @@ -1,6 +1,6 @@ import { PluginContext } from "../../../plugin-core/types"; -export const pluginRegisterAndOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { +export const pluginRegisterCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { ui } = ctx; ui?.unstable_registerCustomPanel('ly.img.foo', (domElement) => { domElement.appendChild(document.createTextNode('Hello World')); @@ -8,7 +8,11 @@ export const pluginRegisterAndOpenCustomPanel = async (ctx: PluginContext, _para console.log('Apps disposer called'); }; }); - - ui?.openPanel("ly.img.foo") } + + +export const pluginOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { + const { ui } = ctx; + ui?.openPanel('ly.img.foo'); +} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/replicate.io.ts b/packages/plugin-design-essentials/src/commands/replicate.io.ts index 251cf3d..1c0f482 100644 --- a/packages/plugin-design-essentials/src/commands/replicate.io.ts +++ b/packages/plugin-design-essentials/src/commands/replicate.io.ts @@ -1,90 +1,158 @@ import { PluginContext } from "@imgly/plugin-core"; -import { downloadBlob } from "../utils/download"; - +// TODOS // https://replicate.com/stability-ai/stable-diffusion-img2img?prediction=63trbdrbookprhnq3eoap6iwz4 // https://replicate.com/pharmapsychotic/clip-interrogator - - - +// https://replicate.com/batouresearch/high-resolution-controlnet-tile/examples#jq5gj2dbjg6j6l3ih7hf3jfuoa // https://replicate.com/mistralai/mixtral-8x7b-instruct-v0.1 const REPLICATE_API_TOKEN = "r8_Y7Qt7U8vkF8QBVDJ9RvWTQNuebwVLBp2qvvBT" -export const callReplicate = async (ctx: PluginContext, params: { blockIds?: number[]; }) => { - const data = { - "version": "39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b", - "input": { - "width": 768, - "height": 768, - "prompt": "An astronaut riding a rainbow unicorn, cinematic, dramatic", +const REPLICATE_HEADERS = { + "Content-Type": 'application/json', + "Authorization": `Token ${REPLICATE_API_TOKEN}` +} + +const proxyForCors = (url: string) => 'https://corsproxy.io/?' + encodeURIComponent(url); + +const MODELS = { + "face2sticker": { + version: "764d4827ea159608a07cdde8ddf1c6000019627515eb02b6b449695fd547e5ef", + input: (iInput) => ({ + "steps": 20, + "width": 1024, + "height": 1024, + "upscale": false, + "upscale_steps": 10, + "negative_prompt": "", + "prompt_strength": 4.5, + "ip_adapter_noise": 0.5, + "ip_adapter_weight": 0.2, + "instant_id_strength": 0.7, + ...iInput + }) + }, + "sdxl": { + version: "39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b", + input: (iInput) => ({ + "width": 1024, + "height": 1024, "refine": "expert_ensemble_refiner", "scheduler": "K_EULER", - "lora_scale": 0.6, "num_outputs": 1, + "lora_scale": 0.6, "guidance_scale": 7.5, "apply_watermark": false, "high_noise_frac": 0.8, "negative_prompt": "", "prompt_strength": 0.8, - "num_inference_steps": 25 - } + "num_inference_steps": 25, + ...iInput + }) + }, + "playgroundai/playground-v2-1024px-aesthetic": { + version: "42fe626e41cc811eaf02c94b892774839268ce1994ea778eba97103fe1ef51b8", + input: (iInput) => ({ + width: 1024, + height: 1024, + scheduler: "K_EULER_ANCESTRAL", + guidance_scale: 3, + apply_watermark: false, + negative_prompt: "", + num_inference_steps: 50, + ...iInput + }) + } +} +export const replicateSDXL = async (ctx: PluginContext, params: { blockIds?: number[]; }) => { + const { block } = ctx.engine; + let { + blockIds = block.findAllSelected() + } = params; + const isGroup = (blockIds.length === 1 && block.getType(blockIds[0]) === '//ly.img.ubq/group'); + blockIds = isGroup ? block.getChildren(blockIds[0]) : blockIds; + + const iIds = blockIds.filter((id: number) => { + if (!block.hasFill(id)) return false + const fId = block.getFill(id) + if (!block.isValid(fId)) return false + const fType = block.getType(fId) + return fType === "//ly.img.ubq/fill/image" + }) + const fIds = iIds.map((id: number) => [id, block.getFill(id)]) + fIds.forEach(async ([bId, fId]) => { + // fake busy + //enssure we have preview + const imageFillUri = block.getString(fId, 'fill/image/imageFileURI'); + const name = block.getName(bId) + block.setString(fId, 'fill/image/previewFileURI', block.getString(fId, 'fill/image/previewFileURI') ?? block.getString(fId, 'fill/image/imageFileURI')); + block.setString(fId, 'fill/image/imageFileURI', ''); + block.setSourceSet(fId, 'fill/image/sourceSet', []); + + + const iPrompt = (name.length === 0) ? prompt("Enter a prompt", name) : name + const iImage = imageFillUri + const iMask = undefined + + + if (!name) block.setName(bId, iPrompt) + // const model = "playgroundai/playground-v2-1024px-aesthetic" + const model = "sdxl" + // const model = "face2sticker" + const replicateIoVersion = MODELS[model].version + const replicateIoinput = MODELS[model].input({ prompt: iPrompt, mask: iMask, image: iImage }) + const images = await callReplicateIo(replicateIoVersion, replicateIoinput) + + const image = images[0] // for now we assume one image but we could gather multiple in batch + block.setString(fId, 'fill/image/imageFileURI', image); + block.setSourceSet(fId, 'fill/image/sourceSet', []); + }) - const url = proxy("https://api.replicate.com/v1/predictions") +} + + + +const callReplicateIo = async (version: string, input: any) => { + const data = { + version, + input + } + + const url = proxyForCors("https://api.replicate.com/v1/predictions") const res = await fetch(url, { method: 'POST', // mode: "no-cors", - headers, + headers: REPLICATE_HEADERS, body: JSON.stringify(data) }) const json = await res.json() - - const images = await waitForReplicate(json) - - images.forEach((image: Blob, index: number) => { - const filename = `replicate-${index}.png` - downloadBlob(image, filename) - }) - -} - -const headers = { - "Content-Type": 'application/json', - "Authorization": `Token ${REPLICATE_API_TOKEN}` + return await waitForReplicate(json) } -const proxy = (url: string) => 'https://corsproxy.io/?' + encodeURIComponent(url); - -const waitForReplicate = async (json: any): Promise => { +const waitForReplicate = async (json: any): Promise => { return new Promise((resolve, reject) => { const interval = 1000 const timeout = setInterval(async () => { // console.log("Checking status") - const url = proxy(json.urls.get) - const statusRes = await fetch(url, { headers }) + const url = proxyForCors(json.urls.get) + const statusRes = await fetch(url, { headers: REPLICATE_HEADERS }) const statusJson = await statusRes.json() - // console.log(statusJson) + console.log(statusJson) if (statusJson.error) { clearInterval(timeout) reject(statusJson.error) } if (statusJson.status === "succeeded") { clearInterval(timeout) - // console.log("Success") - // console.log("Metrics", statusJson.metrics) const { output } = statusJson - const images = await Promise.all(output.map(async (o: string) => { - const image = await fetch(proxy(o), { headers }) - return image.blob() - })) - resolve(images) - + resolve(output?.map((o: string) => proxyForCors(o))) + } }, interval) }) diff --git a/packages/plugin-design-essentials/src/commands/turnInto.ts b/packages/plugin-design-essentials/src/commands/turnInto.ts new file mode 100644 index 0000000..38fae9b --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/turnInto.ts @@ -0,0 +1,24 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { turnBlockInto } from "../utils/turnBlockInto"; + +export const blockTurnIntoGraphic = (ctx: PluginContext, params: { blockIds: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((id) => turnBlockInto(ctx, "graphic", id)) + +} + +export const blockTurnIntoText = (ctx: PluginContext, params: { blockIds: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((id) => turnBlockInto(ctx, "text", id)) +} + +export const blockTurnIntoPage = (ctx: PluginContext, params: { blockIds: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + + blockIds.forEach((id) => turnBlockInto(ctx, "page", id)) +} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/index.ts b/packages/plugin-design-essentials/src/index.ts index 6cf2ead..efb525e 100644 --- a/packages/plugin-design-essentials/src/index.ts +++ b/packages/plugin-design-essentials/src/index.ts @@ -61,14 +61,13 @@ const registerPanels = async (ctx: PluginContext, panels: any) => { } const loadPanels = async (ctx: PluginContext) => { - const panels = await import("./panels/layers") - await registerPanels(ctx, panels) + // const panels = await import("./panels/layers") + // await registerPanels(ctx, panels) } export const activate = async (ctx: PluginContext) => { - await loadTranslation(ctx) await loadCommands(ctx) await loadPanels(ctx) diff --git a/packages/plugin-design-essentials/src/locale/de.json b/packages/plugin-design-essentials/src/locale/de.json deleted file mode 100644 index 74992c7..0000000 --- a/packages/plugin-design-essentials/src/locale/de.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "design-batteries.commands.blockBringForward": "Block nach vorne bringen", - "design-batteries.commands.blockBringToFront": "Block ganz nach vorne bringen", - "design-batteries.commands.blockDelete": "Block löschen", - "design-batteries.commands.blockDuplicate": "Block duplizieren", - "design-batteries.commands.blockRename": "Block umbenennen", - "design-batteries.commands.blockSendBackward": "Block nach hinten senden", - "design-batteries.commands.blockSendToBack": "Block ganz nach hinten senden", - "design-batteries.commands.blockGroup": "Blöcke gruppieren", - "design-batteries.commands.blockUngroup": "Blöcke aufheben", - "design-batteries.commands.debugLogBlockCrop": "Debug-Log für Block zuschneiden", - "design-batteries.commands.debugLogBlockMetadata": "Debug-Log für Block-Metadaten", - "design-batteries.commands.debugLogBlockProperties": "Debug-Log für Block-Eigenschaften", - "design-batteries.commands.exportComponentLibrary": "Komponentenbibliothek exportieren", - "design-batteries.commands.exportComponentToFile": "Komponente in Datei exportieren", - "design-batteries.commands.exportJsonToClipboard": "JSON in Zwischenablage exportieren", - "design-batteries.commands.exportJsonToFile": "JSON in Datei exportieren", - "design-batteries.commands.exportJpegToFile": "JPEG in Datei exportieren", - "design-batteries.commands.exportPdfToFile": "PDF in Datei exportieren", - "design-batteries.commands.exportPngToClipboard": "PNG in Zwischenablage exportieren", - "design-batteries.commands.exportPngToFile": "PNG in Datei exportieren", - "design-batteries.commands.exportRgba8ToFile": "Rohes RGBA8 in Datei exportieren", - "design-batteries.commands.exportSceneToClipboard": "Szene in Zwischenablage exportieren", - "design-batteries.commands.exportSceneToFile": "Szene in Datei exportieren", - "design-batteries.commands.exportWebpToFile": "WEBP in Datei exportieren", - "design-batteries.commands.i18nDownloadMissingCommandTranslations": "Fehlende Befehlsübersetzungen herunterladen", - "design-batteries.commands.imageFitModeContain": "Bildanpassungsmodus auf Enthalten setzen", - "design-batteries.commands.imageFitModeCrop": "Bildanpassungsmodus auf Zuschneiden setzen", - "design-batteries.commands.imageFitModeCover": "Bildanpassungsmodus auf Abdecken setzen", - "design-batteries.commands.importComponent": "Komponente importieren", - "design-batteries.commands.layoutHorizontally": "Horizontal anordnen", - "design-batteries.commands.layoutMasonry": "Mauerwerk anordnen", - "design-batteries.commands.layoutVertically": "Vertikal anordnen", - "design-batteries.commands.myNewFunctionForTheEditor": "Super tolle Funktion", - "design-batteries.commands.playground": "Spielplatz", - "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "Benutzerdefiniertes Panel registrieren und öffnen", - "design-batteries.commands.productSetInstagram": "Instagram-Produkt festlegen", - "design-batteries.commands.syncBlocks": "Blöcke synchronisieren" -} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/locale/en.json b/packages/plugin-design-essentials/src/locale/en.json index 09c4f5e..01a396f 100644 --- a/packages/plugin-design-essentials/src/locale/en.json +++ b/packages/plugin-design-essentials/src/locale/en.json @@ -1,16 +1,26 @@ { "design-batteries.commands.blockBringForward": "Bring Block Forward", "design-batteries.commands.blockBringToFront": "Bring Block to Front", + "design-batteries.commands.blockCreateGraphic": "Create Graphic Block", + "design-batteries.commands.blockCreateText": "Create Text Block", "design-batteries.commands.blockDelete": "Delete Block", "design-batteries.commands.blockDuplicate": "Duplicate Block", + "design-batteries.commands.blockGroup": "Group Blocks", "design-batteries.commands.blockRename": "Rename Block", "design-batteries.commands.blockSendBackward": "Send Block Backward", "design-batteries.commands.blockSendToBack": "Send Block to Back", - "design-batteries.commands.blockGroup": "Group Blocks", + "design-batteries.commands.blockTurnIntoGraphic": "Turn Block into Graphic", + "design-batteries.commands.blockTurnIntoPage": "Turn Block into Page", + "design-batteries.commands.blockTurnIntoText": "Turn Block into Text", "design-batteries.commands.blockUngroup": "Ungroup Blocks", + "design-batteries.commands.createDefaultBlockByType": "Create Default Block by Type", + "design-batteries.commands.debugLogBlockBlur": "Debug Log Block Blur", "design-batteries.commands.debugLogBlockCrop": "Debug Log Block Crop", + "design-batteries.commands.debugLogBlockEffects": "Debug Log Block Effects", + "design-batteries.commands.debugLogBlockFill": "Debug Log Block Fill", "design-batteries.commands.debugLogBlockMetadata": "Debug Log Block Metadata", "design-batteries.commands.debugLogBlockProperties": "Debug Log Block Properties", + "design-batteries.commands.debugLogSceneHierarchy": "Debug Log Scene Hierarchy", "design-batteries.commands.exportComponentLibrary": "Export Component Library", "design-batteries.commands.exportComponentToFile": "Export Component to File", "design-batteries.commands.exportJsonToClipboard": "Export JSON to Clipboard", @@ -32,8 +42,13 @@ "design-batteries.commands.layoutMasonry": "Layout Masonry", "design-batteries.commands.layoutVertically": "Layout Vertically", "design-batteries.commands.myNewFunctionForTheEditor": "Super Duper Function", - "design-batteries.commands.playground": "Playground", + "design-batteries.commands.panelSettingsClose": "Close Settings Panel", + "design-batteries.commands.panelSettingsOpen": "Open Settings Panel", + "design-batteries.commands.pluginOpenCustomPanel": "Open Custom Panel", "design-batteries.commands.pluginRegisterAndOpenCustomPanel": "Register and Open Custom Panel", + "design-batteries.commands.pluginRegisterCustomPanel": "Register Custom Panel", "design-batteries.commands.productSetInstagram": "Set Instagram Product", + "design-batteries.commands.replicateSDXL": "Replicate SDXL", + "design-batteries.commands.syncBlockAppearance": "Sync Block Appearance", "design-batteries.commands.syncBlocks": "Sync Blocks" } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/panels/index.ts b/packages/plugin-design-essentials/src/panels/index.ts index f3d498e..0e84be7 100644 --- a/packages/plugin-design-essentials/src/panels/index.ts +++ b/packages/plugin-design-essentials/src/panels/index.ts @@ -1 +1 @@ -export * from "./layers"; \ No newline at end of file +// export * from "./layers"; \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/panels/layers.ts b/packages/plugin-design-essentials/src/panels/layers.ts index 094c6a7..473a5d6 100644 --- a/packages/plugin-design-essentials/src/panels/layers.ts +++ b/packages/plugin-design-essentials/src/panels/layers.ts @@ -1,19 +1,19 @@ -import { PluginContext } from '@imgly/plugin-core'; +// import { PluginContext } from '@imgly/plugin-core'; -export const layerList = async (ctx: PluginContext, builder: any, params: any) => { - const { block } = ctx.engine; - const { Button, Section, Separator } = builder; - const blockIds = block.findAllSelected(); +// export const layerList = async (ctx: PluginContext, builder: any, params: any) => { +// const { block } = ctx.engine; +// const { Button, Section, Separator } = builder; +// const blockIds = block.findAllSelected(); - Section('layer.section', { - title: 'Layers', - children: () => - blockIds.forEach((bId: number) => - Button(bId.toString(), { - label: block.getName(bId) || block.getUUID(bId).toString(), - onClick: () => block.select(bId) - })) - }); +// Section('layer.section', { +// title: 'Layers', +// children: () => +// blockIds.forEach((bId: number) => +// Button(bId.toString(), { +// label: block.getName(bId) || block.getUUID(bId).toString(), +// onClick: () => block.select(bId) +// })) +// }); -} +// } diff --git a/packages/plugin-design-essentials/src/utils/cesdk.ts b/packages/plugin-design-essentials/src/utils/cesdk.ts index b8169c3..d1c6def 100644 --- a/packages/plugin-design-essentials/src/utils/cesdk.ts +++ b/packages/plugin-design-essentials/src/utils/cesdk.ts @@ -1,7 +1,7 @@ import { BlockAPI } from "@cesdk/cesdk-js"; -export const readPropValue = (block: BlockAPI, id: number, propKey: string, propType?: string) => { +export const readBlockProperty = (block: BlockAPI, id: number, propKey: string, propType?: string) => { const blacklist = ["fill/solid/color", "fill/image/sourceSet"] if (blacklist.includes(propKey)) return undefined; if (!propType) propType = block.getPropertyType(propKey) @@ -21,7 +21,7 @@ export const readPropValue = (block: BlockAPI, id: number, propKey: string, prop }; -export const writePropValue = (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => { +export const setBlockProperty = (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => { if (!propType) propType = block.getPropertyType(propKey) try { switch (propType.toLowerCase()) { diff --git a/packages/plugin-design-essentials/src/utils/getTransform.ts b/packages/plugin-design-essentials/src/utils/getTransform.ts new file mode 100644 index 0000000..6cbd969 --- /dev/null +++ b/packages/plugin-design-essentials/src/utils/getTransform.ts @@ -0,0 +1,12 @@ +import { PluginContext } from "@imgly/plugin-core"; + +export const getTransform = (ctx: PluginContext, bId: number) => { + const { block } = ctx.engine; + return { + x: block.getPositionX(bId), + y: block.getPositionY(bId), + width: block.getFrameWidth(bId), + height: block.getFrameHeight(bId) + }; + +}; diff --git a/packages/plugin-design-essentials/src/utils/setTransform.ts b/packages/plugin-design-essentials/src/utils/setTransform.ts new file mode 100644 index 0000000..fa6c938 --- /dev/null +++ b/packages/plugin-design-essentials/src/utils/setTransform.ts @@ -0,0 +1,10 @@ +import { PluginContext } from "@imgly/plugin-core"; + +export const setTransform = (ctx: PluginContext, bId: number, transform: any) => { + const { block } = ctx.engine; + const { x, y, width, height } = transform; + x && block.setPositionX(bId, x); + y && block.setPositionY(bId, y); + width && block.setWidth(bId, width); + height && block.setHeight(bId, height); +}; diff --git a/packages/plugin-design-essentials/src/utils/turnBlockInto.ts b/packages/plugin-design-essentials/src/utils/turnBlockInto.ts new file mode 100644 index 0000000..f87697c --- /dev/null +++ b/packages/plugin-design-essentials/src/utils/turnBlockInto.ts @@ -0,0 +1,37 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { getTransform } from "./getTransform"; +import { setTransform } from "./setTransform"; +import { createDefaultBlockByType } from "../commands/block"; + +export const turnBlockInto = (ctx: PluginContext, toType: string, id: number) => { + const { block, scene } = ctx.engine; + + const bId = createDefaultBlockByType(ctx, toType); + + if (block.hasFill(id)) { + const fId = block.duplicate(block.getFill(id)); + block.hasFill(bId) && block.setFill(bId, fId); + } + if (block.hasShape(id)) { + const sId = block.duplicate(block.getShape(id)); + block.hasShape(bId) && block.setShape(bId, sId); + } + + setTransform(ctx, bId, getTransform(ctx, id)); + + if (toType === "page") { + console.log("Turning into page"); + let pId = scene.get()!; + const cIds = block.getChildren(pId); + const sId = cIds.find((cId) => block.getType(cId) === "//ly.img.ubq/stack") + const hasStack = sId !== -1 + console.log("Has stack", hasStack); + pId = hasStack ? sId : pId; + block.appendChild(pId, bId); + } else { + const pId = block.getParent(id) ?? scene.getCurrentPage() ?? scene.get()!; + block.appendChild(pId, bId); + } + + block.destroy(id); +}; diff --git a/packages/plugin-vectorizer/src/activate.ts b/packages/plugin-vectorizer/src/activate.ts index 2b4a91d..4e9065a 100644 --- a/packages/plugin-vectorizer/src/activate.ts +++ b/packages/plugin-vectorizer/src/activate.ts @@ -76,15 +76,15 @@ export async function activate(ctx: PluginContext) { }); }); } - { - // THIS DOES not belong here maybe - ctx.logger?.trace("Defaulting canvas menu order") - const canvasMenuEntries = [ - PluginManifest.contributes.ui.button.id, - ...ctx.ui?.unstable_getCanvasMenuOrder() ?? [] - ] - ctx.ui?.unstable_setCanvasMenuOrder(canvasMenuEntries); - } + // { + // // THIS DOES not belong here maybe + // ctx.logger?.trace("Defaulting canvas menu order") + // const canvasMenuEntries = [ + // PluginManifest.contributes.ui.button.id, + // ...ctx.ui?.unstable_getCanvasMenuOrder() ?? [] + // ] + // ctx.ui?.unstable_setCanvasMenuOrder(canvasMenuEntries); + // } } // maybe this should be just engine.event.onUpdate() diff --git a/packages/plugin-vectorizer/types/deps.d.ts b/packages/plugin-vectorizer/types/deps.d.ts index 54a2b05..ab2960b 100644 --- a/packages/plugin-vectorizer/types/deps.d.ts +++ b/packages/plugin-vectorizer/types/deps.d.ts @@ -1,5 +1,5 @@ import { I18NKeys } from "./PluginManifest"; -import { type PluginContext as IPluginContext, CommandCallback } from '../../plugin-core/types'; +import { type PluginContext as IPluginContext, CommandCallback } from '@imgly/plugin-core'; type PluginContext = IPluginContext; export { CreativeEngine } from '@cesdk/cesdk-js'; export { type PluginContext, type CommandCallback }; From 1e806bd5bb69f0c5e6c6e4c411ac74b80e647913 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Sun, 3 Mar 2024 19:56:22 +0100 Subject: [PATCH 31/32] feat: add plugin-documents --- packages/plugin-core/types/index.d.ts | 4 + packages/plugin-documents/.gitignore | 11 +++ packages/plugin-documents/esbuild/config.mjs | 58 +++++++++++++ packages/plugin-documents/esbuild/global.d.ts | 3 + packages/plugin-documents/manifest.json | 13 +++ packages/plugin-documents/package.json | 67 +++++++++++++++ packages/plugin-documents/scripts/build.mjs | 5 ++ packages/plugin-documents/scripts/watch.mjs | 19 +++++ .../plugin-documents/src/PluginManifest.ts | 10 +++ .../src/commands/__template.ts | 3 + .../plugin-documents/src/commands/index.ts | 8 ++ packages/plugin-documents/src/index.ts | 85 +++++++++++++++++++ packages/plugin-documents/src/locale/en.json | 1 + packages/plugin-documents/src/panels/index.ts | 1 + .../plugin-documents/src/panels/layers.ts | 19 +++++ packages/plugin-documents/src/utils/cesdk.ts | 39 +++++++++ .../src/utils/computeBlockName.ts | 8 ++ .../src/utils/computeMultiSelectionBounds.ts | 20 +++++ .../plugin-documents/src/utils/download.ts | 60 +++++++++++++ .../src/utils/exportBlockAs.ts | 34 ++++++++ .../src/utils/getTransform.ts | 12 +++ .../src/utils/setTransform.ts | 10 +++ .../src/utils/turnBlockInto.ts | 37 ++++++++ packages/plugin-documents/src/worker.ts | 0 packages/plugin-documents/tsconfig.json | 17 ++++ 25 files changed, 544 insertions(+) create mode 100644 packages/plugin-documents/.gitignore create mode 100644 packages/plugin-documents/esbuild/config.mjs create mode 100644 packages/plugin-documents/esbuild/global.d.ts create mode 100644 packages/plugin-documents/manifest.json create mode 100644 packages/plugin-documents/package.json create mode 100644 packages/plugin-documents/scripts/build.mjs create mode 100644 packages/plugin-documents/scripts/watch.mjs create mode 100644 packages/plugin-documents/src/PluginManifest.ts create mode 100644 packages/plugin-documents/src/commands/__template.ts create mode 100644 packages/plugin-documents/src/commands/index.ts create mode 100644 packages/plugin-documents/src/index.ts create mode 100644 packages/plugin-documents/src/locale/en.json create mode 100644 packages/plugin-documents/src/panels/index.ts create mode 100644 packages/plugin-documents/src/panels/layers.ts create mode 100644 packages/plugin-documents/src/utils/cesdk.ts create mode 100644 packages/plugin-documents/src/utils/computeBlockName.ts create mode 100644 packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts create mode 100644 packages/plugin-documents/src/utils/download.ts create mode 100644 packages/plugin-documents/src/utils/exportBlockAs.ts create mode 100644 packages/plugin-documents/src/utils/getTransform.ts create mode 100644 packages/plugin-documents/src/utils/setTransform.ts create mode 100644 packages/plugin-documents/src/utils/turnBlockInto.ts create mode 100644 packages/plugin-documents/src/worker.ts create mode 100644 packages/plugin-documents/tsconfig.json diff --git a/packages/plugin-core/types/index.d.ts b/packages/plugin-core/types/index.d.ts index 7588cca..2bd78b9 100644 --- a/packages/plugin-core/types/index.d.ts +++ b/packages/plugin-core/types/index.d.ts @@ -1,4 +1,8 @@ +import { PluginContext } from "./plugin/PluginContext"; export { Commands, type CommandCallback, type CommandDescription } from "./plugin/Commands"; export { I18N } from "./plugin/I18n"; export { type Logger } from "./plugin/Logger"; export { PluginContext } from "./plugin/PluginContext"; +export declare function loadCommands(ctx: PluginContext, imports: any, manifest: Manifest): Promise; diff --git a/packages/plugin-documents/.gitignore b/packages/plugin-documents/.gitignore new file mode 100644 index 0000000..9060c20 --- /dev/null +++ b/packages/plugin-documents/.gitignore @@ -0,0 +1,11 @@ +node_modules +packages/*/dist +examples/*/dist +.env.local + +.DS_Store +yarn-error.log + +.turbo +.vercel +types \ No newline at end of file diff --git a/packages/plugin-documents/esbuild/config.mjs b/packages/plugin-documents/esbuild/config.mjs new file mode 100644 index 0000000..37b437c --- /dev/null +++ b/packages/plugin-documents/esbuild/config.mjs @@ -0,0 +1,58 @@ +import chalk from 'chalk'; +import { readFile } from 'fs/promises'; + +// import packageJson from '../package.json' assert { type: 'json' }; +// Avoid the Experimental Feature warning when using the above. +const packageJson = JSON.parse( + await readFile(new URL('../package.json', import.meta.url)) +); + + +const dependencies = Object.keys(packageJson.dependencies) +const peerDependencies = Object.keys(packageJson.peerDependencies) +const externals = [...dependencies, ...peerDependencies] + +console.log( + chalk.yellow('Building version: '), + chalk.green(packageJson.version) +); + +const configs = [ + { + entryPoints: ['src/index.ts', "src/worker.ts"], + define: { + PLUGIN_VERSION: `"${packageJson.version}"` + }, + minify: true, + bundle: true, + sourcemap: true, + external: externals, + platform: 'node', + format: 'esm', + outdir: 'dist', + outExtension: { '.js': '.mjs' }, + plugins: [ + { + name: 'reporter', + setup(build) { + build.onEnd((result) => { + console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] Build ${ + result.errors.length + ? chalk.red('failed') + : chalk.green('succeeded') + }` + ); + }); + } + } + ] + } +]; + +export default configs; diff --git a/packages/plugin-documents/esbuild/global.d.ts b/packages/plugin-documents/esbuild/global.d.ts new file mode 100644 index 0000000..de80fd8 --- /dev/null +++ b/packages/plugin-documents/esbuild/global.d.ts @@ -0,0 +1,3 @@ +// These constants here are added by the base esbuild config + +declare const PLUGIN_VERSION: string; diff --git a/packages/plugin-documents/manifest.json b/packages/plugin-documents/manifest.json new file mode 100644 index 0000000..9ee9cf1 --- /dev/null +++ b/packages/plugin-documents/manifest.json @@ -0,0 +1,13 @@ +{ + "id": "documents", + "version": "0.0.1", + "publisher": "IMG.LY GmbH", + "icon": null, + "categories": [], + "contributes": { + "commands": { + + }, + "i18n": {} + } +} \ No newline at end of file diff --git a/packages/plugin-documents/package.json b/packages/plugin-documents/package.json new file mode 100644 index 0000000..47188b1 --- /dev/null +++ b/packages/plugin-documents/package.json @@ -0,0 +1,67 @@ +{ + "name": "@imgly/plugin-documents", + "version": "0.1.0", + "keywords": [ + "CE.SDK", + "IMG.LY", + "plugin" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/imgly/plugins.git" + }, + "license": "SEE LICENSE IN LICENSE.md", + "author": { + "name": "IMG.LY GmbH", + "email": "support@img.ly", + "url": "https://img.ly" + }, + "bugs": { + "email": "support@img.ly" + }, + "source": "./src/index.ts", + "module": "./dist/index.mjs", + "types": "./types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./types/index.d.ts" + } + }, + "homepage": "https://img.ly", + "files": [ + "LICENSE.md", + "README.md", + "CHANGELOG.md", + "dist/", + "types/", + "bin/" + ], + "scripts": { + "start": "npm run watch", + "clean": "npx rimraf dist && npx rimraf types", + "build": "yarn run clean && yarn run types:create && node scripts/build.mjs", + "dev": "yarn run types:create && node scripts/watch.mjs", + "publish:latest": "npm run clean && npm run build && npm publish --tag latest --access public", + "publish:next": "npm run clean && npm run build && npm publish --tag next --access public", + "check:all": "concurrently -n lint,type,pretty \"yarn check:lint\" \"yarn check:type\" \"yarn check:pretty\"", + "check:lint": "eslint --max-warnings 0 './src/**/*.{ts,tsx}'", + "check:pretty": "prettier --list-different './src/**/*.{ts,tsx}'", + "check:type": "tsc --noEmit", + "types:create": "tsc --emitDeclarationOnly" + }, + "devDependencies": { + "chalk": "^5.3.0", + "concurrently": "^8.2.2", + "esbuild": "^0.19.11", + "eslint": "^8.51.0", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "@cesdk/cesdk-js": "~1.21.0" + }, + "dependencies": { + "@imgly/plugin-core": "*", + "lodash": "^4.17.21" + } +} diff --git a/packages/plugin-documents/scripts/build.mjs b/packages/plugin-documents/scripts/build.mjs new file mode 100644 index 0000000..13d12e1 --- /dev/null +++ b/packages/plugin-documents/scripts/build.mjs @@ -0,0 +1,5 @@ +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +await Promise.all(configs.map(async (config) => await esbuild.build(config))); diff --git a/packages/plugin-documents/scripts/watch.mjs b/packages/plugin-documents/scripts/watch.mjs new file mode 100644 index 0000000..15dbb21 --- /dev/null +++ b/packages/plugin-documents/scripts/watch.mjs @@ -0,0 +1,19 @@ +import chalk from 'chalk'; +import * as esbuild from 'esbuild'; + +import configs from '../esbuild/config.mjs'; + +console.log( + `[${new Date().toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: false + })}] ${chalk.green('Watching...')}` +); + +const contexts = await Promise.all( + configs.map((config) => esbuild.context(config)) +); + +await Promise.any(contexts.map((ctx) => ctx.watch())); diff --git a/packages/plugin-documents/src/PluginManifest.ts b/packages/plugin-documents/src/PluginManifest.ts new file mode 100644 index 0000000..f60f3b4 --- /dev/null +++ b/packages/plugin-documents/src/PluginManifest.ts @@ -0,0 +1,10 @@ +import Manifest from '../manifest.json'; +import { CommandCallback } from '@imgly/plugin-core'; + + +export type Contributions = typeof Manifest;["contributes"] +export type CommandContributions = keyof typeof Manifest["contributes"]["commands"] +export type CommandImports = Record + +export const PluginManifest = Manifest + diff --git a/packages/plugin-documents/src/commands/__template.ts b/packages/plugin-documents/src/commands/__template.ts new file mode 100644 index 0000000..bad2b6a --- /dev/null +++ b/packages/plugin-documents/src/commands/__template.ts @@ -0,0 +1,3 @@ +// // @ts-ignore +// const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +// } \ No newline at end of file diff --git a/packages/plugin-documents/src/commands/index.ts b/packages/plugin-documents/src/commands/index.ts new file mode 100644 index 0000000..f63cad7 --- /dev/null +++ b/packages/plugin-documents/src/commands/index.ts @@ -0,0 +1,8 @@ +import { PluginContext } from "@imgly/plugin-core"; +export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const { block } = ctx.engine; + const { blockIds = block.findAllSelected() } = params; + blockIds.forEach((id: number) => { + ctx.engine.block.isValid(id) && ctx.engine.block.destroy(id) + }); +} diff --git a/packages/plugin-documents/src/index.ts b/packages/plugin-documents/src/index.ts new file mode 100644 index 0000000..f9788c6 --- /dev/null +++ b/packages/plugin-documents/src/index.ts @@ -0,0 +1,85 @@ + + +import { PluginContext, CommandDescription } from '@imgly/plugin-core'; + + +import { CommandImports, CommandContributions, PluginManifest } from './PluginManifest'; + +export interface PluginConfiguration { } + +const registerTranslation = (ctx: PluginContext, translations: { [key: string]: any } = {}) => { + ctx.i18n.setTranslations(translations) +} + + +const loadCommands = async (ctx: PluginContext, file: string) => { + const commands = await import(file) + await registerCommands(ctx, commands) +} + +const registerCommands = (ctx: PluginContext, imports: any) => { + for (const command in imports) { + const callback = imports[command as CommandContributions] + + let desc: CommandDescription = PluginManifest.contributes.commands[command as CommandContributions]; + desc ??= {}; + desc.id ??= `${PluginManifest.id}.commands.${command as string}`; + const [category, name] = (command as string).split("_") + desc.category ??= name ? category : "Commands"; + ctx.commands.registerCommand( + desc.id, + async (params: any) => await callback(ctx, params), + desc + ); + } +} + +const loadTranslation = async (ctx: PluginContext, locales: readonly string[] = ctx.i18n.locales()) => { + const translations = await Promise.all(locales.map(async (locale) => { + try { + const translations = await import(`./locale/${locale}.json`) + return { [locale]: translations.default } + } catch (e) { + // when loading of the file fails + return { [locale]: {} } + } + })) + + translations.forEach((t) => registerTranslation(ctx, t)) +} + + + +const registerPanels = async (ctx: PluginContext, panels: any) => { + for (const panel in panels) { + const id = `${PluginManifest.id}.panels.${panel}` + // ctx.ui?.unstable_registerPanel(panel, ({ builder: any }) => { + // return panels[panel](ctx, builder) + + // }) + } + +} + +const loadPanels = async (ctx: PluginContext) => { + // const panels = await import("./panels/layers") + // await registerPanels(ctx, panels) +} + + + +export const activate = async (ctx: PluginContext) => { + await loadTranslation(ctx) + await loadCommands(ctx, "./commands") + await loadPanels(ctx) +} + + +export default (ctx: PluginContext, _config: PluginConfiguration) => { + return { + async initializeUserInterface() { + await activate(ctx) + } + }; +}; + diff --git a/packages/plugin-documents/src/locale/en.json b/packages/plugin-documents/src/locale/en.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/packages/plugin-documents/src/locale/en.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/plugin-documents/src/panels/index.ts b/packages/plugin-documents/src/panels/index.ts new file mode 100644 index 0000000..0e84be7 --- /dev/null +++ b/packages/plugin-documents/src/panels/index.ts @@ -0,0 +1 @@ +// export * from "./layers"; \ No newline at end of file diff --git a/packages/plugin-documents/src/panels/layers.ts b/packages/plugin-documents/src/panels/layers.ts new file mode 100644 index 0000000..473a5d6 --- /dev/null +++ b/packages/plugin-documents/src/panels/layers.ts @@ -0,0 +1,19 @@ +// import { PluginContext } from '@imgly/plugin-core'; + + +// export const layerList = async (ctx: PluginContext, builder: any, params: any) => { +// const { block } = ctx.engine; +// const { Button, Section, Separator } = builder; +// const blockIds = block.findAllSelected(); + +// Section('layer.section', { +// title: 'Layers', +// children: () => +// blockIds.forEach((bId: number) => +// Button(bId.toString(), { +// label: block.getName(bId) || block.getUUID(bId).toString(), +// onClick: () => block.select(bId) +// })) +// }); + +// } diff --git a/packages/plugin-documents/src/utils/cesdk.ts b/packages/plugin-documents/src/utils/cesdk.ts new file mode 100644 index 0000000..d1c6def --- /dev/null +++ b/packages/plugin-documents/src/utils/cesdk.ts @@ -0,0 +1,39 @@ +import { BlockAPI } from "@cesdk/cesdk-js"; + + +export const readBlockProperty = (block: BlockAPI, id: number, propKey: string, propType?: string) => { + const blacklist = ["fill/solid/color", "fill/image/sourceSet"] + if (blacklist.includes(propKey)) return undefined; + if (!propType) propType = block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return block.getString(id, propKey); + case "float": return block.getFloat(id, propKey); + case "double": return block.getDouble(id, propKey); + case "color": return block.getColor(id, propKey); + case "bool": return block.getBool(id, propKey); + case "enum": return block.getEnum(id, propKey); + } + } catch (e) { + console.warn("Error reading property value: ", e); + } + return undefined; +}; + + +export const setBlockProperty = (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => { + if (!propType) propType = block.getPropertyType(propKey) + try { + switch (propType.toLowerCase()) { + case "string": return block.setString(id, propKey, propValue); + case "float": return block.setFloat(id, propKey, propValue); + case "double": return block.setDouble(id, propKey, propValue); + case "color": return block.setColor(id, propKey, propValue); + case "bool": return block.setBool(id, propKey, propValue); + case "enum": return block.setEnum(id, propKey, propValue); + } + } catch (e) { + console.warn("Error writing property: ", propKey, propType, propValue); + } + return undefined; +}; diff --git a/packages/plugin-documents/src/utils/computeBlockName.ts b/packages/plugin-documents/src/utils/computeBlockName.ts new file mode 100644 index 0000000..a730434 --- /dev/null +++ b/packages/plugin-documents/src/utils/computeBlockName.ts @@ -0,0 +1,8 @@ +import { BlockAPI } from "@cesdk/cesdk-js"; + +export const inferBlockName = (block: BlockAPI, blockId: number) => { + + const uuid = block.getUUID(blockId); + const name = block.getName(blockId) + return name || uuid || blockId +} \ No newline at end of file diff --git a/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts b/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts new file mode 100644 index 0000000..971075f --- /dev/null +++ b/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts @@ -0,0 +1,20 @@ +import { PluginContext } from "@imgly/plugin-core"; + +export const computeMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { + + const { block } = ctx.engine; + const bounds = blockIds.map((id: number) => { + return { + x: block.getFrameX(id), + y: block.getFrameY(id), + width: block.getFrameWidth(id), + height: block.getFrameHeight(id) + }; + }); + + const x = Math.min(...bounds.map(b => b.x)); + const y = Math.min(...bounds.map(b => b.y)); + const width = Math.max(...bounds.map(b => b.x + b.width)) - x; + const height = Math.max(...bounds.map(b => b.y + b.height)) - y; + return { x, y, width, height }; +}; diff --git a/packages/plugin-documents/src/utils/download.ts b/packages/plugin-documents/src/utils/download.ts new file mode 100644 index 0000000..f83c9c5 --- /dev/null +++ b/packages/plugin-documents/src/utils/download.ts @@ -0,0 +1,60 @@ +import CreativeEditorSDK from "@cesdk/cesdk-js"; + + + +export async function loadAsBlob(filter: string = "*") { + return new Promise((resolve, reject) => { + const upload = document.createElement("input"); + upload.setAttribute("type", "file"); + upload.setAttribute("accept", filter) + upload.setAttribute("style", "display: none") + upload.onchange = (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + const buffer = e.target?.result + if (buffer instanceof ArrayBuffer) { + const blob = new Blob([buffer]); + upload.remove() + resolve(blob) + } else { + upload.remove() + reject(new Error("Invalid buffer")) + } + } + reader.readAsArrayBuffer(file); + } + } + + upload.click() + }) +} + +export function downloadBlob(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + link.click(); + link.remove(); + URL.revokeObjectURL(url); +} +export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { + const postfix = options.mimeType.split("/")[1]; + const pageIds = options.pages ?? []; + + blobs.forEach((blob, index) => { + const pageId = pageIds[index]; + let pageName = `page-${index}`; + if (pageId) { + const name = cesdk.engine.block.getName(pageId); + pageName = name?.length ? name : pageName; + } + const filename = `${pageName}.${postfix}`; + downloadBlob(blob, filename); + }); + return Promise.resolve(); +}; + + diff --git a/packages/plugin-documents/src/utils/exportBlockAs.ts b/packages/plugin-documents/src/utils/exportBlockAs.ts new file mode 100644 index 0000000..4f5cdf7 --- /dev/null +++ b/packages/plugin-documents/src/utils/exportBlockAs.ts @@ -0,0 +1,34 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { type MimeType } from "@cesdk/cesdk-js"; + +export const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { + + const { block } = ctx.engine; + const { + blockIds = block.findAllSelected(), + mimeType = "image/png" as MimeType, + width, + height + } = params; + blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); + return await Promise.all(blockIds.map(async (bId: number) => { + switch (mimeType) { + case "application/x-cesdk": { + const str = await block.saveToString([bId]); + return new Blob([str], { type: mimeType }); + + } + case "application/json": { + const str = await block.saveToString([bId]); + const json = str.substring(4) + const decoded = atob(json) + return new Blob([decoded], { type: mimeType }); + + } + default: + return await block.export(bId, mimeType, { targetHeight: height, targetWidth: width }); + } + + })); +}; + diff --git a/packages/plugin-documents/src/utils/getTransform.ts b/packages/plugin-documents/src/utils/getTransform.ts new file mode 100644 index 0000000..6cbd969 --- /dev/null +++ b/packages/plugin-documents/src/utils/getTransform.ts @@ -0,0 +1,12 @@ +import { PluginContext } from "@imgly/plugin-core"; + +export const getTransform = (ctx: PluginContext, bId: number) => { + const { block } = ctx.engine; + return { + x: block.getPositionX(bId), + y: block.getPositionY(bId), + width: block.getFrameWidth(bId), + height: block.getFrameHeight(bId) + }; + +}; diff --git a/packages/plugin-documents/src/utils/setTransform.ts b/packages/plugin-documents/src/utils/setTransform.ts new file mode 100644 index 0000000..fa6c938 --- /dev/null +++ b/packages/plugin-documents/src/utils/setTransform.ts @@ -0,0 +1,10 @@ +import { PluginContext } from "@imgly/plugin-core"; + +export const setTransform = (ctx: PluginContext, bId: number, transform: any) => { + const { block } = ctx.engine; + const { x, y, width, height } = transform; + x && block.setPositionX(bId, x); + y && block.setPositionY(bId, y); + width && block.setWidth(bId, width); + height && block.setHeight(bId, height); +}; diff --git a/packages/plugin-documents/src/utils/turnBlockInto.ts b/packages/plugin-documents/src/utils/turnBlockInto.ts new file mode 100644 index 0000000..f87697c --- /dev/null +++ b/packages/plugin-documents/src/utils/turnBlockInto.ts @@ -0,0 +1,37 @@ +import { PluginContext } from "@imgly/plugin-core"; +import { getTransform } from "./getTransform"; +import { setTransform } from "./setTransform"; +import { createDefaultBlockByType } from "../commands/block"; + +export const turnBlockInto = (ctx: PluginContext, toType: string, id: number) => { + const { block, scene } = ctx.engine; + + const bId = createDefaultBlockByType(ctx, toType); + + if (block.hasFill(id)) { + const fId = block.duplicate(block.getFill(id)); + block.hasFill(bId) && block.setFill(bId, fId); + } + if (block.hasShape(id)) { + const sId = block.duplicate(block.getShape(id)); + block.hasShape(bId) && block.setShape(bId, sId); + } + + setTransform(ctx, bId, getTransform(ctx, id)); + + if (toType === "page") { + console.log("Turning into page"); + let pId = scene.get()!; + const cIds = block.getChildren(pId); + const sId = cIds.find((cId) => block.getType(cId) === "//ly.img.ubq/stack") + const hasStack = sId !== -1 + console.log("Has stack", hasStack); + pId = hasStack ? sId : pId; + block.appendChild(pId, bId); + } else { + const pId = block.getParent(id) ?? scene.getCurrentPage() ?? scene.get()!; + block.appendChild(pId, bId); + } + + block.destroy(id); +}; diff --git a/packages/plugin-documents/src/worker.ts b/packages/plugin-documents/src/worker.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/plugin-documents/tsconfig.json b/packages/plugin-documents/tsconfig.json new file mode 100644 index 0000000..0d7577f --- /dev/null +++ b/packages/plugin-documents/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "strict": false, + "target": "es2017", + "module": "es2020", + "lib": ["es2018", "dom"], + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "declaration": true, + "declarationDir": "types/", + "skipLibCheck": true + }, + "include": ["src/**/*", "esbuild/global.d.ts"], + "exclude": ["node_modules"] +} From e2c2fe97f346bd8af55ad06ba453adbb77abd176 Mon Sep 17 00:00:00 2001 From: Daniel Hauschildt Date: Tue, 5 Mar 2024 18:50:50 +0100 Subject: [PATCH 32/32] Wip --- examples/web/package.json | 1 + examples/web/src/App.tsx | 4 +- package.json | 3 +- packages/plugin-core/types/index.d.ts | 4 - .../plugin-design-essentials/manifest.json | 3 +- .../src/commands/__template.ts | 3 +- .../src/commands/block.ts | 34 +---- .../src/commands/debug.ts | 3 + .../src/commands/export.ts | 1 + .../src/commands/index.ts | 5 +- .../src/commands/plugins.ts | 9 ++ .../src/commands/shape.ts | 20 +++ .../src/locale/en.json | 4 +- .../src/utils/createDefaultBlockByType.ts | 30 ++++ .../src/utils/turnBlockInto.ts | 2 +- packages/plugin-documents/package.json | 3 +- .../plugin-documents/src/commands/index.ts | 143 +++++++++++++++++- packages/plugin-documents/src/index.ts | 9 +- packages/plugin-documents/src/utils/cesdk.ts | 39 ----- .../src/utils/computeBlockName.ts | 8 - .../src/utils/computeMultiSelectionBounds.ts | 20 --- .../plugin-documents/src/utils/download.ts | 60 -------- .../src/utils/exportBlockAs.ts | 34 ----- .../src/utils/getTransform.ts | 12 -- .../src/utils/setTransform.ts | 10 -- .../src/utils/turnBlockInto.ts | 37 ----- yarn.lock | 19 +++ 27 files changed, 244 insertions(+), 276 deletions(-) create mode 100644 packages/plugin-design-essentials/src/commands/shape.ts create mode 100644 packages/plugin-design-essentials/src/utils/createDefaultBlockByType.ts delete mode 100644 packages/plugin-documents/src/utils/cesdk.ts delete mode 100644 packages/plugin-documents/src/utils/computeBlockName.ts delete mode 100644 packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts delete mode 100644 packages/plugin-documents/src/utils/download.ts delete mode 100644 packages/plugin-documents/src/utils/exportBlockAs.ts delete mode 100644 packages/plugin-documents/src/utils/getTransform.ts delete mode 100644 packages/plugin-documents/src/utils/setTransform.ts delete mode 100644 packages/plugin-documents/src/utils/turnBlockInto.ts diff --git a/examples/web/package.json b/examples/web/package.json index 571a654..8d659e2 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -14,6 +14,7 @@ "@imgly/plugin-background-removal-web": "*", "@imgly/plugin-vectorizer": "*", "@imgly/plugin-design-essentials": "*", + "@imgly/plugin-documents": "*", "lodash": "^4.17.21", "react": "^18.2.0", "react-cmdk": "^1.3.9", diff --git a/examples/web/src/App.tsx b/examples/web/src/App.tsx index 464ee26..1d33543 100644 --- a/examples/web/src/App.tsx +++ b/examples/web/src/App.tsx @@ -17,6 +17,7 @@ import { downloadBlocks } from "./utils/download"; // import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web'; import VectorizerPlugin from '@imgly/plugin-vectorizer'; import DesignBatteriesPlugin from "@imgly/plugin-design-essentials"; +import DocumentPlugin from "@imgly/plugin-documents"; import { PluginContext } from "@imgly/plugin-core"; @@ -82,13 +83,14 @@ function App() { const vectorizerPlugin = VectorizerPlugin(imgly, {}) const commandsPlugin = DesignBatteriesPlugin(imgly, {}) - + const documentPlugin = DocumentPlugin(imgly, {}) // Register Plguins await Promise.all([ cesdk.addDefaultAssetSources(), cesdk.addDemoAssetSources({ sceneMode: "Design" }), cesdk.unstable_addPlugin(commandsPlugin), cesdk.unstable_addPlugin(vectorizerPlugin), + cesdk.unstable_addPlugin(documentPlugin) ]); diff --git a/package.json b/package.json index 33d059c..c776115 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,10 @@ "version": "0.0.0", "workspaces": [ "examples/web", + "packages/background-removal", "packages/plugin-core", "packages/plugin-design-essentials", - "packages/background-removal", + "packages/plugin-documents", "packages/plugin-vectorizer" ], diff --git a/packages/plugin-core/types/index.d.ts b/packages/plugin-core/types/index.d.ts index 2bd78b9..7588cca 100644 --- a/packages/plugin-core/types/index.d.ts +++ b/packages/plugin-core/types/index.d.ts @@ -1,8 +1,4 @@ -import { PluginContext } from "./plugin/PluginContext"; export { Commands, type CommandCallback, type CommandDescription } from "./plugin/Commands"; export { I18N } from "./plugin/I18n"; export { type Logger } from "./plugin/Logger"; export { PluginContext } from "./plugin/PluginContext"; -export declare function loadCommands(ctx: PluginContext, imports: any, manifest: Manifest): Promise; diff --git a/packages/plugin-design-essentials/manifest.json b/packages/plugin-design-essentials/manifest.json index 3a887eb..2c550fa 100644 --- a/packages/plugin-design-essentials/manifest.json +++ b/packages/plugin-design-essentials/manifest.json @@ -78,7 +78,6 @@ "syncBlockAppearance": { "category": "sync" } - }, - "i18n": {} + } } } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/__template.ts b/packages/plugin-design-essentials/src/commands/__template.ts index bad2b6a..ca26232 100644 --- a/packages/plugin-design-essentials/src/commands/__template.ts +++ b/packages/plugin-design-essentials/src/commands/__template.ts @@ -1,3 +1,4 @@ // // @ts-ignore -// const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { +// export const __template = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + // } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/block.ts b/packages/plugin-design-essentials/src/commands/block.ts index 5f79fc0..63663b4 100644 --- a/packages/plugin-design-essentials/src/commands/block.ts +++ b/packages/plugin-design-essentials/src/commands/block.ts @@ -1,7 +1,7 @@ import { PluginContext } from "@imgly/plugin-core"; -import { ary, create } from "lodash"; import { setTransform } from "../utils/setTransform"; -import { turnBlockInto } from "../utils/turnBlockInto"; +import { createDefaultBlockByType } from "../utils/createDefaultBlockByType"; + export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; @@ -116,34 +116,4 @@ export const blockCreateText = async (ctx: PluginContext, _params: { blockIds?: -// UTILS - -export const createDefaultBlockByType = (ctx: PluginContext, type: string) => { - const { block } = ctx.engine; - switch (type) { - - case "graphic": { - const bId = block.create("graphic") - const sId = block.createShape("rect") - const fId = block.createFill("//ly.img.ubq/fill/image") - block.setShape(bId, sId) - block.setFill(bId, fId) - block.setName(bId, type.toUpperCase()) - return bId - } - case "page": { - const bId = block.create("page") - block.setName(bId, type.toUpperCase()) - return bId - } - case "text": { - const bId = block.create("graphic") - block.replaceText(bId, "Hello World") - block.setName(bId, type.toUpperCase()) - return bId - } - default: throw new Error("Invalid type") - } -} - diff --git a/packages/plugin-design-essentials/src/commands/debug.ts b/packages/plugin-design-essentials/src/commands/debug.ts index 4c19623..68143fc 100644 --- a/packages/plugin-design-essentials/src/commands/debug.ts +++ b/packages/plugin-design-essentials/src/commands/debug.ts @@ -1,6 +1,7 @@ import { PluginContext } from "@imgly/plugin-core"; import { readBlockProperty } from "../utils/cesdk"; + export const debugLogBlockProperties = async (ctx: PluginContext, params: { blockIds: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected() } = params; @@ -18,6 +19,8 @@ export const debugLogBlockProperties = async (ctx: PluginContext, params: { bloc }) } + + export const debugLogBlockCrop = (ctx: PluginContext, params: { blockIds?: number[] }) => { const { block } = ctx.engine; const { blockIds = block.findAllSelected() } = params; diff --git a/packages/plugin-design-essentials/src/commands/export.ts b/packages/plugin-design-essentials/src/commands/export.ts index 733ec19..fe0abd8 100644 --- a/packages/plugin-design-essentials/src/commands/export.ts +++ b/packages/plugin-design-essentials/src/commands/export.ts @@ -5,6 +5,7 @@ import { exportBlockAs } from "../utils/exportBlockAs"; + export const exportPngToClipboard = async (ctx: PluginContext, params: { blockIds?: number[] }) => { const items = (await exportBlockAs(ctx, { ...params, mimeType: "image/png" as MimeType })).map((blob) => { return new ClipboardItem({ diff --git a/packages/plugin-design-essentials/src/commands/index.ts b/packages/plugin-design-essentials/src/commands/index.ts index 8b05885..e2b8d4d 100644 --- a/packages/plugin-design-essentials/src/commands/index.ts +++ b/packages/plugin-design-essentials/src/commands/index.ts @@ -12,4 +12,7 @@ export * from "./i18n"; export * from "./panels"; export * from "./turnInto"; -export * from "./replicate.io"; \ No newline at end of file +export * from "./replicate.io"; + +// for convenience I splitted the files into smaller files +export * from "./shape"; \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/plugins.ts b/packages/plugin-design-essentials/src/commands/plugins.ts index 1947e37..4207616 100644 --- a/packages/plugin-design-essentials/src/commands/plugins.ts +++ b/packages/plugin-design-essentials/src/commands/plugins.ts @@ -8,6 +8,8 @@ export const pluginRegisterCustomPanel = async (ctx: PluginContext, _params: { b console.log('Apps disposer called'); }; }); + + ui?.openPanel('ly.img.foo'); } @@ -15,4 +17,11 @@ export const pluginRegisterCustomPanel = async (ctx: PluginContext, _params: { b export const pluginOpenCustomPanel = async (ctx: PluginContext, _params: { blockIds?: number[] }) => { const { ui } = ctx; ui?.openPanel('ly.img.foo'); +} + + + +export const command = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + + } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/commands/shape.ts b/packages/plugin-design-essentials/src/commands/shape.ts new file mode 100644 index 0000000..ea08159 --- /dev/null +++ b/packages/plugin-design-essentials/src/commands/shape.ts @@ -0,0 +1,20 @@ +import { PluginContext } from "@imgly/plugin-core"; + + +// each export must be a command +export const shapeSetEllipse = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const {block} = ctx.engine; + const {blockIds = block.findAllSelected()} = params; + + + blockIds.forEach((bId: number) => { + if (!block.hasShape(bId)) return; + const sId = block.getShape(bId); + block.isValid(sId) && block.destroy(sId); + + const eId = block.createShape("//ly.img.ubq/shape/ellipse"); + block.setShape(bId, eId); + }) + + +} \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/locale/en.json b/packages/plugin-design-essentials/src/locale/en.json index 01a396f..8c8f11f 100644 --- a/packages/plugin-design-essentials/src/locale/en.json +++ b/packages/plugin-design-essentials/src/locale/en.json @@ -1,7 +1,6 @@ { "design-batteries.commands.blockBringForward": "Bring Block Forward", "design-batteries.commands.blockBringToFront": "Bring Block to Front", - "design-batteries.commands.blockCreateGraphic": "Create Graphic Block", "design-batteries.commands.blockCreateText": "Create Text Block", "design-batteries.commands.blockDelete": "Delete Block", "design-batteries.commands.blockDuplicate": "Duplicate Block", @@ -50,5 +49,6 @@ "design-batteries.commands.productSetInstagram": "Set Instagram Product", "design-batteries.commands.replicateSDXL": "Replicate SDXL", "design-batteries.commands.syncBlockAppearance": "Sync Block Appearance", - "design-batteries.commands.syncBlocks": "Sync Blocks" + "design-batteries.commands.syncBlocks": "Sync Blocks", + "design-batteries.commands.shapeSetEllipse": "Set Ellipse Shape" } \ No newline at end of file diff --git a/packages/plugin-design-essentials/src/utils/createDefaultBlockByType.ts b/packages/plugin-design-essentials/src/utils/createDefaultBlockByType.ts new file mode 100644 index 0000000..88ca0f4 --- /dev/null +++ b/packages/plugin-design-essentials/src/utils/createDefaultBlockByType.ts @@ -0,0 +1,30 @@ +import { PluginContext } from "@imgly/plugin-core"; + +// UTILS +export const createDefaultBlockByType = (ctx: PluginContext, type: string) => { + const { block } = ctx.engine; + switch (type) { + + case "graphic": { + const bId = block.create("graphic"); + const sId = block.createShape("rect"); + const fId = block.createFill("//ly.img.ubq/fill/image"); + block.setShape(bId, sId); + block.setFill(bId, fId); + block.setName(bId, type.toUpperCase()); + return bId; + } + case "page": { + const bId = block.create("page"); + block.setName(bId, type.toUpperCase()); + return bId; + } + case "text": { + const bId = block.create("graphic"); + block.replaceText(bId, "Hello World"); + block.setName(bId, type.toUpperCase()); + return bId; + } + default: throw new Error("Invalid type"); + } +}; diff --git a/packages/plugin-design-essentials/src/utils/turnBlockInto.ts b/packages/plugin-design-essentials/src/utils/turnBlockInto.ts index f87697c..5cb81be 100644 --- a/packages/plugin-design-essentials/src/utils/turnBlockInto.ts +++ b/packages/plugin-design-essentials/src/utils/turnBlockInto.ts @@ -1,7 +1,7 @@ import { PluginContext } from "@imgly/plugin-core"; import { getTransform } from "./getTransform"; import { setTransform } from "./setTransform"; -import { createDefaultBlockByType } from "../commands/block"; +import { createDefaultBlockByType } from "../utils/createDefaultBlockByType"; export const turnBlockInto = (ctx: PluginContext, toType: string, id: number) => { const { block, scene } = ctx.engine; diff --git a/packages/plugin-documents/package.json b/packages/plugin-documents/package.json index 47188b1..0efdba4 100644 --- a/packages/plugin-documents/package.json +++ b/packages/plugin-documents/package.json @@ -62,6 +62,7 @@ }, "dependencies": { "@imgly/plugin-core": "*", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "yjs": "^13.6.14" } } diff --git a/packages/plugin-documents/src/commands/index.ts b/packages/plugin-documents/src/commands/index.ts index f63cad7..7d9a23a 100644 --- a/packages/plugin-documents/src/commands/index.ts +++ b/packages/plugin-documents/src/commands/index.ts @@ -1,8 +1,139 @@ +"use strict"; + import { PluginContext } from "@imgly/plugin-core"; -export const blockDelete = async (ctx: PluginContext, params: { blockIds?: number[] }) => { - const { block } = ctx.engine; - const { blockIds = block.findAllSelected() } = params; - blockIds.forEach((id: number) => { - ctx.engine.block.isValid(id) && ctx.engine.block.destroy(id) - }); + +import { isEqual } from 'lodash' + +import * as Y from 'yjs' + +const documents = new Map() + +type YJson = Y.Map + +class Transform extends Y.Map { + constructor() { + super() + } + set x(value: number) { + this.set("x", value) + } + set y(value: number) { + this.set("y", value) + } } + + +class DesignDocument { + doc: Y.Doc; + properties: YJson; + + // shape + // stroke + // style + attachments: Blob[] // images, files, etc + + + constructor() { + this.doc = new Y.Doc({ + meta: { + "content-type": "application/json" + } + }) + this.properties = this.doc.getMap('properties'); + this.properties.set("transform", new Transform()) + this.opacity = 1 + console.log("guid", this.doc.guid) + } + + transact(fn: () => void) { + this.doc.transact(fn) + } + + set opacity(value: number) { + // if (this.opacity === value) return + this.properties.set("opacity", value) + } + + // getter + get opacity(): number | undefined { + return this.properties.get("opacity") + } + + get transform(): Transform | undefined { + return this.properties.get("transform") + } + set transform(value: { x?: number, y?: number }) { + value.x && (this.transform.x = value.x) + value.y && (this.transform.y = value.y) + } +} + +export const documentDemo = async (ctx: PluginContext, params: { blockIds?: number[] }) => { + const design = new DesignDocument() + const design2 = new DesignDocument() + + { + console.log(design.doc.meta, design2.doc.meta) + const hash = await sha256(Y.encodeStateVector(design.doc)) + const hash2 = await sha256(Y.encodeStateVector(design2.doc)) + console.log(hash, hash2) + + } + + + // sync https://docs.yjs.dev/api/document-updates + design.doc.on('update', (update, origin, doc) => { + //call get state vector from others + const stateVector2 = Y.encodeStateVector(design2.doc) + const hash = sha256(stateVector2) + // encode state as update + const diff12 = Y.encodeStateAsUpdate(design.doc, stateVector2) + // send to other and apply + Y.applyUpdate(design2.doc, diff12) + }) + + design2.doc.on('update', (update, origin, doc) => { + const stateVector1 = Y.encodeStateVector(design.doc) + const diff21 = Y.encodeStateAsUpdate(design2.doc, stateVector1) + Y.applyUpdate(design.doc, diff21) + }) + + + + const eventCallback = (events, transaction) => { + events.forEach((event: Y.YMapEvent) => { + const path = event.path + event.keysChanged.forEach(key => { + const newData = event.keys.get(key) + const oldValue = newData?.oldValue + const newValue = event.target.get(key) + const hasChanged = !isEqual(oldValue, newValue) + if (hasChanged) { + const fullPath = new Array(path) + fullPath.push(key) + console.log(event.target.doc.guid, fullPath.join("."), oldValue, newValue) + } + }) + + + }) + } + design.properties.observeDeep(eventCallback) + design2.properties.observeDeep(eventCallback) + + design.opacity = 0.5 + design2.opacity = 0.95 + + console.log(design.opacity) + console.log(design2.opacity) + + const hash = await sha256(Y.encodeStateVector(design.doc)) + const hash2 = await sha256(Y.encodeStateVector(design2.doc)) + console.log(hash, hash2) +} + + +async function sha256(data: Uint8Array) { + const hash = await window.crypto.subtle.digest('SHA-256', data); + return Array.from(new Uint8Array(hash)).map(b => b.toString(16).padStart(2, '0')).join(''); +} \ No newline at end of file diff --git a/packages/plugin-documents/src/index.ts b/packages/plugin-documents/src/index.ts index f9788c6..d728fe9 100644 --- a/packages/plugin-documents/src/index.ts +++ b/packages/plugin-documents/src/index.ts @@ -12,9 +12,9 @@ const registerTranslation = (ctx: PluginContext, translations: { [key: string]: } -const loadCommands = async (ctx: PluginContext, file: string) => { - const commands = await import(file) - await registerCommands(ctx, commands) +const loadCommands = async (ctx: PluginContext, imports: any) => { + + await registerCommands(ctx, imports) } const registerCommands = (ctx: PluginContext, imports: any) => { @@ -26,6 +26,7 @@ const registerCommands = (ctx: PluginContext, imports: any) => { desc.id ??= `${PluginManifest.id}.commands.${command as string}`; const [category, name] = (command as string).split("_") desc.category ??= name ? category : "Commands"; + console.log("registerCommand", command as string) ctx.commands.registerCommand( desc.id, async (params: any) => await callback(ctx, params), @@ -70,7 +71,7 @@ const loadPanels = async (ctx: PluginContext) => { export const activate = async (ctx: PluginContext) => { await loadTranslation(ctx) - await loadCommands(ctx, "./commands") + await loadCommands(ctx, await import('./commands')) await loadPanels(ctx) } diff --git a/packages/plugin-documents/src/utils/cesdk.ts b/packages/plugin-documents/src/utils/cesdk.ts deleted file mode 100644 index d1c6def..0000000 --- a/packages/plugin-documents/src/utils/cesdk.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { BlockAPI } from "@cesdk/cesdk-js"; - - -export const readBlockProperty = (block: BlockAPI, id: number, propKey: string, propType?: string) => { - const blacklist = ["fill/solid/color", "fill/image/sourceSet"] - if (blacklist.includes(propKey)) return undefined; - if (!propType) propType = block.getPropertyType(propKey) - try { - switch (propType.toLowerCase()) { - case "string": return block.getString(id, propKey); - case "float": return block.getFloat(id, propKey); - case "double": return block.getDouble(id, propKey); - case "color": return block.getColor(id, propKey); - case "bool": return block.getBool(id, propKey); - case "enum": return block.getEnum(id, propKey); - } - } catch (e) { - console.warn("Error reading property value: ", e); - } - return undefined; -}; - - -export const setBlockProperty = (block: BlockAPI, id: number, propKey: string, propValue: any, propType?: string) => { - if (!propType) propType = block.getPropertyType(propKey) - try { - switch (propType.toLowerCase()) { - case "string": return block.setString(id, propKey, propValue); - case "float": return block.setFloat(id, propKey, propValue); - case "double": return block.setDouble(id, propKey, propValue); - case "color": return block.setColor(id, propKey, propValue); - case "bool": return block.setBool(id, propKey, propValue); - case "enum": return block.setEnum(id, propKey, propValue); - } - } catch (e) { - console.warn("Error writing property: ", propKey, propType, propValue); - } - return undefined; -}; diff --git a/packages/plugin-documents/src/utils/computeBlockName.ts b/packages/plugin-documents/src/utils/computeBlockName.ts deleted file mode 100644 index a730434..0000000 --- a/packages/plugin-documents/src/utils/computeBlockName.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BlockAPI } from "@cesdk/cesdk-js"; - -export const inferBlockName = (block: BlockAPI, blockId: number) => { - - const uuid = block.getUUID(blockId); - const name = block.getName(blockId) - return name || uuid || blockId -} \ No newline at end of file diff --git a/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts b/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts deleted file mode 100644 index 971075f..0000000 --- a/packages/plugin-documents/src/utils/computeMultiSelectionBounds.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { PluginContext } from "@imgly/plugin-core"; - -export const computeMultiSelectionBounds = (ctx: PluginContext, blockIds: number[]) => { - - const { block } = ctx.engine; - const bounds = blockIds.map((id: number) => { - return { - x: block.getFrameX(id), - y: block.getFrameY(id), - width: block.getFrameWidth(id), - height: block.getFrameHeight(id) - }; - }); - - const x = Math.min(...bounds.map(b => b.x)); - const y = Math.min(...bounds.map(b => b.y)); - const width = Math.max(...bounds.map(b => b.x + b.width)) - x; - const height = Math.max(...bounds.map(b => b.y + b.height)) - y; - return { x, y, width, height }; -}; diff --git a/packages/plugin-documents/src/utils/download.ts b/packages/plugin-documents/src/utils/download.ts deleted file mode 100644 index f83c9c5..0000000 --- a/packages/plugin-documents/src/utils/download.ts +++ /dev/null @@ -1,60 +0,0 @@ -import CreativeEditorSDK from "@cesdk/cesdk-js"; - - - -export async function loadAsBlob(filter: string = "*") { - return new Promise((resolve, reject) => { - const upload = document.createElement("input"); - upload.setAttribute("type", "file"); - upload.setAttribute("accept", filter) - upload.setAttribute("style", "display: none") - upload.onchange = (e) => { - const file = (e.target as HTMLInputElement).files?.[0]; - if (file) { - const reader = new FileReader(); - reader.onload = (e) => { - const buffer = e.target?.result - if (buffer instanceof ArrayBuffer) { - const blob = new Blob([buffer]); - upload.remove() - resolve(blob) - } else { - upload.remove() - reject(new Error("Invalid buffer")) - } - } - reader.readAsArrayBuffer(file); - } - } - - upload.click() - }) -} - -export function downloadBlob(blob: Blob, filename: string) { - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = filename; - link.click(); - link.remove(); - URL.revokeObjectURL(url); -} -export const downloadBlocks = (cesdk: CreativeEditorSDK, blobs: Blob[], options: { mimeType: string; pages?: number[]; }) => { - const postfix = options.mimeType.split("/")[1]; - const pageIds = options.pages ?? []; - - blobs.forEach((blob, index) => { - const pageId = pageIds[index]; - let pageName = `page-${index}`; - if (pageId) { - const name = cesdk.engine.block.getName(pageId); - pageName = name?.length ? name : pageName; - } - const filename = `${pageName}.${postfix}`; - downloadBlob(blob, filename); - }); - return Promise.resolve(); -}; - - diff --git a/packages/plugin-documents/src/utils/exportBlockAs.ts b/packages/plugin-documents/src/utils/exportBlockAs.ts deleted file mode 100644 index 4f5cdf7..0000000 --- a/packages/plugin-documents/src/utils/exportBlockAs.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { PluginContext } from "@imgly/plugin-core"; -import { type MimeType } from "@cesdk/cesdk-js"; - -export const exportBlockAs = async (ctx: PluginContext, params: { blockIds?: number[], mimeType?: MimeType | 'application/x-cesdk' | 'application/json', width?: number, height?: number }) => { - - const { block } = ctx.engine; - const { - blockIds = block.findAllSelected(), - mimeType = "image/png" as MimeType, - width, - height - } = params; - blockIds.length === 0 && blockIds.push(ctx.engine.scene.get()!); - return await Promise.all(blockIds.map(async (bId: number) => { - switch (mimeType) { - case "application/x-cesdk": { - const str = await block.saveToString([bId]); - return new Blob([str], { type: mimeType }); - - } - case "application/json": { - const str = await block.saveToString([bId]); - const json = str.substring(4) - const decoded = atob(json) - return new Blob([decoded], { type: mimeType }); - - } - default: - return await block.export(bId, mimeType, { targetHeight: height, targetWidth: width }); - } - - })); -}; - diff --git a/packages/plugin-documents/src/utils/getTransform.ts b/packages/plugin-documents/src/utils/getTransform.ts deleted file mode 100644 index 6cbd969..0000000 --- a/packages/plugin-documents/src/utils/getTransform.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PluginContext } from "@imgly/plugin-core"; - -export const getTransform = (ctx: PluginContext, bId: number) => { - const { block } = ctx.engine; - return { - x: block.getPositionX(bId), - y: block.getPositionY(bId), - width: block.getFrameWidth(bId), - height: block.getFrameHeight(bId) - }; - -}; diff --git a/packages/plugin-documents/src/utils/setTransform.ts b/packages/plugin-documents/src/utils/setTransform.ts deleted file mode 100644 index fa6c938..0000000 --- a/packages/plugin-documents/src/utils/setTransform.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PluginContext } from "@imgly/plugin-core"; - -export const setTransform = (ctx: PluginContext, bId: number, transform: any) => { - const { block } = ctx.engine; - const { x, y, width, height } = transform; - x && block.setPositionX(bId, x); - y && block.setPositionY(bId, y); - width && block.setWidth(bId, width); - height && block.setHeight(bId, height); -}; diff --git a/packages/plugin-documents/src/utils/turnBlockInto.ts b/packages/plugin-documents/src/utils/turnBlockInto.ts deleted file mode 100644 index f87697c..0000000 --- a/packages/plugin-documents/src/utils/turnBlockInto.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { PluginContext } from "@imgly/plugin-core"; -import { getTransform } from "./getTransform"; -import { setTransform } from "./setTransform"; -import { createDefaultBlockByType } from "../commands/block"; - -export const turnBlockInto = (ctx: PluginContext, toType: string, id: number) => { - const { block, scene } = ctx.engine; - - const bId = createDefaultBlockByType(ctx, toType); - - if (block.hasFill(id)) { - const fId = block.duplicate(block.getFill(id)); - block.hasFill(bId) && block.setFill(bId, fId); - } - if (block.hasShape(id)) { - const sId = block.duplicate(block.getShape(id)); - block.hasShape(bId) && block.setShape(bId, sId); - } - - setTransform(ctx, bId, getTransform(ctx, id)); - - if (toType === "page") { - console.log("Turning into page"); - let pId = scene.get()!; - const cIds = block.getChildren(pId); - const sId = cIds.find((cId) => block.getType(cId) === "//ly.img.ubq/stack") - const hasStack = sId !== -1 - console.log("Has stack", hasStack); - pId = hasStack ? sId : pId; - block.appendChild(pId, bId); - } else { - const pId = block.getParent(id) ?? scene.getCurrentPage() ?? scene.get()!; - block.appendChild(pId, bId); - } - - block.destroy(id); -}; diff --git a/yarn.lock b/yarn.lock index 88eb74c..4859a50 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2929,6 +2929,11 @@ isexe@^3.1.1: resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== +isomorphic.js@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz#13eecf36f2dba53e85d355e11bf9d4208c6f7f88" + integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw== + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -3055,6 +3060,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lib0@^0.2.86: + version "0.2.90" + resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.90.tgz#5187b921291dcbc26c7bcf6ac9de79a1437dc429" + integrity sha512-iQmk+fThPq1ZTD2cFUu8xN6JLp9gFWnjs8auR6hmI6QQXoy6sSEh85uKcdkqpuEnkhhwQm4GSlKHOYfSCVp0Mw== + dependencies: + isomorphic.js "^0.2.4" + libnpmaccess@^8.0.1: version "8.0.2" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-8.0.2.tgz#a13a72fd5b71a1063ea54973fa56d61ec38f718f" @@ -4985,6 +4997,13 @@ yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" +yjs@^13.6.14: + version "13.6.14" + resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.14.tgz#9326dfa03d1be3fb9af9ef7e41de4bfc78849a9f" + integrity sha512-D+7KcUr0j+vBCUSKXXEWfA+bG4UQBviAwP3gYBhkstkgwy5+8diOPMx0iqLIOxNo/HxaREUimZRxqHGAHCL2BQ== + dependencies: + lib0 "^0.2.86" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"