@pie-lib/tools 0.9.36 → 0.10.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.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [0.9.36](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.35...@pie-lib/tools@0.9.36) (2023-06-24)
6
+ # [0.10.0-beta.1](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.36...@pie-lib/tools@0.10.0-beta.1) (2025-07-20)
7
7
 
8
8
  **Note:** Version bump only for package @pie-lib/tools
9
9
 
@@ -11,7 +11,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
11
11
 
12
12
 
13
13
 
14
- ## [0.9.35](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.34...@pie-lib/tools@0.9.35) (2023-01-31)
14
+ # [0.10.0-beta.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.36...@pie-lib/tools@0.10.0-beta.0) (2025-07-20)
15
15
 
16
16
  **Note:** Version bump only for package @pie-lib/tools
17
17
 
@@ -19,62 +19,50 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
19
19
 
20
20
 
21
21
 
22
- ## [0.9.34](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.33...@pie-lib/tools@0.9.34) (2023-01-31)
22
+ # [0.11.0-beta.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.36...@pie-lib/tools@0.11.0-beta.0) (2025-07-15)
23
23
 
24
24
  **Note:** Version bump only for package @pie-lib/tools
25
25
 
26
+ # [0.10.0-beta.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.36...@pie-lib/tools@0.10.0-beta.0) (2025-07-15)
26
27
 
28
+ **Note:** Version bump only for package @pie-lib/tools
27
29
 
30
+ ## [0.9.36](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.35...@pie-lib/tools@0.9.36) (2023-06-24)
28
31
 
32
+ **Note:** Version bump only for package @pie-lib/tools
29
33
 
30
- ## [0.9.33](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.32...@pie-lib/tools@0.9.33) (2023-01-31)
34
+ ## [0.9.35](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.34...@pie-lib/tools@0.9.35) (2023-01-31)
31
35
 
32
36
  **Note:** Version bump only for package @pie-lib/tools
33
37
 
38
+ ## [0.9.34](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.33...@pie-lib/tools@0.9.34) (2023-01-31)
34
39
 
40
+ **Note:** Version bump only for package @pie-lib/tools
35
41
 
42
+ ## [0.9.33](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.32...@pie-lib/tools@0.9.33) (2023-01-31)
36
43
 
44
+ **Note:** Version bump only for package @pie-lib/tools
37
45
 
38
46
  ## [0.9.32](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.31...@pie-lib/tools@0.9.32) (2023-01-31)
39
47
 
40
48
  **Note:** Version bump only for package @pie-lib/tools
41
49
 
42
-
43
-
44
-
45
-
46
50
  ## [0.9.31](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.29...@pie-lib/tools@0.9.31) (2023-01-31)
47
51
 
48
52
  **Note:** Version bump only for package @pie-lib/tools
49
53
 
50
-
51
-
52
-
53
-
54
54
  ## [0.9.29](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.27...@pie-lib/tools@0.9.29) (2023-01-31)
55
55
 
56
56
  **Note:** Version bump only for package @pie-lib/tools
57
57
 
58
-
59
-
60
-
61
-
62
58
  ## [0.9.27](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.25...@pie-lib/tools@0.9.27) (2023-01-31)
63
59
 
64
60
  **Note:** Version bump only for package @pie-lib/tools
65
61
 
66
-
67
-
68
-
69
-
70
62
  ## [0.9.25](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.24...@pie-lib/tools@0.9.25) (2022-11-23)
71
63
 
72
64
  **Note:** Version bump only for package @pie-lib/tools
73
65
 
74
-
75
-
76
-
77
-
78
66
  ## [0.9.24](https://github.com/pie-framework/pie-lib/compare/@pie-lib/tools@0.9.22...@pie-lib/tools@0.9.24) (2021-06-25)
79
67
 
80
68
  **Note:** Version bump only for package @pie-lib/tools
@@ -0,0 +1 @@
1
+ []
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA","sourcesContent":["import Protractor from './protractor';\nimport Ruler from './ruler';\nimport Rotatable from './rotatable';\nimport * as utils from './anchor-utils';\nexport { Protractor, Ruler, Rotatable, utils };\n"],"file":"index.js"}
1
+ {"version":3,"sources":["../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA","sourcesContent":["import Protractor from './protractor';\nimport Ruler from './ruler';\nimport Rotatable from './rotatable';\nimport * as utils from './anchor-utils';\n\nexport { Protractor, Ruler, Rotatable, utils };\n"],"file":"index.js"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.9.36",
6
+ "version": "0.10.0-beta.1",
7
7
  "description": "Some interactive tools",
8
8
  "keywords": [
9
9
  "react",
@@ -18,12 +18,13 @@
18
18
  "license": "ISC",
19
19
  "dependencies": {
20
20
  "@mapbox/point-geometry": "^0.1.0",
21
- "@pie-lib/style-utils": "^0.1.43",
21
+ "@pie-lib/style-utils": "latest",
22
22
  "assert": "^1.4.1",
23
23
  "classnames": "^2.2.6",
24
24
  "debug": "^4.1.1",
25
25
  "invariant": "^2.2.4",
26
26
  "lodash": "^4.17.11",
27
+ "prop-types": "^15.7.2",
27
28
  "react-portal": "^4.2.0",
28
29
  "trigonometry-calculator": "^2.0.0"
29
30
  },
@@ -36,5 +37,5 @@
36
37
  "@material-ui/core": "^3.8.3",
37
38
  "react": "^16.8.1"
38
39
  },
39
- "gitHead": "4043c98430c000ce3a25357d92845175b076ea21"
40
+ "gitHead": "e2aa3ddac60f49bcb8c2562370f496323642f453"
40
41
  }
@@ -0,0 +1,37 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`rotatable snapshot renders 1`] = `
4
+ <div
5
+ className=""
6
+ onMouseDown={[Function]}
7
+ onMouseUp={[Function]}
8
+ style={
9
+ Object {
10
+ "left": 0,
11
+ "top": 0,
12
+ "transform": " rotate(0deg)",
13
+ "transformOrigin": undefined,
14
+ }
15
+ }
16
+ >
17
+ foo
18
+ </div>
19
+ `;
20
+
21
+ exports[`rotatable snapshot renders with transforms 1`] = `
22
+ <div
23
+ className=""
24
+ onMouseDown={[Function]}
25
+ onMouseUp={[Function]}
26
+ style={
27
+ Object {
28
+ "left": 0,
29
+ "top": 0,
30
+ "transform": "translate(10px, 10px) rotate(10deg)",
31
+ "transformOrigin": "bottom left",
32
+ }
33
+ }
34
+ >
35
+ foo
36
+ </div>
37
+ `;
@@ -0,0 +1,131 @@
1
+ import { getAnchor, normalizeAngle, getAngleAndHypotenuse, getTranslateXY } from '../anchor-utils';
2
+
3
+ const o = (strings, ...exp) => {
4
+ return strings.reduce((acc, v, index) => {
5
+ const e = exp[index];
6
+ const s = typeof e === 'object' ? JSON.stringify(e) : e;
7
+ return `${acc}${v}${s || ''}`;
8
+ }, '');
9
+ };
10
+
11
+ const rect = { width: 100, height: 100 };
12
+
13
+ describe('getAngleAndHypotenuse', () => {
14
+ const assert = (corner, rect, point, expected) => {
15
+ it(o`${corner}, ${rect}, ${point} => ${expected}`, () => {
16
+ const result = getAngleAndHypotenuse(corner, rect, point);
17
+ expect(result).toMatchObject(expected);
18
+ });
19
+ };
20
+ assert('top-left', rect, { x: 50, y: 50 }, { degrees: -45 });
21
+ assert('bottom-left', rect, { x: 50, y: 50 }, { degrees: -135 });
22
+ assert('top-right', rect, { x: 50, y: 50 }, { degrees: 45 });
23
+ assert('bottom-right', rect, { x: 50, y: 50 }, { degrees: 135 });
24
+ });
25
+
26
+ describe('getAnchor', () => {
27
+ describe('rect', () => {
28
+ it('does this: ', () => {
29
+ const result = getAnchor(
30
+ {
31
+ width: 400,
32
+ height: 100,
33
+ },
34
+ { x: 0, y: 100 },
35
+ 0,
36
+ );
37
+ expect(result.top).not.toBeUndefined();
38
+ expect(result.left).not.toBeUndefined();
39
+ });
40
+ });
41
+ describe('square', () => {
42
+ it('square @ 45', () => {
43
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 45);
44
+ expect(result.top).toBeCloseTo(70.71);
45
+ expect(result.left).toBeCloseTo(70.71);
46
+ });
47
+ it('square @ 90', () => {
48
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 90);
49
+ expect(result.top).toBeCloseTo(50);
50
+ expect(result.left).toBeCloseTo(50);
51
+ });
52
+
53
+ it('square @ 180', () => {
54
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 180);
55
+ expect(result.top).toBeCloseTo(50);
56
+ expect(result.left).toBeCloseTo(50);
57
+ });
58
+
59
+ it('square @ 270', () => {
60
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 180);
61
+ expect(result.top).toBeCloseTo(50);
62
+ expect(result.left).toBeCloseTo(50);
63
+ });
64
+
65
+ it('square @ -45 - bottom right anchor', () => {
66
+ const result = getAnchor({ width: 100, height: 100 }, { x: 100, y: 100 }, -45);
67
+ expect(result.left).toBeCloseTo(141.42);
68
+ expect(result.top).toBeCloseTo(70.71);
69
+ });
70
+
71
+ it('square @ 45 - bottom right anchor', () => {
72
+ const result = getAnchor({ width: 100, height: 100 }, { x: 100, y: 100 }, 45);
73
+ expect(result.top).toBeCloseTo(141.42);
74
+ expect(result.left).toBeCloseTo(70.71);
75
+ });
76
+
77
+ it('square @ 20 - bottom right anchor', () => {
78
+ const result = getAnchor({ width: 100, height: 100 }, { x: 100, y: 100 }, 20);
79
+
80
+ expect(result.top).toBeCloseTo(128.17);
81
+ expect(result.left).toBeCloseTo(93.969);
82
+ });
83
+
84
+ it('square @ 45, shifted center', () => {
85
+ const result = getAnchor({ width: 100, height: 100 }, { x: 25, y: 25 }, 45);
86
+ expect(result.top).toBeCloseTo(35.36);
87
+ expect(result.left).toBeCloseTo(70.71);
88
+ });
89
+
90
+ it('square @ 20, shifted center', () => {
91
+ const result = getAnchor({ width: 100, height: 100 }, { x: 25, y: 25 }, 20);
92
+ expect(result.top).toBeCloseTo(32.04);
93
+ expect(result.left).toBeCloseTo(49.14);
94
+ });
95
+
96
+ it('square @ 20', () => {
97
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 20);
98
+ expect(result.top).toBeCloseTo(64.085);
99
+ expect(result.left).toBeCloseTo(64.085);
100
+ });
101
+
102
+ it('square @ 135', () => {
103
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 135);
104
+ expect(result.top).toBeCloseTo(70.71);
105
+ expect(result.left).toBeCloseTo(70.71);
106
+ });
107
+ it('square @ 225', () => {
108
+ const result = getAnchor({ width: 100, height: 100 }, { x: 50, y: 50 }, 135);
109
+ expect(result.top).toBeCloseTo(70.71);
110
+ expect(result.left).toBeCloseTo(70.71);
111
+ });
112
+ });
113
+ });
114
+
115
+ describe('normalizeAngle', () => {
116
+ const assert = (a, expected) => {
117
+ it(`${a} -> ${expected}`, () => {
118
+ expect(normalizeAngle(a)).toEqual(expected);
119
+ });
120
+ };
121
+
122
+ assert(360, 360);
123
+ assert(0, 0);
124
+ assert(10, 10);
125
+ assert(361, 1);
126
+ assert(450, 90);
127
+ assert(721, 1);
128
+ assert(-1, 359);
129
+ assert(-361, 359);
130
+ assert(-721, 359);
131
+ });
@@ -0,0 +1,220 @@
1
+ import toJson from 'enzyme-to-json';
2
+ import { shallow } from 'enzyme';
3
+ import { Rotatable } from '../rotatable';
4
+ import React from 'react';
5
+ /** Note: we use the test renderer because we need to make use of ref mocking. */
6
+ import TestRenderer from 'react-test-renderer'; // ES6
7
+ import { distanceBetween } from '../anchor-utils';
8
+
9
+ import Point from '@mapbox/point-geometry';
10
+
11
+ jest.mock('../anchor-utils', () => ({
12
+ distanceBetween: jest.fn(() => ({ x: 2, y: 2 })),
13
+ toPoint: jest.fn(() => ({ x: 0, y: 0 })),
14
+ getAnchor: jest.fn(() => ({ left: 0, top: 0 })),
15
+ toDegrees: jest.fn(() => 90),
16
+ arctangent: jest.fn(() => 90),
17
+ }));
18
+
19
+ const event = (x = 0, y = 0) => ({
20
+ pageX: x,
21
+ pageY: y,
22
+ clientX: x,
23
+ clientY: y,
24
+ preventDefault: jest.fn(),
25
+ });
26
+
27
+ describe('rotatable', () => {
28
+ describe('snapshot', () => {
29
+ it('renders', () => {
30
+ const wrapper = shallow(<Rotatable classes={{}}>foo</Rotatable>);
31
+ expect(toJson(wrapper)).toMatchSnapshot();
32
+ });
33
+
34
+ it('renders with transforms', () => {
35
+ const wrapper = shallow(<Rotatable classes={{}}>foo</Rotatable>);
36
+
37
+ wrapper.setState({
38
+ translate: {
39
+ x: 10,
40
+ y: 10,
41
+ },
42
+ rotation: 10,
43
+ origin: 'bottom left',
44
+ });
45
+ expect(toJson(wrapper)).toMatchSnapshot();
46
+ });
47
+ });
48
+
49
+ describe('logic', () => {
50
+ let wrapper, el, instance;
51
+
52
+ beforeEach(() => {
53
+ el = {
54
+ addEventListener: jest.fn(),
55
+ removeEventListener: jest.fn(),
56
+ };
57
+ wrapper = TestRenderer.create(
58
+ <Rotatable handle={[{ class: 'foo', origin: 'bottom left' }]} classes={{ rotatable: 'rotatable' }}>
59
+ <div className={'foo'}>foo</div>
60
+ </Rotatable>,
61
+ {
62
+ createNodeMock: (e) => {
63
+ if (e.props.className === 'rotatable') {
64
+ return {
65
+ querySelector: jest.fn(() => el),
66
+ getBoundingClientRect: jest.fn(() => ({
67
+ left: 0,
68
+ top: 0,
69
+ width: 100,
70
+ height: 100,
71
+ })),
72
+ };
73
+ }
74
+ },
75
+ },
76
+ );
77
+
78
+ document.addEventListener = jest.fn();
79
+ document.removeEventListener = jest.fn();
80
+ instance = wrapper.root.instance;
81
+ });
82
+
83
+ describe('rotate', () => {
84
+ describe('init', () => {
85
+ it('call el.addEventListener(mousedown)', () => {
86
+ expect(el.addEventListener).toBeCalledWith('mousedown', expect.anything());
87
+ });
88
+ it('call el.addEventListener(mouseup)', () => {
89
+ expect(el.addEventListener).toBeCalledWith('mouseup', instance.rotateStop);
90
+ });
91
+ });
92
+
93
+ describe('rotateStart', () => {
94
+ let e;
95
+ beforeEach(() => {
96
+ e = event();
97
+
98
+ distanceBetween.mockReturnValue({
99
+ x: 22,
100
+ y: 4,
101
+ });
102
+ instance.state.origin = 'bottom right';
103
+
104
+ instance.state.position = {
105
+ left: 0,
106
+ top: 0,
107
+ };
108
+
109
+ instance.rotateStart('bottom left')(e);
110
+ });
111
+
112
+ it('calls event.preventDefault()', () => {
113
+ instance.rotateStart('bottom left')(e);
114
+ expect(e.preventDefault).toBeCalled();
115
+ });
116
+
117
+ it('updates the position if origin has change', () => {
118
+ expect(instance.state.position).toMatchObject({
119
+ left: 22,
120
+ top: 4,
121
+ });
122
+ });
123
+
124
+ it('updates the startAngle', () => {
125
+ expect(instance.state.startAngle).toEqual(90);
126
+ });
127
+
128
+ it('updates the anchor', () => {
129
+ expect(instance.state.anchor).toMatchObject({
130
+ left: 0,
131
+ top: 0,
132
+ });
133
+ });
134
+ });
135
+
136
+ describe('rotate', () => {
137
+ let e;
138
+ beforeEach(() => {
139
+ e = event();
140
+
141
+ instance.state.anchor = {
142
+ left: 0,
143
+ top: 0,
144
+ };
145
+
146
+ instance.state.isRotating = true;
147
+ instance.rotate(e);
148
+ });
149
+ it('calls event.preventDefault()', () => {
150
+ expect(e.preventDefault).toBeCalled();
151
+ });
152
+ });
153
+
154
+ describe('rotateStop', () => {
155
+ let e;
156
+
157
+ beforeEach(() => {
158
+ e = event();
159
+ instance.state.isRotating = true;
160
+ instance.rotateStop(e);
161
+ });
162
+
163
+ it('unsets the anchor', () => {
164
+ expect(instance.state.anchor).toEqual(null);
165
+ });
166
+ it('unsets the anchor', () => {
167
+ expect(instance.state.anchor).toEqual(null);
168
+ });
169
+ it('sets the isRotating to false', () => {
170
+ expect(instance.state.isRotating).toEqual(false);
171
+ });
172
+
173
+ it('calls document.removeEventListener(mousemove, rotate)', () => {
174
+ expect(document.removeEventListener).toBeCalledWith('mousemove', instance.rotate);
175
+ });
176
+ it('calls document.removeEventListener(mousemove), drag', () => {
177
+ expect(document.removeEventListener).toBeCalledWith('mousemove', instance.drag);
178
+ });
179
+ });
180
+ });
181
+
182
+ describe('drag', () => {
183
+ describe('mouseDown', () => {
184
+ it('calls document.addEventListener(mousemove)', () => {
185
+ instance.mouseDown(event());
186
+
187
+ expect(document.addEventListener).toBeCalledWith('mousemove', instance.drag);
188
+ });
189
+ });
190
+
191
+ describe('mouseup', () => {
192
+ it('calls document.removeEventListener(mousemove)', () => {
193
+ instance.state.translate = { x: 10, y: 10 };
194
+ instance.mouseUp({});
195
+
196
+ expect(document.removeEventListener).toBeCalledWith('mousemove', instance.drag);
197
+ });
198
+
199
+ it('updates the state', () => {
200
+ instance.state.translate = { x: 10, y: 10 };
201
+ instance.state.position = { left: 0, top: 0 };
202
+ instance.mouseUp({});
203
+
204
+ expect(instance.state.position).toEqual({
205
+ left: 10,
206
+ top: 10,
207
+ });
208
+ });
209
+ });
210
+
211
+ describe('drag', () => {
212
+ it('updates translate', () => {
213
+ instance.state.dragPoint = new Point(100, 100);
214
+ instance.drag(event(101, 101));
215
+ expect(instance.state.translate).toEqual({ x: 1, y: 1 });
216
+ });
217
+ });
218
+ });
219
+ });
220
+ });
@@ -0,0 +1,24 @@
1
+ import { parse } from '../transform-origin';
2
+
3
+ describe('transform-origin', () => {
4
+ describe('parse', () => {
5
+ const assert = (origin, expected) => {
6
+ it(`${origin} => ${JSON.stringify(expected)}`, () => {
7
+ const out = parse({ width: 100, height: 100 }, origin);
8
+ expect(out).toEqual(expected);
9
+ });
10
+ };
11
+
12
+ assert(undefined, { x: 50, y: 50 });
13
+ assert('right', { x: 100, y: 50 });
14
+ assert('20%', { x: 20, y: 50 });
15
+ assert('left', { x: 0, y: 50 });
16
+ assert('top right', { x: 100, y: 0 });
17
+ assert('right top', { x: 100, y: 0 });
18
+ assert('bottom left', { x: 0, y: 100 });
19
+ assert('left bottom', { x: 0, y: 100 });
20
+ assert('0% 100%', { x: 0, y: 100 });
21
+ assert('100% 0%', { x: 100, y: 0 });
22
+ assert('10px 43px', { x: 10, y: 43 });
23
+ });
24
+ });
package/src/index.js CHANGED
@@ -2,4 +2,5 @@ import Protractor from './protractor';
2
2
  import Ruler from './ruler';
3
3
  import Rotatable from './rotatable';
4
4
  import * as utils from './anchor-utils';
5
+
5
6
  export { Protractor, Ruler, Rotatable, utils };