primer_view_components 0.0.71 → 0.0.72
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +52 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/components/primer/alpha/{tooltip.d.ts → tool-tip-element.d.ts} +2 -3
- data/app/components/primer/alpha/{tooltip.js → tool-tip-element.js} +60 -93
- data/app/components/primer/alpha/{tooltip.ts → tool-tip-element.ts} +27 -63
- data/app/components/primer/link_component.erb +1 -4
- data/app/components/primer/primer.d.ts +1 -1
- data/app/components/primer/primer.js +1 -1
- data/app/components/primer/primer.ts +1 -1
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/rubocop/config/default.yml +3 -0
- data/lib/rubocop/cop/primer/deprecated_components.rb +80 -0
- metadata +11 -12
- data/app/components/primer/alpha/navigation_list_element.d.ts +0 -11
- data/app/components/primer/alpha/navigation_list_element.js +0 -42
@@ -1,5 +1,5 @@
|
|
1
1
|
declare type Direction = 'n' | 's' | 'e' | 'w' | 'ne' | 'se' | 'nw' | 'sw';
|
2
|
-
declare class
|
2
|
+
declare class ToolTipElement extends HTMLElement {
|
3
3
|
#private;
|
4
4
|
styles(): string;
|
5
5
|
get htmlFor(): string;
|
@@ -9,7 +9,6 @@ declare class TooltipElement extends HTMLElement {
|
|
9
9
|
get direction(): Direction;
|
10
10
|
set direction(value: Direction);
|
11
11
|
get control(): HTMLElement | null;
|
12
|
-
constructor();
|
13
12
|
connectedCallback(): void;
|
14
13
|
disconnectedCallback(): void;
|
15
14
|
handleEvent(event: Event): void;
|
@@ -18,7 +17,7 @@ declare class TooltipElement extends HTMLElement {
|
|
18
17
|
}
|
19
18
|
declare global {
|
20
19
|
interface Window {
|
21
|
-
|
20
|
+
ToolTipElement: typeof ToolTipElement;
|
22
21
|
}
|
23
22
|
}
|
24
23
|
export {};
|
@@ -9,10 +9,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
11
|
};
|
12
|
-
var
|
12
|
+
var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_update, _ToolTipElement_updatePosition;
|
13
13
|
import { getAnchoredPosition } from '@primer/behaviors';
|
14
14
|
const TOOLTIP_OPEN_CLASS = 'tooltip-open';
|
15
|
-
const TOOLTIP_ARROW_EDGE_OFFSET =
|
15
|
+
const TOOLTIP_ARROW_EDGE_OFFSET = 6;
|
16
16
|
const DIRECTION_CLASSES = [
|
17
17
|
'tooltip-n',
|
18
18
|
'tooltip-s',
|
@@ -23,21 +23,14 @@ const DIRECTION_CLASSES = [
|
|
23
23
|
'tooltip-nw',
|
24
24
|
'tooltip-sw'
|
25
25
|
];
|
26
|
-
class
|
26
|
+
class ToolTipElement extends HTMLElement {
|
27
27
|
constructor() {
|
28
|
-
super();
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
const shadow = this.attachShadow({ mode: 'open' });
|
35
|
-
shadow.innerHTML = `
|
36
|
-
<style>
|
37
|
-
${this.styles()}
|
38
|
-
</style>
|
39
|
-
<slot></slot>
|
40
|
-
`;
|
28
|
+
super(...arguments);
|
29
|
+
_ToolTipElement_instances.add(this);
|
30
|
+
_ToolTipElement_abortController.set(this, void 0);
|
31
|
+
_ToolTipElement_align.set(this, 'center');
|
32
|
+
_ToolTipElement_side.set(this, 'outside-bottom');
|
33
|
+
_ToolTipElement_allowUpdatePosition.set(this, false);
|
41
34
|
}
|
42
35
|
styles() {
|
43
36
|
return `
|
@@ -103,13 +96,13 @@ class TooltipElement extends HTMLElement {
|
|
103
96
|
:host(.tooltip-s):before,
|
104
97
|
:host(.tooltip-n):before {
|
105
98
|
right: 50%;
|
99
|
+
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
106
100
|
}
|
107
101
|
|
108
102
|
:host(.tooltip-s):before,
|
109
103
|
:host(.tooltip-se):before,
|
110
104
|
:host(.tooltip-sw):before {
|
111
105
|
bottom: 100%;
|
112
|
-
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
113
106
|
border-bottom-color: var(--color-neutral-emphasis-plus)
|
114
107
|
}
|
115
108
|
|
@@ -123,7 +116,6 @@ class TooltipElement extends HTMLElement {
|
|
123
116
|
:host(.tooltip-ne):before,
|
124
117
|
:host(.tooltip-nw):before {
|
125
118
|
top: 100%;
|
126
|
-
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
127
119
|
border-top-color: var(--color-neutral-emphasis-plus)
|
128
120
|
}
|
129
121
|
|
@@ -186,27 +178,35 @@ class TooltipElement extends HTMLElement {
|
|
186
178
|
}
|
187
179
|
connectedCallback() {
|
188
180
|
var _a;
|
181
|
+
const shadow = this.attachShadow({ mode: 'open' });
|
182
|
+
shadow.innerHTML = `
|
183
|
+
<style>
|
184
|
+
${this.styles()}
|
185
|
+
</style>
|
186
|
+
<slot></slot>
|
187
|
+
`;
|
189
188
|
this.hidden = true;
|
190
|
-
__classPrivateFieldSet(this,
|
189
|
+
__classPrivateFieldSet(this, _ToolTipElement_allowUpdatePosition, true, "f");
|
191
190
|
if (!this.id) {
|
192
191
|
this.id = `tooltip-${Date.now()}-${(Math.random() * 10000).toFixed(0)}`;
|
193
192
|
}
|
194
193
|
if (!this.control)
|
195
194
|
return;
|
196
195
|
this.setAttribute('role', 'tooltip');
|
197
|
-
(_a = __classPrivateFieldGet(this,
|
198
|
-
__classPrivateFieldSet(this,
|
199
|
-
const { signal } = __classPrivateFieldGet(this,
|
196
|
+
(_a = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
197
|
+
__classPrivateFieldSet(this, _ToolTipElement_abortController, new AbortController(), "f");
|
198
|
+
const { signal } = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f");
|
200
199
|
this.addEventListener('mouseleave', this, { signal });
|
201
200
|
this.control.addEventListener('mouseenter', this, { signal });
|
202
201
|
this.control.addEventListener('mouseleave', this, { signal });
|
203
202
|
this.control.addEventListener('focus', this, { signal });
|
204
203
|
this.control.addEventListener('blur', this, { signal });
|
205
204
|
this.ownerDocument.addEventListener('keydown', this, { signal });
|
205
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
|
206
206
|
}
|
207
207
|
disconnectedCallback() {
|
208
208
|
var _a;
|
209
|
-
(_a = __classPrivateFieldGet(this,
|
209
|
+
(_a = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
210
210
|
}
|
211
211
|
handleEvent(event) {
|
212
212
|
if (!this.control)
|
@@ -241,109 +241,76 @@ class TooltipElement extends HTMLElement {
|
|
241
241
|
this.control.setAttribute('aria-describedby', describedBy);
|
242
242
|
}
|
243
243
|
}
|
244
|
-
else if (name === 'hidden') {
|
245
|
-
|
246
|
-
this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES);
|
247
|
-
}
|
248
|
-
else {
|
249
|
-
this.classList.add(TOOLTIP_OPEN_CLASS);
|
250
|
-
for (const tooltip of this.ownerDocument.querySelectorAll(this.tagName)) {
|
251
|
-
if (tooltip !== this)
|
252
|
-
tooltip.hidden = true;
|
253
|
-
}
|
254
|
-
__classPrivateFieldGet(this, _TooltipElement_instances, "m", _TooltipElement_updatePosition).call(this);
|
255
|
-
}
|
244
|
+
else if (this.isConnected && name === 'hidden') {
|
245
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
|
256
246
|
}
|
257
247
|
else if (name === 'data-direction') {
|
258
248
|
this.classList.remove(...DIRECTION_CLASSES);
|
259
249
|
const direction = this.direction;
|
260
250
|
if (direction === 'n') {
|
261
|
-
__classPrivateFieldSet(this,
|
262
|
-
__classPrivateFieldSet(this,
|
251
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
|
252
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
|
263
253
|
}
|
264
254
|
else if (direction === 'ne') {
|
265
|
-
__classPrivateFieldSet(this,
|
266
|
-
__classPrivateFieldSet(this,
|
255
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'start', "f");
|
256
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
|
267
257
|
}
|
268
258
|
else if (direction === 'e') {
|
269
|
-
__classPrivateFieldSet(this,
|
270
|
-
__classPrivateFieldSet(this,
|
259
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
|
260
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-right', "f");
|
271
261
|
}
|
272
262
|
else if (direction === 'se') {
|
273
|
-
__classPrivateFieldSet(this,
|
274
|
-
__classPrivateFieldSet(this,
|
263
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'start', "f");
|
264
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
|
275
265
|
}
|
276
266
|
else if (direction === 's') {
|
277
|
-
__classPrivateFieldSet(this,
|
278
|
-
__classPrivateFieldSet(this,
|
267
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
|
268
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
|
279
269
|
}
|
280
270
|
else if (direction === 'sw') {
|
281
|
-
__classPrivateFieldSet(this,
|
282
|
-
__classPrivateFieldSet(this,
|
271
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'end', "f");
|
272
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
|
283
273
|
}
|
284
274
|
else if (direction === 'w') {
|
285
|
-
__classPrivateFieldSet(this,
|
286
|
-
__classPrivateFieldSet(this,
|
275
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
|
276
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-left', "f");
|
287
277
|
}
|
288
278
|
else if (direction === 'nw') {
|
289
|
-
__classPrivateFieldSet(this,
|
290
|
-
__classPrivateFieldSet(this,
|
279
|
+
__classPrivateFieldSet(this, _ToolTipElement_align, 'end', "f");
|
280
|
+
__classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
|
291
281
|
}
|
292
282
|
}
|
293
283
|
}
|
294
284
|
}
|
295
|
-
|
296
|
-
if (
|
297
|
-
|
298
|
-
const tooltipPosition = this.getBoundingClientRect();
|
299
|
-
const targetPosition = this.control.getBoundingClientRect();
|
300
|
-
const tooltipWidth = tooltipPosition.width;
|
301
|
-
const tooltipCenter = tooltipPosition.left + tooltipWidth / 2;
|
302
|
-
const targetCenter = targetPosition.x + targetPosition.width / 2;
|
303
|
-
if (Math.abs(tooltipCenter - targetCenter) < 2 || anchorSide === 'outside-left' || anchorSide === 'outside-right') {
|
304
|
-
return 'center';
|
305
|
-
}
|
306
|
-
else if (tooltipPosition.left === targetPosition.left) {
|
307
|
-
return 'start';
|
308
|
-
}
|
309
|
-
else if (tooltipPosition.right === targetPosition.right) {
|
310
|
-
return 'end';
|
311
|
-
}
|
312
|
-
else if (tooltipCenter < targetCenter) {
|
313
|
-
if (tooltipPosition.left === 0)
|
314
|
-
return 'start';
|
315
|
-
return 'end';
|
285
|
+
_ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new WeakMap(), _ToolTipElement_side = new WeakMap(), _ToolTipElement_allowUpdatePosition = new WeakMap(), _ToolTipElement_instances = new WeakSet(), _ToolTipElement_update = function _ToolTipElement_update() {
|
286
|
+
if (this.hidden) {
|
287
|
+
this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES);
|
316
288
|
}
|
317
289
|
else {
|
318
|
-
|
319
|
-
|
320
|
-
|
290
|
+
this.classList.add(TOOLTIP_OPEN_CLASS);
|
291
|
+
for (const tooltip of this.ownerDocument.querySelectorAll(this.tagName)) {
|
292
|
+
if (tooltip !== this)
|
293
|
+
tooltip.hidden = true;
|
294
|
+
}
|
295
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updatePosition).call(this);
|
321
296
|
}
|
322
|
-
},
|
297
|
+
}, _ToolTipElement_updatePosition = function _ToolTipElement_updatePosition() {
|
323
298
|
if (!this.control)
|
324
299
|
return;
|
325
|
-
if (!__classPrivateFieldGet(this,
|
300
|
+
if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || this.hidden)
|
326
301
|
return;
|
327
302
|
const TOOLTIP_OFFSET = 10;
|
328
303
|
this.style.left = `0px`; // Ensures we have reliable tooltip width in `getAnchoredPosition`
|
329
|
-
|
330
|
-
side: __classPrivateFieldGet(this,
|
331
|
-
align: __classPrivateFieldGet(this,
|
304
|
+
const position = getAnchoredPosition(this, this.control, {
|
305
|
+
side: __classPrivateFieldGet(this, _ToolTipElement_side, "f"),
|
306
|
+
align: __classPrivateFieldGet(this, _ToolTipElement_align, "f"),
|
332
307
|
anchorOffset: TOOLTIP_OFFSET
|
333
308
|
});
|
334
|
-
|
335
|
-
|
309
|
+
const anchorSide = position.anchorSide;
|
310
|
+
const align = position.anchorAlign;
|
336
311
|
this.style.top = `${position.top}px`;
|
337
312
|
this.style.left = `${position.left}px`;
|
338
313
|
let direction = 's';
|
339
|
-
const align = __classPrivateFieldGet(this, _TooltipElement_instances, "m", _TooltipElement_adjustedAnchorAlignment).call(this, anchorSide);
|
340
|
-
if (!align)
|
341
|
-
return;
|
342
|
-
this.style.left = `0px`; // Reset tooltip position again to ensure accurate width in `getAnchoredPosition`
|
343
|
-
position = getAnchoredPosition(this, this.control, { side: anchorSide, align, anchorOffset: TOOLTIP_OFFSET });
|
344
|
-
anchorSide = position.anchorSide;
|
345
|
-
this.style.top = `${position.top}px`;
|
346
|
-
this.style.left = `${position.left}px`;
|
347
314
|
if (anchorSide === 'outside-left') {
|
348
315
|
direction = 'w';
|
349
316
|
}
|
@@ -374,8 +341,8 @@ _TooltipElement_abortController = new WeakMap(), _TooltipElement_align = new Wea
|
|
374
341
|
}
|
375
342
|
this.classList.add(`tooltip-${direction}`);
|
376
343
|
};
|
377
|
-
|
344
|
+
ToolTipElement.observedAttributes = ['data-type', 'data-direction', 'id', 'hidden'];
|
378
345
|
if (!window.customElements.get('tool-tip')) {
|
379
|
-
window.
|
380
|
-
window.customElements.define('tool-tip',
|
346
|
+
window.ToolTipElement = ToolTipElement;
|
347
|
+
window.customElements.define('tool-tip', ToolTipElement);
|
381
348
|
}
|
@@ -2,7 +2,7 @@ import type {AnchorAlignment, AnchorSide} from '@primer/behaviors'
|
|
2
2
|
import {getAnchoredPosition} from '@primer/behaviors'
|
3
3
|
|
4
4
|
const TOOLTIP_OPEN_CLASS = 'tooltip-open'
|
5
|
-
const TOOLTIP_ARROW_EDGE_OFFSET =
|
5
|
+
const TOOLTIP_ARROW_EDGE_OFFSET = 6
|
6
6
|
|
7
7
|
type Direction = 'n' | 's' | 'e' | 'w' | 'ne' | 'se' | 'nw' | 'sw'
|
8
8
|
|
@@ -17,7 +17,7 @@ const DIRECTION_CLASSES = [
|
|
17
17
|
'tooltip-sw'
|
18
18
|
]
|
19
19
|
|
20
|
-
class
|
20
|
+
class ToolTipElement extends HTMLElement {
|
21
21
|
styles() {
|
22
22
|
return `
|
23
23
|
:host {
|
@@ -82,13 +82,13 @@ class TooltipElement extends HTMLElement {
|
|
82
82
|
:host(.tooltip-s):before,
|
83
83
|
:host(.tooltip-n):before {
|
84
84
|
right: 50%;
|
85
|
+
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
85
86
|
}
|
86
87
|
|
87
88
|
:host(.tooltip-s):before,
|
88
89
|
:host(.tooltip-se):before,
|
89
90
|
:host(.tooltip-sw):before {
|
90
91
|
bottom: 100%;
|
91
|
-
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
92
92
|
border-bottom-color: var(--color-neutral-emphasis-plus)
|
93
93
|
}
|
94
94
|
|
@@ -102,7 +102,6 @@ class TooltipElement extends HTMLElement {
|
|
102
102
|
:host(.tooltip-ne):before,
|
103
103
|
:host(.tooltip-nw):before {
|
104
104
|
top: 100%;
|
105
|
-
margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
|
106
105
|
border-top-color: var(--color-neutral-emphasis-plus)
|
107
106
|
}
|
108
107
|
|
@@ -176,8 +175,7 @@ class TooltipElement extends HTMLElement {
|
|
176
175
|
return this.ownerDocument.getElementById(this.htmlFor)
|
177
176
|
}
|
178
177
|
|
179
|
-
|
180
|
-
super()
|
178
|
+
connectedCallback() {
|
181
179
|
const shadow = this.attachShadow({mode: 'open'})
|
182
180
|
shadow.innerHTML = `
|
183
181
|
<style>
|
@@ -185,9 +183,6 @@ class TooltipElement extends HTMLElement {
|
|
185
183
|
</style>
|
186
184
|
<slot></slot>
|
187
185
|
`
|
188
|
-
}
|
189
|
-
|
190
|
-
connectedCallback() {
|
191
186
|
this.hidden = true
|
192
187
|
this.#allowUpdatePosition = true
|
193
188
|
|
@@ -209,6 +204,7 @@ class TooltipElement extends HTMLElement {
|
|
209
204
|
this.control.addEventListener('focus', this, {signal})
|
210
205
|
this.control.addEventListener('blur', this, {signal})
|
211
206
|
this.ownerDocument.addEventListener('keydown', this, {signal})
|
207
|
+
this.#update()
|
212
208
|
}
|
213
209
|
|
214
210
|
disconnectedCallback() {
|
@@ -237,6 +233,18 @@ class TooltipElement extends HTMLElement {
|
|
237
233
|
|
238
234
|
static observedAttributes = ['data-type', 'data-direction', 'id', 'hidden']
|
239
235
|
|
236
|
+
#update() {
|
237
|
+
if (this.hidden) {
|
238
|
+
this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES)
|
239
|
+
} else {
|
240
|
+
this.classList.add(TOOLTIP_OPEN_CLASS)
|
241
|
+
for (const tooltip of this.ownerDocument.querySelectorAll<HTMLElement>(this.tagName)) {
|
242
|
+
if (tooltip !== this) tooltip.hidden = true
|
243
|
+
}
|
244
|
+
this.#updatePosition()
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
240
248
|
attributeChangedCallback(name: string) {
|
241
249
|
if (name === 'id' || name === 'data-type') {
|
242
250
|
if (!this.id || !this.control) return
|
@@ -247,16 +255,8 @@ class TooltipElement extends HTMLElement {
|
|
247
255
|
describedBy ? (describedBy = `${describedBy} ${this.id}`) : (describedBy = this.id)
|
248
256
|
this.control.setAttribute('aria-describedby', describedBy)
|
249
257
|
}
|
250
|
-
} else if (name === 'hidden') {
|
251
|
-
|
252
|
-
this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES)
|
253
|
-
} else {
|
254
|
-
this.classList.add(TOOLTIP_OPEN_CLASS)
|
255
|
-
for (const tooltip of this.ownerDocument.querySelectorAll<HTMLElement>(this.tagName)) {
|
256
|
-
if (tooltip !== this) tooltip.hidden = true
|
257
|
-
}
|
258
|
-
this.#updatePosition()
|
259
|
-
}
|
258
|
+
} else if (this.isConnected && name === 'hidden') {
|
259
|
+
this.#update()
|
260
260
|
} else if (name === 'data-direction') {
|
261
261
|
this.classList.remove(...DIRECTION_CLASSES)
|
262
262
|
const direction = this.direction
|
@@ -288,34 +288,6 @@ class TooltipElement extends HTMLElement {
|
|
288
288
|
}
|
289
289
|
}
|
290
290
|
|
291
|
-
// `getAnchoredPosition` may calibrate `anchoredSide` but does not recalibrate `align`.
|
292
|
-
// Therefore, we need to determine which `align` is best based on the initial `getAnchoredPosition` calcluation.
|
293
|
-
// Related: https://github.com/primer/behaviors/issues/63
|
294
|
-
#adjustedAnchorAlignment(anchorSide: AnchorSide): AnchorAlignment | undefined {
|
295
|
-
if (!this.control) return
|
296
|
-
|
297
|
-
const tooltipPosition = this.getBoundingClientRect()
|
298
|
-
const targetPosition = this.control.getBoundingClientRect()
|
299
|
-
const tooltipWidth = tooltipPosition.width
|
300
|
-
|
301
|
-
const tooltipCenter = tooltipPosition.left + tooltipWidth / 2
|
302
|
-
const targetCenter = targetPosition.x + targetPosition.width / 2
|
303
|
-
|
304
|
-
if (Math.abs(tooltipCenter - targetCenter) < 2 || anchorSide === 'outside-left' || anchorSide === 'outside-right') {
|
305
|
-
return 'center'
|
306
|
-
} else if (tooltipPosition.left === targetPosition.left) {
|
307
|
-
return 'start'
|
308
|
-
} else if (tooltipPosition.right === targetPosition.right) {
|
309
|
-
return 'end'
|
310
|
-
} else if (tooltipCenter < targetCenter) {
|
311
|
-
if (tooltipPosition.left === 0) return 'start'
|
312
|
-
return 'end'
|
313
|
-
} else {
|
314
|
-
if (tooltipPosition.right === 0) return 'end'
|
315
|
-
return 'start'
|
316
|
-
}
|
317
|
-
}
|
318
|
-
|
319
291
|
#updatePosition() {
|
320
292
|
if (!this.control) return
|
321
293
|
if (!this.#allowUpdatePosition || this.hidden) return
|
@@ -323,27 +295,19 @@ class TooltipElement extends HTMLElement {
|
|
323
295
|
const TOOLTIP_OFFSET = 10
|
324
296
|
|
325
297
|
this.style.left = `0px` // Ensures we have reliable tooltip width in `getAnchoredPosition`
|
326
|
-
|
298
|
+
|
299
|
+
const position = getAnchoredPosition(this, this.control, {
|
327
300
|
side: this.#side,
|
328
301
|
align: this.#align,
|
329
302
|
anchorOffset: TOOLTIP_OFFSET
|
330
303
|
})
|
331
|
-
|
304
|
+
const anchorSide = position.anchorSide
|
305
|
+
const align = position.anchorAlign
|
332
306
|
|
333
|
-
// We need to set tooltip position in order to determine ideal align.
|
334
307
|
this.style.top = `${position.top}px`
|
335
308
|
this.style.left = `${position.left}px`
|
336
|
-
let direction: Direction = 's'
|
337
|
-
|
338
|
-
const align = this.#adjustedAnchorAlignment(anchorSide)
|
339
|
-
if (!align) return
|
340
|
-
|
341
|
-
this.style.left = `0px` // Reset tooltip position again to ensure accurate width in `getAnchoredPosition`
|
342
|
-
position = getAnchoredPosition(this, this.control, {side: anchorSide, align, anchorOffset: TOOLTIP_OFFSET})
|
343
|
-
anchorSide = position.anchorSide
|
344
309
|
|
345
|
-
|
346
|
-
this.style.left = `${position.left}px`
|
310
|
+
let direction: Direction = 's'
|
347
311
|
|
348
312
|
if (anchorSide === 'outside-left') {
|
349
313
|
direction = 'w'
|
@@ -372,12 +336,12 @@ class TooltipElement extends HTMLElement {
|
|
372
336
|
}
|
373
337
|
|
374
338
|
if (!window.customElements.get('tool-tip')) {
|
375
|
-
window.
|
376
|
-
window.customElements.define('tool-tip',
|
339
|
+
window.ToolTipElement = ToolTipElement
|
340
|
+
window.customElements.define('tool-tip', ToolTipElement)
|
377
341
|
}
|
378
342
|
|
379
343
|
declare global {
|
380
344
|
interface Window {
|
381
|
-
|
345
|
+
ToolTipElement: typeof ToolTipElement
|
382
346
|
}
|
383
347
|
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
require "json"
|
5
|
+
require "parser/current"
|
6
|
+
|
7
|
+
module RuboCop
|
8
|
+
module Cop
|
9
|
+
module Primer
|
10
|
+
# This cop ensures that components marked as "deprecated" in `static/statuses.json` are discouraged from use.
|
11
|
+
#
|
12
|
+
# bad
|
13
|
+
# Primer::BlankslateComponent.new(:foo)
|
14
|
+
#
|
15
|
+
# good
|
16
|
+
# Primer::Beta::Blankslate.new(:foo)
|
17
|
+
#
|
18
|
+
# bad
|
19
|
+
# Primer::Tooltip.new(:foo)
|
20
|
+
#
|
21
|
+
# good
|
22
|
+
# Primer::Alpha::Tooltip.new(:foo)
|
23
|
+
class DeprecatedComponents < BaseCop
|
24
|
+
# If there is no alternative to suggest, set the value to nil.
|
25
|
+
COMPONENT_TO_USE_INSTEAD = {
|
26
|
+
"Primer::BlankslateComponent" => "Primer::Beta::Blankslate",
|
27
|
+
"Primer::DropdownMenuComponent" => nil,
|
28
|
+
"Primer::Tooltip" => "Primer::Alpha::Tooltip",
|
29
|
+
"Primer::FlexComponent" => nil,
|
30
|
+
"Primer::FlexItemComponent" => nil
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
def on_send(node)
|
34
|
+
return unless node.source.include?("Primer::")
|
35
|
+
|
36
|
+
deprecated_components.each do |component|
|
37
|
+
pattern = NodePattern.new("(send #{pattern(component)} :new ...)")
|
38
|
+
add_offense(node, message: message(component)) if pattern.match(node)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Converts a string to acceptable rubocop-ast pattern syntax
|
45
|
+
def pattern(component)
|
46
|
+
Parser::CurrentRuby.parse(component)
|
47
|
+
.to_s
|
48
|
+
.gsub("nil", "nil?")
|
49
|
+
.delete("\n")
|
50
|
+
.gsub(" ", " ")
|
51
|
+
end
|
52
|
+
|
53
|
+
def message(component)
|
54
|
+
message = "#{component} has been deprecated and should not be used."
|
55
|
+
message += " Try #{COMPONENT_TO_USE_INSTEAD[component]} instead." if COMPONENT_TO_USE_INSTEAD.fetch(component).present?
|
56
|
+
message
|
57
|
+
end
|
58
|
+
|
59
|
+
def statuses_json
|
60
|
+
JSON.parse(
|
61
|
+
File.read(
|
62
|
+
File.join(File.dirname(__FILE__), "../../../../static/statuses.json")
|
63
|
+
)
|
64
|
+
).freeze
|
65
|
+
end
|
66
|
+
|
67
|
+
def deprecated_components
|
68
|
+
@deprecated_components ||= statuses_json.select { |_, value| value == "deprecated" }.keys.tap do |deprecated_components|
|
69
|
+
deprecated_components.each do |deprecated|
|
70
|
+
unless COMPONENT_TO_USE_INSTEAD.key?(deprecated)
|
71
|
+
raise "Please provide a component that should be used in place of #{deprecated} in COMPONENT_TO_USE_INSTEAD. "\
|
72
|
+
"If there is no alternative, set the value to nil."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|