primer_view_components 0.0.92 → 0.0.93
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +2 -2
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -0
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/dialog/body.rb +25 -0
- data/app/components/primer/alpha/dialog/footer.rb +31 -0
- data/app/components/primer/alpha/dialog/header.html.erb +15 -0
- data/app/components/primer/alpha/dialog/header.rb +37 -0
- data/app/components/primer/alpha/dialog.html.erb +12 -0
- data/app/components/primer/alpha/dialog.rb +160 -0
- data/app/components/primer/alpha/modal-dialog-element.d.ts +1 -1
- data/app/components/primer/alpha/modal-dialog-element.js +2 -3
- data/app/components/primer/alpha/modal-dialog-element.ts +148 -0
- data/app/components/primer/alpha/toggle-switch-element.js +2 -0
- data/app/components/primer/alpha/toggle-switch-element.ts +2 -1
- data/app/components/primer/alpha/tool-tip-element.ts +0 -1
- data/app/components/primer/beta/button.html.erb +23 -0
- data/app/components/primer/beta/button.pcss +332 -0
- data/app/components/primer/beta/button.rb +189 -0
- data/app/components/primer/beta/icon_button.html.erb +6 -0
- data/app/components/primer/beta/icon_button.rb +104 -0
- data/app/components/primer/clipboard_copy_component.ts +1 -1
- data/app/components/primer/experimental/action-bar-element.d.ts +14 -0
- data/app/components/primer/experimental/action-bar-element.js +139 -0
- data/app/components/primer/experimental/action-menu-element.d.ts +31 -0
- data/app/components/primer/experimental/action-menu-element.js +334 -0
- data/app/components/primer/experimental/overflow-menu-element.d.ts +13 -0
- data/app/components/primer/experimental/overflow-menu-element.js +113 -0
- data/app/components/primer/primer.d.ts +1 -0
- data/app/components/primer/primer.js +1 -0
- data/app/components/primer/primer.pcss +1 -0
- data/app/components/primer/primer.ts +1 -0
- data/lib/postcss_mixins/focusBoxShadowInset.pcss +6 -0
- data/lib/postcss_mixins/focusOutline.pcss +5 -0
- data/lib/postcss_mixins/focusOutlineOnEmphasis.pcss +6 -0
- data/lib/postcss_mixins/minTouchTarget.js +20 -0
- data/lib/postcss_mixins/targetBoxShadow.pcss +6 -0
- data/lib/primer/view_components/linters/argument_mappers/base.rb +1 -1
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/docs.rake +3 -8
- data/static/arguments.yml +113 -0
- data/static/audited_at.json +6 -0
- data/static/constants.json +107 -0
- data/static/statuses.json +6 -0
- metadata +25 -5
- data/app/components/primer/alpha/segmented-control-element.d.ts +0 -8
- data/app/components/primer/alpha/segmented-control-element.js +0 -28
- data/static/classes.yml +0 -230
@@ -0,0 +1,139 @@
|
|
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
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
10
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
11
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
12
|
+
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");
|
13
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
14
|
+
};
|
15
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
16
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
17
|
+
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");
|
18
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
19
|
+
};
|
20
|
+
var _ActionBarElement_instances, _ActionBarElement_observer, _ActionBarElement_initialBarWidth, _ActionBarElement_itemGap, _ActionBarElement_focusController, _ActionBarElement_focusSettings, _ActionBarElement_availableSpace, _ActionBarElement_calculateVisibleItems, _ActionBarElement_nextItemWidth, _ActionBarElement_hideItem, _ActionBarElement_showItem, _ActionBarElement_hiddenItems, _ActionBarElement_visibleItems, _ActionBarElement_hiddenMenuItems, _ActionBarElement_visibleMenuItems;
|
21
|
+
import { controller, targets, target } from '@github/catalyst';
|
22
|
+
import { positionedOffset, focusZone, FocusKeys } from '@primer/behaviors';
|
23
|
+
let ActionBarElement = class ActionBarElement extends HTMLElement {
|
24
|
+
constructor() {
|
25
|
+
super(...arguments);
|
26
|
+
_ActionBarElement_instances.add(this);
|
27
|
+
_ActionBarElement_observer.set(this, void 0);
|
28
|
+
_ActionBarElement_initialBarWidth.set(this, void 0);
|
29
|
+
_ActionBarElement_itemGap.set(this, void 0);
|
30
|
+
_ActionBarElement_focusController.set(this, void 0);
|
31
|
+
_ActionBarElement_focusSettings.set(this, {
|
32
|
+
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd
|
33
|
+
});
|
34
|
+
}
|
35
|
+
connectedCallback() {
|
36
|
+
var _a, _b, _c;
|
37
|
+
__classPrivateFieldSet(this, _ActionBarElement_initialBarWidth, this.offsetWidth, "f");
|
38
|
+
__classPrivateFieldSet(this, _ActionBarElement_itemGap, parseInt((_a = window.getComputedStyle(this)) === null || _a === void 0 ? void 0 : _a.columnGap, 10) || 0, "f");
|
39
|
+
// Calculate the width of all the items before hiding anything
|
40
|
+
for (const item of this.items) {
|
41
|
+
const width = item.getBoundingClientRect().width;
|
42
|
+
const marginLeft = parseInt((_b = window.getComputedStyle(item)) === null || _b === void 0 ? void 0 : _b.marginLeft, 10);
|
43
|
+
const marginRight = parseInt((_c = window.getComputedStyle(item)) === null || _c === void 0 ? void 0 : _c.marginRight, 10);
|
44
|
+
item.setAttribute('data-offset-width', `${width + marginLeft + marginRight}`);
|
45
|
+
}
|
46
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
47
|
+
// Calculate visible items on page load until there is enough space
|
48
|
+
// to show all items or the first item is hidden
|
49
|
+
while (__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) < 0 && !this.items[0].hidden) {
|
50
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_calculateVisibleItems).call(this);
|
51
|
+
}
|
52
|
+
__classPrivateFieldSet(this, _ActionBarElement_observer, new ResizeObserver(entries => {
|
53
|
+
for (const entry of entries) {
|
54
|
+
// Only recalculate if the bar width changed
|
55
|
+
if (__classPrivateFieldGet(this, _ActionBarElement_initialBarWidth, "f") !== entry.contentRect.width) {
|
56
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_calculateVisibleItems).call(this);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}), "f");
|
60
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").observe(this);
|
61
|
+
}
|
62
|
+
disconnectedCallback() {
|
63
|
+
var _a;
|
64
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
65
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").unobserve(this);
|
66
|
+
}
|
67
|
+
};
|
68
|
+
_ActionBarElement_observer = new WeakMap(), _ActionBarElement_initialBarWidth = new WeakMap(), _ActionBarElement_itemGap = new WeakMap(), _ActionBarElement_focusController = new WeakMap(), _ActionBarElement_focusSettings = new WeakMap(), _ActionBarElement_instances = new WeakSet(), _ActionBarElement_availableSpace = function _ActionBarElement_availableSpace() {
|
69
|
+
// Get the offset of the first item from the container edge
|
70
|
+
const offset = positionedOffset(this.items[0], this);
|
71
|
+
if (!offset) {
|
72
|
+
return this.clientWidth - this.moreMenu.clientWidth;
|
73
|
+
}
|
74
|
+
return offset.left;
|
75
|
+
}, _ActionBarElement_calculateVisibleItems = function _ActionBarElement_calculateVisibleItems() {
|
76
|
+
const space = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this);
|
77
|
+
if (space < 0) {
|
78
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItem).call(this);
|
79
|
+
}
|
80
|
+
else if (space > __classPrivateFieldGet(this, _ActionBarElement_itemGap, "f") + __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_nextItemWidth).call(this)) {
|
81
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItem).call(this);
|
82
|
+
}
|
83
|
+
}, _ActionBarElement_nextItemWidth = function _ActionBarElement_nextItemWidth() {
|
84
|
+
const nextItem = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hiddenItems).call(this)[0] || this.items[0];
|
85
|
+
return Number(nextItem.getAttribute('data-offset-width') || '0');
|
86
|
+
}, _ActionBarElement_hideItem = function _ActionBarElement_hideItem() {
|
87
|
+
var _a;
|
88
|
+
const visibleItems = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_visibleItems).call(this);
|
89
|
+
const hiddenMenuItems = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hiddenMenuItems).call(this);
|
90
|
+
if (visibleItems.length === 0) {
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
visibleItems[visibleItems.length - 1].hidden = true;
|
94
|
+
hiddenMenuItems[hiddenMenuItems.length - 1].hidden = false;
|
95
|
+
if (this.moreMenu.hidden) {
|
96
|
+
this.moreMenu.hidden = false;
|
97
|
+
}
|
98
|
+
// Reset focus controller
|
99
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
100
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
101
|
+
}, _ActionBarElement_showItem = function _ActionBarElement_showItem() {
|
102
|
+
var _a;
|
103
|
+
const hiddenItems = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hiddenItems).call(this);
|
104
|
+
const visibleMenuItems = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_visibleMenuItems).call(this);
|
105
|
+
if (hiddenItems.length === 0) {
|
106
|
+
return;
|
107
|
+
}
|
108
|
+
hiddenItems[0].hidden = false;
|
109
|
+
visibleMenuItems[0].hidden = true;
|
110
|
+
// If there was only one item left, hide the more menu
|
111
|
+
if (hiddenItems.length === 1) {
|
112
|
+
this.moreMenu.hidden = true;
|
113
|
+
this.moreMenu.open = false;
|
114
|
+
}
|
115
|
+
// Reset focus controller
|
116
|
+
(_a = __classPrivateFieldGet(this, _ActionBarElement_focusController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
117
|
+
__classPrivateFieldSet(this, _ActionBarElement_focusController, focusZone(this, __classPrivateFieldGet(this, _ActionBarElement_focusSettings, "f")), "f");
|
118
|
+
}, _ActionBarElement_hiddenItems = function _ActionBarElement_hiddenItems() {
|
119
|
+
return this.items.filter(item => item.hidden);
|
120
|
+
}, _ActionBarElement_visibleItems = function _ActionBarElement_visibleItems() {
|
121
|
+
return this.items.filter(item => !item.hidden);
|
122
|
+
}, _ActionBarElement_hiddenMenuItems = function _ActionBarElement_hiddenMenuItems() {
|
123
|
+
return this.menuItems.filter(item => item.hidden);
|
124
|
+
}, _ActionBarElement_visibleMenuItems = function _ActionBarElement_visibleMenuItems() {
|
125
|
+
return this.menuItems.filter(item => !item.hidden);
|
126
|
+
};
|
127
|
+
__decorate([
|
128
|
+
targets
|
129
|
+
], ActionBarElement.prototype, "items", void 0);
|
130
|
+
__decorate([
|
131
|
+
targets
|
132
|
+
], ActionBarElement.prototype, "menuItems", void 0);
|
133
|
+
__decorate([
|
134
|
+
target
|
135
|
+
], ActionBarElement.prototype, "moreMenu", void 0);
|
136
|
+
ActionBarElement = __decorate([
|
137
|
+
controller
|
138
|
+
], ActionBarElement);
|
139
|
+
export { ActionBarElement };
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import type { AnchorAlignment, AnchorSide } from '@primer/behaviors';
|
2
|
+
export declare class ActionMenuElement extends HTMLElement {
|
3
|
+
#private;
|
4
|
+
get anchorAlign(): AnchorAlignment;
|
5
|
+
get anchorSide(): AnchorSide;
|
6
|
+
get menu(): HTMLUListElement | null;
|
7
|
+
get trigger(): HTMLButtonElement | null;
|
8
|
+
get overlay(): HTMLDivElement | null;
|
9
|
+
get menuItems(): HTMLElement[] | null;
|
10
|
+
get open(): boolean;
|
11
|
+
set open(value: boolean);
|
12
|
+
connectedCallback(): void;
|
13
|
+
disconnectedCallback(): void;
|
14
|
+
show(): void;
|
15
|
+
hide(): void;
|
16
|
+
setFocusToMenuItem(newMenuItem: HTMLElement): void;
|
17
|
+
setFocusToPreviousMenuItem(currentMenuItem: HTMLElement): HTMLElement | undefined;
|
18
|
+
setFocusToNextMenuItem(currentMenuItem: HTMLElement): HTMLElement | undefined;
|
19
|
+
setFocusByFirstCharacter(currentMenuItem: HTMLElement, character: string): void;
|
20
|
+
buttonKeydown(event: KeyboardEvent): void;
|
21
|
+
buttonClick(event: MouseEvent): void;
|
22
|
+
menuItemKeydown(event: KeyboardEvent): void;
|
23
|
+
menuItemClick(): void;
|
24
|
+
menuItemMouseover(event: MouseEvent): void;
|
25
|
+
backgroundMousedown(event: MouseEvent): void;
|
26
|
+
}
|
27
|
+
declare global {
|
28
|
+
interface Window {
|
29
|
+
ActionMenuElement: typeof ActionMenuElement;
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,334 @@
|
|
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 _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_firstCharactersOfItems, _ActionMenuElement_firstMenuItem, _ActionMenuElement_lastMenuItem, _ActionMenuElement_addEvents, _ActionMenuElement_updatePosition;
|
13
|
+
import { getAnchoredPosition } from '@primer/behaviors';
|
14
|
+
export class ActionMenuElement extends HTMLElement {
|
15
|
+
constructor() {
|
16
|
+
super(...arguments);
|
17
|
+
_ActionMenuElement_instances.add(this);
|
18
|
+
_ActionMenuElement_abortController.set(this, void 0);
|
19
|
+
_ActionMenuElement_firstCharactersOfItems.set(this, void 0);
|
20
|
+
_ActionMenuElement_firstMenuItem.set(this, void 0);
|
21
|
+
_ActionMenuElement_lastMenuItem.set(this, void 0);
|
22
|
+
}
|
23
|
+
get anchorAlign() {
|
24
|
+
return (this.getAttribute('data-anchor-align') || 'start');
|
25
|
+
}
|
26
|
+
get anchorSide() {
|
27
|
+
return (this.getAttribute('data-anchor-side') || 'outside-bottom');
|
28
|
+
}
|
29
|
+
get menu() {
|
30
|
+
return this.querySelector('[role="menu"]');
|
31
|
+
}
|
32
|
+
get trigger() {
|
33
|
+
return this.querySelector('button');
|
34
|
+
}
|
35
|
+
get overlay() {
|
36
|
+
return this.querySelector('.Overlay');
|
37
|
+
}
|
38
|
+
get menuItems() {
|
39
|
+
if (!this.menu)
|
40
|
+
return null;
|
41
|
+
return Array.from(this.menu.querySelectorAll('[role="menuitem"],[role="menuitemcheckbox"],[role="menuitemradio"]'));
|
42
|
+
}
|
43
|
+
get open() {
|
44
|
+
return this.hasAttribute('open');
|
45
|
+
}
|
46
|
+
set open(value) {
|
47
|
+
var _a, _b;
|
48
|
+
const initialBodyWidth = document.body.clientWidth;
|
49
|
+
const observer = new ResizeObserver(entries => {
|
50
|
+
for (const entry of entries) {
|
51
|
+
if (initialBodyWidth !== entry.contentRect.width && this.open) {
|
52
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_updatePosition).call(this);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
});
|
56
|
+
if (value) {
|
57
|
+
if (this.open)
|
58
|
+
return;
|
59
|
+
if (!this.trigger || !this.menu)
|
60
|
+
return;
|
61
|
+
this.setAttribute('open', '');
|
62
|
+
this.trigger.setAttribute('aria-expanded', 'true');
|
63
|
+
(_a = this.overlay) === null || _a === void 0 ? void 0 : _a.removeAttribute('hidden');
|
64
|
+
this.menu.style.visibility = 'hidden';
|
65
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_updatePosition).call(this);
|
66
|
+
// If the window width is changed when the menu is open,
|
67
|
+
// this keeps the menu aligned to the button
|
68
|
+
observer.observe(document.body);
|
69
|
+
this.menu.style.visibility = 'visible';
|
70
|
+
}
|
71
|
+
else {
|
72
|
+
if (!this.open)
|
73
|
+
return;
|
74
|
+
this.removeAttribute('open');
|
75
|
+
(_b = this.trigger) === null || _b === void 0 ? void 0 : _b.setAttribute('aria-expanded', 'false');
|
76
|
+
this.overlay && this.overlay.setAttribute('hidden', 'true');
|
77
|
+
observer.unobserve(document.body);
|
78
|
+
// TODO: Do this without a setTimeout
|
79
|
+
setTimeout(() => {
|
80
|
+
var _a;
|
81
|
+
// There are some actions that may move focus to another part of the page intentionally.
|
82
|
+
// For example: "Quote Reply" in the comment options moves focus to the comment box.
|
83
|
+
// This only moves focus to the trigger if it's not managed in another way.
|
84
|
+
if (document.activeElement === document.body)
|
85
|
+
(_a = this.trigger) === null || _a === void 0 ? void 0 : _a.focus();
|
86
|
+
}, 1);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
connectedCallback() {
|
90
|
+
if (!this.trigger)
|
91
|
+
return;
|
92
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_addEvents).call(this);
|
93
|
+
}
|
94
|
+
disconnectedCallback() {
|
95
|
+
__classPrivateFieldGet(this, _ActionMenuElement_abortController, "f").abort();
|
96
|
+
}
|
97
|
+
show() {
|
98
|
+
this.open = true;
|
99
|
+
}
|
100
|
+
hide() {
|
101
|
+
this.open = false;
|
102
|
+
}
|
103
|
+
setFocusToMenuItem(newMenuItem) {
|
104
|
+
if (!this.menuItems)
|
105
|
+
return;
|
106
|
+
for (const item of this.menuItems) {
|
107
|
+
if (item === newMenuItem) {
|
108
|
+
item.tabIndex = 0;
|
109
|
+
newMenuItem.focus();
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
item.tabIndex = -1;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
setFocusToPreviousMenuItem(currentMenuItem) {
|
117
|
+
if (!this.menuItems)
|
118
|
+
return;
|
119
|
+
let newMenuItem = null;
|
120
|
+
let index = null;
|
121
|
+
if (currentMenuItem === __classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f")) {
|
122
|
+
newMenuItem = __classPrivateFieldGet(this, _ActionMenuElement_lastMenuItem, "f");
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
index = this.menuItems.indexOf(currentMenuItem);
|
126
|
+
newMenuItem = this.menuItems[index - 1];
|
127
|
+
}
|
128
|
+
this.setFocusToMenuItem(newMenuItem);
|
129
|
+
return newMenuItem;
|
130
|
+
}
|
131
|
+
setFocusToNextMenuItem(currentMenuItem) {
|
132
|
+
if (!this.menuItems)
|
133
|
+
return;
|
134
|
+
let newMenuItem = null;
|
135
|
+
let index = null;
|
136
|
+
if (currentMenuItem === __classPrivateFieldGet(this, _ActionMenuElement_lastMenuItem, "f")) {
|
137
|
+
newMenuItem = __classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f");
|
138
|
+
}
|
139
|
+
else {
|
140
|
+
index = this.menuItems.indexOf(currentMenuItem);
|
141
|
+
newMenuItem = this.menuItems[index + 1];
|
142
|
+
}
|
143
|
+
this.setFocusToMenuItem(newMenuItem);
|
144
|
+
return newMenuItem;
|
145
|
+
}
|
146
|
+
setFocusByFirstCharacter(currentMenuItem, character) {
|
147
|
+
if (!this.menuItems)
|
148
|
+
return;
|
149
|
+
let start = null;
|
150
|
+
let index = null;
|
151
|
+
if (character.length > 1) {
|
152
|
+
return;
|
153
|
+
}
|
154
|
+
character = character.toLowerCase();
|
155
|
+
// Get start index for search based on position of currentMenuItem
|
156
|
+
start = this.menuItems.indexOf(currentMenuItem) + 1;
|
157
|
+
if (start >= this.menuItems.length) {
|
158
|
+
start = 0;
|
159
|
+
}
|
160
|
+
// Check remaining slots in the menu
|
161
|
+
index = __classPrivateFieldGet(this, _ActionMenuElement_firstCharactersOfItems, "f").indexOf(character, start);
|
162
|
+
// If character is not found in remaining slots, check from beginning
|
163
|
+
if (index === -1) {
|
164
|
+
index = __classPrivateFieldGet(this, _ActionMenuElement_firstCharactersOfItems, "f").indexOf(character, 0);
|
165
|
+
}
|
166
|
+
// If match is found
|
167
|
+
if (index > -1) {
|
168
|
+
this.setFocusToMenuItem(this.menuItems[index]);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
// Menu event handlers
|
172
|
+
buttonKeydown(event) {
|
173
|
+
// TODO: use data-hotkey
|
174
|
+
const key = event.key;
|
175
|
+
let flag = false;
|
176
|
+
switch (key) {
|
177
|
+
case ' ':
|
178
|
+
case 'Enter':
|
179
|
+
case 'ArrowDown':
|
180
|
+
case 'Down':
|
181
|
+
this.show();
|
182
|
+
this.setFocusToMenuItem(__classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f"));
|
183
|
+
flag = true;
|
184
|
+
break;
|
185
|
+
case 'Esc':
|
186
|
+
case 'Escape':
|
187
|
+
this.hide();
|
188
|
+
flag = true;
|
189
|
+
break;
|
190
|
+
case 'Up':
|
191
|
+
case 'ArrowUp':
|
192
|
+
this.show();
|
193
|
+
this.setFocusToMenuItem(__classPrivateFieldGet(this, _ActionMenuElement_lastMenuItem, "f"));
|
194
|
+
flag = true;
|
195
|
+
break;
|
196
|
+
default:
|
197
|
+
break;
|
198
|
+
}
|
199
|
+
if (flag) {
|
200
|
+
event.stopPropagation();
|
201
|
+
event.preventDefault();
|
202
|
+
}
|
203
|
+
}
|
204
|
+
buttonClick(event) {
|
205
|
+
if (this.open) {
|
206
|
+
this.hide();
|
207
|
+
}
|
208
|
+
else {
|
209
|
+
this.show();
|
210
|
+
this.setFocusToMenuItem(__classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f"));
|
211
|
+
}
|
212
|
+
event.stopPropagation();
|
213
|
+
event.preventDefault();
|
214
|
+
}
|
215
|
+
menuItemKeydown(event) {
|
216
|
+
var _a;
|
217
|
+
const currentTarget = event.currentTarget;
|
218
|
+
const key = event.key;
|
219
|
+
let flag = false;
|
220
|
+
function isPrintableCharacter(str) {
|
221
|
+
return str.length === 1 && str.match(/\S/);
|
222
|
+
}
|
223
|
+
if (event.ctrlKey || event.altKey || event.metaKey) {
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
if (event.shiftKey) {
|
227
|
+
if (isPrintableCharacter(key)) {
|
228
|
+
this.setFocusByFirstCharacter(currentTarget, key);
|
229
|
+
flag = true;
|
230
|
+
}
|
231
|
+
if (event.key === 'Tab') {
|
232
|
+
(_a = this.trigger) === null || _a === void 0 ? void 0 : _a.focus();
|
233
|
+
this.hide();
|
234
|
+
flag = true;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
else {
|
238
|
+
switch (key) {
|
239
|
+
case 'Enter':
|
240
|
+
this.hide();
|
241
|
+
break;
|
242
|
+
case 'Esc':
|
243
|
+
case 'Escape':
|
244
|
+
this.hide();
|
245
|
+
flag = true;
|
246
|
+
break;
|
247
|
+
case 'Up':
|
248
|
+
case 'ArrowUp':
|
249
|
+
this.setFocusToPreviousMenuItem(currentTarget);
|
250
|
+
flag = true;
|
251
|
+
break;
|
252
|
+
case 'ArrowDown':
|
253
|
+
case 'Down':
|
254
|
+
this.setFocusToNextMenuItem(currentTarget);
|
255
|
+
flag = true;
|
256
|
+
break;
|
257
|
+
case 'Home':
|
258
|
+
case 'PageUp':
|
259
|
+
this.setFocusToMenuItem(__classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f"));
|
260
|
+
flag = true;
|
261
|
+
break;
|
262
|
+
case 'End':
|
263
|
+
case 'PageDown':
|
264
|
+
this.setFocusToMenuItem(__classPrivateFieldGet(this, _ActionMenuElement_lastMenuItem, "f"));
|
265
|
+
flag = true;
|
266
|
+
break;
|
267
|
+
case 'Tab':
|
268
|
+
this.hide();
|
269
|
+
break;
|
270
|
+
default:
|
271
|
+
if (isPrintableCharacter(key)) {
|
272
|
+
this.setFocusByFirstCharacter(currentTarget, key);
|
273
|
+
flag = true;
|
274
|
+
}
|
275
|
+
break;
|
276
|
+
}
|
277
|
+
}
|
278
|
+
if (flag) {
|
279
|
+
event.stopPropagation();
|
280
|
+
event.preventDefault();
|
281
|
+
}
|
282
|
+
}
|
283
|
+
menuItemClick() {
|
284
|
+
this.hide();
|
285
|
+
}
|
286
|
+
menuItemMouseover(event) {
|
287
|
+
event.currentTarget.focus();
|
288
|
+
}
|
289
|
+
backgroundMousedown(event) {
|
290
|
+
if (!this)
|
291
|
+
return;
|
292
|
+
if (!this.contains(event.target)) {
|
293
|
+
if (this.open) {
|
294
|
+
this.hide();
|
295
|
+
}
|
296
|
+
}
|
297
|
+
}
|
298
|
+
}
|
299
|
+
_ActionMenuElement_abortController = new WeakMap(), _ActionMenuElement_firstCharactersOfItems = new WeakMap(), _ActionMenuElement_firstMenuItem = new WeakMap(), _ActionMenuElement_lastMenuItem = new WeakMap(), _ActionMenuElement_instances = new WeakSet(), _ActionMenuElement_addEvents = function _ActionMenuElement_addEvents() {
|
300
|
+
__classPrivateFieldSet(this, _ActionMenuElement_abortController, new AbortController(), "f");
|
301
|
+
const { signal } = __classPrivateFieldGet(this, _ActionMenuElement_abortController, "f");
|
302
|
+
if (!this.trigger || !this.menu)
|
303
|
+
return;
|
304
|
+
this.trigger.addEventListener('keydown', this.buttonKeydown.bind(this), { signal });
|
305
|
+
this.trigger.addEventListener('click', this.buttonClick.bind(this), { signal });
|
306
|
+
__classPrivateFieldSet(this, _ActionMenuElement_firstCharactersOfItems, [], "f");
|
307
|
+
if (this.menuItems) {
|
308
|
+
for (const menuItem of this.menuItems) {
|
309
|
+
if (menuItem.textContent) {
|
310
|
+
__classPrivateFieldGet(this, _ActionMenuElement_firstCharactersOfItems, "f").push(menuItem.textContent.trim()[0].toLowerCase());
|
311
|
+
}
|
312
|
+
menuItem.addEventListener('keydown', this.menuItemKeydown.bind(this), { signal });
|
313
|
+
menuItem.addEventListener('click', this.menuItemClick.bind(this), { signal });
|
314
|
+
menuItem.addEventListener('mouseover', this.menuItemMouseover.bind(this), { signal });
|
315
|
+
if (!__classPrivateFieldGet(this, _ActionMenuElement_firstMenuItem, "f")) {
|
316
|
+
__classPrivateFieldSet(this, _ActionMenuElement_firstMenuItem, menuItem, "f");
|
317
|
+
}
|
318
|
+
__classPrivateFieldSet(this, _ActionMenuElement_lastMenuItem, menuItem, "f");
|
319
|
+
}
|
320
|
+
}
|
321
|
+
window.addEventListener('mousedown', this.backgroundMousedown.bind(this), true);
|
322
|
+
}, _ActionMenuElement_updatePosition = function _ActionMenuElement_updatePosition() {
|
323
|
+
if (!this.trigger || !this.menu)
|
324
|
+
return;
|
325
|
+
const float = this.querySelector('[data-menu-overlay]') || this.menu;
|
326
|
+
const anchor = this.trigger;
|
327
|
+
const { top, left } = getAnchoredPosition(float, anchor, { side: this.anchorSide, align: this.anchorAlign });
|
328
|
+
float.style.top = `${top}px`;
|
329
|
+
float.style.left = `${left}px`;
|
330
|
+
};
|
331
|
+
if (!window.customElements.get('action-menu')) {
|
332
|
+
window.ActionMenuElement = ActionMenuElement;
|
333
|
+
window.customElements.define('action-menu', ActionMenuElement);
|
334
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export declare class ActionBarElement extends HTMLElement {
|
2
|
+
#private;
|
3
|
+
items: HTMLElement[];
|
4
|
+
menuItems: HTMLElement[];
|
5
|
+
moreMenu: HTMLElement;
|
6
|
+
connectedCallback(): void;
|
7
|
+
disconnectedCallback(): void;
|
8
|
+
}
|
9
|
+
declare global {
|
10
|
+
interface Window {
|
11
|
+
ActionBarElement: typeof ActionBarElement;
|
12
|
+
}
|
13
|
+
}
|
@@ -0,0 +1,113 @@
|
|
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
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
10
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
11
|
+
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");
|
12
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
13
|
+
};
|
14
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
15
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
16
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
17
|
+
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");
|
18
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
19
|
+
};
|
20
|
+
var _ActionBarElement_instances, _ActionBarElement_observer, _ActionBarElement_initialBarWidth, _ActionBarElement_calculateVisibility, _ActionBarElement_hideItems, _ActionBarElement_showItems, _ActionBarElement_hiddenItems, _ActionBarElement_toggleMoreMenu, _ActionBarElement_gap;
|
21
|
+
import { controller, targets, target } from '@github/catalyst';
|
22
|
+
import { positionedOffset } from '@primer/behaviors';
|
23
|
+
let ActionBarElement = class ActionBarElement extends HTMLElement {
|
24
|
+
constructor() {
|
25
|
+
super(...arguments);
|
26
|
+
_ActionBarElement_instances.add(this);
|
27
|
+
// eslint-disable-next-line prettier/prettier
|
28
|
+
_ActionBarElement_observer.set(this, void 0);
|
29
|
+
_ActionBarElement_initialBarWidth.set(this, void 0);
|
30
|
+
}
|
31
|
+
connectedCallback() {
|
32
|
+
let overflowItemsCount = 0;
|
33
|
+
for (const item of this.items) {
|
34
|
+
const offset = positionedOffset(item, this);
|
35
|
+
if (offset && offset.left < 0) {
|
36
|
+
overflowItemsCount++;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItems).call(this, overflowItemsCount);
|
40
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_toggleMoreMenu).call(this);
|
41
|
+
__classPrivateFieldSet(this, _ActionBarElement_initialBarWidth, this.offsetWidth, "f");
|
42
|
+
__classPrivateFieldSet(this, _ActionBarElement_observer, new ResizeObserver(entries => {
|
43
|
+
for (const entry of entries) {
|
44
|
+
if (__classPrivateFieldGet(this, _ActionBarElement_initialBarWidth, "f") !== entry.contentRect.width) {
|
45
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_calculateVisibility).call(this);
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}), "f");
|
49
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").observe(this);
|
50
|
+
}
|
51
|
+
disconnectedCallback() {
|
52
|
+
__classPrivateFieldGet(this, _ActionBarElement_observer, "f").unobserve(this);
|
53
|
+
}
|
54
|
+
};
|
55
|
+
_ActionBarElement_observer = new WeakMap(), _ActionBarElement_initialBarWidth = new WeakMap(), _ActionBarElement_instances = new WeakSet(), _ActionBarElement_calculateVisibility = function _ActionBarElement_calculateVisibility() {
|
56
|
+
const firstItem = this.items[0];
|
57
|
+
if (firstItem.hidden && this.offsetWidth >= firstItem.offsetWidth + __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_gap).call(this)) {
|
58
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItems).call(this, 1);
|
59
|
+
}
|
60
|
+
const offset = positionedOffset(firstItem, this);
|
61
|
+
if (!offset) {
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
if (offset.left < 0) {
|
65
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItems).call(this, 1);
|
66
|
+
}
|
67
|
+
else if (offset.left >= firstItem.offsetWidth + __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_gap).call(this)) {
|
68
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItems).call(this, 1);
|
69
|
+
}
|
70
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_toggleMoreMenu).call(this);
|
71
|
+
}, _ActionBarElement_hideItems = function _ActionBarElement_hideItems(count) {
|
72
|
+
const reversedItems = this.items.slice().reverse().filter(item => !item.hidden);
|
73
|
+
const reversedMenuItems = this.menuItems.slice().reverse().filter(item => item.hidden);
|
74
|
+
for (const i of [...Array(count).keys()]) {
|
75
|
+
if (reversedItems[i]) {
|
76
|
+
reversedItems[i].hidden = true;
|
77
|
+
}
|
78
|
+
if (reversedMenuItems[i]) {
|
79
|
+
reversedMenuItems[i].hidden = false;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}, _ActionBarElement_showItems = function _ActionBarElement_showItems(count) {
|
83
|
+
const items = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hiddenItems).call(this);
|
84
|
+
const menuItems = this.menuItems.filter(item => !item.hidden);
|
85
|
+
for (const i of [...Array(count).keys()]) {
|
86
|
+
if (items[i]) {
|
87
|
+
items[i].hidden = false;
|
88
|
+
}
|
89
|
+
if (menuItems[i]) {
|
90
|
+
menuItems[i].hidden = true;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}, _ActionBarElement_hiddenItems = function _ActionBarElement_hiddenItems() {
|
94
|
+
return this.items.filter(item => item.hidden);
|
95
|
+
}, _ActionBarElement_toggleMoreMenu = function _ActionBarElement_toggleMoreMenu() {
|
96
|
+
this.moreMenu.hidden = __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hiddenItems).call(this).length === 0;
|
97
|
+
}, _ActionBarElement_gap = function _ActionBarElement_gap() {
|
98
|
+
var _a;
|
99
|
+
return parseInt((_a = window.getComputedStyle(this)) === null || _a === void 0 ? void 0 : _a.columnGap) || 0;
|
100
|
+
};
|
101
|
+
__decorate([
|
102
|
+
targets
|
103
|
+
], ActionBarElement.prototype, "items", void 0);
|
104
|
+
__decorate([
|
105
|
+
targets
|
106
|
+
], ActionBarElement.prototype, "menuItems", void 0);
|
107
|
+
__decorate([
|
108
|
+
target
|
109
|
+
], ActionBarElement.prototype, "moreMenu", void 0);
|
110
|
+
ActionBarElement = __decorate([
|
111
|
+
controller
|
112
|
+
], ActionBarElement);
|
113
|
+
export { ActionBarElement };
|