From c730a62309aa9df34807a8a9750024b1d2138e2c Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Thu, 29 Jun 2023 16:53:56 +0200 Subject: [PATCH] BREAKING CHANGE(web): Remove deprecated `Header` component #653 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Migration Guide ### HTML and CSS The original `Header__*` classes no longer exist, and so does the original structure. Instead, new subcomponents replace the original nested classes. The most notable change is that the mobile and desktop navigation are now separate components that cannot be nested: - `Header` - `HeaderDialog` Formerly, the desktop dialog (holding the site navigation) was a responsive CSS modification of a shared HTML code. With the new `Header` and `HeaderDialog`, each component has its own instance of the navigation, i.e. the navigation code is duplicated. This is because `HeaderDialog` will become an independent component in the future. You may need to take additional measures so your SEO is not affected by the duplicate HTML code of the navigation. While there are important changes also in the HTML structure, the old class names in `Header` can be roughly mapped onto the new subcomponents like this: - `Header__mobileOnlyActions` → `HeaderMobileOnlyActions` - `Header__bar` → removed without a replacement - `Header__content` → removed without a replacement - `Header__dialog` → `HeaderDialog`, stands outside of `Header` - `Header__close` → removed without a replacement - `Header__actions` → `HeaderDesktopOnlyActions` - `Header__nav` → `HeaderNav` - `Header__navItem` → `HeaderNavItem` - `Header__link` → `HeaderLink` - `Header__text` → removed without a replacement Inside `HeaderDialog`: - `Header__close` → `HeaderDialogCloseButton` - `Header__actions` → `HeaderDialogActions` - `Header__nav` → `HeaderDialogNav` - `Header__navItem` → `HeaderDialogNavItem` - `Header__link` → `HeaderDialogLink` - `Header__text` → `HeaderDialogText` ### JavaScript The deprecated `Header` JS plugin was removed in favour of the `Offcanvas` plugin. - `import { Header } from '@lmc-eu/spirit-web'` → `import { Offcanvas } from '@lmc-eu/spirit-web'` - `data-toggle="header"` → `data-spirit-toggle="offcanvas"` (`spirit` infix is made mandatory in PR #935) - `data-dismiss="header"` → `data-spirit-dismiss="offcanvas"` (`spirit` infix is made mandatory in PR #935) --- Please refer back to these instructions or reach out to our team if you encounter any issues during migration. --- packages/web/src/js/Header.ts | 147 ---------- packages/web/src/js/index.esm.ts | 1 - packages/web/src/js/index.umd.ts | 2 - .../web/src/scss/components/Header/README.md | 239 --------------- .../components/Header/_Header.deprecated.scss | 275 ------------------ .../components/Header/_theme.deprecated.scss | 50 ---- .../components/Header/_tools.deprecated.scss | 18 -- .../web/src/scss/components/Header/index.html | 212 -------------- .../web/src/scss/components/Header/index.scss | 8 - 9 files changed, 952 deletions(-) delete mode 100644 packages/web/src/js/Header.ts delete mode 100644 packages/web/src/scss/components/Header/_Header.deprecated.scss delete mode 100644 packages/web/src/scss/components/Header/_theme.deprecated.scss delete mode 100644 packages/web/src/scss/components/Header/_tools.deprecated.scss diff --git a/packages/web/src/js/Header.ts b/packages/web/src/js/Header.ts deleted file mode 100644 index bccf8b33ad..0000000000 --- a/packages/web/src/js/Header.ts +++ /dev/null @@ -1,147 +0,0 @@ -import BaseComponent from './BaseComponent'; -import EventHandler from './dom/EventHandler'; -import SelectorEngine from './dom/SelectorEngine'; -import { enableToggleTrigger, reflow, ScrollControl } from './utils'; - -const NAME = 'header'; -const HEADER_TOGGLE_SELECTOR = '[data-toggle="header"]'; -const HEADER_DISMISS_ATTRIBUTE = 'data-dismiss'; -const HEADER_BREAKPOINT = 1280; -const OPEN_CLASSNAME = 'is-open'; -const BACKDROP_TAG_NAME = 'div'; -const BACKDROP_CLASSNAME = 'Header__backdrop'; - -class Header extends BaseComponent { - isShown: boolean; - backdrop: HTMLElement; - scrollControl: ScrollControl; - - static get NAME() { - return NAME; - } - - constructor(element: HTMLElement) { - super(element); - - this.isShown = false; - this.backdrop = Header.initBackdrop(element); - this.scrollControl = new ScrollControl(element); - } - - static initBackdrop(target: HTMLElement) { - const backdropEl = document.createElement(BACKDROP_TAG_NAME); - backdropEl.classList.add(BACKDROP_CLASSNAME); - - if (!SelectorEngine.findAll(`[class*="${BACKDROP_CLASSNAME}"]`, target).length) { - target.appendChild(backdropEl); - reflow(backdropEl); - } - - return backdropEl; - } - - // Using `unknown` - Object is possibly 'null'. - // Using `Element | Window` - Property 'hasAttribute' does not exist on type 'EventTarget'. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onClick(event: Event & { target: any }) { - if (event.target.hasAttribute(HEADER_DISMISS_ATTRIBUTE) || event.target.classList.contains(BACKDROP_CLASSNAME)) { - event.preventDefault(); - event.stopPropagation(); - this.hide(event); - } - } - - onWindowResize(event: Event & { target: Window }) { - if (event.target.innerWidth >= HEADER_BREAKPOINT) { - this.hide(event); - } - } - - onKeyPress(event: KeyboardEvent) { - // Do nothing if the event was already processed. - if (event.defaultPrevented) { - return; - } - - if (event.key === 'Esc' || event.key === 'Escape') { - this.hide(event); - - // Cancel the default action to avoid it being handled twice. - event.preventDefault(); - } - - // @TODO: retain focus when using tab - // @see: https://github.com/lmc-eu/spirit-design-system/issues/278 - } - - addEventListeners() { - EventHandler.on(document, 'keydown', (event: KeyboardEvent) => this.onKeyPress(event)); - EventHandler.on(window, 'resize', (event: Event & { target: Window }) => this.onWindowResize(event)); - EventHandler.on(window, 'click', (event: Event & { target: Window }) => this.onClick(event)); - } - - removeEventListeners() { - EventHandler.off(document, 'keydown', (event: KeyboardEvent) => this.onKeyPress(event)); - EventHandler.off(window, 'resize', (event: Event & { target: Window }) => this.onWindowResize(event)); - EventHandler.off(window, 'click', (event: Event & { target: Window }) => this.onClick(event)); - } - - show(relatedTarget: HTMLElement) { - if (this.isShown) { - return; - } - - this.element.classList.add(OPEN_CLASSNAME); - relatedTarget.setAttribute('aria-expanded', 'true'); - - this.addEventListeners(); - this.isShown = true; - - this.scrollControl.disableScroll(); - } - - // Using `unknown` - Object is possibly 'null'. - // Using `Element | Window` - Property 'hasAttribute' does not exist on type 'EventTarget'. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - hide(event: Event & { target: any }) { - let target; - // hiding by resizing - if (!event.target.dataset) { - target = this.element; - // hiding by clicking - } else if (event.target.dataset.target) { - target = SelectorEngine.findOne(event.target.dataset.target); - // hiding by keyboard - } else { - target = event.target.parentNode; - } - - const navEl = this.element || target; - const headerEl = navEl.parentElement; - const toggleEl = SelectorEngine.findOne(HEADER_TOGGLE_SELECTOR, headerEl); - target.classList.remove(OPEN_CLASSNAME); - toggleEl?.setAttribute('aria-expanded', 'false'); - - this.removeEventListeners(); - this.isShown = false; - - this.scrollControl.enableScroll(); - } - - toggle(targetElement: HTMLElement | null, event: Event & { target: HTMLElement }) { - if (!targetElement) { - // eslint-disable-next-line no-console - console.warn( - '👻 Boo…! Target header pane does not exist. Maybe you forgot to prefix the "data-target" selector with "#"? ', - ); - - return; - } - - this.isShown ? this.hide(event) : this.show(targetElement); - } -} - -enableToggleTrigger(Header); - -export default Header; diff --git a/packages/web/src/js/index.esm.ts b/packages/web/src/js/index.esm.ts index 029c3583f3..e82b7ced8f 100644 --- a/packages/web/src/js/index.esm.ts +++ b/packages/web/src/js/index.esm.ts @@ -3,7 +3,6 @@ export { default as BaseComponent } from './BaseComponent'; export { default as Collapse } from './Collapse'; export { default as Dropdown } from './Dropdown'; export { default as FileUploader } from './FileUploader'; -export { default as Header } from './Header'; export { default as Modal } from './Modal'; export { default as Offcanvas } from './Offcanvas'; export { default as Password } from './Password'; diff --git a/packages/web/src/js/index.umd.ts b/packages/web/src/js/index.umd.ts index 7f5090d1f3..d7b52c9a07 100644 --- a/packages/web/src/js/index.umd.ts +++ b/packages/web/src/js/index.umd.ts @@ -3,7 +3,6 @@ import BaseComponent from './BaseComponent'; import Collapse from './Collapse'; import Dropdown from './Dropdown'; import FileUploader from './FileUploader'; -import Header from './Header'; import Modal from './Modal'; import Offcanvas from './Offcanvas'; import Password from './Password'; @@ -20,7 +19,6 @@ export default { Collapse, Dropdown, FileUploader, - Header, Modal, Offcanvas, Password, diff --git a/packages/web/src/scss/components/Header/README.md b/packages/web/src/scss/components/Header/README.md index b6071b71fb..132fc1005e 100644 --- a/packages/web/src/scss/components/Header/README.md +++ b/packages/web/src/scss/components/Header/README.md @@ -34,11 +34,6 @@ plugins. Or, feel free to write the controlling script yourself. -### DEPRECATION NOTICE - -⚠️ The existing Header JavaScript plugin is deprecated and will be superseded -by the Off-canvas plugin in the next major version. - ## Accessibility Guidelines - Ensure accessibility by using a `