Написано Джереми Китоме ✏️.
Введение
Web Accessibility (также известный как A11Y ) относится к дизайну, кодированию и созданию веб-сайтов и веб-инструментов, которые могут быть использованы всеми. В настоящее время существует много сайтов и инструментов, которые имеют доступность барьеров, которые представляют проблемы для некоторых пользователей. Чтобы построить более доступную сеть, важно привести доступность на переднем крае разработки продукта.
Время доступности веб-контента (WCAG) предоставляет общие стандарты для создания доступных сайтов и инструментов, которые соответствуют потребностям отдельных лиц, организаций и правительств на международном уровне.
Вы можете найти контрольные списки из Проект A11Y , Wuhcag и Webaim Основываясь на WCAG, который вы можете использовать в качестве контрольной точки при создании доступных продуктов.
В этой статье мы будем создавать доступный компонент для выбора даты, который использует рекомендации доступности. Вот краткосрочная демо, показывающая, как будет выглядеть готовый компонент:
Предварительные условия
Эта статья предполагает, что вы знакомы с Реагировать Отказ Прежде чем мы начнем строить сборщик даты, убедитесь, что у вас есть Узел , Пряжа или NPM Установлен на вашу машину. Если нет, вы можете найти инструкции о том, как установить их в предоставленные ссылки. Мы будем использовать Create-raction-app для загрузки нашего проекта. Документация Create-React-App рекомендует, чтобы предыдущие версии были установлены глобально через NPM Установить -g Create-React-App
удалены с использованием NPM Uninstall -G Create-React-App
Чтобы убедиться, что NPX (Инструмент бегуна пакета, который поставляется с версиями NPM 5.2+), всегда использует последнюю версию.
Начиная
Давайте посмотрим вперед и посмотрим, как создать наш проект. Вы можете использовать любой из трех доступных опций, выделенных ниже, чтобы создать свой проект.
NPX:
$ npx create-react-app accessible-datepicker
NPM ( NPM init <Инициализатор>
Доступен в NPM 6+) :
$ npm init react-app accessible-datepicker
пряжа ( пряжа создает
Доступен в пряжа 0,25+) :
$ yarn create react-app my-app
Как только вы закончите создание папки проекта, вы можете открыть ее и запустить:
cd accessible-datepicker npm start //or yarn start
Это запускает приложение в режиме разработки, и вы можете просмотреть его в браузере, используя ссылку http://localhost: 3000/ Отказ
Установка дополнительных зависимостей
Поскольку многие структуры CSS имеют доступность встроенных в их компонентах, мы избегаем их использования. Это позволит нам понять, как создавать доступные компоненты без помощи структуры. Мы потребуем пару библиотек, которые помогут нам построить наш состав сопорядщика даты. Дата FNS Для манипулирования датами, ractawesome для иконок, Лоташ манипулировать некоторыми данными и aDe-ax которые тестируют ваше приложение для доступности и отчеты о результатах непосредственно к консоли при разработке и отладке.
Чтобы установить их, запустите следующую команду:
$ yarn add date-fns lodash @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome react-axe
Как только зависимости установлены, настройте RACT -AXE, добавив следующий код в SRC/index.js
Отказ
import axe from 'react-axe'; if (process.env.NODE_ENV !== 'production') { axe(React, ReactDOM, 1000); }
Настройка компонентов
Наше приложение для выбора даты будет иметь три составных компонента, а именно:
- Компонент приложений, который будет основным компонентом приложения
- Компонент Picker Date, который отобразит текущую дату, когда приложение загружает и приглашает пользователю выбрать дату
- Календарный компонент, который отобразит календарь, который пользователь может перемещаться и выбирать дату
# Navigate to source directory $ cd src/ #Create new files $ touch calendar.js datepicker.js
Доступность
В этой статье мы будем сосредоточиться на том, чтобы сделать компонент, доступный с помощью соответствующего контраста, навигации на клавиатуре и Доступные богатые интернет-приложения (ARIA) Отказ Цвет сейфы это замечательный сайт, который позволяет создавать доступный цвет текста для данного цвета фона на основе WCAG Руководящие принципы для контрастных соотношений.
ARIA SEMANTICS У вас возникнут в этой статье:
- Роль E.G Применение, Кнопка, Сетка, Сетка Cell
- Ария-этикетка
- ария выбрана
Роль определяет тип элемента пользовательского интерфейса. Aria-Label
Атрибут используется для определения строки, которая этикетки текущего элемента и используется в тех случаях, когда текстовая метка не видна на экране. АРИА, с другой стороны, с другой стороны, указывает текущий «выбранный» состояние виджета.
Навигация вокруг календаря мы будем работать позже, можно управлять, используя ключевые ключи, связанные с определенными действиями.
Осталось | Перемещение фокусировки одна ячейка влево (предыдущий день) |
Верно | Перемещения фокусировки одной ячейки справа (на следующий день) |
Вверх | Перемещение фокусировки Одна ячейка вверх (в тот же день предыдущая неделя) |
Вниз | Перемещение фокусировки одной ячейки вниз (в тот же день на следующей неделе) |
Страница вверх | Переходы фокусировки на аналогичную ячейку для предыдущей таблицы (в тот же день предыдущего месяца) |
Листать вниз | Перемещение фокусировки на аналогичную ячейку для следующей таблицы (тот же день в следующем месяце) |
Дома | Перемещение фокусировки на первую ячейку в сетке (первый день месяца) |
Конец | Перемещение фокусировки на последнюю клетку в сетке (последний день месяца) |
Ctrl + Page Up | Движется фокус на тот же день предыдущего года |
Ctrl + Page Down | Движения фокусировки на тот же день в следующем году |
Ввод / пространство | Выберите ячейку в фокусе (день) |
Esc. | Закрыть календарь |
Компонент приложения
Это сделает компонент Picker Date и компонент календаря, условно на основе логических ценностей в состоянии. У нас будут две логические ценности в штате, ShowDatePicker
и Showcalendar
Чтобы переключить сборщик даты и видимость календаря соответственно. Когда видимый сбор даты, календарь не будет видимым и наоборот. У нас также будет ценность Дата
В состоянии, что мы будем инициализировать на текущую дату и можем быть изменены, когда пользователь выбирает другую дату на календаре. Посмотрим, как это выглядит, чтобы начать с. Добавьте следующий код в src/app.js.
:
import React, { useState } from 'react'; import { format } from 'date-fns'; import './App.css'; const App = () => { const [showDatepicker, setShowDatePicker] = useState(true); const [showCalendar, setShowCalendar] = useState(false); const [date, setDate] = useState(format(new Date(), "yyyy-MM-dd")); return ({showDatepicker && (); } export default App;Datepicker)} {showCalendar && (Calendar)}
Когда пользователь нажимает на сборник даты, сборщик даты должен быть закрыт, а также показан календарь. Мы создадим метод компонента TOGGLECALENDAR
сделать это. Мы добавим еще два метода HandleseLectdate
Чтобы обновить дату выбранной пользователем и CloseCalendar
Чтобы переключить из календаря на сборник даты, не изменив текущую выбранную дату. Код будет выглядеть что-то подобное:
const toggleCalendar = (e) => { setShowDatePicker(false); setShowCalendar(true); } const handleSelectDate = (date) => { setDate(date); setShowDatePicker(true); setShowCalendar(false); } const closeCalendar = () => { setShowDatePicker(true); setShowCalendar(false); }
Теперь мы сделали основную настройку для компонента приложений и теперь можем начать строить компоненты детей.
Компонент пикера даты
Компонент Picker Date покажет текст, подсказывающий пользователю выбрать дату и текущую выбранную дату. Это получит Дата
и Ручной отделение
реквизит, чтобы показать текущую дату и переключить видимость календаря соответственно.
Для укладки я решил использовать элемент div, в отличие от чего-то более интуитивного такого как кнопку или ввод. Чтобы позволить пользователю привлекать счетчик даты, используя клавишу Tab, нам нужно дать Div A Tabindex = "0"
атрибут. Пользователь должен иметь возможность привлекать пикер даты, чтобы показать календарь, нажав на Введите
или Пространство
клавиши клавиатуры. Мы можем облегчить это, используя OnkeyPress
Слушатель событий слушает ключевые прессы.
Как только клавиша нажата, нам нужно убедиться, что это Введите
ключ или Пространство
ключ перед продолжением. Для визуальных пользователей, нажав на сборник даты, следует переключить календарь. Наше SRC/DatePicker.js
Файл должен выглядеть что-то вроде этого:
import React from 'react'; import './App.css'; const Datepicker = ({ date, handleSelect }) => { const handleKeyPress = (e) => { const charCode = e.charCode if(charCode === 13 || charCode === 32) { handleSelect(); } } return (); } export default Datepicker;Select a date{date}
Давайте пойдем вперед и импортируем компонент Picker даты в нашем SRC/App.js
Файл и пропустите его соответствующие реквизиты:
... import Datepicker from "./datepicker"; const App = () => { .... return ({showDatepicker && (); } export default App;)} {showCalendar && ( Calendar)}
Давайте также добавлю немного стиля в SRC/App.csss.
. Вы можете стиль его, как вы хотите, пока вы следуете контрастным рекомендациям. Вы заметите, что добавил стиль фокуса для всех элементов:
.App { text-align: center; display: flex; justify-content: center; padding-top: 50px; } *:focus { outline: 2px solid #d71ef7; } .datepicker { display: flex; flex-direction: row; border: 1px solid black; cursor: pointer; } .datepicker > div { padding: 10px 20px; } .datepicker > div:nth-child(1) { border-right: 1px solid black; background-color: #00b5ad; color: #000000; }
Следующие изображения показывают, что наше приложение будет выглядеть как раз перезагрузки:
Сфокусировано со сфокусом
Сосредоточенная сосредоточенная
Календарный компонент
Когда компонент календаря завершен, он должен отображать сетку, которая запускается отображением месяца выбранной текущей даты и может быть перемещена на разные даты. Первый шаг – построить заголовок календаря, который содержит значки для навигации на предыдущий месяц, предыдущий год, в следующем месяце и в следующем году.
Он также будет отображать текущий выбранный месяц и год. Мы создадим таблицу, которая будет иметь только имена дней недели на данный момент. Использование DATE-FNS Мы сможем добавить методы, которые могут добавлять или вычитать в месяц или год с текущей выбранной даты. Мы создадим новый объект даты, используя реквизиты даты, передаваемые из компонента приложений и хранят его в состоянии. Это будет использоваться для создания календаря позже. Наш начальный код для компонента календаря должен выглядеть что-то подобное:
import React, { useState } from 'react'; import { format, startOfMonth, subMonths, addMonths, subYears, addYears, getDaysInMonth, getDay, endOfMonth, setDate, getDate, isEqual, subWeeks, addWeeks, subDays, addDays } from 'date-fns'; import { chunk } from 'lodash'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons' import './App.css'; const Calendar = ({ date, handleSelectDate, closeCalendar }) => { const[selectedDate,setSelectedDate] = useState(new Date(date)); const setPreviousMonth = () => { const previousMonth = subMonths(selectedDate, 1); setStartDate(startOfMonth(previousMonth)); } const setNextMonth = () => { const nextMonth = addMonths(selectedDate, 1); setStartDate(startOfMonth(nextMonth)); } const setPreviousYear = () => { const previousYear = subYears(selectedDate, 1); setStartDate(startOfMonth(previousYear)); } const setNextYear = () => { const nextYear = addYears(selectedDate, 1); setStartDate(startOfMonth(nextYear)); } const handleKeyPress = (e,cb) => { const charCode = e.charCode if(charCode === 13 || charCode === 32) { cb(); } } return (); } export default Calendar;handleKeyPress(e,setPreviousYear)} role="button" aria-label="Previous year" > handleKeyPress(e,setPreviousMonth)} role="button" aria-label="Previous month" > {format(selectedDate, "MMMM yyyy")}handleKeyPress(e,setNextMonth)} role="button" aria-label="Next year" > handleKeyPress(e,setNextYear)} role="button" aria-label="Next year" >
Su Mo Tu We Th Fr Sa
Когда клавиша нажата, в то время как любой из кнопок значков ориентирован, мы позвоним HandleyPlepress
с событием и обратным вызовом. Он проверит, был ли нажатой клавиши, был нажат либо ввода, либо пространство, то выполните обратный вызов.
Как только мы импортируем нашу календарный компонент и передаем его соответствующие реквизиты, наши App.js
Файл будет завершен.
import React, { useState } from 'react'; import { format } from 'date-fns'; import Datepicker from "./datepicker"; import Calendar from "./calendar"; import './App.css'; const App = () => { const [showDatepicker, setShowDatePicker] = useState(true); const [showCalendar, setShowCalendar] = useState(false); const [date, setDate] = useState(format(new Date(), "yyyy-MM-dd")); const toggleCalendar = (e) => { setShowDatePicker(false); setShowCalendar(true); } const handleSelectDate = (date) => { setDate(date); setShowDatePicker(true); setShowCalendar(false); } const closeCalendar = () => { setShowDatePicker(true); setShowCalendar(false); } return ({showDatepicker && (); } export default App;)} {showCalendar && ( )}
Когда вы перезагружаете приложение и щелкните по выборам даты, он принесет календарь, у которого еще нет даты населенных пунктов.
Генерировать дни месяца
Теперь, когда у нас есть заголовок календаря и дни недели, следующий шаг – генерировать дни этого месяца. Календарь будет сгенерирован, используя дату, которую мы инициализировали в состоянии. Нам нужно знать, сколько дней есть в месяц и в какой день первые и последние дни падают. Если в течение первого дня с каждым дневным дни и после последнего дня с следующего месяца на этой неделе нам нужно будет добавить пустые значения для заполнения недели. Это даст нам массив, длина которого является множественным из семи (количество дней в неделю). Затем мы можем использовать метод утилиты Chank Loadash для создания массива массивов, где каждый массив находится в неделю в месяц, имеющих дни недели:
const generateMonth = () => { const daysInMonth = getDaysInMonth(selectedDate); const startWeekday = getDay(startOfMonth(selectedDate)); const endWeekday = getDay(endOfMonth(selectedDate)); const gridDays = chunk([ ...Array.from({ length: startWeekday }).fill(null), ...Array.from({ length: daysInMonth }, (_,i) => setDate(selectedDate, i+1)), ...Array.from({ length: (6-endWeekday) }).fill(null) ], 7); return gridDays; }
Как только у нас есть сгенерированные недели и даты, нам нужно сделать данные. Каждая строка будет представлять неделю и каждый столбец в день недели. Каждая ячейка будет отображать соответствующий день месяца, а для пустых дней мы заполнили недели, с пустыми ячейками будут созданы. Выбранная дата будет выделена:
{generateMonth().map((week,i) => ({week.map((day,i) => ( day ? ))}handleDateSelection(day)} role="gridcell" aria-selected={isEqual(selectedDate, day)} > {getDate(day)} :))}
После перезагрузки приложения вы увидите, что дни месяца теперь заполнены:
Вы, наверное, заметили, что наш табличный элемент имел Tabindex = "0"
атрибут. Это позволяет ориентироваться и клавиши клавиш, используемые для навигации дней. В дополнение к таблице ключа/действия в разделе «Доступность» в разделе «Доступность» необходимо определить некоторые дополнительные правила для навигации на календаре с помощью клавиш клавиатуры.
- Когда пользователь нажимает влево, и текущий выбранный день – первый день месяца, они будут приняты в последний день предыдущего месяца
- Когда пользователь нажимает правильное и текущее выбранное дату – последний день месяца, они будут приняты в первый день следующего месяца
- Когда пользователь нажимает, и соответствующий день недели до текущего выделенного дня находится в предыдущем месяце, они будут приняты в соответствующий день предыдущего месяца
- Когда пользователь нажимает, и соответствующий день недели к текущему выбранному дню находится в следующем месяце, они будут приняты в соответствующий день в следующем месяце
- Когда пользователь нажимает страницу вверх и страницы вниз (для навигации к предыдущему и в следующем месяце соответственно) или Ctrl + Page Up и Ctrl + up (для навигации в похожий день в предыдущем году и в следующем году соответственно), если нет соответствующей даты Например, в течение нескольких месяцев с разными днями или прыжками, они будут доставлены в последний день месяца.
К счастью для нас дата-FNS заботится об этих краевых случаях, и нам не нужно беспокоиться о них. lekeydown
Слушатель событий прослушивает ключ нажимает, когда таблица сосредоточена. Важно отметить, что комбинация некоторых клавиш E.G Control + Page UP на определенных браузерах уже используется для ярлыков браузера и может перемещаться от страницы. Пользователь может понадобиться отключить ярлыки. В качестве альтернативы вы можете использовать клавишу Shift вместо управления. Добавим обработчик событий в элемент таблицы:
HandletableKeyPless
Метод будет обрабатывать ключ нажима, а затем вызывать функцию, которая выполняет соответствующие операции. Давайте добавим методы компонента, необходимые для обработки навигации на клавиатуре:
const setPreviousDay = () => { const previousDay = subDays(selectedDate, 1); setSelectedDate(previousDay); } const setNextDay = () => { const nextDay = addDays(selectedDate, 1); setSelectedDate(nextDay); } const setPreviousWeek = () => { const previousWeek = subWeeks(selectedDate, 1); setSelectedDate(previousWeek); } const setNextWeek = () => { const nextWeek = addWeeks(selectedDate, 1); setSelectedDate(nextWeek); } const setDatePreviousMonth = () => { setSelectedDate(subMonths(selectedDate, 1)); } const setDateNextMonth = () => { setSelectedDate(addMonths(selectedDate, 1)); } const setDatePreviousYear = () => { setSelectedDate(subYears(selectedDate, 1)); } const setDateNextYear = () => { setSelectedDate(addYears(selectedDate, 1)); } const setMonthStart = () => { setSelectedDate(startOfMonth(selectedDate)); } const setMonthEnd = () => { setSelectedDate(endOfMonth(selectedDate)); } const handleTableKeyPress = (e) => { const keyCode = e.keyCode; // Check if control key was pressed // const control = e.ctrlKey; // Use shift key to prevent browser shortcut conflicts const control = e.shiftKey; switch(keyCode) { case 13: //Enter handleSelectDate(format(selectedDate, "yyyy-MM-dd")); return; case 27: //Esc closeCalendar(); return; case 32: //Space handleSelectDate(format(selectedDate, "yyyy-MM-dd")); return; case 33: //Page Up control ? setDatePreviousYear() : setDatePreviousMonth(); return; case 34: //Page Down control ? setDateNextYear() : setDateNextMonth(); return; case 35: //End setMonthEnd(); return; case 36: //Home setMonthStart(); return; case 37: //Left setPreviousDay(); return; case 38: //Up setPreviousWeek(); return; case 39: //Right setNextDay(); return; case 40: //Down setNextWeek(); return; default: return; } } const handleDateSelection = (date) => { const dateString = format(date, "yyyy-MM-dd"); handleSelectDate(dateString); }
Наконец, добавьте следующие стили в App.csss
:
.calendar { width: 300px; display: flex; flex-direction: column; border: 2px solid black; padding: 2px; border-radius: 5px; } .title { display: flex; flex-direction: row; justify-content: space-between; font-size: 16px; background-color: #00b5ad; padding: 10px 0; border: 1px solid black; } .icons { display: flex; flex-direction: row; } .iconContainer { padding: 0 10px; cursor: pointer; } .month { padding: 0 15px; } .header { height: 30px; } .cell { border: 1px solid black; border-radius: 3px; height: 30px; font-family: arial, helvetica, sans-serif; font-size: 16px; } .cell:hover { background-color: #fc3; border-color: #800; } .cell.active { background-color: #fc3; border-color: #800; }
Вот и все!! Мы построили доступный компонент для выбора даты в реакции.
Следующие шаги
Возможно, вы заметили, что мы не следили за некоторыми лучшими практиками, такими как проверка опор. Вы можете добавить их сами. Календарный компонент довольно массивный и может быть разбит на более мелкие детские компоненты. Вы также можете играть с различными цветовыми комбинациями и различными соотношениями контрастности и посмотреть, как это влияет на приложение. Вы можете найти код для этой статьи на Github Отказ
Заключение
Это было посмотреть на то, как вы можете построить доступный сбор дат. Этими же принципами могут следовать при построении других типов компонентов в реакции. Есть гораздо большее соображения, которые можно добавить, что сделает любые инструменты, которые мы построим легко в использовании для всех.
Как разработчики, руководители проектов и предпринимателей, наша обязанность обеспечить, чтобы мы построим экосистему, которая приветствует всем. Я надеюсь, что вы и будете продолжать делать наши проекты, сайты и инструменты более доступными.
Полная видимость в производстве реагированных приложений
Отладка приложений React могут быть сложными, особенно когда пользователи испытывают проблемы, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния redux, автоматически затрагивают ошибки JavaScript, отслеживая медленные сетевые запросы и время загрузки компонентов, попробуйте logrocket.
Logrocket Похоже на DVR для веб-приложений, записывая буквально все, что происходит в вашем приложении React. Вместо того, чтобы угадать, почему проблемы происходят, вы можете совокупные и отчитываться о том, в каком состоянии ваше заявление произошло, когда произошла проблема. Logrocket также контролирует производительность вашего приложения, сообщая метрики, такие как нагрузка на клиент CPU, использование памяти клиента и многое другое.
Пакет Middleware Lognocket Redux добавляет дополнительный слой видимости в ваши сеансы пользователей. Logrocket Bogs все действия и состояние из ваших магазинов Redux.
Модернизация того, как вы отлаживаете свои реагистрационные приложения – Начните мониторинг бесплатно.
Пост Как построить Accessible Component Picker Date в React появился первым на Logocket blog Отказ
Оригинал: “https://dev.to/bnevilleoneill/how-to-build-an-accessible-date-picker-component-in-react-1k90”