hero-editor 1.17.0 → 2.1.0
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.
- package/dist/app.js +1 -1
- package/dist/app.js.map +1 -1
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/package.json +11 -7
- package/src/components/Icon.js +4 -0
- package/src/components/Toolbar.js +29 -0
- package/src/constants.js +4 -0
- package/src/helpers/apply.js +4 -1
- package/src/helpers/compose.js +4 -2
- package/src/helpers/flow.js +4 -2
- package/src/helpers/why.js +9 -1
- package/src/lib.js +8 -1
- package/src/plugins/__tests__/__snapshots__/headingFour.test.js.snap +11 -0
- package/src/plugins/__tests__/__snapshots__/headingThree.test.js.snap +11 -0
- package/src/plugins/__tests__/dropdown.test.js +60 -0
- package/src/plugins/__tests__/headingFour.test.js +27 -0
- package/src/plugins/__tests__/headingOne.test.js +6 -0
- package/src/plugins/__tests__/headingThree.test.js +27 -0
- package/src/plugins/__tests__/headingTwo.test.js +6 -0
- package/src/plugins/dropdown.js +48 -0
- package/src/plugins/headingFour.js +62 -0
- package/src/plugins/headingOne.js +7 -3
- package/src/plugins/headingThree.js +62 -0
- package/src/plugins/headingTwo.js +7 -3
- package/src/plugins/index.js +3 -0
- package/src/transformers/react.js +6 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hero-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/lib.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,15 +13,16 @@
|
|
|
13
13
|
"author": "",
|
|
14
14
|
"license": "ISC",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@babel/core": "^7.
|
|
17
|
-
"@babel/preset-env": "^7.
|
|
18
|
-
"@babel/preset-react": "^7.
|
|
16
|
+
"@babel/core": "^7.26.0",
|
|
17
|
+
"@babel/preset-env": "^7.26.0",
|
|
18
|
+
"@babel/preset-react": "^7.25.9",
|
|
19
19
|
"@testing-library/react": "^10.2.1",
|
|
20
20
|
"@testing-library/react-hooks": "^3.3.0",
|
|
21
21
|
"@webpack-cli/serve": "^2.0.5",
|
|
22
|
-
"babel-jest": "^
|
|
23
|
-
"babel-loader": "^
|
|
24
|
-
"jest": "^
|
|
22
|
+
"babel-jest": "^29.7.0",
|
|
23
|
+
"babel-loader": "^9.2.1",
|
|
24
|
+
"jest": "^29.7.0",
|
|
25
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
25
26
|
"react": "^16.13.1",
|
|
26
27
|
"react-dom": "^16.13.1",
|
|
27
28
|
"react-test-renderer": "^16.13.1",
|
|
@@ -40,5 +41,8 @@
|
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"react": "^16.13.1",
|
|
42
43
|
"react-dom": "^16.13.1"
|
|
44
|
+
},
|
|
45
|
+
"jest": {
|
|
46
|
+
"testEnvironment": "jsdom"
|
|
43
47
|
}
|
|
44
48
|
}
|
package/src/components/Icon.js
CHANGED
|
@@ -15,6 +15,10 @@ const svgIcons = {
|
|
|
15
15
|
'<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14h-2V9h-2V7h4v10z"/></svg>',
|
|
16
16
|
looks_two:
|
|
17
17
|
'<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 8c0 1.11-.9 2-2 2h-2v2h4v2H9v-4c0-1.11.9-2 2-2h2V9H9V7h4c1.1 0 2 .89 2 2v2z"/></svg>',
|
|
18
|
+
looks_three:
|
|
19
|
+
'<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M360-280h160q33 0 56.5-23.5T600-360v-60q0-26-17-43t-43-17q26 0 43-17t17-43v-60q0-33-23.5-56.5T520-680H360v80h160v80h-80v80h80v80H360v80ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"/></svg>',
|
|
20
|
+
looks_four:
|
|
21
|
+
'<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M520-280h80v-400h-80v160h-80v-160h-80v240h160v160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"/></svg>',
|
|
18
22
|
link: '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M13.723 18.654l-3.61 3.609c-2.316 2.315-6.063 2.315-8.378 0-1.12-1.118-1.735-2.606-1.735-4.188 0-1.582.615-3.07 1.734-4.189l4.866-4.865c2.355-2.355 6.114-2.262 8.377 0 .453.453.81.973 1.089 1.527l-1.593 1.592c-.18-.613-.5-1.189-.964-1.652-1.448-1.448-3.93-1.51-5.439-.001l-.001.002-4.867 4.865c-1.5 1.499-1.5 3.941 0 5.44 1.517 1.517 3.958 1.488 5.442 0l2.425-2.424c.993.284 1.791.335 2.654.284zm.161-16.918l-3.574 3.576c.847-.05 1.655 0 2.653.283l2.393-2.389c1.498-1.502 3.94-1.5 5.44-.001 1.517 1.518 1.486 3.959 0 5.442l-4.831 4.831-.003.002c-1.438 1.437-3.886 1.552-5.439-.002-.473-.474-.785-1.042-.956-1.643l-.084.068-1.517 1.515c.28.556.635 1.075 1.088 1.528 2.245 2.245 6.004 2.374 8.378 0l4.832-4.831c2.314-2.316 2.316-6.062-.001-8.377-2.317-2.321-6.067-2.313-8.379-.002z"/></svg>',
|
|
19
23
|
icon: '<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.75 0C10.0637 0 12.75 2.68629 12.75 6C12.75 9.31371 10.0637 12 6.75 12C3.43629 12 0.75 9.31371 0.75 6C0.75 2.68629 3.43629 0 6.75 0ZM6.75 0.84375C3.90228 0.84375 1.59375 3.15228 1.59375 6C1.59375 8.84772 3.90228 11.1562 6.75 11.1562C9.59772 11.1562 11.9062 8.84772 11.9062 6C11.9062 3.15228 9.59772 0.84375 6.75 0.84375ZM8.83711 7.61484C9.04551 7.71904 9.12998 7.97246 9.02578 8.18086C8.53481 9.16281 7.75947 9.67969 6.75 9.67969C5.74053 9.67969 4.96519 9.16281 4.47422 8.18086C4.37002 7.97246 4.45449 7.71904 4.66289 7.61484C4.87129 7.51064 5.12471 7.59512 5.22891 7.80352C5.58168 8.50907 6.07197 8.83594 6.75 8.83594C7.42803 8.83594 7.91832 8.50907 8.27109 7.80352C8.37529 7.59512 8.62871 7.51064 8.83711 7.61484ZM4.3125 3.76172C4.83027 3.76172 5.25 4.18146 5.25 4.69922C5.25 5.21699 4.83027 5.63672 4.3125 5.63672C3.79473 5.63672 3.375 5.21699 3.375 4.69922C3.375 4.18146 3.79473 3.76172 4.3125 3.76172ZM9.15234 3.76172C9.67011 3.76172 10.0898 4.18146 10.0898 4.69922C10.0898 5.21699 9.67011 5.63672 9.15234 5.63672C8.63458 5.63672 8.21484 5.21699 8.21484 4.69922C8.21484 4.18146 8.63458 3.76172 9.15234 3.76172Z" fill="black"/></svg>',
|
|
20
24
|
};
|
|
@@ -27,6 +27,18 @@ const styles = {
|
|
|
27
27
|
margin: '10px 5px',
|
|
28
28
|
borderRight: 'solid thin #eaeaea',
|
|
29
29
|
},
|
|
30
|
+
select: {
|
|
31
|
+
margin: 'auto 0',
|
|
32
|
+
height: 28,
|
|
33
|
+
border: 'solid thin silver',
|
|
34
|
+
borderRadius: 4,
|
|
35
|
+
padding: '0 4px',
|
|
36
|
+
cursor: 'pointer',
|
|
37
|
+
background: 'transparent',
|
|
38
|
+
fontSize: 12,
|
|
39
|
+
outline: 'none',
|
|
40
|
+
maxWidth: 120,
|
|
41
|
+
},
|
|
30
42
|
};
|
|
31
43
|
|
|
32
44
|
const Toolbar = ({ children }) => <div style={styles.toolbar}>{children}</div>;
|
|
@@ -44,5 +56,22 @@ Toolbar.Button = forwardRef(({ active, ...props }, ref) => (
|
|
|
44
56
|
));
|
|
45
57
|
|
|
46
58
|
Toolbar.Separator = () => <div style={styles.separator} />;
|
|
59
|
+
Toolbar.Dropdown = forwardRef(
|
|
60
|
+
({ options = [], currentValue, onChange, ...props }, ref) => (
|
|
61
|
+
<select
|
|
62
|
+
ref={ref}
|
|
63
|
+
onChange={onChange}
|
|
64
|
+
style={styles.select}
|
|
65
|
+
value={currentValue}
|
|
66
|
+
{...props}
|
|
67
|
+
>
|
|
68
|
+
{options.map((option) => (
|
|
69
|
+
<option key={option.value} value={option.value}>
|
|
70
|
+
{option.label}
|
|
71
|
+
</option>
|
|
72
|
+
))}
|
|
73
|
+
</select>
|
|
74
|
+
),
|
|
75
|
+
);
|
|
47
76
|
|
|
48
77
|
export default Toolbar;
|
package/src/constants.js
CHANGED
|
@@ -7,6 +7,8 @@ const EMOJI = 'emoji';
|
|
|
7
7
|
const LINK = 'link';
|
|
8
8
|
const HEADING_ONE = 'heading-one';
|
|
9
9
|
const HEADING_TWO = 'heading-two';
|
|
10
|
+
const HEADING_THREE = 'heading-three';
|
|
11
|
+
const HEADING_FOUR = 'heading-four';
|
|
10
12
|
const PARAGRAPH = 'paragraph';
|
|
11
13
|
|
|
12
14
|
// Marks
|
|
@@ -49,6 +51,8 @@ export {
|
|
|
49
51
|
LINK,
|
|
50
52
|
HEADING_ONE,
|
|
51
53
|
HEADING_TWO,
|
|
54
|
+
HEADING_THREE,
|
|
55
|
+
HEADING_FOUR,
|
|
52
56
|
PARAGRAPH,
|
|
53
57
|
BOLD,
|
|
54
58
|
ITALIC,
|
package/src/helpers/apply.js
CHANGED
package/src/helpers/compose.js
CHANGED
package/src/helpers/flow.js
CHANGED
package/src/helpers/why.js
CHANGED
package/src/lib.js
CHANGED
|
@@ -199,5 +199,12 @@ export { default as plainSerializer } from './serializers/plain';
|
|
|
199
199
|
export { default as makeReactTransformer } from './transformers/react';
|
|
200
200
|
export { defaultReactTransformer } from './transformers/react';
|
|
201
201
|
export { isEmptyContent, getUrl, isUrl, getUrlFromNode } from './helpers';
|
|
202
|
-
export {
|
|
202
|
+
export {
|
|
203
|
+
EMPTY_VALUE,
|
|
204
|
+
PARAGRAPH,
|
|
205
|
+
HEADING_ONE,
|
|
206
|
+
HEADING_TWO,
|
|
207
|
+
HEADING_THREE,
|
|
208
|
+
HEADING_FOUR,
|
|
209
|
+
} from './constants';
|
|
203
210
|
export default HeroEditor;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createEditor } from 'slate';
|
|
2
|
+
import { waitFor } from '@testing-library/react';
|
|
3
|
+
import dropdown from '../dropdown';
|
|
4
|
+
import { createPlugin, postMessage, withId } from '../../helpers';
|
|
5
|
+
import { PARAGRAPH, HEADING_ONE, HEADING_TWO } from '../../constants';
|
|
6
|
+
|
|
7
|
+
const OPTIONS = [
|
|
8
|
+
{ value: PARAGRAPH, label: 'Normal text' },
|
|
9
|
+
{ value: HEADING_ONE, label: 'Heading 1' },
|
|
10
|
+
{ value: HEADING_TWO, label: 'Heading 2' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
describe('dropdown plugin', () => {
|
|
14
|
+
it('is a plugin object', () => {
|
|
15
|
+
const plugin = dropdown({ name: 'test-dropdown', options: OPTIONS });
|
|
16
|
+
for (const prop in createPlugin()) {
|
|
17
|
+
expect(plugin[prop]).toBeDefined();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('handles dropdown message and sets block type', async () => {
|
|
22
|
+
const editor = withId('sample')(createEditor());
|
|
23
|
+
dropdown({ name: 'test-dropdown', options: OPTIONS }).handleMessage(editor);
|
|
24
|
+
editor.insertNode({
|
|
25
|
+
type: PARAGRAPH,
|
|
26
|
+
children: [{ text: 'Some text' }],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
postMessage('test-dropdown', { type: HEADING_ONE }, editor);
|
|
30
|
+
|
|
31
|
+
await waitFor(() => {
|
|
32
|
+
expect(editor.children[0].type).toBe(HEADING_ONE);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('ignores message when data.type is missing', async () => {
|
|
37
|
+
const editor = withId('sample')(createEditor());
|
|
38
|
+
dropdown({ name: 'test-dropdown', options: OPTIONS }).handleMessage(editor);
|
|
39
|
+
editor.insertNode({
|
|
40
|
+
type: PARAGRAPH,
|
|
41
|
+
children: [{ text: 'Some text' }],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
postMessage('test-dropdown', {}, editor);
|
|
45
|
+
|
|
46
|
+
await waitFor(() => {
|
|
47
|
+
expect(editor.children[0].type).toBe(PARAGRAPH);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('provides a ToolbarButton', () => {
|
|
52
|
+
const plugin = dropdown({ name: 'test-dropdown', options: OPTIONS });
|
|
53
|
+
expect(plugin.ToolbarButton).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('provides a ToolbarButton even with empty options', () => {
|
|
57
|
+
const plugin = dropdown({ name: 'test-dropdown', options: [] });
|
|
58
|
+
expect(plugin.ToolbarButton).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import headingFour from '../headingFour';
|
|
3
|
+
import { createPlugin, renderDefaultElement } from '../../helpers';
|
|
4
|
+
|
|
5
|
+
describe('headingFour plugin', () => {
|
|
6
|
+
it('is a plugin object', () => {
|
|
7
|
+
for (const prop in createPlugin()) {
|
|
8
|
+
expect(headingFour()[prop]).toBeDefined();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders h4 element', () => {
|
|
13
|
+
const { baseElement } = render(
|
|
14
|
+
headingFour().renderElement(renderDefaultElement)({
|
|
15
|
+
element: { type: 'heading-four' },
|
|
16
|
+
children: 'Heading four',
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
expect(baseElement).toMatchSnapshot();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('still provides ToolbarButton when showToolbarButton is false', () => {
|
|
23
|
+
expect(
|
|
24
|
+
headingFour({ showToolbarButton: false }).ToolbarButton,
|
|
25
|
+
).toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -18,4 +18,10 @@ describe('headingOne plugin', () => {
|
|
|
18
18
|
);
|
|
19
19
|
expect(baseElement).toMatchSnapshot();
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
it('still provides ToolbarButton when showToolbarButton is false', () => {
|
|
23
|
+
expect(
|
|
24
|
+
headingOne({ showToolbarButton: false }).ToolbarButton,
|
|
25
|
+
).toBeDefined();
|
|
26
|
+
});
|
|
21
27
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import headingThree from '../headingThree';
|
|
3
|
+
import { createPlugin, renderDefaultElement } from '../../helpers';
|
|
4
|
+
|
|
5
|
+
describe('headingThree plugin', () => {
|
|
6
|
+
it('is a plugin object', () => {
|
|
7
|
+
for (const prop in createPlugin()) {
|
|
8
|
+
expect(headingThree()[prop]).toBeDefined();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders h3 element', () => {
|
|
13
|
+
const { baseElement } = render(
|
|
14
|
+
headingThree().renderElement(renderDefaultElement)({
|
|
15
|
+
element: { type: 'heading-three' },
|
|
16
|
+
children: 'Heading three',
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
expect(baseElement).toMatchSnapshot();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('still provides ToolbarButton when showToolbarButton is false', () => {
|
|
23
|
+
expect(
|
|
24
|
+
headingThree({ showToolbarButton: false }).ToolbarButton,
|
|
25
|
+
).toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -18,4 +18,10 @@ describe('headingTwo plugin', () => {
|
|
|
18
18
|
);
|
|
19
19
|
expect(baseElement).toMatchSnapshot();
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
it('still provides ToolbarButton when showToolbarButton is false', () => {
|
|
23
|
+
expect(
|
|
24
|
+
headingTwo({ showToolbarButton: false }).ToolbarButton,
|
|
25
|
+
).toBeDefined();
|
|
26
|
+
});
|
|
21
27
|
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Transforms } from 'slate';
|
|
3
|
+
import { useSlate } from 'slate-react';
|
|
4
|
+
import {
|
|
5
|
+
createPlugin,
|
|
6
|
+
postMessage,
|
|
7
|
+
addMessageListener,
|
|
8
|
+
isBlockActive,
|
|
9
|
+
isList,
|
|
10
|
+
} from '../helpers';
|
|
11
|
+
import Toolbar from '../components/Toolbar';
|
|
12
|
+
|
|
13
|
+
const makeToolbarButton = (name, options) => () => {
|
|
14
|
+
const editor = useSlate();
|
|
15
|
+
if (options.length === 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const currentValue =
|
|
19
|
+
options.find(({ value }) => isBlockActive(editor, value))?.value ??
|
|
20
|
+
options[0]?.value;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Toolbar.Dropdown
|
|
24
|
+
options={options}
|
|
25
|
+
currentValue={currentValue}
|
|
26
|
+
onChange={(event) => {
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
postMessage(name, { type: event.target.value }, editor);
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default ({ name, options = [] }) =>
|
|
35
|
+
createPlugin({
|
|
36
|
+
name,
|
|
37
|
+
ToolbarButton: makeToolbarButton(name, options),
|
|
38
|
+
handleMessage: addMessageListener(name, ({ editor, data }) => {
|
|
39
|
+
if (!data?.type) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
Transforms.unwrapNodes(editor, {
|
|
43
|
+
match: isList,
|
|
44
|
+
split: true,
|
|
45
|
+
});
|
|
46
|
+
Transforms.setNodes(editor, { type: data.type });
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Transforms } from 'slate';
|
|
3
|
+
import { useSlate } from 'slate-react';
|
|
4
|
+
import {
|
|
5
|
+
createPlugin,
|
|
6
|
+
isBlockActive,
|
|
7
|
+
makeRenderElement,
|
|
8
|
+
addMessageListener,
|
|
9
|
+
postMessage,
|
|
10
|
+
isList,
|
|
11
|
+
} from '../helpers';
|
|
12
|
+
import Toolbar from '../components/Toolbar';
|
|
13
|
+
import Icon from '../components/Icon';
|
|
14
|
+
import { HEADING_FOUR } from '../constants';
|
|
15
|
+
|
|
16
|
+
const renderElement = makeRenderElement(
|
|
17
|
+
HEADING_FOUR,
|
|
18
|
+
({ attributes, children }) => <h4 {...attributes}>{children}</h4>,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const handleMessage = addMessageListener(HEADING_FOUR, ({ editor }) => {
|
|
22
|
+
const isActive = isBlockActive(editor, HEADING_FOUR);
|
|
23
|
+
|
|
24
|
+
// Unwrap all the items of any list
|
|
25
|
+
Transforms.unwrapNodes(editor, {
|
|
26
|
+
match: isList,
|
|
27
|
+
split: true,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Transforms.setNodes(editor, {
|
|
31
|
+
type: isActive ? 'paragraph' : HEADING_FOUR,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const ToolbarButton = ({ showToolbarButton }) => {
|
|
36
|
+
const editor = useSlate();
|
|
37
|
+
|
|
38
|
+
if (!showToolbarButton) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Toolbar.Button
|
|
42
|
+
active={isBlockActive(editor, HEADING_FOUR)}
|
|
43
|
+
onMouseDown={(event) => {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
postMessage(HEADING_FOUR, {}, editor);
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<Icon>looks_four</Icon>
|
|
49
|
+
</Toolbar.Button>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default ({ showToolbarButton = true } = {}) =>
|
|
54
|
+
createPlugin({
|
|
55
|
+
name: HEADING_FOUR,
|
|
56
|
+
renderElement,
|
|
57
|
+
handleMessage,
|
|
58
|
+
ToolbarButton: () => (
|
|
59
|
+
<ToolbarButton showToolbarButton={showToolbarButton} />
|
|
60
|
+
),
|
|
61
|
+
isActive: (editor) => isBlockActive(editor, HEADING_FOUR),
|
|
62
|
+
});
|
|
@@ -32,9 +32,11 @@ const handleMessage = addMessageListener(HEADING_ONE, ({ editor }) => {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
const ToolbarButton = () => {
|
|
35
|
+
const ToolbarButton = ({ showToolbarButton }) => {
|
|
36
36
|
const editor = useSlate();
|
|
37
37
|
|
|
38
|
+
if (!showToolbarButton) return null;
|
|
39
|
+
|
|
38
40
|
return (
|
|
39
41
|
<Toolbar.Button
|
|
40
42
|
active={isBlockActive(editor, HEADING_ONE)}
|
|
@@ -48,11 +50,13 @@ const ToolbarButton = () => {
|
|
|
48
50
|
);
|
|
49
51
|
};
|
|
50
52
|
|
|
51
|
-
export default () =>
|
|
53
|
+
export default ({ showToolbarButton = true } = {}) =>
|
|
52
54
|
createPlugin({
|
|
53
55
|
name: HEADING_ONE,
|
|
54
56
|
renderElement,
|
|
55
57
|
handleMessage,
|
|
56
|
-
ToolbarButton
|
|
58
|
+
ToolbarButton: () => (
|
|
59
|
+
<ToolbarButton showToolbarButton={showToolbarButton} />
|
|
60
|
+
),
|
|
57
61
|
isActive: (editor) => isBlockActive(editor, HEADING_ONE),
|
|
58
62
|
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Transforms } from 'slate';
|
|
3
|
+
import { useSlate } from 'slate-react';
|
|
4
|
+
import {
|
|
5
|
+
createPlugin,
|
|
6
|
+
isBlockActive,
|
|
7
|
+
makeRenderElement,
|
|
8
|
+
addMessageListener,
|
|
9
|
+
postMessage,
|
|
10
|
+
isList,
|
|
11
|
+
} from '../helpers';
|
|
12
|
+
import Toolbar from '../components/Toolbar';
|
|
13
|
+
import Icon from '../components/Icon';
|
|
14
|
+
import { HEADING_THREE } from '../constants';
|
|
15
|
+
|
|
16
|
+
const renderElement = makeRenderElement(
|
|
17
|
+
HEADING_THREE,
|
|
18
|
+
({ attributes, children }) => <h3 {...attributes}>{children}</h3>,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const handleMessage = addMessageListener(HEADING_THREE, ({ editor }) => {
|
|
22
|
+
const isActive = isBlockActive(editor, HEADING_THREE);
|
|
23
|
+
|
|
24
|
+
// Unwrap all the items of any list
|
|
25
|
+
Transforms.unwrapNodes(editor, {
|
|
26
|
+
match: isList,
|
|
27
|
+
split: true,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Transforms.setNodes(editor, {
|
|
31
|
+
type: isActive ? 'paragraph' : HEADING_THREE,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const ToolbarButton = ({ showToolbarButton }) => {
|
|
36
|
+
const editor = useSlate();
|
|
37
|
+
|
|
38
|
+
if (!showToolbarButton) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Toolbar.Button
|
|
42
|
+
active={isBlockActive(editor, HEADING_THREE)}
|
|
43
|
+
onMouseDown={(event) => {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
postMessage(HEADING_THREE, {}, editor);
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<Icon>looks_three</Icon>
|
|
49
|
+
</Toolbar.Button>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default ({ showToolbarButton = true } = {}) =>
|
|
54
|
+
createPlugin({
|
|
55
|
+
name: HEADING_THREE,
|
|
56
|
+
renderElement,
|
|
57
|
+
handleMessage,
|
|
58
|
+
ToolbarButton: () => (
|
|
59
|
+
<ToolbarButton showToolbarButton={showToolbarButton} />
|
|
60
|
+
),
|
|
61
|
+
isActive: (editor) => isBlockActive(editor, HEADING_THREE),
|
|
62
|
+
});
|
|
@@ -32,9 +32,11 @@ const handleMessage = addMessageListener(HEADING_TWO, ({ editor }) => {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
const ToolbarButton = () => {
|
|
35
|
+
const ToolbarButton = ({ showToolbarButton }) => {
|
|
36
36
|
const editor = useSlate();
|
|
37
37
|
|
|
38
|
+
if (!showToolbarButton) return null;
|
|
39
|
+
|
|
38
40
|
return (
|
|
39
41
|
<Toolbar.Button
|
|
40
42
|
active={isBlockActive(editor, HEADING_TWO)}
|
|
@@ -48,11 +50,13 @@ const ToolbarButton = () => {
|
|
|
48
50
|
);
|
|
49
51
|
};
|
|
50
52
|
|
|
51
|
-
export default () =>
|
|
53
|
+
export default ({ showToolbarButton = true } = {}) =>
|
|
52
54
|
createPlugin({
|
|
53
55
|
name: HEADING_TWO,
|
|
54
56
|
renderElement,
|
|
55
57
|
handleMessage,
|
|
56
|
-
ToolbarButton
|
|
58
|
+
ToolbarButton: () => (
|
|
59
|
+
<ToolbarButton showToolbarButton={showToolbarButton} />
|
|
60
|
+
),
|
|
57
61
|
isActive: (editor) => isBlockActive(editor, HEADING_TWO),
|
|
58
62
|
});
|
package/src/plugins/index.js
CHANGED
|
@@ -12,5 +12,8 @@ export { default as link } from './link';
|
|
|
12
12
|
export { default as cursorTracker } from './cursorTracker';
|
|
13
13
|
export { default as headingOne } from './headingOne';
|
|
14
14
|
export { default as headingTwo } from './headingTwo';
|
|
15
|
+
export { default as headingThree } from './headingThree';
|
|
16
|
+
export { default as headingFour } from './headingFour';
|
|
17
|
+
export { default as dropdown } from './dropdown';
|
|
15
18
|
export { default as editorResetter } from './editorResetter';
|
|
16
19
|
export { default as editorBuiltInMethod } from './editorBuiltInMethod';
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Text } from 'slate';
|
|
3
|
-
import isUrl from 'is-url';
|
|
4
|
-
import getUrl from '../helpers/getUrl';
|
|
5
3
|
import y from '../helpers/why';
|
|
6
4
|
import { getUrlFromNode } from '../helpers';
|
|
7
5
|
|
|
@@ -49,6 +47,12 @@ const defaultRules = {
|
|
|
49
47
|
case 'heading-two':
|
|
50
48
|
return <h2 key={key}>{children}</h2>;
|
|
51
49
|
|
|
50
|
+
case 'heading-three':
|
|
51
|
+
return <h3 key={key}>{children}</h3>;
|
|
52
|
+
|
|
53
|
+
case 'heading-four':
|
|
54
|
+
return <h4 key={key}>{children}</h4>;
|
|
55
|
+
|
|
52
56
|
case 'link':
|
|
53
57
|
// eslint-disable-next-line no-case-declarations
|
|
54
58
|
const urlFromNode = getUrlFromNode(node);
|