@primer/view-components 0.36.1 → 0.36.2-rc.cf1c67eb

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  import '@oddbird/popover-polyfill';
2
2
  import type { IncludeFragmentElement } from '@github/include-fragment-element';
3
+ import AnchoredPositionElement from '../../anchored_position';
3
4
  type SelectVariant = 'none' | 'single' | 'multiple' | null;
4
5
  type SelectedItem = {
5
6
  label: string | null | undefined;
@@ -9,6 +10,7 @@ type SelectedItem = {
9
10
  export declare class ActionMenuElement extends HTMLElement {
10
11
  #private;
11
12
  includeFragment: IncludeFragmentElement;
13
+ overlay: AnchoredPositionElement;
12
14
  get selectVariant(): SelectVariant;
13
15
  set selectVariant(variant: SelectVariant);
14
16
  get dynamicLabelPrefix(): string;
@@ -15,9 +15,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
15
15
  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");
16
16
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
17
17
  };
18
- var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isAnchorActivationViaSpace, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get;
18
+ var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_intersectionObserver, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isAnchorActivationViaSpace, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get;
19
19
  import { controller, target } from '@github/catalyst';
20
20
  import '@oddbird/popover-polyfill';
21
+ import { observeMutationsUntilConditionMet } from '../../utils';
21
22
  const validSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]'];
22
23
  const menuItemSelectors = validSelectors.map(selector => `:not([hidden]) > ${selector}`);
23
24
  let ActionMenuElement = class ActionMenuElement extends HTMLElement {
@@ -28,6 +29,7 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
28
29
  _ActionMenuElement_originalLabel.set(this, '');
29
30
  _ActionMenuElement_inputName.set(this, '');
30
31
  _ActionMenuElement_invokerBeingClicked.set(this, false);
32
+ _ActionMenuElement_intersectionObserver.set(this, void 0);
31
33
  }
32
34
  get selectVariant() {
33
35
  return this.getAttribute('data-select-variant');
@@ -103,6 +105,30 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
103
105
  signal,
104
106
  });
105
107
  }
108
+ // The code below updates the menu (i.e. overlay) position whenever the invoker button
109
+ // changes position within its scroll container.
110
+ //
111
+ // See: https://github.com/primer/view_components/issues/3175
112
+ const scrollUpdater = () => {
113
+ if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isOpen).call(this)) {
114
+ this.overlay?.update();
115
+ }
116
+ };
117
+ __classPrivateFieldSet(this, _ActionMenuElement_intersectionObserver, new IntersectionObserver(entries => {
118
+ for (const entry of entries) {
119
+ const elem = entry.target;
120
+ if (elem === this.invokerElement) {
121
+ if (entry.isIntersecting) {
122
+ // eslint-disable-next-line github/prefer-observers
123
+ window.addEventListener('scroll', scrollUpdater, { capture: true });
124
+ }
125
+ else {
126
+ window.removeEventListener('scroll', scrollUpdater, { capture: true });
127
+ }
128
+ }
129
+ }
130
+ }), "f");
131
+ observeMutationsUntilConditionMet(this, () => Boolean(this.invokerElement), () => __classPrivateFieldGet(this, _ActionMenuElement_intersectionObserver, "f").observe(this.invokerElement));
106
132
  }
107
133
  disconnectedCallback() {
108
134
  __classPrivateFieldGet(this, _ActionMenuElement_abortController, "f").abort();
@@ -240,6 +266,7 @@ _ActionMenuElement_abortController = new WeakMap();
240
266
  _ActionMenuElement_originalLabel = new WeakMap();
241
267
  _ActionMenuElement_inputName = new WeakMap();
242
268
  _ActionMenuElement_invokerBeingClicked = new WeakMap();
269
+ _ActionMenuElement_intersectionObserver = new WeakMap();
243
270
  _ActionMenuElement_instances = new WeakSet();
244
271
  _ActionMenuElement_softDisableItems = function _ActionMenuElement_softDisableItems() {
245
272
  const { signal } = __classPrivateFieldGet(this, _ActionMenuElement_abortController, "f");
@@ -443,6 +470,9 @@ _ActionMenuElement_firstItem_get = function _ActionMenuElement_firstItem_get() {
443
470
  __decorate([
444
471
  target
445
472
  ], ActionMenuElement.prototype, "includeFragment", void 0);
473
+ __decorate([
474
+ target
475
+ ], ActionMenuElement.prototype, "overlay", void 0);
446
476
  ActionMenuElement = __decorate([
447
477
  controller
448
478
  ], ActionMenuElement);
@@ -15,12 +15,13 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
15
15
  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");
16
16
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
17
  };
18
- var _SelectPanelElement_instances, _SelectPanelElement_dialogIntersectionObserver, _SelectPanelElement_abortController, _SelectPanelElement_originalLabel, _SelectPanelElement_inputName, _SelectPanelElement_selectedItems, _SelectPanelElement_loadingDelayTimeoutId, _SelectPanelElement_loadingAnnouncementTimeoutId, _SelectPanelElement_hasLoadedData, _SelectPanelElement_waitForCondition, _SelectPanelElement_softDisableItems, _SelectPanelElement_updateTabIndices, _SelectPanelElement_potentiallyDisallowActivation, _SelectPanelElement_isAnchorActivationViaSpace, _SelectPanelElement_isActivation, _SelectPanelElement_checkSelectedItems, _SelectPanelElement_addSelectedItem, _SelectPanelElement_removeSelectedItem, _SelectPanelElement_setTextFieldLoadingSpinnerTimer, _SelectPanelElement_handleIncludeFragmentEvent, _SelectPanelElement_toggleIncludeFragmentElements, _SelectPanelElement_handleRemoteInputEvent, _SelectPanelElement_defaultFilterFn, _SelectPanelElement_handleSearchFieldEvent, _SelectPanelElement_updateItemVisibility, _SelectPanelElement_inErrorState, _SelectPanelElement_setErrorState, _SelectPanelElement_clearErrorState, _SelectPanelElement_maybeAnnounce, _SelectPanelElement_fetchStrategy_get, _SelectPanelElement_filterInputTextFieldElement_get, _SelectPanelElement_performFilteringLocally, _SelectPanelElement_handleInvokerActivated, _SelectPanelElement_handleDialogItemActivated, _SelectPanelElement_handleItemActivated, _SelectPanelElement_setDynamicLabel, _SelectPanelElement_updateInput, _SelectPanelElement_firstItem_get, _SelectPanelElement_hideItem, _SelectPanelElement_showItem, _SelectPanelElement_getItemContent;
18
+ var _SelectPanelElement_instances, _SelectPanelElement_dialogIntersectionObserver, _SelectPanelElement_abortController, _SelectPanelElement_originalLabel, _SelectPanelElement_inputName, _SelectPanelElement_selectedItems, _SelectPanelElement_loadingDelayTimeoutId, _SelectPanelElement_loadingAnnouncementTimeoutId, _SelectPanelElement_hasLoadedData, _SelectPanelElement_softDisableItems, _SelectPanelElement_updateTabIndices, _SelectPanelElement_potentiallyDisallowActivation, _SelectPanelElement_isAnchorActivationViaSpace, _SelectPanelElement_isActivation, _SelectPanelElement_checkSelectedItems, _SelectPanelElement_addSelectedItem, _SelectPanelElement_removeSelectedItem, _SelectPanelElement_setTextFieldLoadingSpinnerTimer, _SelectPanelElement_handleIncludeFragmentEvent, _SelectPanelElement_toggleIncludeFragmentElements, _SelectPanelElement_handleRemoteInputEvent, _SelectPanelElement_defaultFilterFn, _SelectPanelElement_handleSearchFieldEvent, _SelectPanelElement_updateItemVisibility, _SelectPanelElement_inErrorState, _SelectPanelElement_setErrorState, _SelectPanelElement_clearErrorState, _SelectPanelElement_maybeAnnounce, _SelectPanelElement_fetchStrategy_get, _SelectPanelElement_filterInputTextFieldElement_get, _SelectPanelElement_performFilteringLocally, _SelectPanelElement_handleInvokerActivated, _SelectPanelElement_handleDialogItemActivated, _SelectPanelElement_handleItemActivated, _SelectPanelElement_setDynamicLabel, _SelectPanelElement_updateInput, _SelectPanelElement_firstItem_get, _SelectPanelElement_hideItem, _SelectPanelElement_showItem, _SelectPanelElement_getItemContent;
19
19
  import { getAnchoredPosition } from '@primer/behaviors';
20
20
  import { controller, target } from '@github/catalyst';
21
21
  import { IncludeFragmentElement } from '@github/include-fragment-element';
22
22
  import '@primer/live-region-element';
23
23
  import '@oddbird/popover-polyfill';
24
+ import { observeMutationsUntilConditionMet } from '../utils';
24
25
  const validSelectors = ['[role="option"]'];
25
26
  const menuItemSelectors = validSelectors.join(',');
26
27
  const visibleMenuItemSelectors = validSelectors.map(selector => `:not([hidden]) > ${selector}`).join(',');
@@ -172,11 +173,11 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
172
173
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_updateInput).call(this);
173
174
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_softDisableItems).call(this);
174
175
  updateWhenVisible(this);
175
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_waitForCondition).call(this, () => Boolean(this.remoteInput), () => {
176
+ observeMutationsUntilConditionMet(this, () => Boolean(this.remoteInput), () => {
176
177
  this.remoteInput.addEventListener('loadstart', this, { signal });
177
178
  this.remoteInput.addEventListener('loadend', this, { signal });
178
179
  });
179
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_waitForCondition).call(this, () => Boolean(this.includeFragment), () => {
180
+ observeMutationsUntilConditionMet(this, () => Boolean(this.includeFragment), () => {
180
181
  this.includeFragment.addEventListener('include-fragment-replaced', this, { signal });
181
182
  this.includeFragment.addEventListener('error', this, { signal });
182
183
  this.includeFragment.addEventListener('loadend', this, { signal });
@@ -201,7 +202,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
201
202
  }
202
203
  }
203
204
  }), "f");
204
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_waitForCondition).call(this, () => Boolean(this.dialog), () => {
205
+ observeMutationsUntilConditionMet(this, () => Boolean(this.dialog), () => {
205
206
  __classPrivateFieldGet(this, _SelectPanelElement_dialogIntersectionObserver, "f").observe(this.dialog);
206
207
  this.dialog.addEventListener('close', this, { signal });
207
208
  if (this.getAttribute('data-open-on-load') === 'true') {
@@ -209,7 +210,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
209
210
  }
210
211
  });
211
212
  if (__classPrivateFieldGet(this, _SelectPanelElement_instances, "a", _SelectPanelElement_fetchStrategy_get) === FetchStrategy.LOCAL) {
212
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_waitForCondition).call(this, () => this.items.length > 0, () => {
213
+ observeMutationsUntilConditionMet(this, () => this.items.length > 0, () => {
213
214
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_updateItemVisibility).call(this);
214
215
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_updateInput).call(this);
215
216
  });
@@ -399,20 +400,6 @@ _SelectPanelElement_loadingDelayTimeoutId = new WeakMap();
399
400
  _SelectPanelElement_loadingAnnouncementTimeoutId = new WeakMap();
400
401
  _SelectPanelElement_hasLoadedData = new WeakMap();
401
402
  _SelectPanelElement_instances = new WeakSet();
402
- _SelectPanelElement_waitForCondition = function _SelectPanelElement_waitForCondition(condition, body) {
403
- if (condition()) {
404
- body();
405
- }
406
- else {
407
- const mutationObserver = new MutationObserver(() => {
408
- if (condition()) {
409
- body();
410
- mutationObserver.disconnect();
411
- }
412
- });
413
- mutationObserver.observe(this, { childList: true, subtree: true });
414
- }
415
- };
416
403
  _SelectPanelElement_softDisableItems = function _SelectPanelElement_softDisableItems() {
417
404
  const { signal } = __classPrivateFieldGet(this, _SelectPanelElement_abortController, "f");
418
405
  for (const item of this.querySelectorAll(validSelectors.join(','))) {
@@ -8,6 +8,7 @@ import './dialog_helper';
8
8
  import './focus_group';
9
9
  import './scrollable_region';
10
10
  import './shared_events';
11
+ import './utils';
11
12
  import './alpha/modal_dialog';
12
13
  import './beta/nav_list';
13
14
  import './beta/nav_list_group_element';
@@ -8,6 +8,7 @@ import './dialog_helper';
8
8
  import './focus_group';
9
9
  import './scrollable_region';
10
10
  import './shared_events';
11
+ import './utils';
11
12
  import './alpha/modal_dialog';
12
13
  import './beta/nav_list';
13
14
  import './beta/nav_list_group_element';
@@ -0,0 +1 @@
1
+ export declare const observeMutationsUntilConditionMet: (element: Element, condition: () => boolean, body: () => void) => void;
@@ -0,0 +1,16 @@
1
+ // Waits for condition to return true. If it returns false initially, this function creates a
2
+ // MutationObserver that calls body() whenever the contents of the component change.
3
+ export const observeMutationsUntilConditionMet = (element, condition, body) => {
4
+ if (condition()) {
5
+ body();
6
+ }
7
+ else {
8
+ const mutationObserver = new MutationObserver(() => {
9
+ if (condition()) {
10
+ body();
11
+ mutationObserver.disconnect();
12
+ }
13
+ });
14
+ mutationObserver.observe(element, { childList: true, subtree: true });
15
+ }
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primer/view-components",
3
- "version": "0.36.1",
3
+ "version": "0.36.2-rc.cf1c67eb",
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",