primer_view_components 0.0.69 → 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.
@@ -1,5 +1,5 @@
1
1
  declare type Direction = 'n' | 's' | 'e' | 'w' | 'ne' | 'se' | 'nw' | 'sw';
2
- declare class TooltipElement extends HTMLElement {
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
- TooltipElement: typeof TooltipElement;
20
+ ToolTipElement: typeof ToolTipElement;
22
21
  }
23
22
  }
24
23
  export {};
@@ -1,19 +1,18 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
2
- if (!privateMap.has(receiver)) {
3
- throw new TypeError("attempted to set private field on non-instance");
4
- }
5
- privateMap.set(receiver, value);
6
- return value;
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
6
  };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
9
- if (!privateMap.has(receiver)) {
10
- throw new TypeError("attempted to get private field on non-instance");
11
- }
12
- return privateMap.get(receiver);
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
13
11
  };
14
- var _abortController, _align, _side, _allowUpdatePosition;
12
+ var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_update, _ToolTipElement_updatePosition;
15
13
  import { getAnchoredPosition } from '@primer/behaviors';
16
14
  const TOOLTIP_OPEN_CLASS = 'tooltip-open';
15
+ const TOOLTIP_ARROW_EDGE_OFFSET = 6;
17
16
  const DIRECTION_CLASSES = [
18
17
  'tooltip-n',
19
18
  'tooltip-s',
@@ -24,20 +23,14 @@ const DIRECTION_CLASSES = [
24
23
  'tooltip-nw',
25
24
  'tooltip-sw'
26
25
  ];
27
- class TooltipElement extends HTMLElement {
26
+ class ToolTipElement extends HTMLElement {
28
27
  constructor() {
29
- super();
30
- _abortController.set(this, void 0);
31
- _align.set(this, 'center');
32
- _side.set(this, 'outside-bottom');
33
- _allowUpdatePosition.set(this, false);
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 `
@@ -60,7 +53,8 @@ class TooltipElement extends HTMLElement {
60
53
  opacity: 0;
61
54
  max-width: 250px;
62
55
  word-wrap: break-word;
63
- white-space: normal
56
+ white-space: normal;
57
+ width: max-content;
64
58
  }
65
59
 
66
60
  :host:before{
@@ -99,12 +93,16 @@ class TooltipElement extends HTMLElement {
99
93
  animation-delay: .4s
100
94
  }
101
95
 
96
+ :host(.tooltip-s):before,
97
+ :host(.tooltip-n):before {
98
+ right: 50%;
99
+ margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
100
+ }
101
+
102
102
  :host(.tooltip-s):before,
103
103
  :host(.tooltip-se):before,
104
104
  :host(.tooltip-sw):before {
105
- right: 50%;
106
105
  bottom: 100%;
107
- margin-right: -6px;
108
106
  border-bottom-color: var(--color-neutral-emphasis-plus)
109
107
  }
110
108
 
@@ -118,8 +116,6 @@ class TooltipElement extends HTMLElement {
118
116
  :host(.tooltip-ne):before,
119
117
  :host(.tooltip-nw):before {
120
118
  top: 100%;
121
- right: 50%;
122
- margin-right: -6px;
123
119
  border-top-color: var(--color-neutral-emphasis-plus)
124
120
  }
125
121
 
@@ -131,13 +127,14 @@ class TooltipElement extends HTMLElement {
131
127
 
132
128
  :host(.tooltip-se):before,
133
129
  :host(.tooltip-ne):before {
134
- right: auto
130
+ left: 0;
131
+ margin-left: ${TOOLTIP_ARROW_EDGE_OFFSET}px;
135
132
  }
136
133
 
137
134
  :host(.tooltip-sw):before,
138
135
  :host(.tooltip-nw):before {
139
136
  right: 0;
140
- margin-right: 6px
137
+ margin-right: ${TOOLTIP_ARROW_EDGE_OFFSET}px;
141
138
  }
142
139
 
143
140
  :host(.tooltip-w):before {
@@ -181,27 +178,35 @@ class TooltipElement extends HTMLElement {
181
178
  }
182
179
  connectedCallback() {
183
180
  var _a;
181
+ const shadow = this.attachShadow({ mode: 'open' });
182
+ shadow.innerHTML = `
183
+ <style>
184
+ ${this.styles()}
185
+ </style>
186
+ <slot></slot>
187
+ `;
184
188
  this.hidden = true;
185
- __classPrivateFieldSet(this, _allowUpdatePosition, true);
189
+ __classPrivateFieldSet(this, _ToolTipElement_allowUpdatePosition, true, "f");
186
190
  if (!this.id) {
187
191
  this.id = `tooltip-${Date.now()}-${(Math.random() * 10000).toFixed(0)}`;
188
192
  }
189
193
  if (!this.control)
190
194
  return;
191
195
  this.setAttribute('role', 'tooltip');
192
- (_a = __classPrivateFieldGet(this, _abortController)) === null || _a === void 0 ? void 0 : _a.abort();
193
- __classPrivateFieldSet(this, _abortController, new AbortController());
194
- const { signal } = __classPrivateFieldGet(this, _abortController);
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");
195
199
  this.addEventListener('mouseleave', this, { signal });
196
200
  this.control.addEventListener('mouseenter', this, { signal });
197
201
  this.control.addEventListener('mouseleave', this, { signal });
198
202
  this.control.addEventListener('focus', this, { signal });
199
203
  this.control.addEventListener('blur', this, { signal });
200
204
  this.ownerDocument.addEventListener('keydown', this, { signal });
205
+ __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
201
206
  }
202
207
  disconnectedCallback() {
203
208
  var _a;
204
- (_a = __classPrivateFieldGet(this, _abortController)) === null || _a === void 0 ? void 0 : _a.abort();
209
+ (_a = __classPrivateFieldGet(this, _ToolTipElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
205
210
  }
206
211
  handleEvent(event) {
207
212
  if (!this.control)
@@ -236,146 +241,108 @@ class TooltipElement extends HTMLElement {
236
241
  this.control.setAttribute('aria-describedby', describedBy);
237
242
  }
238
243
  }
239
- else if (name === 'hidden') {
240
- if (this.hidden) {
241
- this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES);
242
- }
243
- else {
244
- this.classList.add(TOOLTIP_OPEN_CLASS);
245
- for (const tooltip of this.ownerDocument.querySelectorAll(this.tagName)) {
246
- if (tooltip !== this)
247
- tooltip.hidden = true;
248
- }
249
- this..call(this);
250
- }
244
+ else if (this.isConnected && name === 'hidden') {
245
+ __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
251
246
  }
252
247
  else if (name === 'data-direction') {
253
248
  this.classList.remove(...DIRECTION_CLASSES);
254
249
  const direction = this.direction;
255
250
  if (direction === 'n') {
256
- __classPrivateFieldSet(this, _align, 'center');
257
- __classPrivateFieldSet(this, _side, 'outside-top');
251
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
252
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
258
253
  }
259
254
  else if (direction === 'ne') {
260
- __classPrivateFieldSet(this, _align, 'start');
261
- __classPrivateFieldSet(this, _side, 'outside-top');
255
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'start', "f");
256
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
262
257
  }
263
258
  else if (direction === 'e') {
264
- __classPrivateFieldSet(this, _align, 'center');
265
- __classPrivateFieldSet(this, _side, 'outside-right');
259
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
260
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-right', "f");
266
261
  }
267
262
  else if (direction === 'se') {
268
- __classPrivateFieldSet(this, _align, 'start');
269
- __classPrivateFieldSet(this, _side, 'outside-bottom');
263
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'start', "f");
264
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
270
265
  }
271
266
  else if (direction === 's') {
272
- __classPrivateFieldSet(this, _align, 'center');
273
- __classPrivateFieldSet(this, _side, 'outside-bottom');
267
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
268
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
274
269
  }
275
270
  else if (direction === 'sw') {
276
- __classPrivateFieldSet(this, _align, 'end');
277
- __classPrivateFieldSet(this, _side, 'outside-bottom');
271
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'end', "f");
272
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-bottom', "f");
278
273
  }
279
274
  else if (direction === 'w') {
280
- __classPrivateFieldSet(this, _align, 'center');
281
- __classPrivateFieldSet(this, _side, 'outside-left');
275
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'center', "f");
276
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-left', "f");
282
277
  }
283
278
  else if (direction === 'nw') {
284
- __classPrivateFieldSet(this, _align, 'end');
285
- __classPrivateFieldSet(this, _side, 'outside-top');
279
+ __classPrivateFieldSet(this, _ToolTipElement_align, 'end', "f");
280
+ __classPrivateFieldSet(this, _ToolTipElement_side, 'outside-top', "f");
286
281
  }
287
282
  }
288
283
  }
289
- // `getAnchoredPosition` may calibrate `anchoredSide` but does not recalibrate `align`.
290
- // Therefore, we need to determine which `align` is best based on the initial `getAnchoredPosition` calcluation.
291
- // Related: https://github.com/primer/behaviors/issues/63
292
- (anchorSide) {
293
- if (!this.control)
294
- return;
295
- const tooltipPosition = this.getBoundingClientRect();
296
- const targetPosition = this.control.getBoundingClientRect();
297
- const tooltipWidth = tooltipPosition.width;
298
- const tooltipCenter = tooltipPosition.left + tooltipWidth / 2;
299
- const targetCenter = targetPosition.x + targetPosition.width / 2;
300
- if (Math.abs(tooltipCenter - targetCenter) < 2 || anchorSide === 'outside-left' || anchorSide === 'outside-right') {
301
- return 'center';
302
- }
303
- else if (tooltipPosition.left === targetPosition.left) {
304
- return 'start';
284
+ }
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);
288
+ }
289
+ else {
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;
305
294
  }
306
- else if (tooltipPosition.right === targetPosition.right) {
307
- return 'end';
295
+ __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updatePosition).call(this);
296
+ }
297
+ }, _ToolTipElement_updatePosition = function _ToolTipElement_updatePosition() {
298
+ if (!this.control)
299
+ return;
300
+ if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || this.hidden)
301
+ return;
302
+ const TOOLTIP_OFFSET = 10;
303
+ this.style.left = `0px`; // Ensures we have reliable tooltip width in `getAnchoredPosition`
304
+ const position = getAnchoredPosition(this, this.control, {
305
+ side: __classPrivateFieldGet(this, _ToolTipElement_side, "f"),
306
+ align: __classPrivateFieldGet(this, _ToolTipElement_align, "f"),
307
+ anchorOffset: TOOLTIP_OFFSET
308
+ });
309
+ const anchorSide = position.anchorSide;
310
+ const align = position.anchorAlign;
311
+ this.style.top = `${position.top}px`;
312
+ this.style.left = `${position.left}px`;
313
+ let direction = 's';
314
+ if (anchorSide === 'outside-left') {
315
+ direction = 'w';
316
+ }
317
+ else if (anchorSide === 'outside-right') {
318
+ direction = 'e';
319
+ }
320
+ else if (anchorSide === 'outside-top') {
321
+ if (align === 'center') {
322
+ direction = 'n';
308
323
  }
309
- else if (tooltipCenter < targetCenter) {
310
- if (tooltipPosition.left === 0)
311
- return 'start';
312
- return 'end';
324
+ else if (align === 'start') {
325
+ direction = 'ne';
313
326
  }
314
327
  else {
315
- if (tooltipPosition.right === 0)
316
- return 'end';
317
- return 'start';
328
+ direction = 'nw';
318
329
  }
319
330
  }
320
- () {
321
- if (!this.control)
322
- return;
323
- if (!__classPrivateFieldGet(this, _allowUpdatePosition) || this.hidden)
324
- return;
325
- const TOOLTIP_OFFSET = 10;
326
- this.style.left = `0px`; // Ensures we have reliable tooltip width in `getAnchoredPosition`
327
- let position = getAnchoredPosition(this, this.control, {
328
- side: __classPrivateFieldGet(this, _side),
329
- align: __classPrivateFieldGet(this, _align),
330
- anchorOffset: TOOLTIP_OFFSET
331
- });
332
- let anchorSide = position.anchorSide;
333
- // We need to set tooltip position in order to determine ideal align.
334
- this.style.top = `${position.top}px`;
335
- this.style.left = `${position.left}px`;
336
- let direction = 's';
337
- const align = this..call(this, anchorSide);
338
- if (!align)
339
- return;
340
- this.style.left = `0px`; // Reset tooltip position again to ensure accurate width in `getAnchoredPosition`
341
- position = getAnchoredPosition(this, this.control, { side: anchorSide, align, anchorOffset: TOOLTIP_OFFSET });
342
- anchorSide = position.anchorSide;
343
- this.style.top = `${position.top}px`;
344
- this.style.left = `${position.left}px`;
345
- if (anchorSide === 'outside-left') {
346
- direction = 'w';
347
- }
348
- else if (anchorSide === 'outside-right') {
349
- direction = 'e';
331
+ else {
332
+ if (align === 'center') {
333
+ direction = 's';
350
334
  }
351
- else if (anchorSide === 'outside-top') {
352
- if (align === 'center') {
353
- direction = 'n';
354
- }
355
- else if (align === 'start') {
356
- direction = 'ne';
357
- }
358
- else {
359
- direction = 'nw';
360
- }
335
+ else if (align === 'start') {
336
+ direction = 'se';
361
337
  }
362
338
  else {
363
- if (align === 'center') {
364
- direction = 's';
365
- }
366
- else if (align === 'start') {
367
- direction = 'se';
368
- }
369
- else {
370
- direction = 'sw';
371
- }
339
+ direction = 'sw';
372
340
  }
373
- this.classList.add(`tooltip-${direction}`);
374
341
  }
375
- }
376
- _abortController = new WeakMap(), _align = new WeakMap(), _side = new WeakMap(), _allowUpdatePosition = new WeakMap();
377
- TooltipElement.observedAttributes = ['data-type', 'data-direction', 'id', 'hidden'];
342
+ this.classList.add(`tooltip-${direction}`);
343
+ };
344
+ ToolTipElement.observedAttributes = ['data-type', 'data-direction', 'id', 'hidden'];
378
345
  if (!window.customElements.get('tool-tip')) {
379
- window.TooltipElement = TooltipElement;
380
- window.customElements.define('tool-tip', TooltipElement);
346
+ window.ToolTipElement = ToolTipElement;
347
+ window.customElements.define('tool-tip', ToolTipElement);
381
348
  }
@@ -2,6 +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 = 6
5
6
 
6
7
  type Direction = 'n' | 's' | 'e' | 'w' | 'ne' | 'se' | 'nw' | 'sw'
7
8
 
@@ -16,7 +17,7 @@ const DIRECTION_CLASSES = [
16
17
  'tooltip-sw'
17
18
  ]
18
19
 
19
- class TooltipElement extends HTMLElement {
20
+ class ToolTipElement extends HTMLElement {
20
21
  styles() {
21
22
  return `
22
23
  :host {
@@ -38,7 +39,8 @@ class TooltipElement extends HTMLElement {
38
39
  opacity: 0;
39
40
  max-width: 250px;
40
41
  word-wrap: break-word;
41
- white-space: normal
42
+ white-space: normal;
43
+ width: max-content;
42
44
  }
43
45
 
44
46
  :host:before{
@@ -77,12 +79,16 @@ class TooltipElement extends HTMLElement {
77
79
  animation-delay: .4s
78
80
  }
79
81
 
82
+ :host(.tooltip-s):before,
83
+ :host(.tooltip-n):before {
84
+ right: 50%;
85
+ margin-right: -${TOOLTIP_ARROW_EDGE_OFFSET}px;
86
+ }
87
+
80
88
  :host(.tooltip-s):before,
81
89
  :host(.tooltip-se):before,
82
90
  :host(.tooltip-sw):before {
83
- right: 50%;
84
91
  bottom: 100%;
85
- margin-right: -6px;
86
92
  border-bottom-color: var(--color-neutral-emphasis-plus)
87
93
  }
88
94
 
@@ -96,8 +102,6 @@ class TooltipElement extends HTMLElement {
96
102
  :host(.tooltip-ne):before,
97
103
  :host(.tooltip-nw):before {
98
104
  top: 100%;
99
- right: 50%;
100
- margin-right: -6px;
101
105
  border-top-color: var(--color-neutral-emphasis-plus)
102
106
  }
103
107
 
@@ -109,13 +113,14 @@ class TooltipElement extends HTMLElement {
109
113
 
110
114
  :host(.tooltip-se):before,
111
115
  :host(.tooltip-ne):before {
112
- right: auto
116
+ left: 0;
117
+ margin-left: ${TOOLTIP_ARROW_EDGE_OFFSET}px;
113
118
  }
114
119
 
115
120
  :host(.tooltip-sw):before,
116
121
  :host(.tooltip-nw):before {
117
122
  right: 0;
118
- margin-right: 6px
123
+ margin-right: ${TOOLTIP_ARROW_EDGE_OFFSET}px;
119
124
  }
120
125
 
121
126
  :host(.tooltip-w):before {
@@ -170,8 +175,7 @@ class TooltipElement extends HTMLElement {
170
175
  return this.ownerDocument.getElementById(this.htmlFor)
171
176
  }
172
177
 
173
- constructor() {
174
- super()
178
+ connectedCallback() {
175
179
  const shadow = this.attachShadow({mode: 'open'})
176
180
  shadow.innerHTML = `
177
181
  <style>
@@ -179,9 +183,6 @@ class TooltipElement extends HTMLElement {
179
183
  </style>
180
184
  <slot></slot>
181
185
  `
182
- }
183
-
184
- connectedCallback() {
185
186
  this.hidden = true
186
187
  this.#allowUpdatePosition = true
187
188
 
@@ -203,6 +204,7 @@ class TooltipElement extends HTMLElement {
203
204
  this.control.addEventListener('focus', this, {signal})
204
205
  this.control.addEventListener('blur', this, {signal})
205
206
  this.ownerDocument.addEventListener('keydown', this, {signal})
207
+ this.#update()
206
208
  }
207
209
 
208
210
  disconnectedCallback() {
@@ -231,6 +233,18 @@ class TooltipElement extends HTMLElement {
231
233
 
232
234
  static observedAttributes = ['data-type', 'data-direction', 'id', 'hidden']
233
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
+
234
248
  attributeChangedCallback(name: string) {
235
249
  if (name === 'id' || name === 'data-type') {
236
250
  if (!this.id || !this.control) return
@@ -241,16 +255,8 @@ class TooltipElement extends HTMLElement {
241
255
  describedBy ? (describedBy = `${describedBy} ${this.id}`) : (describedBy = this.id)
242
256
  this.control.setAttribute('aria-describedby', describedBy)
243
257
  }
244
- } else if (name === 'hidden') {
245
- if (this.hidden) {
246
- this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES)
247
- } else {
248
- this.classList.add(TOOLTIP_OPEN_CLASS)
249
- for (const tooltip of this.ownerDocument.querySelectorAll<HTMLElement>(this.tagName)) {
250
- if (tooltip !== this) tooltip.hidden = true
251
- }
252
- this.#updatePosition()
253
- }
258
+ } else if (this.isConnected && name === 'hidden') {
259
+ this.#update()
254
260
  } else if (name === 'data-direction') {
255
261
  this.classList.remove(...DIRECTION_CLASSES)
256
262
  const direction = this.direction
@@ -282,34 +288,6 @@ class TooltipElement extends HTMLElement {
282
288
  }
283
289
  }
284
290
 
285
- // `getAnchoredPosition` may calibrate `anchoredSide` but does not recalibrate `align`.
286
- // Therefore, we need to determine which `align` is best based on the initial `getAnchoredPosition` calcluation.
287
- // Related: https://github.com/primer/behaviors/issues/63
288
- #adjustedAnchorAlignment(anchorSide: AnchorSide): AnchorAlignment | undefined {
289
- if (!this.control) return
290
-
291
- const tooltipPosition = this.getBoundingClientRect()
292
- const targetPosition = this.control.getBoundingClientRect()
293
- const tooltipWidth = tooltipPosition.width
294
-
295
- const tooltipCenter = tooltipPosition.left + tooltipWidth / 2
296
- const targetCenter = targetPosition.x + targetPosition.width / 2
297
-
298
- if (Math.abs(tooltipCenter - targetCenter) < 2 || anchorSide === 'outside-left' || anchorSide === 'outside-right') {
299
- return 'center'
300
- } else if (tooltipPosition.left === targetPosition.left) {
301
- return 'start'
302
- } else if (tooltipPosition.right === targetPosition.right) {
303
- return 'end'
304
- } else if (tooltipCenter < targetCenter) {
305
- if (tooltipPosition.left === 0) return 'start'
306
- return 'end'
307
- } else {
308
- if (tooltipPosition.right === 0) return 'end'
309
- return 'start'
310
- }
311
- }
312
-
313
291
  #updatePosition() {
314
292
  if (!this.control) return
315
293
  if (!this.#allowUpdatePosition || this.hidden) return
@@ -317,27 +295,19 @@ class TooltipElement extends HTMLElement {
317
295
  const TOOLTIP_OFFSET = 10
318
296
 
319
297
  this.style.left = `0px` // Ensures we have reliable tooltip width in `getAnchoredPosition`
320
- let position = getAnchoredPosition(this, this.control, {
298
+
299
+ const position = getAnchoredPosition(this, this.control, {
321
300
  side: this.#side,
322
301
  align: this.#align,
323
302
  anchorOffset: TOOLTIP_OFFSET
324
303
  })
325
- let anchorSide = position.anchorSide
304
+ const anchorSide = position.anchorSide
305
+ const align = position.anchorAlign
326
306
 
327
- // We need to set tooltip position in order to determine ideal align.
328
307
  this.style.top = `${position.top}px`
329
308
  this.style.left = `${position.left}px`
330
- let direction: Direction = 's'
331
-
332
- const align = this.#adjustedAnchorAlignment(anchorSide)
333
- if (!align) return
334
309
 
335
- this.style.left = `0px` // Reset tooltip position again to ensure accurate width in `getAnchoredPosition`
336
- position = getAnchoredPosition(this, this.control, {side: anchorSide, align, anchorOffset: TOOLTIP_OFFSET})
337
- anchorSide = position.anchorSide
338
-
339
- this.style.top = `${position.top}px`
340
- this.style.left = `${position.left}px`
310
+ let direction: Direction = 's'
341
311
 
342
312
  if (anchorSide === 'outside-left') {
343
313
  direction = 'w'
@@ -366,12 +336,12 @@ class TooltipElement extends HTMLElement {
366
336
  }
367
337
 
368
338
  if (!window.customElements.get('tool-tip')) {
369
- window.TooltipElement = TooltipElement
370
- window.customElements.define('tool-tip', TooltipElement)
339
+ window.ToolTipElement = ToolTipElement
340
+ window.customElements.define('tool-tip', ToolTipElement)
371
341
  }
372
342
 
373
343
  declare global {
374
344
  interface Window {
375
- TooltipElement: typeof TooltipElement
345
+ ToolTipElement: typeof ToolTipElement
376
346
  }
377
347
  }
@@ -70,6 +70,14 @@ module Primer
70
70
  # <%= render(Primer::Alpha::Tooltip.new(for_id: "Northwest", type: :description, text: "This is a Northwest-facing tooltip and is responsive.", direction: :nw)) %>
71
71
  # <%= render(Primer::ButtonComponent.new(id: "Southwest", m: 2)) { "Southwest" } %>
72
72
  # <%= render(Primer::Alpha::Tooltip.new(for_id: "Southwest", type: :description, text: "This is a Southwest-facing tooltip and is responsive.", direction: :sw)) %>
73
+ # @example With relative parent
74
+ # @description
75
+ # When the tooltip and trigger element have a parent container with `relative: position`, it should not affect width of the tooltip.
76
+ # @code
77
+ # <span style="position: relative;">
78
+ # <%= render(Primer::ButtonComponent.new(id: "test-button", scheme: :primary)) { "Test" } %>
79
+ # <%= render(Primer::Alpha::Tooltip.new(for_id: "test-button", type: :description, text: "This tooltip should take up the full width", direction: :ne)) %>
80
+ # </span>
73
81
  # @param for_id [String] The ID of the element that the tooltip should be attached to.
74
82
  # @param type [Symbol] <%= one_of(Primer::Alpha::Tooltip::TYPE_OPTIONS) %>
75
83
  # @param direction [Symbol] <%= one_of(Primer::Alpha::Tooltip::DIRECTION_OPTIONS) %>
@@ -1,14 +1,24 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <label for="<%= @input_id %>">
2
+ <label for="<%= @input_id %>" class="<%= @label_classes %>">
3
3
  <% if @is_label_visible %>
4
4
  <%= @label_text %>
5
5
  <% else %>
6
6
  <span class="sr-only"><%= @label_text %></span>
7
7
  <% end %>
8
- <% if icon.present? %>
9
- <%= icon %>
10
- <% end %>
11
8
  </label>
12
- <input id="<%= @input_id %>" name="<%= @input_id %>" type="text" class="form-control" autocomplete="off">
13
- <%= results %>
9
+ <span class="autocomplete-body">
10
+ <% if @with_icon %>
11
+ <div class="form-control autocomplete-embedded-icon-wrap">
12
+ <%= render Primer::OcticonComponent.new(:search) %>
13
+ <% end %>
14
+ <%= input %>
15
+ <% if @is_clearable %>
16
+ <button id="<%= @input_id %>-clear" class="btn-octicon" aria-label="Clear"><%= primer_octicon "x" %></button>
17
+ <% end %>
18
+ <% if @with_icon %>
19
+ </div>
20
+ <% end %>
21
+ <%= results %>
22
+ </span>
23
+ <div id="<%= @list_id %>-feedback" class="sr-only"></div>
14
24
  <% end %>