primer_view_components 0.1.4 → 0.1.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -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 +2 -2
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/heading.html.erb +1 -1
- data/app/components/primer/alpha/action_list/heading.rb +5 -3
- data/app/components/primer/alpha/action_list/item.html.erb +9 -0
- data/app/components/primer/alpha/action_list/item.rb +31 -10
- data/app/components/primer/alpha/action_list.css +1 -1
- data/app/components/primer/alpha/action_list.css.json +4 -41
- data/app/components/primer/alpha/action_list.css.map +1 -1
- data/app/components/primer/alpha/action_list.pcss +19 -20
- data/app/components/primer/alpha/action_list.rb +54 -6
- data/app/components/primer/alpha/action_menu/action_menu_element.d.ts +22 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.js +139 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +137 -0
- data/app/components/primer/alpha/action_menu/list.rb +81 -0
- data/app/components/primer/alpha/action_menu.html.erb +26 -0
- data/app/components/primer/alpha/action_menu.rb +322 -0
- data/app/components/primer/alpha/auto_complete.css.json +0 -11
- data/app/components/primer/alpha/banner.css.json +0 -14
- data/app/components/primer/alpha/button_marketing.css.json +0 -10
- data/app/components/primer/alpha/dialog.css.json +0 -63
- data/app/components/primer/alpha/dialog.rb +6 -2
- data/app/components/primer/alpha/dropdown.css.json +0 -21
- data/app/components/primer/alpha/layout.css.json +0 -27
- data/app/components/primer/alpha/menu.css.json +0 -11
- data/app/components/primer/alpha/nav_list/item.rb +5 -0
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +0 -3
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/overlay.pcss +1 -0
- data/app/components/primer/alpha/overlay.rb +14 -18
- data/app/components/primer/alpha/segmented_control.css.json +0 -15
- data/app/components/primer/alpha/tab_nav.css.json +0 -10
- data/app/components/primer/alpha/text_field.css.json +0 -38
- data/app/components/primer/alpha/toggle_switch.css.json +0 -16
- data/app/components/primer/alpha/underline_nav.css.json +0 -13
- data/app/components/primer/beta/avatar.css.json +0 -14
- data/app/components/primer/beta/avatar_stack.css.json +0 -9
- data/app/components/primer/beta/blankslate.css.json +0 -12
- data/app/components/primer/beta/border_box.css.json +0 -32
- data/app/components/primer/beta/border_box.rb +3 -3
- data/app/components/primer/beta/breadcrumbs.css.json +0 -4
- data/app/components/primer/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +0 -22
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.pcss +3 -3
- data/app/components/primer/beta/counter.css.json +0 -6
- data/app/components/primer/beta/flash.css.json +0 -15
- data/app/components/primer/beta/label.css.json +0 -20
- data/app/components/primer/beta/link.css.json +0 -8
- data/app/components/primer/beta/popover.css.json +0 -18
- data/app/components/primer/beta/progress_bar.css.json +0 -6
- data/app/components/primer/beta/state.css.json +0 -10
- data/app/components/primer/beta/subhead.css.json +0 -8
- data/app/components/primer/beta/timeline_item.css.json +0 -9
- data/app/components/primer/beta/truncate.css.json +0 -6
- data/app/components/primer/focus_group.d.ts +19 -0
- data/app/components/primer/focus_group.js +144 -0
- data/app/components/primer/focus_group.ts +137 -0
- data/app/components/primer/icon_button.rb +1 -1
- 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/truncate.css.json +0 -7
- data/app/lib/primer/css/layout.css.json +0 -263
- data/app/lib/primer/css/utilities.css.json +0 -1636
- data/lib/primer/static/generate_arguments.rb +55 -0
- data/lib/primer/static/generate_audited_at.rb +17 -0
- data/lib/primer/static/generate_constants.rb +19 -0
- data/lib/primer/static/generate_info_arch.rb +156 -0
- data/lib/primer/static/generate_previews.rb +45 -0
- data/lib/primer/static/generate_statuses.rb +17 -0
- data/lib/primer/static.rb +72 -0
- data/lib/primer/view_components/linters/disallow_component_css_counter.rb +43 -4
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/primer/view_components.rb +0 -48
- data/lib/primer/yard/component_manifest.rb +1 -0
- data/lib/primer/yard/component_ref.rb +14 -0
- data/lib/primer/yard/docs_helper.rb +3 -0
- data/lib/primer/yard/info_arch_docs_helper.rb +31 -0
- data/lib/primer/yard/legacy_gatsby_backend.rb +3 -35
- data/lib/primer/yard/registry.rb +2 -1
- data/lib/primer/yard.rb +1 -0
- data/lib/tasks/docs.rake +10 -12
- data/lib/tasks/static.rake +20 -28
- data/previews/primer/alpha/action_list_preview.rb +4 -1
- data/previews/primer/alpha/action_menu_preview/align_end.html.erb +6 -0
- data/previews/primer/alpha/action_menu_preview/opens_dialog.html.erb +21 -0
- data/previews/primer/alpha/action_menu_preview.rb +238 -0
- data/previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb +2 -2
- data/previews/primer/alpha/dialog_preview/custom_header.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/nested_dialog.html.erb +4 -4
- data/previews/primer/alpha/dialog_preview/test.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/with_footer.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/with_form.html.erb +1 -1
- data/previews/primer/alpha/dialog_preview/with_text_input.html.erb +2 -2
- data/previews/primer/alpha/dialog_preview.rb +7 -2
- data/previews/primer/beta/auto_complete_item_preview.rb +1 -0
- data/static/arguments.json +3078 -1404
- data/static/audited_at.json +2 -0
- data/static/classes.json +576 -311
- data/static/constants.json +42 -2
- data/static/info_arch.json +8859 -0
- data/static/previews.json +221 -101
- data/static/statuses.json +2 -0
- metadata +23 -2
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
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
|
+
};
|
|
12
|
+
var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_setDynamicLabel;
|
|
13
|
+
import '@github/include-fragment-element';
|
|
14
|
+
const popoverSelector = (() => {
|
|
15
|
+
try {
|
|
16
|
+
document.querySelector(':open');
|
|
17
|
+
return ':open';
|
|
18
|
+
}
|
|
19
|
+
catch (_a) {
|
|
20
|
+
return '.\\:open';
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
const menuItemSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]', '[role="none"]'];
|
|
24
|
+
export class ActionMenuElement extends HTMLElement {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
_ActionMenuElement_instances.add(this);
|
|
28
|
+
_ActionMenuElement_abortController.set(this, void 0);
|
|
29
|
+
_ActionMenuElement_originalLabel.set(this, '');
|
|
30
|
+
}
|
|
31
|
+
get selectVariant() {
|
|
32
|
+
return this.getAttribute('data-select-variant');
|
|
33
|
+
}
|
|
34
|
+
set selectVariant(variant) {
|
|
35
|
+
if (variant) {
|
|
36
|
+
this.setAttribute('data-select-variant', variant);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.removeAttribute('variant');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
get dynamicLabelPrefix() {
|
|
43
|
+
const prefix = this.getAttribute('data-dynamic-label-prefix');
|
|
44
|
+
if (!prefix)
|
|
45
|
+
return '';
|
|
46
|
+
return `${prefix}:`;
|
|
47
|
+
}
|
|
48
|
+
set dynamicLabelPrefix(value) {
|
|
49
|
+
this.setAttribute('data-dynamic-label', value);
|
|
50
|
+
}
|
|
51
|
+
get dynamicLabel() {
|
|
52
|
+
return this.hasAttribute('data-dynamic-label');
|
|
53
|
+
}
|
|
54
|
+
set dynamicLabel(value) {
|
|
55
|
+
this.toggleAttribute('data-dynamic-label', value);
|
|
56
|
+
}
|
|
57
|
+
get popoverElement() {
|
|
58
|
+
return this.querySelector('[popover]');
|
|
59
|
+
}
|
|
60
|
+
get invokerElement() {
|
|
61
|
+
var _a;
|
|
62
|
+
const id = (_a = this.querySelector('[role=menu]')) === null || _a === void 0 ? void 0 : _a.id;
|
|
63
|
+
if (!id)
|
|
64
|
+
return null;
|
|
65
|
+
for (const el of this.querySelectorAll(`[aria-controls]`)) {
|
|
66
|
+
if (el.getAttribute('aria-controls') === id)
|
|
67
|
+
return el;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
connectedCallback() {
|
|
72
|
+
const { signal } = (__classPrivateFieldSet(this, _ActionMenuElement_abortController, new AbortController(), "f"));
|
|
73
|
+
this.addEventListener('keydown', this, { signal });
|
|
74
|
+
this.addEventListener('click', this, { signal });
|
|
75
|
+
this.addEventListener('mouseover', this, { signal });
|
|
76
|
+
this.addEventListener('focusout', this, { signal });
|
|
77
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_setDynamicLabel).call(this);
|
|
78
|
+
}
|
|
79
|
+
disconnectedCallback() {
|
|
80
|
+
__classPrivateFieldGet(this, _ActionMenuElement_abortController, "f").abort();
|
|
81
|
+
}
|
|
82
|
+
handleEvent(event) {
|
|
83
|
+
var _a, _b, _c, _d;
|
|
84
|
+
if (!((_a = this.popoverElement) === null || _a === void 0 ? void 0 : _a.matches(popoverSelector)))
|
|
85
|
+
return;
|
|
86
|
+
if (event.type === 'focusout' && !this.contains(event.relatedTarget)) {
|
|
87
|
+
(_b = this.popoverElement) === null || _b === void 0 ? void 0 : _b.hidePopover();
|
|
88
|
+
}
|
|
89
|
+
else if ((event instanceof KeyboardEvent &&
|
|
90
|
+
event.type === 'keydown' &&
|
|
91
|
+
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
|
92
|
+
event.key === 'Enter') ||
|
|
93
|
+
(event instanceof MouseEvent && event.type === 'click')) {
|
|
94
|
+
const item = (_c = event.target.closest(menuItemSelectors.join(','))) === null || _c === void 0 ? void 0 : _c.closest('li');
|
|
95
|
+
if (!item)
|
|
96
|
+
return;
|
|
97
|
+
const ariaChecked = item.getAttribute('aria-checked');
|
|
98
|
+
const checked = ariaChecked !== 'true';
|
|
99
|
+
item.setAttribute('aria-checked', `${checked}`);
|
|
100
|
+
if (this.selectVariant === 'single') {
|
|
101
|
+
const selector = menuItemSelectors.map(s => `li[aria-checked] ${s}`).join(',');
|
|
102
|
+
for (const checkedItemContent of this.querySelectorAll(selector)) {
|
|
103
|
+
const checkedItem = checkedItemContent.closest('li');
|
|
104
|
+
if (checkedItem !== item) {
|
|
105
|
+
checkedItem.setAttribute('aria-checked', 'false');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_setDynamicLabel).call(this);
|
|
109
|
+
}
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
(_d = this.popoverElement) === null || _d === void 0 ? void 0 : _d.hidePopover();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
_ActionMenuElement_abortController = new WeakMap(), _ActionMenuElement_originalLabel = new WeakMap(), _ActionMenuElement_instances = new WeakSet(), _ActionMenuElement_setDynamicLabel = function _ActionMenuElement_setDynamicLabel() {
|
|
116
|
+
if (!this.dynamicLabel)
|
|
117
|
+
return;
|
|
118
|
+
const invoker = this.invokerElement;
|
|
119
|
+
if (!invoker)
|
|
120
|
+
return;
|
|
121
|
+
const selector = menuItemSelectors.map(s => `${s}[aria-checked=true]`).join(',');
|
|
122
|
+
const item = this.querySelector(selector);
|
|
123
|
+
if (item && this.dynamicLabel) {
|
|
124
|
+
__classPrivateFieldSet(this, _ActionMenuElement_originalLabel, __classPrivateFieldGet(this, _ActionMenuElement_originalLabel, "f") || (invoker.textContent || ''), "f");
|
|
125
|
+
const prefixSpan = document.createElement('span');
|
|
126
|
+
prefixSpan.classList.add('color-fg-muted');
|
|
127
|
+
const contentSpan = document.createElement('span');
|
|
128
|
+
prefixSpan.textContent = this.dynamicLabelPrefix;
|
|
129
|
+
contentSpan.textContent = item.textContent || '';
|
|
130
|
+
invoker.replaceChildren(prefixSpan, contentSpan);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
invoker.textContent = __classPrivateFieldGet(this, _ActionMenuElement_originalLabel, "f");
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
if (!window.customElements.get('action-menu')) {
|
|
137
|
+
window.ActionMenuElement = ActionMenuElement;
|
|
138
|
+
window.customElements.define('action-menu', ActionMenuElement);
|
|
139
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import '@github/include-fragment-element'
|
|
2
|
+
|
|
3
|
+
const popoverSelector = (() => {
|
|
4
|
+
try {
|
|
5
|
+
document.querySelector(':open')
|
|
6
|
+
return ':open'
|
|
7
|
+
} catch {
|
|
8
|
+
return '.\\:open'
|
|
9
|
+
}
|
|
10
|
+
})()
|
|
11
|
+
|
|
12
|
+
type SelectVariant = 'single' | 'multiple' | null
|
|
13
|
+
|
|
14
|
+
const menuItemSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]', '[role="none"]']
|
|
15
|
+
|
|
16
|
+
export class ActionMenuElement extends HTMLElement {
|
|
17
|
+
#abortController: AbortController
|
|
18
|
+
#originalLabel = ''
|
|
19
|
+
|
|
20
|
+
get selectVariant(): SelectVariant {
|
|
21
|
+
return this.getAttribute('data-select-variant') as SelectVariant
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
set selectVariant(variant: SelectVariant) {
|
|
25
|
+
if (variant) {
|
|
26
|
+
this.setAttribute('data-select-variant', variant)
|
|
27
|
+
} else {
|
|
28
|
+
this.removeAttribute('variant')
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get dynamicLabelPrefix(): string {
|
|
33
|
+
const prefix = this.getAttribute('data-dynamic-label-prefix')
|
|
34
|
+
if (!prefix) return ''
|
|
35
|
+
return `${prefix}:`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set dynamicLabelPrefix(value: string) {
|
|
39
|
+
this.setAttribute('data-dynamic-label', value)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get dynamicLabel(): boolean {
|
|
43
|
+
return this.hasAttribute('data-dynamic-label')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
set dynamicLabel(value: boolean) {
|
|
47
|
+
this.toggleAttribute('data-dynamic-label', value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get popoverElement(): HTMLElement | null {
|
|
51
|
+
return this.querySelector<HTMLElement>('[popover]')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get invokerElement(): HTMLElement | null {
|
|
55
|
+
const id = this.querySelector('[role=menu]')?.id
|
|
56
|
+
if (!id) return null
|
|
57
|
+
for (const el of this.querySelectorAll(`[aria-controls]`)) {
|
|
58
|
+
if (el.getAttribute('aria-controls') === id) return el as HTMLElement
|
|
59
|
+
}
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
connectedCallback() {
|
|
64
|
+
const {signal} = (this.#abortController = new AbortController())
|
|
65
|
+
this.addEventListener('keydown', this, {signal})
|
|
66
|
+
this.addEventListener('click', this, {signal})
|
|
67
|
+
this.addEventListener('mouseover', this, {signal})
|
|
68
|
+
this.addEventListener('focusout', this, {signal})
|
|
69
|
+
this.#setDynamicLabel()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
disconnectedCallback() {
|
|
73
|
+
this.#abortController.abort()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
handleEvent(event: Event) {
|
|
77
|
+
if (!this.popoverElement?.matches(popoverSelector)) return
|
|
78
|
+
|
|
79
|
+
if (event.type === 'focusout' && !this.contains((event as FocusEvent).relatedTarget as Node)) {
|
|
80
|
+
this.popoverElement?.hidePopover()
|
|
81
|
+
} else if (
|
|
82
|
+
(event instanceof KeyboardEvent &&
|
|
83
|
+
event.type === 'keydown' &&
|
|
84
|
+
!(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
|
|
85
|
+
event.key === 'Enter') ||
|
|
86
|
+
(event instanceof MouseEvent && event.type === 'click')
|
|
87
|
+
) {
|
|
88
|
+
const item = (event.target as Element).closest(menuItemSelectors.join(','))?.closest('li')
|
|
89
|
+
if (!item) return
|
|
90
|
+
const ariaChecked = item.getAttribute('aria-checked')
|
|
91
|
+
const checked = ariaChecked !== 'true'
|
|
92
|
+
item.setAttribute('aria-checked', `${checked}`)
|
|
93
|
+
if (this.selectVariant === 'single') {
|
|
94
|
+
const selector = menuItemSelectors.map(s => `li[aria-checked] ${s}`).join(',')
|
|
95
|
+
for (const checkedItemContent of this.querySelectorAll(selector)) {
|
|
96
|
+
const checkedItem = checkedItemContent.closest('li')!
|
|
97
|
+
if (checkedItem !== item) {
|
|
98
|
+
checkedItem.setAttribute('aria-checked', 'false')
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
this.#setDynamicLabel()
|
|
102
|
+
}
|
|
103
|
+
event.preventDefault()
|
|
104
|
+
this.popoverElement?.hidePopover()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#setDynamicLabel() {
|
|
109
|
+
if (!this.dynamicLabel) return
|
|
110
|
+
const invoker = this.invokerElement
|
|
111
|
+
if (!invoker) return
|
|
112
|
+
const selector = menuItemSelectors.map(s => `${s}[aria-checked=true]`).join(',')
|
|
113
|
+
const item = this.querySelector(selector)
|
|
114
|
+
if (item && this.dynamicLabel) {
|
|
115
|
+
this.#originalLabel ||= invoker.textContent || ''
|
|
116
|
+
const prefixSpan = document.createElement('span')
|
|
117
|
+
prefixSpan.classList.add('color-fg-muted')
|
|
118
|
+
const contentSpan = document.createElement('span')
|
|
119
|
+
prefixSpan.textContent = this.dynamicLabelPrefix
|
|
120
|
+
contentSpan.textContent = item.textContent || ''
|
|
121
|
+
invoker.replaceChildren(prefixSpan, contentSpan)
|
|
122
|
+
} else {
|
|
123
|
+
invoker.textContent = this.#originalLabel
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!window.customElements.get('action-menu')) {
|
|
129
|
+
window.ActionMenuElement = ActionMenuElement
|
|
130
|
+
window.customElements.define('action-menu', ActionMenuElement)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare global {
|
|
134
|
+
interface Window {
|
|
135
|
+
ActionMenuElement: typeof ActionMenuElement
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Primer
|
|
5
|
+
module Alpha
|
|
6
|
+
class ActionMenu
|
|
7
|
+
# This component is part of <%= link_to_component(Primer::Alpha::ActionMenu) %> and should not be
|
|
8
|
+
# used as a standalone component.
|
|
9
|
+
class List < Primer::Alpha::ActionList
|
|
10
|
+
DEFAULT_ITEM_TAG = :span
|
|
11
|
+
ITEM_TAG_OPTIONS = [:a, :button, :"clipboard-copy", DEFAULT_ITEM_TAG].freeze
|
|
12
|
+
ITEM_ACTION_OPTIONS = [:classes, :onclick, :href, :value].freeze
|
|
13
|
+
|
|
14
|
+
# Adds a new item to the list.
|
|
15
|
+
#
|
|
16
|
+
# @param system_arguments [Hash] The same arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Item) %>.
|
|
17
|
+
def with_item(**system_arguments, &block)
|
|
18
|
+
content_arguments = system_arguments.delete(:content_arguments) || {}
|
|
19
|
+
|
|
20
|
+
content_arguments[:tag] =
|
|
21
|
+
if system_arguments[:tag] && ITEM_TAG_OPTIONS.include?(system_arguments[:tag])
|
|
22
|
+
system_arguments[:tag]
|
|
23
|
+
elsif system_arguments[:href] && !system_arguments[:disabled]
|
|
24
|
+
:a
|
|
25
|
+
else
|
|
26
|
+
DEFAULT_ITEM_TAG
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# disallow setting item's tag
|
|
30
|
+
system_arguments.delete(:tag)
|
|
31
|
+
|
|
32
|
+
# rubocop:disable Style/IfUnlessModifier
|
|
33
|
+
if content_arguments[:tag] == :a
|
|
34
|
+
content_arguments[:href] = system_arguments.delete(:href)
|
|
35
|
+
end
|
|
36
|
+
# rubocop:enable Style/IfUnlessModifier
|
|
37
|
+
|
|
38
|
+
system_arguments[:tabindex] = -1
|
|
39
|
+
system_arguments[:autofocus] = "" if system_arguments[:autofocus]
|
|
40
|
+
|
|
41
|
+
if system_arguments[:disabled]
|
|
42
|
+
content_arguments[:aria] = merge_aria(
|
|
43
|
+
content_arguments,
|
|
44
|
+
{ aria: { disabled: true } }
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
system_arguments[:aria] = merge_aria(
|
|
48
|
+
system_arguments,
|
|
49
|
+
{ aria: { disabled: true } }
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
content_arguments[:disabled] = "" if content_arguments[:tag] == :button
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
super(
|
|
56
|
+
**system_arguments,
|
|
57
|
+
content_arguments: content_arguments,
|
|
58
|
+
&block
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @param menu_id [String] ID of the parent menu.
|
|
63
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
|
64
|
+
def initialize(menu_id:, **system_arguments, &block)
|
|
65
|
+
@menu_id = menu_id
|
|
66
|
+
|
|
67
|
+
system_arguments[:aria] = merge_aria(
|
|
68
|
+
system_arguments,
|
|
69
|
+
{ aria: { labelledby: "#{@menu_id}-button" } }
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
system_arguments[:role] = :menu
|
|
73
|
+
system_arguments[:scheme] = :inset
|
|
74
|
+
system_arguments[:id] = "#{@menu_id}-list"
|
|
75
|
+
|
|
76
|
+
super(**system_arguments, &block)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
|
2
|
+
<focus-group direction="vertical" mnemonics retain>
|
|
3
|
+
<%= render(@overlay) do |overlay| %>
|
|
4
|
+
<% if @src.present? %>
|
|
5
|
+
<include-fragment src="<%= @src %>" loading="<%= preload? ? "eager" : "lazy" %>" data-target="action-menu.includeFragment">
|
|
6
|
+
<%= render(Primer::Alpha::ActionMenu::List.new(id: "#{@menu_id}-list", menu_id: @menu_id)) do |list| %>
|
|
7
|
+
<% list.with_item(
|
|
8
|
+
aria: { disabled: true },
|
|
9
|
+
content_arguments: {
|
|
10
|
+
display: :flex,
|
|
11
|
+
align_items: :center,
|
|
12
|
+
justify_content: :center,
|
|
13
|
+
text_align: :center,
|
|
14
|
+
autofocus: true
|
|
15
|
+
}
|
|
16
|
+
) do %>
|
|
17
|
+
<%= render Primer::Beta::Spinner.new(aria: { label: "Loading content..." }) %>
|
|
18
|
+
<% end %>
|
|
19
|
+
<% end %>
|
|
20
|
+
</include-fragment>
|
|
21
|
+
<% else %>
|
|
22
|
+
<%= render(@list) %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</focus-group>
|
|
26
|
+
<% end %>
|