@pie-lib/plot 2.41.0-mui-update.0 → 3.0.0-next.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.
@@ -1,8 +1,13 @@
1
- import { shallow } from 'enzyme';
1
+ import { render, cleanup } from '@testing-library/react';
2
2
  import React from 'react';
3
3
  import { Root } from '../root';
4
4
  import { select, mouse } from 'd3-selection';
5
5
 
6
+ jest.mock('d3-selection', () => ({
7
+ select: jest.fn(),
8
+ mouse: jest.fn(),
9
+ }));
10
+
6
11
  const scaleMock = () => {
7
12
  const fn = jest.fn((n) => n);
8
13
  fn.invert = jest.fn((n) => n);
@@ -34,83 +39,234 @@ const graphProps = () => ({
34
39
  },
35
40
  });
36
41
 
37
- const wrapper = (props) => {
38
- props = {
39
- classes: {},
40
- graphProps: graphProps(),
41
- ...props,
42
- };
42
+ describe('root', () => {
43
+ let mockOn;
44
+ let defaultProps;
43
45
 
44
- return shallow(<Root {...props}>hi</Root>, { disableLifecycleMethods: true });
45
- };
46
+ beforeEach(() => {
47
+ mockOn = jest.fn();
48
+ select.mockReturnValue({
49
+ on: mockOn,
50
+ });
51
+ mouse.mockReturnValue([0, 0]);
46
52
 
47
- jest.mock('d3-selection', () => ({
48
- select: jest.fn(),
49
- mouse: jest.fn(),
50
- }));
53
+ defaultProps = {
54
+ classes: {},
55
+ graphProps: graphProps(),
56
+ };
57
+ });
51
58
 
52
- describe('root', () => {
53
- describe('snapshot', () => {
54
- it('matches', () => {
55
- const w = wrapper();
56
- expect(w).toMatchSnapshot();
57
- });
59
+ afterEach(() => {
60
+ cleanup();
61
+ jest.clearAllMocks();
62
+ });
63
+
64
+ it('renders with children', () => {
65
+ const { container, getByText } = render(
66
+ <Root {...defaultProps}>hi</Root>
67
+ );
68
+ expect(container.firstChild).toBeInTheDocument();
69
+ expect(getByText('hi')).toBeInTheDocument();
58
70
  });
59
71
 
60
72
  describe('logic', () => {
61
73
  describe('mousemove', () => {
62
74
  describe('mount/unmount', () => {
63
- it('adds mousemove listener on compenentDidMount', () => {
64
- const w = wrapper();
65
- const g = {
66
- on: jest.fn(),
67
- };
68
- select.mockReturnValue(g);
69
- w.instance().componentDidMount();
70
- expect(g.on).toHaveBeenCalledWith('mousemove', expect.any(Function));
75
+ it('adds mousemove listener on componentDidMount', () => {
76
+ render(<Root {...defaultProps}>hi</Root>);
77
+
78
+ // Verify that select was called with the g element
79
+ expect(select).toHaveBeenCalled();
80
+
81
+ // Verify that on() was called with 'mousemove' and a function
82
+ expect(mockOn).toHaveBeenCalledWith('mousemove', expect.any(Function));
71
83
  });
72
- it('unsets mousemove listener on componentWillUnmount', () => {
73
- const w = wrapper();
74
- const g = {
75
- on: jest.fn(),
76
- };
77
- select.mockReturnValue(g);
78
- w.instance().componentWillUnmount();
79
- expect(g.on).toHaveBeenCalledWith('mousemove', null);
84
+
85
+ it('removes mousemove listener on componentWillUnmount', () => {
86
+ const { unmount } = render(<Root {...defaultProps}>hi</Root>);
87
+
88
+ // Clear previous calls to isolate unmount behavior
89
+ mockOn.mockClear();
90
+ select.mockClear();
91
+
92
+ unmount();
93
+
94
+ // Verify that select was called during unmount
95
+ expect(select).toHaveBeenCalled();
96
+
97
+ // Verify that on() was called with 'mousemove' and null to remove the listener
98
+ expect(mockOn).toHaveBeenCalledWith('mousemove', null);
80
99
  });
81
100
  });
82
101
 
83
102
  describe('mouseMove function', () => {
84
- let onMouseMove, w, gp;
85
- beforeEach(() => {
86
- onMouseMove = jest.fn();
87
- gp = graphProps();
88
- w = wrapper({
103
+ it('calls mouse with correct arguments', () => {
104
+ const onMouseMove = jest.fn();
105
+ const gp = graphProps();
106
+ const props = {
107
+ ...defaultProps,
89
108
  onMouseMove,
90
109
  graphProps: gp,
110
+ };
111
+
112
+ const mockNode = document.createElement('div');
113
+ const mockSelection = {
114
+ _groups: [[mockNode]],
115
+ node: () => mockNode,
116
+ };
117
+
118
+ // Mock select to return our mockSelection
119
+ select.mockReturnValue({
120
+ ...mockSelection,
121
+ on: (event, handler) => {
122
+ mockOn(event, handler);
123
+ // When 'mousemove' is registered, immediately test it
124
+ if (event === 'mousemove' && handler) {
125
+ mouse.mockReturnValue([10, 20]);
126
+ // Handler is bound with mockSelection as first arg, so call with no args
127
+ handler();
128
+ }
129
+ },
91
130
  });
92
- mouse.mockReturnValue([0, 0]);
93
- const g = { _groups: [[[0, 0]]] };
94
- w.instance().mouseMove(g);
95
- });
96
- it('calls mouse', () => {
97
- expect(mouse).toHaveBeenCalledWith([0, 0]);
98
- });
99
- it('calls, scale.x.invert', () => {
100
- expect(gp.scale.x.invert).toHaveBeenCalledWith(0);
131
+
132
+ render(<Root {...props}>hi</Root>);
133
+
134
+ // Verify mouse was called with the correct node
135
+ expect(mouse).toHaveBeenCalledWith(mockNode);
101
136
  });
102
- it('calls, scale.y.invert', () => {
103
- expect(gp.scale.y.invert).toHaveBeenCalledWith(0);
137
+
138
+ it('calls scale.x.invert and scale.y.invert', () => {
139
+ const onMouseMove = jest.fn();
140
+ const gp = graphProps();
141
+ const props = {
142
+ ...defaultProps,
143
+ onMouseMove,
144
+ graphProps: gp,
145
+ };
146
+
147
+ const mockNode = document.createElement('div');
148
+ const mockSelection = {
149
+ _groups: [[mockNode]],
150
+ node: () => mockNode,
151
+ };
152
+
153
+ select.mockReturnValue({
154
+ ...mockSelection,
155
+ on: (event, handler) => {
156
+ mockOn(event, handler);
157
+ if (event === 'mousemove' && handler) {
158
+ mouse.mockReturnValue([15, 25]);
159
+ handler();
160
+ }
161
+ },
162
+ });
163
+
164
+ render(<Root {...props}>hi</Root>);
165
+
166
+ expect(gp.scale.x.invert).toHaveBeenCalledWith(15);
167
+ expect(gp.scale.y.invert).toHaveBeenCalledWith(25);
104
168
  });
105
- it('calls, snap.x', () => {
106
- expect(gp.snap.x).toHaveBeenCalledWith(0);
169
+
170
+ it('calls snap.x and snap.y with inverted coordinates', () => {
171
+ const onMouseMove = jest.fn();
172
+ const gp = graphProps();
173
+ gp.scale.x.invert = jest.fn().mockReturnValue(5);
174
+ gp.scale.y.invert = jest.fn().mockReturnValue(10);
175
+ const props = {
176
+ ...defaultProps,
177
+ onMouseMove,
178
+ graphProps: gp,
179
+ };
180
+
181
+ const mockNode = document.createElement('div');
182
+ const mockSelection = {
183
+ _groups: [[mockNode]],
184
+ node: () => mockNode,
185
+ };
186
+
187
+ select.mockReturnValue({
188
+ ...mockSelection,
189
+ on: (event, handler) => {
190
+ mockOn(event, handler);
191
+ if (event === 'mousemove' && handler) {
192
+ mouse.mockReturnValue([15, 25]);
193
+ handler();
194
+ }
195
+ },
196
+ });
197
+
198
+ render(<Root {...props}>hi</Root>);
199
+
200
+ expect(gp.snap.x).toHaveBeenCalledWith(5);
201
+ expect(gp.snap.y).toHaveBeenCalledWith(10);
107
202
  });
108
- it('calls, snap.y', () => {
109
- expect(gp.snap.y).toHaveBeenCalledWith(0);
203
+
204
+ it('calls onMouseMove handler with snapped coordinates', () => {
205
+ const onMouseMove = jest.fn();
206
+ const gp = graphProps();
207
+ gp.scale.x.invert = jest.fn().mockReturnValue(7);
208
+ gp.scale.y.invert = jest.fn().mockReturnValue(14);
209
+ gp.snap.x = jest.fn().mockReturnValue(10);
210
+ gp.snap.y = jest.fn().mockReturnValue(15);
211
+
212
+ const props = {
213
+ ...defaultProps,
214
+ onMouseMove,
215
+ graphProps: gp,
216
+ };
217
+
218
+ const mockNode = document.createElement('div');
219
+ const mockSelection = {
220
+ _groups: [[mockNode]],
221
+ node: () => mockNode,
222
+ };
223
+
224
+ select.mockReturnValue({
225
+ ...mockSelection,
226
+ on: (event, handler) => {
227
+ mockOn(event, handler);
228
+ if (event === 'mousemove' && handler) {
229
+ mouse.mockReturnValue([100, 200]);
230
+ handler();
231
+ }
232
+ },
233
+ });
234
+
235
+ render(<Root {...props}>hi</Root>);
236
+
237
+ expect(onMouseMove).toHaveBeenCalledWith({ x: 10, y: 15 });
110
238
  });
111
239
 
112
- it('calls handler', () => {
113
- expect(onMouseMove).toHaveBeenCalledWith({ x: 0, y: 0 });
240
+ it('does not call onMouseMove when handler is not provided', () => {
241
+ const gp = graphProps();
242
+ const props = {
243
+ ...defaultProps,
244
+ graphProps: gp,
245
+ };
246
+
247
+ const mockNode = document.createElement('div');
248
+ const mockSelection = {
249
+ _groups: [[mockNode]],
250
+ node: () => mockNode,
251
+ };
252
+
253
+ select.mockReturnValue({
254
+ ...mockSelection,
255
+ on: (event, handler) => {
256
+ mockOn(event, handler);
257
+ if (event === 'mousemove' && handler) {
258
+ mouse.mockReturnValue([100, 200]);
259
+ // Should not throw error when onMouseMove is not provided
260
+ expect(() => handler()).not.toThrow();
261
+ }
262
+ },
263
+ });
264
+
265
+ render(<Root {...props}>hi</Root>);
266
+
267
+ // Verify scale methods were not called (early return in mouseMove)
268
+ expect(gp.scale.x.invert).not.toHaveBeenCalled();
269
+ expect(gp.scale.y.invert).not.toHaveBeenCalled();
114
270
  });
115
271
  });
116
272
  });
@@ -38,6 +38,15 @@ export const gridDraggable = (opts) => (Comp) => {
38
38
  onMove: PropTypes.func,
39
39
  graphProps: GraphPropsType.isRequired,
40
40
  };
41
+
42
+ constructor(props) {
43
+ super(props);
44
+ this.state = {
45
+ startX: null,
46
+ startY: null,
47
+ };
48
+ }
49
+
41
50
  grid = () => {
42
51
  const { graphProps } = this.props;
43
52
  const { scale, domain, range } = graphProps;
@@ -87,10 +96,10 @@ export const gridDraggable = (opts) => (Comp) => {
87
96
  const grid = this.grid();
88
97
 
89
98
  const scaled = {
90
- left: (bounds.left / grid.interval) * grid.x,
91
- right: (bounds.right / grid.interval) * grid.x,
92
- top: (bounds.top / grid.interval) * grid.y,
93
- bottom: (bounds.bottom / grid.interval) * grid.y,
99
+ left: bounds.left * grid.x,
100
+ right: bounds.right * grid.x,
101
+ top: bounds.top * grid.y,
102
+ bottom: bounds.bottom * grid.y,
94
103
  };
95
104
  log('[getScaledBounds]: ', scaled);
96
105
  return scaled;
package/src/label.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { Readable } from '@pie-lib/render-ui';
3
3
  import EditableHtml from '@pie-lib/editable-html';
4
4
  import PropTypes from 'prop-types';
@@ -64,7 +64,7 @@ const LabelComponent = (props) => {
64
64
  titleHeight,
65
65
  } = props;
66
66
 
67
- const [rotatedToHorizontal, setRotatedToHorizontal] = useState(false);
67
+ const [rotatedToHorizontal, setRotatedToHorizontal] = useState(false);
68
68
 
69
69
  const activePlugins = [
70
70
  'bold',
@@ -115,6 +115,15 @@ const LabelComponent = (props) => {
115
115
  }
116
116
  };
117
117
 
118
+ const exitEditMode = () => {
119
+ setRotatedToHorizontal(false);
120
+
121
+ // blur active element because rotation is causing editing issues on exit
122
+ requestAnimationFrame(() => {
123
+ document.activeElement?.blur?.();
124
+ });
125
+ };
126
+
118
127
  return (
119
128
  <Readable false>
120
129
  <div
@@ -155,7 +164,7 @@ const LabelComponent = (props) => {
155
164
  }}
156
165
  disableScrollbar
157
166
  activePlugins={activePlugins}
158
- onDone={() => setRotatedToHorizontal(false)}
167
+ onDone={exitEditMode}
159
168
  mathMlOptions={mathMlOptions}
160
169
  charactersLimit={charactersLimit}
161
170
  />
package/src/root.jsx CHANGED
@@ -134,7 +134,7 @@ export class Root extends React.Component {
134
134
  }
135
135
 
136
136
  const { scale, snap } = graphProps;
137
- const coords = mouse(g._groups[0][0]);
137
+ const coords = mouse(g.node());
138
138
  const x = scale.x.invert(coords[0]);
139
139
  const y = scale.y.invert(coords[1]);
140
140
 
@@ -1,185 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`gridDraggable snapshot render with decimals 1`] = `
4
- <mockConstructor
5
- axis="both"
6
- grid={
7
- Array [
8
- 1,
9
- 1,
10
- ]
11
- }
12
- onDrag={[Function]}
13
- onMouseDown={[Function]}
14
- onStart={[Function]}
15
- onStop={[Function]}
16
- >
17
- <Component
18
- domain={
19
- Object {
20
- "max": 1.6,
21
- "min": -1.5,
22
- "step": 0.3,
23
- }
24
- }
25
- graphProps={
26
- Object {
27
- "domain": Object {
28
- "max": 1,
29
- "min": 0,
30
- "step": 1,
31
- },
32
- "getRootNode": [Function],
33
- "range": Object {
34
- "max": 1,
35
- "min": 0,
36
- "step": 1,
37
- },
38
- "scale": Object {
39
- "x": [MockFunction] {
40
- "calls": Array [
41
- Array [
42
- 1,
43
- ],
44
- Array [
45
- 0,
46
- ],
47
- ],
48
- "results": Array [
49
- Object {
50
- "type": "return",
51
- "value": 1,
52
- },
53
- Object {
54
- "type": "return",
55
- "value": 0,
56
- },
57
- ],
58
- },
59
- "y": [MockFunction] {
60
- "calls": Array [
61
- Array [
62
- 1,
63
- ],
64
- Array [
65
- 0,
66
- ],
67
- ],
68
- "results": Array [
69
- Object {
70
- "type": "return",
71
- "value": 1,
72
- },
73
- Object {
74
- "type": "return",
75
- "value": 0,
76
- },
77
- ],
78
- },
79
- },
80
- "size": Object {
81
- "height": 500,
82
- "width": 500,
83
- },
84
- "snap": Object {
85
- "x": [MockFunction],
86
- "y": [MockFunction],
87
- },
88
- }
89
- }
90
- isDragging={false}
91
- range={
92
- Object {
93
- "max": 3,
94
- "min": -2,
95
- "step": 0.2,
96
- }
97
- }
98
- />
99
- </mockConstructor>
100
- `;
101
-
102
- exports[`gridDraggable snapshot reqular 1`] = `
103
- <mockConstructor
104
- axis="both"
105
- grid={
106
- Array [
107
- 1,
108
- 1,
109
- ]
110
- }
111
- onDrag={[Function]}
112
- onMouseDown={[Function]}
113
- onStart={[Function]}
114
- onStop={[Function]}
115
- >
116
- <Component
117
- graphProps={
118
- Object {
119
- "domain": Object {
120
- "max": 1,
121
- "min": 0,
122
- "step": 1,
123
- },
124
- "getRootNode": [Function],
125
- "range": Object {
126
- "max": 1,
127
- "min": 0,
128
- "step": 1,
129
- },
130
- "scale": Object {
131
- "x": [MockFunction] {
132
- "calls": Array [
133
- Array [
134
- 1,
135
- ],
136
- Array [
137
- 0,
138
- ],
139
- ],
140
- "results": Array [
141
- Object {
142
- "type": "return",
143
- "value": 1,
144
- },
145
- Object {
146
- "type": "return",
147
- "value": 0,
148
- },
149
- ],
150
- },
151
- "y": [MockFunction] {
152
- "calls": Array [
153
- Array [
154
- 1,
155
- ],
156
- Array [
157
- 0,
158
- ],
159
- ],
160
- "results": Array [
161
- Object {
162
- "type": "return",
163
- "value": 1,
164
- },
165
- Object {
166
- "type": "return",
167
- "value": 0,
168
- },
169
- ],
170
- },
171
- },
172
- "size": Object {
173
- "height": 500,
174
- "width": 500,
175
- },
176
- "snap": Object {
177
- "x": [MockFunction],
178
- "y": [MockFunction],
179
- },
180
- }
181
- }
182
- isDragging={false}
183
- />
184
- </mockConstructor>
185
- `;
@@ -1,18 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`root snapshot matches 1`] = `
4
- <div>
5
- <div>
6
- <svg
7
- height={480}
8
- width={540}
9
- >
10
- <g
11
- transform="translate(70, 40)"
12
- >
13
- hi
14
- </g>
15
- </svg>
16
- </div>
17
- </div>
18
- `;