asma-ui-richeditor 0.1.11-grisha → 0.1.12-grisha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/package.json +147 -0
  2. package/dist/src/index.d.ts +1 -0
  3. package/dist/src/index.js +1 -0
  4. package/dist/src/rich-input/RichInput.d.ts +13 -0
  5. package/dist/src/rich-input/RichInput.jsx +129 -0
  6. package/dist/src/rich-input/components/CustomMenuItem.d.ts +3 -0
  7. package/dist/src/rich-input/components/CustomMenuItem.jsx +13 -0
  8. package/dist/src/rich-input/components/FontSizeSelect.d.ts +7 -0
  9. package/dist/src/rich-input/components/FontSizeSelect.jsx +53 -0
  10. package/dist/src/rich-input/components/LinkDialog.d.ts +10 -0
  11. package/dist/src/rich-input/components/LinkDialog.jsx +56 -0
  12. package/dist/src/rich-input/components/Toolbar.d.ts +13 -0
  13. package/dist/src/rich-input/components/Toolbar.jsx +202 -0
  14. package/dist/src/rich-input/helpers/EditorExtensions.d.ts +4 -0
  15. package/dist/src/rich-input/helpers/EditorExtensions.jsx +25 -0
  16. package/dist/src/rich-input/hooks/useToggleMenuVisibility.hook.d.ts +6 -0
  17. package/dist/src/rich-input/hooks/useToggleMenuVisibility.hook.js +12 -0
  18. package/dist/src/rich-input/interfaces/types.d.ts +26 -0
  19. package/dist/src/rich-input/interfaces/types.js +1 -0
  20. package/dist/src/stories/RichInput.stories.d.ts +9 -0
  21. package/dist/src/stories/RichInput.stories.jsx +33 -0
  22. package/dist/src/stories/RichInputV2.stories.d.ts +9 -0
  23. package/dist/src/stories/RichInputV2.stories.jsx +40 -0
  24. package/dist/tailwind.config.d.ts +265 -0
  25. package/dist/tailwind.config.js +21 -0
  26. package/dist/tsconfig.tsbuildinfo +1 -0
  27. package/dist/vite.config.d.ts +2 -0
  28. package/dist/vite.config.js +41 -0
  29. package/package.json +147 -146
@@ -0,0 +1,147 @@
1
+ {
2
+ "name": "asma-ui-richeditor",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.1.11-grisha",
7
+ "type": "module",
8
+ "files": [
9
+ "dist/**/*",
10
+ "dist/style.css",
11
+ "tw-configs/**/*"
12
+ ],
13
+ "keywords": [],
14
+ "author": "asma-team",
15
+ "types": "./dist/index.d.ts",
16
+ "main": "./dist/asma-ui-richeditor.es.js",
17
+ "module": "./dist/asma-ui-richeditor.es.js",
18
+ "exports": {
19
+ ".": {
20
+ "import": "./dist/asma-ui-richeditor.es.js",
21
+ "types": "./dist/index.d.ts"
22
+ },
23
+ "./dist/style.css": "./dist/style.css",
24
+ "./tw-configs/twConfigs.json": "./tw-configs/twConfigs.json"
25
+ },
26
+ "scripts": {
27
+ "dev": "vite",
28
+ "build": "npx tsc && rm -rf ./dist && vite build",
29
+ "build:win": "rimraf ./dist && npx tsc && vite build",
30
+ "preview": "vite preview",
31
+ "lint": "eslint src/**/*.{js,jsx,ts,tsx}",
32
+ "version": "echo $npm_package_version",
33
+ "lint:fix": "eslint --fix src/**/*.{jsx,ts,tsx}",
34
+ "prettier": "prettier --write src//**/*.{ts,tsx,scss} --config ./.prettierrc",
35
+ "storybook": "storybook dev -p 6006",
36
+ "storybook:no-browser": "storybook dev -p 6006 --no-open",
37
+ "storybook:node18": "export NODE_OPTIONS=--openssl-legacy-provider && storybook dev -p 6006",
38
+ "storybook:node18:win": "set NODE_OPTIONS=--openssl-legacy-provider && storybook dev -p 6006",
39
+ "build-storybook": "export NODE_OPTIONS=--max_old_space_size=6240 && storybook build",
40
+ "test-storybook": "test-storybook",
41
+ "changeset:pre-beta": "changeset pre enter beta",
42
+ "changeset:pre-exit": "changeset pre exit",
43
+ "changeset:version": "changeset version",
44
+ "changeset:publish": "changeset publish",
45
+ "changeset:status": "changeset status"
46
+ },
47
+ "license": "UNLICENSED",
48
+ "dependencies": {
49
+ "@emoji-mart/data": "^1.2.1",
50
+ "@emoji-mart/react": "^1.1.1",
51
+ "@emotion/react": "^11.11.1",
52
+ "@emotion/styled": "^11.11.0",
53
+ "@floating-ui/react": "^0.27.13",
54
+ "@fontsource/roboto": "^5.0.4",
55
+ "@iconify/react": "^5.0.2",
56
+ "@mui/material": "^5.13.7",
57
+ "@tiptap/core": "^2.11.7",
58
+ "@tiptap/extension-blockquote": "^2.11.7",
59
+ "@tiptap/extension-bold": "^2.11.7",
60
+ "@tiptap/extension-bullet-list": "^2.11.7",
61
+ "@tiptap/extension-color": "^2.11.7",
62
+ "@tiptap/extension-document": "^2.11.7",
63
+ "@tiptap/extension-hard-break": "^2.11.7",
64
+ "@tiptap/extension-heading": "^2.11.7",
65
+ "@tiptap/extension-horizontal-rule": "^2.11.7",
66
+ "@tiptap/extension-italic": "^2.11.7",
67
+ "@tiptap/extension-link": "^2.11.7",
68
+ "@tiptap/extension-list-item": "^2.11.7",
69
+ "@tiptap/extension-ordered-list": "^2.11.7",
70
+ "@tiptap/extension-paragraph": "^2.11.7",
71
+ "@tiptap/extension-placeholder": "^2.11.7",
72
+ "@tiptap/extension-strike": "^2.11.7",
73
+ "@tiptap/extension-text": "^2.11.7",
74
+ "@tiptap/extension-text-style": "^2.11.7",
75
+ "@tiptap/extension-underline": "^2.11.7",
76
+ "@tiptap/react": "^2.11.7",
77
+ "asma-ui-richeditor": "link:../../Users/Ranzi/AppData/Local/pnpm/global/5/node_modules/asma-ui-richeditor",
78
+ "clsx": "^2.1.1",
79
+ "emoji-mart": "^5.6.0",
80
+ "node": "18.17.0",
81
+ "react": "^18.2.0",
82
+ "react-dom": "^18.2.0",
83
+ "tailwind-merge": "^2.5.4",
84
+ "tiptap-extension-font-size": "^1.2.0"
85
+ },
86
+ "devDependencies": {
87
+ "@changesets/cli": "^2.26.2",
88
+ "@faker-js/faker": "^8.0.2",
89
+ "@rollup/plugin-terser": "^0.4.3",
90
+ "@storybook/addon-a11y": "^7.6.9",
91
+ "@storybook/addon-essentials": "^7.6.9",
92
+ "@storybook/addon-interactions": "^7.6.9",
93
+ "@storybook/addon-links": "^7.6.9",
94
+ "@storybook/addon-mdx-gfm": "^7.6.9",
95
+ "@storybook/addon-styling": "^1.3.7",
96
+ "@storybook/addons": "^7.6.9",
97
+ "@storybook/blocks": "^7.6.9",
98
+ "@storybook/manager-api": "^7.6.9",
99
+ "@storybook/preset-create-react-app": "^7.6.9",
100
+ "@storybook/react": "^7.6.9",
101
+ "@storybook/react-vite": "^7.6.9",
102
+ "@storybook/test-runner": "^0.16.0",
103
+ "@storybook/testing-library": "^0.2.2",
104
+ "@storybook/theming": "^7.6.9",
105
+ "@types/lodash-es": "^4.17.7",
106
+ "@types/node": "^18.0.3",
107
+ "@types/react": "^18.0.37",
108
+ "@types/react-dom": "^18.0.11",
109
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
110
+ "@typescript-eslint/parser": "^5.59.0",
111
+ "@vitejs/plugin-react": "^4.0.0",
112
+ "asma-core-ui": "^3.0.147",
113
+ "autoprefixer": "^10.4.14",
114
+ "axe-playwright": "^1.2.3",
115
+ "axios": "^1.6.8",
116
+ "eslint": "^8.38.0",
117
+ "eslint-plugin-react-hooks": "^4.6.0",
118
+ "eslint-plugin-react-refresh": "^0.3.4",
119
+ "eslint-plugin-storybook": "^0.6.15",
120
+ "postcss": "^8.4.24",
121
+ "prop-types": "^15.8.1",
122
+ "rimraf": "^6.0.1",
123
+ "rollup-plugin-typescript2": "^0.35.0",
124
+ "storybook": "^7.6.9",
125
+ "storybook-addon-themes": "^6.1.0",
126
+ "tailwind-scrollbar": "^3.1.0",
127
+ "tailwindcss": "^3.3.2",
128
+ "typescript": "^5.0.2",
129
+ "typescript-plugin-css-modules": "^5.0.1",
130
+ "vite": "^4.3.9",
131
+ "vite-plugin-css-injected-by-js": "^3.5.1",
132
+ "vite-plugin-dts": "^3.1.1",
133
+ "vite-tsconfig-paths": "^4.2.0"
134
+ },
135
+ "peerDependencies": {
136
+ "@emotion/react": "^11.*",
137
+ "@emotion/styled": "^11.*",
138
+ "@mui/material": "^5.*",
139
+ "immer": "^9.*",
140
+ "react": "^18.*",
141
+ "react-dom": "^18.*"
142
+ },
143
+ "resolutions": {
144
+ "@types/node": "18.0.3",
145
+ "node": "18.17.0"
146
+ }
147
+ }
@@ -0,0 +1 @@
1
+ export * from './rich-input/RichInput';
@@ -0,0 +1 @@
1
+ export * from './rich-input/RichInput';
@@ -0,0 +1,13 @@
1
+ import { type FC } from 'react';
2
+ import './styles/tiptap.css';
3
+ import type { IRichInput } from './interfaces/types';
4
+ /**
5
+ * ASMA RichInput - A rich text editor component.
6
+ *
7
+ * @param readOnly - Determines the display style in read-only mode.
8
+ * Options:
9
+ * - `'plain'`: Displays the editor with a white background and no borders.
10
+ * - `'outlined'`: Displays the editor with a gray background and visible borders.
11
+ */
12
+ declare const RichInput: FC<IRichInput>;
13
+ export { RichInput };
@@ -0,0 +1,129 @@
1
+ import { useEffect, useImperativeHandle, useRef, useState } from 'react';
2
+ import clsx from 'clsx';
3
+ import { EditorContent, useEditor } from '@tiptap/react';
4
+ import { Toolbar } from './components/Toolbar';
5
+ import './styles/tiptap.css';
6
+ import { StyledFormControl, StyledFormHelperText } from 'asma-core-ui';
7
+ import { Icon } from '@iconify/react';
8
+ import { defaultExtensions, editModeExtensions } from './helpers/EditorExtensions';
9
+ import { LinkDialog } from './components/LinkDialog';
10
+ import Placeholder from '@tiptap/extension-placeholder';
11
+ import data, {} from '@emoji-mart/data';
12
+ import Picker from '@emoji-mart/react';
13
+ /**
14
+ * ASMA RichInput - A rich text editor component.
15
+ *
16
+ * @param readOnly - Determines the display style in read-only mode.
17
+ * Options:
18
+ * - `'plain'`: Displays the editor with a white background and no borders.
19
+ * - `'outlined'`: Displays the editor with a gray background and visible borders.
20
+ */
21
+ const RichInput = ({ dataTest, attachmentsMenu, id, inputRef, className, editorClassName, disabled, readOnly, error, locale,
22
+ // label, // this in not implemented yet
23
+ title, placeholder, helperText, required, maxScrollableHeight, toolbarDefaultVisible, hideToolbar, noDefaultStyles, ...props }) => {
24
+ const cursor = useRef();
25
+ const [wasTouched, setWasTouched] = useState(false);
26
+ const editor = useEditor({
27
+ ...props,
28
+ extensions: [
29
+ Placeholder.configure({ placeholder }),
30
+ ...defaultExtensions,
31
+ ...editModeExtensions,
32
+ ...(props.extensions || []),
33
+ ],
34
+ parseOptions: {
35
+ preserveWhitespace: true,
36
+ ...props.parseOptions,
37
+ },
38
+ shouldRerenderOnTransaction: props.shouldRerenderOnTransaction || false,
39
+ immediatelyRender: props.immediatelyRender || true,
40
+ editable: props.editable || (!disabled && !readOnly),
41
+ onSelectionUpdate: (updateProps) => {
42
+ props.onSelectionUpdate?.(updateProps);
43
+ cursor.current = updateProps.editor.state.selection.anchor;
44
+ updateProps.editor.commands.focus();
45
+ },
46
+ },
47
+ //NOTE: the dependency list doesn't accept the props object without creating a max call stack error
48
+ [
49
+ props.extensions,
50
+ props.shouldRerenderOnTransaction,
51
+ props.immediatelyRender,
52
+ props.editable,
53
+ props.content,
54
+ disabled,
55
+ readOnly,
56
+ placeholder,
57
+ ]);
58
+ useEffect(() => {
59
+ if (cursor.current === undefined)
60
+ return;
61
+ editor?.commands.setTextSelection(cursor.current);
62
+ }, [props.content, editor]);
63
+ const [showToolbar, setShowToolbar] = useState(toolbarDefaultVisible);
64
+ const [linkDialogVisible, setLinkDialogVisible] = useState(false);
65
+ useImperativeHandle(inputRef, () => editor);
66
+ const [focused, setFocused] = useState(false);
67
+ const [emojiPickerVisible, setEmojiPickerVisible] = useState(false);
68
+ const isEmpty = editor?.isEmpty ?? true;
69
+ useEffect(() => {
70
+ const handleFocus = () => setFocused(true);
71
+ const handleBlur = () => setFocused(false);
72
+ editor?.on('focus', handleFocus);
73
+ editor?.on('blur', handleBlur);
74
+ return () => {
75
+ editor?.off('focus', handleFocus);
76
+ editor?.off('blur', handleBlur);
77
+ };
78
+ }, [editor]);
79
+ const handleEmojiSelect = (emoji) => {
80
+ if (editor) {
81
+ editor.chain().focus().insertContent(emoji.native).run();
82
+ }
83
+ setEmojiPickerVisible(false);
84
+ };
85
+ const isFieldEmpty = editor?.isEmpty;
86
+ const showError = !readOnly && error && isFieldEmpty;
87
+ if (!editor)
88
+ return null;
89
+ return (<div className='w-full flex justify-between flex-col'>
90
+ <StyledFormControl className={className}>
91
+ {title && <p className='font-semibold text-base text-gray-700 mb-2'>{title}</p>}
92
+ <div className={clsx(!noDefaultStyles && 'rte-wrapper', readOnly === 'outlined' && 'readonly-outlined', readOnly === 'plain' && 'readonly-plain', !readOnly && showError && (focused ? 'error-focused-state' : 'error-state'), !readOnly && !showError && focused && 'focused-state')}>
93
+ <div className='relative'>
94
+ <EditorContent data-test={dataTest} id={id} className={clsx('border-none rounded-none w-full min-h-[80px]', !noDefaultStyles && 'core-ui-rte', !hideToolbar && !disabled && !readOnly && !showToolbar && 'displace-text', !noDefaultStyles && !disabled && !readOnly && 'edit-mode', editorClassName)} editor={editor} onClick={() => editor?.chain().focus().run()} style={showToolbar ? { height: '20px' } : undefined}/>
95
+
96
+ {!hideToolbar && !disabled && !readOnly && (<div className='absolute top-1 right-1 bottom-1 flex flex-col gap-4 items-center z-10'>
97
+ {!showToolbar && (<Icon onClick={() => {
98
+ setShowToolbar(true);
99
+ }} className='cursor-pointer iconButton' icon='material-symbols:format-color-text' color='var(--colors-gray-700)' height={24} width={24}/>)}
100
+
101
+ {attachmentsMenu ?? (
102
+ // <Icon
103
+ // className='iconButton'
104
+ // icon='material-symbols:attach-file'
105
+ // color='var(--colors-gray-700)'
106
+ // height={24}
107
+ // width={24}
108
+ // />
109
+ <div></div>)}
110
+ </div>)}
111
+ </div>
112
+ {!hideToolbar && !disabled && !readOnly && showToolbar && (<Toolbar editor={editor} onClose={() => setShowToolbar(false)} error={error} focused={focused} openLinkDialog={() => setLinkDialogVisible(true)} openEmojiPicker={() => setEmojiPickerVisible(true)} locale={locale}/>)}
113
+ </div>
114
+
115
+ {showError && helperText && (<StyledFormHelperText error data-test={`error-${dataTest}`}>
116
+ {helperText}
117
+ </StyledFormHelperText>)}
118
+ </StyledFormControl>
119
+
120
+ <LinkDialog open={linkDialogVisible} setOpen={setLinkDialogVisible} editor={editor} locale={locale}/>
121
+
122
+ {emojiPickerVisible && (<div className='fixed inset-0 bg-black/20 z-[9999] flex items-center justify-center' onClick={() => setEmojiPickerVisible(false)}>
123
+ <div onClick={(e) => e.stopPropagation()}>
124
+ <Picker theme='light' data={data} onEmojiSelect={handleEmojiSelect} locale={locale}/>
125
+ </div>
126
+ </div>)}
127
+ </div>);
128
+ };
129
+ export { RichInput };
@@ -0,0 +1,3 @@
1
+ import type { MenuItemProps } from '@mui/material';
2
+ import React from 'react';
3
+ export declare const CustomMenuItem: (props: MenuItemProps) => React.JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { StyledMenuItem } from 'asma-core-ui';
2
+ import React from 'react';
3
+ export const CustomMenuItem = (props) => {
4
+ return (<StyledMenuItem {...props} sx={{
5
+ '&.MuiMenuItem-root': {
6
+ color: 'var(--colors-delta-700)',
7
+ fontSize: '14px',
8
+ lineHeight: '20px',
9
+ },
10
+ }}>
11
+ {props.children}
12
+ </StyledMenuItem>);
13
+ };
@@ -0,0 +1,7 @@
1
+ import { type TextFieldProps } from 'asma-core-ui';
2
+ import React from 'react';
3
+ import '../styles/toolbar.css';
4
+ import type { Editor } from '@tiptap/core';
5
+ export declare const FontSizeSelect: (props: TextFieldProps & {
6
+ editor: Editor;
7
+ }) => React.JSX.Element;
@@ -0,0 +1,53 @@
1
+ import { Icon } from '@iconify/react';
2
+ import { StyledInputField } from 'asma-core-ui';
3
+ import React, { useLayoutEffect, useState } from 'react';
4
+ import '../styles/toolbar.css';
5
+ const fontSizeMap = {
6
+ small: '10px',
7
+ normal: '16px',
8
+ large: '24px',
9
+ huge: '32px',
10
+ };
11
+ export const FontSizeSelect = (props) => {
12
+ const { editor } = props;
13
+ const [selectedSize, setSelectedSize] = useState('normal');
14
+ const handleFontSizeChange = (event) => {
15
+ const selectedSize = event.target.value;
16
+ editor.chain().focus().setMark('textStyle', { fontSize: fontSizeMap[selectedSize] }).run();
17
+ setSelectedSize(selectedSize);
18
+ };
19
+ useLayoutEffect(() => {
20
+ const { from, to } = editor.state.selection;
21
+ editor.state.doc.nodesBetween(from - 1, to, (node) => {
22
+ if (node.marks) {
23
+ const textStyleMark = node.marks.find((mark) => mark.type.name === 'textStyle');
24
+ const fontSize = textStyleMark?.attrs['fontSize'];
25
+ const currentFontSize = Object.keys(fontSizeMap).find((key) => fontSizeMap[key] === fontSize) || 'normal';
26
+ setSelectedSize(currentFontSize);
27
+ }
28
+ });
29
+ }, [editor.state.selection, editor.state.doc]);
30
+ return (<StyledInputField {...props} select size='small' dataTest='font-size-select' onChange={handleFontSizeChange} value={selectedSize} SelectProps={{ IconComponent: () => null }} InputProps={{
31
+ endAdornment: <Icon icon='tabler:caret-up-down-filled' className='chevron-icon'/>,
32
+ }} sx={{
33
+ '.MuiSelect-select': {
34
+ border: 'none',
35
+ padding: 0,
36
+ overflow: 'hidden',
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ color: 'var(--colors-delta-700)',
40
+ fontSize: '14px',
41
+ lineHeight: '20px',
42
+ },
43
+ '.MuiOutlinedInput-root': {
44
+ height: '32px',
45
+ width: '75px',
46
+ '& .MuiOutlinedInput-notchedOutline': {
47
+ border: 'none',
48
+ },
49
+ },
50
+ }}>
51
+ {props.children}
52
+ </StyledInputField>);
53
+ };
@@ -0,0 +1,10 @@
1
+ import type { Editor } from '@tiptap/react';
2
+ import React from 'react';
3
+ import '../styles/toolbar.css';
4
+ import type { ILocale } from '../interfaces/types';
5
+ export declare const LinkDialog: React.FC<{
6
+ open: boolean;
7
+ setOpen: (value: boolean) => void;
8
+ editor: Editor;
9
+ locale?: ILocale;
10
+ }>;
@@ -0,0 +1,56 @@
1
+ import { StyledButton, StyledDialog, StyledInputField } from 'asma-core-ui';
2
+ import React, { useLayoutEffect, useMemo, useState } from 'react';
3
+ import styles from './LinkDialog.module.scss';
4
+ import '../styles/toolbar.css';
5
+ export const LinkDialog = ({ open, setOpen, editor, locale }) => {
6
+ const [url, setUrl] = useState('');
7
+ const isNorsk = useMemo(() => locale === 'no', [locale]);
8
+ useLayoutEffect(() => {
9
+ if (open) {
10
+ const { from, to } = editor.state.selection;
11
+ let currentLink = null;
12
+ editor.state.doc.nodesBetween(from - 1, to, (node) => {
13
+ if (node.marks) {
14
+ const linkMark = node.marks.find((mark) => mark.type.name === 'link');
15
+ if (linkMark) {
16
+ currentLink = linkMark.attrs['href'];
17
+ }
18
+ }
19
+ });
20
+ if (currentLink)
21
+ setUrl(currentLink);
22
+ else
23
+ setUrl('');
24
+ const input = document.querySelector('[data-test="link-input-field"]');
25
+ input?.focus();
26
+ }
27
+ }, [open, editor]);
28
+ const makeLink = () => {
29
+ editor.chain().focus().setLink({ href: url }).run();
30
+ setOpen(false);
31
+ setUrl('');
32
+ };
33
+ return (<StyledDialog open={open} dataTest={'link-modal-rte'} onClose={() => setOpen(false)} className={'z-[99]'} dialogTitle={<div className={'text-gray-700'}>{isNorsk ? 'Legg til lenke' : 'Add link'}</div>}>
34
+ <div className={styles['link-dialog-container']}>
35
+ <div className='link-input-field'>
36
+ <StyledInputField autoFocus multiline className='w-full' dataTest={'link-input-field'} size={'small'} sx={{
37
+ '& .MuiInputBase-root': {
38
+ minHeight: 64,
39
+ alignItems: 'start',
40
+ },
41
+ }} value={url} onChange={(e) => setUrl(e.target.value)}/>
42
+ </div>
43
+ <div className={'flex gap-2 p-0 w-full justify-end'}>
44
+ <StyledButton dataTest={'delete-customer-reject-button'} size={'medium'} variant={'outlined'} onClick={() => {
45
+ setOpen(false);
46
+ setUrl('');
47
+ }}>
48
+ {isNorsk ? 'Avbryt' : 'Cancel'}
49
+ </StyledButton>
50
+ <StyledButton dataTest={'delete-customer-confirm-button'} size={'medium'} variant={'contained'} onClick={makeLink}>
51
+ {isNorsk ? 'Legg til lenke' : 'Add link'}
52
+ </StyledButton>
53
+ </div>
54
+ </div>
55
+ </StyledDialog>);
56
+ };
@@ -0,0 +1,13 @@
1
+ import { Editor } from '@tiptap/react';
2
+ import '../styles/toolbar.css';
3
+ import type { ILocale } from '../interfaces/types';
4
+ export declare const Toolbar: ({ editor, onClose, error, focused, openLinkDialog, openEmojiPicker, locale, emojiButtonRef, }: {
5
+ editor: Editor;
6
+ onClose: () => void;
7
+ error?: boolean;
8
+ focused: boolean;
9
+ openLinkDialog: () => void;
10
+ openEmojiPicker: () => void;
11
+ locale?: ILocale;
12
+ emojiButtonRef?: React.RefObject<HTMLSpanElement>;
13
+ }) => import("node_modules/@types/react").JSX.Element;