@pie-lib/editable-html 9.1.2 → 9.1.3

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.
@@ -1,10 +1,12 @@
1
1
  import React from 'react';
2
2
  import { withStyles } from '@material-ui/core/styles';
3
- import Popover from '@material-ui/core/Popover';
3
+ import Popper from '@material-ui/core/Popper';
4
4
  import Typography from '@material-ui/core/Typography';
5
5
 
6
6
  const styles = () => ({
7
7
  popover: {
8
+ background: '#fff',
9
+ padding: '10px',
8
10
  pointerEvents: 'none',
9
11
  zIndex: 99999
10
12
  },
@@ -19,8 +21,8 @@ const styles = () => ({
19
21
  }
20
22
  });
21
23
 
22
- const CustomPopOver = withStyles(styles)(({ classes, children, ...props }) => (
23
- <Popover
24
+ const CustomPopper = withStyles(styles)(({ classes, children, ...props }) => (
25
+ <Popper
24
26
  id="mouse-over-popover"
25
27
  open
26
28
  className={classes.popover}
@@ -36,10 +38,11 @@ const CustomPopOver = withStyles(styles)(({ classes, children, ...props }) => (
36
38
  horizontal: 'left'
37
39
  }}
38
40
  disableRestoreFocus
41
+ disableAutoFocus
39
42
  {...props}
40
43
  >
41
44
  <Typography classes={{ root: classes.typography }}>{children}</Typography>
42
- </Popover>
45
+ </Popper>
43
46
  ));
44
47
 
45
- export default CustomPopOver;
48
+ export default CustomPopper;
@@ -5,18 +5,11 @@ import get from 'lodash/get';
5
5
 
6
6
  import { PureToolbar } from '@pie-lib/math-toolbar';
7
7
 
8
- import CustomPopOver from './custom-popover';
8
+ import CustomPopper from './custom-popper';
9
9
  import { insertSnackBar } from '../respArea/utils';
10
10
  import { characterIcons, spanishConfig, specialConfig } from './utils';
11
11
  const log = debug('@pie-lib:editable-html:plugins:characters');
12
12
 
13
- const removeDialogs = () => {
14
- const prevDialogs = document.querySelectorAll('.insert-character-dialog');
15
-
16
- log('[characters:removeDialogs]');
17
- prevDialogs.forEach(s => s.remove());
18
- };
19
-
20
13
  const removePopOvers = () => {
21
14
  const prevPopOvers = document.querySelectorAll('#mouse-over-popover');
22
15
 
@@ -24,16 +17,22 @@ const removePopOvers = () => {
24
17
  prevPopOvers.forEach(s => s.remove());
25
18
  };
26
19
 
27
- const insertDialog = ({ value, callback, opts }) => {
20
+ export const removeDialogs = () => {
21
+ const prevDialogs = document.querySelectorAll('.insert-character-dialog');
22
+
23
+ log('[characters:removeDialogs]');
24
+ prevDialogs.forEach(s => s.remove());
25
+ removePopOvers();
26
+ };
27
+
28
+ const insertDialog = ({ editorDOM, value, callback, opts }) => {
28
29
  const newEl = document.createElement('div');
29
- const initialBodyOverflow = document.body.style.overflow;
30
30
 
31
31
  log('[characters:insertDialog]');
32
32
 
33
33
  removeDialogs();
34
34
 
35
35
  newEl.className = 'insert-character-dialog';
36
- document.body.style.overflow = 'hidden';
37
36
 
38
37
  let configToUse;
39
38
 
@@ -85,33 +84,48 @@ const insertDialog = ({ value, callback, opts }) => {
85
84
 
86
85
  popoverEl = document.createElement('div');
87
86
  ReactDOM.render(
88
- <CustomPopOver onClose={closePopOver} anchorEl={event.currentTarget}>
87
+ <CustomPopper onClose={closePopOver} anchorEl={event.currentTarget}>
89
88
  <div>{el.label}</div>
90
89
 
91
90
  <div style={infoStyle}>{el.description}</div>
92
91
 
93
92
  <div style={infoStyle}>{el.unicode}</div>
94
- </CustomPopOver>,
93
+ </CustomPopper>,
95
94
  popoverEl
96
95
  );
97
96
 
98
97
  document.body.appendChild(newEl);
99
98
  };
100
99
 
100
+ let firstCallMade = false;
101
+
102
+ const listener = e => {
103
+ // this will be triggered right after setting it because
104
+ // this toolbar is added on the mousedown event
105
+ // so right after mouseup, the click will be triggered
106
+ if (firstCallMade) {
107
+ const focusIsInModals =
108
+ newEl.contains(e.target) || (popoverEl && popoverEl.contains(e.target));
109
+ const focusIsInEditor = editorDOM.contains(e.target);
110
+
111
+ if (!(focusIsInModals || focusIsInEditor)) {
112
+ handleClose();
113
+ }
114
+ } else {
115
+ firstCallMade = true;
116
+ }
117
+ };
118
+
101
119
  const handleClose = () => {
120
+ callback(undefined, true);
102
121
  newEl.remove();
103
122
  closePopOver();
104
- document.body.style.overflow = initialBodyOverflow;
105
- callback(undefined, true);
123
+ document.body.removeEventListener('click', listener);
106
124
  };
107
125
 
108
126
  const handleChange = val => {
109
127
  if (typeof val === 'string') {
110
- callback(val);
111
- }
112
-
113
- if (configToUse.autoClose) {
114
- handleClose();
128
+ callback(val, true);
115
129
  }
116
130
  };
117
131
 
@@ -158,31 +172,40 @@ const insertDialog = ({ value, callback, opts }) => {
158
172
  const cursorItem = document.querySelector(`[data-key="${value.anchorKey}"]`);
159
173
 
160
174
  if (cursorItem) {
175
+ const bodyRect = document.body.getBoundingClientRect();
161
176
  const boundRect = cursorItem.getBoundingClientRect();
162
177
 
163
178
  document.body.appendChild(newEl);
164
- newEl.style.position = 'fixed';
165
- newEl.style.top = `${boundRect.top - newEl.offsetHeight - 10}px`;
166
- newEl.style.left = `${boundRect.left + cursorItem.offsetWidth + 10}px`;
179
+ newEl.style.position = 'absolute';
180
+ newEl.style.top = `${boundRect.top + Math.abs(bodyRect.top) - newEl.offsetHeight - 10}px`;
167
181
  newEl.style.zIndex = 99999;
168
182
 
169
- let firstCallMade = false;
170
-
171
- const listener = () => {
172
- // this will be triggered right after setting it because
173
- // this toolbar is added on the mousedown event
174
- // so right after mouseup, the click will be triggered
175
- if (firstCallMade) {
176
- document.body.removeEventListener('click', listener);
177
- handleClose();
178
- } else {
179
- firstCallMade = true;
180
- }
181
- };
182
-
183
- if (configToUse.autoClose) {
184
- document.body.addEventListener('click', listener);
183
+ const leftValue = `${boundRect.left +
184
+ Math.abs(bodyRect.left) +
185
+ cursorItem.offsetWidth +
186
+ 10}px`;
187
+
188
+ const rightValue = `${boundRect.x}px`;
189
+
190
+ newEl.style.left = leftValue;
191
+
192
+ const leftAlignedWidth = newEl.offsetWidth;
193
+
194
+ newEl.style.left = 'unset';
195
+ newEl.style.right = rightValue;
196
+
197
+ const rightAlignedWidth = newEl.offsetWidth;
198
+
199
+ newEl.style.left = 'unset';
200
+ newEl.style.right = 'unset';
201
+
202
+ if (leftAlignedWidth >= rightAlignedWidth) {
203
+ newEl.style.left = leftValue;
204
+ } else {
205
+ newEl.style.right = rightValue;
185
206
  }
207
+
208
+ document.body.addEventListener('click', listener);
186
209
  }
187
210
  });
188
211
  };
@@ -201,12 +224,15 @@ const CharacterIcon = ({ letter }) => (
201
224
  export default function CharactersPlugin(opts) {
202
225
  removeDialogs();
203
226
  return {
204
- name: 'math',
227
+ name: 'characters',
205
228
  toolbar: {
206
229
  icon: <CharacterIcon letter={opts.characterIcon || characterIcons[opts.language] || 'ñ'} />,
207
- onClick: (value, onChange) => {
230
+ onClick: (value, onChange, getFocusedValue) => {
231
+ const editorDOM = document.querySelector(`[data-key="${value.document.key}"]`);
208
232
  let valueToUse = value;
209
233
  const callback = (char, focus) => {
234
+ valueToUse = getFocusedValue();
235
+
210
236
  if (char) {
211
237
  const change = valueToUse
212
238
  .change()
@@ -220,15 +246,13 @@ export default function CharactersPlugin(opts) {
220
246
  log('[characters:click]');
221
247
 
222
248
  if (focus) {
223
- const editorDOM = document.querySelector(`[data-key="${valueToUse.document.key}"]`);
224
-
225
249
  if (editorDOM) {
226
250
  editorDOM.focus();
227
251
  }
228
252
  }
229
253
  };
230
254
 
231
- insertDialog({ value: valueToUse, callback, opts });
255
+ insertDialog({ editorDOM, value: valueToUse, callback, opts });
232
256
  }
233
257
  },
234
258
 
@@ -4,8 +4,7 @@ export const spanishConfig = {
4
4
  ['Á', 'É', 'Í', 'Ó', 'Ú'],
5
5
  ['—', '«', '»', 'ñ', 'ü'],
6
6
  ['-', '¿', '¡', 'Ñ', 'Ü']
7
- ],
8
- autoClose: true
7
+ ]
9
8
  };
10
9
 
11
10
  export const specialConfig = {
@@ -40,7 +40,7 @@ export const ToolbarButton = props => {
40
40
  <Button
41
41
  active={isActive}
42
42
  disabled={disabled}
43
- onClick={() => props.onClick(props.value, props.onChange)}
43
+ onClick={() => props.onClick(props.value, props.onChange, props.getFocusedValue)}
44
44
  extraStyles={props.buttonStyles}
45
45
  >
46
46
  {props.icon}
@@ -60,6 +60,7 @@ export const DefaultToolbar = ({
60
60
  pluginProps,
61
61
  value,
62
62
  onChange,
63
+ getFocusedValue,
63
64
  onDone,
64
65
  classes,
65
66
  showDone,
@@ -71,7 +72,15 @@ export const DefaultToolbar = ({
71
72
  <div className={classes.defaultToolbar}>
72
73
  <div className={classes.buttonsContainer}>
73
74
  {filtered.map((p, index) => {
74
- return <ToolbarButton {...p} key={index} value={value} onChange={onChange} />;
75
+ return (
76
+ <ToolbarButton
77
+ {...p}
78
+ key={index}
79
+ value={value}
80
+ onChange={onChange}
81
+ getFocusedValue={getFocusedValue}
82
+ />
83
+ );
75
84
  })}
76
85
  </div>
77
86
  {showDone && !deletable && <DoneButton onClick={onDone} />}
@@ -85,6 +94,7 @@ DefaultToolbar.propTypes = {
85
94
  pluginProps: PropTypes.object,
86
95
  value: SlatePropTypes.value.isRequired,
87
96
  onChange: PropTypes.func.isRequired,
97
+ getFocusedValue: PropTypes.func.isRequired,
88
98
  onDone: PropTypes.func.isRequired,
89
99
  showDone: PropTypes.bool,
90
100
  addArea: PropTypes.bool,
@@ -17,6 +17,7 @@ export class EditorAndToolbar extends React.Component {
17
17
  value: SlatePropTypes.value.isRequired,
18
18
  plugins: PropTypes.array.isRequired,
19
19
  onChange: PropTypes.func.isRequired,
20
+ getFocusedValue: PropTypes.func.isRequired,
20
21
  onDone: PropTypes.func.isRequired,
21
22
  onDataChange: PropTypes.func,
22
23
  toolbarRef: PropTypes.func,
@@ -49,6 +50,7 @@ export class EditorAndToolbar extends React.Component {
49
50
  value,
50
51
  plugins,
51
52
  onChange,
53
+ getFocusedValue,
52
54
  onDone,
53
55
  focusedNode,
54
56
  autoWidth,
@@ -113,6 +115,7 @@ export class EditorAndToolbar extends React.Component {
113
115
  value={value}
114
116
  isFocused={inFocus}
115
117
  onChange={onChange}
118
+ getFocusedValue={getFocusedValue}
116
119
  onDone={onDone}
117
120
  onDataChange={onDataChange}
118
121
  toolbarRef={toolbarRef}
@@ -13,6 +13,7 @@ import { DoneButton } from './done-button';
13
13
  import { findSingleNode, findParentNode } from '../utils';
14
14
  import { withStyles } from '@material-ui/core/styles';
15
15
  import DefaultToolbar from './default-toolbar';
16
+ import { removeDialogs as removeCharacterDialogs } from '../characters';
16
17
 
17
18
  const log = debug('@pie-lib:editable-html:plugins:toolbar');
18
19
 
@@ -50,6 +51,7 @@ export class Toolbar extends React.Component {
50
51
  isFocused: PropTypes.bool,
51
52
  autoWidth: PropTypes.bool,
52
53
  onChange: PropTypes.func.isRequired,
54
+ getFocusedValue: PropTypes.func.isRequired,
53
55
  pluginProps: PropTypes.object,
54
56
  toolbarOpts: PropTypes.shape({
55
57
  position: PropTypes.oneOf(['bottom', 'top']),
@@ -68,6 +70,10 @@ export class Toolbar extends React.Component {
68
70
  };
69
71
  }
70
72
 
73
+ componentWillUnmount() {
74
+ removeCharacterDialogs();
75
+ }
76
+
71
77
  hasMark = type => {
72
78
  const { value } = this.props;
73
79
  return value.marks.some(mark => mark.type == type);
@@ -136,6 +142,7 @@ export class Toolbar extends React.Component {
136
142
  value,
137
143
  autoWidth,
138
144
  onChange,
145
+ getFocusedValue,
139
146
  isFocused,
140
147
  onDone,
141
148
  toolbarRef
@@ -248,6 +255,7 @@ export class Toolbar extends React.Component {
248
255
  pluginProps={pluginProps}
249
256
  value={value}
250
257
  onChange={onChange}
258
+ getFocusedValue={getFocusedValue}
251
259
  showDone={defaultToolbarShowDone}
252
260
  onDone={handleDone}
253
261
  deletable={deletable}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/plugins/characters/custom-popover.js"],"names":["styles","popover","pointerEvents","zIndex","paper","padding","height","width","typography","fontSize","textAlign","CustomPopOver","classes","children","props","vertical","horizontal","root"],"mappings":";;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;;;AAEA,IAAMA,MAAM,GAAG,SAATA,MAAS;AAAA,SAAO;AACpBC,IAAAA,OAAO,EAAE;AACPC,MAAAA,aAAa,EAAE,MADR;AAEPC,MAAAA,MAAM,EAAE;AAFD,KADW;AAKpBC,IAAAA,KAAK,EAAE;AACLC,MAAAA,OAAO,EAAE,EADJ;AAELC,MAAAA,MAAM,EAAE,MAFH;AAGLC,MAAAA,KAAK,EAAE;AAHF,KALa;AAUpBC,IAAAA,UAAU,EAAE;AACVC,MAAAA,QAAQ,EAAE,EADA;AAEVC,MAAAA,SAAS,EAAE;AAFD;AAVQ,GAAP;AAAA,CAAf;;AAgBA,IAAMC,aAAa,GAAG,wBAAWX,MAAX,EAAmB;AAAA,MAAGY,OAAH,QAAGA,OAAH;AAAA,MAAYC,QAAZ,QAAYA,QAAZ;AAAA,MAAyBC,KAAzB;AAAA,sBACvC,gCAAC,mBAAD;AACE,IAAA,EAAE,EAAC,oBADL;AAEE,IAAA,IAAI,MAFN;AAGE,IAAA,SAAS,EAAEF,OAAO,CAACX,OAHrB;AAIE,IAAA,OAAO,EAAE;AACPG,MAAAA,KAAK,EAAEQ,OAAO,CAACR;AADR,KAJX;AAOE,IAAA,YAAY,EAAE;AACZW,MAAAA,QAAQ,EAAE,QADE;AAEZC,MAAAA,UAAU,EAAE;AAFA,KAPhB;AAWE,IAAA,eAAe,EAAE;AACfD,MAAAA,QAAQ,EAAE,KADK;AAEfC,MAAAA,UAAU,EAAE;AAFG,KAXnB;AAeE,IAAA,mBAAmB;AAfrB,KAgBMF,KAhBN,gBAkBE,gCAAC,sBAAD;AAAY,IAAA,OAAO,EAAE;AAAEG,MAAAA,IAAI,EAAEL,OAAO,CAACJ;AAAhB;AAArB,KAAoDK,QAApD,CAlBF,CADuC;AAAA,CAAnB,CAAtB;eAuBeF,a","sourcesContent":["import React from 'react';\nimport { withStyles } from '@material-ui/core/styles';\nimport Popover from '@material-ui/core/Popover';\nimport Typography from '@material-ui/core/Typography';\n\nconst styles = () => ({\n popover: {\n pointerEvents: 'none',\n zIndex: 99999\n },\n paper: {\n padding: 20,\n height: 'auto',\n width: 'auto'\n },\n typography: {\n fontSize: 50,\n textAlign: 'center'\n }\n});\n\nconst CustomPopOver = withStyles(styles)(({ classes, children, ...props }) => (\n <Popover\n id=\"mouse-over-popover\"\n open\n className={classes.popover}\n classes={{\n paper: classes.paper\n }}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left'\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'left'\n }}\n disableRestoreFocus\n {...props}\n >\n <Typography classes={{ root: classes.typography }}>{children}</Typography>\n </Popover>\n));\n\nexport default CustomPopOver;\n"],"file":"custom-popover.js"}