From 4615a0c098fefb33b3b36e9506fdc1fd956705ac Mon Sep 17 00:00:00 2001 From: AMRIK Date: Sat, 8 Feb 2025 15:18:30 +0530 Subject: [PATCH 01/14] chore: enhance TypeScript configuration and build process - Update tsconfig.json with stricter type checking and module resolution - Modify package.json scripts to include type checking and declaration generation - Update Vite configuration for better module and library bundling - Improve type definitions and utility functions - Add type-related scripts and configuration for better developer experience --- package.json | 10 +- src/index.ts | 174 ++++++++++++++++++----------- src/types/codexteam__ajax.d.ts | 77 +++++++++---- src/types/index.d.ts | 23 ++++ src/types/types.ts | 92 ++++++++++++---- src/ui.ts | 80 ++++++++------ src/uploader.ts | 194 +++++++++++++++++++++------------ src/utils/dom.ts | 13 ++- tsconfig.json | 19 +++- vite.config.js | 20 +++- 10 files changed, 480 insertions(+), 222 deletions(-) create mode 100644 src/types/index.d.ts diff --git a/package.json b/package.json index cdc99cf0..d9b71622 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,12 @@ }, "scripts": { "dev": "concurrently \"vite\" \"node ./dev/server.js\"", - "build": "vite build", - "lint": "eslint", - "lint:errors": "eslint --quiet", - "lint:fix": "eslint --fix" + "build": "vite build && tsc --emitDeclarationOnly", + "lint": "eslint ./src --ext .ts", + "lint:errors": "eslint ./src --ext .ts --quiet", + "lint:fix": "eslint ./src --ext .ts --fix", + "type-check": "tsc --noEmit", + "type-check:watch": "tsc --noEmit --watch" }, "author": { "name": "CodeX", diff --git a/src/index.ts b/src/index.ts index c35f436b..809762e8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,17 +28,47 @@ * }, */ -import type { TunesMenuConfig } from '@editorjs/editorjs/types/tools'; -import type { API, ToolboxConfig, PasteConfig, BlockToolConstructorOptions, BlockTool, BlockAPI, PasteEvent, PatternPasteEventDetail, FilePasteEventDetail } from '@editorjs/editorjs'; -import './index.css'; +import type { TunesMenuConfig } from "@editorjs/editorjs/types/tools"; +import type { + API, + ToolboxConfig, + PasteConfig, + BlockToolConstructorOptions, + BlockTool, + BlockAPI, + PasteEvent, + PatternPasteEventDetail, + FilePasteEventDetail, +} from "@editorjs/editorjs"; +import "./index.css"; + +import Ui from "./ui"; +import Uploader from "./uploader"; + +import { + IconAddBorder, + IconStretch, + IconAddBackground, + IconPicture, + IconText, +} from "@codexteam/icons"; +import type { + ActionConfig, + UploadResponseFormat, + ImageToolData, + ImageConfig, + HTMLPasteEventDetailExtended, + ImageSetterParam, + FeaturesConfig, +} from "./types/types"; -import Ui from './ui'; -import Uploader from './uploader'; - -import { IconAddBorder, IconStretch, IconAddBackground, IconPicture, IconText } from '@codexteam/icons'; -import type { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, HTMLPasteEventDetailExtended, ImageSetterParam, FeaturesConfig } from './types/types'; - -type ImageToolConstructorOptions = BlockToolConstructorOptions; +/** + * Constructor options for ImageTool + */ +type ImageToolConstructorOptions = BlockToolConstructorOptions< + ImageToolData, + ImageConfig +>; /** * Implementation of ImageTool class @@ -47,27 +77,27 @@ export default class ImageTool implements BlockTool { /** * Editor.js API instance */ - private api: API; + private readonly api: API; /** * Current Block API instance */ - private block: BlockAPI; + private readonly block: BlockAPI; /** * Configuration for the ImageTool */ - private config: ImageConfig; + private readonly config: ImageConfig; /** * Uploader module instance */ - private uploader: Uploader; + private readonly uploader: Uploader; /** * UI module instance */ - private ui: Ui; + private readonly ui: Ui; /** * Stores current block data internally @@ -90,7 +120,13 @@ export default class ImageTool implements BlockTool { * @param tool.readOnly - read-only mode flag * @param tool.block - current Block API */ - constructor({ data, config, api, readOnly, block }: ImageToolConstructorOptions) { + constructor({ + data, + config, + api, + readOnly, + block, + }: ImageToolConstructorOptions) { this.api = api; this.block = block; @@ -103,7 +139,9 @@ export default class ImageTool implements BlockTool { additionalRequestHeaders: config.additionalRequestHeaders, field: config.field, types: config.types, - captionPlaceholder: this.api.i18n.t(config.captionPlaceholder ?? 'Caption'), + captionPlaceholder: this.api.i18n.t( + config.captionPlaceholder ?? "Caption" + ), buttonContent: config.buttonContent, uploader: config.uploader, actions: config.actions, @@ -139,12 +177,12 @@ export default class ImageTool implements BlockTool { * Set saved state */ this._data = { - caption: '', + caption: "", withBorder: false, withBackground: false, stretched: false, file: { - url: '', + url: "", }, }; this.data = data; @@ -165,7 +203,7 @@ export default class ImageTool implements BlockTool { public static get toolbox(): ToolboxConfig { return { icon: IconPicture, - title: 'Image', + title: "Image", }; } @@ -175,21 +213,21 @@ export default class ImageTool implements BlockTool { public static get tunes(): Array { return [ { - name: 'withBorder', + name: "withBorder", icon: IconAddBorder, - title: 'With border', + title: "With border", toggle: true, }, { - name: 'stretched', + name: "stretched", icon: IconStretch, - title: 'Stretch image', + title: "Stretch image", toggle: true, }, { - name: 'withBackground', + name: "withBackground", icon: IconAddBackground, - title: 'With background', + title: "With background", toggle: true, }, ]; @@ -199,7 +237,11 @@ export default class ImageTool implements BlockTool { * Renders Block content */ public render(): HTMLDivElement { - if (this.config.features?.caption === true || this.config.features?.caption === undefined || (this.config.features?.caption === 'optional' && this.data.caption)) { + if ( + this.config.features?.caption === true || + this.config.features?.caption === undefined || + (this.config.features?.caption === "optional" && this.data.caption) + ) { this.isCaptionEnabled = true; } @@ -235,29 +277,34 @@ export default class ImageTool implements BlockTool { // @see https://github.com/editor-js/image/pull/49 const tunes = ImageTool.tunes.concat(this.config.actions || []); const featureTuneMap: Record = { - border: 'withBorder', - background: 'withBackground', - stretch: 'stretched', - caption: 'caption', + border: "withBorder", + background: "withBackground", + stretch: "stretched", + caption: "caption", }; - if (this.config.features?.caption === 'optional') { + if (this.config.features?.caption === "optional") { tunes.push({ - name: 'caption', + name: "caption", icon: IconText, - title: 'With caption', + title: "With caption", toggle: true, }); } const availableTunes = tunes.filter((tune) => { - const featureKey = Object.keys(featureTuneMap).find(key => featureTuneMap[key] === tune.name); + const featureKey = Object.keys(featureTuneMap).find( + (key) => featureTuneMap[key] === tune.name + ); - if (featureKey === 'caption') { + if (featureKey === "caption") { return this.config.features?.caption !== false; } - return featureKey == null || this.config.features?.[featureKey as keyof FeaturesConfig] !== false; + return ( + featureKey == null || + this.config.features?.[featureKey as keyof FeaturesConfig] !== false + ); }); /** @@ -267,14 +314,14 @@ export default class ImageTool implements BlockTool { const isActive = (tune: ActionConfig): boolean => { let currentState = this.data[tune.name as keyof ImageToolData] as boolean; - if (tune.name === 'caption') { + if (tune.name === "caption") { currentState = this.isCaptionEnabled ?? currentState; } return currentState; }; - return availableTunes.map(tune => ({ + return availableTunes.map((tune) => ({ icon: tune.icon, label: this.api.i18n.t(tune.title), name: tune.name, @@ -282,7 +329,7 @@ export default class ImageTool implements BlockTool { isActive: isActive(tune), onActivate: () => { /** If it'a user defined tune, execute it's callback stored in action property */ - if (typeof tune.action === 'function') { + if (typeof tune.action === "function") { tune.action(tune.name); return; @@ -293,7 +340,7 @@ export default class ImageTool implements BlockTool { * For the caption tune, we can't rely on the this._data * because it can be manualy toggled by user */ - if (tune.name === 'caption') { + if (tune.name === "caption") { this.isCaptionEnabled = !(this.isCaptionEnabled ?? false); newState = this.isCaptionEnabled; } @@ -336,7 +383,7 @@ export default class ImageTool implements BlockTool { * Drag n drop file from into the Editor */ files: { - mimeTypes: ['image/*'], + mimeTypes: ["image/*"], }, }; } @@ -349,7 +396,7 @@ export default class ImageTool implements BlockTool { */ public async onPaste(event: PasteEvent): Promise { switch (event.type) { - case 'tag': { + case "tag": { const image = (event.detail as HTMLPasteEventDetailExtended).data; /** Images from PDF */ @@ -365,13 +412,13 @@ export default class ImageTool implements BlockTool { this.uploadUrl(image.src); break; } - case 'pattern': { + case "pattern": { const url = (event.detail as PatternPasteEventDetail).data; this.uploadUrl(url); break; } - case 'file': { + case "file": { const file = (event.detail as FilePasteEventDetail).file; this.uploadFile(file); @@ -382,7 +429,7 @@ export default class ImageTool implements BlockTool { /** * Private methods - * ̿̿ ̿̿ ̿̿ ̿'̿'\̵͇̿̿\з= ( ▀ ͜͞ʖ▀) =ε/̵͇̿̿/’̿’̿ ̿ ̿̿ ̿̿ ̿̿ + * ̿̿ ̿̿ ̿̿ ̿'̿'\̵͇̿̿\з= ( ▀ ͜͞ʖ▀) =ε/̵͇̿̿/’̿'̿ ̿ ̿̿ ̿̿ ̿̿ */ /** @@ -392,17 +439,21 @@ export default class ImageTool implements BlockTool { private set data(data: ImageToolData) { this.image = data.file; - this._data.caption = data.caption || ''; + 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); }); if (data.caption) { - this.setTune('caption', true); + this.setTune("caption", true); } } @@ -418,7 +469,7 @@ export default class ImageTool implements BlockTool { * @param file - uploaded file data */ private set image(file: ImageSetterParam | undefined) { - this._data.file = file || { url: '' }; + this._data.file = file || { url: "" }; if (file && file.url) { this.ui.fillImage(file.url); @@ -433,7 +484,7 @@ export default class ImageTool implements BlockTool { if (response.success && Boolean(response.file)) { this.image = response.file; } else { - this.uploadingFailed('incorrect response: ' + JSON.stringify(response)); + this.uploadingFailed("incorrect response: " + JSON.stringify(response)); } } @@ -442,11 +493,11 @@ export default class ImageTool implements BlockTool { * @param errorText - uploading error info */ private uploadingFailed(errorText: string): void { - console.log('Image Tool: uploading failed because of', errorText); + console.log("Image Tool: uploading failed because of", errorText); this.api.notifier.show({ - message: this.api.i18n.t('Couldn’t upload image. Please try another.'), - style: 'error', + message: this.api.i18n.t("Couldn’t upload image. Please try another."), + style: "error", }); this.ui.hidePreloader(); } @@ -457,12 +508,12 @@ export default class ImageTool implements BlockTool { * @param state - new state */ private tuneToggled(tuneName: keyof ImageToolData, state: boolean): void { - if (tuneName === 'caption') { + if (tuneName === "caption") { this.ui.applyTune(tuneName, state); if (state == false) { - this._data.caption = ''; - this.ui.fillCaption(''); + this._data.caption = ""; + this.ui.fillCaption(""); } } else { /** @@ -481,13 +532,14 @@ export default class ImageTool implements BlockTool { (this._data[tuneName] as boolean) = value; this.ui.applyTune(tuneName, value); - if (tuneName === 'stretched') { + if (tuneName === "stretched") { /** * Wait until the API is ready */ - Promise.resolve().then(() => { - this.block.stretched = value; - }) + Promise.resolve() + .then(() => { + this.block.stretched = value; + }) .catch((err) => { console.error(err); }); diff --git a/src/types/codexteam__ajax.d.ts b/src/types/codexteam__ajax.d.ts index 49e1e38b..71f27be8 100644 --- a/src/types/codexteam__ajax.d.ts +++ b/src/types/codexteam__ajax.d.ts @@ -1,9 +1,17 @@ /** * Module declaration for '@codexteam/ajax'. */ -declare module '@codexteam/ajax' { +declare module "@codexteam/ajax" { /** - * Options for configuring an Ajax request. + * Options for configuring an AJAX request + * @typedef {Object} AjaxOptions + * @property {string} [url] - The target URL for the request + * @property {Object} [data] - Payload to send with the request + * @property {string} [accept] - MIME type to accept in response + * @property {Object} [headers] - Custom headers to include + * @property {function(File[]): void} [beforeSend] - Callback before sending files + * @property {string} [fieldName] - Form data field name for file uploads + * @property {string} [type] - HTTP method type (GET/POST/etc) */ export interface AjaxOptions { /** @@ -37,7 +45,9 @@ declare module '@codexteam/ajax' { } /** - * Parameter type of selectFiles function in AjaxOptions interface + * File selection options structure + * @typedef {Object} AjaxFileOptionsParam + * @property {string} accept - Allowed file types (e.g. 'image/*') */ export type AjaxFileOptionsParam = { /** @@ -47,35 +57,64 @@ declare module '@codexteam/ajax' { }; /** - * Represents the response from an Ajax request. - * @template T - The type of the response body. + * AJAX response wrapper with typed body + * @template T - Type of the response body content + * @typedef {Object} AjaxResponse + * @property {number} status - HTTP status code + * @property {T} body - Parsed response content */ - export interface AjaxResponse { - /** The body of the response. */ + export interface AjaxResponse { + status: number; body: T; } /** - * Prompts the user to select files and returns a promise that resolves with the selected files. - * @param options - Options for file selection. - * @param options.accept - The accepted file types. - * @returns A promise that resolves with the selected files. + * File selection handler + * @function selectFiles + * @param {AjaxFileOptionsParam} options - File type restrictions + * @returns {Promise} Array of selected files */ export function selectFiles(options: AjaxFileOptionsParam): Promise; /** - * Sends an Ajax request with the specified options. - * @param options - Options for the Ajax request. - * @returns A promise that resolves with the Ajax response. + * Core transport method for AJAX requests + * @function transport + * @template T - Expected response body type + * @param {Object} options - Transport configuration + * @param {string} options.url - Endpoint URL + * @param {FormData|Record} [options.data] - Request payload + * @param {string} [options.accept] - Response MIME type + * @param {Record} [options.headers] - Request headers + * @param {function(File[]): void} [options.beforeSend] - File preprocessor + * @param {string} [options.fieldName] - Form field name + * @returns {Promise>} Response wrapper */ - export function transport(options: AjaxOptions): Promise; + export function transport(options: { + url: string; + data?: FormData | Record; + accept?: string; + headers?: Record; + beforeSend?: (files: File[]) => void; + fieldName?: string; + }): Promise>; /** - * Sends a POST request with the specified options. - * @param options - Options for the POST request. - * @returns A promise that resolves with the Ajax response. + * POST request shortcut + * @function post + * @template T - Expected response body type + * @param {Object} options - Request configuration + * @param {string} options.url - Target endpoint + * @param {FormData|Record} options.data - POST payload + * @param {string} [options.type] - Content type header + * @param {Record} [options.headers] - Custom headers + * @returns {Promise>} Response wrapper */ - export function post(options: AjaxOptions): Promise; + export function post(options: { + url: string; + data: FormData | Record; + type?: string; + headers?: Record; + }): Promise>; /** * Represents common content types. diff --git a/src/types/index.d.ts b/src/types/index.d.ts new file mode 100644 index 00000000..0d5b247e --- /dev/null +++ b/src/types/index.d.ts @@ -0,0 +1,23 @@ +import type { BlockTool, BlockToolConstructorOptions } from '@editorjs/editorjs'; +import type { ImageToolData, ImageConfig } from './types'; + +declare class ImageTool implements BlockTool { + constructor(options: BlockToolConstructorOptions); + + static get isReadOnlySupported(): boolean; + static get toolbox(): { icon: string; title: string; }; + static get tunes(): Array<{ + name: string; + icon: string; + title: string; + toggle?: boolean; + }>; + + render(): HTMLElement; + save(): ImageToolData; + validate(savedData: ImageToolData): boolean; + + onPaste(event: CustomEvent): Promise; +} + +export default ImageTool; \ No newline at end of file diff --git a/src/types/types.ts b/src/types/types.ts index 3de55056..c60c681f 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,19 +1,27 @@ -import type { HTMLPasteEventDetail } from '@editorjs/editorjs'; +import type { HTMLPasteEventDetail } from "@editorjs/editorjs"; /** - * Represents options for uploading, including a function to handle previewing. + * Configuration options for file upload preview handling + * @typedef {Object} UploadOptions + * @property {function(string): void} onPreview - Preview ready callback */ export interface UploadOptions { /** - * Callback function to be called when the preview is ready. - * @param src - The source of the preview as a string. - * @returns void + * Callback when preview is available + * @param {string} src - Preview image source URL + * @returns {void} */ onPreview: (src: string) => void; } /** - * User configuration of Image block tunes. Allows to add custom tunes through the config + * Configuration for custom block tune actions + * @typedef {Object} ActionConfig + * @property {string} name - Unique action identifier + * @property {string} icon - SVG icon string + * @property {string} title - Display text for UI + * @property {boolean} [toggle] - Whether the action is a toggle + * @property {function(string): void} [action] - Action handler function */ export interface ActionConfig { /** @@ -39,11 +47,16 @@ export interface ActionConfig { /** * An optional action function to be executed when the tune is activated. */ - action?: Function; -}; + action?: (name: string) => void; +} /** - * UploadResponseFormat interface representing the response format expected from the backend on file uploading. + * Standard upload response format + * @template [AdditionalFileData={}] - Type for additional file metadata + * @typedef {Object} UploadResponseFormat + * @property {number} success - Upload status (1=success, 0=failure) + * @property {Object} file - Uploaded file data + * @property {string} file.url - File access URL */ export interface UploadResponseFormat { /** @@ -65,7 +78,16 @@ export interface UploadResponseFormat { } /** - * ImageToolData type representing the input and output data format for the image tool, including optional custome actions. + * Core image tool data structure + * @template [Actions={}] - Type for custom actions + * @template [AdditionalFileData={}] - Type for additional file metadata + * @typedef {Object} ImageToolData + * @property {string} caption - Image description text + * @property {boolean} withBorder - Border display state + * @property {boolean} withBackground - Background display state + * @property {boolean} stretched - Stretch display state + * @property {Object} file - File reference data + * @property {string} file.url - Image source URL */ export type ImageToolData = { /** @@ -101,7 +123,12 @@ export type ImageToolData = { } & (Actions extends Record ? Actions : {}); /** - * @description Allows to enable or disable features. + * Feature toggle configuration + * @typedef {Object} FeaturesConfig + * @property {boolean} [background] - Background toggle state + * @property {boolean} [border] - Border toggle state + * @property {boolean|'optional'} [caption] - Caption display mode + * @property {boolean} [stretch] - Stretch toggle state */ export type FeaturesConfig = { /** @@ -116,7 +143,7 @@ export type FeaturesConfig = { * Flag to enable/disable caption. * Can be set to 'optional' to allow users to toggle via block tunes. */ - caption?: boolean | 'optional'; + caption?: boolean | "optional"; /** * Flag to enable/disable tune - stretched */ @@ -124,24 +151,37 @@ export type FeaturesConfig = { }; /** - * - * @description Config supported by Tool + * Main image tool configuration + * @typedef {Object} ImageConfig + * @property {Object} endpoints - Upload endpoint URLs + * @property {string} endpoints.byFile - File upload endpoint + * @property {string} endpoints.byUrl - URL upload endpoint + * @property {string} [field] - Form field name for uploads + * @property {string} [types] - Allowed MIME types + * @property {string} [captionPlaceholder] - Caption input placeholder + * @property {Object} [additionalRequestData] - Additional POST data + * @property {Object} [additionalRequestHeaders] - Additional headers + * @property {string} [buttonContent] - Custom button content + * @property {Object} [uploader] - Custom uploader implementation + * @property {function(File): Promise} [uploader.uploadByFile] - Custom file upload handler + * @property {function(string): Promise} [uploader.uploadByUrl] - Custom URL upload handler + * @property {ActionConfig[]} [actions] - Custom actions + * @property {FeaturesConfig} [features] - Feature toggle states */ export interface ImageConfig { /** * Endpoints for upload, whether using file or URL. */ endpoints: { - /** * Endpoint for file upload. */ - byFile?: string; + byFile: string; /** * Endpoints for URL upload. */ - byUrl?: string; + byUrl: string; }; /** @@ -162,12 +202,12 @@ export interface ImageConfig { /** * Additional data to send with requests. */ - additionalRequestData?: object; + additionalRequestData?: Record; /** * Additional headers to send with requests. */ - additionalRequestHeaders?: object; + additionalRequestHeaders?: Record; /** * Custom content for the select file button. @@ -178,11 +218,10 @@ export interface ImageConfig { * Optional custom uploader. */ uploader?: { - /** * Method to upload an image by file. */ - uploadByFile?: (file: Blob) => Promise; + uploadByFile?: (file: File) => Promise; /** * Method to upload an image by URL. @@ -202,8 +241,11 @@ export interface ImageConfig { } /** - * Interface representing the details of a paste event for HTML elements. - * Extends the `HTMLPasteEventDetail` interface to include additional data properties. + * Extended paste event details + * @typedef {Object} HTMLPasteEventDetailExtended + * @extends {HTMLPasteEventDetail} + * @property {Object} data - Paste event payload + * @property {string} data.src - Pasted image source URL */ export interface HTMLPasteEventDetailExtended extends HTMLPasteEventDetail { /** @@ -218,7 +260,9 @@ export interface HTMLPasteEventDetailExtended extends HTMLPasteEventDetail { } /** - * Parameter type of Image setter function in ImageTool + * Image setter parameter type + * @typedef {Object} ImageSetterParam + * @property {string} url - Image source URL */ export type ImageSetterParam = { /** diff --git a/src/ui.ts b/src/ui.ts index f66afa01..8d965ae8 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 type { ImageConfig } from './types/types'; +import { IconPicture } from "@codexteam/icons"; +import { make } from "./utils/dom"; +import type { API } from "@editorjs/editorjs"; +import type { ImageConfig } from "./types/types"; /** * Enumeration representing the different states of the UI. @@ -10,18 +10,18 @@ export enum UiState { /** * The UI is in an empty state, with no image loaded or being selected. */ - Empty = 'empty', + Empty = "empty", /** * The UI is in an uploading state, indicating an image is currently being uploaded. */ - Uploading = 'uploading', + Uploading = "uploading", /** * The UI is in a filled state, with an image successfully loaded. */ - Filled = 'filled' -}; + Filled = "filled", +} /** * Nodes interface representing various elements in the UI. @@ -30,32 +30,32 @@ interface Nodes { /** * Wrapper element in the UI. */ - wrapper: HTMLElement; + wrapper: HTMLDivElement; /** * Container for the image element in the UI. */ - imageContainer: HTMLElement; + imageContainer: HTMLDivElement; /** * Button for selecting files. */ - fileButton: HTMLElement; + fileButton: HTMLButtonElement; /** * Represents the image element in the UI, if one is present; otherwise, it's undefined. */ - imageEl?: HTMLElement; + imageEl?: HTMLImageElement | HTMLVideoElement; /** * Preloader element for the image. */ - imagePreloader: HTMLElement; + imagePreloader: HTMLDivElement; /** * Caption element for the image. */ - caption: HTMLElement; + caption: HTMLDivElement; } /** @@ -125,12 +125,12 @@ export default class Ui { this.onSelectFile = onSelectFile; this.readOnly = readOnly; this.nodes = { - wrapper: make('div', [this.CSS.baseClass, this.CSS.wrapper]), - imageContainer: make('div', [this.CSS.imageContainer]), - fileButton: this.createFileButton(), + wrapper: make("div", [this.CSS.baseClass, this.CSS.wrapper]), + imageContainer: make("div", [this.CSS.imageContainer]), + fileButton: this.createFileButton() as HTMLButtonElement, imageEl: undefined, - imagePreloader: make('div', this.CSS.imagePreloader), - caption: make('div', [this.CSS.input, this.CSS.caption], { + imagePreloader: make("div", this.CSS.imagePreloader), + caption: make("div", [this.CSS.input, this.CSS.caption], { contentEditable: !this.readOnly, }), }; @@ -158,7 +158,10 @@ export default class Ui { * @param status - true for enable, false for disable */ public applyTune(tuneName: string, status: boolean): void { - this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${tuneName}`, status); + this.nodes.wrapper.classList.toggle( + `${this.CSS.wrapper}--${tuneName}`, + status + ); } /** @@ -184,7 +187,7 @@ export default class Ui { * Hide uploading preloader */ public hidePreloader(): void { - this.nodes.imagePreloader.style.backgroundImage = ''; + this.nodes.imagePreloader.style.backgroundImage = ""; this.toggleStatus(UiState.Empty); } @@ -196,7 +199,7 @@ export default class Ui { /** * Check for a source extension to compose element correctly: video tag for mp4, img — for others */ - const tag = /\.mp4$/.test(url) ? 'VIDEO' : 'IMG'; + const tag = /\.mp4$/.test(url) ? "VIDEO" : "IMG"; const attributes: { [key: string]: string | boolean } = { src: url, @@ -207,12 +210,12 @@ export default class Ui { * - IMG: load * - VIDEO: loadeddata */ - let eventName = 'load'; + let eventName = "load"; /** * Update attributes and eventName if source is a mp4 video */ - if (tag === 'VIDEO') { + if (tag === "VIDEO") { /** * Add attributes for playing muted mp4 as a gif */ @@ -224,7 +227,7 @@ export default class Ui { /** * Change event to be listened */ - eventName = 'loadeddata'; + eventName = "loadeddata"; } /** @@ -242,7 +245,7 @@ export default class Ui { * Preloader does not exists on first rendering with presaved data */ if (this.nodes.imagePreloader !== undefined) { - this.nodes.imagePreloader.style.backgroundImage = ''; + this.nodes.imagePreloader.style.backgroundImage = ""; } }); @@ -268,7 +271,10 @@ export default class Ui { if (Object.prototype.hasOwnProperty.call(UiState, statusType)) { const state = UiState[statusType as keyof typeof UiState]; - this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${state}`, state === status); + this.nodes.wrapper.classList.toggle( + `${this.CSS.wrapper}--${state}`, + state === status + ); } } } @@ -286,23 +292,25 @@ export default class Ui { /** * Tool's classes */ - wrapper: 'image-tool', - imageContainer: 'image-tool__image', - imagePreloader: 'image-tool__image-preloader', - imageEl: 'image-tool__image-picture', - caption: 'image-tool__caption', + wrapper: "image-tool", + imageContainer: "image-tool__image", + imagePreloader: "image-tool__image-preloader", + imageEl: "image-tool__image-picture", + caption: "image-tool__caption", }; - }; + } /** * Creates upload-file button */ private createFileButton(): HTMLElement { - const button = make('div', [this.CSS.button]); + const button = make("div", [this.CSS.button]); - button.innerHTML = this.config.buttonContent ?? `${IconPicture} ${this.api.i18n.t('Select an Image')}`; + button.innerHTML = + this.config.buttonContent ?? + `${IconPicture} ${this.api.i18n.t("Select an Image")}`; - button.addEventListener('click', () => { + button.addEventListener("click", () => { this.onSelectFile(); }); diff --git a/src/uploader.ts b/src/uploader.ts index 19dabb29..f8409287 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -1,8 +1,8 @@ -import ajax from '@codexteam/ajax'; -import type { AjaxResponse } from '@codexteam/ajax'; -import isPromise from './utils/isPromise'; -import type { UploadOptions } from './types/types'; -import type { UploadResponseFormat, ImageConfig } from './types/types'; +import ajax from "@codexteam/ajax"; +import type { AjaxResponse } from "@codexteam/ajax"; +import isPromise from "./utils/isPromise"; +import type { UploadOptions } from "./types/types"; +import type { UploadResponseFormat, ImageConfig } from "./types/types"; /** * Params interface for Uploader constructor @@ -55,7 +55,7 @@ export default class Uploader { * Fires ajax.transport() * @param onPreview - callback fired when preview is ready */ - public uploadSelectedFile({ onPreview }: UploadOptions): void { + public uploadSelectedFile({ onPreview }: UploadOptions): Promise { const preparePreview = function (file: File): void { const reader = new FileReader(); @@ -72,40 +72,58 @@ export default class Uploader { let upload: Promise; // custom uploading - if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') { + if ( + this.config.uploader && + typeof this.config.uploader.uploadByFile === "function" + ) { const uploadByFile = this.config.uploader.uploadByFile; - upload = ajax.selectFiles({ accept: this.config.types ?? 'image/*' }).then((files: File[]) => { - preparePreview(files[0]); + upload = ajax + .selectFiles({ accept: this.config.types ?? "image/*" }) + .then((files: File[]) => { + preparePreview(files[0]); - const customUpload = uploadByFile(files[0]); + const customUpload = uploadByFile(files[0]); - if (!isPromise(customUpload)) { - console.warn('Custom uploader method uploadByFile should return a Promise'); - } + if (!isPromise(customUpload)) { + console.warn( + "Custom uploader method uploadByFile should return a Promise" + ); + } - return customUpload; - }); + return customUpload; + }); - // default uploading + // default uploading } else { - upload = ajax.transport({ - url: this.config.endpoints.byFile, - data: this.config.additionalRequestData, - accept: this.config.types ?? 'image/*', - headers: this.config.additionalRequestHeaders as Record, - beforeSend: (files: File[]) => { - preparePreview(files[0]); - }, - fieldName: this.config.field ?? 'image', - }).then((response: AjaxResponse) => response.body as UploadResponseFormat); + upload = ajax + .transport({ + url: this.config.endpoints.byFile, + data: this.config.additionalRequestData, + accept: this.config.types ?? "image/*", + headers: this.config.additionalRequestHeaders as Record< + string, + string + >, + beforeSend: (files: File[]) => { + preparePreview(files[0]); + }, + fieldName: this.config.field ?? "image", + }) + .then( + (response: AjaxResponse) => response.body as UploadResponseFormat + ); } - upload.then((response) => { - this.onUpload(response); - }).catch((error: string) => { - this.onError(error); - }); + upload + .then((response) => { + this.onUpload(response); + }) + .catch((error: string) => { + this.onError(error); + }); + + return Promise.resolve(); } /** @@ -113,37 +131,56 @@ export default class Uploader { * Fires ajax.post() * @param url - image source url */ - public uploadByUrl(url: string): void { + public uploadByUrl(url: string): Promise { let upload; /** * Custom uploading */ - if (this.config.uploader && typeof this.config.uploader.uploadByUrl === 'function') { + if ( + this.config.uploader && + typeof this.config.uploader.uploadByUrl === "function" + ) { upload = this.config.uploader.uploadByUrl(url); if (!isPromise(upload)) { - console.warn('Custom uploader method uploadByUrl should return a Promise'); + console.warn( + "Custom uploader method uploadByUrl should return a Promise" + ); } } else { /** * Default uploading */ - upload = ajax.post({ - url: this.config.endpoints.byUrl, - data: Object.assign({ - url: url, - }, this.config.additionalRequestData), - type: ajax.contentType.JSON, - headers: this.config.additionalRequestHeaders as Record, - }).then((response: AjaxResponse) => response.body as UploadResponseFormat); + upload = ajax + .post({ + url: this.config.endpoints.byUrl, + data: Object.assign( + { + url: url, + }, + this.config.additionalRequestData + ), + type: ajax.contentType.JSON, + headers: this.config.additionalRequestHeaders as Record< + string, + string + >, + }) + .then( + (response: AjaxResponse) => response.body as UploadResponseFormat + ); } - upload.then((response: UploadResponseFormat) => { - this.onUpload(response); - }).catch((error: string) => { - this.onError(error); - }); + upload + .then((response: UploadResponseFormat) => { + this.onUpload(response); + }) + .catch((error: string) => { + this.onError(error); + }); + + return Promise.resolve(); } /** @@ -152,7 +189,7 @@ export default class Uploader { * @param file - file pasted by drag-n-drop * @param onPreview - file pasted by drag-n-drop */ - public uploadByFile(file: Blob, { onPreview }: UploadOptions): void { + public uploadByFile(file: Blob, { onPreview }: UploadOptions): Promise { /** * Load file for preview */ @@ -168,11 +205,18 @@ export default class Uploader { /** * Custom uploading */ - if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') { - upload = this.config.uploader.uploadByFile(file); + if ( + this.config.uploader && + typeof this.config.uploader.uploadByFile === "function" + ) { + // Convert Blob to File with a dummy filename + const fileObj = new File([file], "pasted-image", { type: file.type }); + upload = this.config.uploader.uploadByFile(fileObj); if (!isPromise(upload)) { - console.warn('Custom uploader method uploadByFile should return a Promise'); + console.warn( + "Custom uploader method uploadByFile should return a Promise" + ); } } else { /** @@ -180,26 +224,42 @@ export default class Uploader { */ const formData = new FormData(); - formData.append(this.config.field ?? 'image', file); + formData.append(this.config.field ?? "image", file); - if (this.config.additionalRequestData && Object.keys(this.config.additionalRequestData).length) { - Object.entries(this.config.additionalRequestData).forEach(([name, value]: [string, string | Blob]) => { - formData.append(name, value); - }); + if ( + this.config.additionalRequestData && + Object.keys(this.config.additionalRequestData).length + ) { + Object.entries(this.config.additionalRequestData).forEach( + ([name, value]: [string, string | Blob]) => { + formData.append(name, value); + } + ); } - upload = ajax.post({ - url: this.config.endpoints.byFile, - data: formData, - type: ajax.contentType.JSON, - headers: this.config.additionalRequestHeaders as Record, - }).then((response: AjaxResponse) => response.body as UploadResponseFormat); + upload = ajax + .post({ + url: this.config.endpoints.byFile, + data: formData, + type: ajax.contentType.JSON, + headers: this.config.additionalRequestHeaders as Record< + string, + string + >, + }) + .then( + (response: AjaxResponse) => response.body as UploadResponseFormat + ); } - upload.then((response) => { - this.onUpload(response); - }).catch((error: string) => { - this.onError(error); - }); + upload + .then((response) => { + this.onUpload(response); + }) + .catch((error: string) => { + this.onError(error); + }); + + return Promise.resolve(); } } diff --git a/src/utils/dom.ts b/src/utils/dom.ts index 70bf38a2..9a756d17 100644 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -5,18 +5,23 @@ * @param attributes - any attributes * @returns */ -export function make(tagName: string, classNames: string[] | string | null = null, attributes: { [key: string]: string | boolean } = {}): HTMLElement { - const el = document.createElement(tagName); +export function make( + tagName: string, + classNames?: string[] | string | null, + attributes?: Record +): T { + const el = document.createElement(tagName) as T; if (Array.isArray(classNames)) { el.classList.add(...classNames); - } else if (classNames !== null) { + } else if (typeof classNames === "string") { el.classList.add(classNames); } for (const attrName in attributes) { if (attributes.hasOwnProperty(attrName)) { - (el as unknown as { [key: string]: string | boolean })[attrName] = attributes[attrName]; + (el as unknown as { [key: string]: string | boolean })[attrName] = + attributes[attrName]; } } diff --git a/tsconfig.json b/tsconfig.json index 3454236b..b58f74a9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,14 +2,29 @@ "compilerOptions": { /* Language and Environment */ "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["dom", "es2017"], + "jsx": "preserve", /* Modules */ - "module": "CommonJS", /* Specify what module code is generated. */ + "module": "ESNext", + "moduleResolution": "node", + "resolveJsonModule": true, "typeRoots": ["./node_modules/@types", "./types"], /* Specify multiple folders that act like './node_modules/@types'. */ /* Interop Constraints */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "skipLibCheck": true, /* Type Checking */ "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + /* Emit */ + "declaration": true, + "declarationDir": "./dist", + "outDir": "./dist", + "sourceMap": true, }, - "include": ["src/**/*.ts"] + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] } \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 44a9dbed..446a0da7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,8 +1,7 @@ import path from "path"; import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; -import * as pkg from "./package.json"; import dts from 'vite-plugin-dts'; - +import * as pkg from "./package.json"; const NODE_ENV = process.argv.mode || "development"; const VERSION = pkg.version; @@ -14,6 +13,16 @@ export default { entry: path.resolve(__dirname, "src", "index.ts"), name: "ImageTool", fileName: "image", + formats: ['es', 'umd'] + }, + sourcemap: true, + rollupOptions: { + external: ['@editorjs/editorjs'], + output: { + globals: { + '@editorjs/editorjs': 'EditorJS' + } + } } }, server: { @@ -23,10 +32,11 @@ export default { NODE_ENV: JSON.stringify(NODE_ENV), VERSION: JSON.stringify(VERSION), }, - - plugins: [cssInjectedByJsPlugin(), + plugins: [ + cssInjectedByJsPlugin(), dts({ - tsconfigPath: './tsconfig.json' + tsconfigPath: './tsconfig.json', + insertTypesEntry: true }) ], }; From 304192dd7d7f699118ef7d8f92d927817bca6b91 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 18:49:06 +0530 Subject: [PATCH 02/14] chore: bump package version to 2.10.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d9b71622..175f8975 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@editorjs/image", - "version": "2.10.2", + "version": "2.10.3", "keywords": [ "codex editor", "image", From 67b4cf9f3df52dd8753e5b3e16058e40e21ac5c0 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 18:54:14 +0530 Subject: [PATCH 03/14] fix: initialize default image data with empty string values - Update default image data initialization in index.ts - Add type documentation for index.d.ts to improve type clarity --- src/index.ts | 4 ++-- src/types/index.d.ts | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 809762e8..9f02d678 100644 --- a/src/index.ts +++ b/src/index.ts @@ -177,12 +177,12 @@ export default class ImageTool implements BlockTool { * Set saved state */ this._data = { - caption: "", + caption: '', withBorder: false, withBackground: false, stretched: false, file: { - url: "", + url: '', }, }; this.data = data; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 0d5b247e..c394f353 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,3 +1,8 @@ +/** + * Type declarations for the Editor.js Image Tool + * This file defines the public TypeScript interface for the Image Tool plugin, + * providing type definitions and ensuring type safety for TypeScript users. + */ import type { BlockTool, BlockToolConstructorOptions } from '@editorjs/editorjs'; import type { ImageToolData, ImageConfig } from './types'; From 6fc44ab80baaac9a820ca7b9fdfafb05e2c55365 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 18:56:48 +0530 Subject: [PATCH 04/14] refactor: clean up type definitions and documentation - Remove redundant JSDoc comments from type interfaces - Improve inline documentation for type interfaces - Simplify type definitions while preserving their core structure --- src/types/types.ts | 55 ++++------------------------------------------ 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index c60c681f..f54f8151 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -2,26 +2,17 @@ import type { HTMLPasteEventDetail } from "@editorjs/editorjs"; /** * Configuration options for file upload preview handling - * @typedef {Object} UploadOptions - * @property {function(string): void} onPreview - Preview ready callback */ export interface UploadOptions { /** * Callback when preview is available * @param {string} src - Preview image source URL - * @returns {void} */ onPreview: (src: string) => void; } /** * Configuration for custom block tune actions - * @typedef {Object} ActionConfig - * @property {string} name - Unique action identifier - * @property {string} icon - SVG icon string - * @property {string} title - Display text for UI - * @property {boolean} [toggle] - Whether the action is a toggle - * @property {function(string): void} [action] - Action handler function */ export interface ActionConfig { /** @@ -52,11 +43,6 @@ export interface ActionConfig { /** * Standard upload response format - * @template [AdditionalFileData={}] - Type for additional file metadata - * @typedef {Object} UploadResponseFormat - * @property {number} success - Upload status (1=success, 0=failure) - * @property {Object} file - Uploaded file data - * @property {string} file.url - File access URL */ export interface UploadResponseFormat { /** @@ -66,8 +52,7 @@ export interface UploadResponseFormat { /** * Object with file data. - * 'url' is required, - * also can contain any additional data that will be saved and passed back + * 'url' is required, also can contain any additional data that will be saved and passed back */ file: { /** @@ -79,15 +64,6 @@ export interface UploadResponseFormat { /** * Core image tool data structure - * @template [Actions={}] - Type for custom actions - * @template [AdditionalFileData={}] - Type for additional file metadata - * @typedef {Object} ImageToolData - * @property {string} caption - Image description text - * @property {boolean} withBorder - Border display state - * @property {boolean} withBackground - Background display state - * @property {boolean} stretched - Stretch display state - * @property {Object} file - File reference data - * @property {string} file.url - Image source URL */ export type ImageToolData = { /** @@ -124,26 +100,24 @@ export type ImageToolData = { /** * Feature toggle configuration - * @typedef {Object} FeaturesConfig - * @property {boolean} [background] - Background toggle state - * @property {boolean} [border] - Border toggle state - * @property {boolean|'optional'} [caption] - Caption display mode - * @property {boolean} [stretch] - Stretch toggle state */ export type FeaturesConfig = { /** * Flag to enable/disable tune - background. */ background?: boolean; + /** * Flag to enable/disable tune - border. */ border?: boolean; + /** * Flag to enable/disable caption. * Can be set to 'optional' to allow users to toggle via block tunes. */ caption?: boolean | "optional"; + /** * Flag to enable/disable tune - stretched */ @@ -152,21 +126,6 @@ export type FeaturesConfig = { /** * Main image tool configuration - * @typedef {Object} ImageConfig - * @property {Object} endpoints - Upload endpoint URLs - * @property {string} endpoints.byFile - File upload endpoint - * @property {string} endpoints.byUrl - URL upload endpoint - * @property {string} [field] - Form field name for uploads - * @property {string} [types] - Allowed MIME types - * @property {string} [captionPlaceholder] - Caption input placeholder - * @property {Object} [additionalRequestData] - Additional POST data - * @property {Object} [additionalRequestHeaders] - Additional headers - * @property {string} [buttonContent] - Custom button content - * @property {Object} [uploader] - Custom uploader implementation - * @property {function(File): Promise} [uploader.uploadByFile] - Custom file upload handler - * @property {function(string): Promise} [uploader.uploadByUrl] - Custom URL upload handler - * @property {ActionConfig[]} [actions] - Custom actions - * @property {FeaturesConfig} [features] - Feature toggle states */ export interface ImageConfig { /** @@ -242,10 +201,6 @@ export interface ImageConfig { /** * Extended paste event details - * @typedef {Object} HTMLPasteEventDetailExtended - * @extends {HTMLPasteEventDetail} - * @property {Object} data - Paste event payload - * @property {string} data.src - Pasted image source URL */ export interface HTMLPasteEventDetailExtended extends HTMLPasteEventDetail { /** @@ -261,8 +216,6 @@ export interface HTMLPasteEventDetailExtended extends HTMLPasteEventDetail { /** * Image setter parameter type - * @typedef {Object} ImageSetterParam - * @property {string} url - Image source URL */ export type ImageSetterParam = { /** From 46950aedeed158ecd9fc4fb21819ea349576956a Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 18:57:44 +0530 Subject: [PATCH 05/14] refactor: make byFile optional in ImageConfig interface - Update ImageConfig interface to make byFile property optional - Improve type flexibility for image configuration --- src/types/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index f54f8151..acfb315b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -135,7 +135,7 @@ export interface ImageConfig { /** * Endpoint for file upload. */ - byFile: string; + byFile?: string; /** * Endpoints for URL upload. @@ -161,7 +161,7 @@ export interface ImageConfig { /** * Additional data to send with requests. */ - additionalRequestData?: Record; + additionalRequestData?: Record; /** * Additional headers to send with requests. From ca98889e7576195973b6454d5af3b1e3b003c13f Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:05:43 +0530 Subject: [PATCH 06/14] fix: improve upload method promise handling - Return upload promise directly instead of resolving immediately - Ensure proper error and success handling for upload methods - Remove redundant Promise.resolve() calls in upload methods --- src/uploader.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/uploader.ts b/src/uploader.ts index f8409287..4458472c 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -115,15 +115,14 @@ export default class Uploader { ); } - upload + // Return the upload promise instead of resolving immediately + return upload .then((response) => { this.onUpload(response); }) .catch((error: string) => { this.onError(error); }); - - return Promise.resolve(); } /** @@ -172,15 +171,14 @@ export default class Uploader { ); } - upload + // Return the upload promise instead of resolving immediately + return upload .then((response: UploadResponseFormat) => { this.onUpload(response); }) .catch((error: string) => { this.onError(error); }); - - return Promise.resolve(); } /** @@ -252,14 +250,13 @@ export default class Uploader { ); } - upload + // Return the upload promise instead of resolving immediately + return upload .then((response) => { this.onUpload(response); }) .catch((error: string) => { this.onError(error); }); - - return Promise.resolve(); } } From d5efbf58e133d6e83d59adf053eff0cef57e63ba Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:09:37 +0530 Subject: [PATCH 07/14] chore: update tsconfig.json formatting and configuration - Improve JSON formatting and readability - Remove redundant library declaration for 'dom' - Maintain existing TypeScript compiler options --- tsconfig.json | 59 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index b58f74a9..862c831c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,31 @@ { - "compilerOptions": { - /* Language and Environment */ - "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - "lib": ["dom", "es2017"], - "jsx": "preserve", - /* Modules */ - "module": "ESNext", - "moduleResolution": "node", - "resolveJsonModule": true, - "typeRoots": ["./node_modules/@types", "./types"], /* Specify multiple folders that act like './node_modules/@types'. */ - /* Interop Constraints */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - "skipLibCheck": true, - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - /* Emit */ - "declaration": true, - "declarationDir": "./dist", - "outDir": "./dist", - "sourceMap": true, - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules", "dist"] - } \ No newline at end of file + "compilerOptions": { + /* Language and Environment */ + "target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "jsx": "preserve", + /* Modules */ + "module": "ESNext", + "moduleResolution": "node", + "typeRoots": [ + "./node_modules/@types", + "./types" + ] /* Specify multiple folders that act like './node_modules/@types'. */, + /* Interop Constraints */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "skipLibCheck": true, + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + /* Emit */ + "declaration": true, + "declarationDir": "./dist", + "outDir": "./dist", + "sourceMap": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} From 994e1a35118106f4c2ab66f0ce6f1fe38b50472d Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:09:53 +0530 Subject: [PATCH 08/14] chore: remove external configuration in Vite build options - Remove unnecessary rollupOptions configuration for external dependencies - Simplify Vite build configuration - Maintain existing sourcemap and build format settings --- vite.config.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/vite.config.js b/vite.config.js index 446a0da7..e47a226a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -16,14 +16,6 @@ export default { formats: ['es', 'umd'] }, sourcemap: true, - rollupOptions: { - external: ['@editorjs/editorjs'], - output: { - globals: { - '@editorjs/editorjs': 'EditorJS' - } - } - } }, server: { open: './dev/index.html', From d4ac8e5774d4e1295984dc3cd1271a3048e9727b Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:21:22 +0530 Subject: [PATCH 09/14] chore: standardize code formatting and quotes across files - Convert string quotes from double to single quotes in vite.config.js - Update import statements and string literals in index.ts and ui.ts - Maintain consistent code style and formatting - Improve code readability and consistency --- src/index.ts | 88 ++++++++++++++++++++++++------------------------- src/ui.ts | 50 ++++++++++++++-------------- src/uploader.ts | 2 +- vite.config.js | 14 ++++---- 4 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9f02d678..043f172a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,7 +28,7 @@ * }, */ -import type { TunesMenuConfig } from "@editorjs/editorjs/types/tools"; +import type { TunesMenuConfig } from '@editorjs/editorjs/types/tools'; import type { API, ToolboxConfig, @@ -39,11 +39,11 @@ import type { PasteEvent, PatternPasteEventDetail, FilePasteEventDetail, -} from "@editorjs/editorjs"; -import "./index.css"; +} from '@editorjs/editorjs'; +import './index.css'; -import Ui from "./ui"; -import Uploader from "./uploader"; +import Ui from './ui'; +import Uploader from './uploader'; import { IconAddBorder, @@ -51,7 +51,7 @@ import { IconAddBackground, IconPicture, IconText, -} from "@codexteam/icons"; +} from '@codexteam/icons'; import type { ActionConfig, UploadResponseFormat, @@ -60,7 +60,7 @@ import type { HTMLPasteEventDetailExtended, ImageSetterParam, FeaturesConfig, -} from "./types/types"; +} from './types/types'; /** * Constructor options for ImageTool @@ -140,7 +140,7 @@ export default class ImageTool implements BlockTool { field: config.field, types: config.types, captionPlaceholder: this.api.i18n.t( - config.captionPlaceholder ?? "Caption" + config.captionPlaceholder ?? 'Caption' ), buttonContent: config.buttonContent, uploader: config.uploader, @@ -203,7 +203,7 @@ export default class ImageTool implements BlockTool { public static get toolbox(): ToolboxConfig { return { icon: IconPicture, - title: "Image", + title: 'Image', }; } @@ -213,21 +213,21 @@ export default class ImageTool implements BlockTool { public static get tunes(): Array { return [ { - name: "withBorder", + name: 'withBorder', icon: IconAddBorder, - title: "With border", + title: 'With border', toggle: true, }, { - name: "stretched", + name: 'stretched', icon: IconStretch, - title: "Stretch image", + title: 'Stretch image', toggle: true, }, { - name: "withBackground", + name: 'withBackground', icon: IconAddBackground, - title: "With background", + title: 'With background', toggle: true, }, ]; @@ -240,7 +240,7 @@ export default class ImageTool implements BlockTool { if ( this.config.features?.caption === true || this.config.features?.caption === undefined || - (this.config.features?.caption === "optional" && this.data.caption) + (this.config.features?.caption === 'optional' && this.data.caption) ) { this.isCaptionEnabled = true; } @@ -277,17 +277,17 @@ export default class ImageTool implements BlockTool { // @see https://github.com/editor-js/image/pull/49 const tunes = ImageTool.tunes.concat(this.config.actions || []); const featureTuneMap: Record = { - border: "withBorder", - background: "withBackground", - stretch: "stretched", - caption: "caption", + border: 'withBorder', + background: 'withBackground', + stretch: 'stretched', + caption: 'caption', }; - if (this.config.features?.caption === "optional") { + if (this.config.features?.caption === 'optional') { tunes.push({ - name: "caption", + name: 'caption', icon: IconText, - title: "With caption", + title: 'With caption', toggle: true, }); } @@ -297,7 +297,7 @@ export default class ImageTool implements BlockTool { (key) => featureTuneMap[key] === tune.name ); - if (featureKey === "caption") { + if (featureKey === 'caption') { return this.config.features?.caption !== false; } @@ -314,7 +314,7 @@ export default class ImageTool implements BlockTool { const isActive = (tune: ActionConfig): boolean => { let currentState = this.data[tune.name as keyof ImageToolData] as boolean; - if (tune.name === "caption") { + if (tune.name === 'caption') { currentState = this.isCaptionEnabled ?? currentState; } @@ -329,7 +329,7 @@ export default class ImageTool implements BlockTool { isActive: isActive(tune), onActivate: () => { /** If it'a user defined tune, execute it's callback stored in action property */ - if (typeof tune.action === "function") { + if (typeof tune.action === 'function') { tune.action(tune.name); return; @@ -340,7 +340,7 @@ export default class ImageTool implements BlockTool { * For the caption tune, we can't rely on the this._data * because it can be manualy toggled by user */ - if (tune.name === "caption") { + if (tune.name === 'caption') { this.isCaptionEnabled = !(this.isCaptionEnabled ?? false); newState = this.isCaptionEnabled; } @@ -383,7 +383,7 @@ export default class ImageTool implements BlockTool { * Drag n drop file from into the Editor */ files: { - mimeTypes: ["image/*"], + mimeTypes: ['image/*'], }, }; } @@ -396,7 +396,7 @@ export default class ImageTool implements BlockTool { */ public async onPaste(event: PasteEvent): Promise { switch (event.type) { - case "tag": { + case 'tag': { const image = (event.detail as HTMLPasteEventDetailExtended).data; /** Images from PDF */ @@ -412,13 +412,13 @@ export default class ImageTool implements BlockTool { this.uploadUrl(image.src); break; } - case "pattern": { + case 'pattern': { const url = (event.detail as PatternPasteEventDetail).data; this.uploadUrl(url); break; } - case "file": { + case 'file': { const file = (event.detail as FilePasteEventDetail).file; this.uploadFile(file); @@ -439,21 +439,21 @@ export default class ImageTool implements BlockTool { private set data(data: ImageToolData) { this.image = data.file; - this._data.caption = data.caption || ""; + 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" + typeof data[tune as keyof ImageToolData] !== 'undefined' ? data[tune as keyof ImageToolData] === true || - data[tune as keyof ImageToolData] === "true" + data[tune as keyof ImageToolData] === 'true' : false; this.setTune(tune as keyof ImageToolData, value); }); if (data.caption) { - this.setTune("caption", true); + this.setTune('caption', true); } } @@ -469,7 +469,7 @@ export default class ImageTool implements BlockTool { * @param file - uploaded file data */ private set image(file: ImageSetterParam | undefined) { - this._data.file = file || { url: "" }; + this._data.file = file || { url: '' }; if (file && file.url) { this.ui.fillImage(file.url); @@ -484,7 +484,7 @@ export default class ImageTool implements BlockTool { if (response.success && Boolean(response.file)) { this.image = response.file; } else { - this.uploadingFailed("incorrect response: " + JSON.stringify(response)); + this.uploadingFailed('incorrect response: ' + JSON.stringify(response)); } } @@ -493,11 +493,11 @@ export default class ImageTool implements BlockTool { * @param errorText - uploading error info */ private uploadingFailed(errorText: string): void { - console.log("Image Tool: uploading failed because of", errorText); + console.log('Image Tool: uploading failed because of', errorText); this.api.notifier.show({ - message: this.api.i18n.t("Couldn’t upload image. Please try another."), - style: "error", + message: this.api.i18n.t('Couldn't upload image. Please try another.'), + style: 'error', }); this.ui.hidePreloader(); } @@ -508,12 +508,12 @@ export default class ImageTool implements BlockTool { * @param state - new state */ private tuneToggled(tuneName: keyof ImageToolData, state: boolean): void { - if (tuneName === "caption") { + if (tuneName === 'caption') { this.ui.applyTune(tuneName, state); if (state == false) { - this._data.caption = ""; - this.ui.fillCaption(""); + this._data.caption = ''; + this.ui.fillCaption(''); } } else { /** @@ -532,7 +532,7 @@ export default class ImageTool implements BlockTool { (this._data[tuneName] as boolean) = value; this.ui.applyTune(tuneName, value); - if (tuneName === "stretched") { + if (tuneName === 'stretched') { /** * Wait until the API is ready */ diff --git a/src/ui.ts b/src/ui.ts index 8d965ae8..44410475 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 type { ImageConfig } from "./types/types"; +import { IconPicture } from '@codexteam/icons'; +import { make } from './utils/dom'; +import type { API } from '@editorjs/editorjs'; +import type { ImageConfig } from './types/types'; /** * Enumeration representing the different states of the UI. @@ -10,17 +10,17 @@ export enum UiState { /** * The UI is in an empty state, with no image loaded or being selected. */ - Empty = "empty", + Empty = 'empty', /** * The UI is in an uploading state, indicating an image is currently being uploaded. */ - Uploading = "uploading", + Uploading = 'uploading', /** * The UI is in a filled state, with an image successfully loaded. */ - Filled = "filled", + Filled = 'filled', } /** @@ -125,12 +125,12 @@ export default class Ui { this.onSelectFile = onSelectFile; this.readOnly = readOnly; this.nodes = { - wrapper: make("div", [this.CSS.baseClass, this.CSS.wrapper]), - imageContainer: make("div", [this.CSS.imageContainer]), + wrapper: make('div', [this.CSS.baseClass, this.CSS.wrapper]), + imageContainer: make('div', [this.CSS.imageContainer]), fileButton: this.createFileButton() as HTMLButtonElement, imageEl: undefined, - imagePreloader: make("div", this.CSS.imagePreloader), - caption: make("div", [this.CSS.input, this.CSS.caption], { + imagePreloader: make('div', this.CSS.imagePreloader), + caption: make('div', [this.CSS.input, this.CSS.caption], { contentEditable: !this.readOnly, }), }; @@ -187,7 +187,7 @@ export default class Ui { * Hide uploading preloader */ public hidePreloader(): void { - this.nodes.imagePreloader.style.backgroundImage = ""; + this.nodes.imagePreloader.style.backgroundImage = ''; this.toggleStatus(UiState.Empty); } @@ -199,7 +199,7 @@ export default class Ui { /** * Check for a source extension to compose element correctly: video tag for mp4, img — for others */ - const tag = /\.mp4$/.test(url) ? "VIDEO" : "IMG"; + const tag = /\.mp4$/.test(url) ? 'VIDEO' : 'IMG'; const attributes: { [key: string]: string | boolean } = { src: url, @@ -210,12 +210,12 @@ export default class Ui { * - IMG: load * - VIDEO: loadeddata */ - let eventName = "load"; + let eventName = 'load'; /** * Update attributes and eventName if source is a mp4 video */ - if (tag === "VIDEO") { + if (tag === 'VIDEO') { /** * Add attributes for playing muted mp4 as a gif */ @@ -227,7 +227,7 @@ export default class Ui { /** * Change event to be listened */ - eventName = "loadeddata"; + eventName = 'loadeddata'; } /** @@ -245,7 +245,7 @@ export default class Ui { * Preloader does not exists on first rendering with presaved data */ if (this.nodes.imagePreloader !== undefined) { - this.nodes.imagePreloader.style.backgroundImage = ""; + this.nodes.imagePreloader.style.backgroundImage = ''; } }); @@ -292,11 +292,11 @@ export default class Ui { /** * Tool's classes */ - wrapper: "image-tool", - imageContainer: "image-tool__image", - imagePreloader: "image-tool__image-preloader", - imageEl: "image-tool__image-picture", - caption: "image-tool__caption", + wrapper: 'image-tool', + imageContainer: 'image-tool__image', + imagePreloader: 'image-tool__image-preloader', + imageEl: 'image-tool__image-picture', + caption: 'image-tool__caption', }; } @@ -304,13 +304,13 @@ export default class Ui { * Creates upload-file button */ private createFileButton(): HTMLElement { - const button = make("div", [this.CSS.button]); + const button = make('div', [this.CSS.button]); button.innerHTML = this.config.buttonContent ?? - `${IconPicture} ${this.api.i18n.t("Select an Image")}`; + `${IconPicture} ${this.api.i18n.t('Select an Image')}`; - button.addEventListener("click", () => { + button.addEventListener('click', () => { this.onSelectFile(); }); diff --git a/src/uploader.ts b/src/uploader.ts index 4458472c..6ba21231 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -1,4 +1,4 @@ -import ajax from "@codexteam/ajax"; +import ajax from '@codexteam/ajax'; import type { AjaxResponse } from "@codexteam/ajax"; import isPromise from "./utils/isPromise"; import type { UploadOptions } from "./types/types"; diff --git a/vite.config.js b/vite.config.js index e47a226a..82bcb6a7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,18 +1,18 @@ -import path from "path"; -import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; +import path from 'path'; +import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; import dts from 'vite-plugin-dts'; -import * as pkg from "./package.json"; +import * as pkg from './package.json'; -const NODE_ENV = process.argv.mode || "development"; +const NODE_ENV = process.argv.mode || 'development'; const VERSION = pkg.version; export default { build: { copyPublicDir: false, lib: { - entry: path.resolve(__dirname, "src", "index.ts"), - name: "ImageTool", - fileName: "image", + entry: path.resolve(__dirname, 'src', 'index.ts'), + name: 'ImageTool', + fileName: 'image', formats: ['es', 'umd'] }, sourcemap: true, From b3320408ae2330ea31a35f4846de3f08d1dc6bce Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:21:29 +0530 Subject: [PATCH 10/14] fix: handle optional byFile endpoint and improve type safety in uploader - Add null coalescing for byFile endpoint URL - Improve type casting for additional request data - Ensure type safety when appending form data --- src/uploader.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uploader.ts b/src/uploader.ts index 6ba21231..603549e4 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -1,4 +1,4 @@ -import ajax from '@codexteam/ajax'; +import ajax from "@codexteam/ajax"; import type { AjaxResponse } from "@codexteam/ajax"; import isPromise from "./utils/isPromise"; import type { UploadOptions } from "./types/types"; @@ -98,7 +98,7 @@ export default class Uploader { } else { upload = ajax .transport({ - url: this.config.endpoints.byFile, + url: this.config.endpoints.byFile ?? "", data: this.config.additionalRequestData, accept: this.config.types ?? "image/*", headers: this.config.additionalRequestHeaders as Record< @@ -229,15 +229,15 @@ export default class Uploader { Object.keys(this.config.additionalRequestData).length ) { Object.entries(this.config.additionalRequestData).forEach( - ([name, value]: [string, string | Blob]) => { - formData.append(name, value); + ([name, value]) => { + formData.append(name, value as string | Blob); } ); } upload = ajax .post({ - url: this.config.endpoints.byFile, + url: this.config.endpoints.byFile ?? "", data: formData, type: ajax.contentType.JSON, headers: this.config.additionalRequestHeaders as Record< From 2aae5691a1fce70f7fb2c7f50fdf40338f5a3f76 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:23:20 +0530 Subject: [PATCH 11/14] eslint changed them again , fix it now --- src/uploader.ts | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/uploader.ts b/src/uploader.ts index 603549e4..8e30675f 100644 --- a/src/uploader.ts +++ b/src/uploader.ts @@ -1,8 +1,8 @@ -import ajax from "@codexteam/ajax"; -import type { AjaxResponse } from "@codexteam/ajax"; -import isPromise from "./utils/isPromise"; -import type { UploadOptions } from "./types/types"; -import type { UploadResponseFormat, ImageConfig } from "./types/types"; +import ajax from '@codexteam/ajax'; +import type { AjaxResponse } from '@codexteam/ajax'; +import isPromise from './utils/isPromise'; +import type { UploadOptions } from './types/types'; +import type { UploadResponseFormat, ImageConfig } from './types/types'; /** * Params interface for Uploader constructor @@ -74,12 +74,12 @@ export default class Uploader { // custom uploading if ( this.config.uploader && - typeof this.config.uploader.uploadByFile === "function" + typeof this.config.uploader.uploadByFile === 'function' ) { const uploadByFile = this.config.uploader.uploadByFile; upload = ajax - .selectFiles({ accept: this.config.types ?? "image/*" }) + .selectFiles({ accept: this.config.types ?? 'image/*' }) .then((files: File[]) => { preparePreview(files[0]); @@ -87,7 +87,7 @@ export default class Uploader { if (!isPromise(customUpload)) { console.warn( - "Custom uploader method uploadByFile should return a Promise" + 'Custom uploader method uploadByFile should return a Promise' ); } @@ -98,9 +98,9 @@ export default class Uploader { } else { upload = ajax .transport({ - url: this.config.endpoints.byFile ?? "", + url: this.config.endpoints.byFile ?? '', data: this.config.additionalRequestData, - accept: this.config.types ?? "image/*", + accept: this.config.types ?? 'image/*', headers: this.config.additionalRequestHeaders as Record< string, string @@ -108,7 +108,7 @@ export default class Uploader { beforeSend: (files: File[]) => { preparePreview(files[0]); }, - fieldName: this.config.field ?? "image", + fieldName: this.config.field ?? 'image', }) .then( (response: AjaxResponse) => response.body as UploadResponseFormat @@ -138,13 +138,13 @@ export default class Uploader { */ if ( this.config.uploader && - typeof this.config.uploader.uploadByUrl === "function" + typeof this.config.uploader.uploadByUrl === 'function' ) { upload = this.config.uploader.uploadByUrl(url); if (!isPromise(upload)) { console.warn( - "Custom uploader method uploadByUrl should return a Promise" + 'Custom uploader method uploadByUrl should return a Promise' ); } } else { @@ -153,7 +153,7 @@ export default class Uploader { */ upload = ajax .post({ - url: this.config.endpoints.byUrl, + url: this.config.endpoints.byUrl ?? '', data: Object.assign( { url: url, @@ -205,15 +205,15 @@ export default class Uploader { */ if ( this.config.uploader && - typeof this.config.uploader.uploadByFile === "function" + typeof this.config.uploader.uploadByFile === 'function' ) { // Convert Blob to File with a dummy filename - const fileObj = new File([file], "pasted-image", { type: file.type }); + const fileObj = new File([file], 'pasted-image', { type: file.type }); upload = this.config.uploader.uploadByFile(fileObj); if (!isPromise(upload)) { console.warn( - "Custom uploader method uploadByFile should return a Promise" + 'Custom uploader method uploadByFile should return a Promise' ); } } else { @@ -222,7 +222,7 @@ export default class Uploader { */ const formData = new FormData(); - formData.append(this.config.field ?? "image", file); + formData.append(this.config.field ?? 'image', file); if ( this.config.additionalRequestData && @@ -237,7 +237,7 @@ export default class Uploader { upload = ajax .post({ - url: this.config.endpoints.byFile ?? "", + url: this.config.endpoints.byFile ?? '', data: formData, type: ajax.contentType.JSON, headers: this.config.additionalRequestHeaders as Record< From d5523f24fa9b1049d4f2d75afee832bbad15e6f2 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:30:42 +0530 Subject: [PATCH 12/14] chore: remove redundant TypeScript type declarations file - Delete src/types/index.d.ts type declaration file - Remove unnecessary type definitions for ImageTool --- src/types/index.d.ts | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/types/index.d.ts diff --git a/src/types/index.d.ts b/src/types/index.d.ts deleted file mode 100644 index c394f353..00000000 --- a/src/types/index.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Type declarations for the Editor.js Image Tool - * This file defines the public TypeScript interface for the Image Tool plugin, - * providing type definitions and ensuring type safety for TypeScript users. - */ -import type { BlockTool, BlockToolConstructorOptions } from '@editorjs/editorjs'; -import type { ImageToolData, ImageConfig } from './types'; - -declare class ImageTool implements BlockTool { - constructor(options: BlockToolConstructorOptions); - - static get isReadOnlySupported(): boolean; - static get toolbox(): { icon: string; title: string; }; - static get tunes(): Array<{ - name: string; - icon: string; - title: string; - toggle?: boolean; - }>; - - render(): HTMLElement; - save(): ImageToolData; - validate(savedData: ImageToolData): boolean; - - onPaste(event: CustomEvent): Promise; -} - -export default ImageTool; \ No newline at end of file From 96539124ecc8ba5ae2470a8dd3b7c422051b0b80 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:33:43 +0530 Subject: [PATCH 13/14] using single quote here was making build fail. changed it to "". --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 043f172a..64038bc9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -496,7 +496,7 @@ export default class ImageTool implements BlockTool { console.log('Image Tool: uploading failed because of', errorText); this.api.notifier.show({ - message: this.api.i18n.t('Couldn't upload image. Please try another.'), + message: this.api.i18n.t("Couldn't upload image. Please try another."), style: 'error', }); this.ui.hidePreloader(); From dc1b20fa6066e36ea6f67b194360b9f3730d7423 Mon Sep 17 00:00:00 2001 From: AMRIK Date: Fri, 14 Feb 2025 19:40:51 +0530 Subject: [PATCH 14/14] reverted byUrl to optional field --- src/types/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/types.ts b/src/types/types.ts index acfb315b..4688403a 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -140,7 +140,7 @@ export interface ImageConfig { /** * Endpoints for URL upload. */ - byUrl: string; + byUrl?: string; }; /**