Accessibility in Web
by Jacek Tomaszewski
import { useCallback, useState, useEffect, useRef } from "react"; | |
import { | |
LiteralToPrimitive, | |
UnpackNestedValue, | |
useFormContext | |
} from "react-hook-form"; | |
import { useDebouncedCallback } from "use-debounce"; | |
/** | |
* Returns state of a warning for the given form field. |
{ | |
"basics": { | |
"name": "Jack Tomaszewski", | |
"label": "Tech Lead | Full-stack Web Developer", | |
"picture": "https://media-exp1.licdn.com/dms/image/C4E03AQEWKJIgMsE1JQ/profile-displayphoto-shrink_800_800/0?e=1584576000&v=beta&t=MCq9NHtUH2MZehtvD5VIoFrRnVK4EgOWeAIWuEs4RXs", | |
"email": "jacek@jtom.me", | |
"phone": "", | |
"website": "https://jtom.me", | |
"summary": "**Looking for next project.** Full-stack Web Developer with 14 years' experience. • Developed, launched, and maintained dozens of web and mobile apps, both front-ends and back-ends. • Led small software teams. • Recruited, onboarded, mentored new developers. • Collaborated directly with product owners, UI designers, end-users, corporate clients.\n\nProficient in: Elixir, Javascript (TypeScript, React + Redux, Rx.js, Angular), Ruby on Rails, Docker, CI/CD configuration. Fan of functional and strongly typed languages; DDD; and a \"prefer a process than intuition\" approach to programming.\n\nSometimes a tech blogger ( https://medium.com/@j |
by Jacek Tomaszewski
// When SUBMIT action happens: | |
// - emit VALIDATE action, | |
// - validate the form, | |
// - and when validating the form finishes with success: | |
// - emit SUBMIT_START action. | |
const validateOnSubmitEpic = (action$, state$) => { | |
return action$.ofType(SUBMIT).switchMap(() => { | |
const validate$ = Observable.of({ type: VALIDATE }); | |
const onValidate$ = Observable.merge( | |
action$.ofType({ type: VALIDATE_SUCCESS }), |
// Fetch results when: | |
// - page is changed (immediately after): | |
// - "sort by" filter is changed (immediately after), | |
// - search query is changed (after 500 ms debounce), | |
// - filters are changed (after 300 ms debounce) | |
const refetchResultsEpic = action$ => { | |
return Observable.merge( | |
action$.ofType(CHANGE_QUERY).debounceTime(500), | |
action$.ofType(CHANGE_FILTERS).debounceTime(300), | |
action$.ofType(CHANGE_PAGE), |
import Observable from 'rxjs/observable'; | |
// Action creator function | |
function fetchArticles(params) { | |
return { type: FETCH_ARTICLES, params }; | |
} | |
// Epic | |
const fetchArticlesEpic = action$ => { | |
return action$ |
import { call, put, takeLatest } from "redux-saga/effects"; | |
// Action creator function | |
function fetchArticles(params) { | |
return { type: FETCH_ARTICLES, params }; | |
} | |
// Sagas | |
function* fetchArticlesSaga() { | |
yield takeLatest(FETCH_ARTICLES, triggerFetchArticles); |
// Action creator function | |
function fetchArticles(params = {}) { | |
return dispatch => { | |
dispatch({ type: 'FETCH_ARTICLES_START', params }); | |
ArticlesService.getArticles(params).then( | |
response => { | |
dispatch({ | |
type: 'FETCH_ARTICLES_SUCCESS', | |
data: response.data | |
}); |
/* eslint-disable no-await-in-loop */ | |
/* eslint-disable no-restricted-syntax */ | |
// eslint-disable-next-line import/no-extraneous-dependencies | |
const puppeteer = require('puppeteer'); | |
const { green, red, cyan, grey, bold } = require('chalk'); | |
const url = 'http://localhost:9001/iframe.html'; | |
function runAxe() { | |
return new Promise((resolve, reject) => |