@pie-lib/graphing 4.0.23 → 4.0.24-beta.2

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 (66) hide show
  1. package/CHANGELOG.md +0 -92
  2. package/lib/mark-label.js +7 -197
  3. package/lib/mark-label.js.map +1 -1
  4. package/lib/tools/circle/component.js +3 -34
  5. package/lib/tools/circle/component.js.map +1 -1
  6. package/lib/tools/point/component.js +8 -29
  7. package/lib/tools/point/component.js.map +1 -1
  8. package/lib/tools/polygon/component.js +6 -31
  9. package/lib/tools/polygon/component.js.map +1 -1
  10. package/lib/tools/shared/line/index.js +3 -34
  11. package/lib/tools/shared/line/index.js.map +1 -1
  12. package/package.json +17 -17
  13. package/src/mark-label.jsx +8 -209
  14. package/src/tools/circle/component.jsx +3 -26
  15. package/src/tools/point/component.jsx +8 -21
  16. package/src/tools/polygon/component.jsx +6 -24
  17. package/src/tools/shared/line/index.jsx +3 -26
  18. package/LICENSE.md +0 -5
  19. package/src/__tests__/bg.test.jsx +0 -250
  20. package/src/__tests__/coordinates-label.test.jsx +0 -243
  21. package/src/__tests__/graph-with-controls.test.jsx +0 -198
  22. package/src/__tests__/graph.test.jsx +0 -796
  23. package/src/__tests__/grid-setup.test.jsx +0 -645
  24. package/src/__tests__/grid.test.jsx +0 -22
  25. package/src/__tests__/key-legend.test.jsx +0 -260
  26. package/src/__tests__/label-svg-icon.test.jsx +0 -278
  27. package/src/__tests__/labels.test.jsx +0 -55
  28. package/src/__tests__/mark-label.test.jsx +0 -437
  29. package/src/__tests__/toggle-bar.test.jsx +0 -146
  30. package/src/__tests__/tool-menu.test.jsx +0 -115
  31. package/src/__tests__/undo-redo.test.jsx +0 -24
  32. package/src/__tests__/use-debounce.test.js +0 -21
  33. package/src/__tests__/utils.js +0 -41
  34. package/src/__tests__/utils.test.js +0 -105
  35. package/src/axis/__tests__/arrow.test.jsx +0 -38
  36. package/src/axis/__tests__/axes.test.jsx +0 -216
  37. package/src/container/__tests__/actions.test.js +0 -105
  38. package/src/container/__tests__/index.test.jsx +0 -319
  39. package/src/container/__tests__/marks.test.js +0 -172
  40. package/src/container/__tests__/middleware.test.js +0 -235
  41. package/src/container/__tests__/reducer.test.js +0 -324
  42. package/src/tools/absolute/__tests__/component.test.jsx +0 -53
  43. package/src/tools/circle/__tests__/bg-circle.test.jsx +0 -26
  44. package/src/tools/circle/__tests__/component.test.jsx +0 -494
  45. package/src/tools/circle/__tests__/index.test.js +0 -480
  46. package/src/tools/exponential/__tests__/component.test.jsx +0 -53
  47. package/src/tools/exponential/__tests__/index.test.js +0 -729
  48. package/src/tools/line/__tests__/component.test.jsx +0 -37
  49. package/src/tools/parabola/__tests__/component.test.jsx +0 -48
  50. package/src/tools/parabola/__tests__/index.test.js +0 -470
  51. package/src/tools/point/__tests__/component.test.jsx +0 -475
  52. package/src/tools/point/__tests__/index.test.js +0 -241
  53. package/src/tools/polygon/__tests__/component.test.jsx +0 -471
  54. package/src/tools/polygon/__tests__/index.test.js +0 -294
  55. package/src/tools/polygon/__tests__/line.test.jsx +0 -35
  56. package/src/tools/polygon/__tests__/polygon.test.jsx +0 -61
  57. package/src/tools/ray/__tests__/component.test.jsx +0 -29
  58. package/src/tools/segment/__tests__/component.test.jsx +0 -28
  59. package/src/tools/shared/__tests__/arrow-head.test.jsx +0 -31
  60. package/src/tools/shared/line/__tests__/index.test.jsx +0 -109
  61. package/src/tools/shared/line/__tests__/line-path.test.jsx +0 -53
  62. package/src/tools/shared/line/__tests__/with-root-edge.test.jsx +0 -73
  63. package/src/tools/shared/point/__tests__/arrow-point.test.jsx +0 -91
  64. package/src/tools/shared/point/__tests__/base-point.test.jsx +0 -87
  65. package/src/tools/sine/__tests__/component.test.jsx +0 -51
  66. package/src/tools/vector/__tests__/component.test.jsx +0 -25
@@ -16,15 +16,7 @@ export class Point extends React.Component {
16
16
 
17
17
  constructor(props) {
18
18
  super(props);
19
- // which label is being edited, null if none - a point only has the one
20
- this.state = { editingLabel: null };
21
- }
22
-
23
- componentDidUpdate(prevProps) {
24
- // leaving label mode closes any label that is still being edited
25
- if (prevProps.labelModeEnabled && !this.props.labelModeEnabled && this.state.editingLabel !== null) {
26
- this.setState({ editingLabel: null });
27
- }
19
+ this.state = {};
28
20
  }
29
21
 
30
22
  move = (p) => {
@@ -67,12 +59,6 @@ export class Point extends React.Component {
67
59
  });
68
60
  };
69
61
 
70
- stopEditingLabel = () => {
71
- if (this.state.editingLabel !== null) {
72
- this.setState({ editingLabel: null });
73
- }
74
- };
75
-
76
62
  clickPoint = () => {
77
63
  const { labelModeEnabled, onChange, onClick, mark } = this.props;
78
64
 
@@ -87,14 +73,17 @@ export class Point extends React.Component {
87
73
 
88
74
  onChange(mark, { label: '', ...mark });
89
75
 
90
- // MarkLabel focuses itself once it is rendered - it also holds on to the focus if the model
91
- // that comes back from the host (api save) remounts the input.
92
- this.setState({ editingLabel: 'label' });
76
+ // MarkLabel is only rendered after the parent re-renders with the new label prop,
77
+ // so we defer focus until after that render cycle completes.
78
+ setTimeout(() => {
79
+ if (this.input) {
80
+ this.input.focus();
81
+ }
82
+ }, 0);
93
83
  };
94
84
 
95
85
  render() {
96
86
  const { coordinatesOnHover, graphProps, labelNode, labelModeEnabled } = this.props;
97
- const { editingLabel } = this.state;
98
87
  const mark = this.state.mark ? this.state.mark : this.props.mark;
99
88
 
100
89
  return (
@@ -122,11 +111,9 @@ export class Point extends React.Component {
122
111
  ReactDOM.createPortal(
123
112
  <MarkLabel
124
113
  inputRef={(r) => (this.input = r)}
125
- autoFocus={editingLabel === 'label'}
126
114
  disabled={!labelModeEnabled}
127
115
  mark={mark}
128
116
  graphProps={graphProps}
129
- onBlur={this.stopEditingLabel}
130
117
  onChange={this.labelChange}
131
118
  />,
132
119
  labelNode,
@@ -90,16 +90,6 @@ export class RawBaseComponent extends React.Component {
90
90
  points: [],
91
91
  };
92
92
 
93
- // index of the point whose label is edited (points.length for the polygon label), null if none
94
- state = { editingLabel: null };
95
-
96
- componentDidUpdate(prevProps) {
97
- // leaving label mode closes any label that is still being edited
98
- if (prevProps.labelModeEnabled && !this.props.labelModeEnabled && this.state.editingLabel !== null) {
99
- this.setState({ editingLabel: null });
100
- }
101
- }
102
-
103
93
  dragPoint = (index, from, to) => {
104
94
  log('[dragPoint] from, to:', from, to);
105
95
  const { onChange, points } = this.props;
@@ -172,12 +162,6 @@ export class RawBaseComponent extends React.Component {
172
162
  onChangeProps(update);
173
163
  };
174
164
 
175
- stopEditingLabel = () => {
176
- if (this.state.editingLabel !== null) {
177
- this.setState({ editingLabel: null });
178
- }
179
- };
180
-
181
165
  clickPoint = (point, index, data) => {
182
166
  const {
183
167
  closed,
@@ -210,9 +194,12 @@ export class RawBaseComponent extends React.Component {
210
194
  onSetMiddleLabel(strippedMiddle, strippedPoints);
211
195
  }
212
196
 
213
- // MarkLabel focuses itself once it is rendered - it also holds on to the focus if the model
214
- // that comes back from the host (api save) remounts the input.
215
- this.setState({ editingLabel: index });
197
+ // defer the focus() call with setTimeout to allow the re-render to complete first.
198
+ setTimeout(() => {
199
+ if (this.input[index]) {
200
+ this.input[index].focus();
201
+ }
202
+ }, 0);
216
203
 
217
204
  return;
218
205
  }
@@ -243,7 +230,6 @@ export class RawBaseComponent extends React.Component {
243
230
  labelNode,
244
231
  labelModeEnabled,
245
232
  } = this.props;
246
- const { editingLabel } = this.state;
247
233
  const lines = buildLines(points, closed);
248
234
  const common = { onDragStart, onDragStop, graphProps, disabled, correctness };
249
235
  const polygonLabelIndex = (points && points.length) || 0;
@@ -253,11 +239,9 @@ export class RawBaseComponent extends React.Component {
253
239
  polygonLabelNode = ReactDOM.createPortal(
254
240
  <MarkLabel
255
241
  inputRef={(r) => (this.input[polygonLabelIndex] = r)}
256
- autoFocus={editingLabel === polygonLabelIndex}
257
242
  disabled={disabled || !labelModeEnabled}
258
243
  mark={middle}
259
244
  graphProps={graphProps}
260
- onBlur={this.stopEditingLabel}
261
245
  onChange={(label) => onChangeLabelProps({ ...middle, label })}
262
246
  />,
263
247
  labelNode,
@@ -307,11 +291,9 @@ export class RawBaseComponent extends React.Component {
307
291
  ? ReactDOM.createPortal(
308
292
  <MarkLabel
309
293
  inputRef={(r) => (this.input[index] = r)}
310
- autoFocus={editingLabel === index}
311
294
  disabled={disabled || !labelModeEnabled}
312
295
  mark={p}
313
296
  graphProps={graphProps}
314
- onBlur={this.stopEditingLabel}
315
297
  onChange={(label) => this.labelChange({ ...p, label }, index)}
316
298
  />,
317
299
  labelNode,
@@ -234,16 +234,6 @@ export const lineBase = (Comp, opts) => {
234
234
  labelNode: PropTypes.object,
235
235
  };
236
236
 
237
- // which of from/to/middle has its label edited, null if none
238
- state = { editingLabel: null };
239
-
240
- componentDidUpdate(prevProps) {
241
- // leaving label mode closes any label that is still being edited
242
- if (prevProps.labelModeEnabled && !this.props.labelModeEnabled && this.state.editingLabel !== null) {
243
- this.setState({ editingLabel: null });
244
- }
245
- }
246
-
247
237
  onChangePoint = (point) => {
248
238
  const { middle, onChange } = this.props;
249
239
  const { from, to } = point;
@@ -313,12 +303,6 @@ export const lineBase = (Comp, opts) => {
313
303
  changeMarkProps({ [type]: update });
314
304
  };
315
305
 
316
- stopEditingLabel = () => {
317
- if (this.state.editingLabel !== null) {
318
- this.setState({ editingLabel: null });
319
- }
320
- };
321
-
322
306
  clickPoint = (point, type, data) => {
323
307
  const { changeMarkProps, disabled, from, to, middle, labelModeEnabled, limitLabeling, onClick } = this.props;
324
308
 
@@ -347,9 +331,9 @@ export const lineBase = (Comp, opts) => {
347
331
  [type]: { label: '', ...point },
348
332
  });
349
333
 
350
- // MarkLabel focuses itself once it is rendered - it also holds on to the focus if the model
351
- // that comes back from the host (api save) remounts the input.
352
- this.setState({ editingLabel: type });
334
+ if (this.input[type]) {
335
+ this.input[type].focus();
336
+ }
353
337
  };
354
338
 
355
339
  // IMPORTANT, do not remove
@@ -370,7 +354,6 @@ export const lineBase = (Comp, opts) => {
370
354
  labelNode,
371
355
  labelModeEnabled,
372
356
  } = this.props;
373
- const { editingLabel } = this.state;
374
357
  const common = { graphProps, onDragStart, onDragStop, disabled, correctness, onClick };
375
358
  const angle = to ? trig.toDegrees(trig.angle(from, to)) : 0;
376
359
 
@@ -383,11 +366,9 @@ export const lineBase = (Comp, opts) => {
383
366
  fromLabelNode = ReactDOM.createPortal(
384
367
  <MarkLabel
385
368
  inputRef={(r) => (this.input.from = r)}
386
- autoFocus={editingLabel === 'from'}
387
369
  disabled={!labelModeEnabled}
388
370
  mark={from}
389
371
  graphProps={graphProps}
390
- onBlur={this.stopEditingLabel}
391
372
  onChange={(label) => this.labelChange({ ...from, label }, 'from')}
392
373
  />,
393
374
  labelNode,
@@ -398,11 +379,9 @@ export const lineBase = (Comp, opts) => {
398
379
  toLabelNode = ReactDOM.createPortal(
399
380
  <MarkLabel
400
381
  inputRef={(r) => (this.input.to = r)}
401
- autoFocus={editingLabel === 'to'}
402
382
  disabled={!labelModeEnabled}
403
383
  mark={to}
404
384
  graphProps={graphProps}
405
- onBlur={this.stopEditingLabel}
406
385
  onChange={(label) => this.labelChange({ ...to, label }, 'to')}
407
386
  />,
408
387
  labelNode,
@@ -413,11 +392,9 @@ export const lineBase = (Comp, opts) => {
413
392
  lineLabelNode = ReactDOM.createPortal(
414
393
  <MarkLabel
415
394
  inputRef={(r) => (this.input.middle = r)}
416
- autoFocus={editingLabel === 'middle'}
417
395
  disabled={!labelModeEnabled}
418
396
  mark={middle}
419
397
  graphProps={graphProps}
420
- onBlur={this.stopEditingLabel}
421
398
  onChange={(label) => this.labelChange({ ...middle, label }, 'middle')}
422
399
  />,
423
400
  labelNode,
package/LICENSE.md DELETED
@@ -1,5 +0,0 @@
1
- Copyright 2019 CoreSpring Inc
2
-
3
- Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
4
-
5
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -1,250 +0,0 @@
1
- import React from 'react';
2
- import { render } from '@pie-lib/test-utils';
3
- import { select } from 'd3-selection';
4
- import Bg from '../bg';
5
-
6
- jest.mock('d3-selection', () => ({
7
- select: jest.fn(),
8
- pointer: jest.fn(() => [50, 50]),
9
- }));
10
-
11
- describe('Bg', () => {
12
- let defaultProps;
13
- let mockRect;
14
- let clickHandler;
15
-
16
- beforeEach(() => {
17
- clickHandler = null;
18
- mockRect = {
19
- on: jest.fn((event, handler) => {
20
- if (event === 'click') {
21
- clickHandler = handler;
22
- }
23
- }),
24
- node: jest.fn(() => ({})),
25
- };
26
-
27
- select.mockReturnValue(mockRect);
28
-
29
- defaultProps = {
30
- width: 500,
31
- height: 400,
32
- onClick: jest.fn(),
33
- graphProps: {
34
- domain: { min: -10, max: 10, step: 1, label: 'x', axisLabel: 'X' },
35
- range: { min: -10, max: 10, step: 1, label: 'y', axisLabel: 'Y' },
36
- size: { width: 500, height: 400 },
37
- scale: {
38
- x: {
39
- invert: jest.fn((val) => val / 10),
40
- },
41
- y: {
42
- invert: jest.fn((val) => val / 10),
43
- },
44
- },
45
- },
46
- };
47
- });
48
-
49
- describe('rendering', () => {
50
- it('renders without crashing', () => {
51
- const { container } = render(<Bg {...defaultProps} />);
52
- expect(container).toBeTruthy();
53
- });
54
-
55
- it('renders a rect element', () => {
56
- const { container } = render(<Bg {...defaultProps} />);
57
- const rect = container.querySelector('rect');
58
- expect(rect).toBeTruthy();
59
- });
60
-
61
- it('applies correct dimensions', () => {
62
- const { container } = render(<Bg {...defaultProps} />);
63
- const rect = container.querySelector('rect');
64
-
65
- // Width and height should be expanded by padding * 2
66
- const padding = 10; // default padding
67
- expect(rect.getAttribute('width')).toBe(String(defaultProps.width + padding * 2));
68
- expect(rect.getAttribute('height')).toBe(String(defaultProps.height + padding * 2));
69
- });
70
-
71
- it('applies correct transform', () => {
72
- const { container } = render(<Bg {...defaultProps} />);
73
- const rect = container.querySelector('rect');
74
- const padding = 10;
75
-
76
- expect(rect.getAttribute('transform')).toBe(`translate(-${padding}, -${padding})`);
77
- });
78
-
79
- it('sets fill opacity to make it invisible', () => {
80
- const { container } = render(<Bg {...defaultProps} />);
81
- const rect = container.querySelector('rect');
82
-
83
- expect(rect.getAttribute('fill-opacity')).toBe('0.0');
84
- });
85
- });
86
-
87
- describe('componentDidMount', () => {
88
- it('attaches click handler to rect', () => {
89
- render(<Bg {...defaultProps} />);
90
-
91
- expect(select).toHaveBeenCalled();
92
- expect(mockRect.on).toHaveBeenCalledWith('click', expect.any(Function));
93
- });
94
- });
95
-
96
- describe('getRectPadding', () => {
97
- it('returns 10 for normal graphs', () => {
98
- const { container } = render(<Bg {...defaultProps} />);
99
- const rect = container.querySelector('rect');
100
- const padding = 10;
101
-
102
- expect(rect.getAttribute('width')).toBe(String(defaultProps.width + padding * 2));
103
- });
104
-
105
- it('returns 6 for graphs with thinner shapes', () => {
106
- const props = {
107
- ...defaultProps,
108
- graphProps: {
109
- ...defaultProps.graphProps,
110
- domain: { min: -100, max: 100, step: 1, label: 'x', axisLabel: 'X' },
111
- },
112
- };
113
-
114
- const { container } = render(<Bg {...props} />);
115
- const rect = container.querySelector('rect');
116
- const padding = 6;
117
-
118
- expect(rect.getAttribute('width')).toBe(String(props.width + padding * 2));
119
- });
120
- });
121
-
122
- describe('onRectClick', () => {
123
- it('calls onClick with snapped coordinates', () => {
124
- const { pointer } = require('d3-selection');
125
- pointer.mockReturnValue([100, 100]);
126
-
127
- render(<Bg {...defaultProps} />);
128
-
129
- const event = new MouseEvent('click');
130
- clickHandler(event);
131
-
132
- expect(defaultProps.onClick).toHaveBeenCalled();
133
- const calledWith = defaultProps.onClick.mock.calls[0][0];
134
- expect(calledWith).toHaveProperty('x');
135
- expect(calledWith).toHaveProperty('y');
136
- });
137
-
138
- it('snaps coordinates to nearest tick', () => {
139
- const { pointer } = require('d3-selection');
140
-
141
- render(<Bg {...defaultProps} />);
142
-
143
- const event = new MouseEvent('click');
144
- clickHandler(event);
145
-
146
- expect(defaultProps.onClick).toHaveBeenCalled();
147
- const { x, y } = defaultProps.onClick.mock.calls[0][0];
148
-
149
- expect(Number.isInteger(x) || x.toString().length <= 4).toBe(true);
150
- expect(Number.isInteger(y) || y.toString().length <= 4).toBe(true);
151
- });
152
-
153
- it('accounts for padding when converting coordinates', () => {
154
- const { pointer } = require('d3-selection');
155
- const coords = [50, 50];
156
- pointer.mockReturnValue(coords);
157
-
158
- render(<Bg {...defaultProps} />);
159
-
160
- const event = new MouseEvent('click');
161
- clickHandler(event);
162
-
163
- expect(defaultProps.graphProps.scale.x.invert).toHaveBeenCalled();
164
- expect(defaultProps.graphProps.scale.y.invert).toHaveBeenCalled();
165
- });
166
- });
167
-
168
- describe('shouldComponentUpdate', () => {
169
- it('returns true when width changes', () => {
170
- const { rerender } = render(<Bg {...defaultProps} />);
171
- const newProps = {
172
- ...defaultProps,
173
- width: 600,
174
- graphProps: {
175
- ...defaultProps.graphProps,
176
- size: { width: 600, height: defaultProps.height },
177
- },
178
- };
179
-
180
- expect(() => {
181
- rerender(<Bg {...newProps} />);
182
- }).not.toThrow();
183
- });
184
-
185
- it('returns true when height changes', () => {
186
- const { rerender } = render(<Bg {...defaultProps} />);
187
- const newProps = {
188
- ...defaultProps,
189
- height: 500,
190
- graphProps: {
191
- ...defaultProps.graphProps,
192
- size: { width: defaultProps.width, height: 500 },
193
- },
194
- };
195
-
196
- expect(() => {
197
- rerender(<Bg {...newProps} />);
198
- }).not.toThrow();
199
- });
200
-
201
- it('returns true when graphProps domain/range changes', () => {
202
- const { rerender } = render(<Bg {...defaultProps} />);
203
- const newProps = {
204
- ...defaultProps,
205
- graphProps: {
206
- ...defaultProps.graphProps,
207
- domain: { min: -5, max: 5, step: 1, label: 'x', axisLabel: 'X' },
208
- },
209
- };
210
-
211
- expect(() => {
212
- rerender(<Bg {...newProps} />);
213
- }).not.toThrow();
214
- });
215
- });
216
-
217
- describe('edge cases', () => {
218
- it('handles zero dimensions', () => {
219
- const props = { ...defaultProps, width: 0, height: 0 };
220
- const { container } = render(<Bg {...props} />);
221
- const rect = container.querySelector('rect');
222
-
223
- expect(rect).toBeTruthy();
224
- });
225
-
226
- it('handles large dimensions', () => {
227
- const props = { ...defaultProps, width: 10000, height: 10000 };
228
- const { container } = render(<Bg {...props} />);
229
- const rect = container.querySelector('rect');
230
-
231
- expect(rect).toBeTruthy();
232
- expect(rect.getAttribute('width')).toBe('10020');
233
- expect(rect.getAttribute('height')).toBe('10020');
234
- });
235
-
236
- it('handles negative coordinates in domain/range', () => {
237
- const props = {
238
- ...defaultProps,
239
- graphProps: {
240
- ...defaultProps.graphProps,
241
- domain: { min: -100, max: -10, step: 1, label: 'x', axisLabel: 'X' },
242
- range: { min: -100, max: -10, step: 1, label: 'y', axisLabel: 'Y' },
243
- },
244
- };
245
-
246
- const { container } = render(<Bg {...props} />);
247
- expect(container.querySelector('rect')).toBeTruthy();
248
- });
249
- });
250
- });