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 starter kit package #217

Merged
merged 17 commits into from
Jul 21, 2024
24 changes: 24 additions & 0 deletions .github/ISSUE_TEMPLATE/example_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Example Request
description: Submit a request for an example
title: '[Example Request]: '
labels: ['Example Request']
body:
- type: markdown
attributes:
value: |
Need an example of how to do something with Yoopta-Editor?
- type: textarea
id: description
attributes:
label: What's the example?
description: Please describe the example. What would you like to see?
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/Darginec05/Yoopta-Editor/blob/master/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow this project's Code of Conduct
required: true
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
],
"private": true,
"scripts": {
"dev": "npm-run-all --parallel start serve",
"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",
"build": "yarn clean && yarn install && yarn lerna run build --parallel --ignore development",
"clean": "find ./packages -type d -name dist ! -path './packages/development/*' -exec rm -rf {} +",
"coverage": "vitest run --coverage",
"test": "vitest",
"dev": "npm-run-all --parallel start serve",
"test:ui": "vitest --ui",
"test:integration": "playwright test",
"release": "yarn clean && yarn build && yarn lerna publish --no-private"
Expand Down
4 changes: 2 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.6.4",
"version": "4.6.5-rc.3",
"license": "MIT",
"private": false,
"main": "dist/index.js",
Expand Down Expand Up @@ -67,5 +67,5 @@
"url": "https://github.com/Darginec05/Yoopta-Editor/issues"
},
"homepage": "https://github.com/Darginec05/Yoopta-Editor#readme",
"gitHead": "29e4ae316ec75bb43d3822d028abcb0c34256ec5"
"gitHead": "600e0cf267a0ce7df074ddc7db1114d67c4185d1"
}
21 changes: 19 additions & 2 deletions packages/core/editor/src/UI/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,29 @@ type Props = {
lockScroll?: boolean;
className?: string;
onClick?: (e: MouseEvent) => void;
onMouseDown?: (e: MouseEvent) => void;
style?: React.CSSProperties;
};

const Overlay = ({ className, onClick, children, lockScroll = true, ...rest }: Props) => {
const Overlay = ({ className, children, lockScroll = true, ...props }: Props) => {
const onMouseDown = (e: MouseEvent) => {
e.stopPropagation();
props.onMouseDown?.(e);
};

const onClick = (e: MouseEvent) => {
e.stopPropagation();
props.onClick?.(e);
};

return (
<FloatingOverlay lockScroll={lockScroll} className={className} onClick={onClick} {...rest}>
<FloatingOverlay
lockScroll={lockScroll}
className={className}
{...props}
onClick={onClick}
onMouseDown={onMouseDown}
>
{children}
</FloatingOverlay>
);
Expand Down
21 changes: 16 additions & 5 deletions packages/core/editor/src/UI/Portal/Portal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FloatingPortal } from '@floating-ui/react';
import { MutableRefObject, ReactNode, useEffect, useState } from 'react';
import { MutableRefObject, ReactNode, useEffect, useRef, useState } from 'react';
import { useYooptaEditor } from '../../contexts/YooptaContext/YooptaContext';

type Props = {
Expand All @@ -9,19 +9,30 @@ type Props = {

const Portal = (props: Props) => {
const [isMounted, setIsMounted] = useState(false);
const rootEl = useRef<HTMLElement | null>(null);
const editor = useYooptaEditor();

useEffect(() => {
setIsMounted(true);
const editorEl = document.querySelector(`[data-yoopta-editor-id="${editor.id}"]`) as HTMLElement;
const overlays = editorEl.querySelector('.yoopta-overlays');
if (!overlays) {
rootEl.current = document.createElement('div');
rootEl.current.className = 'yoopta-overlays';
editorEl.appendChild(rootEl.current);
}

return () => {
if (rootEl.current) {
rootEl.current.remove();
}
};
}, []);

if (!isMounted) return null;

return (
<FloatingPortal
id={`${props.id}-${editor.id}`}
root={document.querySelector(`[data-yoopta-editor-id="${editor.id}"]`) as HTMLElement}
>
<FloatingPortal id={`${props.id}-${editor.id}`} root={rootEl.current}>
{props.children}
</FloatingPortal>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/editor/src/YooptaEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getDefaultYooptaChildren } from './components/Editor/utils';
import { Editor } from './components/Editor/Editor';
import { CSSProperties, useMemo, useState } from 'react';
import { YooEditor, YooptaBlockData, YooptaContentValue } from './editor/types';
import { Plugin } from './plugins/types';
import { Plugin, PluginElementProps } from './plugins/types';
import NoSSR from './components/NoSsr/NoSsr';
import { Tools, ToolsProvider } from './contexts/YooptaContext/ToolsContext';
import {
Expand All @@ -22,7 +22,7 @@ import { generateId } from './utils/generateId';
type Props = {
id?: string;
editor: YooEditor;
plugins: YooptaPlugin[];
plugins: YooptaPlugin<string, PluginElementProps<any>, Record<string, unknown>>[];
marks?: YooptaMark<any>[];
value?: YooptaContentValue;
autoFocus?: boolean;
Expand Down
16 changes: 9 additions & 7 deletions packages/core/editor/src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { ReactEditor } from 'slate-react';
import { YooptaBlockPath } from '../../editor/types';
import { useRectangeSelectionBox } from '../SelectionBox/hooks';
import { SelectionBox } from '../SelectionBox/SelectionBox';
import { serializeHTML } from '../../parsers/serializeHTML';
import { Blocks } from '../../editor/blocks';

type Props = {
Expand Down Expand Up @@ -155,8 +154,6 @@ const Editor = ({
const isInsideEditor = yooptaEditorRef.current?.contains(event.relatedTarget as Node);
if (isInsideEditor || isReadOnly) return;

editor.blur();

resetSelectionState();
resetSelectedBlocks();
};
Expand All @@ -183,12 +180,17 @@ const Editor = ({
if (Array.isArray(editor.selectedBlocks) && editor.selectedBlocks.length > 0) {
event.preventDefault();

const htmlString = serializeHTML(editor, editor.getEditorValue());
const blob = new Blob([htmlString], { type: 'text/html' });
const htmlString = editor.getHTML(editor.getEditorValue());
const textString = editor.getPlainText(editor.getEditorValue());
const htmlBlob = new Blob([htmlString], { type: 'text/html' });
const textBlob = new Blob([textString], { type: 'text/plain' });

const item = new ClipboardItem({ 'text/html': blob });
const clipboardItem = new ClipboardItem({
'text/html': htmlBlob,
'text/plain': textBlob,
});

navigator.clipboard.write([item]).then(() => {
navigator.clipboard.write([clipboardItem]).then(() => {
const html = new DOMParser().parseFromString(htmlString, 'text/html');
console.log('HTML copied\n', html.body);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ const DEFAULT_HANDLERS: YooptaEditorContext = {
blur: () => undefined,
isFocused: () => false,
focus: () => undefined,

getHTML: () => '',
getMarkdown: () => '',
getPlainText: () => '',
},
};

Expand Down
9 changes: 8 additions & 1 deletion packages/core/editor/src/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { moveBlock } from './blocks/moveBlock';
import { focusBlock } from './blocks/focusBlock';
import { splitBlock } from './blocks/splitBlock';
import { setSelection } from './selection/setSelection';
import { YooEditor } from './types';
import { YooEditor, YooptaContentValue } from './types';
import { increaseBlockDepth } from './blocks/increaseBlockDepth';
import { decreaseBlockDepth } from './blocks/decreaseBlockDepth';
import { getEditorValue } from './core/getEditorValue';
Expand All @@ -19,6 +19,9 @@ import { focus } from './core/focus';
import { isFocused } from './core/isFocused';
import { deleteBlocks } from './blocks/deleteBlocks';
import { getBlock } from './blocks/getBlock';
import { getHTML } from '../parsers/getHTML';
import { getMarkdown } from '../parsers/getMarkdown';
import { getPlainText } from '../parsers/getPlainText';

// export const YooEditor = {}
// export const BlockTransforms = {}
Expand Down Expand Up @@ -75,6 +78,10 @@ export const createYooptaEditor = (): YooEditor => {
isFocused: () => isFocused(editor),
focus: () => focus(editor),
blur: (...args) => blur(editor, ...args),

getHTML: (content: YooptaContentValue) => getHTML(editor, content),
getMarkdown: (content: YooptaContentValue) => getMarkdown(editor, content),
getPlainText: (content: YooptaContentValue) => getPlainText(editor, content),
};

return editor;
Expand Down
6 changes: 6 additions & 0 deletions packages/core/editor/src/editor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,15 @@ export type YooEditor<TNodes = any> = {
emit: (event: YooEditorEvents, payload: any) => void;
readOnly: boolean;

// focus handlers
isFocused: () => boolean;
blur: (options?: EditorBlurOptions) => void;
focus: () => void;

// parser handlers
getHTML: (content: YooptaContentValue) => string;
getMarkdown: (content: YooptaContentValue) => string;
getPlainText: (content: YooptaContentValue) => string;
};

// types for slate values
Expand Down
3 changes: 0 additions & 3 deletions packages/core/editor/src/hooks/useForceRender.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/core/editor/src/parsers/deserializeHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function mapNodeChildren(child) {
const block = child as YooptaBlockData;
let text = '';

block.value[0].children.forEach((child) => {
(block.value[0] as SlateElement).children.forEach((child: any) => {
text += `${child.text}`;
});

Expand All @@ -184,7 +184,6 @@ export function deserializeHTML(editor: YooEditor, html: HTMLElement) {
console.log('pasted html', html);

const PLUGINS_NODE_NAME_MATCHERS_MAP = getMappedPluginByNodeNames(editor);
console.log('PLUGINS_NODE_NAME_MATCHERS_MAP', PLUGINS_NODE_NAME_MATCHERS_MAP);

const blocks = deserialize(editor, PLUGINS_NODE_NAME_MATCHERS_MAP, html).filter(isYooptaBlock) as YooptaBlockData[];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { YooEditor, YooptaContentValue } from '../editor/types';
import { BaseText, Descendant } from 'slate';
import { SlateElement, YooEditor, YooptaContentValue } from '../editor/types';
import { getPluginByInlineElement } from '../utils/blockElements';

const MARKS_NODE_NAME_MATCHERS_MAP = {
Expand Down Expand Up @@ -37,7 +38,7 @@ function serializeChildren(children, plugins) {
.join('');
}

export function serializeHTML(editor: YooEditor, content: YooptaContentValue) {
export function getHTML(editor: YooEditor, content: YooptaContentValue): string {
const blocks = Object.values(content)
.filter((item) => editor.selectedBlocks?.includes(item.meta.order))
.sort((a, b) => a.meta.order - b.meta.order);
Expand All @@ -46,8 +47,8 @@ export function serializeHTML(editor: YooEditor, content: YooptaContentValue) {
const plugin = editor.plugins[blockData.type];

if (plugin && plugin.parsers?.html?.serialize) {
const content = serializeChildren(blockData.value[0].children, editor.plugins);
return plugin.parsers.html.serialize(blockData.value[0], content);
const content = serializeChildren((blockData.value[0] as SlateElement).children, editor.plugins);
return plugin.parsers.html.serialize(blockData.value[0] as SlateElement, content);
}

return '';
Expand Down
30 changes: 30 additions & 0 deletions packages/core/editor/src/parsers/getMarkdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { SlateElement, YooEditor, YooptaBlockData, YooptaContentValue } from '../editor/types';

export function serialize(editor: YooEditor, blocksData: YooptaBlockData[]) {
const blocks = blocksData.sort((a, b) => (a.meta.order > b.meta.order ? 1 : -1));

const markdown = blocks.map((blockData) => {
const plugin = editor.plugins[blockData.type];

if (plugin) {
const element = blockData.value[0] as SlateElement;

if (plugin.parsers?.markdown?.serialize) {
const serialized = plugin.parsers.markdown.serialize(
element,
element.children.map((child) => child.text).join(''),
);
if (serialized) return serialized;
}
}

return '';
});

return markdown.join('\n');
}

export function getMarkdown(editor: YooEditor, content: YooptaContentValue) {
const selectedBlocks = Object.values(content);
return serialize(editor, selectedBlocks);
}
10 changes: 10 additions & 0 deletions packages/core/editor/src/parsers/getPlainText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { YooEditor, YooptaContentValue } from '../editor/types';
import { getHTML } from './getHTML';

export function getPlainText(editor: YooEditor, content: YooptaContentValue) {
const htmlString = getHTML(editor, content);

const div = document.createElement('div');
div.innerHTML = htmlString;
return div.innerText;
}
5 changes: 3 additions & 2 deletions packages/core/exports/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yoopta/exports",
"version": "4.6.4",
"version": "4.6.5-rc.3",
"description": "Serialize/deserialize exports in different formats for Yoopta-Editor",
"author": "Darginec05 <[email protected]>",
"homepage": "https://github.com/Darginec05/Editor-Yoopta#readme",
Expand Down Expand Up @@ -35,5 +35,6 @@
},
"dependencies": {
"marked": "^13.0.0"
}
},
"gitHead": "600e0cf267a0ce7df074ddc7db1114d67c4185d1"
}
21 changes: 21 additions & 0 deletions packages/core/starter-kit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# StarterKit plugin
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docs


StarterKit is plugin for Yoopta-Editor

### Installation

```bash
yarn add @yoopta/starter-kit
```

### Usage

```jsx
import StarterKit from '@yoopta/starter-kit';

const plugins = [StarterKit];

const Editor = () => {
return <YooptaEditor plugins={plugins} />;
};
```
Loading
Loading