primer_view_components 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/app/assets/javascripts/app/components/primer/alpha/action_bar_element.d.ts +16 -0
- data/app/assets/javascripts/app/components/primer/alpha/action_menu/action_menu_element.d.ts +30 -0
- data/app/assets/javascripts/app/components/primer/alpha/dropdown/menu.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/alpha/dropdown.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/alpha/image_crop.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/alpha/modal_dialog.d.ts +18 -0
- data/app/assets/javascripts/app/components/primer/alpha/nav_list.d.ts +28 -0
- data/app/assets/javascripts/app/components/primer/alpha/segmented_control.d.ts +12 -0
- data/app/assets/javascripts/app/components/primer/alpha/tab_container.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/alpha/toggle_switch.d.ts +30 -0
- data/app/assets/javascripts/app/components/primer/alpha/tool_tip.d.ts +26 -0
- data/app/assets/javascripts/app/components/primer/alpha/x_banner.d.ts +11 -0
- data/app/assets/javascripts/app/components/primer/anchored_position.d.ts +27 -0
- data/app/assets/javascripts/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/beta/clipboard_copy.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/beta/relative_time.d.ts +1 -0
- data/app/assets/javascripts/app/components/primer/focus_group.d.ts +19 -0
- data/app/assets/javascripts/app/components/primer/primer.d.ts +21 -0
- data/app/assets/javascripts/lib/primer/forms/primer_multi_input.d.ts +10 -0
- data/app/assets/javascripts/lib/primer/forms/primer_text_field.d.ts +1 -0
- data/app/assets/javascripts/lib/primer/forms/toggle_switch_input.d.ts +5 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_bar/divider.rb +30 -0
- data/app/components/primer/alpha/action_bar/item.rb +26 -0
- data/app/components/primer/alpha/action_bar.css +1 -0
- data/app/components/primer/alpha/action_bar.css.json +17 -0
- data/app/components/primer/alpha/action_bar.css.map +1 -0
- data/app/components/primer/alpha/action_bar.html.erb +12 -0
- data/app/components/primer/alpha/action_bar.pcss +69 -0
- data/app/components/primer/alpha/action_bar.rb +110 -0
- data/app/components/primer/alpha/action_bar_element.d.ts +16 -0
- data/app/components/primer/alpha/action_bar_element.js +172 -0
- data/app/components/primer/alpha/action_bar_element.ts +175 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.d.ts +2 -2
- data/app/components/primer/alpha/tool_tip.d.ts +3 -2
- data/app/components/primer/alpha/tool_tip.js +89 -44
- data/app/components/primer/alpha/tool_tip.ts +88 -41
- data/app/components/primer/alpha/tooltip.rb +1 -0
- data/app/components/primer/beta/link.css +1 -1
- data/app/components/primer/beta/link.css.map +1 -1
- data/app/components/primer/beta/link.pcss +4 -0
- data/app/components/primer/beta/link.rb +6 -10
- data/app/components/primer/primer.d.ts +1 -0
- data/app/components/primer/primer.js +1 -0
- data/app/components/primer/primer.pcss +1 -0
- data/app/components/primer/primer.ts +1 -0
- data/lib/primer/static/generate_previews.rb +9 -0
- data/lib/primer/view_components/linters/tooltipped_migration.rb +1 -3
- data/lib/primer/view_components/version.rb +2 -2
- data/lib/primer/yard.rb +5 -0
- data/previews/primer/alpha/action_bar_preview/inline.html.erb +16 -0
- data/previews/primer/alpha/action_bar_preview.rb +77 -0
- data/previews/primer/alpha/action_list_preview.rb +10 -0
- data/previews/primer/alpha/action_menu_preview.rb +5 -0
- data/previews/primer/alpha/auto_complete_preview.rb +1 -0
- data/previews/primer/alpha/banner_preview.rb +9 -1
- data/previews/primer/alpha/button_marketing_preview.rb +2 -0
- data/previews/primer/alpha/check_box_group_preview.rb +1 -0
- data/previews/primer/alpha/check_box_preview.rb +6 -0
- data/previews/primer/alpha/dialog_preview.rb +1 -0
- data/previews/primer/alpha/dropdown_preview.rb +1 -0
- data/previews/primer/alpha/hellip_button_preview.rb +1 -0
- data/previews/primer/alpha/hidden_text_expander_preview.rb +1 -0
- data/previews/primer/alpha/layout_preview.rb +4 -0
- data/previews/primer/alpha/menu_preview.rb +1 -0
- data/previews/primer/alpha/multi_input_preview.rb +4 -0
- data/previews/primer/alpha/nav_list_preview.rb +3 -0
- data/previews/primer/alpha/radio_button_group_preview.rb +2 -0
- data/previews/primer/alpha/radio_button_preview.rb +10 -0
- data/previews/primer/alpha/segmented_control_preview.rb +13 -0
- data/previews/primer/alpha/select_preview.rb +6 -0
- data/previews/primer/alpha/tab_nav_preview.rb +3 -0
- data/previews/primer/alpha/tab_panels_preview.rb +1 -0
- data/previews/primer/alpha/text_area_preview.rb +7 -0
- data/previews/primer/alpha/text_field_preview.rb +15 -0
- data/previews/primer/alpha/toggle_switch_preview.rb +7 -0
- data/previews/primer/alpha/tooltip_preview/tooltip_inside_primer_overlay.html.erb +20 -0
- data/previews/primer/alpha/tooltip_preview.rb +7 -0
- data/previews/primer/alpha/underline_nav_preview.rb +2 -0
- data/previews/primer/beta/auto_complete_item_preview.rb +2 -0
- data/previews/primer/beta/auto_complete_preview.rb +7 -0
- data/previews/primer/beta/avatar_preview.rb +10 -0
- data/previews/primer/beta/avatar_stack_preview.rb +3 -0
- data/previews/primer/beta/blankslate_preview.rb +9 -0
- data/previews/primer/beta/border_box_preview.rb +4 -0
- data/previews/primer/beta/breadcrumbs_preview.rb +1 -0
- data/previews/primer/beta/button_group_preview.rb +4 -0
- data/previews/primer/beta/button_preview.rb +10 -0
- data/previews/primer/beta/clipboard_copy_preview.rb +2 -0
- data/previews/primer/beta/close_button_preview.rb +1 -0
- data/previews/primer/beta/counter_preview.rb +11 -0
- data/previews/primer/beta/flash_preview.rb +8 -0
- data/previews/primer/beta/heading_preview.rb +1 -0
- data/previews/primer/beta/icon_button_preview.rb +3 -0
- data/previews/primer/beta/label_preview.rb +13 -0
- data/previews/primer/beta/link_preview.rb +11 -9
- data/previews/primer/beta/markdown_preview.rb +1 -0
- data/previews/primer/beta/octicon_preview.rb +1 -0
- data/previews/primer/beta/popover_preview.rb +6 -0
- data/previews/primer/beta/progress_bar_preview.rb +4 -0
- data/previews/primer/beta/spinner_preview.rb +1 -0
- data/previews/primer/beta/state_preview.rb +6 -0
- data/previews/primer/beta/subhead_preview.rb +4 -0
- data/previews/primer/beta/text_preview.rb +1 -0
- data/previews/primer/beta/timeline_item_preview.rb +1 -0
- data/previews/primer/beta/truncate_preview.rb +1 -0
- data/previews/primer/box_preview.rb +2 -0
- data/static/arguments.json +51 -7
- data/static/audited_at.json +3 -0
- data/static/classes.json +21 -0
- data/static/constants.json +20 -6
- data/static/info_arch.json +669 -7
- data/static/previews.json +571 -0
- data/static/statuses.json +3 -0
- metadata +43 -8
@@ -10,10 +10,11 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
11
11
|
};
|
12
12
|
var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_update, _ToolTipElement_updateControlReference, _ToolTipElement_updateDirection, _ToolTipElement_updatePosition;
|
13
|
+
import '@oddbird/popover-polyfill';
|
13
14
|
import { getAnchoredPosition } from '@primer/behaviors';
|
14
|
-
const TOOLTIP_OPEN_CLASS = 'tooltip-open';
|
15
15
|
const TOOLTIP_ARROW_EDGE_OFFSET = 6;
|
16
16
|
const TOOLTIP_SR_ONLY_CLASS = 'sr-only';
|
17
|
+
const TOOLTIP_OFFSET = 10;
|
17
18
|
const DIRECTION_CLASSES = [
|
18
19
|
'tooltip-n',
|
19
20
|
'tooltip-s',
|
@@ -24,6 +25,23 @@ const DIRECTION_CLASSES = [
|
|
24
25
|
'tooltip-nw',
|
25
26
|
'tooltip-sw'
|
26
27
|
];
|
28
|
+
function closeOpenTooltips(except) {
|
29
|
+
for (const tooltip of openTooltips) {
|
30
|
+
if (tooltip === except)
|
31
|
+
continue;
|
32
|
+
if (tooltip.matches(':popover-open')) {
|
33
|
+
tooltip.hidePopover();
|
34
|
+
}
|
35
|
+
else {
|
36
|
+
openTooltips.delete(tooltip);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
function focusOutListener() {
|
41
|
+
closeOpenTooltips();
|
42
|
+
}
|
43
|
+
const tooltips = new Set();
|
44
|
+
const openTooltips = new Set();
|
27
45
|
class ToolTipElement extends HTMLElement {
|
28
46
|
constructor() {
|
29
47
|
super(...arguments);
|
@@ -36,12 +54,10 @@ class ToolTipElement extends HTMLElement {
|
|
36
54
|
styles() {
|
37
55
|
return `
|
38
56
|
:host {
|
39
|
-
|
40
|
-
z-index: 1000000;
|
41
|
-
padding: .5em .75em;
|
57
|
+
padding: .5em .75em !important;
|
42
58
|
font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
43
59
|
-webkit-font-smoothing: subpixel-antialiased;
|
44
|
-
color: var(--color-fg-on-emphasis);
|
60
|
+
color: var(--color-fg-on-emphasis) !important;
|
45
61
|
text-align: center;
|
46
62
|
text-decoration: none;
|
47
63
|
text-shadow: none;
|
@@ -49,13 +65,16 @@ class ToolTipElement extends HTMLElement {
|
|
49
65
|
letter-spacing: normal;
|
50
66
|
word-wrap: break-word;
|
51
67
|
white-space: pre;
|
52
|
-
background: var(--color-neutral-emphasis-plus);
|
68
|
+
background: var(--color-neutral-emphasis-plus) !important;
|
53
69
|
border-radius: 6px;
|
70
|
+
border: 0 !important;
|
54
71
|
opacity: 0;
|
55
72
|
max-width: 250px;
|
56
73
|
word-wrap: break-word;
|
57
74
|
white-space: normal;
|
58
|
-
width: max-content;
|
75
|
+
width: max-content !important;
|
76
|
+
inset: var(--tool-tip-position-top, 0) auto auto var(--tool-tip-position-left, 0) !important;
|
77
|
+
overflow: visible !important;
|
59
78
|
}
|
60
79
|
|
61
80
|
:host:before{
|
@@ -69,7 +88,7 @@ class ToolTipElement extends HTMLElement {
|
|
69
88
|
|
70
89
|
@keyframes tooltip-appear {
|
71
90
|
from {
|
72
|
-
opacity: 0
|
91
|
+
opacity: 0;
|
73
92
|
}
|
74
93
|
to {
|
75
94
|
opacity: 1
|
@@ -85,8 +104,17 @@ class ToolTipElement extends HTMLElement {
|
|
85
104
|
content: ""
|
86
105
|
}
|
87
106
|
|
88
|
-
:host(
|
89
|
-
:host(
|
107
|
+
:host(:popover-open),
|
108
|
+
:host(:popover-open):before {
|
109
|
+
animation-name: tooltip-appear;
|
110
|
+
animation-duration: .1s;
|
111
|
+
animation-fill-mode: forwards;
|
112
|
+
animation-timing-function: ease-in;
|
113
|
+
animation-delay: .4s
|
114
|
+
}
|
115
|
+
|
116
|
+
:host(.\\:popover-open),
|
117
|
+
:host(.\\:popover-open):before {
|
90
118
|
animation-name: tooltip-appear;
|
91
119
|
animation-duration: .1s;
|
92
120
|
animation-fill-mode: forwards;
|
@@ -177,16 +205,22 @@ class ToolTipElement extends HTMLElement {
|
|
177
205
|
get control() {
|
178
206
|
return this.ownerDocument.getElementById(this.htmlFor);
|
179
207
|
}
|
208
|
+
/* @deprecated */
|
180
209
|
set hiddenFromView(value) {
|
181
|
-
this.
|
182
|
-
|
183
|
-
|
210
|
+
if (value && this.matches(':popover-open')) {
|
211
|
+
this.hidePopover();
|
212
|
+
}
|
213
|
+
else if (!value && !this.matches(':popover-open')) {
|
214
|
+
this.showPopover();
|
215
|
+
}
|
184
216
|
}
|
217
|
+
/* @deprecated */
|
185
218
|
get hiddenFromView() {
|
186
|
-
return this.
|
219
|
+
return !this.matches(':popover-open');
|
187
220
|
}
|
188
221
|
connectedCallback() {
|
189
|
-
var _a;
|
222
|
+
var _a, _b;
|
223
|
+
tooltips.add(this);
|
190
224
|
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updateControlReference).call(this);
|
191
225
|
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updateDirection).call(this);
|
192
226
|
if (!this.shadowRoot) {
|
@@ -195,7 +229,7 @@ class ToolTipElement extends HTMLElement {
|
|
195
229
|
style.textContent = this.styles();
|
196
230
|
shadow.appendChild(document.createElement('slot'));
|
197
231
|
}
|
198
|
-
this.
|
232
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this, false);
|
199
233
|
__classPrivateFieldSet(this, _ToolTipElement_allowUpdatePosition, true, "f");
|
200
234
|
if (!this.control)
|
201
235
|
return;
|
@@ -204,35 +238,48 @@ class ToolTipElement extends HTMLElement {
|
|
204
238
|
__classPrivateFieldSet(this, _ToolTipElement_abortController, new AbortController(), "f");
|
205
239
|
const { signal } = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f");
|
206
240
|
this.addEventListener('mouseleave', this, { signal });
|
241
|
+
this.addEventListener('toggle', this, { signal });
|
207
242
|
this.control.addEventListener('mouseenter', this, { signal });
|
208
243
|
this.control.addEventListener('mouseleave', this, { signal });
|
209
244
|
this.control.addEventListener('focus', this, { signal });
|
210
|
-
this.control.addEventListener('
|
245
|
+
this.control.addEventListener('mousedown', this, { signal });
|
246
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
247
|
+
// @ts-ignore popoverTargetElement is not in the type definition
|
248
|
+
(_b = this.control.popoverTargetElement) === null || _b === void 0 ? void 0 : _b.addEventListener('beforetoggle', this, {
|
249
|
+
signal
|
250
|
+
});
|
251
|
+
this.ownerDocument.addEventListener('focusout', focusOutListener);
|
211
252
|
this.ownerDocument.addEventListener('keydown', this, { signal });
|
212
|
-
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
|
213
253
|
}
|
214
254
|
disconnectedCallback() {
|
215
255
|
var _a;
|
256
|
+
tooltips.delete(this);
|
257
|
+
openTooltips.delete(this);
|
216
258
|
(_a = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
217
259
|
}
|
218
|
-
handleEvent(event) {
|
260
|
+
async handleEvent(event) {
|
219
261
|
if (!this.control)
|
220
262
|
return;
|
263
|
+
const showing = this.matches(':popover-open');
|
221
264
|
// Ensures that tooltip stays open when hovering between tooltip and element
|
222
265
|
// WCAG Success Criterion 1.4.13 Hoverable
|
223
|
-
|
224
|
-
|
225
|
-
}
|
226
|
-
else if (event.type === 'blur') {
|
227
|
-
this.hiddenFromView = true;
|
228
|
-
}
|
229
|
-
else if (event.type === 'mouseleave' &&
|
266
|
+
const shouldShow = event.type === 'mouseenter' || event.type === 'focus';
|
267
|
+
const isMouseLeaveFromButton = event.type === 'mouseleave' &&
|
230
268
|
event.relatedTarget !== this.control &&
|
231
|
-
event.relatedTarget !== this
|
232
|
-
|
269
|
+
event.relatedTarget !== this;
|
270
|
+
const isEscapeKeydown = event.type === 'keydown' && event.key === 'Escape';
|
271
|
+
const isMouseDownOnButton = event.type === 'mousedown' && event.currentTarget === this.control;
|
272
|
+
const isOpeningOtherPopover = event.type === 'beforetoggle' && event.currentTarget !== this;
|
273
|
+
const shouldHide = isMouseLeaveFromButton || isEscapeKeydown || isMouseDownOnButton || isOpeningOtherPopover;
|
274
|
+
await Promise.resolve();
|
275
|
+
if (!showing && shouldShow) {
|
276
|
+
this.showPopover();
|
277
|
+
}
|
278
|
+
else if (showing && shouldHide) {
|
279
|
+
this.hidePopover();
|
233
280
|
}
|
234
|
-
|
235
|
-
this.
|
281
|
+
if (event.type === 'toggle') {
|
282
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this, event.newState === 'open');
|
236
283
|
}
|
237
284
|
}
|
238
285
|
attributeChangedCallback(name) {
|
@@ -246,17 +293,17 @@ class ToolTipElement extends HTMLElement {
|
|
246
293
|
}
|
247
294
|
}
|
248
295
|
}
|
249
|
-
_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() {
|
250
|
-
if (
|
251
|
-
|
296
|
+
_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(isOpen) {
|
297
|
+
if (isOpen) {
|
298
|
+
openTooltips.add(this);
|
299
|
+
this.classList.remove(TOOLTIP_SR_ONLY_CLASS);
|
300
|
+
closeOpenTooltips(this);
|
301
|
+
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updatePosition).call(this);
|
252
302
|
}
|
253
303
|
else {
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
tooltip.hiddenFromView = true;
|
258
|
-
}
|
259
|
-
__classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updatePosition).call(this);
|
304
|
+
openTooltips.delete(this);
|
305
|
+
this.classList.remove(...DIRECTION_CLASSES);
|
306
|
+
this.classList.add(TOOLTIP_SR_ONLY_CLASS);
|
260
307
|
}
|
261
308
|
}, _ToolTipElement_updateControlReference = function _ToolTipElement_updateControlReference() {
|
262
309
|
if (!this.id || !this.control)
|
@@ -331,10 +378,8 @@ _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new Wea
|
|
331
378
|
}, _ToolTipElement_updatePosition = function _ToolTipElement_updatePosition() {
|
332
379
|
if (!this.control)
|
333
380
|
return;
|
334
|
-
if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || this.
|
381
|
+
if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || !this.matches(':popover-open'))
|
335
382
|
return;
|
336
|
-
const TOOLTIP_OFFSET = 10;
|
337
|
-
this.style.left = `0px`; // Ensures we have reliable tooltip width in `getAnchoredPosition`
|
338
383
|
const position = getAnchoredPosition(this, this.control, {
|
339
384
|
side: __classPrivateFieldGet(this, _ToolTipElement_side, "f"),
|
340
385
|
align: __classPrivateFieldGet(this, _ToolTipElement_align, "f"),
|
@@ -342,8 +387,8 @@ _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new Wea
|
|
342
387
|
});
|
343
388
|
const anchorSide = position.anchorSide;
|
344
389
|
const align = position.anchorAlign;
|
345
|
-
this.style.top
|
346
|
-
this.style.left
|
390
|
+
this.style.setProperty('--tool-tip-position-top', `${position.top}px`);
|
391
|
+
this.style.setProperty('--tool-tip-position-left', `${position.left}px`);
|
347
392
|
let direction = 's';
|
348
393
|
if (anchorSide === 'outside-left') {
|
349
394
|
direction = 'w';
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import type {AnchorAlignment, AnchorSide} from '@primer/behaviors'
|
2
|
+
import '@oddbird/popover-polyfill'
|
2
3
|
import {getAnchoredPosition} from '@primer/behaviors'
|
3
4
|
|
4
|
-
const TOOLTIP_OPEN_CLASS = 'tooltip-open'
|
5
5
|
const TOOLTIP_ARROW_EDGE_OFFSET = 6
|
6
6
|
const TOOLTIP_SR_ONLY_CLASS = 'sr-only'
|
7
|
+
const TOOLTIP_OFFSET = 10
|
7
8
|
|
8
9
|
type Direction = 'n' | 's' | 'e' | 'w' | 'ne' | 'se' | 'nw' | 'sw'
|
9
10
|
|
@@ -18,16 +19,31 @@ const DIRECTION_CLASSES = [
|
|
18
19
|
'tooltip-sw'
|
19
20
|
]
|
20
21
|
|
22
|
+
function closeOpenTooltips(except?: Element) {
|
23
|
+
for (const tooltip of openTooltips) {
|
24
|
+
if (tooltip === except) continue
|
25
|
+
if (tooltip.matches(':popover-open')) {
|
26
|
+
tooltip.hidePopover()
|
27
|
+
} else {
|
28
|
+
openTooltips.delete(tooltip)
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
function focusOutListener() {
|
34
|
+
closeOpenTooltips()
|
35
|
+
}
|
36
|
+
|
37
|
+
const tooltips = new Set<ToolTipElement>()
|
38
|
+
const openTooltips = new Set<ToolTipElement>()
|
21
39
|
class ToolTipElement extends HTMLElement {
|
22
40
|
styles() {
|
23
41
|
return `
|
24
42
|
:host {
|
25
|
-
|
26
|
-
z-index: 1000000;
|
27
|
-
padding: .5em .75em;
|
43
|
+
padding: .5em .75em !important;
|
28
44
|
font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
29
45
|
-webkit-font-smoothing: subpixel-antialiased;
|
30
|
-
color: var(--color-fg-on-emphasis);
|
46
|
+
color: var(--color-fg-on-emphasis) !important;
|
31
47
|
text-align: center;
|
32
48
|
text-decoration: none;
|
33
49
|
text-shadow: none;
|
@@ -35,13 +51,16 @@ class ToolTipElement extends HTMLElement {
|
|
35
51
|
letter-spacing: normal;
|
36
52
|
word-wrap: break-word;
|
37
53
|
white-space: pre;
|
38
|
-
background: var(--color-neutral-emphasis-plus);
|
54
|
+
background: var(--color-neutral-emphasis-plus) !important;
|
39
55
|
border-radius: 6px;
|
56
|
+
border: 0 !important;
|
40
57
|
opacity: 0;
|
41
58
|
max-width: 250px;
|
42
59
|
word-wrap: break-word;
|
43
60
|
white-space: normal;
|
44
|
-
width: max-content;
|
61
|
+
width: max-content !important;
|
62
|
+
inset: var(--tool-tip-position-top, 0) auto auto var(--tool-tip-position-left, 0) !important;
|
63
|
+
overflow: visible !important;
|
45
64
|
}
|
46
65
|
|
47
66
|
:host:before{
|
@@ -55,7 +74,7 @@ class ToolTipElement extends HTMLElement {
|
|
55
74
|
|
56
75
|
@keyframes tooltip-appear {
|
57
76
|
from {
|
58
|
-
opacity: 0
|
77
|
+
opacity: 0;
|
59
78
|
}
|
60
79
|
to {
|
61
80
|
opacity: 1
|
@@ -71,8 +90,17 @@ class ToolTipElement extends HTMLElement {
|
|
71
90
|
content: ""
|
72
91
|
}
|
73
92
|
|
74
|
-
:host(
|
75
|
-
:host(
|
93
|
+
:host(:popover-open),
|
94
|
+
:host(:popover-open):before {
|
95
|
+
animation-name: tooltip-appear;
|
96
|
+
animation-duration: .1s;
|
97
|
+
animation-fill-mode: forwards;
|
98
|
+
animation-timing-function: ease-in;
|
99
|
+
animation-delay: .4s
|
100
|
+
}
|
101
|
+
|
102
|
+
:host(.\\:popover-open),
|
103
|
+
:host(.\\:popover-open):before {
|
76
104
|
animation-name: tooltip-appear;
|
77
105
|
animation-duration: .1s;
|
78
106
|
animation-fill-mode: forwards;
|
@@ -176,16 +204,22 @@ class ToolTipElement extends HTMLElement {
|
|
176
204
|
return this.ownerDocument.getElementById(this.htmlFor)
|
177
205
|
}
|
178
206
|
|
207
|
+
/* @deprecated */
|
179
208
|
set hiddenFromView(value: true | false) {
|
180
|
-
this.
|
181
|
-
|
209
|
+
if (value && this.matches(':popover-open')) {
|
210
|
+
this.hidePopover()
|
211
|
+
} else if (!value && !this.matches(':popover-open')) {
|
212
|
+
this.showPopover()
|
213
|
+
}
|
182
214
|
}
|
183
215
|
|
216
|
+
/* @deprecated */
|
184
217
|
get hiddenFromView() {
|
185
|
-
return this.
|
218
|
+
return !this.matches(':popover-open')
|
186
219
|
}
|
187
220
|
|
188
221
|
connectedCallback() {
|
222
|
+
tooltips.add(this)
|
189
223
|
this.#updateControlReference()
|
190
224
|
this.#updateDirection()
|
191
225
|
if (!this.shadowRoot) {
|
@@ -194,7 +228,7 @@ class ToolTipElement extends HTMLElement {
|
|
194
228
|
style.textContent = this.styles()
|
195
229
|
shadow.appendChild(document.createElement('slot'))
|
196
230
|
}
|
197
|
-
this
|
231
|
+
this.#update(false)
|
198
232
|
this.#allowUpdatePosition = true
|
199
233
|
|
200
234
|
if (!this.control) return
|
@@ -206,49 +240,66 @@ class ToolTipElement extends HTMLElement {
|
|
206
240
|
const {signal} = this.#abortController
|
207
241
|
|
208
242
|
this.addEventListener('mouseleave', this, {signal})
|
243
|
+
this.addEventListener('toggle', this, {signal})
|
209
244
|
this.control.addEventListener('mouseenter', this, {signal})
|
210
245
|
this.control.addEventListener('mouseleave', this, {signal})
|
211
246
|
this.control.addEventListener('focus', this, {signal})
|
212
|
-
this.control.addEventListener('
|
247
|
+
this.control.addEventListener('mousedown', this, {signal})
|
248
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
249
|
+
// @ts-ignore popoverTargetElement is not in the type definition
|
250
|
+
this.control.popoverTargetElement?.addEventListener('beforetoggle', this, {
|
251
|
+
signal
|
252
|
+
})
|
253
|
+
this.ownerDocument.addEventListener('focusout', focusOutListener)
|
213
254
|
this.ownerDocument.addEventListener('keydown', this, {signal})
|
214
|
-
this.#update()
|
215
255
|
}
|
216
256
|
|
217
257
|
disconnectedCallback() {
|
258
|
+
tooltips.delete(this)
|
259
|
+
openTooltips.delete(this)
|
218
260
|
this.#abortController?.abort()
|
219
261
|
}
|
220
262
|
|
221
|
-
handleEvent(event: Event) {
|
263
|
+
async handleEvent(event: Event) {
|
222
264
|
if (!this.control) return
|
265
|
+
const showing = this.matches(':popover-open')
|
223
266
|
|
224
267
|
// Ensures that tooltip stays open when hovering between tooltip and element
|
225
268
|
// WCAG Success Criterion 1.4.13 Hoverable
|
226
|
-
|
227
|
-
|
228
|
-
} else if (event.type === 'blur') {
|
229
|
-
this.hiddenFromView = true
|
230
|
-
} else if (
|
269
|
+
const shouldShow = event.type === 'mouseenter' || event.type === 'focus'
|
270
|
+
const isMouseLeaveFromButton =
|
231
271
|
event.type === 'mouseleave' &&
|
232
272
|
(event as MouseEvent).relatedTarget !== this.control &&
|
233
273
|
(event as MouseEvent).relatedTarget !== this
|
234
|
-
)
|
235
|
-
|
236
|
-
|
237
|
-
|
274
|
+
const isEscapeKeydown = event.type === 'keydown' && (event as KeyboardEvent).key === 'Escape'
|
275
|
+
const isMouseDownOnButton = event.type === 'mousedown' && event.currentTarget === this.control
|
276
|
+
const isOpeningOtherPopover = event.type === 'beforetoggle' && event.currentTarget !== this
|
277
|
+
const shouldHide = isMouseLeaveFromButton || isEscapeKeydown || isMouseDownOnButton || isOpeningOtherPopover
|
278
|
+
|
279
|
+
await Promise.resolve()
|
280
|
+
if (!showing && shouldShow) {
|
281
|
+
this.showPopover()
|
282
|
+
} else if (showing && shouldHide) {
|
283
|
+
this.hidePopover()
|
284
|
+
}
|
285
|
+
|
286
|
+
if (event.type === 'toggle') {
|
287
|
+
this.#update((event as ToggleEvent).newState === 'open')
|
238
288
|
}
|
239
289
|
}
|
240
290
|
|
241
291
|
static observedAttributes = ['data-type', 'data-direction', 'id']
|
242
292
|
|
243
|
-
#update() {
|
244
|
-
if (
|
245
|
-
|
246
|
-
|
247
|
-
this
|
248
|
-
for (const tooltip of this.ownerDocument.querySelectorAll<ToolTipElement>(this.tagName)) {
|
249
|
-
if (tooltip !== this) tooltip.hiddenFromView = true
|
250
|
-
}
|
293
|
+
#update(isOpen: boolean) {
|
294
|
+
if (isOpen) {
|
295
|
+
openTooltips.add(this)
|
296
|
+
this.classList.remove(TOOLTIP_SR_ONLY_CLASS)
|
297
|
+
closeOpenTooltips(this)
|
251
298
|
this.#updatePosition()
|
299
|
+
} else {
|
300
|
+
openTooltips.delete(this)
|
301
|
+
this.classList.remove(...DIRECTION_CLASSES)
|
302
|
+
this.classList.add(TOOLTIP_SR_ONLY_CLASS)
|
252
303
|
}
|
253
304
|
}
|
254
305
|
|
@@ -326,11 +377,7 @@ class ToolTipElement extends HTMLElement {
|
|
326
377
|
|
327
378
|
#updatePosition() {
|
328
379
|
if (!this.control) return
|
329
|
-
if (!this.#allowUpdatePosition || this.
|
330
|
-
|
331
|
-
const TOOLTIP_OFFSET = 10
|
332
|
-
|
333
|
-
this.style.left = `0px` // Ensures we have reliable tooltip width in `getAnchoredPosition`
|
380
|
+
if (!this.#allowUpdatePosition || !this.matches(':popover-open')) return
|
334
381
|
|
335
382
|
const position = getAnchoredPosition(this, this.control, {
|
336
383
|
side: this.#side,
|
@@ -340,8 +387,8 @@ class ToolTipElement extends HTMLElement {
|
|
340
387
|
const anchorSide = position.anchorSide
|
341
388
|
const align = position.anchorAlign
|
342
389
|
|
343
|
-
this.style.top
|
344
|
-
this.style.left
|
390
|
+
this.style.setProperty('--tool-tip-position-top', `${position.top}px`)
|
391
|
+
this.style.setProperty('--tool-tip-position-left', `${position.left}px`)
|
345
392
|
|
346
393
|
let direction: Direction = 's'
|
347
394
|
|
@@ -110,6 +110,7 @@ module Primer
|
|
110
110
|
@system_arguments[:id] ||= self.class.generate_id
|
111
111
|
@system_arguments[:tag] = :"tool-tip"
|
112
112
|
@system_arguments[:for] = for_id
|
113
|
+
@system_arguments[:popover] = "manual"
|
113
114
|
@system_arguments[:classes] = class_names(
|
114
115
|
@system_arguments[:classes],
|
115
116
|
"sr-only"
|
@@ -1 +1 @@
|
|
1
|
-
.Link{color:var(--color-accent-fg)}.Link:hover{cursor:pointer
|
1
|
+
.Link{color:var(--color-accent-fg)}.Link:hover{cursor:pointer}.Link:focus,.Link:hover{text-decoration:underline}.Link:focus,.Link:focus-visible{outline-offset:0}.Link--primary{color:var(--color-fg-default)!important}.Link--primary:hover{color:var(--color-accent-fg)!important}.Link--secondary{color:var(--color-fg-muted)!important}.Link--secondary:hover{color:var(--color-accent-fg)!important}.Link--muted{color:var(--color-fg-muted)!important}.Link--muted:hover{text-decoration:none}.Link--muted:hover,.Link--onHover:hover{color:var(--color-accent-fg)!important}.Link--onHover:hover{cursor:pointer;text-decoration:underline}.Link--muted:hover [class*=color-fg],.Link--primary:hover [class*=color-fg],.Link--secondary:hover [class*=color-fg]{color:inherit!important}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["link.pcss"],"names":[],"mappings":"AAEA,MACE,
|
1
|
+
{"version":3,"sources":["link.pcss"],"names":[],"mappings":"AAEA,MACE,4BAeF,CAbE,YAEE,cACF,CAEA,wBAJE,yBAMF,CAEA,gCAEE,gBACF,CAGF,eACE,uCAKF,CAHE,qBACE,sCACF,CAGF,iBACE,qCAKF,CAHE,uBACE,sCACF,CAGF,aACE,qCAMF,CAJE,mBAEE,oBACF,CAMA,wCARE,sCAYF,CAJA,qBAGE,cAAe,CADf,yBAEF,CAQA,qHACE,uBACF","file":"link.css","sourcesContent":["/* Links */\n\n.Link {\n color: var(--color-accent-fg);\n\n &:hover {\n text-decoration: underline;\n cursor: pointer;\n }\n\n &:focus {\n text-decoration: underline;\n }\n\n &:focus,\n &:focus-visible {\n outline-offset: 0;\n }\n}\n\n.Link--primary {\n color: var(--color-fg-default) !important;\n\n &:hover {\n color: var(--color-accent-fg) !important;\n }\n}\n\n.Link--secondary {\n color: var(--color-fg-muted) !important;\n\n &:hover {\n color: var(--color-accent-fg) !important;\n }\n}\n\n.Link--muted {\n color: var(--color-fg-muted) !important;\n\n &:hover {\n color: var(--color-accent-fg) !important;\n text-decoration: none;\n }\n}\n\n/* Set the link color only on hover\n Useful when you want only part of a link to turn blue on hover */\n.Link--onHover {\n &:hover {\n color: var(--color-accent-fg) !important;\n text-decoration: underline;\n cursor: pointer;\n }\n}\n\n/* When using a color utility class inside of a link class\n color should change with link on hover. */\n.Link--secondary,\n.Link--primary,\n.Link--muted {\n &:hover [class*='color-fg'] {\n color: inherit !important;\n }\n}\n"]}
|
@@ -13,9 +13,6 @@ module Primer
|
|
13
13
|
:secondary => "Link--secondary"
|
14
14
|
}.freeze
|
15
15
|
|
16
|
-
DEFAULT_TAG = :a
|
17
|
-
TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
|
18
|
-
|
19
16
|
# `Tooltip` that appears on mouse hover or keyboard focus over the link. Use tooltips sparingly and as a last resort.
|
20
17
|
# **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
|
21
18
|
# The tooltip will appear adjacent to the anchor element. Both the tooltip and the anchor will be nested
|
@@ -55,30 +52,29 @@ module Primer
|
|
55
52
|
# Link
|
56
53
|
# <% end %>
|
57
54
|
#
|
58
|
-
# @param
|
59
|
-
# @param href [String] URL to be used for the Link. Required if tag is `:a`. If the requirements are not met an error will be raised in non production environments. In production, an empty link element will be rendered.
|
55
|
+
# @param href [String] URL to be used for the Link. Required. If the requirements are not met an error will be raised in non production environments. In production, an empty link element will be rendered.
|
60
56
|
# @param scheme [Symbol] <%= one_of(Primer::Beta::Link::SCHEME_MAPPINGS.keys) %>
|
61
57
|
# @param muted [Boolean] Uses light gray for Link color, and blue on hover.
|
62
58
|
# @param underline [Boolean] Whether or not to underline the link.
|
63
59
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
64
|
-
def initialize(href: nil,
|
65
|
-
@system_arguments = system_arguments
|
60
|
+
def initialize(href: nil, scheme: DEFAULT_SCHEME, muted: false, underline: true, **system_arguments)
|
61
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
66
62
|
|
67
63
|
@id = @system_arguments[:id]
|
68
64
|
|
69
|
-
@system_arguments[:tag] =
|
65
|
+
@system_arguments[:tag] = :a
|
70
66
|
@system_arguments[:href] = href
|
71
67
|
@system_arguments[:classes] = class_names(
|
72
68
|
@system_arguments[:classes],
|
73
69
|
SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)],
|
74
|
-
"Link"
|
70
|
+
"Link",
|
75
71
|
"Link--muted" => muted,
|
76
72
|
"no-underline" => !underline
|
77
73
|
)
|
78
74
|
end
|
79
75
|
|
80
76
|
def before_render
|
81
|
-
raise ArgumentError, "href is required
|
77
|
+
raise ArgumentError, "href is required" if @system_arguments[:href].nil? && !Rails.env.production?
|
82
78
|
end
|
83
79
|
|
84
80
|
def call
|
@@ -33,9 +33,18 @@ module Primer
|
|
33
33
|
scenarios = parent_scenario.type == :scenario_group ? parent_scenario.scenarios : [parent_scenario]
|
34
34
|
|
35
35
|
scenarios.map do |scenario|
|
36
|
+
snapshot_tag = scenario.tags.find { |tag| tag.tag_name == "snapshot" }
|
37
|
+
snapshot = if snapshot_tag.nil?
|
38
|
+
"false"
|
39
|
+
elsif snapshot_tag.text.blank?
|
40
|
+
"true"
|
41
|
+
else
|
42
|
+
snapshot_tag.text
|
43
|
+
end
|
36
44
|
{
|
37
45
|
preview_path: scenario.lookup_path,
|
38
46
|
name: scenario.name,
|
47
|
+
snapshot: snapshot,
|
39
48
|
skip_rules: Primer::Accessibility.axe_rules_to_skip(
|
40
49
|
component: component,
|
41
50
|
scenario_name: scenario.name
|
@@ -10,9 +10,7 @@ module ERBLint
|
|
10
10
|
include LinterRegistry
|
11
11
|
include Helpers::RuleHelpers
|
12
12
|
|
13
|
-
MIGRATE_TO_NEWER_TOOLTIP = ".tooltipped has been deprecated.
|
14
|
-
"Find alternatives in https://primer.style/design/guides/accessibility/tooltip-alternatives/. " \
|
15
|
-
"If you're setting a tooltip on an interactive element, use the latest tooltip in https://primer.style/view-components."
|
13
|
+
MIGRATE_TO_NEWER_TOOLTIP = ".tooltipped has been deprecated. There are major accessibility concerns with using this tooltip so please take action. See https://github.com/primer/view_components/blob/main/docs/content/guides/accessibility/tooltipped_migration.md."
|
16
14
|
TOOLTIPPED_RUBY_PATTERN = /classes:.*tooltipped|class:.*tooltipped/.freeze
|
17
15
|
|
18
16
|
def run(processed_source)
|