@pie-lib/editable-html 11.1.1 → 11.2.0-beta.1

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 (158) hide show
  1. package/CHANGELOG.md +43 -167
  2. package/NEXT.CHANGELOG.json +1 -0
  3. package/lib/block-tags.js +25 -0
  4. package/lib/block-tags.js.map +1 -0
  5. package/lib/constants.js +16 -0
  6. package/lib/constants.js.map +1 -0
  7. package/lib/editor.js +348 -87
  8. package/lib/editor.js.map +1 -1
  9. package/lib/index.js +25 -9
  10. package/lib/index.js.map +1 -1
  11. package/lib/plugins/characters/index.js +8 -3
  12. package/lib/plugins/characters/index.js.map +1 -1
  13. package/lib/plugins/characters/utils.js +12 -12
  14. package/lib/plugins/characters/utils.js.map +1 -1
  15. package/lib/plugins/css/icons/index.js +37 -0
  16. package/lib/plugins/css/icons/index.js.map +1 -0
  17. package/lib/plugins/css/index.js +397 -0
  18. package/lib/plugins/css/index.js.map +1 -0
  19. package/lib/plugins/customPlugin/index.js +114 -0
  20. package/lib/plugins/customPlugin/index.js.map +1 -0
  21. package/lib/plugins/html/index.js +11 -7
  22. package/lib/plugins/html/index.js.map +1 -1
  23. package/lib/plugins/image/index.js +2 -1
  24. package/lib/plugins/image/index.js.map +1 -1
  25. package/lib/plugins/image/insert-image-handler.js +13 -4
  26. package/lib/plugins/image/insert-image-handler.js.map +1 -1
  27. package/lib/plugins/index.js +270 -11
  28. package/lib/plugins/index.js.map +1 -1
  29. package/lib/plugins/list/index.js +130 -0
  30. package/lib/plugins/list/index.js.map +1 -1
  31. package/lib/plugins/math/index.js +91 -56
  32. package/lib/plugins/math/index.js.map +1 -1
  33. package/lib/plugins/media/index.js +5 -2
  34. package/lib/plugins/media/index.js.map +1 -1
  35. package/lib/plugins/media/media-dialog.js +98 -57
  36. package/lib/plugins/media/media-dialog.js.map +1 -1
  37. package/lib/plugins/rendering/index.js +46 -0
  38. package/lib/plugins/rendering/index.js.map +1 -0
  39. package/lib/plugins/respArea/drag-in-the-blank/choice.js +5 -2
  40. package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
  41. package/lib/plugins/respArea/explicit-constructed-response/index.js +11 -9
  42. package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
  43. package/lib/plugins/respArea/index.js +69 -21
  44. package/lib/plugins/respArea/index.js.map +1 -1
  45. package/lib/plugins/respArea/inline-dropdown/index.js +10 -5
  46. package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
  47. package/lib/plugins/respArea/math-templated/index.js +130 -0
  48. package/lib/plugins/respArea/math-templated/index.js.map +1 -0
  49. package/lib/plugins/respArea/utils.js +16 -1
  50. package/lib/plugins/respArea/utils.js.map +1 -1
  51. package/lib/plugins/table/CustomTablePlugin.js +133 -0
  52. package/lib/plugins/table/CustomTablePlugin.js.map +1 -0
  53. package/lib/plugins/table/index.js +43 -59
  54. package/lib/plugins/table/index.js.map +1 -1
  55. package/lib/plugins/table/table-toolbar.js +33 -4
  56. package/lib/plugins/table/table-toolbar.js.map +1 -1
  57. package/lib/plugins/textAlign/icons/index.js +226 -0
  58. package/lib/plugins/textAlign/icons/index.js.map +1 -0
  59. package/lib/plugins/textAlign/index.js +34 -0
  60. package/lib/plugins/textAlign/index.js.map +1 -0
  61. package/lib/plugins/toolbar/default-toolbar.js +82 -27
  62. package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
  63. package/lib/plugins/toolbar/done-button.js +5 -2
  64. package/lib/plugins/toolbar/done-button.js.map +1 -1
  65. package/lib/plugins/toolbar/editor-and-toolbar.js +18 -19
  66. package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
  67. package/lib/plugins/toolbar/toolbar-buttons.js +44 -11
  68. package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
  69. package/lib/plugins/toolbar/toolbar.js +35 -11
  70. package/lib/plugins/toolbar/toolbar.js.map +1 -1
  71. package/lib/serialization.js +233 -44
  72. package/lib/serialization.js.map +1 -1
  73. package/package.json +11 -6
  74. package/src/__tests__/editor.test.jsx +363 -0
  75. package/src/__tests__/serialization.test.js +291 -0
  76. package/src/__tests__/utils.js +36 -0
  77. package/src/block-tags.js +17 -0
  78. package/src/constants.js +7 -0
  79. package/src/editor.jsx +303 -49
  80. package/src/index.jsx +19 -10
  81. package/src/plugins/characters/index.jsx +11 -3
  82. package/src/plugins/characters/utils.js +12 -12
  83. package/src/plugins/css/icons/index.jsx +17 -0
  84. package/src/plugins/css/index.jsx +346 -0
  85. package/src/plugins/customPlugin/index.jsx +85 -0
  86. package/src/plugins/html/index.jsx +9 -6
  87. package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +51 -0
  88. package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +27 -0
  89. package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +44 -0
  90. package/src/plugins/image/__tests__/component.test.jsx +41 -0
  91. package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +42 -0
  92. package/src/plugins/image/__tests__/image-toolbar.test.jsx +11 -0
  93. package/src/plugins/image/__tests__/index.test.js +95 -0
  94. package/src/plugins/image/__tests__/insert-image-handler.test.js +113 -0
  95. package/src/plugins/image/__tests__/mock-change.js +15 -0
  96. package/src/plugins/image/index.jsx +2 -1
  97. package/src/plugins/image/insert-image-handler.js +13 -6
  98. package/src/plugins/index.jsx +248 -5
  99. package/src/plugins/list/__tests__/index.test.js +54 -0
  100. package/src/plugins/list/index.jsx +130 -0
  101. package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +48 -0
  102. package/src/plugins/math/__tests__/index.test.jsx +245 -0
  103. package/src/plugins/math/index.jsx +87 -56
  104. package/src/plugins/media/__tests__/index.test.js +75 -0
  105. package/src/plugins/media/index.jsx +3 -2
  106. package/src/plugins/media/media-dialog.js +106 -57
  107. package/src/plugins/rendering/index.js +31 -0
  108. package/src/plugins/respArea/drag-in-the-blank/choice.jsx +4 -1
  109. package/src/plugins/respArea/explicit-constructed-response/index.jsx +10 -8
  110. package/src/plugins/respArea/index.jsx +53 -7
  111. package/src/plugins/respArea/inline-dropdown/index.jsx +13 -6
  112. package/src/plugins/respArea/math-templated/index.jsx +104 -0
  113. package/src/plugins/respArea/utils.jsx +11 -0
  114. package/src/plugins/table/CustomTablePlugin.js +113 -0
  115. package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +44 -0
  116. package/src/plugins/table/__tests__/index.test.jsx +401 -0
  117. package/src/plugins/table/__tests__/table-toolbar.test.jsx +42 -0
  118. package/src/plugins/table/index.jsx +46 -59
  119. package/src/plugins/table/table-toolbar.jsx +39 -2
  120. package/src/plugins/textAlign/icons/index.jsx +139 -0
  121. package/src/plugins/textAlign/index.jsx +23 -0
  122. package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +923 -0
  123. package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +20 -0
  124. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +36 -0
  125. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +46 -0
  126. package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +94 -0
  127. package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +37 -0
  128. package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +51 -0
  129. package/src/plugins/toolbar/__tests__/toolbar.test.jsx +106 -0
  130. package/src/plugins/toolbar/default-toolbar.jsx +82 -20
  131. package/src/plugins/toolbar/done-button.jsx +3 -1
  132. package/src/plugins/toolbar/editor-and-toolbar.jsx +18 -13
  133. package/src/plugins/toolbar/toolbar-buttons.jsx +52 -11
  134. package/src/plugins/toolbar/toolbar.jsx +31 -8
  135. package/src/serialization.jsx +213 -38
  136. package/README.md +0 -45
  137. package/deploy.sh +0 -16
  138. package/playground/image/data.js +0 -59
  139. package/playground/image/index.html +0 -22
  140. package/playground/image/index.jsx +0 -81
  141. package/playground/index.html +0 -25
  142. package/playground/mathquill/index.html +0 -22
  143. package/playground/mathquill/index.jsx +0 -155
  144. package/playground/package.json +0 -15
  145. package/playground/prod-test/index.html +0 -22
  146. package/playground/prod-test/index.jsx +0 -28
  147. package/playground/schema-override/data.js +0 -29
  148. package/playground/schema-override/image-plugin.jsx +0 -41
  149. package/playground/schema-override/index.html +0 -21
  150. package/playground/schema-override/index.jsx +0 -97
  151. package/playground/serialization/data.js +0 -29
  152. package/playground/serialization/image-plugin.jsx +0 -41
  153. package/playground/serialization/index.html +0 -22
  154. package/playground/serialization/index.jsx +0 -12
  155. package/playground/static.json +0 -3
  156. package/playground/table-examples.html +0 -70
  157. package/playground/webpack.config.js +0 -42
  158. package/static.json +0 -1
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
- import EditTable from 'slate-edit-table';
3
2
  import { Block } from 'slate';
4
3
  import debug from 'debug';
5
4
  import GridOn from '@material-ui/icons/GridOn';
@@ -9,6 +8,7 @@ import SlatePropTypes from 'slate-prop-types';
9
8
  import { withStyles } from '@material-ui/core/styles';
10
9
  import convert from 'react-attr-converter';
11
10
  import { object as toStyleObject } from 'to-style';
11
+ import CustomTablePlugin from './CustomTablePlugin';
12
12
 
13
13
  const log = debug('@pie-lib:editable-html:plugins:table');
14
14
 
@@ -93,9 +93,7 @@ export const moveFocusToBeginningOfTable = (change) => {
93
93
  };
94
94
 
95
95
  export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
96
- const core = EditTable({
97
- typeContent: 'div',
98
- });
96
+ const core = CustomTablePlugin(opts);
99
97
 
100
98
  // fix outdated schema
101
99
 
@@ -142,7 +140,9 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
142
140
  };
143
141
 
144
142
  core.toolbar = {
143
+ type: 'table',
145
144
  icon: <GridOn />,
145
+ ariaLabel: 'Insert Table',
146
146
  onClick: (value, onChange) => {
147
147
  log('insert table');
148
148
  const change = value.change();
@@ -162,7 +162,7 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
162
162
  /**
163
163
  * Note - the node may not be a table node - it may be a node inside a table.
164
164
  */
165
- customToolbar: (node, value, onToolbarDone) => {
165
+ customToolbar: (node, value, onToolbarDone, getFocusedValue) => {
166
166
  log('[customToolbar] node.data: ', node.data);
167
167
 
168
168
  const tableBlock = core.utils.getTableBlock(value.document, node?.key);
@@ -209,6 +209,7 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
209
209
 
210
210
  const Tb = () => (
211
211
  <TableToolbar
212
+ getFocusedValue={getFocusedValue}
212
213
  plugins={toolbarPlugins}
213
214
  onChange={(c) => onToolbarDone(c, false)}
214
215
  value={value}
@@ -222,6 +223,7 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
222
223
  onDone={onDone}
223
224
  />
224
225
  );
226
+
225
227
  return Tb;
226
228
  },
227
229
  };
@@ -243,74 +245,59 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
243
245
  };
244
246
 
245
247
  core.normalizeNode = (node) => {
246
- if (node.object !== 'document') {
247
- return;
248
- }
248
+ const addNodeBeforeArray = [];
249
249
 
250
- const tableAdded = node.findDescendant((d) => d.data && d.data.get('newTable'));
251
-
252
- if (!tableAdded) {
253
- return;
254
- }
250
+ if (node.object !== 'document') return;
255
251
 
256
- const nodeToSearch = node.getParent(tableAdded.key) || node;
257
- let shouldAddTextAfterNode = false;
258
- const indexToNotHaveTableOn = nodeToSearch.nodes.size - 1;
259
- const indexOfLastTable = nodeToSearch.nodes.findLastIndex((d) => d.type === 'table');
252
+ node.findDescendant((d) => {
253
+ if (d.type === 'table') {
254
+ const tablePath = node.getPath(d.key);
255
+ const prevNode = node.getPreviousNode(tablePath);
256
+ const nextNode = node.getNextNode(tablePath);
260
257
 
261
- // if the last table in the document is of type table, we need to do the change
262
- if (indexOfLastTable === indexToNotHaveTableOn) {
263
- shouldAddTextAfterNode = true;
264
- }
258
+ if (!prevNode || !nextNode) {
259
+ addNodeBeforeArray.push({
260
+ node: d,
261
+ prevNode,
262
+ nextNode,
263
+ });
264
+ }
265
+ }
266
+ });
265
267
 
266
- if (!shouldAddTextAfterNode) {
268
+ if (!addNodeBeforeArray.length) {
267
269
  return;
268
270
  }
269
271
 
270
272
  return (change) => {
271
- if (shouldAddTextAfterNode) {
272
- const tableJSON = tableAdded.toJSON();
273
-
274
- // we remove the table node because otherwise we can't add the empty block after it
275
- // we need a block that contains text in order to do it
276
- change.removeNodeByKey(tableAdded.key);
273
+ const newBlock = {
274
+ object: 'block',
275
+ type: 'div',
276
+ };
277
277
 
278
- const newBlock = Block.create({
279
- object: 'block',
280
- type: 'div',
281
- });
282
-
283
- // we add an empty block but that it's going to be normalized
284
- // because it will add the empty text to it like it should
285
- change.insertBlock(newBlock);
286
-
287
- change.withoutNormalization(() => {
288
- // we do these changes without normalization
289
-
290
- // we get the text previous to the new block added
291
- const prevText = change.value.document.getPreviousText(newBlock.key);
292
-
293
- if (prevText) {
294
- // we move focus to the previous text
295
- change.moveFocusTo(prevText.key, prevText.text?.length).moveAnchorTo(prevText.key, prevText.text?.length);
296
- }
297
-
298
- // we insert the table block between the first block with text and the last block with text
299
- change.insertBlock({
300
- ...tableJSON,
301
- data: {
302
- ...tableJSON.data,
303
- newTable: true,
304
- },
305
- });
278
+ addNodeBeforeArray.forEach((n) => {
279
+ const tablePath = change.value.document.getPath(n.node.key).toJSON();
280
+ // removing tableIndex
281
+ let indexToAdd = tablePath.splice(-1)[0];
282
+
283
+ if (!n.prevNode) {
284
+ // inserting block key before table
285
+ change.insertNodeByPath(tablePath, indexToAdd, newBlock);
286
+ // this will trigger another normalization, which will figure out if there's not
287
+ // a block after the table and add it, so we exit for now
288
+ return;
289
+ }
306
290
 
307
- moveFocusToBeginningOfTable(change);
308
- });
309
- }
291
+ if (!n.nextNode) {
292
+ // inserting block key after table
293
+ change.insertNodeByPath(tablePath, indexToAdd + 1, newBlock);
294
+ }
295
+ });
310
296
  };
311
297
  };
312
298
 
313
299
  core.renderNode = Node;
300
+ core.name = 'table';
314
301
 
315
302
  return core;
316
303
  };
@@ -41,6 +41,7 @@ export class TableToolbar extends React.Component {
41
41
 
42
42
  render() {
43
43
  const {
44
+ getFocusedValue,
44
45
  plugins,
45
46
  value,
46
47
  onChange,
@@ -55,6 +56,27 @@ export class TableToolbar extends React.Component {
55
56
  } = this.props;
56
57
  log('[render] hasBorder:', hasBorder);
57
58
 
59
+ // we're separating the response area plugin because we want to display it next to the done button
60
+ const filteredPlugins = (plugins || []).reduce(
61
+ (acc, plugin) => {
62
+ if (plugin.name === 'response_area') {
63
+ return {
64
+ ...acc,
65
+ respAreaPlugin: plugin,
66
+ };
67
+ }
68
+
69
+ return {
70
+ ...acc,
71
+ otherPlugins: [...acc.otherPlugins, plugin],
72
+ };
73
+ },
74
+ {
75
+ respAreaPlugin: null,
76
+ otherPlugins: [],
77
+ },
78
+ );
79
+
58
80
  return (
59
81
  <div className={classes.tableToolbar}>
60
82
  <div className={classes.toolbarButtons}>
@@ -73,13 +95,28 @@ export class TableToolbar extends React.Component {
73
95
  <Button onClick={onRemoveTable}>
74
96
  <RemoveTable />
75
97
  </Button>
76
- {plugins.map((p, index) => (
77
- <ToolbarButton key={`plugin-${index}`} {...p.toolbar} value={value} onChange={onChange} />
98
+ {(filteredPlugins.otherPlugins || []).map((p, index) => (
99
+ <ToolbarButton
100
+ key={`plugin-${index}`}
101
+ {...p.toolbar}
102
+ value={value}
103
+ onChange={onChange}
104
+ getFocusedValue={getFocusedValue}
105
+ />
78
106
  ))}
79
107
  <Button onClick={onToggleBorder} active={hasBorder}>
80
108
  <BorderAll />
81
109
  </Button>
82
110
  </div>
111
+ {filteredPlugins.respAreaPlugin && (
112
+ <ToolbarButton
113
+ key={'plugin-response-area'}
114
+ {...filteredPlugins.respAreaPlugin.toolbar}
115
+ value={value}
116
+ onChange={onChange}
117
+ getFocusedValue={getFocusedValue}
118
+ />
119
+ )}
83
120
  <DoneButton onClick={this.onDone} />
84
121
  </div>
85
122
  );
@@ -0,0 +1,139 @@
1
+ import React, { useState } from 'react';
2
+ import Collapse from '@material-ui/core/Collapse';
3
+ import List from '@material-ui/core/List';
4
+ import ListItem from '@material-ui/core/ListItem';
5
+
6
+ export const AlignLeft = () => (
7
+ <svg width="20" height="20" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
8
+ <path
9
+ d="M42.1875 4.75C42.1875 7.38672 39.9902 9.4375 37.5 9.4375H4.6875C2.05078 9.4375 0 7.38672 0 4.75C0 2.25977 2.05078 0.0625 4.6875 0.0625H37.5C39.9902 0.0625 42.1875 2.25977 42.1875 4.75ZM42.1875 42.25C42.1875 44.8867 39.9902 46.9375 37.5 46.9375H4.6875C2.05078 46.9375 0 44.8867 0 42.25C0 39.7598 2.05078 37.5625 4.6875 37.5625H37.5C39.9902 37.5625 42.1875 39.7598 42.1875 42.25ZM0 23.5C0 21.0098 2.05078 18.8125 4.6875 18.8125H60.9375C63.4277 18.8125 65.625 21.0098 65.625 23.5C65.625 26.1367 63.4277 28.1875 60.9375 28.1875H4.6875C2.05078 28.1875 0 26.1367 0 23.5ZM65.625 61C65.625 63.6367 63.4277 65.6875 60.9375 65.6875H4.6875C2.05078 65.6875 0 63.6367 0 61C0 58.5098 2.05078 56.3125 4.6875 56.3125H60.9375C63.4277 56.3125 65.625 58.5098 65.625 61Z"
10
+ fill="currentColor"
11
+ />
12
+ </svg>
13
+ );
14
+
15
+ export const AlignRight = () => (
16
+ <svg width="20" height="20" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
17
+ <path
18
+ d="M65.625 4.75C65.625 7.38672 63.4277 9.4375 60.9375 9.4375H28.125C25.4883 9.4375 23.4375 7.38672 23.4375 4.75C23.4375 2.25977 25.4883 0.0625 28.125 0.0625H60.9375C63.4277 0.0625 65.625 2.25977 65.625 4.75ZM65.625 42.25C65.625 44.8867 63.4277 46.9375 60.9375 46.9375H28.125C25.4883 46.9375 23.4375 44.8867 23.4375 42.25C23.4375 39.7598 25.4883 37.5625 28.125 37.5625H60.9375C63.4277 37.5625 65.625 39.7598 65.625 42.25ZM0 23.5C0 21.0098 2.05078 18.8125 4.6875 18.8125H60.9375C63.4277 18.8125 65.625 21.0098 65.625 23.5C65.625 26.1367 63.4277 28.1875 60.9375 28.1875H4.6875C2.05078 28.1875 0 26.1367 0 23.5ZM65.625 61C65.625 63.6367 63.4277 65.6875 60.9375 65.6875H4.6875C2.05078 65.6875 0 63.6367 0 61C0 58.5098 2.05078 56.3125 4.6875 56.3125H60.9375C63.4277 56.3125 65.625 58.5098 65.625 61Z"
19
+ fill="currentColor"
20
+ />
21
+ </svg>
22
+ );
23
+
24
+ export const AlignCenter = () => (
25
+ <svg width="20" height="20" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
26
+ <path
27
+ d="M51.5625 4.75C51.5625 7.38672 49.3652 9.4375 46.875 9.4375H18.75C16.1133 9.4375 14.0625 7.38672 14.0625 4.75C14.0625 2.25977 16.1133 0.0625 18.75 0.0625H46.875C49.3652 0.0625 51.5625 2.25977 51.5625 4.75ZM65.625 23.5C65.625 26.1367 63.4277 28.1875 60.9375 28.1875H4.6875C2.05078 28.1875 0 26.1367 0 23.5C0 21.0098 2.05078 18.8125 4.6875 18.8125H60.9375C63.4277 18.8125 65.625 21.0098 65.625 23.5ZM0 61C0 58.5098 2.05078 56.3125 4.6875 56.3125H60.9375C63.4277 56.3125 65.625 58.5098 65.625 61C65.625 63.6367 63.4277 65.6875 60.9375 65.6875H4.6875C2.05078 65.6875 0 63.6367 0 61ZM51.5625 42.25C51.5625 44.8867 49.3652 46.9375 46.875 46.9375H18.75C16.1133 46.9375 14.0625 44.8867 14.0625 42.25C14.0625 39.7598 16.1133 37.5625 18.75 37.5625H46.875C49.3652 37.5625 51.5625 39.7598 51.5625 42.25Z"
28
+ fill="currentColor"
29
+ />
30
+ </svg>
31
+ );
32
+
33
+ export const AlignJustify = () => (
34
+ <svg width="20" height="20" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
35
+ <path
36
+ d="M65.625 4.75C65.625 7.38672 63.4277 9.4375 60.9375 9.4375H4.6875C2.05078 9.4375 0 7.38672 0 4.75C0 2.25977 2.05078 0.0625 4.6875 0.0625H60.9375C63.4277 0.0625 65.625 2.25977 65.625 4.75ZM65.625 42.25C65.625 44.8867 63.4277 46.9375 60.9375 46.9375H4.6875C2.05078 46.9375 0 44.8867 0 42.25C0 39.7598 2.05078 37.5625 4.6875 37.5625H60.9375C63.4277 37.5625 65.625 39.7598 65.625 42.25ZM0 23.5C0 21.0098 2.05078 18.8125 4.6875 18.8125H60.9375C63.4277 18.8125 65.625 21.0098 65.625 23.5C65.625 26.1367 63.4277 28.1875 60.9375 28.1875H4.6875C2.05078 28.1875 0 26.1367 0 23.5ZM65.625 61C65.625 63.6367 63.4277 65.6875 60.9375 65.6875H4.6875C2.05078 65.6875 0 63.6367 0 61C0 58.5098 2.05078 56.3125 4.6875 56.3125H60.9375C63.4277 56.3125 65.625 58.5098 65.625 61Z"
37
+ fill="currentColor"
38
+ />
39
+ </svg>
40
+ );
41
+
42
+ export default ({ getValue, onChange }) => {
43
+ const [open, setOpen] = useState(false);
44
+ const value = getValue();
45
+ const text = value.texts.get(0);
46
+
47
+ let type;
48
+
49
+ if (text) {
50
+ const blockParent = value.document.getParent(text.key);
51
+ const data = blockParent.data.toJSON();
52
+
53
+ if (data?.attributes?.align) {
54
+ type = data?.attributes?.align;
55
+ }
56
+ }
57
+
58
+ let icon;
59
+
60
+ switch (type) {
61
+ case 'right':
62
+ icon = <AlignRight />;
63
+ break;
64
+ case 'center':
65
+ icon = <AlignCenter />;
66
+ break;
67
+ case 'justify':
68
+ icon = <AlignJustify />;
69
+ break;
70
+ default:
71
+ icon = <AlignLeft />;
72
+ break;
73
+ }
74
+
75
+ const applyAlignment = (event) => {
76
+ if (value.texts.size) {
77
+ const alignType = event.target?.closest('div')?.getAttribute('value');
78
+
79
+ if (alignType) {
80
+ let c = value.change();
81
+
82
+ value.texts.forEach((text) => {
83
+ const blockParent = value.document.getParent(text.key);
84
+
85
+ c = c.setNodeByKey(blockParent.key, {
86
+ data: { ...blockParent.data, attributes: { ...blockParent.data?.attributes, align: alignType } },
87
+ });
88
+ });
89
+
90
+ onChange(c);
91
+ }
92
+ }
93
+
94
+ setOpen(false);
95
+ };
96
+
97
+ const onMouseDown = (event) => {
98
+ event.preventDefault();
99
+ event.stopPropagation();
100
+ setOpen(!open);
101
+ };
102
+
103
+ return (
104
+ <div>
105
+ <div style={{ display: 'flex', alignItems: 'center' }} onClick={onMouseDown}>
106
+ {icon}
107
+ <span style={{ marginLeft: '5px', fontSize: '8px' }}>&#9660;</span>
108
+ </div>
109
+ <Collapse in={open} timeout="auto" unmountOnExit style={{ position: 'absolute' }}>
110
+ <List
111
+ component="div"
112
+ disablePadding
113
+ style={{
114
+ background: '#fff',
115
+ display: 'flex',
116
+ flexDirection: 'row',
117
+ padding: 0,
118
+ }}
119
+ >
120
+ <ListItem button type="submit" value="left" aria-label="Align text left" onClick={applyAlignment}>
121
+ <AlignLeft />
122
+ </ListItem>
123
+
124
+ <ListItem button type="submit" value="center" aria-label="Align text center" onClick={applyAlignment}>
125
+ <AlignCenter />
126
+ </ListItem>
127
+
128
+ <ListItem button type="submit" value="right" aria-label="Align text right" onClick={applyAlignment}>
129
+ <AlignRight />
130
+ </ListItem>
131
+
132
+ <ListItem button type="submit" value="justify" aria-label="Justify text" onClick={applyAlignment}>
133
+ <AlignJustify />
134
+ </ListItem>
135
+ </List>
136
+ </Collapse>
137
+ </div>
138
+ );
139
+ };
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import debug from 'debug';
3
+ import TextAlignIcon from './icons';
4
+
5
+ const log = debug('@pie-lib:editable-html:plugins:characters');
6
+
7
+ /**
8
+ * Plugin in order to be able to change alignment for the selected text(s) element(s).
9
+ * @param opts
10
+ * @constructor
11
+ */
12
+ export default function TextAlign(opts) {
13
+ const plugin = {
14
+ name: 'textAlign',
15
+ toolbar: {
16
+ icon: <TextAlignIcon {...opts} />,
17
+ ariaLabel: 'Text Align',
18
+ onClick: () => {},
19
+ },
20
+ };
21
+
22
+ return plugin;
23
+ }