UNPKG

@wordpress/components

Version:
8 lines (7 loc) 9.22 kB
{ "version": 3, "sources": ["../../../src/input-control/reducer/reducer.ts"], "sourcesContent": ["/**\n * External dependencies\n */\n\n/**\n * WordPress dependencies\n */\nimport { useReducer, useLayoutEffect, useRef } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\n\nimport { initialInputControlState, initialStateReducer } from './state';\nimport * as actions from './actions';\n/**\n * Prepares initialState for the reducer.\n *\n * @param initialState The initial state.\n * @return Prepared initialState for the reducer\n */\nfunction mergeInitialState(initialState = initialInputControlState) {\n const {\n value\n } = initialState;\n return {\n ...initialInputControlState,\n ...initialState,\n initialValue: value\n };\n}\n\n/**\n * Creates the base reducer which may be coupled to a specializing reducer.\n * As its final step, for all actions other than CONTROL, the base reducer\n * passes the state and action on through the specializing reducer. The\n * exception for CONTROL actions is because they represent controlled updates\n * from props and no case has yet presented for their specialization.\n *\n * @param composedStateReducers A reducer to specialize state changes.\n * @return The reducer.\n */\nfunction inputControlStateReducer(composedStateReducers) {\n return (state, action) => {\n const nextState = {\n ...state\n };\n switch (action.type) {\n /*\n * Controlled updates\n */\n case actions.CONTROL:\n nextState.value = action.payload.value;\n nextState.isDirty = false;\n nextState._event = undefined;\n // Returns immediately to avoid invoking additional reducers.\n return nextState;\n\n /**\n * Keyboard events\n */\n case actions.PRESS_UP:\n nextState.isDirty = false;\n break;\n case actions.PRESS_DOWN:\n nextState.isDirty = false;\n break;\n\n /**\n * Drag events\n */\n case actions.DRAG_START:\n nextState.isDragging = true;\n break;\n case actions.DRAG_END:\n nextState.isDragging = false;\n break;\n\n /**\n * Input events\n */\n case actions.CHANGE:\n nextState.error = null;\n nextState.value = action.payload.value;\n if (state.isPressEnterToChange) {\n nextState.isDirty = true;\n }\n break;\n case actions.COMMIT:\n nextState.value = action.payload.value;\n nextState.isDirty = false;\n break;\n case actions.RESET:\n nextState.error = null;\n nextState.isDirty = false;\n nextState.value = action.payload.value || state.initialValue;\n break;\n\n /**\n * Validation\n */\n case actions.INVALIDATE:\n nextState.error = action.payload.error;\n break;\n }\n nextState._event = action.payload.event;\n\n /**\n * Send the nextState + action to the composedReducers via\n * this \"bridge\" mechanism. This allows external stateReducers\n * to hook into actions, and modify state if needed.\n */\n return composedStateReducers(nextState, action);\n };\n}\n\n/**\n * A custom hook that connects and external stateReducer with an internal\n * reducer. This hook manages the internal state of InputControl.\n * However, by connecting an external stateReducer function, other\n * components can react to actions as well as modify state before it is\n * applied.\n *\n * This technique uses the \"stateReducer\" design pattern:\n * https://kentcdodds.com/blog/the-state-reducer-pattern/\n *\n * @param stateReducer An external state reducer.\n * @param initialState The initial state for the reducer.\n * @param onChangeHandler A handler for the onChange event.\n * @return State, dispatch, and a collection of actions.\n */\nexport function useInputControlStateReducer(stateReducer = initialStateReducer, initialState = initialInputControlState, onChangeHandler) {\n const [state, dispatch] = useReducer(inputControlStateReducer(stateReducer), mergeInitialState(initialState));\n const createChangeEvent = type => (nextValue, event) => {\n dispatch({\n type,\n payload: {\n value: nextValue,\n event\n }\n });\n };\n const createKeyEvent = type => event => {\n dispatch({\n type,\n payload: {\n event\n }\n });\n };\n const createDragEvent = type => payload => {\n dispatch({\n type,\n payload\n });\n };\n\n /**\n * Actions for the reducer\n */\n const change = createChangeEvent(actions.CHANGE);\n const invalidate = (error, event) => dispatch({\n type: actions.INVALIDATE,\n payload: {\n error,\n event\n }\n });\n const reset = createChangeEvent(actions.RESET);\n const commit = createChangeEvent(actions.COMMIT);\n const dragStart = createDragEvent(actions.DRAG_START);\n const drag = createDragEvent(actions.DRAG);\n const dragEnd = createDragEvent(actions.DRAG_END);\n const pressUp = createKeyEvent(actions.PRESS_UP);\n const pressDown = createKeyEvent(actions.PRESS_DOWN);\n const pressEnter = createKeyEvent(actions.PRESS_ENTER);\n const currentStateRef = useRef(state);\n const refPropsRef = useRef({\n value: initialState.value,\n onChangeHandler\n });\n\n // Freshens refs to props and state so that subsequent effects have access\n // to their latest values without their changes causing effect runs.\n useLayoutEffect(() => {\n currentStateRef.current = state;\n refPropsRef.current = {\n value: initialState.value,\n onChangeHandler\n };\n });\n\n // Propagates the latest state through onChange.\n useLayoutEffect(() => {\n if (currentStateRef.current._event !== undefined && state.value !== refPropsRef.current.value && !state.isDirty) {\n refPropsRef.current.onChangeHandler(state.value ?? '', {\n event: currentStateRef.current._event\n });\n }\n }, [state.value, state.isDirty]);\n\n // Updates the state from props.\n useLayoutEffect(() => {\n if (initialState.value !== currentStateRef.current.value && !currentStateRef.current.isDirty) {\n dispatch({\n type: actions.CONTROL,\n payload: {\n value: initialState.value ?? ''\n }\n });\n }\n }, [initialState.value]);\n return {\n change,\n commit,\n dispatch,\n drag,\n dragEnd,\n dragStart,\n invalidate,\n pressDown,\n pressEnter,\n pressUp,\n reset,\n state\n };\n}"], "mappings": "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", "names": [] }