primer_view_components 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/assets/styles/primer_view_components.css +2 -2
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/heading.html.erb +1 -1
  8. data/app/components/primer/alpha/action_list/heading.rb +5 -3
  9. data/app/components/primer/alpha/action_list/item.html.erb +9 -0
  10. data/app/components/primer/alpha/action_list/item.rb +31 -10
  11. data/app/components/primer/alpha/action_list.css +1 -1
  12. data/app/components/primer/alpha/action_list.css.json +4 -41
  13. data/app/components/primer/alpha/action_list.css.map +1 -1
  14. data/app/components/primer/alpha/action_list.pcss +19 -20
  15. data/app/components/primer/alpha/action_list.rb +54 -6
  16. data/app/components/primer/alpha/action_menu/action_menu_element.d.ts +22 -0
  17. data/app/components/primer/alpha/action_menu/action_menu_element.js +139 -0
  18. data/app/components/primer/alpha/action_menu/action_menu_element.ts +137 -0
  19. data/app/components/primer/alpha/action_menu/list.rb +81 -0
  20. data/app/components/primer/alpha/action_menu.html.erb +26 -0
  21. data/app/components/primer/alpha/action_menu.rb +322 -0
  22. data/app/components/primer/alpha/auto_complete.css.json +0 -11
  23. data/app/components/primer/alpha/banner.css.json +0 -14
  24. data/app/components/primer/alpha/button_marketing.css.json +0 -10
  25. data/app/components/primer/alpha/dialog.css.json +0 -63
  26. data/app/components/primer/alpha/dialog.rb +6 -2
  27. data/app/components/primer/alpha/dropdown.css.json +0 -21
  28. data/app/components/primer/alpha/layout.css.json +0 -27
  29. data/app/components/primer/alpha/menu.css.json +0 -11
  30. data/app/components/primer/alpha/nav_list/item.rb +5 -0
  31. data/app/components/primer/alpha/overlay.css +1 -1
  32. data/app/components/primer/alpha/overlay.css.json +0 -3
  33. data/app/components/primer/alpha/overlay.css.map +1 -1
  34. data/app/components/primer/alpha/overlay.pcss +1 -0
  35. data/app/components/primer/alpha/overlay.rb +14 -18
  36. data/app/components/primer/alpha/segmented_control.css.json +0 -15
  37. data/app/components/primer/alpha/tab_nav.css.json +0 -10
  38. data/app/components/primer/alpha/text_field.css.json +0 -38
  39. data/app/components/primer/alpha/toggle_switch.css.json +0 -16
  40. data/app/components/primer/alpha/underline_nav.css.json +0 -13
  41. data/app/components/primer/beta/avatar.css.json +0 -14
  42. data/app/components/primer/beta/avatar_stack.css.json +0 -9
  43. data/app/components/primer/beta/blankslate.css.json +0 -12
  44. data/app/components/primer/beta/border_box.css.json +0 -32
  45. data/app/components/primer/beta/border_box.rb +3 -3
  46. data/app/components/primer/beta/breadcrumbs.css.json +0 -4
  47. data/app/components/primer/beta/button.css +1 -1
  48. data/app/components/primer/beta/button.css.json +0 -22
  49. data/app/components/primer/beta/button.css.map +1 -1
  50. data/app/components/primer/beta/button.pcss +3 -3
  51. data/app/components/primer/beta/counter.css.json +0 -6
  52. data/app/components/primer/beta/flash.css.json +0 -15
  53. data/app/components/primer/beta/label.css.json +0 -20
  54. data/app/components/primer/beta/link.css.json +0 -8
  55. data/app/components/primer/beta/popover.css.json +0 -18
  56. data/app/components/primer/beta/progress_bar.css.json +0 -6
  57. data/app/components/primer/beta/state.css.json +0 -10
  58. data/app/components/primer/beta/subhead.css.json +0 -8
  59. data/app/components/primer/beta/timeline_item.css.json +0 -9
  60. data/app/components/primer/beta/truncate.css.json +0 -6
  61. data/app/components/primer/focus_group.d.ts +19 -0
  62. data/app/components/primer/focus_group.js +144 -0
  63. data/app/components/primer/focus_group.ts +137 -0
  64. data/app/components/primer/icon_button.rb +1 -1
  65. data/app/components/primer/primer.d.ts +2 -0
  66. data/app/components/primer/primer.js +2 -0
  67. data/app/components/primer/primer.ts +2 -0
  68. data/app/components/primer/truncate.css.json +0 -7
  69. data/app/forms/select_form.rb +2 -2
  70. data/app/lib/primer/css/layout.css.json +0 -263
  71. data/app/lib/primer/css/utilities.css.json +0 -1636
  72. data/lib/primer/classify/utilities.yml +60 -0
  73. data/lib/primer/forms/form_control.html.erb +1 -1
  74. data/lib/primer/forms/form_control.rb +5 -1
  75. data/lib/primer/forms/multi.html.erb +6 -8
  76. data/lib/primer/forms/text_field.html.erb +15 -17
  77. data/lib/primer/static/generate_arguments.rb +55 -0
  78. data/lib/primer/static/generate_audited_at.rb +17 -0
  79. data/lib/primer/static/generate_constants.rb +19 -0
  80. data/lib/primer/static/generate_info_arch.rb +156 -0
  81. data/lib/primer/static/generate_previews.rb +45 -0
  82. data/lib/primer/static/generate_statuses.rb +17 -0
  83. data/lib/primer/static.rb +72 -0
  84. data/lib/primer/view_components/linters/disallow_component_css_counter.rb +43 -4
  85. data/lib/primer/view_components/version.rb +1 -1
  86. data/lib/primer/view_components.rb +0 -48
  87. data/lib/primer/yard/component_manifest.rb +1 -0
  88. data/lib/primer/yard/component_ref.rb +14 -0
  89. data/lib/primer/yard/docs_helper.rb +3 -0
  90. data/lib/primer/yard/info_arch_docs_helper.rb +31 -0
  91. data/lib/primer/yard/legacy_gatsby_backend.rb +3 -35
  92. data/lib/primer/yard/registry.rb +2 -1
  93. data/lib/primer/yard.rb +1 -0
  94. data/lib/tasks/custom_utilities.yml +60 -0
  95. data/lib/tasks/docs.rake +10 -12
  96. data/lib/tasks/static.rake +20 -28
  97. data/previews/primer/alpha/action_list_preview.rb +4 -1
  98. data/previews/primer/alpha/action_menu_preview/align_end.html.erb +6 -0
  99. data/previews/primer/alpha/action_menu_preview/opens_dialog.html.erb +21 -0
  100. data/previews/primer/alpha/action_menu_preview.rb +238 -0
  101. data/previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb +2 -2
  102. data/previews/primer/alpha/dialog_preview/custom_header.html.erb +3 -3
  103. data/previews/primer/alpha/dialog_preview/nested_dialog.html.erb +4 -4
  104. data/previews/primer/alpha/dialog_preview/test.html.erb +3 -3
  105. data/previews/primer/alpha/dialog_preview/with_footer.html.erb +3 -3
  106. data/previews/primer/alpha/dialog_preview/with_form.html.erb +1 -1
  107. data/previews/primer/alpha/dialog_preview/with_text_input.html.erb +2 -2
  108. data/previews/primer/alpha/dialog_preview.rb +7 -2
  109. data/previews/primer/beta/auto_complete_item_preview.rb +1 -0
  110. data/static/arguments.json +3078 -1404
  111. data/static/audited_at.json +2 -0
  112. data/static/classes.json +576 -311
  113. data/static/constants.json +42 -2
  114. data/static/info_arch.json +8859 -0
  115. data/static/previews.json +221 -101
  116. data/static/statuses.json +2 -0
  117. 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 %>