mirror of
https://github.com/codex-team/editor.js
synced 2026-03-17 16:10:07 +01:00
fix: left typescript errors
This commit is contained in:
parent
b677b63eeb
commit
1d6d0a477e
4 changed files with 350 additions and 18 deletions
|
|
@ -37,7 +37,7 @@ export default class MoveDownTune implements BlockTune {
|
|||
*
|
||||
* @param {API} api — Editor's API
|
||||
*/
|
||||
constructor({ api }) {
|
||||
constructor({ api }: { api: API }) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
|
|
@ -68,15 +68,9 @@ export default class MoveDownTune implements BlockTune {
|
|||
const nextBlockElement = nextBlock.holder;
|
||||
const nextBlockCoords = nextBlockElement.getBoundingClientRect();
|
||||
|
||||
let scrollOffset = Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
|
||||
|
||||
/**
|
||||
* Next block ends on screen.
|
||||
* Increment scroll by next block's height to save element onscreen-position
|
||||
*/
|
||||
if (nextBlockCoords.top < window.innerHeight) {
|
||||
scrollOffset = window.scrollY + nextBlockElement.offsetHeight;
|
||||
}
|
||||
const scrollOffset = nextBlockCoords.top < window.innerHeight
|
||||
? window.scrollY + nextBlockElement.offsetHeight
|
||||
: Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
|
||||
|
||||
window.scrollTo(0, scrollOffset);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export default class MoveUpTune implements BlockTune {
|
|||
*
|
||||
* @param {API} api - Editor's API
|
||||
*/
|
||||
constructor({ api }) {
|
||||
constructor({ api }: { api: API }) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
|
|
@ -77,13 +77,9 @@ export default class MoveUpTune implements BlockTune {
|
|||
const currentBlockCoords = currentBlockElement.getBoundingClientRect();
|
||||
const previousBlockCoords = previousBlockElement.getBoundingClientRect();
|
||||
|
||||
let scrollUpOffset;
|
||||
|
||||
if (previousBlockCoords.top > 0) {
|
||||
scrollUpOffset = Math.abs(currentBlockCoords.top) - Math.abs(previousBlockCoords.top);
|
||||
} else {
|
||||
scrollUpOffset = Math.abs(currentBlockCoords.top) + previousBlockCoords.height;
|
||||
}
|
||||
const scrollUpOffset = previousBlockCoords.top > 0
|
||||
? Math.abs(currentBlockCoords.top) - Math.abs(previousBlockCoords.top)
|
||||
: Math.abs(currentBlockCoords.top) + previousBlockCoords.height;
|
||||
|
||||
window.scrollBy(0, -1 * scrollUpOffset);
|
||||
|
||||
|
|
|
|||
166
test/unit/components/block-tunes/block-tune-move-down.test.ts
Normal file
166
test/unit/components/block-tunes/block-tune-move-down.test.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
import { IconChevronDown } from '@codexteam/icons';
|
||||
import type { Mock } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import MoveDownTune from '../../../../src/components/block-tunes/block-tune-move-down';
|
||||
import type { API } from '../../../../types';
|
||||
import type { PopoverItemDefaultBaseParams } from '../../../../types/utils/popover';
|
||||
|
||||
type BlocksMocks = {
|
||||
getCurrentBlockIndex: Mock<[], number>;
|
||||
getBlockByIndex: Mock<[number], { holder: HTMLElement } | undefined>;
|
||||
move: Mock<[number], void>;
|
||||
};
|
||||
|
||||
type ToolbarMocks = {
|
||||
toggleBlockSettings: Mock<[boolean], void>;
|
||||
};
|
||||
|
||||
type I18nMocks = {
|
||||
t: Mock<[string], string>;
|
||||
};
|
||||
|
||||
const createApiMocks = (): {
|
||||
api: API;
|
||||
blocks: BlocksMocks;
|
||||
toolbar: ToolbarMocks;
|
||||
i18n: I18nMocks;
|
||||
} => {
|
||||
const blocks: BlocksMocks = {
|
||||
getCurrentBlockIndex: vi.fn<[], number>().mockReturnValue(0),
|
||||
getBlockByIndex: vi.fn<[number], { holder: HTMLElement } | undefined>(),
|
||||
move: vi.fn<[number], void>(),
|
||||
};
|
||||
|
||||
const toolbar: ToolbarMocks = {
|
||||
toggleBlockSettings: vi.fn<[boolean], void>(),
|
||||
};
|
||||
|
||||
const i18n: I18nMocks = {
|
||||
t: vi.fn<[string], string>().mockImplementation((text) => text),
|
||||
};
|
||||
|
||||
const api = {
|
||||
blocks: blocks as unknown as API['blocks'],
|
||||
toolbar: toolbar as unknown as API['toolbar'],
|
||||
i18n: i18n as unknown as API['i18n'],
|
||||
} as unknown as API;
|
||||
|
||||
return {
|
||||
api,
|
||||
blocks,
|
||||
toolbar,
|
||||
i18n,
|
||||
};
|
||||
};
|
||||
|
||||
const createBlockElement = (top: number, height: number): HTMLDivElement => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
Object.defineProperty(element, 'offsetHeight', {
|
||||
configurable: true,
|
||||
value: height,
|
||||
});
|
||||
|
||||
vi.spyOn(element, 'getBoundingClientRect').mockReturnValue({
|
||||
bottom: top + height,
|
||||
height,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top,
|
||||
width: 0,
|
||||
x: 0,
|
||||
y: top,
|
||||
toJSON: () => ({}),
|
||||
} as DOMRect);
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
describe('MoveDownTune', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders block tune config with translated title and handler', () => {
|
||||
const { api, i18n } = createApiMocks();
|
||||
const tune = new MoveDownTune({ api });
|
||||
const handleClickSpy = vi.spyOn(tune, 'handleClick').mockImplementation(() => {});
|
||||
|
||||
const config = tune.render() as PopoverItemDefaultBaseParams;
|
||||
|
||||
expect(i18n.t).toHaveBeenCalledWith('Move down');
|
||||
expect(config.icon).toBe(IconChevronDown);
|
||||
expect(config.title).toBe('Move down');
|
||||
expect(config.name).toBe('move-down');
|
||||
|
||||
config.onActivate(config);
|
||||
|
||||
expect(handleClickSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('moves the block down and scrolls relative to current position when next block is visible', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveDownTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(2);
|
||||
|
||||
const nextBlockElement = createBlockElement(400, 180);
|
||||
|
||||
blocks.getBlockByIndex.mockReturnValue({
|
||||
holder: nextBlockElement,
|
||||
});
|
||||
|
||||
vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(800);
|
||||
vi.spyOn(window, 'scrollY', 'get').mockReturnValue(150);
|
||||
|
||||
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
||||
|
||||
tune.handleClick();
|
||||
|
||||
expect(blocks.getBlockByIndex).toHaveBeenCalledWith(3);
|
||||
expect(scrollToSpy).toHaveBeenCalledWith(0, 330);
|
||||
expect(blocks.move).toHaveBeenCalledWith(3);
|
||||
expect(toolbar.toggleBlockSettings).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('moves the block down and scrolls by viewport delta when next block is below the fold', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveDownTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(0);
|
||||
|
||||
const nextBlockElement = createBlockElement(1_000, 200);
|
||||
|
||||
blocks.getBlockByIndex.mockReturnValue({
|
||||
holder: nextBlockElement,
|
||||
});
|
||||
|
||||
vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(600);
|
||||
vi.spyOn(window, 'scrollY', 'get').mockReturnValue(50);
|
||||
|
||||
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
||||
|
||||
tune.handleClick();
|
||||
|
||||
expect(blocks.getBlockByIndex).toHaveBeenCalledWith(1);
|
||||
expect(scrollToSpy).toHaveBeenCalledWith(0, 400);
|
||||
expect(blocks.move).toHaveBeenCalledWith(1);
|
||||
expect(toolbar.toggleBlockSettings).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('throws when there is no block below the current one', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveDownTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(5);
|
||||
blocks.getBlockByIndex.mockReturnValue(undefined);
|
||||
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
||||
|
||||
expect(() => tune.handleClick()).toThrowError('Unable to move Block down since it is already the last');
|
||||
expect(blocks.move).not.toHaveBeenCalled();
|
||||
expect(toolbar.toggleBlockSettings).not.toHaveBeenCalled();
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
176
test/unit/components/block-tunes/block-tune-move-up.test.ts
Normal file
176
test/unit/components/block-tunes/block-tune-move-up.test.ts
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import { IconChevronUp } from '@codexteam/icons';
|
||||
import type { Mock } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import MoveUpTune from '../../../../src/components/block-tunes/block-tune-move-up';
|
||||
import type { API } from '../../../../types';
|
||||
import type { PopoverItemDefaultBaseParams } from '../../../../types/utils/popover';
|
||||
|
||||
type BlocksMocks = {
|
||||
getCurrentBlockIndex: Mock<[], number>;
|
||||
getBlockByIndex: Mock<[number], { holder: HTMLElement } | undefined>;
|
||||
move: Mock<[number], void>;
|
||||
};
|
||||
|
||||
type ToolbarMocks = {
|
||||
toggleBlockSettings: Mock<[boolean], void>;
|
||||
};
|
||||
|
||||
type I18nMocks = {
|
||||
t: Mock<[string], string>;
|
||||
};
|
||||
|
||||
const createApiMocks = (): {
|
||||
api: API;
|
||||
blocks: BlocksMocks;
|
||||
toolbar: ToolbarMocks;
|
||||
i18n: I18nMocks;
|
||||
} => {
|
||||
const blocks: BlocksMocks = {
|
||||
getCurrentBlockIndex: vi.fn<[], number>().mockReturnValue(0),
|
||||
getBlockByIndex: vi.fn<[number], { holder: HTMLElement } | undefined>(),
|
||||
move: vi.fn<[number], void>(),
|
||||
};
|
||||
|
||||
const toolbar: ToolbarMocks = {
|
||||
toggleBlockSettings: vi.fn<[boolean], void>(),
|
||||
};
|
||||
|
||||
const i18n: I18nMocks = {
|
||||
t: vi.fn<[string], string>().mockImplementation((text) => text),
|
||||
};
|
||||
|
||||
const api = {
|
||||
blocks: blocks as unknown as API['blocks'],
|
||||
toolbar: toolbar as unknown as API['toolbar'],
|
||||
i18n: i18n as unknown as API['i18n'],
|
||||
} as unknown as API;
|
||||
|
||||
return {
|
||||
api,
|
||||
blocks,
|
||||
toolbar,
|
||||
i18n,
|
||||
};
|
||||
};
|
||||
|
||||
const createBlockElement = (top: number, height: number): HTMLDivElement => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
vi.spyOn(element, 'getBoundingClientRect').mockReturnValue({
|
||||
bottom: top + height,
|
||||
height,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top,
|
||||
width: 0,
|
||||
x: 0,
|
||||
y: top,
|
||||
toJSON: () => ({}),
|
||||
} as DOMRect);
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
describe('MoveUpTune', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders block tune config with translated title and handler', () => {
|
||||
const { api, i18n } = createApiMocks();
|
||||
const tune = new MoveUpTune({ api });
|
||||
const handleClickSpy = vi.spyOn(tune, 'handleClick').mockImplementation(() => {});
|
||||
|
||||
const config = tune.render() as PopoverItemDefaultBaseParams;
|
||||
|
||||
expect(i18n.t).toHaveBeenCalledWith('Move up');
|
||||
expect(config.icon).toBe(IconChevronUp);
|
||||
expect(config.title).toBe('Move up');
|
||||
expect(config.name).toBe('move-up');
|
||||
|
||||
config.onActivate(config);
|
||||
|
||||
expect(handleClickSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('moves the block up and scrolls relative to blocks when previous block is visible', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveUpTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(2);
|
||||
|
||||
const currentBlockElement = createBlockElement(500, 180);
|
||||
const previousBlockElement = createBlockElement(200, 160);
|
||||
|
||||
blocks.getBlockByIndex.mockImplementation((index) => {
|
||||
if (index === 2) {
|
||||
return { holder: currentBlockElement };
|
||||
}
|
||||
|
||||
if (index === 1) {
|
||||
return { holder: previousBlockElement };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const scrollBySpy = vi.spyOn(window, 'scrollBy').mockImplementation(() => {});
|
||||
|
||||
tune.handleClick();
|
||||
|
||||
expect(blocks.getBlockByIndex).toHaveBeenCalledWith(1);
|
||||
expect(scrollBySpy).toHaveBeenCalledWith(0, -(Math.abs(500) - Math.abs(200)));
|
||||
expect(blocks.move).toHaveBeenCalledWith(1);
|
||||
expect(toolbar.toggleBlockSettings).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('moves the block up and scrolls by delta when previous block is above the viewport', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveUpTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(3);
|
||||
|
||||
const currentBlockElement = createBlockElement(400, 160);
|
||||
const previousBlockElement = createBlockElement(-150, 120);
|
||||
|
||||
blocks.getBlockByIndex.mockImplementation((index) => {
|
||||
if (index === 3) {
|
||||
return { holder: currentBlockElement };
|
||||
}
|
||||
|
||||
if (index === 2) {
|
||||
return { holder: previousBlockElement };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const scrollBySpy = vi.spyOn(window, 'scrollBy').mockImplementation(() => {});
|
||||
|
||||
tune.handleClick();
|
||||
|
||||
expect(blocks.getBlockByIndex).toHaveBeenCalledWith(2);
|
||||
expect(scrollBySpy).toHaveBeenCalledWith(0, -(Math.abs(400) + 120));
|
||||
expect(blocks.move).toHaveBeenCalledWith(2);
|
||||
expect(toolbar.toggleBlockSettings).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('throws when block is already the first or previous block is missing', () => {
|
||||
const { api, blocks, toolbar } = createApiMocks();
|
||||
const tune = new MoveUpTune({ api });
|
||||
|
||||
blocks.getCurrentBlockIndex.mockReturnValue(0);
|
||||
blocks.getBlockByIndex.mockReturnValue(undefined);
|
||||
|
||||
const scrollBySpy = vi.spyOn(window, 'scrollBy').mockImplementation(() => {});
|
||||
|
||||
expect(() => tune.handleClick()).toThrowError(
|
||||
'Unable to move Block up since it is already the first'
|
||||
);
|
||||
expect(blocks.move).not.toHaveBeenCalled();
|
||||
expect(toolbar.toggleBlockSettings).not.toHaveBeenCalled();
|
||||
expect(scrollBySpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue