Skip to content

Commit

Permalink
Merge pull request #108 from dependentmadani/migrate-typescript
Browse files Browse the repository at this point in the history
fix (fixing an issue): migrate to typescript
  • Loading branch information
neSpecc authored Jun 15, 2024
2 parents 5118ce8 + ae936f1 commit 477853c
Show file tree
Hide file tree
Showing 6 changed files with 720 additions and 81 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
],
"main": "./dist/header.umd.js",
"module": "./dist/header.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/header.mjs",
Expand All @@ -30,10 +31,13 @@
"email": "[email protected]"
},
"devDependencies": {
"typescript": "^5.4.5",
"vite": "^4.5.0",
"vite-plugin-css-injected-by-js": "^3.3.0"
"vite-plugin-css-injected-by-js": "^3.3.0",
"vite-plugin-dts": "^3.9.1"
},
"dependencies": {
"@codexteam/icons": "^0.0.5"
"@codexteam/icons": "^0.0.5",
"@editorjs/editorjs": "^2.29.1"
}
}
217 changes: 140 additions & 77 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,55 @@
import './index.css';

import { IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconHeading } from '@codexteam/icons';
import { API, BlockTune, PasteEvent } from '@editorjs/editorjs';

/**
* @typedef {object} HeaderData
* @description Tool's input and output data format
* @property {string} text — Header's content
* @property {number} level - Header's level from 1 to 6
*/
* @description Tool's input and output data format
*/
export interface HeaderData {
/** Header's content */
text: string;
/** Header's level from 1 to 6 */
level: number;
}

/**
* @typedef {object} HeaderConfig
* @description Tool's config from Editor
* @property {string} placeholder — Block's placeholder
* @property {number[]} levels — Heading levels
* @property {number} defaultLevel — default level
*/
export interface HeaderConfig {
/** Block's placeholder */
placeholder?: string;
/** Heading levels */
levels?: number[];
/** Default level */
defaultLevel?: number;
}

/**
* @description Heading level information
*/
interface Level {
/** Level number */
number: number;
/** HTML tag corresponding with level number */
tag: string;
/** Icon */
svg: string;
}

/**
* @description Constructor arguments for Header
*/
interface ConstructorArgs {
/** Previously saved data */
data: HeaderData;
/** User config for the tool */
config: HeaderConfig;
/** Editor.js API */
api: API;
/** Read-only mode flag */
readOnly: boolean;
}

/**
* Header block for the Editor.js.
Expand All @@ -38,20 +72,36 @@ export default class Header {
* api - Editor.js API
* readOnly - read only mode flag
*/
constructor({ data, config, api, readOnly }) {
/**
* Editor.js API
* @private
*/
private api: API;
/**
* Read-only mode flag
* @private
*/
private readOnly: boolean;
/**
* Tool's settings passed from Editor
* @private
*/
private _settings: HeaderConfig;
/**
* Block's data
* @private
*/
private _data: HeaderData;
/**
* Main Block wrapper
* @private
*/
private _element: HTMLHeadingElement;

constructor({ data, config, api, readOnly }: ConstructorArgs) {
this.api = api;
this.readOnly = readOnly;

/**
* Styles
*
* @type {object}
*/
this._CSS = {
block: this.api.styles.block,
wrapper: 'ce-header',
};

/**
* Tool's settings passed from Editor
*
Expand All @@ -76,6 +126,15 @@ export default class Header {
*/
this._element = this.getTag();
}
/**
* Styles
*/
private get _CSS() {
return {
block: this.api.styles.block,
wrapper: 'ce-header',
};
}

/**
* Normalize input data
Expand All @@ -85,15 +144,15 @@ export default class Header {
* @returns {HeaderData}
* @private
*/
normalizeData(data) {
const newData = {};
normalizeData(data: HeaderData): HeaderData {
const newData: HeaderData = {text: '', level: this.defaultLevel.number };

if (typeof data !== 'object') {
data = {};
data = {} as HeaderData;
}

newData.text = data.text || '';
newData.level = parseInt(data.level) || this.defaultLevel.number;
newData.level = parseInt(data.level.toString()) || this.defaultLevel.number;

return newData;
}
Expand All @@ -104,7 +163,7 @@ export default class Header {
* @returns {HTMLHeadingElement}
* @public
*/
render() {
render(): HTMLHeadingElement {
return this._element;
}

Expand All @@ -113,13 +172,14 @@ export default class Header {
*
* @returns {Array}
*/
renderSettings() {
renderSettings(): BlockTune[] {
return this.levels.map(level => ({
icon: level.svg,
label: this.api.i18n.t(`Heading ${level.number}`),
onActivate: () => this.setLevel(level.number),
closeOnActivate: true,
isActive: this.currentLevel.number === level.number,
render: () => document.createElement('div')
}));
}

Expand All @@ -128,7 +188,7 @@ export default class Header {
*
* @param {number} level - level to set
*/
setLevel(level) {
setLevel(level: number): void {
this.data = {
level: level,
text: this.data.text,
Expand All @@ -142,7 +202,7 @@ export default class Header {
* @param {HeaderData} data - saved data to merger with current block
* @public
*/
merge(data) {
merge(data: HeaderData): void {
const newData = {
text: this.data.text + data.text,
level: this.data.level,
Expand All @@ -159,7 +219,7 @@ export default class Header {
* @returns {boolean} false if saved data is not correct, otherwise true
* @public
*/
validate(blockData) {
validate(blockData: HeaderData): boolean {
return blockData.text.trim() !== '';
}

Expand All @@ -170,7 +230,7 @@ export default class Header {
* @returns {HeaderData} - saved data
* @public
*/
save(toolsContent) {
save(toolsContent: HTMLHeadingElement): HeaderData {
return {
text: toolsContent.innerHTML,
level: this.currentLevel.number,
Expand Down Expand Up @@ -212,7 +272,7 @@ export default class Header {
* @returns {HeaderData} Current data
* @private
*/
get data() {
get data(): HeaderData {
this._data.text = this._element.innerHTML;
this._data.level = this.currentLevel.number;

Expand All @@ -227,7 +287,7 @@ export default class Header {
* @param {HeaderData} data — data to set
* @private
*/
set data(data) {
set data(data: HeaderData) {
this._data = this.normalizeData(data);

/**
Expand Down Expand Up @@ -275,11 +335,11 @@ export default class Header {
*
* @returns {HTMLElement}
*/
getTag() {
getTag(): HTMLHeadingElement {
/**
* Create element for current Block's level
*/
const tag = document.createElement(this.currentLevel.tag);
const tag = document.createElement(this.currentLevel.tag) as HTMLHeadingElement;

/**
* Add text to block
Expand Down Expand Up @@ -309,7 +369,7 @@ export default class Header {
*
* @returns {level}
*/
get currentLevel() {
get currentLevel(): Level {
let level = this.levels.find(levelItem => levelItem.number === this._data.level);

if (!level) {
Expand All @@ -324,7 +384,7 @@ export default class Header {
*
* @returns {level}
*/
get defaultLevel() {
get defaultLevel(): Level {
/**
* User can specify own default level value
*/
Expand Down Expand Up @@ -360,7 +420,7 @@ export default class Header {
*
* @returns {level[]}
*/
get levels() {
get levels(): Level[] {
const availableLevels = [
{
number: 1,
Expand Down Expand Up @@ -395,7 +455,7 @@ export default class Header {
];

return this._settings.levels ? availableLevels.filter(
l => this._settings.levels.includes(l.number)
l => this._settings.levels!.includes(l.number)
) : availableLevels;
}

Expand All @@ -404,48 +464,51 @@ export default class Header {
*
* @param {PasteEvent} event - event with pasted content
*/
onPaste(event) {
const content = event.detail.data;
onPaste(event: PasteEvent): void {
const detail = event.detail;

/**
* Define default level value
*
* @type {number}
*/
let level = this.defaultLevel.number;

switch (content.tagName) {
case 'H1':
level = 1;
break;
case 'H2':
level = 2;
break;
case 'H3':
level = 3;
break;
case 'H4':
level = 4;
break;
case 'H5':
level = 5;
break;
case 'H6':
level = 6;
break;
}
if ('data' in detail) {
const content = detail.data as HTMLElement;
/**
* Define default level value
*
* @type {number}
*/
let level = this.defaultLevel.number;

switch (content.tagName) {
case 'H1':
level = 1;
break;
case 'H2':
level = 2;
break;
case 'H3':
level = 3;
break;
case 'H4':
level = 4;
break;
case 'H5':
level = 5;
break;
case 'H6':
level = 6;
break;
}

if (this._settings.levels) {
// Fallback to nearest level when specified not available
level = this._settings.levels.reduce((prevLevel, currLevel) => {
return Math.abs(currLevel - level) < Math.abs(prevLevel - level) ? currLevel : prevLevel;
});
}
if (this._settings.levels) {
// Fallback to nearest level when specified not available
level = this._settings.levels.reduce((prevLevel, currLevel) => {
return Math.abs(currLevel - level) < Math.abs(prevLevel - level) ? currLevel : prevLevel;
});
}

this.data = {
level,
text: content.innerHTML,
};
this.data = {
level,
text: content.innerHTML,
};
}
}

/**
Expand Down
Loading

0 comments on commit 477853c

Please sign in to comment.