@phun-ky/speccer 3.5.1 → 4.1.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.
@@ -0,0 +1,13 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const set = (el, attrs) => {
5
+ if (!el) return;
6
+ if (!attrs || (attrs && attrs.length === 0)) return;
7
+ Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
8
+ };
9
+ export const remove = (el, attrs) => {
10
+ if (!el) return;
11
+ if (!attrs || (attrs && attrs.length === 0)) return;
12
+ Object.keys(attrs).forEach(key => el.removeAttribute(key));
13
+ };
@@ -0,0 +1,37 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const set = (el, cls, avoid = 'noop') => {
5
+ if (!el) return;
6
+ if (!cls || (cls && cls.length === 0)) return;
7
+ cls
8
+ .trim()
9
+ .split(' ')
10
+ .filter(cl => cl !== avoid)
11
+ .forEach(cl => el.classList.add(cl));
12
+ };
13
+
14
+ export const toggle = (el, cls, avoid = 'noop') => {
15
+ if (!el) return;
16
+ if (!cls || (cls && cls.length === 0)) return;
17
+ cls
18
+ .trim()
19
+ .split(' ')
20
+ .filter(cl => cl !== avoid)
21
+ .forEach(cl => el.classList.toggle(cl));
22
+ };
23
+
24
+ export const remove = (el, cls, avoid = 'noop') => {
25
+ if (!el) return;
26
+ if (!cls || (cls && cls.length === 0)) return;
27
+ cls
28
+ .trim()
29
+ .split(' ')
30
+ .filter(cl => cl !== avoid)
31
+ .forEach(cl => el.classList.remove(cl));
32
+ };
33
+
34
+ export const cx = (cls, cls_obj) =>
35
+ `${cls} ${Object.keys(cls_obj)
36
+ .filter(classname => cls_obj[classname])
37
+ .join(' ')}`.trim();
@@ -0,0 +1,5 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const SPECCER_LITERALS = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'];
5
+ export const SPECCER_TAGS_TO_AVOID = ['TR', 'TH', 'TD', 'TBODY', 'THEAD', 'TFOOT'];
package/src/lib/css.js ADDED
@@ -0,0 +1,37 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const getNumberValue = value => parseInt(value, 10);
5
+
6
+ export const normalizeNumberValue = value => {
7
+ const _value = parseFloat(value);
8
+ return (_value >= 0 && _value < 1) || (_value <= 0 && _value > -1) ? 0 : _value;
9
+ };
10
+
11
+ export const getSpacing = style => {
12
+ const { marginTop, marginBottom, marginLeft, marginRight, paddingTop, paddingBottom, paddingLeft, paddingRight } =
13
+ style;
14
+ return {
15
+ marginTop,
16
+ marginBottom,
17
+ marginLeft,
18
+ marginRight,
19
+ paddingTop,
20
+ paddingBottom,
21
+ paddingLeft,
22
+ paddingRight
23
+ };
24
+ };
25
+
26
+ export const getTypography = style => {
27
+ const { lineHeight, letterSpacing, fontFamily, fontSize, fontStyle, fontVariationSettings, fontWeight } = style;
28
+ return {
29
+ lineHeight,
30
+ letterSpacing,
31
+ fontFamily,
32
+ fontSize,
33
+ fontStyle,
34
+ fontVariationSettings,
35
+ fontWeight
36
+ };
37
+ };
@@ -0,0 +1,22 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const waitForFrame = () => new Promise(requestAnimationFrame);
5
+
6
+ const debounce = function (func, wait, immediate) {
7
+ var timeout;
8
+ return function () {
9
+ var context = this,
10
+ args = arguments;
11
+ var later = function () {
12
+ timeout = null;
13
+ if (!immediate) func.apply(context, args);
14
+ };
15
+ var callNow = immediate && !timeout;
16
+ clearTimeout(timeout);
17
+ timeout = setTimeout(later, wait);
18
+ if (callNow) func.apply(context, args);
19
+ };
20
+ };
21
+
22
+ export default debounce;
@@ -0,0 +1,7 @@
1
+ export const after = (el, newSibling) => el.insertAdjacentElement('afterend', newSibling);
2
+
3
+ export const removeAll = (selector, el = document) => {
4
+ [].forEach.call(el.querySelectorAll(selector), function (e) {
5
+ e.remove();
6
+ });
7
+ };
@@ -0,0 +1,4 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ export const to3Decimals = number => parseFloat(number).toFixed(3);
@@ -0,0 +1,13 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ import debounce from './debounce';
5
+
6
+ export const activate = speccer => {
7
+ const speccerEventFunc = debounce(() => {
8
+ speccer();
9
+ }, 300);
10
+
11
+ window.removeEventListener('resize', speccerEventFunc);
12
+ window.addEventListener('resize', speccerEventFunc);
13
+ };
@@ -0,0 +1,27 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+ import { waitForFrame } from './debounce';
4
+
5
+ export const add = async (el, styles) => {
6
+ if (!el) return;
7
+ if (
8
+ !styles ||
9
+ (styles && styles.length === 0 && styles.constructor === String) ||
10
+ (styles && styles.length === 0 && styles.constructor === Array) ||
11
+ (styles && Object.keys(styles).length === 0 && styles.constructor === Object)
12
+ ) {
13
+ return;
14
+ }
15
+
16
+ await waitForFrame();
17
+ if (typeof styles === 'string' || Array.isArray(styles)) {
18
+ styles.forEach(style => (el.style[style.key] = style.value));
19
+ } else {
20
+ Object.keys(styles).forEach(key => (el.style[key] = styles[key]));
21
+ }
22
+ };
23
+
24
+ export const get = async el => {
25
+ await waitForFrame();
26
+ return window.getComputedStyle ? getComputedStyle(el, null) : el.currentStyle;
27
+ };
package/src/measure.js ADDED
@@ -0,0 +1,88 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ import * as classnames from './lib/classnames';
5
+ import * as styles from './lib/styles';
6
+ import * as node from './lib/node';
7
+
8
+ import { SPECCER_TAGS_TO_AVOID } from './lib/constants';
9
+
10
+ const create = (text = '', area = '', tag = 'span') => {
11
+ const _el = document.createElement(tag);
12
+ _el.setAttribute('title', text + 'px');
13
+ _el.setAttribute('data-measure', parseInt(text, 10) + 'px');
14
+
15
+ classnames.set(_el, `ph speccer measure ${area}`);
16
+
17
+ return _el;
18
+ };
19
+
20
+ export const element = el => {
21
+ if (!el) return;
22
+
23
+ const _el_rect = el.getBoundingClientRect();
24
+ const _area = el.getAttribute('data-speccer-measure');
25
+
26
+ if (_area === '') {
27
+ return;
28
+ }
29
+
30
+ const _el_offset_top = el.offsetTop;
31
+ const _el_offset_left = el.offsetLeft;
32
+
33
+ if (_area.indexOf('width') !== -1) {
34
+ if (_area.indexOf('bottom') !== -1) {
35
+ const _measure_node = create(_el_rect.width, 'width bottom');
36
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
37
+ node.after(el.closest('table'), _measure_node);
38
+ } else {
39
+ node.after(el, _measure_node);
40
+ }
41
+ styles.add(_measure_node, {
42
+ left: _el_offset_left + 'px',
43
+ top: _el_offset_top + _el_rect.height + 1 + 'px',
44
+ width: _el_rect.width + 'px'
45
+ });
46
+ } else {
47
+ const _measure_node = create(_el_rect.width, 'width top');
48
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
49
+ node.after(el.closest('table'), _measure_node);
50
+ } else {
51
+ node.after(el, _measure_node);
52
+ }
53
+ const _measure_node_rect = _measure_node.getBoundingClientRect();
54
+ styles.add(_measure_node, {
55
+ left: _el_offset_left + 'px',
56
+ top: _el_offset_top - _measure_node_rect.height + 1 + 'px',
57
+ width: _el_rect.width + 'px'
58
+ });
59
+ }
60
+ } else if (_area.indexOf('height') !== -1) {
61
+ if (_area.indexOf('right') !== -1) {
62
+ const _measure_node = create(_el_rect.height, 'height right');
63
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
64
+ node.after(el.closest('table'), _measure_node);
65
+ } else {
66
+ node.after(el, _measure_node);
67
+ }
68
+ styles.add(_measure_node, {
69
+ left: _el_offset_left + _el_rect.width + 'px',
70
+ top: _el_offset_top + 'px',
71
+ height: _el_rect.height + 'px'
72
+ });
73
+ } else {
74
+ const _measure_node = create(_el_rect.height, 'height top');
75
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
76
+ node.after(el.closest('table'), _measure_node);
77
+ } else {
78
+ node.after(el, _measure_node);
79
+ }
80
+ const _measure_node_rect = _measure_node.getBoundingClientRect();
81
+ styles.add(_measure_node, {
82
+ left: _el_offset_left - _measure_node_rect.width + 'px',
83
+ top: _el_offset_top + 'px',
84
+ height: _el_rect.height + 'px'
85
+ });
86
+ }
87
+ }
88
+ };
package/src/spec.js ADDED
@@ -0,0 +1,183 @@
1
+ /* eslint no-console:0 */
2
+ 'use strict';
3
+
4
+ import * as classnames from './lib/classnames';
5
+ import * as css from './lib/css';
6
+ import * as node from './lib/node';
7
+ import * as styles from './lib/styles';
8
+ import { SPECCER_TAGS_TO_AVOID } from './lib/constants';
9
+
10
+ export const create = (text = '', tag = 'span') => {
11
+ const _el = document.createElement(tag);
12
+ const textContent = document.createTextNode(text);
13
+ _el.appendChild(textContent);
14
+ _el.setAttribute('title', text + 'px');
15
+ classnames.set(_el, 'ph speccer spacing');
16
+ return _el;
17
+ };
18
+
19
+ export const element = async el => {
20
+ const _speccer_el = {};
21
+ const _el_style = await styles.get(el);
22
+ if (_el_style.display === 'none' || _el_style.visibility === 'hidden') {
23
+ return;
24
+ }
25
+ el.classList.add('is-specced');
26
+ const _parent_el_style = styles.get(el.parentElement);
27
+ if (_parent_el_style.position === 'static') {
28
+ window.requestAnimationFrame(() => {
29
+ el.parentElement.style.position = 'relative';
30
+ });
31
+ }
32
+ _speccer_el.styles = css.getSpacing(_el_style);
33
+ _speccer_el.rect = el.getBoundingClientRect();
34
+ if (_speccer_el.styles['marginTop'] !== '0px') {
35
+ const _speccer_margin_top_el = create(css.getNumberValue(_speccer_el.styles.marginTop));
36
+ classnames.set(_speccer_margin_top_el, 'margin top');
37
+ styles.add(_speccer_margin_top_el, {
38
+ height: _speccer_el.styles.marginTop,
39
+ width: _speccer_el.rect.width + 'px',
40
+ left: css.normalizeNumberValue(_speccer_el.rect.x - el.parentElement.getBoundingClientRect().x) + 'px',
41
+ top:
42
+ css.normalizeNumberValue(
43
+ _speccer_el.rect.y - el.parentElement.getBoundingClientRect().y - parseInt(_speccer_el.styles.marginTop, 10)
44
+ ) + 'px'
45
+ });
46
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
47
+ node.after(el.closest('table'), _speccer_margin_top_el);
48
+ } else {
49
+ node.after(el, _speccer_margin_top_el);
50
+ }
51
+ }
52
+ if (_speccer_el.styles['marginRight'] !== '0px') {
53
+ const _speccer_margin_right_el = create(css.getNumberValue(_speccer_el.styles.marginRight));
54
+ classnames.set(_speccer_margin_right_el, 'margin right');
55
+
56
+ styles.add(_speccer_margin_right_el, {
57
+ height: _speccer_el.rect.height + 'px',
58
+ width: _speccer_el.styles.marginRight,
59
+ left:
60
+ css.normalizeNumberValue(
61
+ _speccer_el.rect.x - el.parentElement.getBoundingClientRect().x + parseInt(_speccer_el.rect.width, 10)
62
+ ) + 'px',
63
+ top: css.normalizeNumberValue(_speccer_el.rect.y - el.parentElement.getBoundingClientRect().y) + 'px'
64
+ });
65
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
66
+ node.after(el.closest('table'), _speccer_margin_right_el);
67
+ } else {
68
+ node.after(el, _speccer_margin_right_el);
69
+ }
70
+ }
71
+ if (_speccer_el.styles['marginBottom'] !== '0px') {
72
+ const _speccer_margin_bottom_el = create(css.getNumberValue(_speccer_el.styles.marginBottom));
73
+ classnames.set(_speccer_margin_bottom_el, 'margin bottom');
74
+
75
+ styles.add(_speccer_margin_bottom_el, {
76
+ height: _speccer_el.styles.marginBottom,
77
+ width: _speccer_el.rect.width + 'px',
78
+ left: css.normalizeNumberValue(_speccer_el.rect.x - el.parentElement.getBoundingClientRect().x) + 'px',
79
+ top:
80
+ css.normalizeNumberValue(
81
+ _speccer_el.rect.y - el.parentElement.getBoundingClientRect().y + parseInt(_speccer_el.rect.height, 10)
82
+ ) + 'px'
83
+ });
84
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
85
+ node.after(el.closest('table'), _speccer_margin_bottom_el);
86
+ } else {
87
+ node.after(el, _speccer_margin_bottom_el);
88
+ }
89
+ }
90
+ if (_speccer_el.styles['marginLeft'] !== '0px') {
91
+ const _speccer_margin_left_el = create(css.getNumberValue(_speccer_el.styles.marginLeft));
92
+ classnames.set(_speccer_margin_left_el, 'margin left');
93
+
94
+ styles.add(_speccer_margin_left_el, {
95
+ height: _speccer_el.rect.height + 'px',
96
+ width: _speccer_el.styles.marginLeft,
97
+ left:
98
+ css.normalizeNumberValue(
99
+ _speccer_el.rect.x - el.parentElement.getBoundingClientRect().x - parseInt(_speccer_el.styles.marginLeft, 10)
100
+ ) + 'px',
101
+ top: css.normalizeNumberValue(_speccer_el.rect.y - el.parentElement.getBoundingClientRect().y) + 'px'
102
+ });
103
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
104
+ node.after(el.closest('table'), _speccer_margin_left_el);
105
+ } else {
106
+ node.after(el, _speccer_margin_left_el);
107
+ }
108
+ }
109
+ if (_speccer_el.styles['paddingTop'] !== '0px') {
110
+ const _speccer_padding_top_el = create(css.getNumberValue(_speccer_el.styles.paddingTop));
111
+ classnames.set(_speccer_padding_top_el, 'padding top');
112
+
113
+ styles.add(_speccer_padding_top_el, {
114
+ height: _speccer_el.styles.paddingTop,
115
+ width: _speccer_el.rect.width + 'px',
116
+ left: css.normalizeNumberValue(_speccer_el.rect.x - el.parentElement.getBoundingClientRect().x) + 'px',
117
+ top: css.normalizeNumberValue(_speccer_el.rect.y - el.parentElement.getBoundingClientRect().y) + 'px'
118
+ });
119
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
120
+ node.after(el.closest('table'), _speccer_padding_top_el);
121
+ } else {
122
+ node.after(el, _speccer_padding_top_el);
123
+ }
124
+ }
125
+ if (_speccer_el.styles['paddingBottom'] !== '0px') {
126
+ const _speccer_padding_bottom_el = create(css.getNumberValue(_speccer_el.styles.paddingBottom));
127
+ classnames.set(_speccer_padding_bottom_el, 'padding bottom');
128
+
129
+ styles.add(_speccer_padding_bottom_el, {
130
+ height: _speccer_el.styles.paddingBottom,
131
+ width: _speccer_el.rect.width + 'px',
132
+ left: css.normalizeNumberValue(_speccer_el.rect.x - el.parentElement.getBoundingClientRect().x) + 'px',
133
+ top:
134
+ css.normalizeNumberValue(
135
+ _speccer_el.rect.y -
136
+ el.parentElement.getBoundingClientRect().y +
137
+ (parseInt(_speccer_el.rect.height, 10) - parseInt(_speccer_el.styles.paddingBottom, 10))
138
+ ) + 'px'
139
+ });
140
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
141
+ node.after(el.closest('table'), _speccer_padding_bottom_el);
142
+ } else {
143
+ node.after(el, _speccer_padding_bottom_el);
144
+ }
145
+ }
146
+ if (_speccer_el.styles['paddingRight'] !== '0px') {
147
+ const _speccer_padding_right_el = create(css.getNumberValue(_speccer_el.styles.paddingRight));
148
+ classnames.set(_speccer_padding_right_el, 'padding right');
149
+
150
+ styles.add(_speccer_padding_right_el, {
151
+ height: _speccer_el.rect.height + 'px',
152
+ width: _speccer_el.styles.paddingRight,
153
+ left:
154
+ css.normalizeNumberValue(
155
+ _speccer_el.rect.x -
156
+ el.parentElement.getBoundingClientRect().x +
157
+ (parseInt(_speccer_el.rect.width, 10) - parseInt(_speccer_el.styles.paddingRight, 10))
158
+ ) + 'px',
159
+ top: css.normalizeNumberValue(_speccer_el.rect.y - el.parentElement.getBoundingClientRect().y) + 'px'
160
+ });
161
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
162
+ node.after(el.closest('table'), _speccer_padding_right_el);
163
+ } else {
164
+ node.after(el, _speccer_padding_right_el);
165
+ }
166
+ }
167
+ if (_speccer_el.styles['paddingLeft'] !== '0px') {
168
+ const _speccer_padding_left_el = create(css.getNumberValue(_speccer_el.styles.paddingLeft));
169
+ classnames.set(_speccer_padding_left_el, 'padding left');
170
+
171
+ styles.add(_speccer_padding_left_el, {
172
+ height: _speccer_el.rect.height + 'px',
173
+ width: _speccer_el.styles.paddingLeft,
174
+ left: css.normalizeNumberValue(_speccer_el.rect.x - el.parentElement.getBoundingClientRect().x) + 'px',
175
+ top: css.normalizeNumberValue(_speccer_el.rect.y - el.parentElement.getBoundingClientRect().y) + 'px'
176
+ });
177
+ if (SPECCER_TAGS_TO_AVOID.indexOf(el.nodeName) >= 0) {
178
+ node.after(el.closest('table'), _speccer_padding_left_el);
179
+ } else {
180
+ node.after(el, _speccer_padding_left_el);
181
+ }
182
+ }
183
+ };