diff --git a/src/app/components/Layout.tsx b/src/app/components/Layout.tsx index 7d7d440819..2613a8d908 100644 --- a/src/app/components/Layout.tsx +++ b/src/app/components/Layout.tsx @@ -6,11 +6,13 @@ import theme from '../theme'; import AccessibilityButtonsWrapper from './AccessibilityButtonsWrapper'; import NavBar from './NavBar'; import OnEsc from './OnEsc'; +import PageTitleConfirmation from './PageTitleConfirmation'; // tslint:disable-next-line:variable-name const Layout: SFC = ({ children }) => + {children} diff --git a/src/app/components/PageTitleConfirmation.spec.tsx b/src/app/components/PageTitleConfirmation.spec.tsx new file mode 100644 index 0000000000..ad2be45612 --- /dev/null +++ b/src/app/components/PageTitleConfirmation.spec.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { renderToDom } from '../../test/reactutils'; +// import { act } from 'react-dom/test-utils'; +import { initialState } from '../reducer'; +import createTestStore from '../../test/createTestStore'; +import PageTitleConfirmation from './PageTitleConfirmation'; +import TestContainer from '../../test/TestContainer'; +import { setHead } from '../head/actions'; + +describe('PageTitleConfirmation', () => { + it('skips blank, skips first non-blank, announces subsequent', async() => { + const state = { + ...initialState, + }; + + state.head.title = 'initial'; + const store = createTestStore(state); + + store.dispatch(setHead({...initialState.head, title: ''})); + const component = renderToDom( + + + + ); + + expect(component.node.textContent).toBe(''); + store.dispatch(setHead({...initialState.head, title: 'initial'})); + expect(component.node.textContent).toBe(''); + store.dispatch(setHead({...initialState.head, title: 'something'})); + expect(component.node.textContent).toBe('Loaded page something'); + component.unmount(); + }); +}); diff --git a/src/app/components/PageTitleConfirmation.tsx b/src/app/components/PageTitleConfirmation.tsx new file mode 100644 index 0000000000..0b990ff5fd --- /dev/null +++ b/src/app/components/PageTitleConfirmation.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { hiddenButAccessible } from '../theme'; +import { AppState } from '../types'; +import styled from 'styled-components'; +import { connect } from 'react-redux'; +import { title as titleSelector } from '../head/selectors'; + +function PageTitleConfirmation({ + className, + title, +}: { + className: string; + title: string; +}) { + const skipFirst = React.useRef(true); + const message = React.useMemo(() => { + if (!title) { + return ''; + } + if (skipFirst.current) { + skipFirst.current = false; + return ''; + } + return `Loaded page ${title}`; + }, [title]); + + return ( +
+ {message} +
+ ); +} + +export default connect((state: AppState) => ({title: titleSelector(state)}))(styled( + PageTitleConfirmation +)` + ${hiddenButAccessible} +`); diff --git a/src/app/content/components/__snapshots__/Content.spec.tsx.snap b/src/app/content/components/__snapshots__/Content.spec.tsx.snap index c26f60fa27..da08515acd 100644 --- a/src/app/content/components/__snapshots__/Content.spec.tsx.snap +++ b/src/app/content/components/__snapshots__/Content.spec.tsx.snap @@ -169,6 +169,26 @@ Array [ /> + , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c4 { display: inline-block; @@ -4867,6 +4887,26 @@ Array [ /> + , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c4 { display: inline-block; diff --git a/src/app/developer/components/__snapshots__/Home.spec.tsx.snap b/src/app/developer/components/__snapshots__/Home.spec.tsx.snap index 2c81ba1cbf..4c095338a4 100644 --- a/src/app/developer/components/__snapshots__/Home.spec.tsx.snap +++ b/src/app/developer/components/__snapshots__/Home.spec.tsx.snap @@ -169,6 +169,26 @@ Array [ /> + , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c19 { display: inline-block; diff --git a/src/app/theme.ts b/src/app/theme.ts index c43ac98245..141ca5ffe8 100644 --- a/src/app/theme.ts +++ b/src/app/theme.ts @@ -9,6 +9,18 @@ export interface ColorSet { darkest?: string; } +export const hiddenButAccessible = ` + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +`; + const textColors = { black: '#000', default: '#424242',