diff --git a/README.md b/README.md index a0d59f39..39e29a2d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Image Block for the [Editor.js](https://editorjs.io). - Pasting copied content from the web - Pasting images by drag-n-drop - Pasting files and screenshots from Clipboard -- Allows adding a border, and a background +- Allows adding a border, a background and a caption - Allows stretching an image to the container's full-width **Notes** @@ -83,6 +83,7 @@ Image Tool supports these configuration parameters: | buttonContent | `string` | Allows to override HTML content of «Select file» button | | uploader | `{{uploadByFile: function, uploadByUrl: function}}` | Optional custom uploading methods. See details below. | | actions | `array` | Array with custom actions to show in the tool's settings menu. See details below. | +| features | `object` | Allows you to enable/disable additional features such as border, background tunes and caption. See details below. | Note that if you don't implement your custom uploader methods, the `endpoints` param is required. @@ -96,6 +97,8 @@ Note that if you don't implement your custom uploader methods, the `endpoints` p 3. Add background +4. Add caption + Add extra setting-buttons by adding them to the `actions`-array in the configuration: ```js actions: [ @@ -113,6 +116,17 @@ actions: [ **_NOTE:_** return value of `action` callback for settings whether action button should be toggled or not is *deprecated*. Consider using `toggle` option instead. +You can disable features such as border, background tunes and caption by defining `features` in the configuration: +```js +features: { + border: false, + caption: 'optional', + stretch: false +} +``` + +**_NOTE:_** set caption to `optional` in order to configure caption as a tune. + ## Output data This Tool returns `data` with following format @@ -136,7 +150,7 @@ This Tool returns `data` with following format "caption" : "Roadster // tesla.com", "withBorder" : false, "withBackground" : false, - "stretched" : true + "stretched" : true, } } ``` diff --git a/dev/index.html b/dev/index.html new file mode 100644 index 00000000..f9495ce7 --- /dev/null +++ b/dev/index.html @@ -0,0 +1,35 @@ + + + + + + Image Plugin Test | EditorJS + + +
+ + + + + diff --git a/package.json b/package.json index 7b27d495..5f75a71d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@editorjs/image", - "version": "2.9.3", + "version": "2.10.0", "keywords": [ "codex editor", "image", diff --git a/src/index.css b/src/index.css index 2823c160..82331659 100644 --- a/src/index.css +++ b/src/index.css @@ -44,6 +44,8 @@ } &__caption { + display: none; + &[contentEditable="true"][data-placeholder]::before { position: absolute !important; content: attr(data-placeholder); @@ -86,7 +88,7 @@ margin: 0 6px 0 0; } } - + &--filled { .cdx-button { display: none; @@ -147,13 +149,19 @@ } } + &--caption { + ^&__caption { + display: block; + } + } } @keyframes image-preloader-spin { 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 7c7145aa..de1bece8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,6 @@ * 1) index.ts — main Tool's interface, public API and methods for working with data * 2) uploader.ts — module that has methods for sending files via AJAX: from device, by URL or File pasting * 3) ui.ts — module for UI manipulations: render, showing preloader, etc - * 4) tunes.js — working with Block Tunes: render buttons, handle clicks * * For debug purposes there is a testing server * that can save uploaded files and return a Response {@link UploadResponseFormat} @@ -36,8 +35,8 @@ import './index.css'; import Ui from './ui'; import Uploader from './uploader'; -import { IconAddBorder, IconStretch, IconAddBackground, IconPicture } from '@codexteam/icons'; -import type { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, HTMLPasteEventDetailExtended, ImageSetterParam } from './types/types'; +import { IconAddBorder, IconStretch, IconAddBackground, IconPicture, IconText } from '@codexteam/icons'; +import type { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, HTMLPasteEventDetailExtended, ImageSetterParam, FeaturesConfig } from './types/types'; type ImageToolConstructorOptions = BlockToolConstructorOptions; @@ -50,11 +49,6 @@ export default class ImageTool implements BlockTool { */ private api: API; - /** - * Flag indicating read-only mode - */ - private readOnly: boolean; - /** * Current Block API instance */ @@ -90,7 +84,6 @@ export default class ImageTool implements BlockTool { */ constructor({ data, config, api, readOnly, block }: ImageToolConstructorOptions) { this.api = api; - this.readOnly = readOnly; this.block = block; /** @@ -106,6 +99,7 @@ export default class ImageTool implements BlockTool { buttonContent: config.buttonContent, uploader: config.uploader, actions: config.actions, + features: config.features || {}, }; /** @@ -197,6 +191,10 @@ 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)) { + this.ui.applyTune('caption', true); + } + return this.ui.render(this.data) as HTMLDivElement; } @@ -228,8 +226,33 @@ export default class ImageTool implements BlockTool { // Merge default tunes with the ones that might be added by user // @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', + }; + + if (this.config.features?.caption === 'optional') { + tunes.push({ + name: 'caption', + icon: IconText, + title: 'With caption', + toggle: true, + }); + } + + const availableTunes = tunes.filter((tune) => { + const featureKey = Object.keys(featureTuneMap).find(key => featureTuneMap[key] === tune.name); + + if (featureKey === 'caption') { + return this.config.features?.caption !== false; + } - return tunes.map(tune => ({ + return featureKey == null || this.config.features?.[featureKey as keyof FeaturesConfig] !== false; + }); + + return availableTunes.map(tune => ({ icon: tune.icon, label: this.api.i18n.t(tune.title), name: tune.name, @@ -398,6 +421,12 @@ export default class ImageTool implements BlockTool { private tuneToggled(tuneName: keyof ImageToolData): void { // inverse tune state this.setTune(tuneName, !(this._data[tuneName] as boolean)); + + // reset caption on toggle + if (tuneName === 'caption' && !this._data[tuneName]) { + this._data.caption = ''; + this.ui.fillCaption(''); + } } /** diff --git a/src/types/types.ts b/src/types/types.ts index 6b4da7e7..3de55056 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -100,6 +100,29 @@ export type ImageToolData = { } & AdditionalFileData; } & (Actions extends Record ? Actions : {}); +/** + * @description Allows to enable or disable features. + */ +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 + */ + stretch?: boolean; +}; + /** * * @description Config supported by Tool @@ -171,6 +194,11 @@ export interface ImageConfig { * Additional actions for the tool. */ actions?: ActionConfig[]; + + /** + * Tunes to be enabled. + */ + features?: FeaturesConfig; } /**