openproject-primer_view_components 0.18.1 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -0
- data/app/assets/javascripts/app/components/primer/alpha/action_bar_element.d.ts +3 -2
- data/app/assets/javascripts/app/components/primer/alpha/action_menu/action_menu_element.d.ts +20 -0
- data/app/assets/javascripts/app/components/primer/beta/nav_list.d.ts +0 -11
- data/app/assets/javascripts/app/components/primer/beta/nav_list_group_element.d.ts +19 -0
- data/app/assets/javascripts/app/components/primer/primer.d.ts +2 -0
- data/app/assets/javascripts/app/components/primer/scrollable_region.d.ts +13 -0
- 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 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_bar.css +1 -1
- data/app/components/primer/alpha/action_bar.css.map +1 -1
- data/app/components/primer/alpha/action_bar.pcss +8 -6
- data/app/components/primer/alpha/action_bar_element.d.ts +3 -2
- data/app/components/primer/alpha/action_bar_element.js +80 -97
- data/app/components/primer/alpha/action_bar_element.ts +84 -89
- data/app/components/primer/alpha/action_list/item.rb +13 -1
- data/app/components/primer/alpha/action_list.css +1 -1
- data/app/components/primer/alpha/action_list.css.json +1 -0
- data/app/components/primer/alpha/action_list.css.map +1 -1
- data/app/components/primer/alpha/action_list.pcss +3 -1
- data/app/components/primer/alpha/action_list.rb +5 -4
- data/app/components/primer/alpha/action_menu/action_menu_element.d.ts +20 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.js +92 -15
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +115 -13
- data/app/components/primer/alpha/action_menu/group.rb +23 -0
- data/app/components/primer/alpha/action_menu/heading.rb +17 -0
- data/app/components/primer/alpha/action_menu/list.html.erb +1 -0
- data/app/components/primer/alpha/action_menu/list.rb +62 -51
- data/app/components/primer/alpha/action_menu/list_wrapper.rb +40 -0
- data/app/components/primer/alpha/action_menu.rb +38 -1
- data/app/components/primer/alpha/banner.html.erb +1 -1
- data/app/components/primer/alpha/banner.rb +5 -1
- data/app/components/primer/alpha/dialog.html.erb +3 -1
- data/app/components/primer/alpha/dialog.rb +5 -1
- data/app/components/primer/alpha/layout.css +1 -1
- data/app/components/primer/alpha/layout.css.map +1 -1
- data/app/components/primer/alpha/modal_dialog.ts +1 -1
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +4 -2
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/overlay.pcss +12 -2
- data/app/components/primer/alpha/text_field.css +1 -1
- data/app/components/primer/alpha/text_field.css.map +1 -1
- data/app/components/primer/alpha/text_field.pcss +4 -3
- data/app/components/primer/alpha/tool_tip.js +22 -5
- data/app/components/primer/alpha/tool_tip.ts +24 -5
- data/app/components/primer/alpha/underline_nav.css +1 -1
- data/app/components/primer/alpha/underline_nav.css.map +1 -1
- data/app/components/primer/base_component.rb +20 -18
- data/app/components/primer/beta/auto_complete/auto_complete.html.erb +1 -7
- data/app/components/primer/beta/auto_complete/item.rb +1 -1
- data/app/components/primer/beta/auto_complete.rb +6 -1
- data/app/components/primer/beta/base_button.rb +2 -3
- data/app/components/primer/beta/blankslate.css +1 -1
- data/app/components/primer/beta/blankslate.css.map +1 -1
- data/app/components/primer/beta/blankslate.pcss +3 -3
- data/app/components/primer/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +9 -8
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.pcss +15 -11
- data/app/components/primer/beta/nav_list/group.html.erb +7 -5
- data/app/components/primer/beta/nav_list/group.rb +2 -2
- data/app/components/primer/beta/nav_list.d.ts +0 -11
- data/app/components/primer/beta/nav_list.js +2 -85
- data/app/components/primer/beta/nav_list.ts +1 -85
- data/app/components/primer/beta/nav_list_group_element.d.ts +19 -0
- data/app/components/primer/beta/nav_list_group_element.js +108 -0
- data/app/components/primer/beta/nav_list_group_element.ts +97 -0
- data/app/components/primer/beta/relative_time.rb +4 -4
- data/app/components/primer/component.rb +3 -0
- data/app/components/primer/primer.d.ts +2 -0
- data/app/components/primer/primer.js +2 -0
- data/app/components/primer/primer.ts +2 -0
- data/app/components/primer/scrollable_region.d.ts +13 -0
- data/app/components/primer/scrollable_region.js +52 -0
- data/app/components/primer/scrollable_region.ts +48 -0
- data/app/lib/primer/experimental_render_helpers.rb +32 -0
- data/app/lib/primer/experimental_slot_helpers.rb +30 -0
- data/lib/primer/classify/utilities.rb +3 -4
- data/lib/primer/view_components/version.rb +2 -2
- data/lib/primer/yard/lookbook_pages_backend.rb +2 -2
- data/previews/primer/alpha/action_menu_preview/in_scroll_container.html.erb +11 -0
- data/previews/primer/alpha/action_menu_preview.rb +80 -7
- data/previews/primer/alpha/banner_preview.rb +3 -2
- data/previews/primer/alpha/dialog_preview/with_auto_complete.html.erb +8 -0
- data/previews/primer/alpha/dialog_preview.rb +17 -0
- data/previews/primer/beta/blankslate_preview/inside_flex_container.html.erb +6 -0
- data/previews/primer/beta/blankslate_preview.rb +3 -0
- data/previews/primer/beta/nav_list_preview.rb +10 -1
- data/static/arguments.json +92 -1
- data/static/audited_at.json +4 -1
- data/static/classes.json +3 -0
- data/static/constants.json +9 -0
- data/static/info_arch.json +256 -52
- data/static/previews.json +52 -0
- data/static/statuses.json +3 -0
- metadata +19 -2
@@ -1 +1 @@
|
|
1
|
-
.ActionBar{display:flex!important;flex-grow:1;flex-shrink:1;justify-content:flex-end;min-width:calc(var(--control-medium-size,2rem)*3);overflow:hidden;position:relative}.ActionBar
|
1
|
+
.ActionBar{align-items:center;box-sizing:initial;display:flex!important;flex-grow:1;flex-shrink:1;justify-content:flex-end;min-width:calc(var(--control-medium-size,2rem)*3);overflow:hidden;position:relative}.ActionBar-item-container{box-sizing:initial;height:var(--control-medium-size,2rem);overflow:hidden}.ActionBar-item{float:left;position:relative}.ActionBar-more-menu{float:left}.ActionBar--small{min-width:calc(var(--control-small-size,1.75rem)*3)}.ActionBar--large{min-width:calc(var(--control-large-size,2.5rem)*3)}.ActionBar-divider{border-left:var(--borderWidth-thin,max(1px,.0625rem)) solid var(--borderColor-muted,var(--color-border-muted));bottom:50%;float:left;height:calc(var(--control-medium-size,2rem)/2);margin:0 var(--controlStack-medium-gap-condensed,.5rem);top:50%;transform:translateY(-50%)}.ActionBar--small .ActionBar-divider{margin:0 var(--controlStack-small-gap-condensed,.5rem)}.ActionBar--large .ActionBar-divider{margin:0 var(--controlStack-large-gap-condensed,.5rem)}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["action_bar.pcss"],"names":[],"mappings":"AACA,
|
1
|
+
{"version":3,"sources":["action_bar.pcss"],"names":[],"mappings":"AACA,WAIE,kBAAmB,CAGnB,kBAAuB,CALvB,sBAAwB,CAGxB,WAAY,CACZ,aAAc,CAGd,wBAAyB,CANzB,iDAA+C,CAK/C,eAAgB,CAPhB,iBASF,CAEA,0BACE,kBAAuB,CAEvB,sCAAkC,CADlC,eAEF,CAEA,gBAEE,UAAW,CADX,iBAEF,CAEA,qBACE,UACF,CAEA,kBACE,mDACF,CAEA,kBACE,kDACF,CAIA,mBAGE,8GAAmE,CAGnE,UAAW,CAFX,UAAW,CAHX,8CAA4C,CAC5C,uDAAkD,CAGlD,OAAQ,CAER,0BACF,CAEA,qCACE,sDACF,CAEA,qCACE,sDACF","file":"action_bar.css","sourcesContent":["/* CSS for ActionBar */\n.ActionBar {\n position: relative;\n display: flex !important;\n min-width: calc(var(--control-medium-size) * 3);\n align-items: center;\n flex-grow: 1;\n flex-shrink: 1;\n box-sizing: content-box;\n overflow: hidden;\n justify-content: flex-end;\n}\n\n.ActionBar-item-container {\n box-sizing: content-box;\n overflow: hidden;\n height: var(--control-medium-size);\n}\n\n.ActionBar-item {\n position: relative;\n float: left;\n}\n\n.ActionBar-more-menu {\n float: left;\n}\n\n.ActionBar--small {\n min-width: calc(var(--control-small-size) * 3);\n}\n\n.ActionBar--large {\n min-width: calc(var(--control-large-size) * 3);\n}\n\n/* Divider */\n\n.ActionBar-divider {\n height: calc(var(--control-medium-size) / 2);\n margin: 0 var(--controlStack-medium-gap-condensed);\n border-left: var(--borderWidth-thin) solid var(--borderColor-muted);\n float: left;\n top: 50%;\n bottom: 50%;\n transform: translateY(-50%);\n}\n\n.ActionBar--small .ActionBar-divider {\n margin: 0 var(--controlStack-small-gap-condensed);\n}\n\n.ActionBar--large .ActionBar-divider {\n margin: 0 var(--controlStack-large-gap-condensed);\n}\n"]}
|
@@ -12,20 +12,18 @@
|
|
12
12
|
}
|
13
13
|
|
14
14
|
.ActionBar-item-container {
|
15
|
-
display: flex;
|
16
15
|
box-sizing: content-box;
|
17
|
-
|
18
|
-
|
19
|
-
flex-grow: 0;
|
16
|
+
overflow: hidden;
|
17
|
+
height: var(--control-medium-size);
|
20
18
|
}
|
21
19
|
|
22
20
|
.ActionBar-item {
|
23
21
|
position: relative;
|
24
|
-
|
22
|
+
float: left;
|
25
23
|
}
|
26
24
|
|
27
25
|
.ActionBar-more-menu {
|
28
|
-
|
26
|
+
float: left;
|
29
27
|
}
|
30
28
|
|
31
29
|
.ActionBar--small {
|
@@ -42,6 +40,10 @@
|
|
42
40
|
height: calc(var(--control-medium-size) / 2);
|
43
41
|
margin: 0 var(--controlStack-medium-gap-condensed);
|
44
42
|
border-left: var(--borderWidth-thin) solid var(--borderColor-muted);
|
43
|
+
float: left;
|
44
|
+
top: 50%;
|
45
|
+
bottom: 50%;
|
46
|
+
transform: translateY(-50%);
|
45
47
|
}
|
46
48
|
|
47
49
|
.ActionBar--small .ActionBar-divider {
|
@@ -1,12 +1,13 @@
|
|
1
|
+
import { ActionMenuElement } from './action_menu/action_menu_element';
|
1
2
|
declare class ActionBarElement extends HTMLElement {
|
2
3
|
#private;
|
3
4
|
items: HTMLElement[];
|
4
5
|
itemContainer: HTMLElement;
|
5
|
-
moreMenu:
|
6
|
+
moreMenu: ActionMenuElement;
|
6
7
|
connectedCallback(): void;
|
7
8
|
disconnectedCallback(): void;
|
8
9
|
menuItemClick(event: Event): void;
|
9
|
-
update(
|
10
|
+
update(): void;
|
10
11
|
}
|
11
12
|
declare global {
|
12
13
|
interface Window {
|
@@ -4,18 +4,18 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
4
4
|
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;
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
6
|
};
|
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
|
+
};
|
7
12
|
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
8
13
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
9
14
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
10
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");
|
11
16
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
12
17
|
};
|
13
|
-
var
|
14
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
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
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
17
|
-
};
|
18
|
-
var _ActionBarElement_instances, _ActionBarElement_initialBarWidth, _ActionBarElement_previousBarWidth, _ActionBarElement_focusZoneAbortController, _ActionBarElement_isVisible, _ActionBarElement_itemGap, _ActionBarElement_availableSpace, _ActionBarElement_menuSpace, _ActionBarElement_shrink, _ActionBarElement_grow, _ActionBarElement_showItem, _ActionBarElement_hideItem, _ActionBarElement_menuItems_get;
|
18
|
+
var _ActionBarElement_instances, _ActionBarElement_focusZoneAbortController, _ActionBarElement_firstItem_get, _ActionBarElement_showItem, _ActionBarElement_hideItem, _ActionBarElement_menuItems_get, _ActionBarElement_eachItem;
|
19
19
|
import { controller, targets, target } from '@github/catalyst';
|
20
20
|
import { focusZone, FocusKeys } from '@primer/behaviors';
|
21
21
|
const instersectionObserver = new IntersectionObserver(entries => {
|
@@ -30,35 +30,43 @@ const resizeObserver = new ResizeObserver(entries => {
|
|
30
30
|
for (const entry of entries) {
|
31
31
|
const action = entry.target;
|
32
32
|
if (action instanceof ActionBarElement) {
|
33
|
-
action.update(
|
33
|
+
action.update();
|
34
34
|
}
|
35
35
|
}
|
36
36
|
});
|
37
|
+
// These are definitely used, but eslint is dumb apparently
|
38
|
+
// eslint-disable-next-line no-unused-vars
|
39
|
+
var ItemType;
|
40
|
+
(function (ItemType) {
|
41
|
+
// eslint-disable-next-line no-unused-vars
|
42
|
+
ItemType[ItemType["Item"] = 0] = "Item";
|
43
|
+
// eslint-disable-next-line no-unused-vars
|
44
|
+
ItemType[ItemType["Divider"] = 1] = "Divider";
|
45
|
+
})(ItemType || (ItemType = {}));
|
37
46
|
let ActionBarElement = class ActionBarElement extends HTMLElement {
|
38
47
|
constructor() {
|
39
48
|
super(...arguments);
|
40
49
|
_ActionBarElement_instances.add(this);
|
41
|
-
_ActionBarElement_initialBarWidth.set(this, void 0);
|
42
|
-
_ActionBarElement_previousBarWidth.set(this, void 0);
|
43
50
|
_ActionBarElement_focusZoneAbortController.set(this, null);
|
44
51
|
}
|
45
52
|
connectedCallback() {
|
46
|
-
var _a, _b
|
47
|
-
__classPrivateFieldSet(this, _ActionBarElement_previousBarWidth, (_a = this.offsetWidth) !== null && _a !== void 0 ? _a : Infinity, "f");
|
48
|
-
__classPrivateFieldSet(this, _ActionBarElement_initialBarWidth, (_b = this.itemContainer.offsetWidth) !== null && _b !== void 0 ? _b : Infinity, "f");
|
53
|
+
var _a, _b;
|
49
54
|
// Calculate the width of all the items before hiding anything
|
50
55
|
for (const item of this.items) {
|
51
56
|
const width = item.getBoundingClientRect().width;
|
52
|
-
const marginLeft = parseInt((
|
53
|
-
const marginRight = parseInt((
|
57
|
+
const marginLeft = parseInt((_a = window.getComputedStyle(item)) === null || _a === void 0 ? void 0 : _a.marginLeft, 10);
|
58
|
+
const marginRight = parseInt((_b = window.getComputedStyle(item)) === null || _b === void 0 ? void 0 : _b.marginRight, 10);
|
54
59
|
item.setAttribute('data-offset-width', `${width + marginLeft + marginRight}`);
|
55
60
|
}
|
56
61
|
resizeObserver.observe(this);
|
57
62
|
instersectionObserver.observe(this);
|
58
|
-
|
63
|
+
requestAnimationFrame(() => {
|
64
|
+
// This overflow visible is needed for browsers that don't support PopoverElement
|
65
|
+
// to ensure the menu and tooltips are visible when the action bar is in a collapsed state
|
66
|
+
// once popover is fully supported we can remove this.style.overflow = 'visible'
|
59
67
|
this.style.overflow = 'visible';
|
60
68
|
this.update();
|
61
|
-
}
|
69
|
+
});
|
62
70
|
}
|
63
71
|
disconnectedCallback() {
|
64
72
|
resizeObserver.unobserve(this);
|
@@ -72,21 +80,37 @@ let ActionBarElement = class ActionBarElement extends HTMLElement {
|
|
72
80
|
(_a = document.getElementById(id)) === null || _a === void 0 ? void 0 : _a.click();
|
73
81
|
}
|
74
82
|
}
|
75
|
-
update(
|
76
|
-
|
77
|
-
if (
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
update() {
|
84
|
+
const firstItem = __classPrivateFieldGet(this, _ActionBarElement_instances, "a", _ActionBarElement_firstItem_get);
|
85
|
+
if (!firstItem)
|
86
|
+
return;
|
87
|
+
const firstItemTop = firstItem.getBoundingClientRect().top;
|
88
|
+
let previousItemType = null;
|
89
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_eachItem).call(this, (item, index, type) => {
|
90
|
+
const itemTop = item.getBoundingClientRect().top;
|
91
|
+
if (type === ItemType.Item) {
|
92
|
+
if (itemTop > firstItemTop) {
|
93
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItem).call(this, index);
|
94
|
+
if (this.moreMenu.hidden) {
|
95
|
+
this.moreMenu.hidden = false;
|
96
|
+
}
|
97
|
+
if (previousItemType === ItemType.Divider) {
|
98
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItem).call(this, index - 1);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
else {
|
102
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItem).call(this, index);
|
103
|
+
if (index === this.items.length - 1) {
|
104
|
+
this.moreMenu.hidden = true;
|
105
|
+
}
|
106
|
+
if (previousItemType === ItemType.Divider) {
|
107
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItem).call(this, index - 1);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
previousItemType = type;
|
112
|
+
return true;
|
113
|
+
});
|
90
114
|
if (__classPrivateFieldGet(this, _ActionBarElement_focusZoneAbortController, "f")) {
|
91
115
|
__classPrivateFieldGet(this, _ActionBarElement_focusZoneAbortController, "f").abort();
|
92
116
|
}
|
@@ -94,88 +118,47 @@ let ActionBarElement = class ActionBarElement extends HTMLElement {
|
|
94
118
|
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
|
95
119
|
focusOutBehavior: 'wrap',
|
96
120
|
focusableElementFilter: element => {
|
97
|
-
|
98
|
-
|
121
|
+
const idx = this.items.indexOf(element.parentElement);
|
122
|
+
const elementIsVisibleItem = idx > -1 && this.items[idx].style.visibility === 'visible';
|
123
|
+
const elementIsVisibleActionMenuInvoker = element === this.moreMenu.invokerElement && !this.moreMenu.hidden;
|
124
|
+
return elementIsVisibleItem || elementIsVisibleActionMenuInvoker;
|
125
|
+
},
|
99
126
|
}), "f");
|
100
127
|
}
|
101
128
|
};
|
102
|
-
_ActionBarElement_initialBarWidth = new WeakMap();
|
103
|
-
_ActionBarElement_previousBarWidth = new WeakMap();
|
104
129
|
_ActionBarElement_focusZoneAbortController = new WeakMap();
|
105
130
|
_ActionBarElement_instances = new WeakSet();
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
return Boolean(element.offsetParent || element.offsetWidth || element.offsetHeight);
|
113
|
-
};
|
114
|
-
_ActionBarElement_itemGap = function _ActionBarElement_itemGap() {
|
115
|
-
var _a;
|
116
|
-
return parseInt((_a = window.getComputedStyle(this.itemContainer)) === null || _a === void 0 ? void 0 : _a.columnGap, 10) || 0;
|
117
|
-
};
|
118
|
-
_ActionBarElement_availableSpace = function _ActionBarElement_availableSpace() {
|
119
|
-
// Get the offset of the item container from the container edge
|
120
|
-
return this.offsetWidth - this.itemContainer.offsetWidth;
|
121
|
-
};
|
122
|
-
_ActionBarElement_menuSpace = function _ActionBarElement_menuSpace() {
|
123
|
-
if (this.moreMenu.hidden) {
|
124
|
-
return 0;
|
125
|
-
}
|
126
|
-
return this.moreMenu.offsetWidth + __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_itemGap).call(this);
|
127
|
-
};
|
128
|
-
_ActionBarElement_shrink = function _ActionBarElement_shrink() {
|
129
|
-
if (this.items[0].hidden) {
|
130
|
-
return;
|
131
|
-
}
|
132
|
-
let index = this.items.length - 1;
|
133
|
-
for (const item of this.items.reverse()) {
|
134
|
-
if (!item.hidden && __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) < __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_menuSpace).call(this)) {
|
135
|
-
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_hideItem).call(this, index);
|
131
|
+
_ActionBarElement_firstItem_get = function _ActionBarElement_firstItem_get() {
|
132
|
+
let foundItem = null;
|
133
|
+
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_eachItem).call(this, (item, _index, type) => {
|
134
|
+
if (type === ItemType.Item) {
|
135
|
+
foundItem = item;
|
136
|
+
return false;
|
136
137
|
}
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
index--;
|
141
|
-
}
|
142
|
-
};
|
143
|
-
_ActionBarElement_grow = function _ActionBarElement_grow() {
|
144
|
-
// If last item is visible, there is no need to grow
|
145
|
-
if (!this.items[this.items.length - 1].hidden) {
|
146
|
-
return;
|
147
|
-
}
|
148
|
-
let index = 0;
|
149
|
-
for (const item of this.items) {
|
150
|
-
if (item.hidden) {
|
151
|
-
const offsetWidth = Number(item.getAttribute('data-offset-width'));
|
152
|
-
if (__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_availableSpace).call(this) >= __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_menuSpace).call(this) + offsetWidth || index === this.items.length - 1) {
|
153
|
-
__classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_showItem).call(this, index);
|
154
|
-
}
|
155
|
-
else {
|
156
|
-
return;
|
157
|
-
}
|
158
|
-
}
|
159
|
-
index++;
|
160
|
-
}
|
161
|
-
if (!this.items[this.items.length - 1].hidden) {
|
162
|
-
this.moreMenu.hidden = true;
|
163
|
-
}
|
138
|
+
return true;
|
139
|
+
});
|
140
|
+
return foundItem;
|
164
141
|
};
|
165
142
|
_ActionBarElement_showItem = function _ActionBarElement_showItem(index) {
|
166
|
-
this.items[index].
|
143
|
+
this.items[index].style.setProperty('visibility', 'visible');
|
167
144
|
__classPrivateFieldGet(this, _ActionBarElement_instances, "a", _ActionBarElement_menuItems_get)[index].hidden = true;
|
168
145
|
};
|
169
146
|
_ActionBarElement_hideItem = function _ActionBarElement_hideItem(index) {
|
170
|
-
this.items[index].hidden
|
147
|
+
this.items[index].style.setProperty('visibility', 'hidden');
|
171
148
|
__classPrivateFieldGet(this, _ActionBarElement_instances, "a", _ActionBarElement_menuItems_get)[index].hidden = false;
|
172
|
-
if (this.moreMenu.hidden) {
|
173
|
-
this.moreMenu.hidden = false;
|
174
|
-
}
|
175
149
|
};
|
176
150
|
_ActionBarElement_menuItems_get = function _ActionBarElement_menuItems_get() {
|
177
151
|
return this.moreMenu.querySelectorAll('[role="menu"] > li');
|
178
152
|
};
|
153
|
+
_ActionBarElement_eachItem = function _ActionBarElement_eachItem(callback) {
|
154
|
+
for (let i = 0; i < this.items.length; i++) {
|
155
|
+
const item = this.items[i];
|
156
|
+
const type = item.classList.contains('ActionBar-divider') ? ItemType.Divider : ItemType.Item;
|
157
|
+
if (!callback(item, i, type)) {
|
158
|
+
break;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
};
|
179
162
|
__decorate([
|
180
163
|
targets
|
181
164
|
], ActionBarElement.prototype, "items", void 0);
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import {controller, targets, target} from '@github/catalyst'
|
2
2
|
import {focusZone, FocusKeys} from '@primer/behaviors'
|
3
|
+
import {ActionMenuElement} from './action_menu/action_menu_element'
|
3
4
|
|
4
5
|
const instersectionObserver = new IntersectionObserver(entries => {
|
5
6
|
for (const entry of entries) {
|
@@ -14,25 +15,30 @@ const resizeObserver = new ResizeObserver(entries => {
|
|
14
15
|
for (const entry of entries) {
|
15
16
|
const action = entry.target
|
16
17
|
if (action instanceof ActionBarElement) {
|
17
|
-
action.update(
|
18
|
+
action.update()
|
18
19
|
}
|
19
20
|
}
|
20
21
|
})
|
21
22
|
|
23
|
+
// These are definitely used, but eslint is dumb apparently
|
24
|
+
|
25
|
+
// eslint-disable-next-line no-unused-vars
|
26
|
+
enum ItemType {
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
28
|
+
Item,
|
29
|
+
// eslint-disable-next-line no-unused-vars
|
30
|
+
Divider,
|
31
|
+
}
|
32
|
+
|
22
33
|
@controller
|
23
34
|
class ActionBarElement extends HTMLElement {
|
24
35
|
@targets items: HTMLElement[]
|
25
36
|
@target itemContainer: HTMLElement
|
26
|
-
@target moreMenu:
|
37
|
+
@target moreMenu: ActionMenuElement
|
27
38
|
|
28
|
-
#initialBarWidth: number
|
29
|
-
#previousBarWidth: number
|
30
39
|
#focusZoneAbortController: AbortController | null = null
|
31
40
|
|
32
41
|
connectedCallback() {
|
33
|
-
this.#previousBarWidth = this.offsetWidth ?? Infinity
|
34
|
-
this.#initialBarWidth = this.itemContainer.offsetWidth ?? Infinity
|
35
|
-
|
36
42
|
// Calculate the width of all the items before hiding anything
|
37
43
|
for (const item of this.items) {
|
38
44
|
const width = item.getBoundingClientRect().width
|
@@ -44,10 +50,13 @@ class ActionBarElement extends HTMLElement {
|
|
44
50
|
resizeObserver.observe(this)
|
45
51
|
instersectionObserver.observe(this)
|
46
52
|
|
47
|
-
|
53
|
+
requestAnimationFrame(() => {
|
54
|
+
// This overflow visible is needed for browsers that don't support PopoverElement
|
55
|
+
// to ensure the menu and tooltips are visible when the action bar is in a collapsed state
|
56
|
+
// once popover is fully supported we can remove this.style.overflow = 'visible'
|
48
57
|
this.style.overflow = 'visible'
|
49
58
|
this.update()
|
50
|
-
}
|
59
|
+
})
|
51
60
|
}
|
52
61
|
|
53
62
|
disconnectedCallback() {
|
@@ -65,114 +74,100 @@ class ActionBarElement extends HTMLElement {
|
|
65
74
|
}
|
66
75
|
}
|
67
76
|
|
68
|
-
update(
|
69
|
-
|
70
|
-
if (
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
this.#
|
77
|
+
update() {
|
78
|
+
const firstItem = this.#firstItem
|
79
|
+
if (!firstItem) return
|
80
|
+
|
81
|
+
const firstItemTop = firstItem.getBoundingClientRect().top
|
82
|
+
let previousItemType: ItemType | null = null
|
83
|
+
|
84
|
+
this.#eachItem((item: HTMLElement, index: number, type: ItemType): boolean => {
|
85
|
+
const itemTop = item.getBoundingClientRect().top
|
86
|
+
|
87
|
+
if (type === ItemType.Item) {
|
88
|
+
if (itemTop > firstItemTop) {
|
89
|
+
this.#hideItem(index)
|
90
|
+
|
91
|
+
if (this.moreMenu.hidden) {
|
92
|
+
this.moreMenu.hidden = false
|
93
|
+
}
|
94
|
+
|
95
|
+
if (previousItemType === ItemType.Divider) {
|
96
|
+
this.#hideItem(index - 1)
|
97
|
+
}
|
98
|
+
} else {
|
99
|
+
this.#showItem(index)
|
100
|
+
|
101
|
+
if (index === this.items.length - 1) {
|
102
|
+
this.moreMenu.hidden = true
|
103
|
+
}
|
104
|
+
|
105
|
+
if (previousItemType === ItemType.Divider) {
|
106
|
+
this.#showItem(index - 1)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
previousItemType = type
|
112
|
+
|
113
|
+
return true
|
114
|
+
})
|
76
115
|
|
77
|
-
if (rect.width <= this.#initialBarWidth) {
|
78
|
-
this.style.justifyContent = 'space-between'
|
79
|
-
} else {
|
80
|
-
this.style.justifyContent = 'flex-end'
|
81
|
-
}
|
82
116
|
if (this.#focusZoneAbortController) {
|
83
117
|
this.#focusZoneAbortController.abort()
|
84
118
|
}
|
119
|
+
|
85
120
|
this.#focusZoneAbortController = focusZone(this, {
|
86
121
|
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
|
87
122
|
focusOutBehavior: 'wrap',
|
88
123
|
focusableElementFilter: element => {
|
89
|
-
|
90
|
-
|
124
|
+
const idx = this.items.indexOf(element.parentElement!)
|
125
|
+
const elementIsVisibleItem = idx > -1 && this.items[idx].style.visibility === 'visible'
|
126
|
+
const elementIsVisibleActionMenuInvoker = element === this.moreMenu.invokerElement && !this.moreMenu.hidden
|
127
|
+
return elementIsVisibleItem || elementIsVisibleActionMenuInvoker
|
128
|
+
},
|
91
129
|
})
|
92
130
|
}
|
93
131
|
|
94
|
-
#
|
95
|
-
|
96
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
97
|
-
// @ts-ignore
|
98
|
-
if (typeof element.checkVisibility === 'function') return element.checkVisibility()
|
132
|
+
get #firstItem(): HTMLElement | null {
|
133
|
+
let foundItem = null
|
99
134
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
return parseInt(window.getComputedStyle(this.itemContainer)?.columnGap, 10) || 0
|
105
|
-
}
|
106
|
-
|
107
|
-
#availableSpace(): number {
|
108
|
-
// Get the offset of the item container from the container edge
|
109
|
-
return this.offsetWidth - this.itemContainer.offsetWidth
|
110
|
-
}
|
111
|
-
|
112
|
-
#menuSpace(): number {
|
113
|
-
if (this.moreMenu.hidden) {
|
114
|
-
return 0
|
115
|
-
}
|
116
|
-
return this.moreMenu.offsetWidth + this.#itemGap()
|
117
|
-
}
|
118
|
-
|
119
|
-
#shrink() {
|
120
|
-
if (this.items[0]!.hidden) {
|
121
|
-
return
|
122
|
-
}
|
123
|
-
|
124
|
-
let index = this.items.length - 1
|
125
|
-
for (const item of this.items.reverse()) {
|
126
|
-
if (!item.hidden && this.#availableSpace() < this.#menuSpace()) {
|
127
|
-
this.#hideItem(index)
|
128
|
-
} else if (this.#availableSpace() >= this.#menuSpace()) {
|
129
|
-
return
|
135
|
+
this.#eachItem((item: HTMLElement, _index: number, type: ItemType): boolean => {
|
136
|
+
if (type === ItemType.Item) {
|
137
|
+
foundItem = item
|
138
|
+
return false
|
130
139
|
}
|
131
|
-
index--
|
132
|
-
}
|
133
|
-
}
|
134
|
-
|
135
|
-
#grow() {
|
136
|
-
// If last item is visible, there is no need to grow
|
137
|
-
if (!this.items[this.items.length - 1]!.hidden) {
|
138
|
-
return
|
139
|
-
}
|
140
|
-
let index = 0
|
141
|
-
for (const item of this.items) {
|
142
|
-
if (item.hidden) {
|
143
|
-
const offsetWidth = Number(item.getAttribute('data-offset-width'))
|
144
140
|
|
145
|
-
|
146
|
-
|
147
|
-
} else {
|
148
|
-
return
|
149
|
-
}
|
150
|
-
}
|
151
|
-
index++
|
152
|
-
}
|
141
|
+
return true
|
142
|
+
})
|
153
143
|
|
154
|
-
|
155
|
-
this.moreMenu.hidden = true
|
156
|
-
}
|
144
|
+
return foundItem
|
157
145
|
}
|
158
146
|
|
159
147
|
#showItem(index: number) {
|
160
|
-
this.items[index]
|
148
|
+
this.items[index].style.setProperty('visibility', 'visible')
|
161
149
|
this.#menuItems[index]!.hidden = true
|
162
150
|
}
|
163
151
|
|
164
152
|
#hideItem(index: number) {
|
165
|
-
this.items[index]
|
153
|
+
this.items[index].style.setProperty('visibility', 'hidden')
|
166
154
|
this.#menuItems[index]!.hidden = false
|
167
|
-
|
168
|
-
if (this.moreMenu.hidden) {
|
169
|
-
this.moreMenu.hidden = false
|
170
|
-
}
|
171
155
|
}
|
172
156
|
|
173
157
|
get #menuItems(): NodeListOf<HTMLElement> {
|
174
158
|
return this.moreMenu.querySelectorAll('[role="menu"] > li')
|
175
159
|
}
|
160
|
+
|
161
|
+
// eslint-disable-next-line no-unused-vars
|
162
|
+
#eachItem(callback: (item: HTMLElement, index: number, type: ItemType) => boolean): void {
|
163
|
+
for (let i = 0; i < this.items.length; i++) {
|
164
|
+
const item = this.items[i]
|
165
|
+
const type = item.classList.contains('ActionBar-divider') ? ItemType.Divider : ItemType.Item
|
166
|
+
if (!callback(item, i, type)) {
|
167
|
+
break
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
176
171
|
}
|
177
172
|
|
178
173
|
declare global {
|
@@ -128,7 +128,7 @@ module Primer
|
|
128
128
|
# @private
|
129
129
|
renders_one :private_content
|
130
130
|
|
131
|
-
attr_reader :id, :list, :href, :active, :disabled, :parent
|
131
|
+
attr_reader :id, :item_id, :list, :href, :active, :disabled, :parent
|
132
132
|
|
133
133
|
# Whether or not this item is active.
|
134
134
|
#
|
@@ -143,6 +143,7 @@ module Primer
|
|
143
143
|
# @param list [Primer::Alpha::ActionList] The list that contains this item. Used internally.
|
144
144
|
# @param parent [Primer::Alpha::ActionList::Item] This item's parent item. `nil` if this item is at the root. Used internally.
|
145
145
|
# @param label [String] Item label. If no label is provided, content is used.
|
146
|
+
# @param item_id [String] An ID that will be attached to the item's `<li>` element as `data-item-id` for distinguishing between items, perhaps in JavaScript.
|
146
147
|
# @param label_classes [String] CSS classes that will be added to the label.
|
147
148
|
# @param label_arguments [Hash] <%= link_to_system_arguments_docs %> used to construct the label.
|
148
149
|
# @param content_arguments [Hash] <%= link_to_system_arguments_docs %> used to construct the item's anchor or button tag.
|
@@ -161,6 +162,7 @@ module Primer
|
|
161
162
|
def initialize(
|
162
163
|
list:,
|
163
164
|
label: nil,
|
165
|
+
item_id: nil,
|
164
166
|
label_classes: nil,
|
165
167
|
label_arguments: {},
|
166
168
|
content_arguments: {},
|
@@ -181,6 +183,7 @@ module Primer
|
|
181
183
|
@list = list
|
182
184
|
@parent = parent
|
183
185
|
@label = label
|
186
|
+
@item_id = item_id
|
184
187
|
@href = href || content_arguments[:href]
|
185
188
|
@truncate_label = truncate_label
|
186
189
|
@disabled = disabled
|
@@ -206,6 +209,15 @@ module Primer
|
|
206
209
|
@system_arguments[:data] ||= {}
|
207
210
|
@system_arguments[:data][:targets] = "#{list_class.custom_element_name}.items"
|
208
211
|
|
212
|
+
@system_arguments[:data] = merge_data(
|
213
|
+
@system_arguments, {
|
214
|
+
data: {
|
215
|
+
targets: "#{list_class.custom_element_name}.items",
|
216
|
+
**(@item_id ? { item_id: @item_id } : {})
|
217
|
+
}
|
218
|
+
}
|
219
|
+
)
|
220
|
+
|
209
221
|
@label_arguments = {
|
210
222
|
**label_arguments,
|
211
223
|
classes: class_names(
|