@eeacms/volto-eea-website-theme 1.7.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -4,7 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- ### [1.7.0](https://github.com/eea/volto-eea-website-theme/compare/1.6.4...1.7.0) - 7 February 2023
7
+ ### [1.8.0](https://github.com/eea/volto-eea-website-theme/compare/1.7.0...1.8.0) - 8 February 2023
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat(align): Move text align to slate buttons - refs 160747 [Alin Voinea - [`24d8fe5`](https://github.com/eea/volto-eea-website-theme/commit/24d8fe5a74afc2b61dc622b368d3fe5b8b422390)]
12
+
13
+ #### :nail_care: Enhancements
14
+
15
+ - change(object-browser): Popup is hoverable in object browser nav #99 from eea/object_browser_nav_popup_hoverable [ichim-david - [`205c2c4`](https://github.com/eea/volto-eea-website-theme/commit/205c2c48803ce5814f71aea932038bf72272459e)]
16
+
17
+ #### :hammer_and_wrench: Others
18
+
19
+ - Release 1.8.0 [Alin Voinea - [`f15437f`](https://github.com/eea/volto-eea-website-theme/commit/f15437f9c9fd978431d3af48410d3ab9746be9fb)]
20
+ - Popup is hoverable in object browser nav [andreiggr - [`a944bff`](https://github.com/eea/volto-eea-website-theme/commit/a944bff8026b40c481bec474f2b509dc5c8b044a)]
21
+ ### [1.7.0](https://github.com/eea/volto-eea-website-theme/compare/1.6.4...1.7.0) - 8 February 2023
8
22
 
9
23
  #### :rocket: New Features
10
24
 
@@ -25,7 +39,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
25
39
 
26
40
  #### :hammer_and_wrench: Others
27
41
 
28
- - Release 1.7.0 [Alin Voinea - [`065c0d0`](https://github.com/eea/volto-eea-website-theme/commit/065c0d05cb43458463e3ca293bd51b32d2e89f34)]
29
42
  - Use scale for img in obj browser and preview in popup [andreiggr - [`e78e21d`](https://github.com/eea/volto-eea-website-theme/commit/e78e21d0b35d69242833914ff41455f24d31927b)]
30
43
  ### [1.6.4](https://github.com/eea/volto-eea-website-theme/compare/1.6.3...1.6.4) - 31 January 2023
31
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-website-theme",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "@eeacms/volto-eea-website-theme: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -12,32 +12,12 @@ export const StyleSchema = () => {
12
12
  title: 'Preset styles',
13
13
  fields: ['style_name'],
14
14
  },
15
- {
16
- id: 'text',
17
- title: 'Text',
18
- fields: ['textAlign', 'fontWeight'],
19
- },
20
15
  ],
21
16
  properties: {
22
17
  style_name: {
23
18
  title: 'Style',
24
19
  widget: 'style_select',
25
20
  },
26
- textAlign: {
27
- title: 'Text align',
28
- widget: 'style_text_align',
29
- },
30
- fontWeight: {
31
- title: 'Font weight',
32
- description: 'The weight (or boldness) of the font',
33
- choices: [
34
- ['300', 'Light'],
35
- ['400', 'Regular'],
36
- ['500', 'Medium'],
37
- ['600', 'SemiBold'],
38
- ['700', 'Bold'],
39
- ],
40
- },
41
21
  },
42
22
  required: [],
43
23
  };
@@ -0,0 +1,2 @@
1
+ This is customized because of stupid logic implemented in the attributes
2
+ calculation. This should be moved to volto proper. The difference is in Element
@@ -0,0 +1,165 @@
1
+ import React from 'react';
2
+ import { renderToStaticMarkup } from 'react-dom/server';
3
+ import { Node, Text } from 'slate';
4
+ import cx from 'classnames';
5
+ import { isEmpty, isEqual, omit } from 'lodash';
6
+ import config from '@plone/volto/registry';
7
+
8
+ const OMITTED = ['editor', 'path'];
9
+
10
+ // TODO: read, see if relevant
11
+ // https://reactjs.org/docs/higher-order-components.html#dont-use-hocs-inside-the-render-method
12
+ export const Element = ({ element, attributes = {}, extras, ...rest }) => {
13
+ const { slate } = config.settings;
14
+ const { elements } = slate;
15
+ const El = elements[element.type] || elements['default'];
16
+
17
+ // CUSTOMIZATION Code fix
18
+ const attrs = Object.keys(attributes || {}).reduce(
19
+ (acc, k) => {
20
+ if (!isEmpty(attributes[k])) {
21
+ if (k === 'className') {
22
+ acc.className = cx(attributes.className, acc.className);
23
+ } else {
24
+ acc[k] = attributes[k];
25
+ }
26
+ }
27
+ return acc;
28
+ },
29
+ element.styleName ? { className: element.styleName } : {},
30
+ );
31
+ // END CUSTOMIZATION
32
+
33
+ attrs.ref = attributes?.ref; // never remove the ref
34
+
35
+ return (
36
+ <El
37
+ element={element}
38
+ {...omit(rest, OMITTED)}
39
+ attributes={attrs}
40
+ extras={extras}
41
+ />
42
+ );
43
+ };
44
+
45
+ export const Leaf = ({ children, ...rest }) => {
46
+ const { attributes, leaf, mode } = rest;
47
+ let { leafs } = config.settings.slate;
48
+
49
+ children = Object.keys(leafs).reduce((acc, name) => {
50
+ return Object.keys(leaf).includes(name)
51
+ ? leafs[name]({ children: acc })
52
+ : acc;
53
+ }, children);
54
+
55
+ const classNames = {
56
+ [`highlight-${leaf.highlightType}`]: mode !== 'view' && leaf.highlightType,
57
+ 'highlight-selection': mode !== 'view' && leaf.isSelection,
58
+ };
59
+
60
+ // stylemenu support
61
+ for (const prop in leaf) {
62
+ if (prop.startsWith('style-')) {
63
+ classNames[prop.substring(6)] = true;
64
+ }
65
+ }
66
+
67
+ const klass = cx(classNames);
68
+
69
+ return mode === 'view' ? (
70
+ typeof children === 'string' ? (
71
+ children.split('\n').map((t, i) => {
72
+ // Softbreak support. Should do a plugin?
73
+ return (
74
+ <React.Fragment key={`${i}`}>
75
+ {children.indexOf('\n') > -1 &&
76
+ children.split('\n').length - 1 > i ? (
77
+ <>
78
+ {klass ? <span className={klass}>{t}</span> : t}
79
+ <br />
80
+ </>
81
+ ) : klass ? (
82
+ <span className={klass}>{t}</span>
83
+ ) : (
84
+ t
85
+ )}
86
+ </React.Fragment>
87
+ );
88
+ })
89
+ ) : (
90
+ <span className={klass}>{children}</span>
91
+ )
92
+ ) : (
93
+ <span {...attributes} className={klass}>
94
+ {children}
95
+ </span>
96
+ );
97
+ };
98
+
99
+ const serializeData = (node) => {
100
+ return JSON.stringify({ type: node.type, data: node.data });
101
+ };
102
+
103
+ export const serializeNodes = (nodes, getAttributes, extras = {}) => {
104
+ const editor = { children: nodes || [] };
105
+
106
+ const _serializeNodes = (nodes) => {
107
+ return (nodes || []).map(([node, path], i) => {
108
+ return Text.isText(node) ? (
109
+ <Leaf path={path} leaf={node} text={node} mode="view" key={path}>
110
+ {node.text}
111
+ </Leaf>
112
+ ) : (
113
+ <Element
114
+ path={path}
115
+ element={node}
116
+ mode="view"
117
+ key={path}
118
+ data-slate-data={node.data ? serializeData(node) : null}
119
+ attributes={
120
+ isEqual(path, [0])
121
+ ? getAttributes
122
+ ? getAttributes(node, path)
123
+ : null
124
+ : null
125
+ }
126
+ extras={extras}
127
+ >
128
+ {_serializeNodes(Array.from(Node.children(editor, path)))}
129
+ </Element>
130
+ );
131
+ });
132
+ };
133
+
134
+ return _serializeNodes(Array.from(Node.children(editor, [])));
135
+ };
136
+
137
+ /**
138
+ * Get the concatenated text string of a node's content.
139
+ *
140
+ * Note that this WILL include spaces between block node leafs in contrary to
141
+ * the original slate method. This function joins text of nodes with
142
+ * separating spaces to produce a string for indexing purposes.
143
+ *
144
+ */
145
+ const ConcatenatedString = (node) => {
146
+ if (Text.isText(node)) {
147
+ return node.text.trim();
148
+ } else {
149
+ return node.children.map(ConcatenatedString).join(' ');
150
+ }
151
+ };
152
+
153
+ /**
154
+ * @function serializeNodesToText
155
+ *
156
+ * @param {Array[Node]} nodes
157
+ *
158
+ * @returns {string}
159
+ */
160
+ export const serializeNodesToText = (nodes) => {
161
+ return nodes.map(ConcatenatedString).join('\n');
162
+ };
163
+
164
+ export const serializeNodesToHtml = (nodes) =>
165
+ renderToStaticMarkup(serializeNodes(nodes));
@@ -71,6 +71,7 @@ const ObjectBrowserNav = ({
71
71
  >
72
72
  <span title={`${item['@id']} (${item['@type']})`}>
73
73
  <Popup
74
+ hoverable
74
75
  key={item['@id']}
75
76
  content={
76
77
  <>
package/src/index.js CHANGED
@@ -8,14 +8,9 @@ import SubsiteClass from './components/theme/SubsiteClass';
8
8
  import HomePageView from '@eeacms/volto-eea-website-theme/components/theme/Homepage/HomePageView';
9
9
  import HomePageInverseView from '@eeacms/volto-eea-website-theme/components/theme/Homepage/HomePageInverseView';
10
10
  import { Icon } from '@plone/volto/components';
11
- import { MarkElementButton } from '@plone/volto-slate/editor/ui';
12
- import installCallout from '@plone/volto-slate/editor/plugins/Callout';
13
- import paintSVG from '@plone/volto/icons/paint.svg';
14
11
  import contentBoxSVG from './icons/content-box.svg';
15
- import lightIcon from './icons/light.svg';
16
- import smallIcon from './icons/small.svg';
17
12
  import voltoCustomMiddleware from './middleware/voltoCustom';
18
- import { List } from 'semantic-ui-react';
13
+ import installSlate from './slate';
19
14
 
20
15
  const applyConfig = (config) => {
21
16
  // EEA specific settings
@@ -111,141 +106,7 @@ const applyConfig = (config) => {
111
106
  },
112
107
  ];
113
108
 
114
- if (config.settings.slate) {
115
- // Callout slate button
116
- config = installCallout(config);
117
-
118
- // Remove blockquote, italic, strikethrough slate button from toolbarButtons
119
- config.settings.slate.toolbarButtons = config.settings.slate.toolbarButtons.filter(
120
- (item) => !['blockquote', 'italic', 'strikethrough'].includes(item),
121
- );
122
-
123
- // Remove blockquote, italic, strikethrough slate button from expandedToolbarButtons
124
- config.settings.slate.expandedToolbarButtons = config.settings.slate.expandedToolbarButtons.filter(
125
- (item) => !['blockquote', 'italic', 'strikethrough'].includes(item),
126
- );
127
-
128
- // Remove 'underline' and 'italic' hotkeys
129
- config.settings.slate.hotkeys = Object.keys(config.settings.slate.hotkeys)
130
- .filter((item) => !['mod+u', 'mod+i'].includes(item))
131
- .reduce((out, key) => {
132
- out[key] = config.settings.slate.hotkeys[key];
133
- return out;
134
- }, {});
135
-
136
- // Small button
137
- if (!config.settings.slate.toolbarButtons.includes('small')) {
138
- config.settings.slate.elements.small = ({ children }) => (
139
- <small>{children}</small>
140
- );
141
-
142
- config.settings.slate.buttons.small = (props) => (
143
- <MarkElementButton
144
- title="Small"
145
- format="small"
146
- icon={smallIcon}
147
- {...props}
148
- />
149
- );
150
-
151
- config.settings.slate.inlineElements = [
152
- ...config.settings.slate.inlineElements,
153
- 'small',
154
- ];
155
-
156
- config.settings.slate.toolbarButtons = [
157
- ...config.settings.slate.toolbarButtons.slice(0, 1),
158
- 'small',
159
- ...config.settings.slate.toolbarButtons.slice(1),
160
- ];
161
-
162
- config.settings.slate.hotkeys['mod+s'] = {
163
- format: 'small',
164
- type: 'inline',
165
- };
166
- }
167
-
168
- // Light button
169
- if (!config.settings.slate.toolbarButtons.includes('light')) {
170
- config.settings.slate.elements.light = ({ children }) => (
171
- <span className="fw-light">{children}</span>
172
- );
173
-
174
- config.settings.slate.buttons.light = (props) => (
175
- <MarkElementButton
176
- title="Light"
177
- format="light"
178
- icon={lightIcon}
179
- {...props}
180
- />
181
- );
182
-
183
- config.settings.slate.inlineElements = [
184
- ...config.settings.slate.inlineElements,
185
- 'light',
186
- ];
187
-
188
- config.settings.slate.toolbarButtons = [
189
- ...config.settings.slate.toolbarButtons.slice(0, 1),
190
- 'light',
191
- ...config.settings.slate.toolbarButtons.slice(1),
192
- ];
193
-
194
- config.settings.slate.hotkeys['mod+l'] = {
195
- format: 'light',
196
- type: 'inline',
197
- };
198
- }
199
-
200
- // Clear formatting
201
- if (!config.settings.slate.toolbarButtons.includes('clearformatting')) {
202
- config.settings.slate.toolbarButtons = [
203
- ...config.settings.slate.toolbarButtons,
204
- 'clearformatting',
205
- ];
206
- }
207
-
208
- // Align Slate Lists to EEA Design System
209
- config.settings.slate.elements.ul = ({ attributes, children }) => (
210
- <List bulleted as="ul" {...attributes}>
211
- {children}
212
- </List>
213
- );
214
-
215
- config.settings.slate.elements.ol = ({ attributes, children }) => (
216
- <List ordered as="ol" {...attributes}>
217
- {children}
218
- </List>
219
- );
220
-
221
- config.settings.slate.elements.li = ({ attributes, children }) => (
222
- <List.Item as="li" {...attributes}>
223
- {children}
224
- </List.Item>
225
- );
226
-
227
- // Slate StyleMenu configuration
228
- config.settings.slate.styleMenu = {
229
- ...(config.settings.slate.styleMenu || {}),
230
- blockStyles: [
231
- {
232
- cssClass: 'primary',
233
- label: 'Primary',
234
- icon: () => <Icon name={paintSVG} size="18px" />,
235
- },
236
- {
237
- cssClass: 'secondary',
238
- label: 'Secondary',
239
- icon: () => <Icon name={paintSVG} size="18px" />,
240
- },
241
- {
242
- cssClass: 'tertiary',
243
- label: 'Tertiary',
244
- icon: () => <Icon name={paintSVG} size="18px" />,
245
- },
246
- ],
247
- };
248
- }
109
+ config = installSlate(config);
249
110
 
250
111
  // Custom block-style colors
251
112
  config.settings.available_colors = eea.colors;
package/src/slate.js ADDED
@@ -0,0 +1,323 @@
1
+ import React from 'react';
2
+ import { List } from 'semantic-ui-react';
3
+ import { MarkElementButton, ToolbarButton } from '@plone/volto-slate/editor/ui';
4
+ import installCallout from '@plone/volto-slate/editor/plugins/Callout';
5
+ import { Icon } from '@plone/volto/components';
6
+ import { Editor, Transforms } from 'slate';
7
+ import { useSlate } from 'slate-react';
8
+
9
+ import formatClearIcon from '@plone/volto/icons/format-clear.svg';
10
+ import paintSVG from '@plone/volto/icons/paint.svg';
11
+ import alignLeftIcon from '@plone/volto/icons/align-left.svg';
12
+ import alignRightIcon from '@plone/volto/icons/align-right.svg';
13
+ import alignCenterIcon from '@plone/volto/icons/align-center.svg';
14
+ import alignJustifyIcon from '@plone/volto/icons/align-justify.svg';
15
+ import lightIcon from './icons/light.svg';
16
+ import smallIcon from './icons/small.svg';
17
+
18
+ const toggleBlockClassFormat = (editor, format) => {
19
+ const levels = Array.from(Editor.levels(editor, editor.selection));
20
+ const [, [, path]] = levels;
21
+ Transforms.setNodes(
22
+ editor,
23
+ { styleName: format },
24
+ {
25
+ at: path,
26
+ },
27
+ );
28
+ return;
29
+ };
30
+
31
+ const isBlockClassActive = (editor, format) => {
32
+ if (!editor.selection) return false;
33
+ const levels = Array.from(Editor.levels(editor, editor.selection));
34
+ const [, [node]] = levels;
35
+ return node.styleName === format;
36
+ };
37
+
38
+ function BlockClassButton({ format, icon, ...props }) {
39
+ const editor = useSlate();
40
+
41
+ const isActive = isBlockClassActive(editor, format);
42
+
43
+ const handleMouseDown = React.useCallback(
44
+ (event) => {
45
+ event.preventDefault();
46
+ toggleBlockClassFormat(editor, format);
47
+ },
48
+ [editor, format], // , isActive
49
+ );
50
+
51
+ return (
52
+ <ToolbarButton
53
+ {...props}
54
+ active={isActive}
55
+ onMouseDown={handleMouseDown}
56
+ icon={icon}
57
+ />
58
+ );
59
+ }
60
+
61
+ const clearFormatting = (editor) => {
62
+ Transforms.setNodes(editor, {
63
+ type: 'p',
64
+ styleName: null,
65
+ });
66
+ Transforms.unwrapNodes(editor, {
67
+ match: (n) => n.type && n.type !== 'p',
68
+ mode: 'all',
69
+ split: false,
70
+ });
71
+ };
72
+
73
+ const ClearFormattingButton = ({ icon, ...props }) => {
74
+ const editor = useSlate();
75
+
76
+ const handleMouseDown = React.useCallback(
77
+ (event) => {
78
+ event.preventDefault();
79
+ clearFormatting(editor);
80
+ },
81
+ [editor],
82
+ );
83
+
84
+ return <ToolbarButton {...props} onMouseDown={handleMouseDown} icon={icon} />;
85
+ };
86
+
87
+ export default function installSlate(config) {
88
+ if (config.settings.slate) {
89
+ // Callout slate button
90
+ config = installCallout(config);
91
+
92
+ config.settings.slate.buttons.clearformatting = (props) => (
93
+ <ClearFormattingButton title="Clear formatting" icon={formatClearIcon} />
94
+ );
95
+
96
+ // Remove blockquote, italic, strikethrough slate button from toolbarButtons
97
+ config.settings.slate.toolbarButtons = config.settings.slate.toolbarButtons.filter(
98
+ (item) => !['blockquote', 'italic', 'strikethrough'].includes(item),
99
+ );
100
+
101
+ // Remove blockquote, italic, strikethrough slate button from expandedToolbarButtons
102
+ config.settings.slate.expandedToolbarButtons = config.settings.slate.expandedToolbarButtons.filter(
103
+ (item) => !['blockquote', 'italic', 'strikethrough'].includes(item),
104
+ );
105
+
106
+ // Remove 'underline' and 'italic' hotkeys
107
+ config.settings.slate.hotkeys = Object.keys(config.settings.slate.hotkeys)
108
+ .filter((item) => !['mod+u', 'mod+i'].includes(item))
109
+ .reduce((out, key) => {
110
+ out[key] = config.settings.slate.hotkeys[key];
111
+ return out;
112
+ }, {});
113
+
114
+ // Small button
115
+ if (!config.settings.slate.toolbarButtons.includes('small')) {
116
+ config.settings.slate.elements.small = ({ children }) => (
117
+ <small>{children}</small>
118
+ );
119
+
120
+ config.settings.slate.buttons.small = (props) => (
121
+ <MarkElementButton
122
+ title="Small"
123
+ format="small"
124
+ icon={smallIcon}
125
+ {...props}
126
+ />
127
+ );
128
+
129
+ config.settings.slate.inlineElements = [
130
+ ...config.settings.slate.inlineElements,
131
+ 'small',
132
+ ];
133
+
134
+ config.settings.slate.toolbarButtons = [
135
+ ...config.settings.slate.toolbarButtons.slice(0, 1),
136
+ 'small',
137
+ ...config.settings.slate.toolbarButtons.slice(1),
138
+ ];
139
+
140
+ config.settings.slate.hotkeys['mod+s'] = {
141
+ format: 'small',
142
+ type: 'inline',
143
+ };
144
+ }
145
+
146
+ // Light button
147
+ if (!config.settings.slate.toolbarButtons.includes('light')) {
148
+ config.settings.slate.elements.light = ({ children }) => (
149
+ <span className="fw-light">{children}</span>
150
+ );
151
+
152
+ config.settings.slate.buttons.light = (props) => (
153
+ <MarkElementButton
154
+ title="Light"
155
+ format="light"
156
+ icon={lightIcon}
157
+ {...props}
158
+ />
159
+ );
160
+
161
+ config.settings.slate.inlineElements = [
162
+ ...config.settings.slate.inlineElements,
163
+ 'light',
164
+ ];
165
+
166
+ config.settings.slate.toolbarButtons = [
167
+ ...config.settings.slate.toolbarButtons.slice(0, 1),
168
+ 'light',
169
+ ...config.settings.slate.toolbarButtons.slice(1),
170
+ ];
171
+
172
+ config.settings.slate.hotkeys['mod+l'] = {
173
+ format: 'light',
174
+ type: 'inline',
175
+ };
176
+ }
177
+
178
+ // Align Slate Lists to EEA Design System
179
+ config.settings.slate.elements.ul = ({ attributes, children }) => (
180
+ <List bulleted as="ul" {...attributes}>
181
+ {children}
182
+ </List>
183
+ );
184
+
185
+ config.settings.slate.elements.ol = ({ attributes, children }) => (
186
+ <List ordered as="ol" {...attributes}>
187
+ {children}
188
+ </List>
189
+ );
190
+
191
+ config.settings.slate.elements.li = ({ attributes, children }) => (
192
+ <List.Item as="li" {...attributes}>
193
+ {children}
194
+ </List.Item>
195
+ );
196
+
197
+ // Slate StyleMenu configuration
198
+ config.settings.slate.styleMenu = {
199
+ ...(config.settings.slate.styleMenu || {}),
200
+ blockStyles: [
201
+ {
202
+ cssClass: 'primary',
203
+ label: 'Primary',
204
+ icon: () => <Icon name={paintSVG} size="18px" />,
205
+ },
206
+ {
207
+ cssClass: 'secondary',
208
+ label: 'Secondary',
209
+ icon: () => <Icon name={paintSVG} size="18px" />,
210
+ },
211
+ {
212
+ cssClass: 'tertiary',
213
+ label: 'Tertiary',
214
+ icon: () => <Icon name={paintSVG} size="18px" />,
215
+ },
216
+ ],
217
+ };
218
+
219
+ // Text Align buttons
220
+
221
+ // Align left
222
+ if (!config.settings.slate.toolbarButtons.includes('text-left')) {
223
+ config.settings.slate.buttons['text-left'] = (props) => (
224
+ <BlockClassButton
225
+ format="text-left"
226
+ icon={alignLeftIcon}
227
+ title="Align left"
228
+ {...props}
229
+ />
230
+ );
231
+
232
+ config.settings.slate.toolbarButtons = [
233
+ ...config.settings.slate.toolbarButtons,
234
+ 'separator',
235
+ 'text-left',
236
+ ];
237
+
238
+ config.settings.slate.expandedToolbarButtons = [
239
+ ...config.settings.slate.expandedToolbarButtons,
240
+ 'separator',
241
+ 'text-left',
242
+ ];
243
+ }
244
+
245
+ // Align center
246
+ if (!config.settings.slate.toolbarButtons.includes('text-center')) {
247
+ config.settings.slate.buttons['text-center'] = (props) => (
248
+ <BlockClassButton
249
+ format="text-center"
250
+ icon={alignCenterIcon}
251
+ title="Align center"
252
+ {...props}
253
+ />
254
+ );
255
+
256
+ config.settings.slate.toolbarButtons = [
257
+ ...config.settings.slate.toolbarButtons,
258
+ 'text-center',
259
+ ];
260
+
261
+ config.settings.slate.expandedToolbarButtons = [
262
+ ...config.settings.slate.expandedToolbarButtons,
263
+ 'text-center',
264
+ ];
265
+ }
266
+
267
+ // Align right
268
+ if (!config.settings.slate.toolbarButtons.includes('text-right')) {
269
+ config.settings.slate.buttons['text-right'] = (props) => (
270
+ <BlockClassButton
271
+ format="text-right"
272
+ icon={alignRightIcon}
273
+ title="Align right"
274
+ {...props}
275
+ />
276
+ );
277
+
278
+ config.settings.slate.toolbarButtons = [
279
+ ...config.settings.slate.toolbarButtons,
280
+ 'text-right',
281
+ ];
282
+
283
+ config.settings.slate.expandedToolbarButtons = [
284
+ ...config.settings.slate.expandedToolbarButtons,
285
+ 'text-right',
286
+ ];
287
+ }
288
+
289
+ // Align justify
290
+ if (!config.settings.slate.toolbarButtons.includes('text-justify')) {
291
+ config.settings.slate.buttons['text-justify'] = (props) => (
292
+ <BlockClassButton
293
+ format="text-justify"
294
+ icon={alignJustifyIcon}
295
+ title="Align justify"
296
+ {...props}
297
+ />
298
+ );
299
+
300
+ config.settings.slate.toolbarButtons = [
301
+ ...config.settings.slate.toolbarButtons,
302
+ 'text-justify',
303
+ 'separator',
304
+ ];
305
+
306
+ config.settings.slate.expandedToolbarButtons = [
307
+ ...config.settings.slate.expandedToolbarButtons,
308
+ 'text-justify',
309
+ 'separator',
310
+ ];
311
+ }
312
+
313
+ // Clear formatting
314
+ if (!config.settings.slate.toolbarButtons.includes('clearformatting')) {
315
+ config.settings.slate.toolbarButtons = [
316
+ ...config.settings.slate.toolbarButtons,
317
+ 'clearformatting',
318
+ ];
319
+ }
320
+ }
321
+
322
+ return config;
323
+ }