openproject-primer_view_components 0.34.0 → 0.35.1
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 +26 -0
- data/app/assets/javascripts/lib/primer/forms/primer_text_field.d.ts +27 -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_menu/action_menu_element.js +13 -43
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +13 -51
- data/app/components/primer/alpha/tab_nav.css +1 -1
- data/app/components/primer/alpha/tab_nav.css.json +2 -0
- data/app/components/primer/alpha/tab_nav.css.map +1 -1
- data/app/components/primer/alpha/tab_nav.pcss +11 -1
- data/app/components/primer/alpha/tab_panels.html.erb +5 -9
- data/app/components/primer/alpha/tab_panels.rb +4 -13
- data/app/components/primer/alpha/text_field.rb +1 -0
- data/app/components/primer/alpha/underline_nav.css +1 -1
- data/app/components/primer/alpha/underline_nav.css.json +2 -0
- data/app/components/primer/alpha/underline_nav.css.map +1 -1
- data/app/components/primer/alpha/underline_nav.pcss +7 -1
- data/app/components/primer/alpha/underline_panels.css +1 -0
- data/app/components/primer/alpha/underline_panels.css.json +6 -0
- data/app/components/primer/alpha/underline_panels.css.map +1 -0
- data/app/components/primer/alpha/underline_panels.html.erb +6 -8
- data/app/components/primer/alpha/underline_panels.pcss +4 -0
- data/app/components/primer/alpha/underline_panels.rb +6 -14
- data/app/components/primer/beta/icon_button.rb +5 -0
- data/app/components/primer/beta/relative_time.rb +3 -0
- data/app/components/primer/beta/spinner.html.erb +3 -0
- data/app/components/primer/beta/spinner.rb +15 -1
- data/app/components/primer/open_project/flex_layout.rb +1 -1
- data/app/components/primer/primer.pcss +1 -0
- data/lib/primer/forms/dsl/text_field_input.rb +8 -1
- data/lib/primer/forms/primer_text_field.d.ts +27 -0
- data/lib/primer/forms/primer_text_field.js +17 -5
- data/lib/primer/forms/primer_text_field.ts +24 -5
- data/lib/primer/forms/text_field.html.erb +6 -2
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/alpha/text_field_preview.rb +11 -0
- data/previews/primer/beta/breadcrumbs_preview.rb +9 -0
- data/previews/primer/beta/icon_button_preview/summary_as_button.html.erb +12 -0
- data/previews/primer/beta/icon_button_preview.rb +95 -14
- data/previews/primer/beta/relative_time_preview/link_with_tooltip.html.erb +13 -0
- data/previews/primer/beta/relative_time_preview.rb +12 -0
- data/previews/primer/beta/spinner_preview.rb +2 -2
- data/static/arguments.json +12 -12
- data/static/constants.json +1 -0
- data/static/info_arch.json +78 -13
- data/static/previews.json +65 -0
- metadata +9 -3
| @@ -15,7 +15,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function ( | |
| 15 15 | 
             
                if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
         | 
| 16 16 | 
             
                return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
         | 
| 17 17 | 
             
            };
         | 
| 18 | 
            -
            var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation,  | 
| 18 | 
            +
            var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isAnchorActivationViaSpace, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get;
         | 
| 19 19 | 
             
            import { controller, target } from '@github/catalyst';
         | 
| 20 20 | 
             
            import '@oddbird/popover-polyfill';
         | 
| 21 21 | 
             
            const validSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]'];
         | 
| @@ -152,18 +152,13 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement { | |
| 152 152 | 
             
                                return;
         | 
| 153 153 | 
             
                            }
         | 
| 154 154 | 
             
                        }
         | 
| 155 | 
            -
                         | 
| 156 | 
            -
                         | 
| 157 | 
            -
                         | 
| 158 | 
            -
                        // is called. While calling preventDefault() appears to have no effect on link navigation, it skips
         | 
| 159 | 
            -
                        // form submission. The code below therefore only calls preventDefault() if the button has been
         | 
| 160 | 
            -
                        // activated by the space key, and manually submits the form if the button is a submit button.
         | 
| 161 | 
            -
                        if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isKeyboardActivationViaSpace).call(this, event)) {
         | 
| 155 | 
            +
                        // Pressing the space key on a link will cause the page to scroll unless preventDefault() is called.
         | 
| 156 | 
            +
                        // We then click it manually to navigate.
         | 
| 157 | 
            +
                        if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isAnchorActivationViaSpace).call(this, event)) {
         | 
| 162 158 | 
             
                            event.preventDefault();
         | 
| 163 | 
            -
                             | 
| 164 | 
            -
                                item.closest('form')?.submit();
         | 
| 165 | 
            -
                            }
         | 
| 159 | 
            +
                            item.click();
         | 
| 166 160 | 
             
                        }
         | 
| 161 | 
            +
                        __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_handleItemActivated).call(this, item);
         | 
| 167 162 | 
             
                        return;
         | 
| 168 163 | 
             
                    }
         | 
| 169 164 | 
             
                    if (event.type === 'include-fragment-replaced') {
         | 
| @@ -269,26 +264,18 @@ _ActionMenuElement_potentiallyDisallowActivation = function _ActionMenuElement_p | |
| 269 264 | 
             
                }
         | 
| 270 265 | 
             
                return false;
         | 
| 271 266 | 
             
            };
         | 
| 272 | 
            -
             | 
| 273 | 
            -
                return  | 
| 274 | 
            -
             | 
| 275 | 
            -
            _ActionMenuElement_isKeyboardActivationViaEnter = function _ActionMenuElement_isKeyboardActivationViaEnter(event) {
         | 
| 276 | 
            -
                return (event instanceof KeyboardEvent &&
         | 
| 277 | 
            -
                    event.type === 'keydown' &&
         | 
| 278 | 
            -
                    !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| 279 | 
            -
                    event.key === 'Enter');
         | 
| 280 | 
            -
            };
         | 
| 281 | 
            -
            _ActionMenuElement_isKeyboardActivationViaSpace = function _ActionMenuElement_isKeyboardActivationViaSpace(event) {
         | 
| 282 | 
            -
                return (event instanceof KeyboardEvent &&
         | 
| 267 | 
            +
            _ActionMenuElement_isAnchorActivationViaSpace = function _ActionMenuElement_isAnchorActivationViaSpace(event) {
         | 
| 268 | 
            +
                return (event.target instanceof HTMLAnchorElement &&
         | 
| 269 | 
            +
                    event instanceof KeyboardEvent &&
         | 
| 283 270 | 
             
                    event.type === 'keydown' &&
         | 
| 284 271 | 
             
                    !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| 285 272 | 
             
                    event.key === ' ');
         | 
| 286 273 | 
             
            };
         | 
| 287 | 
            -
            _ActionMenuElement_isMouseActivation = function _ActionMenuElement_isMouseActivation(event) {
         | 
| 288 | 
            -
                return event instanceof MouseEvent && event.type === 'click';
         | 
| 289 | 
            -
            };
         | 
| 290 274 | 
             
            _ActionMenuElement_isActivation = function _ActionMenuElement_isActivation(event) {
         | 
| 291 | 
            -
                 | 
| 275 | 
            +
                // Some browsers fire MouseEvents (Firefox) and others fire PointerEvents (Chrome). Activating an item via
         | 
| 276 | 
            +
                // enter or space counterintuitively fires one of these rather than a KeyboardEvent. Since PointerEvent
         | 
| 277 | 
            +
                // inherits from MouseEvent, it is enough to check for MouseEvent here.
         | 
| 278 | 
            +
                return (event instanceof MouseEvent && event.type === 'click') || __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isAnchorActivationViaSpace).call(this, event);
         | 
| 292 279 | 
             
            };
         | 
| 293 280 | 
             
            _ActionMenuElement_handleInvokerActivated = function _ActionMenuElement_handleInvokerActivated(event) {
         | 
| 294 281 | 
             
                event.preventDefault();
         | 
| @@ -363,23 +350,6 @@ _ActionMenuElement_handleItemActivated = function _ActionMenuElement_handleItemA | |
| 363 350 | 
             
                    detail: { item: item.parentElement, checked: this.isItemChecked(item.parentElement) },
         | 
| 364 351 | 
             
                }));
         | 
| 365 352 | 
             
            };
         | 
| 366 | 
            -
            _ActionMenuElement_activateItem = function _ActionMenuElement_activateItem(event, item) {
         | 
| 367 | 
            -
                const eventWillActivateByDefault = (event instanceof MouseEvent && event.type === 'click') ||
         | 
| 368 | 
            -
                    (event instanceof KeyboardEvent &&
         | 
| 369 | 
            -
                        event.type === 'keydown' &&
         | 
| 370 | 
            -
                        !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| 371 | 
            -
                        event.key === 'Enter');
         | 
| 372 | 
            -
                // if the event will result in activating the current item by default, i.e. is a
         | 
| 373 | 
            -
                // mouse click or keyboard enter, bail out
         | 
| 374 | 
            -
                if (eventWillActivateByDefault)
         | 
| 375 | 
            -
                    return;
         | 
| 376 | 
            -
                // otherwise, event will not result in activation by default, so we stop it and
         | 
| 377 | 
            -
                // simulate a click
         | 
| 378 | 
            -
                /* eslint-disable-next-line no-restricted-syntax */
         | 
| 379 | 
            -
                event.stopPropagation();
         | 
| 380 | 
            -
                const elem = item;
         | 
| 381 | 
            -
                elem.click();
         | 
| 382 | 
            -
            };
         | 
| 383 353 | 
             
            _ActionMenuElement_handleIncludeFragmentReplaced = function _ActionMenuElement_handleIncludeFragmentReplaced() {
         | 
| 384 354 | 
             
                if (__classPrivateFieldGet(this, _ActionMenuElement_instances, "a", _ActionMenuElement_firstItem_get))
         | 
| 385 355 | 
             
                    __classPrivateFieldGet(this, _ActionMenuElement_instances, "a", _ActionMenuElement_firstItem_get).focus();
         | 
| @@ -151,21 +151,9 @@ export class ActionMenuElement extends HTMLElement { | |
| 151 151 | 
             
                return false
         | 
| 152 152 | 
             
              }
         | 
| 153 153 |  | 
| 154 | 
            -
              # | 
| 155 | 
            -
                return this.#isKeyboardActivationViaEnter(event) || this.#isKeyboardActivationViaSpace(event)
         | 
| 156 | 
            -
              }
         | 
| 157 | 
            -
             | 
| 158 | 
            -
              #isKeyboardActivationViaEnter(event: Event): boolean {
         | 
| 159 | 
            -
                return (
         | 
| 160 | 
            -
                  event instanceof KeyboardEvent &&
         | 
| 161 | 
            -
                  event.type === 'keydown' &&
         | 
| 162 | 
            -
                  !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| 163 | 
            -
                  event.key === 'Enter'
         | 
| 164 | 
            -
                )
         | 
| 165 | 
            -
              }
         | 
| 166 | 
            -
             | 
| 167 | 
            -
              #isKeyboardActivationViaSpace(event: Event): boolean {
         | 
| 154 | 
            +
              #isAnchorActivationViaSpace(event: Event): boolean {
         | 
| 168 155 | 
             
                return (
         | 
| 156 | 
            +
                  event.target instanceof HTMLAnchorElement &&
         | 
| 169 157 | 
             
                  event instanceof KeyboardEvent &&
         | 
| 170 158 | 
             
                  event.type === 'keydown' &&
         | 
| 171 159 | 
             
                  !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| @@ -173,12 +161,11 @@ export class ActionMenuElement extends HTMLElement { | |
| 173 161 | 
             
                )
         | 
| 174 162 | 
             
              }
         | 
| 175 163 |  | 
| 176 | 
            -
              #isMouseActivation(event: Event): boolean {
         | 
| 177 | 
            -
                return event instanceof MouseEvent && event.type === 'click'
         | 
| 178 | 
            -
              }
         | 
| 179 | 
            -
             | 
| 180 164 | 
             
              #isActivation(event: Event): boolean {
         | 
| 181 | 
            -
                 | 
| 165 | 
            +
                // Some browsers fire MouseEvents (Firefox) and others fire PointerEvents (Chrome). Activating an item via
         | 
| 166 | 
            +
                // enter or space counterintuitively fires one of these rather than a KeyboardEvent. Since PointerEvent
         | 
| 167 | 
            +
                // inherits from MouseEvent, it is enough to check for MouseEvent here.
         | 
| 168 | 
            +
                return (event instanceof MouseEvent && event.type === 'click') || this.#isAnchorActivationViaSpace(event)
         | 
| 182 169 | 
             
              }
         | 
| 183 170 |  | 
| 184 171 | 
             
              handleEvent(event: Event) {
         | 
| @@ -237,21 +224,15 @@ export class ActionMenuElement extends HTMLElement { | |
| 237 224 | 
             
                    }
         | 
| 238 225 | 
             
                  }
         | 
| 239 226 |  | 
| 240 | 
            -
                   | 
| 241 | 
            -
                   | 
| 242 | 
            -
             | 
| 243 | 
            -
                  // Pressing the space key on a button or link will cause the page to scroll unless preventDefault()
         | 
| 244 | 
            -
                  // is called. While calling preventDefault() appears to have no effect on link navigation, it skips
         | 
| 245 | 
            -
                  // form submission. The code below therefore only calls preventDefault() if the button has been
         | 
| 246 | 
            -
                  // activated by the space key, and manually submits the form if the button is a submit button.
         | 
| 247 | 
            -
                  if (this.#isKeyboardActivationViaSpace(event)) {
         | 
| 227 | 
            +
                  // Pressing the space key on a link will cause the page to scroll unless preventDefault() is called.
         | 
| 228 | 
            +
                  // We then click it manually to navigate.
         | 
| 229 | 
            +
                  if (this.#isAnchorActivationViaSpace(event)) {
         | 
| 248 230 | 
             
                    event.preventDefault()
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                    if (item.getAttribute('type') === 'submit') {
         | 
| 251 | 
            -
                      item.closest('form')?.submit()
         | 
| 252 | 
            -
                    }
         | 
| 231 | 
            +
                    ;(item as HTMLElement).click()
         | 
| 253 232 | 
             
                  }
         | 
| 254 233 |  | 
| 234 | 
            +
                  this.#handleItemActivated(item)
         | 
| 235 | 
            +
             | 
| 255 236 | 
             
                  return
         | 
| 256 237 | 
             
                }
         | 
| 257 238 |  | 
| @@ -335,6 +316,7 @@ export class ActionMenuElement extends HTMLElement { | |
| 335 316 | 
             
                }
         | 
| 336 317 |  | 
| 337 318 | 
             
                this.#updateInput()
         | 
| 319 | 
            +
             | 
| 338 320 | 
             
                this.dispatchEvent(
         | 
| 339 321 | 
             
                  new CustomEvent('itemActivated', {
         | 
| 340 322 | 
             
                    detail: {item: item.parentElement, checked: this.isItemChecked(item.parentElement)},
         | 
| @@ -342,26 +324,6 @@ export class ActionMenuElement extends HTMLElement { | |
| 342 324 | 
             
                )
         | 
| 343 325 | 
             
              }
         | 
| 344 326 |  | 
| 345 | 
            -
              #activateItem(event: Event, item: Element) {
         | 
| 346 | 
            -
                const eventWillActivateByDefault =
         | 
| 347 | 
            -
                  (event instanceof MouseEvent && event.type === 'click') ||
         | 
| 348 | 
            -
                  (event instanceof KeyboardEvent &&
         | 
| 349 | 
            -
                    event.type === 'keydown' &&
         | 
| 350 | 
            -
                    !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
         | 
| 351 | 
            -
                    event.key === 'Enter')
         | 
| 352 | 
            -
             | 
| 353 | 
            -
                // if the event will result in activating the current item by default, i.e. is a
         | 
| 354 | 
            -
                // mouse click or keyboard enter, bail out
         | 
| 355 | 
            -
                if (eventWillActivateByDefault) return
         | 
| 356 | 
            -
             | 
| 357 | 
            -
                // otherwise, event will not result in activation by default, so we stop it and
         | 
| 358 | 
            -
                // simulate a click
         | 
| 359 | 
            -
                /* eslint-disable-next-line no-restricted-syntax */
         | 
| 360 | 
            -
                event.stopPropagation()
         | 
| 361 | 
            -
                const elem = item as HTMLElement
         | 
| 362 | 
            -
                elem.click()
         | 
| 363 | 
            -
              }
         | 
| 364 | 
            -
             | 
| 365 327 | 
             
              #handleIncludeFragmentReplaced() {
         | 
| 366 328 | 
             
                if (this.#firstItem) this.#firstItem.focus()
         | 
| 367 329 | 
             
                this.#softDisableItems()
         | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow: | 
| 1 | 
            +
            .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:hidden}.tabnav::part(tablist-wrapper){border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal)}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;flex-shrink:0;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}.tabnav-tab.selected .octicon,.tabnav-tab[aria-current]:not([aria-current=false]) .octicon,.tabnav-tab[aria-selected=true] .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}tab-container .tabnav-tab{margin-bottom:-1px}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:2px}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
         | 
| @@ -3,6 +3,7 @@ | |
| 3 3 | 
             
              "selectors": [
         | 
| 4 4 | 
             
                ".tabnav",
         | 
| 5 5 | 
             
                ".tabnav-tabs",
         | 
| 6 | 
            +
                ".tabnav::part(tablist-wrapper)",
         | 
| 6 7 | 
             
                ".tabnav-tab",
         | 
| 7 8 | 
             
                ".tabnav-tab.selected",
         | 
| 8 9 | 
             
                ".tabnav-tab[aria-current]:not([aria-current=false])",
         | 
| @@ -16,6 +17,7 @@ | |
| 16 17 | 
             
                ".tabnav-tab .octicon",
         | 
| 17 18 | 
             
                ".tabnav-tab:active",
         | 
| 18 19 | 
             
                ".tabnav-tab .Counter",
         | 
| 20 | 
            +
                "tab-container .tabnav-tab",
         | 
| 19 21 | 
             
                ".tabnav-extra",
         | 
| 20 22 | 
             
                ".tabnav-extra>.octicon",
         | 
| 21 23 | 
             
                "a.tabnav-extra:hover",
         | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            {"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD, | 
| 1 | 
            +
            {"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD,eACF,CAEA,+BAEE,sEAAuE,CADvE,qCAEF,CAEA,YAQE,wBAA6B,CAE7B,0CAAgB,CAAhB,eAAgB,CAJhB,0BAA2B,CAL3B,oBAAqB,CACrB,aAAc,CAEd,sCAAuC,CACvC,gBAAiB,CAFjB,uEAAwE,CAIxE,4BAAqB,CAArB,oBAAqB,CAIrB,4CAwCF,CAtCE,yGAIE,uCAAwC,CACxC,uCAAwC,CACxC,uEAAwE,CAHxE,4BAQF,CAHE,oIACE,aACF,CAGF,kBACE,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CACrB,uBACF,CAEA,4CAEE,iFAAmF,CACnF,mBACF,CAMA,wCAHE,0BAMF,CAHA,qBACE,qCAEF,CAEA,qBAEE,aAAc,CADd,oCAEF,CAGF,0BACE,kBACF,CAQA,cAKE,0BAA2B,CAJ3B,oBAAqB,CAGrB,qCAAsC,CADtC,gBAAiB,CADjB,gBAQF,CAHE,uBACE,gBACF,CAKF,qBACE,2BAA4B,CAC5B,4BAAqB,CAArB,oBACF,CAOA,YACE,oDACF","file":"tab_nav.css","sourcesContent":["/* tabnav */\n\n/* Outer wrapper */\n.tabnav {\n  margin-top: 0;\n  margin-bottom: var(--stack-gap-normal);\n  border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tabs {\n  display: flex;\n  margin-bottom: calc(var(--borderWidth-thin) * -1);\n  overflow: hidden;\n}\n\n.tabnav::part(tablist-wrapper) {\n  margin-bottom: var(--stack-gap-normal);\n  border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tab {\n  display: inline-block;\n  flex-shrink: 0;\n  padding: var(--base-size-8) var(--control-medium-paddingInline-spacious);\n  font-size: var(--text-body-size-medium);\n  line-height: 23px;\n  color: var(--fgColor-muted);\n  text-decoration: none;\n  background-color: transparent;\n  border: var(--borderWidth-thin) solid transparent;\n  border-bottom: 0;\n  transition: color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n\n  &.selected,\n  &[aria-selected='true'],\n  &[aria-current]:not([aria-current='false']) {\n    color: var(--fgColor-default);\n    background-color: var(--bgColor-default); /* cover bottom border */\n    border-color: var(--borderColor-default);\n    border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0;\n\n    & .octicon {\n      color: inherit;\n    }\n  }\n\n  &:hover {\n    color: var(--fgColor-default);\n    text-decoration: none;\n    transition-duration: 0.1s;\n  }\n\n  &:focus,\n  &:focus-visible {\n    border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0 !important;\n    outline-offset: -6px;\n  }\n\n  &:active {\n    color: var(--fgColor-muted);\n  }\n\n  & .octicon {\n    margin-right: var(--control-small-gap);\n    color: var(--fgColor-muted);\n  }\n\n  & .Counter {\n    margin-left: var(--control-small-gap);\n    color: inherit;\n  }\n}\n\ntab-container .tabnav-tab {\n  margin-bottom: -1px;\n}\n\n\n/* Tabnav extras\n**\n** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're\n** inline text or links. */\n\n.tabnav-extra {\n  display: inline-block;\n  padding-top: 10px;\n  margin-left: 10px;\n  font-size: var(--text-body-size-small);\n  color: var(--fgColor-muted);\n\n  & > .octicon {\n    margin-right: 2px;\n  }\n}\n\n/* When tabnav-extra are anchors\n** stylelint-disable-next-line selector-no-qualifying-type */\na.tabnav-extra:hover {\n  color: var(--fgColor-accent);\n  text-decoration: none;\n}\n\n/* Tabnav buttons\n**\n** For when there are multiple buttons, space them out appropriately. Requires\n** the buttons to be floated or inline-block. */\n\n.tabnav-btn {\n  margin-left: var(--controlStack-medium-gap-condensed);\n}\n"]}
         | 
| @@ -10,7 +10,12 @@ | |
| 10 10 | 
             
            .tabnav-tabs {
         | 
| 11 11 | 
             
              display: flex;
         | 
| 12 12 | 
             
              margin-bottom: calc(var(--borderWidth-thin) * -1);
         | 
| 13 | 
            -
              overflow:  | 
| 13 | 
            +
              overflow: hidden;
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            .tabnav::part(tablist-wrapper) {
         | 
| 17 | 
            +
              margin-bottom: var(--stack-gap-normal);
         | 
| 18 | 
            +
              border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);
         | 
| 14 19 | 
             
            }
         | 
| 15 20 |  | 
| 16 21 | 
             
            .tabnav-tab {
         | 
| @@ -66,6 +71,11 @@ | |
| 66 71 | 
             
              }
         | 
| 67 72 | 
             
            }
         | 
| 68 73 |  | 
| 74 | 
            +
            tab-container .tabnav-tab {
         | 
| 75 | 
            +
              margin-bottom: -1px;
         | 
| 76 | 
            +
            }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
             | 
| 69 79 | 
             
            /* Tabnav extras
         | 
| 70 80 | 
             
            **
         | 
| 71 81 | 
             
            ** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're
         | 
| @@ -1,13 +1,9 @@ | |
| 1 | 
            -
            <%=  | 
| 2 | 
            -
              <%=  | 
| 3 | 
            -
             | 
| 4 | 
            -
                <%=  | 
| 5 | 
            -
                  <% tabs.each do |tab| %>
         | 
| 6 | 
            -
                    <%= tab %>
         | 
| 7 | 
            -
                  <% end %>
         | 
| 8 | 
            -
                <% end %>
         | 
| 9 | 
            -
                <%= extra if @align == :right %>
         | 
| 1 | 
            +
            <%= render Primer::BaseComponent.new(**@system_arguments) do %>
         | 
| 2 | 
            +
              <%= extra if @align == :left %>
         | 
| 3 | 
            +
              <% tabs.each do |tab| %>
         | 
| 4 | 
            +
                <%= tab %>
         | 
| 10 5 | 
             
              <% end %>
         | 
| 6 | 
            +
              <%= extra if @align == :right %>
         | 
| 11 7 | 
             
              <% tabs.each do |tab| %>
         | 
| 12 8 | 
             
                <%= tab.panel %>
         | 
| 13 9 | 
             
              <% end %>
         | 
| @@ -26,7 +26,7 @@ module Primer | |
| 26 26 | 
             
                    Primer::Alpha::Navigation::Tab.new(
         | 
| 27 27 | 
             
                      selected: selected,
         | 
| 28 28 | 
             
                      with_panel: true,
         | 
| 29 | 
            -
                      list:  | 
| 29 | 
            +
                      list: false,
         | 
| 30 30 | 
             
                      panel_id: "panel-#{id}",
         | 
| 31 31 | 
             
                      **system_arguments
         | 
| 32 32 | 
             
                    )
         | 
| @@ -43,23 +43,14 @@ module Primer | |
| 43 43 |  | 
| 44 44 | 
             
                  # @param label [String] Sets an `aria-label` that helps assistive technology users understand the purpose of the tabs.
         | 
| 45 45 | 
             
                  # @param align [Symbol] <%= one_of(Primer::TabNavHelper::EXTRA_ALIGN_OPTIONS) %> - Defaults to <%= Primer::TabNavHelper::EXTRA_ALIGN_DEFAULT %>
         | 
| 46 | 
            -
                  # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
         | 
| 47 | 
            -
                  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper.
         | 
| 48 46 | 
             
                  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
         | 
| 49 47 | 
             
                  def initialize(label:, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
         | 
| 50 48 | 
             
                    @align = EXTRA_ALIGN_DEFAULT
         | 
| 51 | 
            -
                    @wrapper_arguments = wrapper_arguments
         | 
| 52 49 |  | 
| 53 | 
            -
                    @system_arguments = deny_tag_argument(**system_arguments)
         | 
| 54 | 
            -
                    @system_arguments[:tag] = : | 
| 50 | 
            +
                    @system_arguments = { **deny_tag_argument(**system_arguments), **deny_tag_argument(**wrapper_arguments) }
         | 
| 51 | 
            +
                    @system_arguments[:tag] = :"tab-container"
         | 
| 55 52 | 
             
                    @system_arguments[:classes] = tab_nav_classes(@system_arguments[:classes])
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                    @body_arguments = deny_tag_argument(**body_arguments)
         | 
| 58 | 
            -
                    @body_arguments[:tag] = :ul
         | 
| 59 | 
            -
                    @body_arguments[:classes] = tab_nav_body_classes(@body_arguments[:classes])
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                    @body_arguments[:role] = :tablist
         | 
| 62 | 
            -
                    @body_arguments[:"aria-label"] = label
         | 
| 53 | 
            +
                    @system_arguments[:"aria-label"] = label
         | 
| 63 54 | 
             
                  end
         | 
| 64 55 |  | 
| 65 56 | 
             
                  def before_render
         | 
| @@ -26,6 +26,7 @@ module Primer | |
| 26 26 | 
             
                  # @param monospace [Boolean] If `true`, uses a monospace font for the input field.
         | 
| 27 27 | 
             
                  # @param auto_check_src [String] When provided, makes a request to the given URL whenever the contents of the text field changes. If the server responds with a non-2xx status code, the response body is used as the validation message.
         | 
| 28 28 | 
             
                  # @param leading_visual [Hash] Renders a leading visual icon before the text field's cursor. The hash will be passed to Primer's <%= link_to_component(Primer::Beta::Octicon) %> component.
         | 
| 29 | 
            +
                  # @param leading_spinner [Boolean] If `true`, a leading spinner will be included in the markup. The spinner can be shown via the `showLeadingSpinner()` JavaScript method, and hidden via `hideLeadingSpinner()`. If this argument is `true`, a leading visual must also be provided.
         | 
| 29 30 | 
             
                  # @param show_clear_button [Boolean] Whether or not to include a clear button inside the input that clears the input's contents when clicked.
         | 
| 30 31 | 
             
                  # @param clear_button_id [String] The HTML id attribute of the clear button.
         | 
| 31 32 | 
             
                end
         | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            .UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav-body{align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%;z-index:1}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
         | 
| 1 | 
            +
            .UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav::part(tablist-wrapper){box-shadow:inset 0 -1px 0 var(--borderColor-muted);padding:var(--control-medium-gap) 0;width:100%}.UnderlineNav-body,.UnderlineNav::part(tablist){align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%;z-index:1}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
         | 
| @@ -4,7 +4,9 @@ | |
| 4 4 | 
             
                ".UnderlineNav",
         | 
| 5 5 | 
             
                ".UnderlineNav .Counter",
         | 
| 6 6 | 
             
                ".UnderlineNav .Counter--primary",
         | 
| 7 | 
            +
                ".UnderlineNav::part(tablist-wrapper)",
         | 
| 7 8 | 
             
                ".UnderlineNav-body",
         | 
| 9 | 
            +
                ".UnderlineNav::part(tablist)",
         | 
| 8 10 | 
             
                ".UnderlineNav-item",
         | 
| 9 11 | 
             
                ".UnderlineNav-item:focus",
         | 
| 10 12 | 
             
                ".UnderlineNav-item:focus-visible",
         | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            {"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF, | 
| 1 | 
            +
            {"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF,qCAEE,kDAAmD,CACnD,mCAAoC,CAFpC,UAGF,CAEA,gDAEE,kBAAmB,CADnB,YAAa,CAEb,6BAA8B,CAC9B,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,wCAAyC,CANzC,4BAA6B,CAG7B,cAAe,CAPf,YAAa,CAEb,sCAAuC,CACvC,gBAAiB,CAFjB,uDAAwD,CAFxD,iBAAkB,CAMlB,iBAAkB,CAClB,kBA8DF,CAvDE,mFAKE,oDAAqD,CAFrD,4BAA6B,CAG7B,mBAAoB,CAFpB,4BAAqB,CAArB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,0BCxEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDwE8B,CAI5B,sBACE,yBAGE,mDAAoD,CAFpD,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,0DAA2D,CAD3D,4BAA6B,CAD7B,4CAiBF,CAZE,0JAQE,iDAAkD,CAClD,wCAAyC,CALzC,uBAAwB,CAGxB,UAAW,CADX,UAAW,CALX,iBAAkB,CAElB,SAAU,CAOV,6BAA+B,CAL/B,UAAW,CAHX,SASF,CAIJ,qBACE,wBAKF,CAHE,2CACE,aACF,CAGF,sBACE,iBACF,CAEA,oBACE,aAMF,CAHE,uCACE,8BACF,CAGF,sBAGE,0BAA2B,CAF3B,wBAA0B,CAC1B,sCAAuC,CAEvC,yBACF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n  display: flex;\n  min-height: var(--base-size-48);\n  overflow-x: auto;\n  overflow-y: hidden;\n  box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n  -webkit-overflow-scrolling: auto;\n  justify-content: space-between;\n\n  & .Counter {\n    margin-left: var(--control-medium-gap);\n    color: var(--fgColor-default);\n    background-color: var(--bgColor-neutral-muted, var(--color-neutral-muted));\n  }\n\n  & .Counter--primary {\n    color: var(--fgColor-onEmphasis);\n    background-color: var(--bgColor-neutral-emphasis);\n  }\n}\n\n.UnderlineNav::part(tablist-wrapper) {\n  width: 100%;\n  box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n  padding: var(--control-medium-gap) 0;\n}\n\n.UnderlineNav-body,.UnderlineNav::part(tablist) {\n  display: flex;\n  align-items: center;\n  gap: var(--control-medium-gap);\n  list-style: none;\n}\n\n.UnderlineNav-item {\n  position: relative;\n  display: flex;\n  padding: 0 var(--control-medium-paddingInline-condensed);\n  font-size: var(--text-body-size-medium);\n  line-height: 30px;\n  color: var(--fgColor-default);\n  text-align: center;\n  white-space: nowrap;\n  cursor: pointer;\n  background-color: transparent;\n  border: 0;\n  border-radius: var(--borderRadius-medium);\n  align-items: center;\n\n  &:hover,\n  &:focus,\n  &:focus-visible {\n    color: var(--fgColor-default);\n    text-decoration: none;\n    border-bottom-color: var(--borderColor-neutral-muted);\n    outline-offset: -2px;\n    transition: border-bottom-color 0.12s ease-out;\n  }\n\n  /* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n  & [data-content]::before {\n    display: block;\n    height: 0;\n    font-weight: var(--base-text-weight-semibold);\n    visibility: hidden;\n    content: attr(data-content);\n  }\n\n  /* increase touch target area */\n  &::before {\n    @mixin minTouchTarget 48px;\n  }\n\n  /* hover state was \"sticking\" on mobile after click */\n  @media (pointer: fine) {\n    &:hover {\n      color: var(--fgColor-default);\n      text-decoration: none;\n      background: var(--control-transparent-bgColor-hover);\n      transition: background 0.12s ease-out;\n    }\n  }\n\n  &.selected,\n  &[role='tab'][aria-selected='true'],\n  &[aria-current]:not([aria-current='false']) {\n    font-weight: var(--base-text-weight-semibold);\n    color: var(--fgColor-default);\n    border-bottom-color: var(--underlineNav-borderColor-active);\n\n    /* current/selected underline */\n    &::after {\n      position: absolute;\n      z-index: 1; /* raise above full-width flash banner */\n      right: 50%;\n      bottom: calc(50% - 25px); /* 48px total height / 2 (24px) + 1px */\n      width: 100%;\n      height: 2px;\n      content: '';\n      background: var(--underlineNav-borderColor-active);\n      border-radius: var(--borderRadius-medium);\n      transform: translate(50%, -50%);\n    }\n  }\n}\n\n.UnderlineNav--right {\n  justify-content: flex-end;\n\n  & .UnderlineNav-actions {\n    flex: 1 1 auto;\n  }\n}\n\n.UnderlineNav-actions {\n  align-self: center;\n}\n\n.UnderlineNav--full {\n  display: block;\n\n  /* required for underline to align with additional wrapper element */\n  & .UnderlineNav-body {\n    min-height: var(--base-size-48);\n  }\n}\n\n.UnderlineNav-octicon {\n  display: inline !important;\n  margin-right: var(--control-medium-gap);\n  color: var(--fgColor-muted);\n  fill: var(--fgColor-muted);\n}\n\n.UnderlineNav-container {\n  display: flex;\n  justify-content: space-between;\n}\n",null]}
         | 
| @@ -21,7 +21,13 @@ | |
| 21 21 | 
             
              }
         | 
| 22 22 | 
             
            }
         | 
| 23 23 |  | 
| 24 | 
            -
            .UnderlineNav- | 
| 24 | 
            +
            .UnderlineNav::part(tablist-wrapper) {
         | 
| 25 | 
            +
              width: 100%;
         | 
| 26 | 
            +
              box-shadow: inset 0 -1px 0 var(--borderColor-muted);
         | 
| 27 | 
            +
              padding: var(--control-medium-gap) 0;
         | 
| 28 | 
            +
            }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            .UnderlineNav-body,.UnderlineNav::part(tablist) {
         | 
| 25 31 | 
             
              display: flex;
         | 
| 26 32 | 
             
              align-items: center;
         | 
| 27 33 | 
             
              gap: var(--control-medium-gap);
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            tab-container.UnderlineNav{box-shadow:none;flex-direction:column}
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            {"version":3,"sources":["underline_panels.pcss"],"names":[],"mappings":"AAAA,2BACE,eAAgB,CAChB,qBACF","file":"underline_panels.css","sourcesContent":["tab-container.UnderlineNav {\n  box-shadow: none;\n  flex-direction: column;\n}\n"]}
         | 
| @@ -1,18 +1,16 @@ | |
| 1 | 
            -
            <%=  | 
| 1 | 
            +
            <%= render Primer::BaseComponent.new(**@wrapper_arguments) do %>
         | 
| 2 2 | 
             
              <%= render Primer::BaseComponent.new(**@system_arguments) do %>
         | 
| 3 3 | 
             
                <% if @align == :right %>
         | 
| 4 4 | 
             
                  <%= actions %>
         | 
| 5 5 | 
             
                <% end %>
         | 
| 6 | 
            -
                 | 
| 7 | 
            -
                   | 
| 8 | 
            -
                    <%= tab %>
         | 
| 9 | 
            -
                  <% end %>
         | 
| 6 | 
            +
                <% tabs.each do |tab| %>
         | 
| 7 | 
            +
                  <%= tab %>
         | 
| 10 8 | 
             
                <% end %>
         | 
| 11 9 | 
             
                <% if @align == :left %>
         | 
| 12 10 | 
             
                  <%= actions %>
         | 
| 13 11 | 
             
                <% end %>
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                 | 
| 12 | 
            +
                <% tabs.each do |tab| %>
         | 
| 13 | 
            +
                  <%= tab.panel %>
         | 
| 14 | 
            +
                <% end %>
         | 
| 17 15 | 
             
              <% end %>
         | 
| 18 16 | 
             
            <% end %>
         | 
| @@ -18,7 +18,7 @@ module Primer | |
| 18 18 | 
             
                    Primer::Alpha::Navigation::Tab.new(
         | 
| 19 19 | 
             
                      selected: selected,
         | 
| 20 20 | 
             
                      with_panel: true,
         | 
| 21 | 
            -
                      list:  | 
| 21 | 
            +
                      list: false,
         | 
| 22 22 | 
             
                      icon_classes: "UnderlineNav-octicon",
         | 
| 23 23 | 
             
                      panel_id: "panel-#{id}",
         | 
| 24 24 | 
             
                      **system_arguments
         | 
| @@ -43,24 +43,16 @@ module Primer | |
| 43 43 | 
             
                  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
         | 
| 44 44 | 
             
                  def initialize(label:, align: ALIGN_DEFAULT, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
         | 
| 45 45 | 
             
                    @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
         | 
| 46 | 
            -
                    @wrapper_arguments = wrapper_arguments
         | 
| 46 | 
            +
                    @wrapper_arguments = deny_tag_argument(**wrapper_arguments)
         | 
| 47 | 
            +
                    @wrapper_arguments[:tag] = :div
         | 
| 47 48 |  | 
| 48 49 | 
             
                    @system_arguments = deny_tag_argument(**system_arguments)
         | 
| 49 | 
            -
                    @system_arguments[:tag] = : | 
| 50 | 
            +
                    @system_arguments[:tag] = :"tab-container"
         | 
| 50 51 | 
             
                    @system_arguments[:classes] = underline_nav_classes(@system_arguments[:classes], @align)
         | 
| 52 | 
            +
                    @system_arguments[:"aria-label"] = label
         | 
| 51 53 |  | 
| 52 54 | 
             
                    @body_arguments = deny_tag_argument(**body_arguments)
         | 
| 53 | 
            -
                    @body_arguments[:tag] = : | 
| 54 | 
            -
                    @body_arguments[:classes] = underline_nav_body_classes(@body_arguments[:classes])
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    @body_arguments[:role] = :tablist
         | 
| 57 | 
            -
                    @body_arguments[:"aria-label"] = label
         | 
| 58 | 
            -
                  end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                  private
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                  def body
         | 
| 63 | 
            -
                    Primer::BaseComponent.new(**@body_arguments)
         | 
| 55 | 
            +
                    @body_arguments[:tag] = :div
         | 
| 64 56 | 
             
                  end
         | 
| 65 57 | 
             
                end
         | 
| 66 58 | 
             
              end
         | 
| @@ -14,6 +14,11 @@ module Primer | |
| 14 14 | 
             
                #   Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
         | 
| 15 15 | 
             
                #   Either `aria-label` or `aria-description` will be used for the `Tooltip` text, depending on which one is present.
         | 
| 16 16 | 
             
                #   [Learn more about best functional image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/functional)
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                #   Additional markup is required if setting the `tag` argument to either `:a` or `:summary`.
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                #   * `:a` requires you to pass in an `href` attribute
         | 
| 21 | 
            +
                #   * `:summary` requires you to wrap the component in a `<details>` element
         | 
| 17 22 | 
             
                class IconButton < Primer::Component
         | 
| 18 23 | 
             
                  status :beta
         | 
| 19 24 |  | 
| @@ -101,6 +101,7 @@ module Primer | |
| 101 101 | 
             
                  # @param format_style [Symbol] The format the display should take. <%= one_of(Primer::Beta::RelativeTime::FORMAT_STYLE_OPTIONS) %>
         | 
| 102 102 | 
             
                  # @param lang [string] The language to use.
         | 
| 103 103 | 
             
                  # @param title [string] Provide a custom title to the element.
         | 
| 104 | 
            +
                  # @param no_title [Boolean] Removes the `title` attribute provided on the element by default.
         | 
| 104 105 | 
             
                  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
         | 
| 105 106 | 
             
                  def initialize(
         | 
| 106 107 | 
             
                    datetime:,
         | 
| @@ -120,6 +121,7 @@ module Primer | |
| 120 121 | 
             
                    format_style: nil,
         | 
| 121 122 | 
             
                    lang: nil,
         | 
| 122 123 | 
             
                    title: nil,
         | 
| 124 | 
            +
                    no_title: false,
         | 
| 123 125 | 
             
                    **system_arguments
         | 
| 124 126 | 
             
                  )
         | 
| 125 127 | 
             
                    @system_arguments = deny_tag_argument(**system_arguments)
         | 
| @@ -137,6 +139,7 @@ module Primer | |
| 137 139 | 
             
                    @system_arguments[:threshold] = threshold if threshold.present?
         | 
| 138 140 | 
             
                    @system_arguments[:precision] = precision if precision.present?
         | 
| 139 141 | 
             
                    @system_arguments[:title] = title if title.present?
         | 
| 142 | 
            +
                    @system_arguments[:"no-title"] = no_title if no_title
         | 
| 140 143 | 
             
                    @system_arguments[:lang] = lang if lang.present?
         | 
| 141 144 | 
             
                    @system_arguments[:format] = fetch_or_fallback(FORMAT_OPTIONS, format, FORMAT_DEFAULT) if format.present?
         | 
| 142 145 | 
             
                    @system_arguments[:"format-style"] = format_style if format_style.present?
         | 
| @@ -2,3 +2,6 @@ | |
| 2 2 | 
             
              <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" />
         | 
| 3 3 | 
             
              <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" />
         | 
| 4 4 | 
             
            <% end %>
         | 
| 5 | 
            +
            <% if no_aria_label? %>
         | 
| 6 | 
            +
              <span class="sr-only"><%= @sr_text %></span>
         | 
| 7 | 
            +
            <% end %>
         | 
| @@ -12,6 +12,7 @@ module Primer | |
| 12 12 | 
             
                    DEFAULT_SIZE => 32,
         | 
| 13 13 | 
             
                    :large => 64
         | 
| 14 14 | 
             
                  }.freeze
         | 
| 15 | 
            +
                  DEFAULT_SR_TEXT = "Loading"
         | 
| 15 16 |  | 
| 16 17 | 
             
                  SIZE_OPTIONS = SIZE_MAPPINGS.keys
         | 
| 17 18 |  | 
| @@ -22,7 +23,7 @@ module Primer | |
| 22 23 | 
             
                  # @param size [Symbol] <%= one_of(Primer::Beta::Spinner::SIZE_MAPPINGS) %>
         | 
| 23 24 | 
             
                  # @param style [String] Custom element styles.
         | 
| 24 25 | 
             
                  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
         | 
| 25 | 
            -
                  def initialize(size: DEFAULT_SIZE, style: DEFAULT_STYLE, **system_arguments)
         | 
| 26 | 
            +
                  def initialize(size: DEFAULT_SIZE, style: DEFAULT_STYLE, sr_text: DEFAULT_SR_TEXT, **system_arguments)
         | 
| 26 27 | 
             
                    @system_arguments = deny_tag_argument(**system_arguments)
         | 
| 27 28 | 
             
                    @system_arguments[:tag] = :svg
         | 
| 28 29 | 
             
                    @system_arguments[:style] ||= style
         | 
| @@ -31,6 +32,19 @@ module Primer | |
| 31 32 | 
             
                    @system_arguments[:height] = SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)]
         | 
| 32 33 | 
             
                    @system_arguments[:viewBox] = "0 0 16 16"
         | 
| 33 34 | 
             
                    @system_arguments[:fill] = :none
         | 
| 35 | 
            +
                    @system_arguments[:aria] ||= {}
         | 
| 36 | 
            +
                    @sr_text = sr_text
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    if no_aria_label?
         | 
| 39 | 
            +
                      @system_arguments[:aria][:hidden] = true
         | 
| 40 | 
            +
                    else
         | 
| 41 | 
            +
                      @system_arguments[:role] = "img"
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def no_aria_label?
         | 
| 46 | 
            +
                    !@system_arguments[:aria][:label] && !@system_arguments[:"aria-label"] &&
         | 
| 47 | 
            +
                        !@system_arguments[:aria][:labelledby] && !@system_arguments[:"aria-labelledby"]
         | 
| 34 48 | 
             
                  end
         | 
| 35 49 | 
             
                end
         | 
| 36 50 | 
             
              end
         | 
| @@ -29,7 +29,7 @@ module Primer | |
| 29 29 |  | 
| 30 30 | 
             
                  def render?
         | 
| 31 31 | 
             
                    # no slot provided
         | 
| 32 | 
            -
                     | 
| 32 | 
            +
                    return false if rows.empty? && columns.empty? && boxes.empty?
         | 
| 33 33 |  | 
| 34 34 | 
             
                    if [rows, columns, boxes].count { |arr| !arr.empty? } == 1
         | 
| 35 35 | 
             
                      # only rows or columns or boxes are used
         | 
| @@ -7,17 +7,20 @@ module Primer | |
| 7 7 | 
             
                  class TextFieldInput < Input
         | 
| 8 8 | 
             
                    attr_reader(
         | 
| 9 9 | 
             
                      *%i[
         | 
| 10 | 
            -
                        name label show_clear_button leading_visual clear_button_id
         | 
| 10 | 
            +
                        name label show_clear_button leading_visual leading_spinner clear_button_id
         | 
| 11 11 | 
             
                        visually_hide_label inset monospace field_wrap_classes auto_check_src
         | 
| 12 12 | 
             
                      ]
         | 
| 13 13 | 
             
                    )
         | 
| 14 14 |  | 
| 15 | 
            +
                    alias leading_spinner? leading_spinner
         | 
| 16 | 
            +
             | 
| 15 17 | 
             
                    def initialize(name:, label:, **system_arguments)
         | 
| 16 18 | 
             
                      @name = name
         | 
| 17 19 | 
             
                      @label = label
         | 
| 18 20 |  | 
| 19 21 | 
             
                      @show_clear_button = system_arguments.delete(:show_clear_button)
         | 
| 20 22 | 
             
                      @leading_visual = system_arguments.delete(:leading_visual)
         | 
| 23 | 
            +
                      @leading_spinner = !!system_arguments.delete(:leading_spinner)
         | 
| 21 24 | 
             
                      @clear_button_id = system_arguments.delete(:clear_button_id)
         | 
| 22 25 | 
             
                      @inset = system_arguments.delete(:inset)
         | 
| 23 26 | 
             
                      @monospace = system_arguments.delete(:monospace)
         | 
| @@ -30,6 +33,10 @@ module Primer | |
| 30 33 | 
             
                        )
         | 
| 31 34 | 
             
                      end
         | 
| 32 35 |  | 
| 36 | 
            +
                      if @leading_spinner && !@leading_visual
         | 
| 37 | 
            +
                        raise ArgumentError, "text fields that request a leading spinner must also specify a leading visual"
         | 
| 38 | 
            +
                      end
         | 
| 39 | 
            +
             | 
| 33 40 | 
             
                      super(**system_arguments)
         | 
| 34 41 |  | 
| 35 42 | 
             
                      add_input_data(:target, "primer-text-field.inputElement #{system_arguments.dig(:data, :target) || ''}")
         |