Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create API methods for manipulating with block elements #135

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b170900
create API methods for manipulating with block elements
Darginec05 May 5, 2024
2eba977
get Element implemnted
Darginec05 May 9, 2024
c345cdb
working on API with elements
Darginec05 May 11, 2024
960229a
Merge branch 'master' of github.com:Darginec05/Editor-Yopta into 131-…
Darginec05 May 17, 2024
3bd8cc4
merge
Darginec05 May 17, 2024
a118f0a
pass element path to props
Darginec05 May 18, 2024
8c9a9a5
Merge branch 'master' of github.com:Darginec05/Editor-Yopta into 131-…
Darginec05 May 18, 2024
c336e08
finish API of elements
Darginec05 May 21, 2024
1d74f79
add new API object Elements and Blocks
Darginec05 May 24, 2024
611df90
remove elements API from editor.blocks
Darginec05 May 24, 2024
ed6b56e
extend API for elements
Darginec05 May 25, 2024
ee3e3e6
Merge branch 'master' of github.com:Darginec05/Editor-Yopta into 131-…
Darginec05 May 26, 2024
1d6484b
remvoe unused pacakge
Darginec05 May 27, 2024
e728140
fix bug with prev block
Darginec05 May 29, 2024
7fcc71a
update peer deps
Darginec05 May 29, 2024
abd2670
Publish
Darginec05 May 29, 2024
29e4ae3
Publish
Darginec05 May 29, 2024
26df3e6
fix error with arrow down and up
Darginec05 May 30, 2024
8624ba9
Publish
Darginec05 May 30, 2024
018d25b
udpate exampels
Darginec05 May 30, 2024
7acee1f
update value for examples
Darginec05 May 30, 2024
1824c9b
Fix update block & fix element API`s
Darginec05 May 31, 2024
9f78b25
fix arrow up and arrow down
Darginec05 May 31, 2024
28c70e7
Publish
Darginec05 May 31, 2024
0b5539a
added example with carousel plugin
Darginec05 Jun 5, 2024
66e50e5
Publish
Darginec05 Jun 5, 2024
ef021df
add carousel block options
Darginec05 Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"private": true,
"scripts": {
"start": "yarn lerna run start --scope @yoopta/editor --scope @yoopta/paragraph --parallel --ignore development",
"start": "yarn lerna run start --parallel --ignore development",
"build": "yarn clean && yarn lerna run build --parallel --ignore development",
"clean": "find ./packages -type d -name dist ! -path './packages/development/*' -exec rm -rf {} +",
"serve": "yarn lerna run dev --scope=development",
Expand Down
5 changes: 3 additions & 2 deletions packages/core/editor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yoopta/editor",
"version": "4.4.1",
"version": "4.5.0",
"license": "MIT",
"private": false,
"main": "dist/index.js",
Expand Down Expand Up @@ -66,5 +66,6 @@
"bugs": {
"url": "https://github.com/Darginec05/Yoopta-Editor/issues"
},
"homepage": "https://github.com/Darginec05/Yoopta-Editor#readme"
"homepage": "https://github.com/Darginec05/Yoopta-Editor#readme",
"gitHead": "29e4ae316ec75bb43d3822d028abcb0c34256ec5"
}
3 changes: 2 additions & 1 deletion packages/core/editor/src/UI/BlockOptions/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export function buildActionMenuRenderProps({ editor, view, onClose, mode = 'togg
return items.map((action) => {
const title = editor.blocks[action].options?.display?.title || action;
const description = editor.blocks[action].options?.display?.description;
return { type: action, title, description };
const icon = editor.blocks[action].options?.display?.icon;
return { type: action, title, description, icon };
});
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/editor/src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ const Editor = ({ placeholder, marks, className, selectionBoxRoot, width, childr
resetSelectedBlocks();
};

// [TODO] - implement with @yoopta/exports
const onCopy = (event: React.ClipboardEvent) => {
// function escapeHtml(text) {
// const map = {
Expand Down
20 changes: 11 additions & 9 deletions packages/core/editor/src/components/Editor/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { YooptaBlockData, SlateElement } from '../../editor/types';
import { generateId } from '../../utils/generateId';

export const buildBlockElement = (element?: Partial<SlateElement>): SlateElement => ({
id: generateId(),
type: element?.type || 'paragraph',
children: element?.children || [{ text: '' }],
props: {
nodeType: 'block',
...element?.props,
},
});
export const buildBlockElement = (element?: Partial<SlateElement>): SlateElement => {
return {
id: generateId(),
type: element?.type || 'paragraph',
children: element?.children || [{ text: '' }],
props: {
nodeType: 'block',
...element?.props,
},
};
};

export const buildBlockData = (block?: Partial<YooptaBlockData>): YooptaBlockData => ({
id: block?.id || generateId(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { createDraft, finishDraft } from 'immer';
import { Element, Transforms } from 'slate';
import { buildBlockData, buildBlockElement } from '../../components/Editor/utils';
import { getRootBlockElementType } from '../../utils/blockElements';
import { Transforms } from 'slate';
import { buildBlockData } from '../../components/Editor/utils';
import { buildBlockElementsStructure } from '../../utils/blockElements';
import { findPluginBlockBySelectionPath } from '../../utils/findPluginBlockBySelectionPath';
import { findSlateBySelectionPath } from '../../utils/findSlateBySelectionPath';
import { generateId } from '../../utils/generateId';
import { YooEditor, YooptaEditorTransformOptions } from '../types';
import { YooEditor, YooptaEditorTransformOptions, SlateElement, YooptaBlock } from '../types';

export type CreateBlockOptions = YooptaEditorTransformOptions & {
deleteText?: boolean;
Expand All @@ -21,23 +20,15 @@ export function createBlock(editor: YooEditor, type: string, options?: CreateBlo
if (!slate || !slate.selection) return;

const selectedBlock = editor.blocks[type];
const rootBlockElementType = getRootBlockElementType(selectedBlock.elements);
const rootBlockElement = selectedBlock.elements[rootBlockElementType!];
const elements = buildBlockElementsStructure(editor, type);

if (!rootBlockElement) return;
// Transforms.setNodes(slate, elements, {
// at: [0],
// match: (n) => Element.isElement(n),
// mode: 'highest',
// });

const nodeProps = { nodeType: rootBlockElement.props?.nodeType || 'block', ...rootBlockElement.props };
const elementNode = buildBlockElement({
id: generateId(),
type: rootBlockElementType,
props: nodeProps,
});

Transforms.setNodes(slate, elementNode, {
at: [0, 0],
match: (n) => Element.isElement(n),
mode: 'highest',
});
// Transforms.insertNodes(slate, elements, { at: slate.selection.anchor.path.slice(0, 1) });

if (options?.deleteText) Transforms.delete(slate, { at: [0, 0] });

Expand All @@ -48,9 +39,10 @@ export function createBlock(editor: YooEditor, type: string, options?: CreateBlo
order: block.meta.order,
depth: block.meta.depth,
},
value: [elementNode],
value: [elements],
});

slate.children = blockData.value;
const blockId = blockData.id;

editor.children[blockId] = blockData;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { createDraft, finishDraft } from 'immer';
import { createEditor, Editor } from 'slate';
import { withHistory } from 'slate-history';
import { withReact } from 'slate-react';
import { buildBlockData } from '../../components/Editor/utils';
import { buildSlateEditor } from '../../utils/editorBuilders';
import { withShortcuts } from '../../extensions/shortcuts';
import { findPluginBlockBySelectionPath } from '../../utils/findPluginBlockBySelectionPath';
import { generateId } from '../../utils/generateId';
import { YooEditor, YooptaEditorTransformOptions } from '../types';
// // [TODO] Circular deps
// import { buildSlateEditor } from '../../utils/editorBuilders';

function buildSlateEditor(editor: YooEditor): Editor {
const slate = withShortcuts(editor, withHistory(withReact(createEditor())));
return slate;
}

export type DeleteBlockOptions = YooptaEditorTransformOptions & {
deleteAll?: boolean;
Expand Down
27 changes: 27 additions & 0 deletions packages/core/editor/src/editor/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { insertBlock } from './insertBlock';
import { deleteBlock } from './deleteBlock';
import { moveBlock } from './moveBlock';
import { focusBlock } from './focusBlock';
import { splitBlock } from './splitBlock';
import { increaseBlockDepth } from './increaseBlockDepth';
import { decreaseBlockDepth } from './decreaseBlockDepth';
import { duplicateBlock } from './duplicateBlock';
import { updateBlock } from './updateBlock';
import { toggleBlock } from './toggleBlock';
import { insertBlocks } from './insertBlocks';

export const Blocks = {
insertBlock,
deleteBlock,
moveBlock,
focusBlock,
splitBlock,
increaseBlockDepth,
decreaseBlockDepth,
duplicateBlock,
updateBlock,
toggleBlock,
insertBlocks,
// [TODO]
// updateBlocks
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getRootBlockElementType } from '../../utils/blockElements';

import { findPluginBlockBySelectionPath } from '../../utils/findPluginBlockBySelectionPath';
import { findSlateBySelectionPath } from '../../utils/findSlateBySelectionPath';
import { YooEditor, YooptaBlockPath, YooptaEditorTransformOptions, YooptaBlockData } from '../types';
import { YooEditor, YooptaEditorTransformOptions, YooptaBlockData } from '../types';

export type ToggleBlockOptions = YooptaEditorTransformOptions & {
deleteText?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export function updateBlock<TElementKeys extends string, TProps>(
let shouldApply = false;

const block = editor.children[blockId];

if (!block) {
throw Error(`Block with id ${blockId} not found`);
// [TODO] - some weird behaviour when copy/paste
console.log(`Block with id ${blockId} not found`);
return;
}

if (data.id) {
Expand Down
96 changes: 96 additions & 0 deletions packages/core/editor/src/editor/elements/createElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Editor, Path, Span, Transforms } from 'slate';
import { buildBlockElement } from '../../components/Editor/utils';
import { findSlateBySelectionPath } from '../../utils/findSlateBySelectionPath';
import { SlateElement, YooEditor } from '../types';
import { getElementEntry } from './getElementEntry';

export type CreateBlockElementOptions = {
path?: 'next' | 'prev' | Path | Span;
focus?: boolean;
split?: boolean;
};

export type CreateElement<TElementKeys, TElementProps> = {
type: TElementKeys;
props?: TElementProps;
};

export function createElement<TElementKeys extends string, TElementProps>(
editor: YooEditor,
blockId: string,
element: CreateElement<TElementKeys, TElementProps>,
options?: CreateBlockElementOptions,
) {
const blockData = editor.children[blockId];
if (!blockData) {
throw new Error(`Block with id ${blockId} not found`);
}

const slate = findSlateBySelectionPath(editor, { at: [blockData.meta.order] });
if (!slate) {
console.warn('No slate found');
return;
}

Editor.withoutNormalizing(slate, () => {
const block = editor.blocks[blockData.type];
const blockElement = block.elements[element.type];
const nodeElement = buildBlockElement({ type: element.type, props: { ...blockElement.props, ...element.props } });

const elementTypes = Object.keys(block.elements);

let childrenElements: SlateElement[] = [];

elementTypes.forEach((blockElementType) => {
const blockElement = block.elements[blockElementType];

if (blockElementType === element.type) {
if (Array.isArray(blockElement.children) && blockElement.children.length > 0) {
blockElement.children.forEach((childElementType) => {
const childElement = block.elements[childElementType];
childrenElements.push(buildBlockElement({ type: childElementType, props: childElement.props }));
});
}
}
});

if (childrenElements.length > 0) nodeElement.children = childrenElements;

const { path, focus = true } = options || {};
let atPath;

const elementEntry = getElementEntry(editor, blockId, { type: element.type });

if (elementEntry) {
const [, elementPath] = elementEntry;

if (Path.isPath(path)) {
atPath = path;
} else if (path === 'prev') {
atPath = Path.previous(elementPath);
} else if (path === 'next') {
atPath = Path.next(elementPath);
}
}

Transforms.insertNodes(slate, nodeElement, { at: atPath, select: focus });

if (focus) {
if (childrenElements.length > 0) {
const firstChild = childrenElements[0];
const firstElementEntry = getElementEntry(editor, blockId, {
path: atPath,
type: firstChild.type,
});

if (firstElementEntry) {
const [, firstElementPath] = firstElementEntry;
Transforms.select(slate, firstElementPath);
}
}
}

editor.applyChanges();
editor.emit('change', editor.children);
});
}
33 changes: 33 additions & 0 deletions packages/core/editor/src/editor/elements/deleteElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Editor, Element, Path, Transforms } from 'slate';
import { findSlateBySelectionPath } from '../../utils/findSlateBySelectionPath';
import { YooEditor } from '../types';

export type DeleteBlockElement = {
type: string;
path: Path;
};

export function deleteElement(editor: YooEditor, blockId: string, element: DeleteBlockElement) {
const block = editor.children[blockId];

if (!block) {
throw new Error(`Block with id ${blockId} not found`);
}

const slate = findSlateBySelectionPath(editor, { at: [block.meta.order] });

if (!slate) {
console.warn('No slate found');
return;
}

Editor.withoutNormalizing(slate, () => {
Transforms.removeNodes(slate, {
at: element.path,
match: (n) => Element.isElement(n) && n.type === element.type,
});

editor.applyChanges();
editor.emit('change', editor.children);
});
}
18 changes: 18 additions & 0 deletions packages/core/editor/src/editor/elements/getElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { SlateElement, YooEditor } from '../types';
import { getElementEntry, GetBlockElementEntryOptions } from './getElementEntry';

export type GetBlockElementOptions = GetBlockElementEntryOptions;

export function getElement<TElementKeys extends string>(
editor: YooEditor,
blockId: string,
options?: GetBlockElementOptions,
): SlateElement<TElementKeys> | undefined {
const elementEntry = getElementEntry(editor, blockId, options);

if (elementEntry) {
return elementEntry[0] as SlateElement<TElementKeys>;
}

return undefined;
}
16 changes: 16 additions & 0 deletions packages/core/editor/src/editor/elements/getElementChildren.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { SlateElement, YooEditor } from '../types';
import { getElement } from './getElement';
import { GetBlockElementEntryOptions } from './getElementEntry';

export type GetElementChildrenOptions = GetBlockElementEntryOptions;

export function getElementChildren<TElementKeys extends string>(
editor: YooEditor,
blockId: string,
options?: GetElementChildrenOptions,
): SlateElement<TElementKeys>['children'] | undefined {
const element = getElement(editor, blockId, options);
if (element) return element.children;

return undefined;
}
Loading
Loading