From dc398cacee0007167ca674dd7fc8c7c86dac7d39 Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 12:58:36 +0800 Subject: [PATCH 01/16] chore(link element): add tab index to hyperlink --- src/base/link-element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/base/link-element.ts b/src/base/link-element.ts index 5ffce35e..3f318346 100644 --- a/src/base/link-element.ts +++ b/src/base/link-element.ts @@ -37,6 +37,7 @@ export default class LinkElement extends SgdsElement { })} " ?disabled=${this.disabled} aria-disabled=${this.disabled ? "true" : "false"} + tabindex=${this.disabled ? "-1" : "0"} > From 7797ba49b3ac91ed55b13cd1b342a03e36ff7947 Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 12:59:35 +0800 Subject: [PATCH 02/16] chore(icon): add menu icon --- src/components/Icon/icon-registry.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/Icon/icon-registry.ts b/src/components/Icon/icon-registry.ts index 4b869d32..30d91cf4 100644 --- a/src/components/Icon/icon-registry.ts +++ b/src/components/Icon/icon-registry.ts @@ -385,6 +385,12 @@ export const Map = ` `; +export const Menu = ` + + + + +`; export const Paperclip = ` From ff7406be5afd1ef1245b9134dbf45dc793742b8d Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 13:18:44 +0800 Subject: [PATCH 03/16] chore(icon button): fix text case --- test/icon-button.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/icon-button.test.ts b/test/icon-button.test.ts index a2bbe51f..22090476 100644 --- a/test/icon-button.test.ts +++ b/test/icon-button.test.ts @@ -20,7 +20,7 @@ describe("", () => { class="btn btn-icon btn-primary btn-md" tabindex="0" type="button"> - + ` ); From 2b6c7f415e6807d79d51dbd584ccebf4da50e9ca Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 13:19:22 +0800 Subject: [PATCH 04/16] chore(link element): fix text case --- test/link-element.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/link-element.test.ts b/test/link-element.test.ts index b7d037b1..9f7b8b2d 100644 --- a/test/link-element.test.ts +++ b/test/link-element.test.ts @@ -12,6 +12,7 @@ describe("link-element", () => { From 3ad83fa9527a0490ccf977711dbd39b162bdad88 Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 13:19:51 +0800 Subject: [PATCH 05/16] chore(overflow menu): fix text case --- test/overflow-menu.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/overflow-menu.test.ts b/test/overflow-menu.test.ts index dd63c58b..6d285d94 100644 --- a/test/overflow-menu.test.ts +++ b/test/overflow-menu.test.ts @@ -9,11 +9,11 @@ describe("", () => { el, ` - - - + + + ` ); }); From ebd197b9698b46e4790b338ea081f38a16eae2cb Mon Sep 17 00:00:00 2001 From: Tong Hau Date: Thu, 26 Dec 2024 13:33:02 +0800 Subject: [PATCH 06/16] feat(mainnav): update mainnav --- src/components/Mainnav/mainnav-dropdown.css | 80 +++-- src/components/Mainnav/mainnav-item.css | 126 ++++++-- src/components/Mainnav/mainnav.css | 287 +++++------------- .../Mainnav/sgds-mainnav-dropdown.ts | 70 ++--- src/components/Mainnav/sgds-mainnav.ts | 120 +++++--- 5 files changed, 347 insertions(+), 336 deletions(-) diff --git a/src/components/Mainnav/mainnav-dropdown.css b/src/components/Mainnav/mainnav-dropdown.css index c5b9047a..426412e3 100644 --- a/src/components/Mainnav/mainnav-dropdown.css +++ b/src/components/Mainnav/mainnav-dropdown.css @@ -1,40 +1,66 @@ -.dropdown-menu { - margin-top: 0; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 0 0 5px 5px; - background-color: #fff; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + +@media (min-width: 576px) { + :host([expand="sm"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } } -.nav-link.show { - border-color: var(--mainnav-theme-color); - color: var(--mainnav-theme-color); + +@media (min-width: 768px) { + :host([expand="md"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } +} + +@media (min-width: 992px) { + :host([expand="lg"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } +} + +@media (min-width: 1200px) { + :host([expand="xl"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } } -.sgds.dropdown.nav-item { - height: 100%; +@media (min-width: 1400px) { + :host([expand="xxl"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } } -a.nav-link { + +.nav-link { display: flex; + gap: var(--sgds-gap-xs); cursor: pointer; - color: var(--sgds-body-color); - border-bottom: 0.125rem solid transparent; + border-bottom: var(--sgds-border-width-4) solid transparent; min-height: 100%; align-items: center; - padding: 0; text-decoration: none; - &.active, - &:hover { - color: var(--mainnav-theme-color); - border-color: var(--mainnav-theme-color); - } - &:focus-visible { - box-shadow: 0 0 0 0.25rem rgba(89, 66, 219, 0.25); - outline: 0; - } + padding: var(--sgds-padding-sm) var(--mainnav-padding-x); + +} + +.nav-link:not(.disabled).active, +.nav-link.show { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); +} + +.nav-link:not(.disabled):hover { + color: var(--sgds-primary-color); +} + +.nav-link:not(.disabled):focus, +.nav-link:not(.disabled):focus-visible { + outline: 0; +} + +.nav-link:not(.disabled):focus-visible { + box-shadow: var(--sgds-box-shadow-focus); } .nav-link.disabled { - cursor: default; - pointer-events: none; - opacity: var(--mainnav-disabled-opacity); + opacity: var(--sgds-opacity-50); + cursor: not-allowed; } diff --git a/src/components/Mainnav/mainnav-item.css b/src/components/Mainnav/mainnav-item.css index 4a8953ba..dc11f580 100644 --- a/src/components/Mainnav/mainnav-item.css +++ b/src/components/Mainnav/mainnav-item.css @@ -1,31 +1,117 @@ -:host { - --mainnav-item-border-bottom-width: 0.125rem; +@media (min-width: 576px) { + :host([expand="sm"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } + + :host([expand="sm"]) .nav-link:not(.disabled).active { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); + } +} + +@media (min-width: 768px) { + :host([expand="md"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } + + :host([expand="md"]) .nav-link:not(.disabled).active { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); + } +} + +@media (min-width: 992px) { + :host([expand="lg"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } + + :host([expand="lg"]) .nav-link:not(.disabled).active { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); + } +} + +@media (min-width: 1200px) { + :host([expand="xl"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } + + :host([expand="xl"]) .nav-link:not(.disabled).active { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); + } +} + +@media (min-width: 1400px) { + :host([expand="xxl"]) .nav-link { + padding: 0px var(--sgds-padding-md); + } + + :host([expand="xxl"]) .nav-link:not(.disabled).active { + color: var(--sgds-primary-color); + border-color: var(--sgds-border-width-4) solid var(--sgds-primary-border-color); + } +} + +@media (max-width: 576px) { + :host([expand="sm"]) .nav-link:not(.disabled).active { + background-color: var(--sgds-default-bg-translucent-subtle); + } +} + +@media (max-width: 768px) { + :host([expand="md"]) .nav-link:not(.disabled).active { + background-color: var(--sgds-default-bg-translucent-subtle); + } +} + +@media (max-width: 992px) { + :host([expand="lg"]) .nav-link:not(.disabled).active { + background-color: var(--sgds-default-bg-translucent-subtle); + } +} + +@media (max-width: 1200px) { + :host([expand="xl"]) .nav-link:not(.disabled).active { + background-color: var(--sgds-default-bg-translucent-subtle); + } } -li { - height: 100%; + +@media (max-width: 1200px) { + :host([expand="xxl"]) .nav-link:not(.disabled).active { + background-color: var(--sgds-default-bg-translucent-subtle); + } } -a.nav-link { + +.nav-link { display: flex; cursor: pointer; - color: var(--sgds-body-color); - border-bottom: var(--mainnav-item-border-bottom-width) solid transparent; + border-bottom: var(--sgds-border-width-4) solid transparent; min-height: 100%; align-items: center; - padding: 0; text-decoration: none; - &.active, - &:hover { - color: var(--mainnav-theme-color); - border-color: var(--mainnav-theme-color); - } - &:focus-visible { - box-shadow: 0 0 0 0.25rem rgba(89, 66, 219, 0.25); - outline: 0; - } + color: var(--sgds-default-color); + padding: var(--sgds-padding-sm) var(--mainnav-padding-x); +} + +.nav-link:not(.disabled).active { + color: var(--sgds-primary-color); +} + +.nav-link:not(.disabled):hover { + color: var(--sgds-primary-color); +} + +.nav-link:focus, +.nav-link:focus-visible { + outline: 0; +} + +.nav-link:focus-visible { + box-shadow: var(--sgds-box-shadow-focus); } .nav-link.disabled { - cursor: default; - pointer-events: none; - opacity: var(--sgds-disabled-opacity); + opacity: var(--sgds-opacity-50); + cursor: not-allowed; } diff --git a/src/components/Mainnav/mainnav.css b/src/components/Mainnav/mainnav.css index ac984bbf..fb157892 100644 --- a/src/components/Mainnav/mainnav.css +++ b/src/components/Mainnav/mainnav.css @@ -1,369 +1,230 @@ -:host { - --mainnav-bg: transparent; - --mainnav-padding-x: var(--sgds-spacer-5); - --mainnav-padding-y: var(--sgds-spacer-0); - --mainnav-mobile-padding-x: var(--sgds-spacer-2); - --mainnav-mobile-padding-y: var(--sgds-spacer-0); - --mainnav-border-bottom-width: 1px; - --mainnav-border-bottom-color: var(--sgds-gray-400); - --mainnav-theme-color: var(--sgds-primary); +nav { + background-color: var(--sgds-neutral-bg-inverse); + box-shadow: 0px 2px 2px 0px rgba(14, 14, 14, 0.08); } + .navbar { - align-items: stretch; display: flex; flex-wrap: wrap; + align-items: stretch; justify-content: space-between; - padding: var(--mainnav-padding-y) var(--mainnav-padding-x); + gap: var(--sgds-gap-xs); position: relative; + padding: 0px var(--sgds-mainnav-padding-x); + width: 100%; + max-width: var(--sgds-mainnav-max-width); min-height: 80px; - background-color: var(--mainnav-bg); - border-bottom: var(--mainnav-border-bottom-width) solid var(--mainnav-border-bottom-color); - @media (max-width: 768px) { - padding: var(--mainnav-mobile-padding-y) var(--mainnav-mobile-padding-x); + margin: auto; +} + + +@media screen and (max-width: 768px) { + .navbar { + padding: 0px var(--sgds-mainnav-mobile-padding-x); } } + .navbar-brand { display: flex; align-items: center; - color: rgba(var(--sgds-emphasis-color-rgb), 0.9); - font-size: 1.25rem; - margin-right: var(--sgds-spacer-4); text-decoration: none; white-space: nowrap; - padding-bottom: 0.125rem; - padding-top: 0.125rem; } .navbar-brand:focus, -.navbar-brand:hover { - color: rgba(var(--sgds-emphasis-color-rgb), 0.9); +.navbar-brand:focus-visible { + box-shadow: var(--sgds-box-shadow-focus); + outline: 0; } + .navbar-nav { display: flex; flex-direction: column; - list-style: none; - gap: var(--sgds-spacer-4); - padding-left: 0; - padding-right: var(--sgds-spacer-4); + gap: var(--sgds-gap-xs); height: 100%; width: 100%; margin-top: 0; margin-bottom: 0; } + +nav > .navbar-body { + position: absolute; + z-index: 5; + width: 100%; + background-color: var(--sgds-default-bg-surface); + padding: var(--sgds-padding-md) 0px; + border-top: var(--sgds-border-width-1) solid var(--sgds-default-border-color-translucent); + box-shadow: 0px 2px 2px 0px rgba(14, 14, 14, 0.08); +} + +nav > .navbar-body slot::slotted(:not(sgds-mainnav-item):not(sgds-mainnav-dropdown)) { + padding: var(--sgds-padding-sm) var(--sgds-padding-lg); +} + .navbar-collapse { align-items: center; flex-basis: 100%; flex-grow: 1; } + .navbar-toggler { - cursor: pointer; - background-color: transparent; - border: none; - /* color: var(--mainnav-color); */ - font-size: 1.25rem; - line-height: 1; - padding: var(--sgds-spacer-1) 0.75rem; + align-self: center; } + @media (prefers-reduced-motion: reduce) { .navbar-toggler { transition: none; } } -.navbar-toggler:hover { - text-decoration: none; -} -.navbar-toggler:focus { - box-shadow: none; - outline: 0; - text-decoration: none; -} -.navbar-toggler-icon { - background-image: url('data:image/svg+xml,'); - background-position: 50%; - background-repeat: no-repeat; - background-size: 100%; - display: inline-block; - height: 1.5em; - vertical-align: middle; - width: 1.5em; -} + .navbar-nav-scroll { max-height: 75vh; - padding-right: 0.5rem; overflow-y: auto; } + @media (min-width: 576px) { .navbar-expand-sm { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } + .navbar-expand-sm .navbar-nav { flex-direction: row; } - /* .navbar-expand-sm .navbar-nav .dropdown-menu { - position: absolute; - } */ - /* .navbar-expand-sm .navbar-nav .nav-link { - padding-left: var(--mainnav-nav-link-padding-x); - padding-right: var(--mainnav-nav-link-padding-x); - } */ + .navbar-expand-sm .navbar-nav-scroll { overflow: visible; } + .navbar-expand-sm .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-sm .navbar-toggler { display: none; } - /* .navbar-expand-sm .offcanvas { - background-color: transparent !important; - border: 0 !important; - flex-grow: 1; - height: auto !important; - position: static; - transform: none !important; - transition: none; - visibility: visible !important; - width: auto !important; - z-index: auto; - } - .navbar-expand-sm .offcanvas .offcanvas-header { - display: none; - } - .navbar-expand-sm .offcanvas .offcanvas-body { - display: flex; - flex-grow: 0; - overflow-y: visible; - padding: 0; - } */ } @media (min-width: 768px) { .navbar-expand-md { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } + .navbar-expand-md .navbar-nav { flex-direction: row; } - /* .navbar-expand-md .navbar-nav .dropdown-menu { - position: absolute; - } */ - /* .navbar-expand-md .navbar-nav .nav-link { - padding-left: var(--mainnav-nav-link-padding-x); - padding-right: var(--mainnav-nav-link-padding-x); - } */ + .navbar-expand-md .navbar-nav-scroll { overflow: visible; } + .navbar-expand-md .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-md .navbar-toggler { display: none; } - /* - .navbar-expand-md .offcanvas { - background-color: transparent !important; - border: 0 !important; - flex-grow: 1; - height: auto !important; - position: static; - transform: none !important; - transition: none; - visibility: visible !important; - width: auto !important; - z-index: auto; - } - .navbar-expand-md .offcanvas .offcanvas-header { - display: none; - } - .navbar-expand-md .offcanvas .offcanvas-body { - display: flex; - flex-grow: 0; - overflow-y: visible; - padding: 0; - } */ } @media (min-width: 992px) { .navbar-expand-lg { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } + .navbar-expand-lg .navbar-nav { flex-direction: row; } - /* .navbar-expand-lg .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-lg .navbar-nav .nav-link { - padding-left: var(--mainnav-nav-link-padding-x); - padding-right: var(--mainnav-nav-link-padding-x); - } */ + .navbar-expand-lg .navbar-nav-scroll { overflow: visible; } + .navbar-expand-lg .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-lg .navbar-toggler { display: none; } - /* .navbar-expand-lg .offcanvas { - background-color: transparent !important; - border: 0 !important; - flex-grow: 1; - height: auto !important; - position: static; - transform: none !important; - transition: none; - visibility: visible !important; - width: auto !important; - z-index: auto; - } - .navbar-expand-lg .offcanvas .offcanvas-header { - display: none; - } - .navbar-expand-lg .offcanvas .offcanvas-body { - display: flex; - flex-grow: 0; - overflow-y: visible; - padding: 0; - } */ } @media (min-width: 1200px) { .navbar-expand-xl { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } - /* .navbar-expand-xl .navbar-nav { - flex-direction: row; - } - .navbar-expand-xl .navbar-nav .dropdown-menu { - position: absolute; - } */ + .navbar-expand-xl .navbar-nav .nav-link { padding-left: var(--mainnav-nav-link-padding-x); padding-right: var(--mainnav-nav-link-padding-x); } + .navbar-expand-xl .navbar-nav-scroll { overflow: visible; } + .navbar-expand-xl .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-xl .navbar-toggler { display: none; } - /* .navbar-expand-xl .offcanvas { - background-color: transparent !important; - border: 0 !important; - flex-grow: 1; - height: auto !important; - position: static; - transform: none !important; - transition: none; - visibility: visible !important; - width: auto !important; - z-index: auto; - } - .navbar-expand-xl .offcanvas .offcanvas-header { - display: none; - } - .navbar-expand-xl .offcanvas .offcanvas-body { - display: flex; - flex-grow: 0; - overflow-y: visible; - padding: 0; - } */ } @media (min-width: 1400px) { .navbar-expand-xxl { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } + .navbar-expand-xxl .navbar-nav { flex-direction: row; } - /* .navbar-expand-xxl .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand-xxl .navbar-nav .nav-link { - padding-left: var(--mainnav-nav-link-padding-x); - padding-right: var(--mainnav-nav-link-padding-x); - } */ + .navbar-expand-xxl .navbar-nav-scroll { overflow: visible; } + .navbar-expand-xxl .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-xxl .navbar-toggler { display: none; } - /* .navbar-expand-xxl .offcanvas { - background-color: transparent !important; - border: 0 !important; - flex-grow: 1; - height: auto !important; - position: static; - transform: none !important; - transition: none; - visibility: visible !important; - width: auto !important; - z-index: auto; - } - .navbar-expand-xxl .offcanvas .offcanvas-header { - display: none; - } - .navbar-expand-xxl .offcanvas .offcanvas-body { - display: flex; - flex-grow: 0; - overflow-y: visible; - padding: 0; - } */ } + .navbar-expand { flex-wrap: nowrap; justify-content: flex-start; + gap: var(--sgds-gap-xl); } .navbar-expand .navbar-nav { flex-direction: row; } -/* .navbar-expand .navbar-nav .dropdown-menu { - position: absolute; - } - .navbar-expand .navbar-nav .nav-link { - padding-left: var(--mainnav-nav-link-padding-x); - padding-right: var(--mainnav-nav-link-padding-x); - } */ + .navbar-expand .navbar-nav-scroll { overflow: visible; } + .navbar-expand .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand .navbar-toggler { display: none; } -.order-first { - order: -1 !important; -} -.order-1 { - order: 1 !important; -} -.order-2 { - order: 2 !important; -} -.order-last { - order: 6 !important; -} /* slot */ @@ -378,10 +239,10 @@ slot[name="non-collapsible"] { display: flex; margin-left: auto; align-items: stretch; - gap: var(--sgds-spacer-4); + gap: var(--sgds-gap-xs); } /* there is no wildcard selector for element tag names in css */ .slot-end::slotted(:not([name$="-mainnav-item"]):not([name$="-mainnav-dropdown"])) { align-self: center; -} +} \ No newline at end of file diff --git a/src/components/Mainnav/sgds-mainnav-dropdown.ts b/src/components/Mainnav/sgds-mainnav-dropdown.ts index bcbe4614..c93e5522 100644 --- a/src/components/Mainnav/sgds-mainnav-dropdown.ts +++ b/src/components/Mainnav/sgds-mainnav-dropdown.ts @@ -1,22 +1,25 @@ import { html } from "lit"; -import { property, queryAsync } from "lit/decorators.js"; +import { property } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; -import { ref } from "lit/directives/ref.js"; -import { DropdownListElement } from "../../base/dropdown-list-element"; import genId from "../../utils/generateId"; import dropdownStyle from "../Dropdown/dropdown.css"; import dropdownMenuStyle from "../Dropdown/dropdown-menu.css"; import mainnavDropdownStyle from "./mainnav-dropdown.css"; +import SgdsDropdown from "../Dropdown/sgds-dropdown"; +import SgdsDropdownItem from "../Dropdown/sgds-dropdown-item"; +import SgdsIcon from "../Icon/sgds-icon"; +import SgdsElement from "../../base/sgds-element"; /** * @slot default - The menu items. Pass in sgds-dropdown-item as the menu items * @slot toggler - The content of the toggler to pass in html content. `togglerText` property takes precedence over this slot when both are defined. */ -export class SgdsMainnavDropdown extends DropdownListElement { - static styles = [...DropdownListElement.styles, dropdownStyle, dropdownMenuStyle, mainnavDropdownStyle]; - - /**@internal */ - @queryAsync("a") - private dropdownRef: Promise; +export class SgdsMainnavDropdown extends SgdsElement { + static styles = [...SgdsElement.styles, dropdownStyle, dropdownMenuStyle, mainnavDropdownStyle]; + static dependencies = { + "sgds-dropdown": SgdsDropdown, + "sgds-dropdown-item": SgdsDropdownItem, + "sgds-icon": SgdsIcon + }; /** @internal Forwards value to id attribute of toggle button of Dropdown. An unique id generated by default */ private togglerId: string = genId("dropdown", "button"); @@ -29,51 +32,40 @@ export class SgdsMainnavDropdown extends DropdownListElement { @property({ type: Boolean }) active = false; - async firstUpdated() { - super.firstUpdated(); - if (this.menuIsOpen) { - await this.dropdownRef; - this.showMenu(); - } - } + /** When true, applies active styles on the dropdown button */ + @property({ type: Boolean, reflect: true }) + disabled = false; render() { return html` - + + `; } } diff --git a/src/components/Mainnav/sgds-mainnav.ts b/src/components/Mainnav/sgds-mainnav.ts index cd379ee2..129cd7a1 100644 --- a/src/components/Mainnav/sgds-mainnav.ts +++ b/src/components/Mainnav/sgds-mainnav.ts @@ -1,5 +1,5 @@ import { html } from "lit"; -import { property, query, state } from "lit/decorators.js"; +import { property, query, queryAssignedElements, state } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; import SgdsElement from "../../base/sgds-element"; import { animateTo, shimKeyframesHeightAuto, stopAnimations } from "../../utils/animate"; @@ -8,7 +8,10 @@ import { LG_BREAKPOINT, MD_BREAKPOINT, SM_BREAKPOINT, XL_BREAKPOINT, XXL_BREAKPO import { waitForEvent } from "../../utils/event"; import genId from "../../utils/generateId"; import { watch } from "../../utils/watch"; +import SgdsMainnavItem from "./sgds-mainnav-item"; import mainnavStyle from "./mainnav.css"; +import SgdsMainnavDropdown from "./sgds-mainnav-dropdown"; +import SgdsIcon from "../Icon/sgds-icon"; export type MainnavExpandSize = "sm" | "md" | "lg" | "xl" | "xxl" | "always" | "never"; const SIZES = { @@ -29,27 +32,28 @@ const SIZES = { * @event sgds-hide - Emitted on hide. Only for collapsed menu. * @event sgds-after-hide - Emitted on hide after animation has completed. Only for collapsed menu. * - * @slot - Default slot of SgdsMainnav. Pass in SgdsMainnavItem elements here. + * @slot default - Default slot of SgdsMainnav. Pass in SgdsMainnavItem elements here. * @slot end - Elements in this slot will be positioned to the right end of .navbar-nav. Elements in this slot will also be included in collapsed menu. * @slot brand - Brand slot of SgdsMainnav. Pass in brand logo img here * @slot non-collapsible - Elements in this slot will not be collapsed * - * @cssproperty --mainnav-bg - Navbar's background color. - * @cssproperty --mainnav-padding-x - left and right padding for browser width > 768px - * @cssproperty --mainnav-padding-y - top and bottom padding for browser width > 768px - * @cssproperty --mainnav-mobile-padding-x - left and right padding for browser width < 768px - * @cssproperty --mainnav-mobile-padding-y - top and bottom padding for browser width < 768px - * @cssproperty --mainnav-border-bottom-width - bottom border width - * @cssproperty --mainnav-border-bottom-color - border-bottom width color - * @cssproperty --mainnav-theme-color - The theme color of mainnav affecting the hover and active states of items in the mainnav */ export class SgdsMainnav extends SgdsElement { static styles = [...SgdsElement.styles, mainnavStyle]; + static dependencies = { + "sgds-icon": SgdsIcon + }; + /** @internal */ + @query("nav") nav: HTMLElement; + /** @internal */ + @query(".navbar") navbar: HTMLElement; /** @internal */ @query(".navbar-toggler") header: HTMLElement; /** @internal */ @query(".navbar-body") body: HTMLElement; + /** @internal */ + @query("slot[name='non-collapsible']") nonCollapsibleSlot: HTMLSlotElement; constructor() { super(); @@ -61,6 +65,12 @@ export class SgdsMainnav extends SgdsElement { this.body ? (this.body.hidden = true) : null; this.expanded = false; } + + if (newBreakpointReachedValue) { + this._handleMobileNav(); + } else { + this._handleDesktopNav(); + } }); } @@ -81,12 +91,41 @@ export class SgdsMainnav extends SgdsElement { /** @internal */ @state() expanded = false; + + /** @internal */ + @queryAssignedElements() private defaultNodes!: SgdsMainnavItem[] | SgdsMainnavDropdown[]; + + /** @internal */ + @queryAssignedElements({ slot: "end" }) private endNodes!: SgdsMainnavItem[] | SgdsMainnavDropdown[]; + + /** @internal */ + get defaultSlotitems(): SgdsMainnavItem[] | SgdsMainnavDropdown[] { + return [...(this.defaultNodes || [])].filter((node: HTMLElement) => typeof node.tagName !== "undefined") as + | SgdsMainnavItem[] + | SgdsMainnavDropdown[]; + } + + /** @internal */ + get endSlotItems(): SgdsMainnavItem[] | SgdsMainnavDropdown[] { + return [...(this.endNodes || [])].filter((node: HTMLElement) => typeof node.tagName !== "undefined") as + | SgdsMainnavItem[] + | SgdsMainnavDropdown[]; + } + firstUpdated() { if (this.breakpointReached && this.body) { this.expanded = false; this.body.hidden = true; + this._handleMobileNav(); } + + const items = [...this.defaultSlotitems, ...this.endSlotItems] as SgdsMainnavItem[] | SgdsMainnavDropdown[]; + + items.forEach((item: SgdsMainnavItem | SgdsMainnavDropdown) => { + item.setAttribute("expand", this.expand); + }); } + private handleSummaryClick() { if (this.expanded) { this.hide(); @@ -97,6 +136,14 @@ export class SgdsMainnav extends SgdsElement { this.header.focus(); } + private _handleMobileNav() { + this.nav?.appendChild(this.body); + } + + private _handleDesktopNav() { + this.navbar?.insertBefore(this.body, this.nonCollapsibleSlot); + } + private async _animateToShow() { const sgdsShow = this.emit("sgds-show", { cancelable: true }); if (sgdsShow.defaultPrevented) { @@ -171,35 +218,34 @@ export class SgdsMainnav extends SgdsElement { render() { this.breakpointReached = window.innerWidth < SIZES[this.expand]; - const collapseClass = "navbar-body navbar-collapse order-2"; + return html` -