From 9a46c290725888e0851b4d47fa22dddf108f29a3 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Tue, 24 Oct 2023 14:54:31 -0400 Subject: [PATCH] fixes/updates --- cspell.json | 1 + docs/_includes/default.njk | 2 +- docs/_includes/layout-templates/example.html | 52 +++++- docs/assets/styles/docs.css | 10 +- scripts/build.js | 10 +- src/components/layout/layout.component.ts | 177 +++++++++---------- src/components/layout/layout.styles.ts | 64 ++++--- 7 files changed, 183 insertions(+), 133 deletions(-) diff --git a/cspell.json b/cspell.json index 8b66531e1..977a0811c 100644 --- a/cspell.json +++ b/cspell.json @@ -171,6 +171,7 @@ "valpha", "valuenow", "valuetext", + "viewports", "WCAG", "webawesome", "WEBP", diff --git a/docs/_includes/default.njk b/docs/_includes/default.njk index a34f47bbb..33a8ea6bc 100644 --- a/docs/_includes/default.njk +++ b/docs/_includes/default.njk @@ -61,7 +61,7 @@ - + Skip to main content diff --git a/docs/_includes/layout-templates/example.html b/docs/_includes/layout-templates/example.html index 45d44a620..00e8a329c 100644 --- a/docs/_includes/layout-templates/example.html +++ b/docs/_includes/layout-templates/example.html @@ -1,9 +1,47 @@ - -
Header
- -
Main
- -
Footer
+ +
+
+ Option 1
+ Option 2
+ Option 3 +
+
+ + + +

I'm just a lowly page.

+

+ I think I'll put a link right here for you to click. And maybe another one here for + fun. +

+ + I'm just a lowly dialog. + + Open Dialog
-{% include "layout-widget.njk" %} + + + diff --git a/docs/assets/styles/docs.css b/docs/assets/styles/docs.css index 4e6ab9416..42e2ee026 100644 --- a/docs/assets/styles/docs.css +++ b/docs/assets/styles/docs.css @@ -7,7 +7,6 @@ --docs-content-padding: 2rem; --docs-content-vertical-spacing: 2rem; --docs-search-overlay-background: rgb(0 0 0 / 0.2); - --docs-skip-to-main-width: 200px; } /* Light theme */ @@ -650,18 +649,17 @@ html.sidebar-open #menu-toggle { } /* Skip to main content */ -#skip-to-main { +#skip-to-content { position: fixed; - top: 0.25rem; - left: calc(50% - var(--docs-skip-to-main-width) / 2); + top: var(--wa-space-m); + left: var(--wa-space-m); z-index: 100; - width: var(--docs-skip-to-main-width); text-align: center; text-decoration: none; border-radius: 9999px; background: var(--wa-color-surface-default); color: var(--wa-color-text-normal); - padding: 0.5rem; + padding: var(--wa-space-s); } /* Print styles */ diff --git a/scripts/build.js b/scripts/build.js index 17cfb18d2..dc241ee3d 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -335,12 +335,12 @@ if (!serve) { await nextTask('Building the docs', async () => { result = await buildTheDocs(); - }); - // Log deferred output - if (result.output.length > 0) { - console.log('\n' + result.output.join('\n')); - } + // Log deferred output + if (result.output.length > 0) { + console.log('\n' + result.output.join('\n')); + } + }); } // Cleanup on exit diff --git a/src/components/layout/layout.component.ts b/src/components/layout/layout.component.ts index 0e147257c..ecf201858 100644 --- a/src/components/layout/layout.component.ts +++ b/src/components/layout/layout.component.ts @@ -1,13 +1,10 @@ import { html } from 'lit'; +import { live } from 'lit/directives/live.js'; import { property, query } from 'lit/decorators.js'; -import { when } from 'lit/directives/when.js'; import styles from './layout.styles.js'; -import WaButton from '../button/button.component.js'; import WaDrawer from '../drawer/drawer.component.js'; -import WaVisuallyHidden from '../visually-hidden/visually-hidden.component.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import type { CSSResultGroup, PropertyValueMap } from 'lit'; -import { live } from 'lit/directives/live.js'; /** * @summary @@ -15,60 +12,85 @@ import { live } from 'lit/directives/live.js'; * @status experimental * @since 3.0 * - * @slot - The default slot. This is generally where your main content will go. - * @slot banner - A banner to display above the header. Will collapse if the content size is 0px. - * @slot header - A header to display at the top of the page or below a banner. Will collapse if the content size is 0px. - * @slot sub-header - A sub-header to display below the `header`. Generally this is where breadcrumbs would go. - * @slot menu - The left hand side of the page. If you slot an element in here, you will override the default "navigation" slot and will be handling navigation on your own. This also will not disable the fallback behavior of the navigation button. This is a sticky element. - * @slot navigation-header - The header for a navigation area. On mobile this will be the header for `` + * @slot - The page's main content. + * @slot banner - The banner that gets display above the header. The banner will not be shown if no content is provided. + * @slot header - The header to display at the top of the page. If a banner is present, the header will appear below the banner. The header will not be shown if there is no content. + * @slot subheader - A subheader to display below the `header`. This is a good place to put things like breadcrumbs. + * @slot menu - The left side of the page. If you slot an element in here, you will override the default "navigation" slot and will be handling navigation on your own. This also will not disable the fallback behavior of the navigation button. This section "sticks" to the top as the page scrolls. + * @slot navigation-header - The header for a navigation area. On mobile this will be the header for ``. * @slot navigation - The main content to display in the navigation area. - * @slot navigation-footer - The footer for a navigation area. On mobile this will be the footer for `` - * @slot main-header - Header to display inline above the main content - * @slot main-footer - Footer to display inline below the main content - * @slot aside - Content to be shown on the right side of the page. Generally this may be table of contents, ads, etc. This is sticky. - * @slot skip-links - If you would like to override the `Skip to main` button and add additional "Skip to X", they can be inserted here. + * @slot navigation-footer - The footer for a navigation area. On mobile this will be the footer for ``. + * @slot main-header - Header to display inline above the main content. + * @slot main-footer - Footer to display inline below the main content. + * @slot aside - Content to be shown on the right side of the page. Typically contains a table of contents, ads, etc. This section "sticks" to the top as the page scrolls. + * @slot skip-to-content - The "skip to content" slot. You can override this If you would like to override the `Skip to main` button and add additional "Skip to X", they can be inserted here. * @slot footer - The content to display in the footer. This is always displayed underneath the viewport so will always make the page "scrollable". * * @csspart base - The component's base wrapper. - * @csspart banner - The banner to show above header + * @csspart banner - The banner to show above header. * @csspart header - The header, usually for top level navigation / branding. - * @csspart sub-header - Shown below the header, usually intended for things like breadcrumbs and other page level navigation. - * @csspart body - The wrapper around menu, main, and aside + * @csspart subheader - Shown below the header, usually intended for things like breadcrumbs and other page level navigation. + * @csspart body - The wrapper around menu, main, and aside. * @csspart menu - The left hand side of the page. Generally intended for navigation. - * @csspart main-header - The header above main-content. - * @csspart main-content - The main content + * @csspart main-header - The header above main content. + * @csspart main-content - The main content. * @csspart main-footer - The footer below main content. * @csspart aside - The right hand side of the page. Used for things like table of contents, ads, etc. - * @csspart skip-links - Wrapper around skip-link - * @csspart skip-link - The "skip to main content" link + * @csspart skip-to-content - The "skip to content" link that shows when focused. * @csspart nav-button - The default mobile `` displayed on mobile viewports. - * @csspart footer - The footer of the page. This is always below the initial viewport size. - * @csspart dialog-wrapper - A wrapper around elements such as dialogs or other modal-like elements. + * @csspart footer - The footer of the page. This is always below the initial viewport. * - * @cssproperty [--menu-width=auto] - used for the grid for the menu width - * @cssproperty [--main-width=1fr] - used for the grid for the main width - * @cssproperty [--aside-width=auto] - Used for the grid for the aside width - * @cssproperty [--banner-height=0px] - This gets auto-calculated when the layout connects. If you know the height of your banner, you can optionally set this to the proper value to prevent shifting. - * @cssproperty [--header-height=0px] - This gets auto-calculated when the layout connects. If you know the height of your header, you can optionally set this to the proper value to prevent shifting. - * @cssproperty [--sub-header-height=0px] - This gets auto-calculated when the layout connects. If you know the height of your sub-header, you can optionally set this to the proper value to prevent shifting. + * @cssproperty [--menu-width=auto] - The width of the layout's "menu" section. + * @cssproperty [--main-width=1fr] - The width of the layout's "main" section. + * @cssproperty [--aside-width=auto] - The wide of the layout's "aside" section. + * @cssproperty [--banner-height=0px] - The height of the banner. This gets calculated when the layout initializes. If the height is known, you can set it here to prevent shifting when the page loads. + * @cssproperty [--header-height=0px] - The height of the header. This gets calculated when the layout initializes. If the height is known, you can set it here to prevent shifting when the page loads. + * @cssproperty [--subheader-height=0px] - The height of the subheader. This gets calculated when the layout initializes. If the height is known, you can set it here to prevent shifting when the page loads. */ export default class WaLayout extends WebAwesomeElement { static styles: CSSResultGroup = styles; static dependencies = { - 'wa-button': WaButton, - 'wa-visually-hidden': WaVisuallyHidden, 'wa-drawer': WaDrawer }; - /** - * This maps to the "id" of the element placed in the default slot of the layout component. - * This is used to generate the "Skip to main content" button. - */ - @property({ attribute: 'main-id' }) mainId: string = ''; + private headerResizeObserver = this.slotResizeObserver('header'); + private subheaderResizeObserver = this.slotResizeObserver('subheader'); + private bannerResizeObserver = this.slotResizeObserver('banner'); + private footerResizeObserver = this.slotResizeObserver('footer'); + + private slotResizeObserver(slot: string) { + return new ResizeObserver(entries => { + for (const entry of entries) { + if (entry.contentBoxSize) { + const contentBoxSize = entry.borderBoxSize[0]; + this.style.setProperty(`--${slot}-height`, `${contentBoxSize.blockSize}px`); + } + } + }); + } + + private handleNavigationToggle = (e: Event) => { + // Don't toggle the nav when we're in desktop mode + if (this.view === 'desktop') { + return; + } + + if (e.composedPath().find((el: Element) => el?.hasAttribute?.('data-toggle-nav'))) { + e.preventDefault(); + this.toggleNavigation(); + } + }; + + @query("[part~='header']") header: HTMLElement; + @query("[part~='subheader']") subheader: HTMLElement; + @query("[part~='footer']") footer: HTMLElement; + @query("[part~='banner']") banner: HTMLElement; + @query("[part~='drawer']") navigationDrawer: WaDrawer; /** - * The view is a reflection of the "mobileBreakpoint", when the layout is larger than the mobileBreakpoint (768px by default) - * it is considered to be a "desktop" view. The view is merely a way to distinguish when to show / hide the navigation. + * The view is a reflection of the "mobileBreakpoint", when the layout is larger than the `mobile-breakpoint` (768 by + * default), it is considered to be a "desktop" view. The view is merely a way to distinguish when to show/hide the + * navigation. You can use additional media queries to make other adjustments to content as necessary. */ @property({ attribute: 'view', reflect: true }) view: 'mobile' | 'desktop' = 'mobile'; @@ -115,38 +137,8 @@ export default class WaLayout extends WebAwesomeElement { super.update(changedProperties); } - headerResizeObserver = this.slotResizeObserver('header'); - subHeaderResizeObserver = this.slotResizeObserver('sub-header'); - bannerResizeObserver = this.slotResizeObserver('banner'); - footerResizeObserver = this.slotResizeObserver('footer'); - - slotResizeObserver(slot: string) { - return new ResizeObserver(entries => { - for (const entry of entries) { - if (entry.contentBoxSize) { - const contentBoxSize = entry.borderBoxSize[0]; - this.style.setProperty(`--${slot}-height`, `${contentBoxSize.blockSize}px`); - } - } - }); - } - - @query("[part~='header']") header: HTMLElement; - @query("[part~='sub-header']") subHeader: HTMLElement; - @query("[part~='footer']") footer: HTMLElement; - @query("[part~='banner']") banner: HTMLElement; - @query("[part~='drawer']") navigationDrawer: WaDrawer; - - handleNavigationToggle = (e: Event) => { - if (e.composedPath().find((el: Element) => el?.hasAttribute?.('data-toggle-nav'))) { - e.preventDefault(); - this.toggleNavigation(); - } - }; - constructor() { super(); - this.addEventListener('click', this.handleNavigationToggle); } @@ -157,17 +149,28 @@ export default class WaLayout extends WebAwesomeElement { setTimeout(() => { this.headerResizeObserver.observe(this.header); - this.subHeaderResizeObserver.observe(this.subHeader); + this.subheaderResizeObserver.observe(this.subheader); this.bannerResizeObserver.observe(this.banner); this.footerResizeObserver.observe(this.footer); }); } + firstUpdated() { + // If the user provides a #main-content id, it should be present in the default slot and the "skip to + // content" link will point to it. If not, we'll prepend an empty element for them so things just work. + if (!document.getElementById('main-content')) { + const div = document.createElement('div'); + div.id = 'main-content'; + div.slot = 'skip-to-content-target'; + this.prepend(div); + } + } + disconnectedCallback() { super.disconnectedCallback(); this.layoutResizeObserver.unobserve(this); this.headerResizeObserver.unobserve(this.header); - this.subHeaderResizeObserver.unobserve(this.subHeader); + this.subheaderResizeObserver.unobserve(this.subheader); this.footerResizeObserver.unobserve(this.footer); this.bannerResizeObserver.unobserve(this.banner); } @@ -195,18 +198,9 @@ export default class WaLayout extends WebAwesomeElement { render() { return html` - - - ${when( - this.mainId, - () => html` - - Skip to main - - ` - )} - - + + Skip to content +
-
- +
+
-
+
+ + +