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
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 --parallel --ignore development",
"start": "yarn lerna run start --scope @yoopta/editor --scope @yoopta/starter-kit --scope @yoopta/action-menu-list --scope @yoopta/video --scope @yoopta/file --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
2 changes: 1 addition & 1 deletion packages/core/editor/src/UI/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Props = {

const Overlay = ({ className, onClick, children, lockScroll = true, ...rest }: Props) => {
return (
<FloatingOverlay lockScroll={lockScroll} className={className} onClick={onClick} {...rest}>
<FloatingOverlay lockScroll={lockScroll} className={`yoopta-portal ${className}`} onClick={onClick} {...rest}>
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

remove

{children}
</FloatingOverlay>
);
Expand Down
19 changes: 13 additions & 6 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 @@ -123,7 +122,10 @@ const Editor = ({
};

const onMouseDown = (event: React.MouseEvent) => {
if (isReadOnly) return;
const isTargetInsidePortal =
event.target instanceof HTMLElement && !!event.target.closest('[data-floating-ui-portal]');

if (isReadOnly || isTargetInsidePortal) return;

// if (event.shiftKey) {
// const currentSelectionIndex = editor.selection;
Expand Down Expand Up @@ -183,12 +185,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
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.

1 change: 0 additions & 1 deletion packages/core/editor/src/parsers/deserializeHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 @@ -47,7 +48,7 @@ export function serializeHTML(editor: YooEditor, content: YooptaContentValue) {

if (plugin && plugin.parsers?.html?.serialize) {
const content = serializeChildren(blockData.value[0].children, editor.plugins);
return plugin.parsers.html.serialize(blockData.value[0], content);
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 '@yoopta/editor';

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 '@yoopta/editor';
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;
}
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} />;
};
```
58 changes: 58 additions & 0 deletions packages/core/starter-kit/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@yoopta/starter-kit",
"version": "4.6.4",
"description": "StarterKit for Yoopta Editor",
"author": "Darginec05 <[email protected]>",
"homepage": "https://github.com/Darginec05/Editor-Yoopta#readme",
"license": "MIT",
"private": false,
"main": "dist/index.js",
"type": "module",
"module": "dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/"
],
"dependencies": {
"@yoopta/accordion": "^4.6.4",
"@yoopta/action-menu-list": "^4.6.4",
"@yoopta/blockquote": "^4.6.4",
"@yoopta/callout": "^4.6.4",
"@yoopta/code": "^4.6.4",
"@yoopta/editor": "^4.6.4",
"@yoopta/embed": "^4.6.4",
"@yoopta/exports": "^4.6.4",
"@yoopta/file": "^4.6.4",
"@yoopta/headings": "^4.6.4",
"@yoopta/image": "^4.6.4",
"@yoopta/link": "^4.6.4",
"@yoopta/link-tool": "^4.6.4",
"@yoopta/lists": "^4.6.4",
"@yoopta/marks": "^4.6.4",
"@yoopta/paragraph": "^4.6.4",
"@yoopta/toolbar": "^4.6.4",
"@yoopta/video": "^4.6.4",
"slate": "^0.102.0",
"slate-react": "^0.102.0"
},
"peerDependencies": {
"react": ">=17.0.2",
"react-dom": ">=17.0.2"
},
"publishConfig": {
"registry": "https://registry.yarnpkg.com"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Darginec05/Editor-Yoopta.git"
},
"scripts": {
"test": "node ./__tests__/yoopta-starter-kit.test.js",
"start": "rollup --config rollup.config.js --watch --bundleConfigAsCjs --environment NODE_ENV:development",
"prepublishOnly": "yarn build",
"build": "rollup --config rollup.config.js --bundleConfigAsCjs --environment NODE_ENV:production"
},
"bugs": {
"url": "https://github.com/Darginec05/Editor-Yoopta/issues"
}
}
7 changes: 7 additions & 0 deletions packages/core/starter-kit/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createRollupConfig } from '../../../config/rollup';

const pkg = require('./package.json');
export default createRollupConfig({
pkg,
tailwindConfig: { content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], prefix: 'yoo-starter-' },
});
72 changes: 72 additions & 0 deletions packages/core/starter-kit/src/components/StarterKit/StarterKit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { CSSProperties, useEffect, useMemo, useRef } from 'react';
import YooptaEditor, { createYooptaEditor, YooptaContentValue } from '@yoopta/editor';

import { TOOLS } from '../../utilts/tools';
import { MARKS } from '../../utilts/marks';
import { getPlugins } from '../../utilts/plugins';
import { ImageUploadResponse } from '@yoopta/image';
import { VideoUploadResponse } from '@yoopta/video';
import { FileUploadResponse } from '@yoopta/file';

export type StarterKitProps = {
id?: string;
value?: YooptaContentValue;
onChange?: (value: YooptaContentValue) => void;
readOnly?: boolean;
autoFocus?: boolean;
className?: string;
placeholder?: string;
style?: CSSProperties;
selectionRef?: React.RefObject<HTMLDivElement> | false;
media?: MediaUploadsFn;
};

export type MediaUploadsFn = {
imageUpload?: (file: File) => Promise<ImageUploadResponse>;
videoUpload?: (file: File) => Promise<VideoUploadResponse>;
fileUpload?: (file: File) => Promise<FileUploadResponse>;
};

function StarterKit({
id,
value,
style,
onChange,
readOnly,
autoFocus,
className,
placeholder,
media,
selectionRef = false,
}: StarterKitProps) {
const editor = useMemo(() => createYooptaEditor(), []);

useEffect(() => {
if (typeof onChange === 'function') {
editor.on('change', onChange);
return () => {
editor.off('change', onChange);
};
}
}, [editor]);

return (
<YooptaEditor
key={id}
id={id}
selectionBoxRoot={selectionRef}
editor={editor}
plugins={getPlugins({ media })}
tools={TOOLS}
marks={MARKS}
value={value}
readOnly={readOnly}
autoFocus={autoFocus}
className={className}
style={style}
placeholder={placeholder}
/>
);
}

export { StarterKit };
4 changes: 4 additions & 0 deletions packages/core/starter-kit/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { StarterKit, type MediaUploadsFn, type StarterKitProps } from './components/StarterKit/StarterKit';

export default StarterKit;
export type { MediaUploadsFn, StarterKitProps };
1 change: 1 addition & 0 deletions packages/core/starter-kit/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@tailwind utilities;
3 changes: 3 additions & 0 deletions packages/core/starter-kit/src/utilts/marks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Bold, Italic, CodeMark, Underline, Strike, Highlight } from '@yoopta/marks';

export const MARKS = [Bold, Italic, CodeMark, Underline, Strike, Highlight];
Loading
Loading