UNPKG

@rhds/elements

Version:
195 lines (193 loc) 10.9 kB
var _RhJumpLinks_instances, _RhJumpLinks_internals, _RhJumpLinks_overflow, _RhJumpLinks_onScroll, _RhJumpLinks_spy, _RhJumpLinks_onClickScroll, _RhJumpLinks_onSelect, _RhJumpLinks_setActiveItem; import { __classPrivateFieldGet, __decorate } from "tslib"; import { html, isServer, LitElement } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { provide } from '@lit/context'; import { ScrollSpyController } from '@patternfly/pfe-core/controllers/scroll-spy-controller.js'; import { OverflowController } from '@patternfly/pfe-core/controllers/overflow-controller.js'; import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; import { observes } from '@patternfly/pfe-core/decorators.js'; import { themable } from '@rhds/elements/lib/themable.js'; import { RhJumpLink } from './rh-jump-link.js'; import { rhJumpLinksOrientationContext } from './context.js'; import { css } from "lit"; const style = css `:host{display:block;position:relative}.overflow-button{display:hidden}#container{--_bdr:var(--rh-length-4xs,1px) solid var(--rh-color-border-subtle)}:host([orientation=horizontal]){display:flex;justify-content:center}:host([orientation=horizontal]) #container{display:flex;flex-flow:row nowrap;overflow:auto visible}:is(:host([orientation=horizontal]) #container):after,:is(:host([orientation=horizontal]) #container):before{display:block;position:absolute;inset-inline:0;content:""}:is(:host([orientation=horizontal]) #container):before{margin-inline:var(--rh-space-3xl);border-block-start:var(--rh-border-width-sm,1px) solid var(--rh-color-border-subtle)}:is(:host([orientation=horizontal]) #container):after{border-block-end:var(--rh-border-width-sm,1px) solid var(--rh-color-border-subtle);inset-block-end:0}:host([orientation=horizontal]) .overflow-button{flex:none;line-height:1;opacity:1;border:0;padding-block:0;padding-inline:var(--rh-space-lg,16px);background-color:initial;color:var(--_overflow-button-text-color);position:relative;z-index:2}:is(:host([orientation=horizontal]) .overflow-button) rh-icon{pointer-events:none}:is(:is(:host([orientation=horizontal]) .overflow-button) rh-icon):dir(rtl){rotate:180deg}:is(:host([orientation=horizontal]) .overflow-button):first-of-type{margin-inline-end:0;translate:0 0}:is(:host([orientation=horizontal]) .overflow-button):first-of-type:before{border-inline-width:0 1px}:is(:host([orientation=horizontal]) .overflow-button):nth-of-type(2){margin-inline-start:0;translate:0 0;inset-inline-start:-1px}:is(:host([orientation=horizontal]) .overflow-button):nth-of-type(2):before{border-inline-width:1px 0}:is(:host([orientation=horizontal]) .overflow-button):disabled{pointer-events:none;color:light-dark(var(--rh-color-gray-40,#a3a3a3),var(--rh-color-gray-50,#707070))}:is(:host([orientation=horizontal]) .overflow-button):hover{color:var(--rh-color-text-primary)}`; import '@rhds/elements/rh-icon/rh-icon.js'; /** * Persistent in-page navigation for jumping to content sections. * Renders a `role="navigation"` landmark with `aria-label` from * `accessible-label` (required per WCAG 1.3.6 when multiple nav * landmarks exist). Supports vertical and horizontal orientations * with ScrollSpy auto-highlighting. Avoid nesting more than one * level deep. * * @alias jump-links * * @summary Persistent navigation links to page sections * * @fires toggle - Fired when the `expanded` disclosure widget is toggled. * Does not carry additional detail data. */ let RhJumpLinks = class RhJumpLinks extends LitElement { constructor() { super(...arguments); _RhJumpLinks_instances.add(this); /** * Controls the layout direction of jump link items. * * - `vertical` (default) - Links are stacked vertically, typically displayed on the side of the page * - `horizontal` - Links are arranged in a row, with overflow scroll controls when needed * * ## Usage guidelines * - Use `vertical` for sidebar navigation on desktop layouts * - Use `horizontal` for mobile-friendly layouts or when space is limited * - When horizontal, scroll buttons appear automatically to navigate overflowing links * - The orientation cascades to child `<rh-jump-link>` and `<rh-jump-links-list>` elements * * @see [Orientation](https://ux.redhat.com/elements/jump-links/style/#orientation) in Style documentation */ this.orientation = 'vertical'; _RhJumpLinks_internals.set(this, InternalsController.of(this, { role: 'navigation' })); _RhJumpLinks_overflow.set(this, new OverflowController(this)); _RhJumpLinks_onScroll.set(this, __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").onScroll.bind(this)); _RhJumpLinks_spy.set(this, new ScrollSpyController(this, { rootMargin: '0px 0px 0px 0px', tagNames: ['rh-jump-link'], onIntersection: () => { for (const list of this.querySelectorAll('rh-jump-links-list')) { list.active = !!list.querySelector('rh-jump-link[active]'); } __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").update(); }, })); } connectedCallback() { super.connectedCallback(); this.addEventListener('select', __classPrivateFieldGet(this, _RhJumpLinks_instances, "m", _RhJumpLinks_onSelect)); } firstUpdated() { const active = this.querySelector('rh-jump-link[active]'); if (active) { __classPrivateFieldGet(this, _RhJumpLinks_instances, "m", _RhJumpLinks_setActiveItem).call(this, active); } } labelChanged() { if (this.accessibleLabel) { __classPrivateFieldGet(this, _RhJumpLinks_internals, "f").ariaLabel = this.accessibleLabel; } } render() { const { overflowLeft, overflowRight, showScrollButtons: overflow } = __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f"); return html ` <button id="scroll-start" class="overflow-button" ?hidden="${!overflow}" tabindex="-1" data-direction="start" aria-label="${this.getAttribute('label-scroll-left') ?? 'Scroll back'}" ?disabled="${!overflowLeft}" @click="${__classPrivateFieldGet(this, _RhJumpLinks_instances, "m", _RhJumpLinks_onClickScroll)}"> <rh-icon set="ui" icon="caret-left" loading="eager"></rh-icon> </button> <div id="container" role="list"> <!-- summary: navigation link items and nested lists (default slot) description: | Contains \`<rh-jump-link>\` elements and optional \`<rh-jump-links-list>\` groups. Each child receives \`role="listitem"\` within the \`role="list"\` container, forming an accessible navigation structure for screen readers. Link each item to a section ID (\`href="#id"\`) corresponding to a heading or landmark on the page. Place links in page order so assistive technology users experience a logical sequence. Use nested lists sparingly to avoid overwhelming users. --> <slot></slot> </div> <button id="scroll-end" class="overflow-button" ?hidden="${!overflow}" tabindex="-1" data-direction="end" aria-label="${this.getAttribute('label-scroll-right') ?? 'Scroll forward'}" ?disabled="${!overflowRight}" @click="${__classPrivateFieldGet(this, _RhJumpLinks_instances, "m", _RhJumpLinks_onClickScroll)}"> <rh-icon set="ui" icon="caret-right" loading="eager"></rh-icon> </button> `; } async orientationChanged() { if (isServer) { return; } if (!this.hasUpdated) { await this.updateComplete; } const container = this.shadowRoot.getElementById('container'); const items = Array.from(this.querySelectorAll(':scope > *')); switch (this.orientation) { case 'horizontal': __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").init(container, items); container.addEventListener('scroll', __classPrivateFieldGet(this, _RhJumpLinks_onScroll, "f")); break; case 'vertical': container.removeEventListener('scroll', __classPrivateFieldGet(this, _RhJumpLinks_onScroll, "f")); } } }; _RhJumpLinks_internals = new WeakMap(); _RhJumpLinks_overflow = new WeakMap(); _RhJumpLinks_onScroll = new WeakMap(); _RhJumpLinks_spy = new WeakMap(); _RhJumpLinks_instances = new WeakSet(); _RhJumpLinks_onClickScroll = function _RhJumpLinks_onClickScroll(event) { if (event.target instanceof HTMLElement) { switch (event.target.dataset.direction) { case 'start': if (this.matches(':dir(rtl)')) { __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").scrollRight(); } else { __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").scrollLeft(); } break; case 'end': if (this.matches(':dir(rtl)')) { __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").scrollLeft(); } else { __classPrivateFieldGet(this, _RhJumpLinks_overflow, "f").scrollRight(); } break; } } }; _RhJumpLinks_onSelect = function _RhJumpLinks_onSelect(event) { if (event.target instanceof RhJumpLink) { __classPrivateFieldGet(this, _RhJumpLinks_instances, "m", _RhJumpLinks_setActiveItem).call(this, event.target); } }; _RhJumpLinks_setActiveItem = async function _RhJumpLinks_setActiveItem(item) { await this.updateComplete; __classPrivateFieldGet(this, _RhJumpLinks_spy, "f").setActive(item); }; RhJumpLinks.styles = [style]; __decorate([ provide({ context: rhJumpLinksOrientationContext }), property({ reflect: true }) ], RhJumpLinks.prototype, "orientation", void 0); __decorate([ property({ attribute: 'accessible-label' }) ], RhJumpLinks.prototype, "accessibleLabel", void 0); __decorate([ observes('accessibleLabel') ], RhJumpLinks.prototype, "labelChanged", null); __decorate([ observes('orientation') ], RhJumpLinks.prototype, "orientationChanged", null); RhJumpLinks = __decorate([ customElement('rh-jump-links'), themable ], RhJumpLinks); export { RhJumpLinks }; //# sourceMappingURL=rh-jump-links.js.map