@primer/view-components 0.0.91 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ export declare class ModalDialogElement extends HTMLElement {
2
+ #private;
3
+ get open(): boolean;
4
+ set open(value: boolean);
5
+ get showButtons(): NodeList;
6
+ connectedCallback(): void;
7
+ disconnectedCallback(): void;
8
+ show(): void;
9
+ close(closed?: boolean): void;
10
+ }
11
+ declare global {
12
+ interface Window {
13
+ ModalDialogElement: typeof ModalDialogElement;
14
+ }
15
+ interface HTMLElementTagNameMap {
16
+ 'modal-dialog': ModalDialogElement;
17
+ }
18
+ }
@@ -0,0 +1,143 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ 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");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ 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");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _ModalDialogElement_instances, _ModalDialogElement_focusAbortController, _ModalDialogElement_abortController, _ModalDialogElement_openButton, _ModalDialogElement_shouldTryLoadingFragment, _ModalDialogElement_overlayBackdrop_get, _ModalDialogElement_keydown;
13
+ import { focusTrap } from '@primer/behaviors';
14
+ import { getFocusableChild } from '@primer/behaviors/utils';
15
+ function focusIfNeeded(elem) {
16
+ if (document.activeElement !== elem) {
17
+ elem === null || elem === void 0 ? void 0 : elem.focus();
18
+ }
19
+ }
20
+ export class ModalDialogElement extends HTMLElement {
21
+ constructor() {
22
+ super(...arguments);
23
+ _ModalDialogElement_instances.add(this);
24
+ //TODO: Do we remove the abortController from focusTrap?
25
+ _ModalDialogElement_focusAbortController.set(this, new AbortController());
26
+ _ModalDialogElement_abortController.set(this, null);
27
+ _ModalDialogElement_openButton.set(this, void 0);
28
+ _ModalDialogElement_shouldTryLoadingFragment.set(this, true);
29
+ }
30
+ get open() {
31
+ return this.hasAttribute('open');
32
+ }
33
+ set open(value) {
34
+ var _a, _b, _c, _d;
35
+ if (value) {
36
+ if (this.open)
37
+ return;
38
+ this.setAttribute('open', '');
39
+ (_a = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay--hidden');
40
+ document.body.style.overflow = 'hidden';
41
+ if (__classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal.aborted) {
42
+ __classPrivateFieldSet(this, _ModalDialogElement_focusAbortController, new AbortController(), "f");
43
+ }
44
+ focusTrap(this, undefined, __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal);
45
+ }
46
+ else {
47
+ if (!this.open)
48
+ return;
49
+ this.removeAttribute('open');
50
+ (_b = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _b === void 0 ? void 0 : _b.classList.add('Overlay--hidden');
51
+ document.body.style.overflow = 'initial';
52
+ __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").abort();
53
+ // if #openButton is a child of a menu, we need to focus a suitable child of the menu
54
+ // element since it is expected for the menu to close on click
55
+ const menu = ((_c = __classPrivateFieldGet(this, _ModalDialogElement_openButton, "f")) === null || _c === void 0 ? void 0 : _c.closest('details')) || ((_d = __classPrivateFieldGet(this, _ModalDialogElement_openButton, "f")) === null || _d === void 0 ? void 0 : _d.closest('action-menu'));
56
+ if (menu) {
57
+ focusIfNeeded(getFocusableChild(menu));
58
+ }
59
+ else {
60
+ focusIfNeeded(__classPrivateFieldGet(this, _ModalDialogElement_openButton, "f"));
61
+ }
62
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, undefined, "f");
63
+ }
64
+ }
65
+ get showButtons() {
66
+ // Dialogs may also be opened from any arbitrary button with a matching show-dialog-id data attribute
67
+ return document.querySelectorAll(`button[data-show-dialog-id='${this.id}']`);
68
+ }
69
+ connectedCallback() {
70
+ if (!this.hasAttribute('role'))
71
+ this.setAttribute('role', 'dialog');
72
+ const { signal } = (__classPrivateFieldSet(this, _ModalDialogElement_abortController, new AbortController(), "f"));
73
+ this.ownerDocument.addEventListener('click', event => {
74
+ const target = event.target;
75
+ const clickOutsideDialog = target.closest(this.tagName) !== this;
76
+ const button = target === null || target === void 0 ? void 0 : target.closest('button');
77
+ // go over this logic:
78
+ if (!button) {
79
+ if (clickOutsideDialog) {
80
+ // This click is outside the dialog
81
+ this.close();
82
+ }
83
+ return;
84
+ }
85
+ let dialogId = button.getAttribute('data-close-dialog-id');
86
+ if (dialogId === this.id) {
87
+ this.close();
88
+ }
89
+ dialogId = button.getAttribute('data-submit-dialog-id');
90
+ if (dialogId === this.id) {
91
+ this.close(true);
92
+ }
93
+ dialogId = button.getAttribute('data-show-dialog-id');
94
+ if (dialogId === this.id) {
95
+ //TODO: see if I can remove this
96
+ event.stopPropagation();
97
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, button, "f");
98
+ this.show();
99
+ }
100
+ }, { signal });
101
+ this.addEventListener('keydown', e => __classPrivateFieldGet(this, _ModalDialogElement_instances, "m", _ModalDialogElement_keydown).call(this, e));
102
+ }
103
+ disconnectedCallback() {
104
+ var _a;
105
+ (_a = __classPrivateFieldGet(this, _ModalDialogElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
106
+ }
107
+ show() {
108
+ this.open = true;
109
+ }
110
+ close(closed = false) {
111
+ if (this.open === false)
112
+ return;
113
+ const eventType = closed ? 'close' : 'cancel';
114
+ const dialogEvent = new Event(eventType);
115
+ this.dispatchEvent(dialogEvent);
116
+ this.open = false;
117
+ }
118
+ }
119
+ _ModalDialogElement_focusAbortController = new WeakMap(), _ModalDialogElement_abortController = new WeakMap(), _ModalDialogElement_openButton = new WeakMap(), _ModalDialogElement_shouldTryLoadingFragment = new WeakMap(), _ModalDialogElement_instances = new WeakSet(), _ModalDialogElement_overlayBackdrop_get = function _ModalDialogElement_overlayBackdrop_get() {
120
+ var _a;
121
+ if ((_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.hasAttribute('data-modal-dialog-overlay')) {
122
+ return this.parentElement;
123
+ }
124
+ return null;
125
+ }, _ModalDialogElement_keydown = function _ModalDialogElement_keydown(event) {
126
+ if (!(event instanceof KeyboardEvent))
127
+ return;
128
+ if (event.isComposing)
129
+ return;
130
+ switch (event.key) {
131
+ case 'Escape':
132
+ if (this.open) {
133
+ this.close();
134
+ event.preventDefault();
135
+ event.stopPropagation();
136
+ }
137
+ break;
138
+ }
139
+ };
140
+ if (!window.customElements.get('modal-dialog')) {
141
+ window.ModalDialogElement = ModalDialogElement;
142
+ window.customElements.define('modal-dialog', ModalDialogElement);
143
+ }
@@ -0,0 +1,28 @@
1
+ export declare class ToggleSwitchElement extends HTMLElement {
2
+ switch: HTMLElement;
3
+ loadingSpinner: HTMLElement;
4
+ errorIcon: HTMLElement;
5
+ get src(): string | null;
6
+ get csrf(): string | null;
7
+ get csrfField(): string;
8
+ isRemote(): boolean;
9
+ toggle(): void;
10
+ turnOn(): void;
11
+ turnOff(): void;
12
+ isOn(): boolean;
13
+ isOff(): boolean;
14
+ isDisabled(): boolean;
15
+ disable(): void;
16
+ enable(): void;
17
+ private performToggle;
18
+ private setLoadingState;
19
+ private setSuccessState;
20
+ private setErrorState;
21
+ private setFinishedState;
22
+ private check;
23
+ }
24
+ declare global {
25
+ interface Window {
26
+ ToggleSwitchElement: typeof ToggleSwitchElement;
27
+ }
28
+ }
@@ -0,0 +1,135 @@
1
+ /* eslint-disable custom-elements/expose-class-on-global */
2
+ /* eslint-disable custom-elements/define-tag-after-class-definition */
3
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
4
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
5
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
8
+ };
9
+ import { controller, target } from '@github/catalyst';
10
+ import { debounce } from '@github/mini-throttle/decorators';
11
+ let ToggleSwitchElement = class ToggleSwitchElement extends HTMLElement {
12
+ get src() {
13
+ const src = this.getAttribute('src');
14
+ if (!src)
15
+ return null;
16
+ const link = this.ownerDocument.createElement('a');
17
+ link.href = src;
18
+ return link.href;
19
+ }
20
+ get csrf() {
21
+ const csrfElement = this.querySelector('[data-csrf]');
22
+ return this.getAttribute('csrf') || (csrfElement instanceof HTMLInputElement && csrfElement.value) || null;
23
+ }
24
+ get csrfField() {
25
+ // the authenticity token is passed into the element and is not generated in js land
26
+ return this.getAttribute('csrf-field') || 'authenticity_token';
27
+ }
28
+ isRemote() {
29
+ return this.src != null;
30
+ }
31
+ toggle() {
32
+ if (this.isRemote()) {
33
+ this.setLoadingState();
34
+ this.check();
35
+ }
36
+ else {
37
+ this.performToggle();
38
+ }
39
+ }
40
+ turnOn() {
41
+ if (this.isDisabled()) {
42
+ return;
43
+ }
44
+ this.switch.setAttribute('aria-checked', 'true');
45
+ this.classList.add('ToggleSwitch--checked');
46
+ }
47
+ turnOff() {
48
+ if (this.isDisabled()) {
49
+ return;
50
+ }
51
+ this.switch.setAttribute('aria-checked', 'false');
52
+ this.classList.remove('ToggleSwitch--checked');
53
+ }
54
+ isOn() {
55
+ return this.switch.getAttribute('aria-checked') === 'true';
56
+ }
57
+ isOff() {
58
+ return !this.isOn();
59
+ }
60
+ isDisabled() {
61
+ return this.switch.getAttribute('aria-disabled') === 'true';
62
+ }
63
+ disable() {
64
+ this.switch.setAttribute('aria-disabled', 'true');
65
+ }
66
+ enable() {
67
+ this.switch.setAttribute('aria-disabled', 'false');
68
+ }
69
+ performToggle() {
70
+ if (this.isOn()) {
71
+ this.turnOff();
72
+ }
73
+ else {
74
+ this.turnOn();
75
+ }
76
+ }
77
+ setLoadingState() {
78
+ this.disable();
79
+ this.errorIcon.setAttribute('hidden', 'hidden');
80
+ this.loadingSpinner.removeAttribute('hidden');
81
+ }
82
+ setSuccessState() {
83
+ this.setFinishedState(false);
84
+ }
85
+ setErrorState() {
86
+ this.setFinishedState(true);
87
+ }
88
+ setFinishedState(error) {
89
+ if (error) {
90
+ this.errorIcon.removeAttribute('hidden');
91
+ }
92
+ this.loadingSpinner.setAttribute('hidden', 'hidden');
93
+ this.enable();
94
+ }
95
+ async check() {
96
+ const body = new FormData();
97
+ if (this.csrf) {
98
+ body.append(this.csrfField, this.csrf);
99
+ }
100
+ body.append('value', this.isOn() ? '1' : '0');
101
+ try {
102
+ const response = await fetch(this.src, {
103
+ credentials: 'same-origin',
104
+ method: 'POST',
105
+ body
106
+ });
107
+ if (response.ok) {
108
+ this.setSuccessState();
109
+ this.performToggle();
110
+ }
111
+ else {
112
+ this.setErrorState();
113
+ }
114
+ }
115
+ catch (error) {
116
+ this.setErrorState();
117
+ }
118
+ }
119
+ };
120
+ __decorate([
121
+ target
122
+ ], ToggleSwitchElement.prototype, "switch", void 0);
123
+ __decorate([
124
+ target
125
+ ], ToggleSwitchElement.prototype, "loadingSpinner", void 0);
126
+ __decorate([
127
+ target
128
+ ], ToggleSwitchElement.prototype, "errorIcon", void 0);
129
+ __decorate([
130
+ debounce(300)
131
+ ], ToggleSwitchElement.prototype, "check", null);
132
+ ToggleSwitchElement = __decorate([
133
+ controller
134
+ ], ToggleSwitchElement);
135
+ export { ToggleSwitchElement };
@@ -9,6 +9,8 @@ declare class ToolTipElement extends HTMLElement {
9
9
  get direction(): Direction;
10
10
  set direction(value: Direction);
11
11
  get control(): HTMLElement | null;
12
+ set hiddenFromView(value: true | false);
13
+ get hiddenFromView(): true | false;
12
14
  connectedCallback(): void;
13
15
  disconnectedCallback(): void;
14
16
  handleEvent(event: Event): void;
@@ -1,18 +1,19 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ 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");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
1
6
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
7
  if (kind === "m") throw new TypeError("Private method is not writable");
3
8
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
9
  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
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
11
  };
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);
11
- };
12
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
15
  const TOOLTIP_ARROW_EDGE_OFFSET = 6;
16
+ const TOOLTIP_SR_ONLY_CLASS = 'sr-only';
16
17
  const DIRECTION_CLASSES = [
17
18
  'tooltip-n',
18
19
  'tooltip-s',
@@ -176,6 +177,14 @@ class ToolTipElement extends HTMLElement {
176
177
  get control() {
177
178
  return this.ownerDocument.getElementById(this.htmlFor);
178
179
  }
180
+ set hiddenFromView(value) {
181
+ this.classList.toggle(TOOLTIP_SR_ONLY_CLASS, value);
182
+ if (this.isConnected)
183
+ __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
184
+ }
185
+ get hiddenFromView() {
186
+ return this.classList.contains(TOOLTIP_SR_ONLY_CLASS);
187
+ }
179
188
  connectedCallback() {
180
189
  var _a;
181
190
  if (!this.shadowRoot) {
@@ -188,7 +197,7 @@ class ToolTipElement extends HTMLElement {
188
197
  <slot></slot>
189
198
  `;
190
199
  }
191
- this.hidden = true;
200
+ this.hiddenFromView = true;
192
201
  __classPrivateFieldSet(this, _ToolTipElement_allowUpdatePosition, true, "f");
193
202
  if (!this.id) {
194
203
  this.id = `tooltip-${Date.now()}-${(Math.random() * 10000).toFixed(0)}`;
@@ -216,19 +225,19 @@ class ToolTipElement extends HTMLElement {
216
225
  return;
217
226
  // Ensures that tooltip stays open when hovering between tooltip and element
218
227
  // WCAG Success Criterion 1.4.13 Hoverable
219
- if ((event.type === 'mouseenter' || event.type === 'focus') && this.hidden) {
220
- this.hidden = false;
228
+ if ((event.type === 'mouseenter' || event.type === 'focus') && this.hiddenFromView) {
229
+ this.hiddenFromView = false;
221
230
  }
222
231
  else if (event.type === 'blur') {
223
- this.hidden = true;
232
+ this.hiddenFromView = true;
224
233
  }
225
234
  else if (event.type === 'mouseleave' &&
226
235
  event.relatedTarget !== this.control &&
227
236
  event.relatedTarget !== this) {
228
- this.hidden = true;
237
+ this.hiddenFromView = true;
229
238
  }
230
- else if (event.type === 'keydown' && event.key === 'Escape' && !this.hidden) {
231
- this.hidden = true;
239
+ else if (event.type === 'keydown' && event.key === 'Escape' && !this.hiddenFromView) {
240
+ this.hiddenFromView = true;
232
241
  }
233
242
  }
234
243
  attributeChangedCallback(name) {
@@ -236,7 +245,15 @@ class ToolTipElement extends HTMLElement {
236
245
  if (!this.id || !this.control)
237
246
  return;
238
247
  if (this.type === 'label') {
239
- this.control.setAttribute('aria-labelledby', this.id);
248
+ let labelledBy = this.control.getAttribute('aria-labelledby');
249
+ if (labelledBy) {
250
+ labelledBy = `${labelledBy} ${this.id}`;
251
+ }
252
+ else {
253
+ labelledBy = this.id;
254
+ }
255
+ this.control.setAttribute('aria-labelledby', labelledBy);
256
+ // Prevent duplicate accessible name announcements.
240
257
  this.setAttribute('aria-hidden', 'true');
241
258
  }
242
259
  else {
@@ -245,9 +262,6 @@ class ToolTipElement extends HTMLElement {
245
262
  this.control.setAttribute('aria-describedby', describedBy);
246
263
  }
247
264
  }
248
- else if (this.isConnected && name === 'hidden') {
249
- __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_update).call(this);
250
- }
251
265
  else if (name === 'data-direction') {
252
266
  this.classList.remove(...DIRECTION_CLASSES);
253
267
  const direction = this.direction;
@@ -287,21 +301,21 @@ class ToolTipElement extends HTMLElement {
287
301
  }
288
302
  }
289
303
  _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() {
290
- if (this.hidden) {
304
+ if (this.hiddenFromView) {
291
305
  this.classList.remove(TOOLTIP_OPEN_CLASS, ...DIRECTION_CLASSES);
292
306
  }
293
307
  else {
294
308
  this.classList.add(TOOLTIP_OPEN_CLASS);
295
309
  for (const tooltip of this.ownerDocument.querySelectorAll(this.tagName)) {
296
310
  if (tooltip !== this)
297
- tooltip.hidden = true;
311
+ tooltip.hiddenFromView = true;
298
312
  }
299
313
  __classPrivateFieldGet(this, _ToolTipElement_instances, "m", _ToolTipElement_updatePosition).call(this);
300
314
  }
301
315
  }, _ToolTipElement_updatePosition = function _ToolTipElement_updatePosition() {
302
316
  if (!this.control)
303
317
  return;
304
- if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || this.hidden)
318
+ if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || this.hiddenFromView)
305
319
  return;
306
320
  const TOOLTIP_OFFSET = 10;
307
321
  this.style.left = `0px`; // Ensures we have reliable tooltip width in `getAnchoredPosition`
@@ -345,7 +359,7 @@ _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new Wea
345
359
  }
346
360
  this.classList.add(`tooltip-${direction}`);
347
361
  };
348
- ToolTipElement.observedAttributes = ['data-type', 'data-direction', 'id', 'hidden'];
362
+ ToolTipElement.observedAttributes = ['data-type', 'data-direction', 'id'];
349
363
  if (!window.customElements.get('tool-tip')) {
350
364
  window.ToolTipElement = ToolTipElement;
351
365
  window.customElements.define('tool-tip', ToolTipElement);
@@ -5,4 +5,5 @@ import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
7
  import './dropdown';
8
+ import './alpha/toggle-switch-element';
8
9
  import './alpha/tool-tip-element';
@@ -5,4 +5,5 @@ import './time_ago_component';
5
5
  import './local_time';
6
6
  import './image_crop';
7
7
  import './dropdown';
8
+ import './alpha/toggle-switch-element';
8
9
  import './alpha/tool-tip-element';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primer/view-components",
3
- "version": "0.0.91",
3
+ "version": "0.0.92",
4
4
  "description": "ViewComponents for the Primer Design System",
5
5
  "main": "app/assets/javascripts/primer_view_components.js",
6
6
  "module": "app/components/primer/primer.js",
@@ -37,9 +37,11 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@github/auto-complete-element": "^3.3.4",
40
+ "@github/catalyst": "^1.6.0",
40
41
  "@github/clipboard-copy-element": "^1.1.2",
41
42
  "@github/details-menu-element": "^1.0.12",
42
43
  "@github/image-crop-element": "^5.0.0",
44
+ "@github/mini-throttle": "^2.1.0",
43
45
  "@github/tab-container-element": "^3.1.2",
44
46
  "@github/time-elements": "^3.1.2",
45
47
  "@primer/behaviors": "^1.1.3"