mirror of
https://github.com/owncast/owncast.git
synced 2024-11-25 22:31:09 +03:00
Use slate.js as a rich text editor for chat messages
This commit is contained in:
parent
f96bde4f71
commit
66a55401a8
3 changed files with 280 additions and 31 deletions
|
@ -1,27 +1,101 @@
|
|||
import { SmileOutlined } from '@ant-design/icons';
|
||||
import { Button, Input } from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import ContentEditable from 'react-contenteditable';
|
||||
import { Transforms, createEditor, Node, BaseEditor, Text } from 'slate';
|
||||
import { Slate, Editable, withReact, ReactEditor } from 'slate-react';
|
||||
import WebsocketService from '../../../services/websocket-service';
|
||||
import { websocketServiceAtom } from '../../stores/ClientConfigStore';
|
||||
import { getCaretPosition, convertToText, convertOnPaste } from '../chat';
|
||||
import { MessageType } from '../../../interfaces/socket-events';
|
||||
import s from './ChatTextField.module.scss';
|
||||
|
||||
type CustomElement = { type: 'paragraph'; children: CustomText[] };
|
||||
type CustomText = { text: string };
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Editor: BaseEditor & ReactEditor;
|
||||
Element: CustomElement;
|
||||
Text: CustomText;
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
}
|
||||
|
||||
const Image = ({ element }) => (
|
||||
<img
|
||||
src={element.url}
|
||||
alt="emoji"
|
||||
style={{ display: 'inline', position: 'relative', width: '30px', bottom: '10px' }}
|
||||
/>
|
||||
);
|
||||
|
||||
const insertImage = (editor, url) => {
|
||||
const text = { text: '' };
|
||||
const image: ImageElement = { type: 'image', url, children: [text] };
|
||||
Transforms.insertNodes(editor, image);
|
||||
};
|
||||
|
||||
const withImages = editor => {
|
||||
const { isVoid } = editor;
|
||||
|
||||
editor.isVoid = element => (element.type === 'image' ? true : isVoid(element));
|
||||
editor.isInline = element => element.type === 'image';
|
||||
|
||||
return editor;
|
||||
};
|
||||
|
||||
export type EmptyText = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
type ImageElement = {
|
||||
type: 'image';
|
||||
url: string;
|
||||
children: EmptyText[];
|
||||
};
|
||||
|
||||
const Element = props => {
|
||||
const { attributes, children, element } = props;
|
||||
|
||||
switch (element.type) {
|
||||
case 'image':
|
||||
return <Image {...props} />;
|
||||
default:
|
||||
return <p {...attributes}>{children}</p>;
|
||||
}
|
||||
};
|
||||
|
||||
const serialize = node => {
|
||||
if (Text.isText(node)) {
|
||||
let string = node.text; // escapeHtml(node.text);
|
||||
if (node.bold) {
|
||||
string = `<strong>${string}</strong>`;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
const children = node.children.map(n => serialize(n)).join('');
|
||||
|
||||
switch (node.type) {
|
||||
case 'paragraph':
|
||||
return `<p>${children}</p>`;
|
||||
case 'image':
|
||||
return `<img src="${node.url}" alt="emoji" />`;
|
||||
default:
|
||||
return children;
|
||||
}
|
||||
};
|
||||
|
||||
export default function ChatTextField(props: Props) {
|
||||
const { value: originalValue } = props;
|
||||
const [value, setValue] = useState(originalValue);
|
||||
const [showEmojis, setShowEmojis] = useState(false);
|
||||
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
|
||||
const [editor] = useState(() => withImages(withReact(createEditor())));
|
||||
|
||||
const text = useRef(value);
|
||||
|
||||
// large is 40px
|
||||
const size = 'small';
|
||||
|
||||
const sendMessage = () => {
|
||||
|
@ -30,41 +104,46 @@ export default function ChatTextField(props: Props) {
|
|||
return;
|
||||
}
|
||||
|
||||
const message = convertToText(value);
|
||||
const message = serialize(editor);
|
||||
|
||||
websocketService.send({ type: MessageType.CHAT, body: message });
|
||||
setValue('');
|
||||
|
||||
// Clear the editor.
|
||||
Transforms.select(editor, [0, editor.children.length - 1]);
|
||||
Transforms.delete(editor);
|
||||
};
|
||||
|
||||
const handleChange = evt => {
|
||||
text.current = evt.target.value;
|
||||
setValue(evt.target.value);
|
||||
};
|
||||
const handleChange = e => {};
|
||||
|
||||
const handleKeyDown = event => {
|
||||
const key = event && event.key;
|
||||
|
||||
if (key === 'Enter') {
|
||||
const onKeyDown = e => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
sendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: originalValue }],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input.Group compact style={{ display: 'flex', width: '100%', position: 'absolute' }}>
|
||||
<ContentEditable
|
||||
style={{ width: '60%', maxHeight: '50px', padding: '5px' }}
|
||||
html={text.current}
|
||||
onChange={handleChange}
|
||||
onKeyDown={e => {
|
||||
handleKeyDown(e);
|
||||
}}
|
||||
<Slate editor={editor} value={initialValue} onChange={handleChange}>
|
||||
<Editable
|
||||
onKeyDown={onKeyDown}
|
||||
renderElement={props => <Element {...props} />}
|
||||
placeholder="Chat message goes here..."
|
||||
/>
|
||||
<Button type="default" ghost title="Emoji" onClick={() => setShowEmojis(!showEmojis)}>
|
||||
<SmileOutlined style={{ color: 'rgba(0,0,0,.45)' }} />
|
||||
</Button>
|
||||
<Button size={size} type="primary" onClick={sendMessage}>
|
||||
Submit
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Slate>
|
||||
<Button type="default" ghost title="Emoji" onClick={() => setShowEmojis(!showEmojis)}>
|
||||
<SmileOutlined style={{ color: 'rgba(0,0,0,.45)' }} />
|
||||
</Button>
|
||||
<Button size={size} type="primary" onClick={sendMessage}>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
168
web/package-lock.json
generated
168
web/package-lock.json
generated
|
@ -33,6 +33,8 @@
|
|||
"react-markdown-editor-lite": "1.3.2",
|
||||
"react-virtuoso": "^2.10.2",
|
||||
"recoil": "^0.7.2",
|
||||
"slate": "^0.78.0",
|
||||
"slate-react": "^0.79.0",
|
||||
"ua-parser-js": "1.0.2",
|
||||
"video.js": "^7.18.1"
|
||||
},
|
||||
|
@ -10813,6 +10815,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.1.tgz",
|
||||
"integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q=="
|
||||
},
|
||||
"node_modules/@types/is-hotkey": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.7.tgz",
|
||||
"integrity": "sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ=="
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||
|
@ -10859,6 +10866,11 @@
|
|||
"integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "12.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
|
||||
|
@ -15461,6 +15473,18 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==",
|
||||
"bin": {
|
||||
"direction": "cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
|
@ -19065,6 +19089,15 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "9.0.12",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
|
||||
"integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
|
||||
|
@ -19597,6 +19630,11 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-hotkey": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.1.8.tgz",
|
||||
"integrity": "sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ=="
|
||||
},
|
||||
"node_modules/is-installed-globally": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
|
||||
|
@ -28434,6 +28472,52 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/slate": {
|
||||
"version": "0.78.0",
|
||||
"resolved": "https://registry.npmjs.org/slate/-/slate-0.78.0.tgz",
|
||||
"integrity": "sha512-VwQ0RafT3JPf9SFrXI02Dh3S4Iz9en7d1nn50C/LJjjqjfgv+a2ORbgWMdYjhycPYldaxJwcI3OpP9D1g4SXEg==",
|
||||
"dependencies": {
|
||||
"immer": "^9.0.6",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"tiny-warning": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/slate-react": {
|
||||
"version": "0.79.0",
|
||||
"resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.79.0.tgz",
|
||||
"integrity": "sha512-uPzYArGwHKq4QvpzRvP/DVvsDgB2Zw6x9Som/hJWaydu18r0Vp2vmgHL0Dbc4EU6pUNV6o83XbBJLLEwISzBHQ==",
|
||||
"dependencies": {
|
||||
"@types/is-hotkey": "^0.1.1",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"direction": "^1.0.3",
|
||||
"is-hotkey": "^0.1.6",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"lodash": "^4.17.4",
|
||||
"scroll-into-view-if-needed": "^2.2.20",
|
||||
"tiny-invariant": "1.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0",
|
||||
"slate": ">=0.65.3"
|
||||
}
|
||||
},
|
||||
"node_modules/slate-react/node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/slate/node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/snapdragon": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||
|
@ -29808,6 +29892,16 @@
|
|||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.6.tgz",
|
||||
"integrity": "sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA=="
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"node_modules/tlds": {
|
||||
"version": "1.231.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.231.0.tgz",
|
||||
|
@ -39698,6 +39792,11 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.1.tgz",
|
||||
"integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q=="
|
||||
},
|
||||
"@types/is-hotkey": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.7.tgz",
|
||||
"integrity": "sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ=="
|
||||
},
|
||||
"@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||
|
@ -39744,6 +39843,11 @@
|
|||
"integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"@types/markdown-it": {
|
||||
"version": "12.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz",
|
||||
|
@ -43358,6 +43462,11 @@
|
|||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ=="
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
|
@ -46160,6 +46269,11 @@
|
|||
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"version": "9.0.12",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
|
||||
"integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
|
||||
},
|
||||
"immutable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
|
||||
|
@ -46529,6 +46643,11 @@
|
|||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
|
||||
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="
|
||||
},
|
||||
"is-hotkey": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.1.8.tgz",
|
||||
"integrity": "sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ=="
|
||||
},
|
||||
"is-installed-globally": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
|
||||
|
@ -53282,6 +53401,45 @@
|
|||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
},
|
||||
"slate": {
|
||||
"version": "0.78.0",
|
||||
"resolved": "https://registry.npmjs.org/slate/-/slate-0.78.0.tgz",
|
||||
"integrity": "sha512-VwQ0RafT3JPf9SFrXI02Dh3S4Iz9en7d1nn50C/LJjjqjfgv+a2ORbgWMdYjhycPYldaxJwcI3OpP9D1g4SXEg==",
|
||||
"requires": {
|
||||
"immer": "^9.0.6",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"tiny-warning": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"slate-react": {
|
||||
"version": "0.79.0",
|
||||
"resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.79.0.tgz",
|
||||
"integrity": "sha512-uPzYArGwHKq4QvpzRvP/DVvsDgB2Zw6x9Som/hJWaydu18r0Vp2vmgHL0Dbc4EU6pUNV6o83XbBJLLEwISzBHQ==",
|
||||
"requires": {
|
||||
"@types/is-hotkey": "^0.1.1",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"direction": "^1.0.3",
|
||||
"is-hotkey": "^0.1.6",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"lodash": "^4.17.4",
|
||||
"scroll-into-view-if-needed": "^2.2.20",
|
||||
"tiny-invariant": "1.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||
|
@ -54368,6 +54526,16 @@
|
|||
"setimmediate": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.6.tgz",
|
||||
"integrity": "sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA=="
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"tlds": {
|
||||
"version": "1.231.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.231.0.tgz",
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
"react-markdown-editor-lite": "1.3.2",
|
||||
"react-virtuoso": "^2.10.2",
|
||||
"recoil": "^0.7.2",
|
||||
"slate": "^0.78.0",
|
||||
"slate-react": "^0.79.0",
|
||||
"ua-parser-js": "1.0.2",
|
||||
"video.js": "^7.18.1"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue