From ffca8c46e6f2ce6ff3ba35aee539fd07c84b6d59 Mon Sep 17 00:00:00 2001 From: dependentmadani Date: Mon, 8 Jul 2024 15:39:40 +0100 Subject: [PATCH 1/5] feat(generics): the use of generics in Image object --- src/index.ts | 52 +++++++++++++++++++++++----------------------- src/types/types.ts | 10 +++++++++ src/ui.ts | 4 ++-- src/uploader.ts | 20 +++++++++--------- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0c367629..28e4715f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,12 +38,12 @@ import Ui from './ui'; import Uploader from './uploader'; import { IconAddBorder, IconStretch, IconAddBackground, IconPicture } from '@codexteam/icons'; -import { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig } from './types/types'; +import { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, FileObjectData } from './types/types'; -type ImageToolConstructorOptions = BlockToolConstructorOptions +type ImageToolConstructorOptions< CustomActions = {},AdditionalUploadResponse = {}> = BlockToolConstructorOptions, ImageConfig> -export default class ImageTool implements BlockTool { +export default class ImageTool implements BlockTool { /** * Editor.js API instance */ @@ -67,17 +67,17 @@ export default class ImageTool implements BlockTool { /** * Uploader module instance */ - private uploader: Uploader; + private uploader: Uploader; /** * UI module instance */ - private ui: Ui; + private ui: Ui; /** * Stores current block data internally */ - private _data: ImageToolData; + private _data: ImageToolData; /** * @param {object} tool - tool properties got from editor.js @@ -87,7 +87,7 @@ export default class ImageTool implements BlockTool { * @param {boolean} tool.readOnly - read-only mode flag * @param {BlockAPI|{}} tool.block - current Block API */ - constructor({ data, config, api, readOnly, block }: ImageToolConstructorOptions) { + constructor({ data, config, api, readOnly, block }: ImageToolConstructorOptions) { this.api = api; this.readOnly = readOnly; this.block = block; @@ -110,16 +110,16 @@ export default class ImageTool implements BlockTool { /** * Module for file uploading */ - this.uploader = new Uploader({ + this.uploader = new Uploader({ config: this.config, - onUpload: (response) => this.onUpload(response), + onUpload: (response: UploadResponseFormat) => this.onUpload(response), onError: (error) => this.uploadingFailed(error), }); /** * Module for working with UI */ - this.ui = new Ui({ + this.ui = new Ui({ api, config: this.config, onSelectFile: () => { @@ -143,7 +143,7 @@ export default class ImageTool implements BlockTool { file: { url: '', }, - }; + } as ImageToolData; this.data = data; } /** @@ -215,7 +215,7 @@ export default class ImageTool implements BlockTool { * @returns {boolean} false if saved data is not correct, otherwise true * @public */ - validate(savedData: ImageToolData): boolean { + validate(savedData: ImageToolData): boolean { return !!savedData.file.url; } @@ -226,7 +226,7 @@ export default class ImageTool implements BlockTool { * * @returns {ImageToolData} */ - save(): ImageToolData { + save(): ImageToolData { const caption = this.ui.nodes.caption; this._data.caption = caption.innerHTML; @@ -251,7 +251,7 @@ export default class ImageTool implements BlockTool { label: this.api.i18n.t(tune.title), name: tune.name, toggle: tune.toggle, - isActive: this.data[tune.name as keyof ImageToolData] as boolean, + isActive: this.data[tune.name as keyof ImageToolData] as boolean, onActivate: () => { /**If it'a user defined tune, execute it's callback stored in action property */ if (typeof tune.action === 'function') { @@ -259,7 +259,7 @@ export default class ImageTool implements BlockTool { return; } - this.tuneToggled(tune.name as keyof ImageToolData); + this.tuneToggled(tune.name as keyof ImageToolData); }, })); } @@ -360,16 +360,16 @@ export default class ImageTool implements BlockTool { * * @param {ImageToolData} data - data in Image Tool format */ - set data(data: ImageToolData) { + set data(data: ImageToolData) { this.image = data.file; this._data.caption = data.caption || ''; this.ui.fillCaption(this._data.caption); ImageTool.tunes.forEach(({ name: tune }) => { - const value = typeof data[tune as keyof ImageToolData] !== 'undefined' ? data[tune as keyof ImageToolData] === true || data[tune as keyof ImageToolData] === 'true' : false; + const value = typeof data[tune as keyof ImageToolData] !== 'undefined' ? data[tune as keyof ImageToolData] === true || data[tune as keyof ImageToolData] === 'true' : false; - this.setTune(tune as keyof ImageToolData, value); + this.setTune(tune as keyof ImageToolData, value); }); } @@ -380,7 +380,7 @@ export default class ImageTool implements BlockTool { * * @returns {ImageToolData} */ - get data(): ImageToolData { + get data(): ImageToolData { return this._data; } @@ -391,8 +391,8 @@ export default class ImageTool implements BlockTool { * * @param {object} file - uploaded file data */ - set image(file: { url: string } | undefined) { - this._data.file = file || {url: ''}; + set image(file: FileObjectData | undefined) { + this._data.file = file || ({url: ''} as FileObjectData); if (file && file.url) { this.ui.fillImage(file.url); @@ -407,7 +407,7 @@ export default class ImageTool implements BlockTool { * @param {UploadResponseFormat} response - uploading server response * @returns {void} */ - onUpload(response: UploadResponseFormat): void { + onUpload(response: UploadResponseFormat): void { if (response.success && response.file) { this.image = response.file; } else { @@ -440,9 +440,9 @@ export default class ImageTool implements BlockTool { * @param {string} tuneName - tune that has been clicked * @returns {void} */ - tuneToggled(tuneName: keyof ImageToolData): void { + tuneToggled(tuneName: keyof ImageToolData): void { // inverse tune state - this.setTune(tuneName, !this._data[tuneName as keyof ImageToolData]); + this.setTune(tuneName, !this._data[tuneName as keyof ImageToolData]); } /** @@ -452,10 +452,10 @@ export default class ImageTool implements BlockTool { * @param {boolean} value - tune state * @returns {void} */ - setTune(tuneName: keyof ImageToolData, value: boolean): void { + setTune(tuneName: keyof ImageToolData, value: boolean): void { (this._data[tuneName] as boolean) = value; - this.ui.applyTune(tuneName, value); + this.ui.applyTune(String(tuneName), value); if (tuneName === 'stretched') { /** * Wait until the API is ready diff --git a/src/types/types.ts b/src/types/types.ts index 2c77a2e7..f34f2547 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -5,6 +5,16 @@ export interface UploadOptions { onPreview: (src: string) => void }; +/** + * Represents the format of a file object data with the additional data. + */ +export type FileObjectData = { + /** + * The URL of the file. + */ + url: string; +} & AdditionalData; + /** * User configuration of Image block tunes. Allows to add custom tunes through the config */ diff --git a/src/ui.ts b/src/ui.ts index 402e622c..e873f7b4 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -86,7 +86,7 @@ interface ConstructorParams { * - show/hide preview * - apply tune view */ -export default class Ui { +export default class Ui { /** * API instance for Editor.js. */ @@ -180,7 +180,7 @@ public nodes: Nodes; * @param {ImageToolData} toolData - saved tool data * @returns {Element} */ - render(toolData: ImageToolData): HTMLElement { + render(toolData: ImageToolData): HTMLElement { if (!toolData.file || Object.keys(toolData.file).length === 0) { this.toggleStatus(UiState.Empty); } else { diff --git a/src/uploader.ts b/src/uploader.ts index 3f456ba9..3be5960f 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -6,7 +6,7 @@ import { UploadResponseFormat, ImageConfig } from './types/types'; /** * Params interface for Uploader constructor */ -interface UploaderParams { +interface UploaderParams { /** * Configuration for the uploader */ @@ -16,7 +16,7 @@ interface UploaderParams { * @param response: Callback function for successful upload * @returns void */ - onUpload: (response: UploadResponseFormat) => void; + onUpload: (response: UploadResponseFormat) => void; /** * * @param error : error type @@ -31,9 +31,9 @@ interface UploaderParams { * 2. Upload by pasting URL * 3. Upload by pasting file from Clipboard or by Drag'n'Drop */ -export default class Uploader { +export default class Uploader { private config: ImageConfig; - private onUpload: (response: UploadResponseFormat) => void; + private onUpload: (response: UploadResponseFormat) => void; private onError: (error: any) => void; /** * @param {object} params - uploader module params @@ -41,7 +41,7 @@ export default class Uploader { * @param {Function} params.onUpload - one callback for all uploading (file, url, d-n-d, pasting) * @param {Function} params.onError - callback for uploading errors */ - constructor({ config, onUpload, onError }: UploaderParams) { + constructor({ config, onUpload, onError }: UploaderParams) { this.config = config; this.onUpload = onUpload; this.onError = onError; @@ -67,7 +67,7 @@ export default class Uploader { * Custom uploading * or default uploading */ - let upload: Promise; + let upload: Promise>; // custom uploading if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') { @@ -81,7 +81,7 @@ export default class Uploader { console.warn('Custom uploader method uploadByFile should return a Promise'); } - return customUpload as Promise; + return customUpload as Promise>; }); // default uploading @@ -99,7 +99,7 @@ export default class Uploader { } upload.then((response) => { - this.onUpload(response); + this.onUpload(response as UploadResponseFormat); }).catch((error) => { this.onError(error); }); @@ -137,7 +137,7 @@ export default class Uploader { }).then((response: any) => response.body); } - upload.then((response: UploadResponseFormat) => { + upload.then((response: UploadResponseFormat) => { this.onUpload(response); }).catch((error: any) => { this.onError(error); @@ -198,7 +198,7 @@ export default class Uploader { } upload.then((response) => { - this.onUpload(response); + this.onUpload(response as UploadResponseFormat); }).catch((error) => { this.onError(error); }); From 10336e0c55152ab1220fb42068a68fcb38f5caee Mon Sep 17 00:00:00 2001 From: dependentmadani Date: Wed, 10 Jul 2024 11:18:58 +0100 Subject: [PATCH 2/5] update: the use of a type in some interfaces --- src/types/types.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index e6aa8d64..4f16c2d7 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -8,12 +8,12 @@ export interface UploadOptions { /** * Represents the format of a file object data with the additional data. */ -export type FileObjectData = { +export type FileObjectData = { /** * The URL of the file. */ url: string; -} & AdditionalData; +} & AdditionalFileData; /** * User configuration of Image block tunes. Allows to add custom tunes through the config @@ -59,12 +59,7 @@ export interface UploadResponseFormat { * 'url' is required, * also can contain any additional data that will be saved and passed back */ - file: { - /** - * The URL of the uploaded image. - */ - url: string; - } & AdditionalFileData; + file: FileObjectData; } /** @@ -95,12 +90,7 @@ export type ImageToolData = { * Object containing the URL of the image file. * Also can contain any additional data. */ - file: { - /** - * The URL of the image. - */ - url: string; - } & AdditionalFileData; + file: FileObjectData; } & (Actions extends Record ? Actions : {}); /** From da9b4030c4430641c4ccb578d8545112c787050c Mon Sep 17 00:00:00 2001 From: dependentmadani Date: Thu, 11 Jul 2024 00:38:18 +0100 Subject: [PATCH 3/5] fix(headers): additionalRequestHeaders is now sent in the requests --- src/types/codexteam__ajax.d.ts | 2 +- src/uploader.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types/codexteam__ajax.d.ts b/src/types/codexteam__ajax.d.ts index 63c45a52..b47e6940 100644 --- a/src/types/codexteam__ajax.d.ts +++ b/src/types/codexteam__ajax.d.ts @@ -3,7 +3,7 @@ declare module '@codexteam/ajax' { url?: string; data?: any; accept?: string; - headers?: Headers; + headers?: Record | Headers; beforeSend?: (files: File[]) => void; fieldName?: string; type?: string; diff --git a/src/uploader.ts b/src/uploader.ts index 3be5960f..5fd814c9 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -90,7 +90,7 @@ export default class Uploader { url: this.config.endpoints.byFile, data: this.config.additionalRequestData, accept: this.config.types, - headers: new Headers(this.config.additionalRequestHeaders as Record), + headers: this.config.additionalRequestHeaders as Record, beforeSend: (files: File[]) => { preparePreview(files[0]); }, @@ -98,7 +98,7 @@ export default class Uploader { }).then((response: any) => response.body); } - upload.then((response) => { + upload.then((response) => { this.onUpload(response as UploadResponseFormat); }).catch((error) => { this.onError(error); @@ -133,7 +133,7 @@ export default class Uploader { url: url, }, this.config.additionalRequestData), type: ajax.contentType.JSON, - headers: new Headers(this.config.additionalRequestHeaders as Record), + headers: this.config.additionalRequestHeaders as Record, }).then((response: any) => response.body); } @@ -193,7 +193,7 @@ export default class Uploader { url: this.config.endpoints.byFile, data: formData, type: ajax.contentType.JSON, - headers: new Headers(this.config.additionalRequestHeaders as Record), + headers: this.config.additionalRequestHeaders as Record, }).then((response: any) => response.body); } From 66e734ba9ad09a8407fd0aed50b5fe809496b13a Mon Sep 17 00:00:00 2001 From: dependentmadani Date: Sat, 13 Jul 2024 20:08:41 +0100 Subject: [PATCH 4/5] refactor: improve readability and fix generics usage in UI and ImageTool --- src/index.ts | 16 ++++++++++------ src/types/types.ts | 2 +- src/ui.ts | 6 +++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/index.ts b/src/index.ts index 28e4715f..6aa6ec22 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,9 +41,9 @@ import { IconAddBorder, IconStretch, IconAddBackground, IconPicture } from '@cod import { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, FileObjectData } from './types/types'; -type ImageToolConstructorOptions< CustomActions = {},AdditionalUploadResponse = {}> = BlockToolConstructorOptions, ImageConfig> +type ImageToolConstructorOptions = BlockToolConstructorOptions, ImageConfig> -export default class ImageTool implements BlockTool { +export default class ImageTool implements BlockTool { /** * Editor.js API instance */ @@ -72,7 +72,7 @@ export default class ImageTool; + private ui: Ui>; /** * Stores current block data internally @@ -119,7 +119,7 @@ export default class ImageTool({ + this.ui = new Ui>({ api, config: this.config, onSelectFile: () => { @@ -367,8 +367,12 @@ export default class ImageTool { - const value = typeof data[tune as keyof ImageToolData] !== 'undefined' ? data[tune as keyof ImageToolData] === true || data[tune as keyof ImageToolData] === 'true' : false; - + const tuneKey = tune as keyof ImageToolData; + const tuneValue = data[tuneKey]; + + const value = typeof tuneValue !== 'undefined' + ? tuneValue === true || tuneValue === 'true' : false; + this.setTune(tune as keyof ImageToolData, value); }); } diff --git a/src/types/types.ts b/src/types/types.ts index 4f16c2d7..eaf02550 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -91,7 +91,7 @@ export type ImageToolData = { * Also can contain any additional data. */ file: FileObjectData; -} & (Actions extends Record ? Actions : {}); +} & Actions; /** * diff --git a/src/ui.ts b/src/ui.ts index e873f7b4..7bb94025 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,7 +1,7 @@ import { IconPicture } from '@codexteam/icons'; import { make } from './utils/dom'; import type { API } from '@editorjs/editorjs'; -import { ImageToolData, ImageConfig } from './types/types'; +import { ImageConfig, ImageToolData } from './types/types'; /** * Enumeration representing the different states of the UI. @@ -86,7 +86,7 @@ interface ConstructorParams { * - show/hide preview * - apply tune view */ -export default class Ui { +export default class Ui { /** * API instance for Editor.js. */ @@ -180,7 +180,7 @@ public nodes: Nodes; * @param {ImageToolData} toolData - saved tool data * @returns {Element} */ - render(toolData: ImageToolData): HTMLElement { + render(toolData: ImageToolDataType): HTMLElement { if (!toolData.file || Object.keys(toolData.file).length === 0) { this.toggleStatus(UiState.Empty); } else { From e45e915cbf78f0da520dcab66a917d55f7463ae5 Mon Sep 17 00:00:00 2001 From: dependentmadani Date: Sat, 3 Aug 2024 19:53:59 +0100 Subject: [PATCH 5/5] refactor: remove some unecessary generics from isPromise --- package.json | 2 +- src/index.ts | 2 +- src/utils/isPromise.ts | 4 +--- yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 7b27d495..7120556e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,6 @@ "vite-plugin-dts": "^3.9.1" }, "dependencies": { - "@codexteam/icons": "^0.3.0" + "@codexteam/icons": "^0.3.2" } } diff --git a/src/index.ts b/src/index.ts index 018ce450..3e93f82c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,7 +30,7 @@ */ import type { TunesMenuConfig } from '@editorjs/editorjs/types/tools'; -import type { API, ToolboxConfig, PasteConfig, BlockToolConstructorOptions, BlockTool, BlockAPI, PasteEvent, PatternPasteEventDetail, FilePasteEventDetail } from '@editorjs/editorjs'; +import type { API, ToolboxConfig, PasteConfig, BlockToolConstructorOptions, BlockAPI, PasteEvent, PatternPasteEventDetail, FilePasteEventDetail, BlockTool } from '@editorjs/editorjs'; import './index.css'; import Ui from './ui'; diff --git a/src/utils/isPromise.ts b/src/utils/isPromise.ts index bb693416..5eb679d1 100644 --- a/src/utils/isPromise.ts +++ b/src/utils/isPromise.ts @@ -1,10 +1,8 @@ -import type { UploadResponseFormat } from '../types/types'; - /** * Check if passed object is a Promise * @param object - object to check * @returns */ -export default function isPromise(object: Promise>): object is Promise> { +export default function isPromise(object: Promise<{}>): object is Promise<{}> { return object !== undefined && typeof object.then === 'function'; } diff --git a/yarn.lock b/yarn.lock index b1b136d1..2a3bf174 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,10 +12,10 @@ resolved "https://registry.yarnpkg.com/@codexteam/ajax/-/ajax-4.2.0.tgz#f89faecbaf8cd496bfd77ef20a7fe99ee20ca9a3" integrity sha512-54r/HZirqBPEV8rM9gZh570RCwG6M/iDAXT9Q9eGuMo9KZU49tw1dEDHjYsResGckfCsaymDqg4GnhfrBtX9JQ== -"@codexteam/icons@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.3.0.tgz#62380b4053d487a257de443864b5c72dafab95e6" - integrity sha512-fJE9dfFdgq8xU+sbsxjH0Kt8Yeatw9xHBJWb77DhRkEXz3OCoIS6hrRC1ewHEryxzIjxD8IyQrRq2f+Gz3BcmA== +"@codexteam/icons@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.3.2.tgz#b7aed0ba7b344e07953101f5476cded570d4f150" + integrity sha512-P1ep2fHoy0tv4wx85eic+uee5plDnZQ1Qa6gDfv7eHPkCXorMtVqJhzMb75o1izogh6G7380PqmFDXV3bW3Pig== "@editorjs/editorjs@2.30.0-rc.12": version "2.30.0-rc.12"