From 27af3f621cb4bc6d749b236c8807c1e93297308b Mon Sep 17 00:00:00 2001 From: Waste-Brain <82304484+Waste-Brain@users.noreply.github.com> Date: Tue, 15 Jun 2021 23:34:20 +0800 Subject: [PATCH 001/244] Update Usage.md The method of import seems wrong --- docs/Usage.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/Usage.md b/docs/Usage.md index 90da532b99..243e354f88 100644 --- a/docs/Usage.md +++ b/docs/Usage.md @@ -16,10 +16,19 @@ Depending on your bundler you might run into a missing dependency error with ES6 ```json [ - "import", { - "libraryName": "react-use", - "libraryDirectory": "lib", - "camel2DashComponentName": false - } -] + 'import', + { + libraryName: 'react-use', + camel2DashComponentName: false, + customName(/** @type {string} */ name) { + const libraryDirectory = name.startsWith('Use') + ? 'lib/component' + : name.startsWith('create') + ? 'lib/factory' + : 'lib' + return `react-use/${libraryDirectory}/${name}` + } + }, + 'import-react-use' + ] ``` From 99208ffceda2c5861398ebc984157f04c56e4472 Mon Sep 17 00:00:00 2001 From: gelove Date: Wed, 11 Aug 2021 00:28:32 +0800 Subject: [PATCH 002/244] refactor: (useSpeech,usePermission) improved types --- src/usePermission.ts | 58 +++++++++++------- src/useSpeech.ts | 114 ++++++++++++++++++++++++------------ stories/useSpeech.story.tsx | 3 +- 3 files changed, 112 insertions(+), 63 deletions(-) diff --git a/src/usePermission.ts b/src/usePermission.ts index 00046059db..0aae85f55c 100644 --- a/src/usePermission.ts +++ b/src/usePermission.ts @@ -1,45 +1,59 @@ import { useEffect, useState } from 'react'; import { noop, off, on } from './misc/util'; -type PermissionDesc = - | PermissionDescriptor - | DevicePermissionDescriptor - | MidiPermissionDescriptor - | PushPermissionDescriptor; +export type IState = PermissionState | ''; -type State = PermissionState | ''; +interface IPushPermissionDescriptor extends PermissionDescriptor { + name: 'push'; + userVisibleOnly?: boolean; +} -const usePermission = (permissionDesc: PermissionDesc): State => { - let mounted = true; - let permissionStatus: PermissionStatus | null = null; +interface IMidiPermissionDescriptor extends PermissionDescriptor { + name: 'midi'; + sysex?: boolean; +} - const [state, setState] = useState(''); +interface IDevicePermissionDescriptor extends PermissionDescriptor { + name: 'camera' | 'microphone' | 'speaker'; + deviceId?: string; +} - const onChange = () => { - if (mounted && permissionStatus) { - setState(permissionStatus.state); - } - }; +export type IPermissionDescriptor = + | PermissionDescriptor + | IPushPermissionDescriptor + | IMidiPermissionDescriptor + | IDevicePermissionDescriptor; - const changeState = () => { - onChange(); - on(permissionStatus, 'change', onChange); - }; +// const usePermission = (permissionDesc: T): IState => { +const usePermission = (permissionDesc: IPermissionDescriptor): IState => { + const [state, setState] = useState(''); useEffect(() => { + let mounted = true; + let permissionStatus: PermissionStatus | null = null; + + const onChange = () => { + if (!mounted) { + return; + } + setState(() => permissionStatus?.state ?? ''); + }; + navigator.permissions .query(permissionDesc) .then((status) => { permissionStatus = status; - changeState(); + on(permissionStatus, 'change', onChange); + onChange(); }) .catch(noop); return () => { - mounted = false; permissionStatus && off(permissionStatus, 'change', onChange); + mounted = false; + permissionStatus = null; }; - }, []); + }, [permissionDesc]); return state; }; diff --git a/src/useSpeech.ts b/src/useSpeech.ts index b8eaee9791..a38037db5b 100644 --- a/src/useSpeech.ts +++ b/src/useSpeech.ts @@ -1,54 +1,90 @@ -import { useRef } from 'react'; -import useMount from './useMount'; -import useSetState from './useSetState'; -import { isBrowser } from './misc/util'; +import { useCallback, useEffect, useRef, useState } from 'react'; -export interface SpeechState { - isPlaying: boolean; +type SpeechOptions = { lang: string; - voice: SpeechSynthesisVoice; + voice?: SpeechSynthesisVoice; rate: number; pitch: number; volume: number; -} +}; -export interface SpeechOptions { - lang?: string; - voice?: SpeechSynthesisVoice; - rate?: number; - pitch?: number; - volume?: number; +export type ISpeechOptions = Partial; + +export type VoiceInfo = Pick; + +export type ISpeechState = SpeechOptions & { + isPlaying: boolean; + status: string; + voiceInfo: VoiceInfo; +}; + +enum Status { + init, + play, + pause, + end, } -const voices = - isBrowser && typeof window.speechSynthesis === 'object' ? window.speechSynthesis.getVoices() : []; - -const useSpeech = (text: string, opts: SpeechOptions = {}): SpeechState => { - const [state, setState] = useSetState({ - isPlaying: false, - lang: opts.lang || 'default', - voice: opts.voice || voices[0], - rate: opts.rate || 1, - pitch: opts.pitch || 1, - volume: opts.volume || 1, +const useSpeech = (text: string, options: ISpeechOptions): ISpeechState => { + let mounted = useRef(false); + const [state, setState] = useState(() => { + const { lang = 'default', name = '' } = options.voice || {}; + return { + isPlaying: false, + status: Status[Status.init], + lang: options.lang || 'default', + voiceInfo: { lang, name }, + rate: options.rate || 1, + pitch: options.pitch || 1, + volume: options.volume || 1, + }; }); - const uterranceRef = useRef(null); + const handlePlay = useCallback(() => { + if (!mounted.current) { + return; + } + setState((preState) => { + return { ...preState, isPlaying: true, status: Status[Status.play] }; + }); + }, []); + + const handlePause = useCallback(() => { + if (!mounted.current) { + return; + } + setState((preState) => { + return { ...preState, isPlaying: false, status: Status[Status.pause] }; + }); + }, []); - useMount(() => { + const handleEnd = useCallback(() => { + if (!mounted.current) { + return; + } + setState((preState) => { + return { ...preState, isPlaying: false, status: Status[Status.end] }; + }); + }, []); + + useEffect(() => { + mounted.current = true; const utterance = new SpeechSynthesisUtterance(text); - opts.lang && (utterance.lang = opts.lang); - opts.voice && (utterance.voice = opts.voice); - utterance.rate = opts.rate || 1; - utterance.pitch = opts.pitch || 1; - utterance.volume = opts.volume || 1; - utterance.onstart = () => setState({ isPlaying: true }); - utterance.onresume = () => setState({ isPlaying: true }); - utterance.onend = () => setState({ isPlaying: false }); - utterance.onpause = () => setState({ isPlaying: false }); - uterranceRef.current = utterance; - window.speechSynthesis.speak(uterranceRef.current); - }); + options.lang && (utterance.lang = options.lang); + options.voice && (utterance.voice = options.voice); + utterance.rate = options.rate || 1; + utterance.pitch = options.pitch || 1; + utterance.volume = options.volume || 1; + utterance.onstart = handlePlay; + utterance.onpause = handlePause; + utterance.onresume = handlePlay; + utterance.onend = handleEnd; + window.speechSynthesis.speak(utterance); + + return () => { + mounted.current = false; + }; + }, []); return state; }; diff --git a/stories/useSpeech.story.tsx b/stories/useSpeech.story.tsx index 146bb593f7..e1948e6eaf 100644 --- a/stories/useSpeech.story.tsx +++ b/stories/useSpeech.story.tsx @@ -3,9 +3,8 @@ import * as React from 'react'; import { useSpeech } from '../src'; import ShowDocs from './util/ShowDocs'; -const voices = window.speechSynthesis.getVoices(); - const Demo = () => { + const voices = window.speechSynthesis.getVoices(); const state = useSpeech('Hello world!', { rate: 0.8, pitch: 0.5, voice: voices[0] }); return
{JSON.stringify(state, null, 2)}
; From 11144764c7be6c8e4302e21e2fca8dd746365dae Mon Sep 17 00:00:00 2001 From: SkutinAnton Date: Wed, 25 Aug 2021 11:06:59 +0300 Subject: [PATCH 003/244] - fixed loading if we have initialState with loading: true --- src/useAsyncFn.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/useAsyncFn.ts b/src/useAsyncFn.ts index 0ec39a52ed..8cc67351f1 100644 --- a/src/useAsyncFn.ts +++ b/src/useAsyncFn.ts @@ -40,7 +40,10 @@ export default function useAsyncFn( const callback = useCallback((...args: Parameters): ReturnType => { const callId = ++lastCallId.current; - set(prevState => ({ ...prevState, loading: true })); + + if (!state.loading) { + set(prevState => ({ ...prevState, loading: true })); + } return fn(...args).then( value => { From 3203610efdcb8e1fe3c6a17ea19e41bacbeb851b Mon Sep 17 00:00:00 2001 From: longwanxiang Date: Fri, 27 Aug 2021 18:04:22 +0800 Subject: [PATCH 004/244] feat: useAudio add playing state --- docs/useAudio.md | 7 +++++-- src/factory/createHTMLMediaHook.ts | 10 +++++++++- tests/useAudio.test.ts | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/useAudio.md b/docs/useAudio.md index 84184037e5..8939060400 100644 --- a/docs/useAudio.md +++ b/docs/useAudio.md @@ -64,10 +64,13 @@ render tree, for example: "duration": 425.952625, "paused": false, "muted": false, - "volume": 1 + "volume": 1, + "playing": true } ``` +`playing`: The audio is being played and is affected by the network. If it starts to buffer audio, it will be false + `controls` is a list collection of methods that allow you to control the playback of the audio, it has the following interface: @@ -85,4 +88,4 @@ interface AudioControls { `ref` is a React reference to HTML `