UNPKG

@atlaskit/page-layout

Version:

A collection of components which let you compose an application's page layout.

114 lines (112 loc) 3.99 kB
/* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners */ /** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled import { css, jsx } from '@emotion/react'; import { easeOut, prefersReducedMotion } from '@atlaskit/motion'; import { DEFAULT_I18N_PROPS_SKIP_LINKS, PAGE_LAYOUT_CONTAINER_SELECTOR } from '../../common/constants'; import { useSkipLinks } from '../../controllers'; import { SkipLink } from './skip-link'; // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 const prefersReducedMotionStyles = css(prefersReducedMotion()); const skipLinkStyles = css({ margin: "var(--ds-space-250, 20px)", padding: '0.8rem 1rem', position: 'fixed', zIndex: -1, backgroundColor: "var(--ds-surface-overlay, #FFFFFF)", border: 'none', borderRadius: "var(--ds-radius-small, 3px)", boxShadow: "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)", insetInlineStart: -999999, opacity: 0, transform: 'translateY(-50%)', transition: `transform 0.3s ${easeOut}`, '&:focus-within': { zIndex: 2147483640, insetInlineStart: 0, opacity: 1, transform: 'translateY(0%)' } }); const skipLinkHeadingStyles = css({ fontWeight: "var(--ds-font-weight-semibold, 600)" }); const skipLinkListStyles = css({ listStylePosition: 'outside', listStyleType: 'none', marginBlockStart: "var(--ds-space-050, 4px)", paddingInlineStart: 0 }); const assignIndex = (num, arr) => { if (!arr.includes(num)) { return num; } return assignIndex(num + 1, arr); }; /** * The default label will be used when the `skipLinksLabel` attribute is not * provided or the attribute is an empty string. If a string comprised only of * spaces is provided, the skip link heading element will be removed, but the * default label will still be used in `title` attribute of the skip links * themselves. */ export const SkipLinkWrapper = ({ skipLinksLabel }) => { const { skipLinksData } = useSkipLinks(); if (skipLinksData.length === 0) { return null; } const sortSkipLinks = arr => { const customLinks = arr.filter(link => Number.isInteger(link.listIndex)); if (customLinks.length === 0) { return arr; } const usedIndexes = customLinks.map(a => a.listIndex); const regularLinksWithIdx = arr.filter(link => link.listIndex === undefined).map((link, idx) => { const listIndex = assignIndex(idx, usedIndexes); usedIndexes.push(listIndex); return { ...link, listIndex }; }); return [...customLinks, ...regularLinksWithIdx].sort((a, b) => a.listIndex - b.listIndex); }; const escapeHandler = event => { if (event.keyCode === 27) { const container = document.querySelector(`[${PAGE_LAYOUT_CONTAINER_SELECTOR}="true"]` // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage ); if (container !== null) { container.focus(); } } }; const attachEscHandler = () => window.addEventListener('keydown', escapeHandler, false); const removeEscHandler = () => window.removeEventListener('keydown', escapeHandler, false); const emptyLabelOverride = !!(skipLinksLabel !== null && skipLinksLabel !== void 0 && skipLinksLabel.match(/^\s+$/)); const label = skipLinksLabel || DEFAULT_I18N_PROPS_SKIP_LINKS; return jsx("div", { onFocus: attachEscHandler, onBlur: removeEscHandler, css: [skipLinkStyles, prefersReducedMotionStyles], "data-skip-link-wrapper": true }, emptyLabelOverride ? null : jsx("p", { css: skipLinkHeadingStyles }, label), jsx("ol", { css: skipLinkListStyles }, sortSkipLinks(skipLinksData).map(({ id, skipLinkTitle }) => jsx(SkipLink, { key: id, href: `#${id}`, isFocusable: true }, skipLinkTitle)))); };