primer_view_components 0.0.69 → 0.0.72

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 %>