-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
45adc40
commit 45ff3eb
Showing
73 changed files
with
2,164 additions
and
623 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 15 additions & 0 deletions
15
exercises/03.compound-components/02.problem.validation/app.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Toggle, ToggleOn, ToggleOff, ToggleButton } from './toggle' | ||
|
||
export function App() { | ||
return ( | ||
<div> | ||
<Toggle> | ||
<ToggleOn>The button is on</ToggleOn> | ||
<ToggleOff>The button is off</ToggleOff> | ||
<div> | ||
<ToggleButton /> | ||
</div> | ||
</Toggle> | ||
</div> | ||
) | ||
} |
File renamed without changes.
File renamed without changes.
34 changes: 34 additions & 0 deletions
34
exercises/03.compound-components/02.problem.validation/toggle.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import * as React from 'react' | ||
import { Switch } from '~/shared/switch' | ||
|
||
type ToggleValue = { on: boolean; toggle: () => void } | ||
const ToggleContext = React.createContext<ToggleValue | undefined>(undefined) | ||
ToggleContext.displayName = 'ToggleContext' | ||
|
||
export function Toggle({ children }: { children: React.ReactNode }) { | ||
const [on, setOn] = React.useState(false) | ||
const toggle = () => setOn(!on) | ||
|
||
return ( | ||
<ToggleContext.Provider value={{ on, toggle }}> | ||
{children} | ||
</ToggleContext.Provider> | ||
) | ||
} | ||
|
||
export function ToggleOn({ children }: { children: React.ReactNode }) { | ||
const { on } = React.useContext(ToggleContext)! | ||
return <>{on ? children : null}</> | ||
} | ||
|
||
export function ToggleOff({ children }: { children: React.ReactNode }) { | ||
const { on } = React.useContext(ToggleContext)! | ||
return <>{on ? null : children}</> | ||
} | ||
|
||
export function ToggleButton({ | ||
...props | ||
}: Omit<React.ComponentProps<typeof Switch>, 'on' | 'onClick'>) { | ||
const { on, toggle } = React.useContext(ToggleContext)! | ||
return <Switch {...props} on={on} onClick={toggle} /> | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Switch } from '~/shared/switch' | ||
import { useToggle } from './toggle' | ||
|
||
export function App() { | ||
const { on, getTogglerProps, getResetterProps } = useToggle({ | ||
initialOn: true, | ||
}) | ||
|
||
return ( | ||
<div> | ||
<Switch {...getTogglerProps({ on: on })} /> | ||
<button {...getResetterProps({})}>Reset</button> | ||
</div> | ||
) | ||
} |
File renamed without changes.
File renamed without changes.
61 changes: 61 additions & 0 deletions
61
exercises/05.state-initializer/02.problem.initial/toggle.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import * as React from 'react' | ||
|
||
function callAll<Args extends Array<unknown>>( | ||
...fns: Array<((...args: Args) => unknown) | undefined> | ||
) { | ||
return (...args: Args) => fns.forEach(fn => fn?.(...args)) | ||
} | ||
|
||
type ToggleState = { on: boolean } | ||
type ToggleAction = | ||
| { type: 'toggle' } | ||
| { type: 'reset'; initialState: ToggleState } | ||
|
||
function toggleReducer(state: ToggleState, action: ToggleAction) { | ||
switch (action.type) { | ||
case 'toggle': { | ||
return { on: !state.on } | ||
} | ||
case 'reset': { | ||
return action.initialState | ||
} | ||
} | ||
} | ||
|
||
export function useToggle({ initialOn = false } = {}) { | ||
const initialState = { on: initialOn } | ||
const [state, dispatch] = React.useReducer(toggleReducer, initialState) | ||
const { on } = state | ||
|
||
const toggle = () => dispatch({ type: 'toggle' }) | ||
const reset = () => dispatch({ type: 'reset', initialState }) | ||
|
||
function getTogglerProps<Props>({ | ||
onClick, | ||
...props | ||
}: { onClick?: React.DOMAttributes<HTMLButtonElement>['onClick'] } & Props) { | ||
return { | ||
'aria-checked': on, | ||
onClick: callAll(onClick, toggle), | ||
...props, | ||
} | ||
} | ||
|
||
function getResetterProps<Props>({ | ||
onClick, | ||
...props | ||
}: { onClick?: React.DOMAttributes<HTMLButtonElement>['onClick'] } & Props) { | ||
return { | ||
onClick: callAll(onClick, reset), | ||
...props, | ||
} | ||
} | ||
|
||
return { | ||
on, | ||
reset, | ||
toggle, | ||
getTogglerProps, | ||
getResetterProps, | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import '/switch.styles.css'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import * as ReactDOM from 'react-dom/client' | ||
import { App } from './app' | ||
|
||
const rootEl = document.createElement('div') | ||
document.body.append(rootEl) | ||
ReactDOM.createRoot(rootEl).render(<App />) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import * as React from 'react' | ||
import { Switch } from '~/shared/switch' | ||
import { useToggle } from './toggle' | ||
|
||
export function App() { | ||
const [timesClicked, setTimesClicked] = React.useState(0) | ||
const clickedTooMuch = timesClicked >= 4 | ||
|
||
const { on, getTogglerProps, getResetterProps } = useToggle({ | ||
reducer(state, action) { | ||
switch (action.type) { | ||
case 'toggle': { | ||
if (clickedTooMuch) { | ||
return state | ||
} | ||
return { on: !state.on } | ||
} | ||
case 'reset': { | ||
return { on: false } | ||
} | ||
} | ||
}, | ||
}) | ||
|
||
return ( | ||
<div> | ||
<Switch | ||
{...getTogglerProps({ | ||
on: on, | ||
onClick: () => setTimesClicked(count => count + 1), | ||
})} | ||
/> | ||
{clickedTooMuch ? ( | ||
<div data-testid="notice"> | ||
Whoa, you clicked too much! | ||
<br /> | ||
</div> | ||
) : timesClicked > 0 ? ( | ||
<div data-testid="click-count">Click count: {timesClicked}</div> | ||
) : null} | ||
<button {...getResetterProps({ onClick: () => setTimesClicked(0) })}> | ||
Reset | ||
</button> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import '/switch.styles.css'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import * as ReactDOM from 'react-dom/client' | ||
import { App } from './app' | ||
|
||
const rootEl = document.createElement('div') | ||
document.body.append(rootEl) | ||
ReactDOM.createRoot(rootEl).render(<App />) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import * as React from 'react' | ||
|
||
function callAll<Args extends Array<unknown>>( | ||
...fns: Array<((...args: Args) => unknown) | undefined> | ||
) { | ||
return (...args: Args) => fns.forEach(fn => fn?.(...args)) | ||
} | ||
|
||
type ToggleState = { on: boolean } | ||
type ToggleAction = | ||
| { type: 'toggle' } | ||
| { type: 'reset'; initialState: ToggleState } | ||
|
||
function toggleReducer(state: ToggleState, action: ToggleAction) { | ||
switch (action.type) { | ||
case 'toggle': { | ||
return { on: !state.on } | ||
} | ||
case 'reset': { | ||
return action.initialState | ||
} | ||
} | ||
} | ||
|
||
export function useToggle({ initialOn = false, reducer = toggleReducer } = {}) { | ||
const { current: initialState } = React.useRef<ToggleState>({ on: initialOn }) | ||
const [state, dispatch] = React.useReducer(reducer, initialState) | ||
const { on } = state | ||
|
||
const toggle = () => dispatch({ type: 'toggle' }) | ||
const reset = () => dispatch({ type: 'reset', initialState }) | ||
|
||
function getTogglerProps<Props>({ | ||
onClick, | ||
...props | ||
}: { onClick?: React.DOMAttributes<HTMLButtonElement>['onClick'] } & Props) { | ||
return { | ||
'aria-checked': on, | ||
onClick: callAll(onClick, toggle), | ||
...props, | ||
} | ||
} | ||
|
||
function getResetterProps<Props>({ | ||
onClick, | ||
...props | ||
}: { onClick?: React.DOMAttributes<HTMLButtonElement>['onClick'] } & Props) { | ||
return { | ||
onClick: callAll(onClick, reset), | ||
...props, | ||
} | ||
} | ||
|
||
return { | ||
on, | ||
reset, | ||
toggle, | ||
getTogglerProps, | ||
getResetterProps, | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import '/switch.styles.css'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import * as ReactDOM from 'react-dom/client' | ||
import { App } from './app' | ||
|
||
const rootEl = document.createElement('div') | ||
document.body.append(rootEl) | ||
ReactDOM.createRoot(rootEl).render(<App />) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import * as React from 'react' | ||
import { Toggle, type ToggleAction, type ToggleState } from './toggle' | ||
|
||
export function App() { | ||
const [bothOn, setBothOn] = React.useState(false) | ||
const [timesClicked, setTimesClicked] = React.useState(0) | ||
|
||
function handleToggleChange(state: ToggleState, action: ToggleAction) { | ||
if (action.type === 'toggle' && timesClicked > 4) { | ||
return | ||
} | ||
setBothOn(state.on) | ||
setTimesClicked(c => c + 1) | ||
} | ||
|
||
function handleResetClick() { | ||
setBothOn(false) | ||
setTimesClicked(0) | ||
} | ||
|
||
return ( | ||
<div> | ||
<div> | ||
<Toggle on={bothOn} onChange={handleToggleChange} /> | ||
<Toggle on={bothOn} onChange={handleToggleChange} /> | ||
</div> | ||
{timesClicked > 4 ? ( | ||
<div data-testid="notice"> | ||
Whoa, you clicked too much! | ||
<br /> | ||
</div> | ||
) : ( | ||
<div data-testid="click-count">Click count: {timesClicked}</div> | ||
)} | ||
<button onClick={handleResetClick}>Reset</button> | ||
<hr /> | ||
<div> | ||
<div>Uncontrolled Toggle:</div> | ||
<Toggle | ||
onChange={(...args) => | ||
console.info('Uncontrolled Toggle onChange', ...args) | ||
} | ||
/> | ||
</div> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import '/switch.styles.css'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import * as ReactDOM from 'react-dom/client' | ||
import { App } from './app' | ||
|
||
const rootEl = document.createElement('div') | ||
document.body.append(rootEl) | ||
ReactDOM.createRoot(rootEl).render(<App />) |
Oops, something went wrong.