From 7c4e79094f1b06631e454184cf85adb35d98ee30 Mon Sep 17 00:00:00 2001 From: Cameron Wardzala Date: Thu, 8 Sep 2022 14:38:15 -0400 Subject: [PATCH 1/5] Start conversion to TS --- package.json | 7 +- src/{App.js => App.tsx} | 0 src/{AppRoutes.jsx => AppRoutes.tsx} | 0 src/components/form/Checkbox.jsx | 65 ------- src/components/form/Checkbox.tsx | 92 +++++++++ src/components/form/{Input.jsx => Input.tsx} | 99 +++++++--- src/{index.js => index.tsx} | 3 - src/pages/{Home.jsx => Home.tsx} | 2 - src/pages/{Javascript.jsx => Javascript.tsx} | 35 +++- src/polyfills.js | 17 -- src/react-app-env.d.ts | 1 + src/types/global.d.ts | 1 + src/utils/{index.js => index.ts} | 0 src/utils/{sorts.js => sorts.ts} | 14 +- tsconfig.json | 22 +++ yarn.lock | 192 +++++++++++++++++-- 16 files changed, 413 insertions(+), 137 deletions(-) rename src/{App.js => App.tsx} (100%) rename src/{AppRoutes.jsx => AppRoutes.tsx} (100%) delete mode 100644 src/components/form/Checkbox.jsx create mode 100644 src/components/form/Checkbox.tsx rename src/components/form/{Input.jsx => Input.tsx} (72%) rename src/{index.js => index.tsx} (77%) rename src/pages/{Home.jsx => Home.tsx} (99%) rename src/pages/{Javascript.jsx => Javascript.tsx} (68%) delete mode 100644 src/polyfills.js create mode 100644 src/react-app-env.d.ts create mode 100644 src/types/global.d.ts rename src/utils/{index.js => index.ts} (100%) rename src/utils/{sorts.js => sorts.ts} (62%) create mode 100644 tsconfig.json diff --git a/package.json b/package.json index 9e046f4..23d1090 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,10 @@ "@reach/dialog": "^0.16.2", "@reach/menu-button": "^0.16.2", "@reach/visually-hidden": "^0.16.0", + "@types/jest": "^29.0.0", + "@types/node": "^18.7.16", + "@types/react": "^18.0.18", + "@types/react-dom": "^18.0.6", "classnames": "^2.3.1", "color": "^4.2.3", "formik": "^2.2.9", @@ -18,9 +22,10 @@ "react-dom": "^17.0.2", "react-icons": "^4.3.1", "react-router-dom": "^6.3.0", - "react-scripts": "5.0.0", + "react-scripts": "5.0.1", "react-select": "^5.2.2", "sass": "^1.50.0", + "typescript": "^4.8.2", "yup": "^0.32.11" }, "scripts": { diff --git a/src/App.js b/src/App.tsx similarity index 100% rename from src/App.js rename to src/App.tsx diff --git a/src/AppRoutes.jsx b/src/AppRoutes.tsx similarity index 100% rename from src/AppRoutes.jsx rename to src/AppRoutes.tsx diff --git a/src/components/form/Checkbox.jsx b/src/components/form/Checkbox.jsx deleted file mode 100644 index 604406a..0000000 --- a/src/components/form/Checkbox.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import classnames from 'classnames'; -import {useId} from '@reach/auto-id'; - -const Checkbox = ({ - checked = undefined, - label = '', - help = null, - placeholder = null, - id = null, - name = null, - error = false, - touched = false, - value = undefined, - required = false, - className = '', - inline = false, - disabled = false, - children = null, - onChange = () => {}, - onBlur = () => {} -}) => { - let handleChange = onChange; - let handleBlur = onBlur; - let autoId = useId(id); - - if (!id && name && value) { - id = `${name}_${value}`; - } - if (!id && !name) { - id = autoId; - } - - return ( -
- - {help} - {error && touched &&
- {error} -
} -
- ); -}; - -export default Checkbox; diff --git a/src/components/form/Checkbox.tsx b/src/components/form/Checkbox.tsx new file mode 100644 index 0000000..09a3f03 --- /dev/null +++ b/src/components/form/Checkbox.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import classnames from 'classnames'; +import { useId } from '@reach/auto-id'; + +interface CheckboxProps { + checked?: React.InputHTMLAttributes['checked']; + children?: React.ReactNode[]; + className?: string; + disabled?: React.InputHTMLAttributes['disabled']; + error?: string; + help?: React.ReactNode; + id: React.InputHTMLAttributes['id']; + inline?: boolean; + label?: React.ReactNode; + name?: React.InputHTMLAttributes['name']; + placeholder?: React.InputHTMLAttributes['placeholder']; + required?: boolean; + touched?: boolean; + value?: React.InputHTMLAttributes['value']; + onBlur?: (e: React.FocusEvent) => void; + onChange?: (e: React.ChangeEvent) => void; +} + +const Checkbox: React.FC = ({ + checked = undefined, + children = undefined, + className = '', + disabled = false, + error = false, + help = undefined, + id = undefined, + inline = false, + label = '', + name = undefined, + placeholder = undefined, + required = false, + touched = false, + value = undefined, + onBlur = () => {}, + onChange = () => {} +}) => { + let handleChange = onChange; + let handleBlur = onBlur; + let autoId = useId(id); + + if (!id && name && value) { + id = `${name}_${value}`; + } + if (!id && !name) { + id = autoId; + } + + return ( +
+ + {' '} + {help} + {error && touched && ( +
+ {error} +
+ )} +
+ ); +}; + +export default Checkbox; diff --git a/src/components/form/Input.jsx b/src/components/form/Input.tsx similarity index 72% rename from src/components/form/Input.jsx rename to src/components/form/Input.tsx index 24af9d1..c6f907e 100644 --- a/src/components/form/Input.jsx +++ b/src/components/form/Input.tsx @@ -2,38 +2,89 @@ import React from 'react'; import classnames from 'classnames'; import { useId } from '@reach/auto-id'; -const Input = ({ - label = '', - labelHelp = null, - placeholder = null, - id = undefined, - name = null, - value = undefined, - defaultValue = undefined, - required = false, +interface InputProps { + append?: React.ReactNode; + autoComplete?: React.InputHTMLAttributes['autoComplete']; + children?: React.ReactNode; + className?: string; + collapse?: boolean; + defaultValue?: React.InputHTMLAttributes['value']; + disabled?: boolean; + enterkeyhint?: string; + error?: string; + errorStyle?: object; + flex?: boolean; + ghost?: boolean; + guidance?: React.ReactNode; + help?: React.ReactNode; + hidden?: boolean; + hideLabel?: boolean; + id: string; + innerClassName?: React.HTMLAttributes['className']; + inputClass?: string; + inputStyles?: object; + isHistoryInput?: boolean; + label?: string; + labelClass?: string; + labelHelp?: React.ReactNode; + labelledBy?: string; + max?: number; + maxLength?: number; + min?: number; + name?: string; + onBlur?: (e: React.FocusEvent) => void; + onChange?: (e: React.ChangeEvent) => void; + onFocus?: React.FocusEventHandler; + onKeyDown?: (e: React.KeyboardEvent) => void; + onKeyPress?: (e: React.KeyboardEvent) => void; + onKeyUp?: (e: React.KeyboardEvent) => void; + placeholder?: React.InputHTMLAttributes['placeholder']; + prepend?: React.ReactNode; + prependLabel?: boolean; + readOnly?: boolean; + required?: boolean; + restricted?: string[]; + showRequired?: boolean; + small?: boolean; + step?: React.InputHTMLAttributes['step']; + touched?: boolean; + type?: string; + value: React.InputHTMLAttributes['value']; + warning?: string | false; +} + +const Input: React.FC = ({ + append = null, + autoComplete = undefined, + children = undefined, className = '', - type = 'text', collapse = false, + defaultValue = undefined, + disabled = false, + error = null, + flex = false, + ghost = false, + help = null, + hidden = false, hideLabel = false, + id = undefined, inputStyles = {}, + label = '', + labelClass = null, + labelHelp = null, + name = null, + placeholder = undefined, + prepend = null, + prependLabel = false, + readOnly = false, + required = false, restricted = [], showRequired = false, - prependLabel = false, - autoComplete = null, - hidden = false, - children = false, - prepend = null, - append = null, small = false, - disabled = false, - readOnly = false, - labelClass = null, - help = null, - flex = false, - ghost = false, - error = null, - touched = false, step = undefined, + touched = false, + type = 'text', + value = undefined, onBlur = () => {}, onChange = () => {}, onFocus = () => {}, diff --git a/src/index.js b/src/index.tsx similarity index 77% rename from src/index.js rename to src/index.tsx index 715bb9d..c16c85d 100644 --- a/src/index.js +++ b/src/index.tsx @@ -1,7 +1,4 @@ -import 'react-app-polyfill/ie9'; import 'react-app-polyfill/stable'; -import './polyfills'; -import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import './scss/styles.scss'; diff --git a/src/pages/Home.jsx b/src/pages/Home.tsx similarity index 99% rename from src/pages/Home.jsx rename to src/pages/Home.tsx index 54d5406..0ddc55e 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - const HomePage = () => ( <>
diff --git a/src/pages/Javascript.jsx b/src/pages/Javascript.tsx similarity index 68% rename from src/pages/Javascript.jsx rename to src/pages/Javascript.tsx index b922045..3bc9d37 100644 --- a/src/pages/Javascript.jsx +++ b/src/pages/Javascript.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import Code from '../components/Code'; const JSPage = () => ( @@ -58,7 +57,14 @@ const JSPage = () => ( Function to sort an array ascending based on passed values. This is to be used with the{' '} Array.sort method.

- asc(x,y))`} /> + asc(a.key, b.key)) +arrayOfArrays.sort((a,b) => asc(a[1], b[1]))`} + />

desc @@ -67,7 +73,30 @@ const JSPage = () => ( Function to sort an array descending based on passed values. This is to be used with the{' '} Array.sort method.

- desc(x,y))`} /> + desc(a.key, b.key)) +arrayOfArrays.sort((a,b) => desc(a[1], b[1]))`} + /> + +

+ sorted +

+

+ Use any sort function asc, or desc and return a new array. Great when working + with immutable data. +

+ asc(a.key, b.key)) +const newArrayOfArrays = sorted(arrayOfArrays, (a,b) => desc(a[1], b[1]))`} + /> ); diff --git a/src/polyfills.js b/src/polyfills.js deleted file mode 100644 index fa50c7d..0000000 --- a/src/polyfills.js +++ /dev/null @@ -1,17 +0,0 @@ -/*eslint-disable*/ -if (!String.prototype.includes) { - Object.defineProperty(String.prototype, 'includes', { - value: function (search, start) { - if (typeof start !== 'number') { - start = 0 - } - - if (start + search.length > this.length) { - return false - } else { - return this.indexOf(search, start) !== -1 - } - } - }); -} -/*eslint-enable*/ \ No newline at end of file diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1 @@ + diff --git a/src/utils/index.js b/src/utils/index.ts similarity index 100% rename from src/utils/index.js rename to src/utils/index.ts diff --git a/src/utils/sorts.js b/src/utils/sorts.ts similarity index 62% rename from src/utils/sorts.js rename to src/utils/sorts.ts index b9ba740..6f77d2a 100644 --- a/src/utils/sorts.js +++ b/src/utils/sorts.ts @@ -1,3 +1,7 @@ +type Sortable = string | number | boolean; +interface SortFunction { + (a: T, b:T): -1|0|1 +} /** * Sort Ascending * [].sort((x, y) => asc(x, y)); @@ -5,7 +9,7 @@ * @param a * @param b */ -export const asc = (a, b) => { +export const asc: SortFunction = (a : Sortable, b : Sortable) => { let at = typeof a === 'string' ? a.toLowerCase() : a; let bt = typeof b === 'string' ? b.toLowerCase() : b; if (at < bt) { @@ -24,7 +28,7 @@ export const asc = (a, b) => { * @param a * @param b */ -export const desc = (a, b) => { +export const desc: SortFunction = (a : Sortable, b : Sortable) => { let at = typeof a === 'string' ? a.toLowerCase() : a; let bt = typeof b === 'string' ? b.toLowerCase() : b; if (at > bt) { @@ -36,6 +40,10 @@ export const desc = (a, b) => { } }; -const sorts = { asc, desc }; +export const sorted = (array: T[], sortCallback: SortFunction) => { + return [...array || []].sort(sortCallback); +}; + +const sorts = { asc, desc, sorted }; export default sorts; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..18b1abe --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "noImplicitAny": false, + "noFallthroughCasesInSwitch": true, + "downlevelIteration": true + }, + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index 45c282e..e93dd89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1735,6 +1735,13 @@ "@types/node" "*" jest-mock "^27.5.1" +"@jest/expect-utils@^29.0.2": + version "29.0.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.0.2.tgz#00dfcb9e6fe99160c326ba39f7734b984543dea8" + integrity sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw== + dependencies: + jest-get-type "^29.0.0" + "@jest/fake-timers@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" @@ -1787,6 +1794,13 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + "@jest/source-map@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" @@ -1848,6 +1862,18 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^29.0.2": + version "29.0.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.0.2.tgz#5a5391fa7f7f41bf4b201d6d2da30e874f95b6c1" + integrity sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/resolve-uri@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" @@ -2047,6 +2073,11 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.1.tgz#782fa5da44c4f38ae9fd38e9184b54e451936118" integrity sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg== +"@sinclair/typebox@^0.24.1": + version "0.24.38" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.38.tgz#7f68d9c5775c4c2cec0524b3b990263dd009c968" + integrity sha512-IbYB6vdhLFmzGEyXXEdFAJKyq7S4/RsivkgxNzs/LzwYuUJHmeNQ0cHkjG/Yqm6VgUzzZDLMZAf0XgeeaZAocA== + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -2361,6 +2392,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.0.0.tgz#bc66835bf6b09d6a47e22c21d7f5b82692e60e72" + integrity sha512-X6Zjz3WO4cT39Gkl0lZ2baFRaEMqJl5NC1OjElkwtNzAlbkr2K/WJXkBkH5VP0zx4Hgsd2TZYdOEfvp2Dxia+Q== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" @@ -2391,6 +2430,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2" integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA== +"@types/node@^18.7.16": + version "18.7.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.16.tgz#0eb3cce1e37c79619943d2fd903919fc30850601" + integrity sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -2421,6 +2465,13 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/react-dom@^18.0.6": + version "18.0.6" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1" + integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA== + dependencies: + "@types/react" "*" + "@types/react-transition-group@^4.4.0": version "4.4.4" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" @@ -2437,6 +2488,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.0.18": + version "18.0.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.18.tgz#9f16f33d57bc5d9dca848d12c3572110ff9429ac" + integrity sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -2505,6 +2565,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.12.tgz#0745ff3e4872b4ace98616d4b7e37ccbd75f9526" + integrity sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^5.5.0": version "5.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" @@ -4198,6 +4265,11 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.0.0.tgz#bae49972ef3933556bcb0800b72e8579d19d9e4f" + integrity sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4552,10 +4624,10 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-react-app@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.0.tgz#0fa96d5ec1dfb99c029b1554362ab3fa1c3757df" - integrity sha512-xyymoxtIt1EOsSaGag+/jmcywRuieQoA2JbPCjnw9HukFj9/97aGPoZVFioaotzk1K5Qt9sHO5EutZbkrAXS0g== +eslint-config-react-app@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz#73ba3929978001c5c86274c017ea57eb5fa644b4" + integrity sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA== dependencies: "@babel/core" "^7.16.0" "@babel/eslint-parser" "^7.16.3" @@ -4860,6 +4932,17 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +expect@^29.0.0: + version "29.0.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.0.2.tgz#22c7132400f60444b427211f1d6bb604a9ab2420" + integrity sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw== + dependencies: + "@jest/expect-utils" "^29.0.2" + jest-get-type "^29.0.0" + jest-matcher-utils "^29.0.2" + jest-message-util "^29.0.2" + jest-util "^29.0.2" + express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -6146,6 +6229,16 @@ jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-diff@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.0.2.tgz#1a99419efda66f9ee72f91e580e774df95de5ddc" + integrity sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.0.0" + jest-get-type "^29.0.0" + pretty-format "^29.0.2" + jest-docblock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" @@ -6194,6 +6287,11 @@ jest-get-type@^27.5.1: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== +jest-get-type@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.0.0.tgz#843f6c50a1b778f7325df1129a0fd7aa713aef80" + integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw== + jest-haste-map@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" @@ -6255,6 +6353,16 @@ jest-matcher-utils@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-matcher-utils@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz#0ffdcaec340a9810caee6c73ff90fb029b446e10" + integrity sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.0.2" + jest-get-type "^29.0.0" + pretty-format "^29.0.2" + jest-message-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" @@ -6270,6 +6378,21 @@ jest-message-util@^27.5.1: slash "^3.0.0" stack-utils "^2.0.3" +jest-message-util@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.0.2.tgz#b2781dfb6a2d1c63830d9684c5148ae3155c6154" + integrity sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.0.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.0.2" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" @@ -6416,6 +6539,18 @@ jest-util@^27.5.1: graceful-fs "^4.2.9" picomatch "^2.2.3" +jest-util@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.0.2.tgz#c75c5cab7f3b410782f9570a60c5558b5dfb6e3a" + integrity sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ== + dependencies: + "@jest/types" "^29.0.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" @@ -8096,6 +8231,15 @@ pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^29.0.0, pretty-format@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.0.2.tgz#7f7666a7bf05ba2bcacde61be81c6db64f6f3be6" + integrity sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -8228,10 +8372,10 @@ react-clientside-effect@^1.2.5: dependencies: "@babel/runtime" "^7.12.13" -react-dev-utils@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.0.tgz#4eab12cdb95692a077616770b5988f0adf806526" - integrity sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ== +react-dev-utils@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" + integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== dependencies: "@babel/code-frame" "^7.16.0" address "^1.1.2" @@ -8252,7 +8396,7 @@ react-dev-utils@^12.0.0: open "^8.4.0" pkg-up "^3.1.0" prompts "^2.4.2" - react-error-overlay "^6.0.10" + react-error-overlay "^6.0.11" recursive-readdir "^2.2.2" shell-quote "^1.7.3" strip-ansi "^6.0.1" @@ -8267,10 +8411,10 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-error-overlay@^6.0.10: - version "6.0.10" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" - integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA== +react-error-overlay@^6.0.11: + version "6.0.11" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" + integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== react-fast-compare@^2.0.1: version "2.0.4" @@ -8304,6 +8448,11 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-refresh@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" @@ -8343,10 +8492,10 @@ react-router@6.3.0: dependencies: history "^5.2.0" -react-scripts@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.0.tgz#6547a6d7f8b64364ef95273767466cc577cb4b60" - integrity sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg== +react-scripts@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" + integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ== dependencies: "@babel/core" "^7.16.0" "@pmmmwh/react-refresh-webpack-plugin" "^0.5.3" @@ -8364,7 +8513,7 @@ react-scripts@5.0.0: dotenv "^10.0.0" dotenv-expand "^5.1.0" eslint "^8.3.0" - eslint-config-react-app "^7.0.0" + eslint-config-react-app "^7.0.1" eslint-webpack-plugin "^3.1.1" file-loader "^6.2.0" fs-extra "^10.0.0" @@ -8381,7 +8530,7 @@ react-scripts@5.0.0: postcss-preset-env "^7.0.1" prompts "^2.4.2" react-app-polyfill "^3.0.0" - react-dev-utils "^12.0.0" + react-dev-utils "^12.0.1" react-refresh "^0.11.0" resolve "^1.20.0" resolve-url-loader "^4.0.0" @@ -9650,6 +9799,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript@^4.8.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" + integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" From 64ace36c8096d65966a87b01af5e7ec838c2edcf Mon Sep 17 00:00:00 2001 From: Cameron Wardzala Date: Thu, 8 Sep 2022 15:56:27 -0400 Subject: [PATCH 2/5] Migrate ProgressBar to TS --- .../{ProgressBar.jsx => ProgressBar.tsx} | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) rename src/components/{ProgressBar.jsx => ProgressBar.tsx} (65%) diff --git a/src/components/ProgressBar.jsx b/src/components/ProgressBar.tsx similarity index 65% rename from src/components/ProgressBar.jsx rename to src/components/ProgressBar.tsx index ff839b3..e4e2eaa 100644 --- a/src/components/ProgressBar.jsx +++ b/src/components/ProgressBar.tsx @@ -1,8 +1,15 @@ import VisuallyHidden from '@reach/visually-hidden'; import classNames from 'classnames'; -import PropTypes from 'prop-types'; -const ProgressBar = ({ value, label, max, className = '', barClassName = '' }) => { +interface ProgressBarProps { + value: number; + label: string; + max: number; + className?: string; + barClassName?: string; +} + +const ProgressBar: React.FC = ({ value, label, max, className = '', barClassName = '' }) => { const hasValue = typeof value === 'number' && value >= 0; const progress = hasValue ? Math.ceil((value / max) * 100) : undefined; @@ -17,8 +24,8 @@ const ProgressBar = ({ value, label, max, className = '', barClassName = '' }) = role="progressbar" aria-label={label} aria-valuenow={progress} - aria-valuemin="0" - aria-valuemax="100" + aria-valuemin={0} + aria-valuemax={100} style={!!progress ? { width: `${progress}%` } : {}} > {progress}% Complete @@ -27,12 +34,4 @@ const ProgressBar = ({ value, label, max, className = '', barClassName = '' }) = ); }; -ProgressBar.propTypes = { - label: PropTypes.string.isRequired, - max: PropTypes.number.isRequired, - value: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), - className: PropTypes.string, - barClassName: PropTypes.string -}; - export default ProgressBar; From 25bf696114990dceee377027359992cf1baa5b22 Mon Sep 17 00:00:00 2001 From: Cameron Wardzala Date: Thu, 8 Sep 2022 16:04:53 -0400 Subject: [PATCH 3/5] Update StatusButton to TS --- .../{StatusButton.jsx => StatusButton.tsx} | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) rename src/components/{StatusButton.jsx => StatusButton.tsx} (72%) diff --git a/src/components/StatusButton.jsx b/src/components/StatusButton.tsx similarity index 72% rename from src/components/StatusButton.jsx rename to src/components/StatusButton.tsx index 475c00b..737a3d3 100644 --- a/src/components/StatusButton.jsx +++ b/src/components/StatusButton.tsx @@ -1,14 +1,27 @@ -import React from 'react'; +import React, { MouseEventHandler } from 'react'; import classnames from 'classnames'; import { FiCheck } from 'react-icons/fi'; -const StatusButton = ({ +interface StatusButtonProps { + className?: string; + successState?: string; + disabled?: boolean; + label?: string; + successLabel?: string; + onClick?: MouseEventHandler; + type?: React.ButtonHTMLAttributes['type']; + defaultClass?: string; + successClass?: string; + dangerClass?: string; +} + +const StatusButton: React.FC = ({ className = '', successState = null, disabled = false, label = 'Submit', successLabel = 'Success', - onClick = null, + onClick = () => {}, type = 'submit', defaultClass = 'btn-primary', successClass = 'btn-success', From 051310e98e3dcf49b986c40db53eed89d6db6669 Mon Sep 17 00:00:00 2001 From: Cameron Wardzala Date: Fri, 30 Sep 2022 10:34:35 -0400 Subject: [PATCH 4/5] =?UTF-8?q?Convert=20lots=20of=20things,=20should=20ha?= =?UTF-8?q?ve=20broken=20this=20up=20=F0=9F=A4=A6=E2=80=8D=E2=99=82?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 7 +- src/components/Breadcrumbs.jsx | 31 ------ src/components/Breadcrumbs.tsx | 36 +++++++ src/components/{Code.jsx => Code.tsx} | 6 +- .../{ConfirmButton.jsx => ConfirmButton.tsx} | 33 +++--- ...FormikState.jsx => DisplayFormikState.tsx} | 3 +- src/components/FormattedCurrency.jsx | 11 -- src/components/FormattedCurrency.tsx | 9 ++ src/components/FormattedPlural.jsx | 11 -- src/components/FormattedPlural.tsx | 9 ++ src/components/Loading.jsx | 24 ----- src/components/Loading.tsx | 23 ++++ src/components/{Modal.jsx => Modal.tsx} | 28 +++-- src/components/Pagination.jsx | 72 ------------- src/components/Pagination.tsx | 101 ++++++++++++++++++ .../{InputWrapper.jsx => InputWrapper.tsx} | 30 ++++-- src/hooks/useTimeout.js | 6 +- src/pages/Accessibility.jsx | 7 +- ...readcrumbsPage.jsx => BreadcrumbsPage.tsx} | 0 19 files changed, 246 insertions(+), 201 deletions(-) delete mode 100644 src/components/Breadcrumbs.jsx create mode 100644 src/components/Breadcrumbs.tsx rename src/components/{Code.jsx => Code.tsx} (92%) rename src/components/{ConfirmButton.jsx => ConfirmButton.tsx} (83%) rename src/components/{DisplayFormikState.jsx => DisplayFormikState.tsx} (76%) delete mode 100644 src/components/FormattedCurrency.jsx create mode 100644 src/components/FormattedCurrency.tsx delete mode 100644 src/components/FormattedPlural.jsx create mode 100644 src/components/FormattedPlural.tsx delete mode 100644 src/components/Loading.jsx create mode 100644 src/components/Loading.tsx rename src/components/{Modal.jsx => Modal.tsx} (69%) delete mode 100644 src/components/Pagination.jsx create mode 100644 src/components/Pagination.tsx rename src/components/form/{InputWrapper.jsx => InputWrapper.tsx} (78%) rename src/pages/Components/{BreadcrumbsPage.jsx => BreadcrumbsPage.tsx} (100%) diff --git a/src/App.tsx b/src/App.tsx index 2a86717..aa1af31 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -148,7 +148,7 @@ const App = () => { to={`/${item.path}`} > {item.icon} - + {item.path.split('-').join(' ')} @@ -167,10 +167,7 @@ const App = () => { target="_blank" rel="noopener noreferrer" > - {' '} - - Github - + Github diff --git a/src/components/Breadcrumbs.jsx b/src/components/Breadcrumbs.jsx deleted file mode 100644 index 4a13345..0000000 --- a/src/components/Breadcrumbs.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; - -export const Breadcrumbs = ({ children, className }) => { - return ( - - ); -}; - -Breadcrumbs.propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string -}; - -export const BreadcrumbItem = ({ children = null, current = false, as: Comp = 'a', ...props }) => { - return ( -
  • - {current && children} - {!current && {children}} -
  • - ); -}; - -BreadcrumbItem.propTypes = { - children: PropTypes.node.isRequired, - current: PropTypes.bool, - as: PropTypes.elementType -}; diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx new file mode 100644 index 0000000..45b18ef --- /dev/null +++ b/src/components/Breadcrumbs.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import classnames from 'classnames'; + +interface BreadcrumbsProps extends React.PropsWithChildren { + className?: string; +} + +export const Breadcrumbs: React.FC = ({ children, className }) => { + return ( + + ); +}; + +interface BreadcrumbItemProps extends React.PropsWithChildren { + current?: boolean; + as?: React.ElementType; + to?: string; + href?: string; +} + +export const BreadcrumbItem: React.FC = ({ + children = null, + current = false, + as = 'a', + ...props +}) => { + const Comp = as; + return ( +
  • + {current && children} + {!current && {children}} +
  • + ); +}; diff --git a/src/components/Code.jsx b/src/components/Code.tsx similarity index 92% rename from src/components/Code.jsx rename to src/components/Code.tsx index 8f648ff..a435b03 100644 --- a/src/components/Code.jsx +++ b/src/components/Code.tsx @@ -14,12 +14,14 @@ hljs.registerLanguage('json', js_n); hljs.registerLanguage('scss', scss); const Code = ({ code, lang, className = '' }) => { - const el = useRef(); + const el = useRef(null); + useEffect(() => { - if (code) { + if (code && el.current) { hljs.highlightElement(el.current); } }, [code]); + return (
    diff --git a/src/components/ConfirmButton.jsx b/src/components/ConfirmButton.tsx
    similarity index 83%
    rename from src/components/ConfirmButton.jsx
    rename to src/components/ConfirmButton.tsx
    index b198e65..fe8d9da 100644
    --- a/src/components/ConfirmButton.jsx
    +++ b/src/components/ConfirmButton.tsx
    @@ -1,5 +1,4 @@
     import React, { useState } from 'react';
    -import PropTypes from 'prop-types';
     import classnames from 'classnames';
     import { FiCheck } from 'react-icons/fi';
     import useTimeoutFn from '../hooks/useTimeout';
    @@ -7,10 +6,23 @@ import useTimeoutFn from '../hooks/useTimeout';
     const CONFIRM_STATES = {
         CONFIRM: 'confirm',
         DONE: 'done',
    -    READY: null
    +    READY: 'ready'
     };
     
    -const ConfirmButton = ({
    +interface ConfirmButtonProps {
    +    className?: string;
    +    disabled?: boolean;
    +    label?: string;
    +    confirmLabel?: string;
    +    successLabel?: string;
    +    defaultClass?: string;
    +    successClass?: string;
    +    confirmClass?: string;
    +    timeout?: number | false;
    +    onConfirm?: () => void;
    +}
    +
    +const ConfirmButton: React.FC = ({
         className = '',
         disabled = false,
     
    @@ -18,14 +30,13 @@ const ConfirmButton = ({
         confirmLabel = 'Are you sure?',
         successLabel = 'Thanks!',
     
    -    type = 'submit',
         defaultClass = 'btn-primary',
         successClass = 'btn-success',
         confirmClass = 'btn-danger',
         timeout = 3000,
         onConfirm = () => {}
     }) => {
    -    const [buttonState, setButtonState] = useState(null);
    +    const [buttonState, setButtonState] = useState('ready');
     
         const isConfirm = [CONFIRM_STATES.CONFIRM, CONFIRM_STATES.DONE].includes(buttonState);
     
    @@ -80,16 +91,4 @@ const ConfirmButton = ({
         );
     };
     
    -ConfirmButton.propTypes = {
    -    label: PropTypes.string,
    -    confirmLabel: PropTypes.string,
    -    successLabel: PropTypes.string,
    -
    -    defaultClass: PropTypes.string,
    -    confirmClass: PropTypes.string,
    -    successClass: PropTypes.string,
    -
    -    onConfirm: PropTypes.func.isRequired
    -};
    -
     export default ConfirmButton;
    diff --git a/src/components/DisplayFormikState.jsx b/src/components/DisplayFormikState.tsx
    similarity index 76%
    rename from src/components/DisplayFormikState.jsx
    rename to src/components/DisplayFormikState.tsx
    index dc02ae5..4984ecb 100644
    --- a/src/components/DisplayFormikState.jsx
    +++ b/src/components/DisplayFormikState.tsx
    @@ -1,6 +1,7 @@
     import React from 'react';
     import Code from './Code';
    -const DisplayFormikState = (props) => (
    +
    +const DisplayFormikState = (props: React.PropsWithChildren) => (
         
    diff --git a/src/components/FormattedCurrency.jsx b/src/components/FormattedCurrency.jsx deleted file mode 100644 index 7770139..0000000 --- a/src/components/FormattedCurrency.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import PropTypes from 'prop-types'; - -const FormattedCurrency = ({ value = null, currency = 'USD' }) => - new window.Intl.NumberFormat('en-US', { style: 'currency', currency }).format(value); - -FormattedCurrency.propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - currency: PropTypes.string -}; - -export default FormattedCurrency; diff --git a/src/components/FormattedCurrency.tsx b/src/components/FormattedCurrency.tsx new file mode 100644 index 0000000..9643be1 --- /dev/null +++ b/src/components/FormattedCurrency.tsx @@ -0,0 +1,9 @@ +interface FormattedCurrencyProps { + value: number; + currency?: string; +} + +const FormattedCurrency = ({ value = 0, currency = 'USD' }: FormattedCurrencyProps) => + new window.Intl.NumberFormat('en-US', { style: 'currency', currency }).format(value); + +export default FormattedCurrency; diff --git a/src/components/FormattedPlural.jsx b/src/components/FormattedPlural.jsx deleted file mode 100644 index 476ff05..0000000 --- a/src/components/FormattedPlural.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import PropTypes from 'prop-types'; - -const FormattedPlural = ({ value = 1, one = '', many = '' }) => (value === 1 ? one : many); - -FormattedPlural.propTypes = { - value: PropTypes.number.isRequired, - one: PropTypes.string.isRequired, - many: PropTypes.string.isRequired -}; - -export default FormattedPlural; diff --git a/src/components/FormattedPlural.tsx b/src/components/FormattedPlural.tsx new file mode 100644 index 0000000..33f5f77 --- /dev/null +++ b/src/components/FormattedPlural.tsx @@ -0,0 +1,9 @@ +interface FormattedPluralProps { + value: number; + one: string; + many: string; +} + +const FormattedPlural = ({ value = 1, one = '', many = '' }: FormattedPluralProps) => (value === 1 ? one : many); + +export default FormattedPlural; diff --git a/src/components/Loading.jsx b/src/components/Loading.jsx deleted file mode 100644 index 6774c1a..0000000 --- a/src/components/Loading.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; - -const Loading = ({ inline = false, invert = false }) => ( - - - -); - -Loading.propTypes = { - inline: PropTypes.bool, - invert: PropTypes.bool -}; - -export default Loading; diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx new file mode 100644 index 0000000..67a81f3 --- /dev/null +++ b/src/components/Loading.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import classNames from 'classnames'; + +interface LoadingProps { + inline?: boolean; + invert?: false; +} + +const Loading: React.FC = ({ inline = false, invert = false }) => ( + + + +); + +export default Loading; diff --git a/src/components/Modal.jsx b/src/components/Modal.tsx similarity index 69% rename from src/components/Modal.jsx rename to src/components/Modal.tsx index ff7df1c..4587ab1 100644 --- a/src/components/Modal.jsx +++ b/src/components/Modal.tsx @@ -1,10 +1,20 @@ import React from 'react'; -import PropTypes from 'prop-types'; import classnames from 'classnames'; import { DialogOverlay, DialogContent } from '@reach/dialog'; import VisuallyHidden from '@reach/visually-hidden'; -const Modal = ({ +interface ModalProps { + visible: boolean; + label: string; + onClose: () => void; + disableOverlayClick?: boolean; + children: React.ReactNode; + showClose?: boolean; + innerClassName?: string; + center?: boolean; +} + +const Modal: React.FC = ({ center = false, children = [], disableOverlayClick = false, @@ -26,9 +36,7 @@ const Modal = ({ {showClose && ( )} {children} @@ -37,14 +45,4 @@ const Modal = ({ ); }; -Modal.propTypes = { - visible: PropTypes.bool.isRequired, - label: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - children: PropTypes.node.isRequired, - showClose: PropTypes.bool, - innerClassName: PropTypes.string, - center: PropTypes.bool -}; - export default Modal; diff --git a/src/components/Pagination.jsx b/src/components/Pagination.jsx deleted file mode 100644 index 40b5eb6..0000000 --- a/src/components/Pagination.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; - -const Pagination = ({ - as: Comp = 'a', - toProp = 'href', - numPages = 1, - currentPage = 1, - perPage = 5, - pagesToShow = null, - showJumpFirst = false, - showJumpLast = false, - pathName = '', - className = '' -}) => { - - const isFirst = currentPage === 1 - const isLast = currentPage === numPages - const prevPage = currentPage - 1 === 1 ? pathName : `${pathName}/${(currentPage - 1).toString()}`; - const nextPage = `${pathName}/${(currentPage + 1).toString()}`; - - let half = Math.ceil((pagesToShow || perPage) / 2); - - let cp = currentPage; - - let begin = cp < half ? 0 : cp - half; - let end = cp < half ? perPage : cp + (half - 1); - - const allPages = []; - for (var i = 0; i < numPages; i++) { - allPages.push(i + 1); - } - - return ( -
      - {!isFirst &&<> - {showJumpFirst &&
    • First
    • } -
    • Previous
    • - } - {allPages.slice(begin, end).map((i, p) => { - let current = (i) === currentPage; - return ( -
    • - {i} -
    • - ); - })} - {!isLast && <> -
    • Next
    • - {showJumpLast &&
    • Last
    • } - } -
    - ); -}; - -Pagination.propTypes = { - as: PropTypes.elementType, - toProp: PropTypes.string, - numPages: PropTypes.number.isRequired, - currentPage: PropTypes.number.isRequired, - perPage: PropTypes.number.isRequired, - pagesToShow: PropTypes.number, - showJumpFirst: PropTypes.bool, - showJumpLast: PropTypes.bool, - pathName: PropTypes.string, - className: PropTypes.string -}; - -export default Pagination; diff --git a/src/components/Pagination.tsx b/src/components/Pagination.tsx new file mode 100644 index 0000000..f0f51a1 --- /dev/null +++ b/src/components/Pagination.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import classnames from 'classnames'; + +interface PaginationProps { + as: React.ElementType; + toProp?: string; + numPages?: number; + currentPage?: number; + perPage?: number; + pagesToShow?: number; + showJumpFirst?: boolean; + showJumpLast?: boolean; + pathName?: string; + className?: string; +} + +const Pagination: React.FC = ({ + as = 'a', + toProp = 'href', + numPages = 1, + currentPage = 1, + perPage = 5, + pagesToShow = undefined, + showJumpFirst = false, + showJumpLast = false, + pathName = '', + className = '' +}) => { + const Comp = as; + const isFirst = currentPage === 1; + const isLast = currentPage === numPages; + const prevPage = currentPage - 1 === 1 ? pathName : `${pathName}/${(currentPage - 1).toString()}`; + const nextPage = `${pathName}/${(currentPage + 1).toString()}`; + + let half = Math.ceil((pagesToShow || perPage) / 2); + + let cp = currentPage; + + let begin = cp < half ? 0 : cp - half; + let end = cp < half ? perPage : cp + (half - 1); + + const allPages = Array.from({ length: numPages }).map((x, i) => i + 1); + + return ( +
      + {!isFirst && ( + <> + {showJumpFirst && ( +
    • + + First + +
    • + )} +
    • + + Previous + +
    • + + )} + {allPages.slice(begin, end).map((i, p) => { + let current = i === currentPage; + return ( +
    • + + {i} + +
    • + ); + })} + {!isLast && ( + <> +
    • + + Next + +
    • + {showJumpLast && ( +
    • + + Last + +
    • + )} + + )} +
    + ); +}; + +export default Pagination; diff --git a/src/components/form/InputWrapper.jsx b/src/components/form/InputWrapper.tsx similarity index 78% rename from src/components/form/InputWrapper.jsx rename to src/components/form/InputWrapper.tsx index 74fcf56..ed60065 100644 --- a/src/components/form/InputWrapper.jsx +++ b/src/components/form/InputWrapper.tsx @@ -1,10 +1,28 @@ import React from 'react'; import classnames from 'classnames'; -const InputWrapper = ({ +interface InputWrapperProps { + label?: React.ReactNode; + labelHelp?: React.ReactNode; + id?: React.InputHTMLAttributes['id']; + required?: React.InputHTMLAttributes['required']; + showRequired?: boolean; + prependLabel?: boolean; + hidden?: boolean; + collapse?: boolean; + small?: boolean; + className?: string; + error?: string; + touched?: boolean; + prepend?: boolean; + append?: boolean; + children?: React.ReactNode; +} + +const InputWrapper: React.FC = ({ label = '', - labelHelp = null, - id = null, + labelHelp = undefined, + id = undefined, required = false, showRequired = false, prependLabel = false, @@ -14,9 +32,9 @@ const InputWrapper = ({ className = '', error = false, touched = false, - prepend = null, - append = null, - children = null + prepend = undefined, + append = undefined, + children = undefined }) => { let isRequired = required || showRequired; diff --git a/src/hooks/useTimeout.js b/src/hooks/useTimeout.js index ee8d3db..fad3c15 100644 --- a/src/hooks/useTimeout.js +++ b/src/hooks/useTimeout.js @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef } from 'react'; -export default function useTimeoutFn(fn, ms = 0) { +const useTimeoutFn = (fn: () => void, ms: number | false = 0): array => { const ready = useRef(false); const timeout = useRef(); const callback = useRef(fn); @@ -36,4 +36,6 @@ export default function useTimeoutFn(fn, ms = 0) { }, [clear, set]); return [isReady, clear, set]; -} +}; + +export default useTimeoutFn; diff --git a/src/pages/Accessibility.jsx b/src/pages/Accessibility.jsx index 57593cf..628e811 100644 --- a/src/pages/Accessibility.jsx +++ b/src/pages/Accessibility.jsx @@ -15,10 +15,9 @@ const Accessibility = () => {

    It's good practice to include focusable="false" with aria-hidden{' '} - because the attribute - aria-hidden="true" hides an element and all its children from assistive - technologies, but users can still use the keyboard to navigate to any focusable child elements, - but their content is inaccessible to people who use assistive technologies. + because the attribute aria-hidden="true" hides an element and all its children from + assistive technologies, but users can still use the keyboard to navigate to any focusable child + elements, but their content is inaccessible to people who use assistive technologies.

    Button icon without text examples:

    diff --git a/src/pages/Components/BreadcrumbsPage.jsx b/src/pages/Components/BreadcrumbsPage.tsx similarity index 100% rename from src/pages/Components/BreadcrumbsPage.jsx rename to src/pages/Components/BreadcrumbsPage.tsx From a26709c901c2478dbff30afb84743ab49ec09f24 Mon Sep 17 00:00:00 2001 From: Cameron Wardzala Date: Wed, 11 Jan 2023 14:32:39 -0500 Subject: [PATCH 5/5] Fix all comments from PR --- package.json | 2 +- src/components/Breadcrumbs.tsx | 4 ++-- src/components/ConfirmButton.tsx | 12 ++++++------ src/components/DisplayFormikState.tsx | 2 +- src/components/FormattedPlural.tsx | 2 +- src/hooks/{useTimeout.js => useTimeout.ts} | 8 ++++---- yarn.lock | 8 ++++---- 7 files changed, 19 insertions(+), 19 deletions(-) rename src/hooks/{useTimeout.js => useTimeout.ts} (77%) diff --git a/package.json b/package.json index d24d06d..9808b65 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@reach/visually-hidden": "^0.16.0", "@types/jest": "^29.0.0", "@types/node": "^18.7.16", - "@types/react": "^18.0.18", + "@types/react": "^17.0.0", "@types/react-dom": "^18.0.6", "classnames": "^2.3.1", "color": "^4.2.3", diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index 45b18ef..963ac92 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classnames from 'classnames'; -interface BreadcrumbsProps extends React.PropsWithChildren { +interface BreadcrumbsProps { className?: string; } @@ -13,7 +13,7 @@ export const Breadcrumbs: React.FC = ({ children, className }) ); }; -interface BreadcrumbItemProps extends React.PropsWithChildren { +interface BreadcrumbItemProps { current?: boolean; as?: React.ElementType; to?: string; diff --git a/src/components/ConfirmButton.tsx b/src/components/ConfirmButton.tsx index fe8d9da..486aba0 100644 --- a/src/components/ConfirmButton.tsx +++ b/src/components/ConfirmButton.tsx @@ -3,11 +3,11 @@ import classnames from 'classnames'; import { FiCheck } from 'react-icons/fi'; import useTimeoutFn from '../hooks/useTimeout'; -const CONFIRM_STATES = { - CONFIRM: 'confirm', - DONE: 'done', - READY: 'ready' -}; +enum CONFIRM_STATES { + CONFIRM = 'confirm', + DONE = 'done', + READY = 'ready' +} interface ConfirmButtonProps { className?: string; @@ -36,7 +36,7 @@ const ConfirmButton: React.FC = ({ timeout = 3000, onConfirm = () => {} }) => { - const [buttonState, setButtonState] = useState('ready'); + const [buttonState, setButtonState] = useState(CONFIRM_STATES.READY); const isConfirm = [CONFIRM_STATES.CONFIRM, CONFIRM_STATES.DONE].includes(buttonState); diff --git a/src/components/DisplayFormikState.tsx b/src/components/DisplayFormikState.tsx index 4984ecb..c5a0ebd 100644 --- a/src/components/DisplayFormikState.tsx +++ b/src/components/DisplayFormikState.tsx @@ -1,7 +1,7 @@ import React from 'react'; import Code from './Code'; -const DisplayFormikState = (props: React.PropsWithChildren) => ( +const DisplayFormikState = (props: React.PropsWithChildren) => (
    diff --git a/src/components/FormattedPlural.tsx b/src/components/FormattedPlural.tsx index 33f5f77..15bf5e2 100644 --- a/src/components/FormattedPlural.tsx +++ b/src/components/FormattedPlural.tsx @@ -4,6 +4,6 @@ interface FormattedPluralProps { many: string; } -const FormattedPlural = ({ value = 1, one = '', many = '' }: FormattedPluralProps) => (value === 1 ? one : many); +const FormattedPlural = ({ value, one, many }: FormattedPluralProps) => (value === 1 ? one : many); export default FormattedPlural; diff --git a/src/hooks/useTimeout.js b/src/hooks/useTimeout.ts similarity index 77% rename from src/hooks/useTimeout.js rename to src/hooks/useTimeout.ts index fad3c15..badcdc8 100644 --- a/src/hooks/useTimeout.js +++ b/src/hooks/useTimeout.ts @@ -1,8 +1,8 @@ import { useCallback, useEffect, useRef } from 'react'; -const useTimeoutFn = (fn: () => void, ms: number | false = 0): array => { - const ready = useRef(false); - const timeout = useRef(); +const useTimeoutFn = (fn: () => void, ms: number | false = 0): readonly [() => boolean | null, () => void, () => void] => { + const ready = useRef(false); + const timeout = useRef(); const callback = useRef(fn); const isReady = useCallback(() => ready.current, []); @@ -15,7 +15,7 @@ const useTimeoutFn = (fn: () => void, ms: number | false = 0): array => { timeout.current = setTimeout(() => { ready.current = true; callback.current(); - }, ms); + }, ms) as unknown as number; }, [ms]); const clear = useCallback(() => { diff --git a/yarn.lock b/yarn.lock index a5bb76a..57f26e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2488,10 +2488,10 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^18.0.18": - version "18.0.18" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.18.tgz#9f16f33d57bc5d9dca848d12c3572110ff9429ac" - integrity sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg== +"@types/react@^17.0.0": + version "17.0.52" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b" + integrity sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A== dependencies: "@types/prop-types" "*" "@types/scheduler" "*"