Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | <script lang="ts"> import Link from "$lib/components/Link/Link.svelte"; import chunk from "$lib/util/chunk"; import classNames from "$lib/util/classNames"; import { createEventDispatcher } from "svelte"; import type { NavMenuProps, NavLinkType } from "./types"; type $$Props = NavMenuProps; const dispatch = createEventDispatcher(); export let id = ""; export let current = false; export let columns = 1; export let children: NavLinkType[] = []; export let expanded = false; $: buttonClassNames = classNames("usa-accordion__button usa-nav__link", current && "usa-current"); // If we want more than one column, evenly divide the nav items into mega menu columns. // TODO: We may want to let the CMS determine the position of each item in the future. let megaMenuColumns: NavLinkType[][] = []; $: { if (columns > 1) { // Calculate the maximum length of columns (maximum number of items in a column) and provide // to chunk as the size (second) parameter. megaMenuColumns = chunk(children, Math.ceil(children.length / columns)); } } // We can't use on:click since it only triggers if the mousedown and mouseup events occur on the // same target, and on mobile the collapse of an accordion when it loses focus happens on // mousedown, sometimes shifting the elements so that mouseup misses the target. // Instead, we'll use both mousedown and keydown to ensure everything functions accessibly on // both desktop and mobile screen sizes. const handleKeyDown = (event: KeyboardEvent) => (event.key === "Enter" || event.key === " ") && dispatch("toggle"); const handleMouseDown = () => dispatch("toggle"); // By default focusout on the container will trigger for all its children, but using 'self' // doesn't resolve the issue since the container element isn't the one with the focus. // This workaround will ignore the event if the new focused element is a child of the container. // Based on this REPL: https://svelte.dev/repl/4c5dfd34cc634774bd242725f0fc2dab?version=3.46.4 const handleDropdownFocusLoss = ({ relatedTarget, currentTarget, }: FocusEvent & { currentTarget: EventTarget & HTMLDivElement }) => { if (relatedTarget instanceof HTMLElement && currentTarget?.contains(relatedTarget)) return; dispatch("close"); }; </script> <!-- TODO: This div is necessary for handling focus loss, but it breaks the styling for a menu being marked with an underline as the active / current nav item. --> <div on:focusout={handleDropdownFocusLoss}> <button type="button" class={buttonClassNames} aria-expanded={expanded} aria-controls="extended-mega-nav-section-{id}" on:keydown={handleKeyDown} on:mousedown={handleMouseDown} > <!-- Extra <span/> element is necessary for expand icons to load. --> <span><slot /></span> </button> {#if columns <= 1} <!-- Basic Menu Layout--> <ul id="extended-mega-nav-section-{id}" class="usa-nav__submenu" hidden={!expanded}> {#each children as { id, link, name } (id)} <li class="usa-nav__submenu-item"> <Link href={link}>{name}</Link> </li> {/each} </ul> {:else} <!-- Mega Menu Layout --> <div id="extended-mega-nav-section-{id}" class="usa-nav__submenu usa-megamenu" hidden={!expanded} > <div class="grid-row grid-gap-4"> {#each megaMenuColumns as column, i (i)} <div class="usa-col"> <ul class="usa-nav__submenu-list"> {#each column as { id, link, name } (id)} <li class="usa-nav__submenu-item"> <Link href={link}>{name}</Link> </li> {/each} </ul> </div> {/each} </div> </div> {/if} </div> |