-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: refactoring and rearrangement.
More DRY code. Also move non-hooks to separate directories. BREAKING CHANGE: all `create*` factories been moved to `factory` subdirectory and in case direct import should be imported like `react-use/esm/factory/createBreakpoint` BREAKING CHANGE: `comps` directory renamed to `component`
- Loading branch information
1 parent
bbbe4d5
commit a27f09f
Showing
96 changed files
with
2,585 additions
and
4,903 deletions.
There are no files selected for viewing
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
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
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
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
4 changes: 2 additions & 2 deletions
4
src/createGlobalState.ts β src/factory/createGlobalState.ts
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
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,235 @@ | ||
import * as React from 'react'; | ||
import { useEffect, useRef } from 'react'; | ||
import useSetState from '../useSetState'; | ||
import parseTimeRanges from '../misc/parseTimeRanges'; | ||
|
||
export interface HTMLMediaProps extends React.AudioHTMLAttributes<any>, React.VideoHTMLAttributes<any> { | ||
src: string; | ||
} | ||
|
||
export interface HTMLMediaState { | ||
buffered: any[]; | ||
duration: number; | ||
paused: boolean; | ||
muted: boolean; | ||
time: number; | ||
volume: number; | ||
} | ||
|
||
export interface HTMLMediaControls { | ||
play: () => Promise<void> | void; | ||
pause: () => void; | ||
mute: () => void; | ||
unmute: () => void; | ||
volume: (volume: number) => void; | ||
seek: (time: number) => void; | ||
} | ||
|
||
type createHTMLMediaHookReturn = [ | ||
React.ReactElement<HTMLMediaProps>, | ||
HTMLMediaState, | ||
HTMLMediaControls, | ||
{ current: HTMLAudioElement | null } | ||
]; | ||
|
||
export default function createHTMLMediaHook(tag: 'audio' | 'video') { | ||
return (elOrProps: HTMLMediaProps | React.ReactElement<HTMLMediaProps>): createHTMLMediaHookReturn => { | ||
let element: React.ReactElement<any> | undefined; | ||
let props: HTMLMediaProps; | ||
|
||
if (React.isValidElement(elOrProps)) { | ||
element = elOrProps; | ||
props = element.props; | ||
} else { | ||
props = elOrProps as HTMLMediaProps; | ||
} | ||
|
||
const [state, setState] = useSetState<HTMLMediaState>({ | ||
buffered: [], | ||
time: 0, | ||
duration: 0, | ||
paused: true, | ||
muted: false, | ||
volume: 1, | ||
}); | ||
const ref = useRef<HTMLAudioElement | null>(null); | ||
|
||
const wrapEvent = (userEvent, proxyEvent?) => { | ||
return (event) => { | ||
try { | ||
proxyEvent && proxyEvent(event); | ||
} finally { | ||
userEvent && userEvent(event); | ||
} | ||
}; | ||
}; | ||
|
||
const onPlay = () => setState({ paused: false }); | ||
const onPause = () => setState({ paused: true }); | ||
const onVolumeChange = () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
setState({ | ||
muted: el.muted, | ||
volume: el.volume, | ||
}); | ||
}; | ||
const onDurationChange = () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
const { duration, buffered } = el; | ||
setState({ | ||
duration, | ||
buffered: parseTimeRanges(buffered), | ||
}); | ||
}; | ||
const onTimeUpdate = () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
setState({ time: el.currentTime }); | ||
}; | ||
const onProgress = () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
setState({ buffered: parseTimeRanges(el.buffered) }); | ||
}; | ||
|
||
if (element) { | ||
element = React.cloneElement(element, { | ||
controls: false, | ||
...props, | ||
ref, | ||
onPlay: wrapEvent(props.onPlay, onPlay), | ||
onPause: wrapEvent(props.onPause, onPause), | ||
onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange), | ||
onDurationChange: wrapEvent(props.onDurationChange, onDurationChange), | ||
onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate), | ||
onProgress: wrapEvent(props.onProgress, onProgress), | ||
}); | ||
} else { | ||
element = React.createElement(tag, { | ||
controls: false, | ||
...props, | ||
ref, | ||
onPlay: wrapEvent(props.onPlay, onPlay), | ||
onPause: wrapEvent(props.onPause, onPause), | ||
onVolumeChange: wrapEvent(props.onVolumeChange, onVolumeChange), | ||
onDurationChange: wrapEvent(props.onDurationChange, onDurationChange), | ||
onTimeUpdate: wrapEvent(props.onTimeUpdate, onTimeUpdate), | ||
onProgress: wrapEvent(props.onProgress, onProgress), | ||
} as any); // TODO: fix this typing. | ||
} | ||
|
||
// Some browsers return `Promise` on `.play()` and may throw errors | ||
// if one tries to execute another `.play()` or `.pause()` while that | ||
// promise is resolving. So we prevent that with this lock. | ||
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=593273 | ||
let lockPlay: boolean = false; | ||
|
||
const controls = { | ||
play: () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return undefined; | ||
} | ||
|
||
if (!lockPlay) { | ||
const promise = el.play(); | ||
const isPromise = typeof promise === 'object'; | ||
|
||
if (isPromise) { | ||
lockPlay = true; | ||
const resetLock = () => { | ||
lockPlay = false; | ||
}; | ||
promise.then(resetLock, resetLock); | ||
} | ||
|
||
return promise; | ||
} | ||
return undefined; | ||
}, | ||
pause: () => { | ||
const el = ref.current; | ||
if (el && !lockPlay) { | ||
return el.pause(); | ||
} | ||
}, | ||
seek: (time: number) => { | ||
const el = ref.current; | ||
if (!el || state.duration === undefined) { | ||
return; | ||
} | ||
time = Math.min(state.duration, Math.max(0, time)); | ||
el.currentTime = time; | ||
}, | ||
volume: (volume: number) => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
volume = Math.min(1, Math.max(0, volume)); | ||
el.volume = volume; | ||
setState({ volume }); | ||
}, | ||
mute: () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
el.muted = true; | ||
}, | ||
unmute: () => { | ||
const el = ref.current; | ||
if (!el) { | ||
return; | ||
} | ||
el.muted = false; | ||
}, | ||
}; | ||
|
||
useEffect(() => { | ||
const el = ref.current!; | ||
|
||
if (!el) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (tag === 'audio') { | ||
console.error( | ||
'useAudio() ref to <audio> element is empty at mount. ' + | ||
'It seem you have not rendered the audio element, which it ' + | ||
'returns as the first argument const [audio] = useAudio(...).' | ||
); | ||
} else if (tag === 'video') { | ||
console.error( | ||
'useVideo() ref to <video> element is empty at mount. ' + | ||
'It seem you have not rendered the video element, which it ' + | ||
'returns as the first argument const [video] = useVideo(...).' | ||
); | ||
} | ||
} | ||
return; | ||
} | ||
|
||
setState({ | ||
volume: el.volume, | ||
muted: el.muted, | ||
paused: el.paused, | ||
}); | ||
|
||
// Start media, if autoPlay requested. | ||
if (props.autoPlay && el.paused) { | ||
controls.play(); | ||
} | ||
}, [props.src]); | ||
|
||
return [element, state, controls, ref]; | ||
}; | ||
} |
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
2 changes: 1 addition & 1 deletion
2
src/createReducerContext.ts β src/factory/createReducerContext.ts
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
10 changes: 3 additions & 7 deletions
10
src/util/createRenderProp.ts β src/factory/createRenderProp.ts
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 |
---|---|---|
@@ -1,13 +1,9 @@ | ||
const defaultMapPropsToArgs = (props) => [props]; | ||
|
||
const createRenderProp = (hook, mapPropsToArgs = defaultMapPropsToArgs) => { | ||
const RenderProp = (props) => { | ||
export default function createRenderProp(hook, mapPropsToArgs = defaultMapPropsToArgs) { | ||
return function RenderProp(props) { | ||
const state = hook(...mapPropsToArgs(props)); | ||
const { children, render = children } = props; | ||
return render ? render(state) || null : null; | ||
}; | ||
|
||
return RenderProp; | ||
}; | ||
|
||
export default createRenderProp; | ||
} |
File renamed without changes.
Oops, something went wrong.