Skip to content

Commit

Permalink
Enable react-hooks ESLint rules & fix associated errors (#6277)
Browse files Browse the repository at this point in the history
Co-authored-by: Braeden Smith <braedens@palantir.com>
  • Loading branch information
braeden and Braeden Smith authored Jul 17, 2023
1 parent e696232 commit 214cc02
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 95 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/context/hotkeys/hotkeysProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ export interface HotkeysProviderProps {
*/
export const HotkeysProvider = ({ children, dialogProps, renderDialog, value }: HotkeysProviderProps) => {
const hasExistingContext = value != null;
const [state, dispatch] = value ?? React.useReducer(hotkeysReducer, { ...initialHotkeysState, hasProvider: true });
const fallbackReducer = React.useReducer(hotkeysReducer, { ...initialHotkeysState, hasProvider: true });
const [state, dispatch] = value ?? fallbackReducer;
const handleDialogClose = React.useCallback(() => dispatch({ type: "CLOSE_DIALOG" }), []);

const dialog = renderDialog?.(state, { handleDialogClose }) ?? (
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/hooks/hotkeys/useHotkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ export function useHotkeys(keys: readonly HotkeyConfig[], options: UseHotkeysOpt
// register keys with global context
const [state, dispatch] = React.useContext(HotkeysContext);

if (!state.hasProvider) {
React.useEffect(() => console.warn(HOTKEYS_PROVIDER_NOT_FOUND), []);
}
React.useEffect(() => {
if (!state.hasProvider) {
console.warn(HOTKEYS_PROVIDER_NOT_FOUND);
}
}, []);

// we can still bind the hotkeys if there is no HotkeysProvider, they just won't show up in the dialog
React.useEffect(() => {
Expand Down
158 changes: 79 additions & 79 deletions packages/docs-app/src/examples/core-examples/useHotkeysExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ export const UseHotkeysExample: React.FC<ExampleProps> = props => {
}
}, [pianoRef]);

// create a dictionary of key states and updater functions
const keys = Array.apply(null, Array(24))
.map(() => React.useState(() => false), [])
.map(([pressed, setPressed]) => ({
pressed,
setPressed,
}));
const [keyPressed, setKeyPressed] = React.useState<readonly boolean[]>(new Array(25).fill(false));

const setKeyState = React.useCallback((targetIndex: number, newValue: boolean) => {
setKeyPressed(previouslySelected =>
previouslySelected.map((value, index) => (index === targetIndex ? newValue : value)),
);
}, []);

const hotkeys = React.useMemo(
() => [
Expand All @@ -52,169 +52,169 @@ export const UseHotkeysExample: React.FC<ExampleProps> = props => {
combo: "Q",
group: "useHotkeys Example",
label: "Play a C5",
onKeyDown: () => keys[0].setPressed(true),
onKeyUp: () => keys[0].setPressed(false),
onKeyDown: () => setKeyState(0, true),
onKeyUp: () => setKeyState(0, false),
},
{
combo: "2",
group: "useHotkeys Example",
label: "Play a C#5",
onKeyDown: () => keys[1].setPressed(true),
onKeyUp: () => keys[1].setPressed(false),
onKeyDown: () => setKeyState(1, true),
onKeyUp: () => setKeyState(1, false),
},
{
combo: "W",
group: "useHotkeys Example",
label: "Play a D5",
onKeyDown: () => keys[2].setPressed(true),
onKeyUp: () => keys[2].setPressed(false),
onKeyDown: () => setKeyState(2, true),
onKeyUp: () => setKeyState(2, false),
},
{
combo: "3",
group: "useHotkeys Example",
label: "Play a D#5",
onKeyDown: () => keys[3].setPressed(true),
onKeyUp: () => keys[3].setPressed(false),
onKeyDown: () => setKeyState(3, true),
onKeyUp: () => setKeyState(3, false),
},
{
combo: "E",
group: "useHotkeys Example",
label: "Play a E5",
onKeyDown: () => keys[4].setPressed(true),
onKeyUp: () => keys[4].setPressed(false),
onKeyDown: () => setKeyState(4, true),
onKeyUp: () => setKeyState(4, false),
},
{
combo: "R",
group: "useHotkeys Example",
label: "Play a F5",
onKeyDown: () => keys[5].setPressed(true),
onKeyUp: () => keys[5].setPressed(false),
onKeyDown: () => setKeyState(5, true),
onKeyUp: () => setKeyState(5, false),
},
{
combo: "5",
group: "useHotkeys Example",
label: "Play a F#5",
onKeyDown: () => keys[6].setPressed(true),
onKeyUp: () => keys[6].setPressed(false),
onKeyDown: () => setKeyState(6, true),
onKeyUp: () => setKeyState(6, false),
},
{
combo: "T",
group: "useHotkeys Example",
label: "Play a G5",
onKeyDown: () => keys[7].setPressed(true),
onKeyUp: () => keys[7].setPressed(false),
onKeyDown: () => setKeyState(7, true),
onKeyUp: () => setKeyState(7, false),
},
{
combo: "6",
group: "useHotkeys Example",
label: "Play a G#5",
onKeyDown: () => keys[8].setPressed(true),
onKeyUp: () => keys[8].setPressed(false),
onKeyDown: () => setKeyState(8, true),
onKeyUp: () => setKeyState(8, false),
},
{
combo: "Y",
group: "useHotkeys Example",
label: "Play a A5",
onKeyDown: () => keys[9].setPressed(true),
onKeyUp: () => keys[9].setPressed(false),
onKeyDown: () => setKeyState(9, true),
onKeyUp: () => setKeyState(9, false),
},
{
combo: "7",
group: "useHotkeys Example",
label: "Play a A#5",
onKeyDown: () => keys[10].setPressed(true),
onKeyUp: () => keys[10].setPressed(false),
onKeyDown: () => setKeyState(10, true),
onKeyUp: () => setKeyState(10, false),
},
{
combo: "U",
group: "useHotkeys Example",
label: "Play a B5",
onKeyDown: () => keys[11].setPressed(true),
onKeyUp: () => keys[11].setPressed(false),
onKeyDown: () => setKeyState(11, true),
onKeyUp: () => setKeyState(11, false),
},
{
combo: "Z",
group: "useHotkeys Example",
label: "Play a C4",
onKeyDown: () => keys[12].setPressed(true),
onKeyUp: () => keys[12].setPressed(false),
onKeyDown: () => setKeyState(12, true),
onKeyUp: () => setKeyState(12, false),
},
{
combo: "S",
group: "useHotkeys Example",
label: "Play a C#4",
onKeyDown: () => keys[13].setPressed(true),
onKeyUp: () => keys[13].setPressed(false),
onKeyDown: () => setKeyState(13, true),
onKeyUp: () => setKeyState(13, false),
},
{
combo: "X",
group: "useHotkeys Example",
label: "Play a D4",
onKeyDown: () => keys[14].setPressed(true),
onKeyUp: () => keys[14].setPressed(false),
onKeyDown: () => setKeyState(14, true),
onKeyUp: () => setKeyState(14, false),
},
{
combo: "D",
group: "useHotkeys Example",
label: "Play a D#4",
onKeyDown: () => keys[15].setPressed(true),
onKeyUp: () => keys[15].setPressed(false),
onKeyDown: () => setKeyState(15, true),
onKeyUp: () => setKeyState(15, false),
},
{
combo: "C",
group: "useHotkeys Example",
label: "Play a E4",
onKeyDown: () => keys[16].setPressed(true),
onKeyUp: () => keys[16].setPressed(false),
onKeyDown: () => setKeyState(16, true),
onKeyUp: () => setKeyState(16, false),
},
{
combo: "V",
group: "useHotkeys Example",
label: "Play a F4",
onKeyDown: () => keys[17].setPressed(true),
onKeyUp: () => keys[17].setPressed(false),
onKeyDown: () => setKeyState(17, true),
onKeyUp: () => setKeyState(17, false),
},
{
combo: "G",
group: "useHotkeys Example",
label: "Play a F#4",
onKeyDown: () => keys[18].setPressed(true),
onKeyUp: () => keys[18].setPressed(false),
onKeyDown: () => setKeyState(18, true),
onKeyUp: () => setKeyState(18, false),
},
{
combo: "B",
group: "useHotkeys Example",
label: "Play a G4",
onKeyDown: () => keys[19].setPressed(true),
onKeyUp: () => keys[19].setPressed(false),
onKeyDown: () => setKeyState(19, true),
onKeyUp: () => setKeyState(19, false),
},
{
combo: "H",
group: "useHotkeys Example",
label: "Play a G#4",
onKeyDown: () => keys[20].setPressed(true),
onKeyUp: () => keys[20].setPressed(false),
onKeyDown: () => setKeyState(20, true),
onKeyUp: () => setKeyState(20, false),
},
{
combo: "N",
group: "useHotkeys Example",
label: "Play a A4",
onKeyDown: () => keys[21].setPressed(true),
onKeyUp: () => keys[21].setPressed(false),
onKeyDown: () => setKeyState(21, true),
onKeyUp: () => setKeyState(21, false),
},
{
combo: "J",
group: "useHotkeys Example",
label: "Play a A#4",
onKeyDown: () => keys[22].setPressed(true),
onKeyUp: () => keys[22].setPressed(false),
onKeyDown: () => setKeyState(22, true),
onKeyUp: () => setKeyState(22, false),
},
{
combo: "M",
group: "useHotkeys Example",
label: "Play a B4",
onKeyDown: () => keys[23].setPressed(true),
onKeyUp: () => keys[23].setPressed(false),
onKeyDown: () => setKeyState(23, true),
onKeyUp: () => setKeyState(23, false),
},
],
[],
Expand All @@ -232,32 +232,32 @@ export const UseHotkeysExample: React.FC<ExampleProps> = props => {
onKeyUp={handleKeyUp}
>
<div>
<PianoKey note="C5" hotkey="Q" pressed={keys[0].pressed} context={audioContext} />
<PianoKey note="C#5" hotkey="2" pressed={keys[1].pressed} context={audioContext} />
<PianoKey note="D5" hotkey="W" pressed={keys[2].pressed} context={audioContext} />
<PianoKey note="D#5" hotkey="3" pressed={keys[3].pressed} context={audioContext} />
<PianoKey note="E5" hotkey="E" pressed={keys[4].pressed} context={audioContext} />
<PianoKey note="F5" hotkey="R" pressed={keys[5].pressed} context={audioContext} />
<PianoKey note="F#5" hotkey="5" pressed={keys[6].pressed} context={audioContext} />
<PianoKey note="G5" hotkey="T" pressed={keys[7].pressed} context={audioContext} />
<PianoKey note="G#5" hotkey="6" pressed={keys[8].pressed} context={audioContext} />
<PianoKey note="A5" hotkey="Y" pressed={keys[9].pressed} context={audioContext} />
<PianoKey note="A#5" hotkey="7" pressed={keys[10].pressed} context={audioContext} />
<PianoKey note="B5" hotkey="U" pressed={keys[11].pressed} context={audioContext} />
<PianoKey note="C5" hotkey="Q" pressed={keyPressed[0]} context={audioContext} />
<PianoKey note="C#5" hotkey="2" pressed={keyPressed[1]} context={audioContext} />
<PianoKey note="D5" hotkey="W" pressed={keyPressed[2]} context={audioContext} />
<PianoKey note="D#5" hotkey="3" pressed={keyPressed[3]} context={audioContext} />
<PianoKey note="E5" hotkey="E" pressed={keyPressed[4]} context={audioContext} />
<PianoKey note="F5" hotkey="R" pressed={keyPressed[5]} context={audioContext} />
<PianoKey note="F#5" hotkey="5" pressed={keyPressed[6]} context={audioContext} />
<PianoKey note="G5" hotkey="T" pressed={keyPressed[7]} context={audioContext} />
<PianoKey note="G#5" hotkey="6" pressed={keyPressed[8]} context={audioContext} />
<PianoKey note="A5" hotkey="Y" pressed={keyPressed[9]} context={audioContext} />
<PianoKey note="A#5" hotkey="7" pressed={keyPressed[10]} context={audioContext} />
<PianoKey note="B5" hotkey="U" pressed={keyPressed[11]} context={audioContext} />
</div>
<div>
<PianoKey note="C4" hotkey="Z" pressed={keys[12].pressed} context={audioContext} />
<PianoKey note="C#4" hotkey="S" pressed={keys[13].pressed} context={audioContext} />
<PianoKey note="D4" hotkey="X" pressed={keys[14].pressed} context={audioContext} />
<PianoKey note="D#4" hotkey="D" pressed={keys[15].pressed} context={audioContext} />
<PianoKey note="E4" hotkey="C" pressed={keys[16].pressed} context={audioContext} />
<PianoKey note="F4" hotkey="V" pressed={keys[17].pressed} context={audioContext} />
<PianoKey note="F#4" hotkey="G" pressed={keys[18].pressed} context={audioContext} />
<PianoKey note="G4" hotkey="B" pressed={keys[19].pressed} context={audioContext} />
<PianoKey note="G#4" hotkey="H" pressed={keys[20].pressed} context={audioContext} />
<PianoKey note="A4" hotkey="N" pressed={keys[21].pressed} context={audioContext} />
<PianoKey note="A#4" hotkey="J" pressed={keys[22].pressed} context={audioContext} />
<PianoKey note="B4" hotkey="M" pressed={keys[23].pressed} context={audioContext} />
<PianoKey note="C4" hotkey="Z" pressed={keyPressed[12]} context={audioContext} />
<PianoKey note="C#4" hotkey="S" pressed={keyPressed[13]} context={audioContext} />
<PianoKey note="D4" hotkey="X" pressed={keyPressed[14]} context={audioContext} />
<PianoKey note="D#4" hotkey="D" pressed={keyPressed[15]} context={audioContext} />
<PianoKey note="E4" hotkey="C" pressed={keyPressed[16]} context={audioContext} />
<PianoKey note="F4" hotkey="V" pressed={keyPressed[17]} context={audioContext} />
<PianoKey note="F#4" hotkey="G" pressed={keyPressed[18]} context={audioContext} />
<PianoKey note="G4" hotkey="B" pressed={keyPressed[19]} context={audioContext} />
<PianoKey note="G#4" hotkey="H" pressed={keyPressed[20]} context={audioContext} />
<PianoKey note="A4" hotkey="N" pressed={keyPressed[21]} context={audioContext} />
<PianoKey note="A#4" hotkey="J" pressed={keyPressed[22]} context={audioContext} />
<PianoKey note="B4" hotkey="M" pressed={keyPressed[23]} context={audioContext} />
</div>
</div>
</Example>
Expand Down
19 changes: 10 additions & 9 deletions packages/docs-theme/src/tags/css.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ export const CssExample: React.FC<ITag> = ({ value }) => {
const { getDocsData } = React.useContext(DocumentationContext);
const [activeModifiers, setActiveModifiers] = React.useState<Set<string>>(new Set());

const getModifiers = React.useCallback(
(prefix: "." | ":") => {
return Array.from(activeModifiers.keys())
.filter(mod => mod.charAt(0) === prefix)
.map(mod => mod.slice(1))
.join(" ");
},
[activeModifiers],
);

const getModifierToggleHandler = (modifier: string) => {
return () => {
const newModifiers = new Set(activeModifiers);
Expand Down Expand Up @@ -60,15 +70,6 @@ export const CssExample: React.FC<ITag> = ({ value }) => {
</Checkbox>
));

const getModifiers = React.useCallback(
(prefix: "." | ":") => {
return Array.from(activeModifiers.keys())
.filter(mod => mod.charAt(0) === prefix)
.map(mod => mod.slice(1))
.join(" ");
},
[activeModifiers],
);
const classModifiers = getModifiers(".");
const attrModifiers = getModifiers(":");
const exampleHtml = markup
Expand Down
4 changes: 3 additions & 1 deletion packages/eslint-config/eslint-plugin-rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,7 @@
"react/no-direct-mutation-state": "error",
"react/no-find-dom-node": "error",
"react/no-string-refs": "error",
"react/self-closing-comp": "error"
"react/self-closing-comp": "error",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
2 changes: 1 addition & 1 deletion packages/eslint-config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const tsEslintRules = require("./typescript-eslint-rules.json");
* For TS files, configure typescript-eslint, including type-aware lint rules which use the TS program.
*/
module.exports = {
plugins: ["@blueprintjs", "header", "import", "jsdoc", "react"],
plugins: ["@blueprintjs", "header", "import", "jsdoc", "react", "react-hooks"],
extends: ["plugin:@blueprintjs/recommended", "plugin:import/typescript"],
parserOptions: { ecmaVersion: 2022 },
settings: {
Expand Down
3 changes: 2 additions & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-import": "~2.26.0",
"eslint-plugin-jsdoc": "^46.2.4",
"eslint-plugin-react": "^7.32.2"
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0"
},
"repository": {
"type": "git",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4697,6 +4697,11 @@ eslint-plugin-prettier@^4.2.1:
dependencies:
prettier-linter-helpers "^1.0.0"

eslint-plugin-react-hooks@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==

eslint-plugin-react@^7.32.2:
version "7.32.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10"
Expand Down

1 comment on commit 214cc02

@adidahiya
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enable react-hooks ESLint rules & fix associated errors (#6277)

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

Please sign in to comment.