use-location-state
Advanced tools
| /// <reference types="react" /> | ||
| export declare function useRefLatest<T>(value: T): import("react").MutableRefObject<T>; |
| export declare type Reducer<S, A> = (prevState: S, action: A) => S; | ||
| export declare type ReducerWithoutAction<S> = (prevState: S) => S; | ||
| export declare type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never; | ||
| export declare type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never; | ||
| export declare type LazyValueFn<S> = () => S; | ||
| export declare type SetStateAction<S> = S | ((prevState: S) => S); |
| import { LocationStateOpts, SetLocationStateOptions } from './useLocationState.types'; | ||
| export declare type LocationDispatch<A> = (value: A, opts?: SetLocationStateOptions) => void; | ||
| export declare type LocationReducerFn<State, Action> = (state: State, action: Action) => State; | ||
| export declare function useLocationReducer<State, Action>(itemName: string, reducer: LocationReducerFn<State, Action>, initialState: State, opts?: LocationStateOpts): [State, LocationDispatch<Action>]; | ||
| export declare function useLocationReducer<State, Action, InitialArg>(itemName: string, reducer: LocationReducerFn<State, Action>, initialArg: InitialArg, initStateFn: (initialArg: InitialArg) => State, opts?: LocationStateOpts): [State, LocationDispatch<Action>]; |
| export {}; |
| export {}; |
| export {}; |
| export {}; |
| export {}; |
| import { QueryStringInterface } from '../useQueryState.types'; | ||
| export default function useTestQueryStringInterface(): QueryStringInterface; |
| export {}; |
| import { QueryStateOpts, SetQueryStringOptions } from './useQueryState.types'; | ||
| import { ReducerState } from 'react'; | ||
| import { Reducer, ReducerAction } from '../types/sharedTypes'; | ||
| export declare type QueryDispatch<A> = (value: A, opts?: SetQueryStringOptions) => void; | ||
| export declare function useQueryReducer<R extends Reducer<ReducerState<R>, ReducerAction<R>>>(itemName: string, reducer: R, initialState: ReducerState<R>, queryStateOpts?: QueryStateOpts): [ReducerState<R>, QueryDispatch<ReducerAction<R>>]; | ||
| export declare function useQueryReducer<R extends Reducer<ReducerState<R>, ReducerAction<R>>, InitialArg>(itemName: string, reducer: R, initialArg: InitialArg, initStateFn: (initialArg: InitialArg) => ReducerState<R>, queryStateOpts?: QueryStateOpts): [ReducerState<R>, QueryDispatch<ReducerAction<R>>]; |
+179
-120
@@ -11,14 +11,14 @@ 'use strict'; | ||
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| Copyright (c) Microsoft Corporation. | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| Permission to use, copy, modify, and/or distribute this software for any | ||
| purpose with or without fee is hereby granted. | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
| REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
| AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
| INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
| LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
| OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
| PERFORMANCE OF THIS SOFTWARE. | ||
| ***************************************************************************** */ | ||
@@ -75,71 +75,54 @@ | ||
| function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| var queryStringInterface = queryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| var queryString = activeQSI.getQueryString(); | ||
| var _a = react.useState(), setLatestMergedQueryString = _a[1]; | ||
| var queryState = react.useMemo(function () { return (__assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
| var ref = react.useRef({ | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }); | ||
| var setQueryState = react.useCallback(function (newState, opts) { | ||
| var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
| var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
| var stripOverwrite = {}; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| Object.entries(newState).forEach(function (_a) { | ||
| var key = _a[0]; | ||
| if (defaultQueryState[key] === newState[key]) { | ||
| stripOverwrite[key] = null; | ||
| } | ||
| }); | ||
| } | ||
| // retrieve the last value (by re-executing the search getter) | ||
| var currentQueryState = __assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(activeQSI.getQueryString())); | ||
| var mergedQueryString = queryStateCore.createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
| activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
| // triggers an update (in case the QueryStringInterface misses to do so) | ||
| setLatestMergedQueryString(mergedQueryString); | ||
| }, []); | ||
| react.useEffect(function () { | ||
| ref.current = { | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }; | ||
| }); | ||
| return [queryState, setQueryState]; | ||
| function useRefLatest(value) { | ||
| var ref = react.useRef(value); | ||
| react.useLayoutEffect(function () { | ||
| ref.current = value; | ||
| }, [value]); | ||
| return ref; | ||
| } | ||
| function sameAsJsonString(compareValueA, compareValueB) { | ||
| return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
| } | ||
| function useQueryState(itemName, defaultValue, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| defaultValue = react.useState(defaultValue)[0]; | ||
| var defaultQueryStateValue = queryStateCore.toQueryStateValue(defaultValue); | ||
| var defaultQueryState = react.useMemo(function () { | ||
| var _a; | ||
| return defaultQueryStateValue | ||
| ? (_a = {}, | ||
| _a[itemName] = defaultQueryStateValue, | ||
| _a) : {}; | ||
| }, [itemName, defaultQueryStateValue]); | ||
| var queryStateOptsDefaults = Object.freeze({}); | ||
| function useQueryReducer(itemName, reducer, initialStateOrInitialArg, initStateFnOrOpts, queryStateOpts) { | ||
| var _a; | ||
| var mergedQueryStateOpts = Object.assign({}, queryStateOptsDefaults, queryStateOpts, typeof initStateFnOrOpts === 'object' ? initStateFnOrOpts : null); | ||
| var queryStringInterface = mergedQueryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface ? { disabled: true } : undefined); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| // itemName & defaultValue is not allowed to be changed after init | ||
| var defaultValue = react.useState(function () { | ||
| return initStateFnOrOpts && typeof initStateFnOrOpts === 'function' | ||
| ? initStateFnOrOpts(initialStateOrInitialArg) | ||
| : initialStateOrInitialArg; | ||
| })[0]; | ||
| var defaultQueryStateValue = react.useMemo(function () { return queryStateCore.toQueryStateValue(defaultValue); }, [defaultValue]); | ||
| if (defaultQueryStateValue === null) { | ||
| throw new Error('unsupported defaultValue'); | ||
| } | ||
| var _a = useQueryStateObj(defaultQueryState, queryStateOpts), queryState = _a[0], setQueryState = _a[1]; | ||
| var setQueryStateItem = react.useCallback(function (newValue, opts) { | ||
| var ref = useRefLatest({ | ||
| activeQSI: activeQSI, | ||
| defaultValue: defaultValue, | ||
| mergedQueryStateOpts: mergedQueryStateOpts, | ||
| reducer: reducer, | ||
| }); | ||
| var resetQueryStateItem = react.useCallback(function (opts) { | ||
| var _a; | ||
| // stringify the given value (or array of strings) | ||
| var activeQSI = ref.current.activeQSI; | ||
| var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var newState = __assign(__assign({}, currentState), (_a = {}, _a[itemName] = null, _a)); | ||
| activeQSI.setQueryString(queryStateCore.createMergedQuery(newState), opts); | ||
| setR(function (rC) { return rC + 1; }); | ||
| }, [itemName, ref]); | ||
| var _b = react.useState(0), setR = _b[1]; | ||
| var dispatch = react.useCallback(function (action, opts) { | ||
| var _a; | ||
| if (opts === void 0) { opts = {}; } | ||
| var _b = ref.current, activeQSI = _b.activeQSI, defaultValue = _b.defaultValue, mergedQueryStateOpts = _b.mergedQueryStateOpts, reducer = _b.reducer; | ||
| var _c = mergedQueryStateOpts.stripDefaults, stripDefaults = _c === void 0 ? true : _c; | ||
| var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var currentValue = itemName in currentState | ||
| ? queryStateCore.parseQueryStateValue(currentState[itemName], defaultValue) | ||
| : defaultValue; | ||
| var newValue = reducer(currentValue !== null && currentValue !== void 0 ? currentValue : defaultValue, action); | ||
| var newQueryStateValue = queryStateCore.toQueryStateValue(newValue); | ||
| // warn when value type is not supported (do not warn when null was passed explicitly) | ||
| if ((newQueryStateValue === null && newValue !== newQueryStateValue) || | ||
| !(newQueryStateValue !== null && | ||
| typeof queryStateCore.parseQueryStateValue(newQueryStateValue, defaultValue) === typeof defaultValue)) { | ||
| if (newQueryStateValue === null) { | ||
| console.warn('value of ' + | ||
@@ -149,32 +132,40 @@ JSON.stringify(newValue) + | ||
| itemName + | ||
| '" will reset to default value', defaultValue); | ||
| newQueryStateValue = null; | ||
| '" will reset to default value of:', defaultValue); | ||
| } | ||
| // when new value is equal to default, we call setQueryState with a null value to reset query string | ||
| // arrays have to be compared json stringified, other values can compared by value | ||
| if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
| newQueryStateValue = null; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
| return resetQueryStateItem(opts); | ||
| } | ||
| else if (newValue === defaultValue) { | ||
| return resetQueryStateItem(opts); | ||
| } | ||
| } | ||
| else if (newValue === defaultValue) { | ||
| newQueryStateValue = null; | ||
| } | ||
| setQueryState((_a = {}, _a[itemName] = newQueryStateValue, _a), opts); | ||
| }, [defaultValue, itemName, setQueryState]); | ||
| // fallback to default value | ||
| var value = defaultValue; | ||
| var queryStateItem = queryState[itemName]; | ||
| var queryStateValue = null; | ||
| if (queryStateItem || queryStateItem === '') { | ||
| queryStateValue = queryStateCore.parseQueryStateValue(queryStateItem, defaultValue); | ||
| } | ||
| if (queryStateValue !== null && typeof queryStateValue === typeof defaultValue) { | ||
| value = queryStateValue; | ||
| } | ||
| return [value, setQueryStateItem]; | ||
| activeQSI.setQueryString(queryStateCore.createMergedQuery(__assign(__assign({}, currentState), (_a = {}, _a[itemName] = queryStateCore.toQueryStateValue(newValue), _a))), opts); | ||
| // force re-render | ||
| setR(function (rC) { return rC + 1; }); | ||
| }, [itemName, ref, resetQueryStateItem]); | ||
| var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var currentValue = (_a = (itemName in currentState | ||
| ? queryStateCore.parseQueryStateValue(currentState[itemName], defaultValue) | ||
| : defaultValue)) !== null && _a !== void 0 ? _a : defaultValue; | ||
| return [currentValue, dispatch]; | ||
| } | ||
| function sameAsJsonString(compareValueA, compareValueB) { | ||
| return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
| } | ||
| function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
| function useQueryState(itemName, initialState, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| var reducer = react.useCallback(function (prevState, action) { | ||
| if (action && typeof action === 'function') { | ||
| return action(prevState); | ||
| } | ||
| return action; | ||
| }, []); | ||
| if (typeof initialState === 'function') { | ||
| return useQueryReducer(itemName, reducer, undefined, initialState, queryStateOpts); | ||
| } | ||
| return useQueryReducer(itemName, reducer, initialState, queryStateOpts); | ||
| } | ||
@@ -217,7 +208,7 @@ | ||
| return; | ||
| var hashChangeHandler = function () { | ||
| var popstateHandler = function () { | ||
| setR(function (r) { return r + 1; }); | ||
| }; | ||
| window.addEventListener('popstate', hashChangeHandler, false); | ||
| return function () { return window.removeEventListener('popstate', hashChangeHandler, false); }; | ||
| window.addEventListener('popstate', popstateHandler, false); | ||
| return function () { return window.removeEventListener('popstate', popstateHandler, false); }; | ||
| }, [enabled]); | ||
@@ -229,5 +220,12 @@ return locationStateInterface; | ||
| var locationStateOptsDefaults = Object.freeze({}); | ||
| function useLocationState(itemName, defaultValue, _a) { | ||
| var locationStateInterface = (_a === void 0 ? locationStateOptsDefaults : _a).locationStateInterface; | ||
| defaultValue = react.useState(defaultValue)[0]; | ||
| function useLocationReducer(itemName, reducer, initialStateOrInitialArg, maybeInitStateFnOrOpts, opts) { | ||
| var locationStateInterface = (opts || | ||
| (typeof maybeInitStateFnOrOpts === 'object' && maybeInitStateFnOrOpts) || | ||
| locationStateOptsDefaults).locationStateInterface; | ||
| // itemName & defaultValue is not allowed to be changed after init | ||
| var defaultValue = react.useState(function () { | ||
| return maybeInitStateFnOrOpts && typeof maybeInitStateFnOrOpts === 'function' | ||
| ? maybeInitStateFnOrOpts(initialStateOrInitialArg) | ||
| : initialStateOrInitialArg; | ||
| })[0]; | ||
| // throw for invalid values like functions | ||
@@ -238,3 +236,3 @@ if (!validTypes.includes(typeof defaultValue)) { | ||
| itemName = react.useState(function () { | ||
| var suffixObscurer = typeof btoa !== "undefined" ? btoa : (function (s) { return s; }); | ||
| var suffixObscurer = typeof btoa !== 'undefined' ? btoa : function (s) { return s; }; | ||
| var suffix = suffixObscurer(Array.isArray(defaultValue) ? 'array' : typeof defaultValue).replace(/=/g, ''); | ||
@@ -246,4 +244,5 @@ return itemName + "__" + suffix; | ||
| var activeLSI = locationStateInterface || standardLSI; | ||
| var ref = react.useRef({ | ||
| var ref = useRefLatest({ | ||
| activeLSI: activeLSI, | ||
| reducer: reducer, | ||
| }); | ||
@@ -263,17 +262,10 @@ var currentState = activeLSI.getLocationState(); | ||
| activeLSI.setLocationState(newState, opts); | ||
| }, [itemName]); | ||
| var setLocationStateItem = react.useCallback(function (newValueOrFn, opts) { | ||
| }, [itemName, ref]); | ||
| var dispatchAction = react.useCallback(function (action, opts) { | ||
| var _a; | ||
| if (opts === void 0) { opts = {}; } | ||
| var _b = ref.current.activeLSI, getLocationState = _b.getLocationState, setLocationState = _b.setLocationState; | ||
| var newValue; | ||
| var _b = ref.current, reducer = _b.reducer, _c = _b.activeLSI, getLocationState = _c.getLocationState, setLocationState = _c.setLocationState; | ||
| var currentState = getLocationState(); | ||
| var currentValue = itemName in currentState ? currentState[itemName] : defaultValue; | ||
| if (typeof newValueOrFn === 'function') { | ||
| // @ts-ignore | ||
| newValue = newValueOrFn(currentValue); | ||
| } | ||
| else { | ||
| newValue = newValueOrFn; | ||
| } | ||
| var newValue = reducer(currentValue, action); | ||
| if (newValue === defaultValue) { | ||
@@ -290,15 +282,82 @@ return resetLocationStateItem(opts); | ||
| _a); | ||
| setLocationState(__assign(__assign({}, getLocationState()), stateExtendOverwrite), opts); | ||
| }, [defaultValue, itemName, resetLocationStateItem]); | ||
| setLocationState(__assign(__assign({}, currentState), stateExtendOverwrite), opts); | ||
| }, [defaultValue, itemName, ref, resetLocationStateItem]); | ||
| return [value, dispatchAction]; | ||
| } | ||
| var locationStateOptsDefaults$1 = Object.freeze({}); | ||
| function useLocationState(itemName, initialState, opts) { | ||
| if (opts === void 0) { opts = locationStateOptsDefaults$1; } | ||
| if (typeof initialState === 'function') { | ||
| return useLocationReducer(itemName, stateReducer, undefined, initialState, opts); | ||
| } | ||
| return useLocationReducer(itemName, stateReducer, initialState, opts); | ||
| } | ||
| function stateReducer(prevState, action) { | ||
| if (action && typeof action === 'function') { | ||
| return action(prevState); | ||
| } | ||
| return action; | ||
| } | ||
| function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| var queryStringInterface = queryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| var queryString = activeQSI.getQueryString(); | ||
| var _a = react.useState(), setLatestMergedQueryString = _a[1]; | ||
| var queryState = react.useMemo(function () { return (__assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
| var ref = react.useRef({ | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }); | ||
| var setQueryState = react.useCallback(function (newState, opts) { | ||
| var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
| var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
| var stripOverwrite = {}; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| Object.entries(newState).forEach(function (_a) { | ||
| var key = _a[0]; | ||
| if (defaultQueryState[key] === newState[key]) { | ||
| stripOverwrite[key] = null; | ||
| } | ||
| }); | ||
| } | ||
| // retrieve the last value (by re-executing the search getter) | ||
| var currentQueryState = __assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(activeQSI.getQueryString())); | ||
| var mergedQueryString = queryStateCore.createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
| activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
| // triggers an update (in case the QueryStringInterface misses to do so) | ||
| setLatestMergedQueryString(mergedQueryString); | ||
| }, []); | ||
| react.useEffect(function () { | ||
| ref.current = { | ||
| activeLSI: activeLSI, | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }; | ||
| }); | ||
| return [value, setLocationStateItem]; | ||
| return [queryState, setQueryState]; | ||
| } | ||
| function useHashQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryStateObj(defaultQueryState, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| } | ||
| function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| } | ||
| exports.LOCATION_STATE_KEY = LOCATION_STATE_KEY; | ||
| exports.useHashQueryState = useHashQueryState; | ||
| exports.useHashQueryStateObj = useHashQueryStateObj; | ||
| exports.useLocationReducer = useLocationReducer; | ||
| exports.useLocationState = useLocationState; | ||
| exports.useQueryReducer = useQueryReducer; | ||
| exports.useQueryState = useQueryState; |
| export * from './useQueryState/useQueryState.types'; | ||
| export * from './useLocationState/useLocationState.types'; | ||
| export { default as useQueryState } from './useQueryState/useQueryState'; | ||
| export { default as useHashQueryState } from './useQueryState/useHashQueryState'; | ||
| export { default as useLocationState } from './useLocationState/useLocationState'; | ||
| export * from './types/sharedTypes'; | ||
| export * from './useQueryState/useQueryState'; | ||
| export * from './useQueryState/useQueryReducer'; | ||
| export * from './useLocationState/useLocationState'; | ||
| export * from './useLocationState/useLocationReducer'; | ||
| export * from './useQueryState/useHashQueryState'; |
+179
-123
@@ -1,3 +0,3 @@ | ||
| import { useMemo, useState, useEffect, useRef, useCallback } from 'react'; | ||
| import { parseQueryState, createMergedQuery, toQueryStateValue, parseQueryStateValue } from 'query-state-core'; | ||
| import { useMemo, useState, useEffect, useRef, useLayoutEffect, useCallback } from 'react'; | ||
| import { toQueryStateValue, parseQueryState, createMergedQuery, parseQueryStateValue } from 'query-state-core'; | ||
@@ -7,14 +7,14 @@ var LOCATION_STATE_KEY = '__useLocationState'; | ||
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| Copyright (c) Microsoft Corporation. | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| Permission to use, copy, modify, and/or distribute this software for any | ||
| purpose with or without fee is hereby granted. | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
| REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
| AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
| INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
| LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
| OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
| PERFORMANCE OF THIS SOFTWARE. | ||
| ***************************************************************************** */ | ||
@@ -71,71 +71,54 @@ | ||
| function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| var queryStringInterface = queryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| var queryString = activeQSI.getQueryString(); | ||
| var _a = useState(), setLatestMergedQueryString = _a[1]; | ||
| var queryState = useMemo(function () { return (__assign(__assign({}, defaultQueryState), parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
| var ref = useRef({ | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }); | ||
| var setQueryState = useCallback(function (newState, opts) { | ||
| var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
| var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
| var stripOverwrite = {}; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| Object.entries(newState).forEach(function (_a) { | ||
| var key = _a[0]; | ||
| if (defaultQueryState[key] === newState[key]) { | ||
| stripOverwrite[key] = null; | ||
| } | ||
| }); | ||
| } | ||
| // retrieve the last value (by re-executing the search getter) | ||
| var currentQueryState = __assign(__assign({}, defaultQueryState), parseQueryState(activeQSI.getQueryString())); | ||
| var mergedQueryString = createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
| activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
| // triggers an update (in case the QueryStringInterface misses to do so) | ||
| setLatestMergedQueryString(mergedQueryString); | ||
| }, []); | ||
| useEffect(function () { | ||
| ref.current = { | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }; | ||
| }); | ||
| return [queryState, setQueryState]; | ||
| function useRefLatest(value) { | ||
| var ref = useRef(value); | ||
| useLayoutEffect(function () { | ||
| ref.current = value; | ||
| }, [value]); | ||
| return ref; | ||
| } | ||
| function sameAsJsonString(compareValueA, compareValueB) { | ||
| return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
| } | ||
| function useQueryState(itemName, defaultValue, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| defaultValue = useState(defaultValue)[0]; | ||
| var defaultQueryStateValue = toQueryStateValue(defaultValue); | ||
| var defaultQueryState = useMemo(function () { | ||
| var _a; | ||
| return defaultQueryStateValue | ||
| ? (_a = {}, | ||
| _a[itemName] = defaultQueryStateValue, | ||
| _a) : {}; | ||
| }, [itemName, defaultQueryStateValue]); | ||
| var queryStateOptsDefaults = Object.freeze({}); | ||
| function useQueryReducer(itemName, reducer, initialStateOrInitialArg, initStateFnOrOpts, queryStateOpts) { | ||
| var _a; | ||
| var mergedQueryStateOpts = Object.assign({}, queryStateOptsDefaults, queryStateOpts, typeof initStateFnOrOpts === 'object' ? initStateFnOrOpts : null); | ||
| var queryStringInterface = mergedQueryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface ? { disabled: true } : undefined); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| // itemName & defaultValue is not allowed to be changed after init | ||
| var defaultValue = useState(function () { | ||
| return initStateFnOrOpts && typeof initStateFnOrOpts === 'function' | ||
| ? initStateFnOrOpts(initialStateOrInitialArg) | ||
| : initialStateOrInitialArg; | ||
| })[0]; | ||
| var defaultQueryStateValue = useMemo(function () { return toQueryStateValue(defaultValue); }, [defaultValue]); | ||
| if (defaultQueryStateValue === null) { | ||
| throw new Error('unsupported defaultValue'); | ||
| } | ||
| var _a = useQueryStateObj(defaultQueryState, queryStateOpts), queryState = _a[0], setQueryState = _a[1]; | ||
| var setQueryStateItem = useCallback(function (newValue, opts) { | ||
| var ref = useRefLatest({ | ||
| activeQSI: activeQSI, | ||
| defaultValue: defaultValue, | ||
| mergedQueryStateOpts: mergedQueryStateOpts, | ||
| reducer: reducer, | ||
| }); | ||
| var resetQueryStateItem = useCallback(function (opts) { | ||
| var _a; | ||
| // stringify the given value (or array of strings) | ||
| var activeQSI = ref.current.activeQSI; | ||
| var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var newState = __assign(__assign({}, currentState), (_a = {}, _a[itemName] = null, _a)); | ||
| activeQSI.setQueryString(createMergedQuery(newState), opts); | ||
| setR(function (rC) { return rC + 1; }); | ||
| }, [itemName, ref]); | ||
| var _b = useState(0), setR = _b[1]; | ||
| var dispatch = useCallback(function (action, opts) { | ||
| var _a; | ||
| if (opts === void 0) { opts = {}; } | ||
| var _b = ref.current, activeQSI = _b.activeQSI, defaultValue = _b.defaultValue, mergedQueryStateOpts = _b.mergedQueryStateOpts, reducer = _b.reducer; | ||
| var _c = mergedQueryStateOpts.stripDefaults, stripDefaults = _c === void 0 ? true : _c; | ||
| var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var currentValue = itemName in currentState | ||
| ? parseQueryStateValue(currentState[itemName], defaultValue) | ||
| : defaultValue; | ||
| var newValue = reducer(currentValue !== null && currentValue !== void 0 ? currentValue : defaultValue, action); | ||
| var newQueryStateValue = toQueryStateValue(newValue); | ||
| // warn when value type is not supported (do not warn when null was passed explicitly) | ||
| if ((newQueryStateValue === null && newValue !== newQueryStateValue) || | ||
| !(newQueryStateValue !== null && | ||
| typeof parseQueryStateValue(newQueryStateValue, defaultValue) === typeof defaultValue)) { | ||
| if (newQueryStateValue === null) { | ||
| console.warn('value of ' + | ||
@@ -145,32 +128,40 @@ JSON.stringify(newValue) + | ||
| itemName + | ||
| '" will reset to default value', defaultValue); | ||
| newQueryStateValue = null; | ||
| '" will reset to default value of:', defaultValue); | ||
| } | ||
| // when new value is equal to default, we call setQueryState with a null value to reset query string | ||
| // arrays have to be compared json stringified, other values can compared by value | ||
| if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
| newQueryStateValue = null; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
| return resetQueryStateItem(opts); | ||
| } | ||
| else if (newValue === defaultValue) { | ||
| return resetQueryStateItem(opts); | ||
| } | ||
| } | ||
| else if (newValue === defaultValue) { | ||
| newQueryStateValue = null; | ||
| } | ||
| setQueryState((_a = {}, _a[itemName] = newQueryStateValue, _a), opts); | ||
| }, [defaultValue, itemName, setQueryState]); | ||
| // fallback to default value | ||
| var value = defaultValue; | ||
| var queryStateItem = queryState[itemName]; | ||
| var queryStateValue = null; | ||
| if (queryStateItem || queryStateItem === '') { | ||
| queryStateValue = parseQueryStateValue(queryStateItem, defaultValue); | ||
| } | ||
| if (queryStateValue !== null && typeof queryStateValue === typeof defaultValue) { | ||
| value = queryStateValue; | ||
| } | ||
| return [value, setQueryStateItem]; | ||
| activeQSI.setQueryString(createMergedQuery(__assign(__assign({}, currentState), (_a = {}, _a[itemName] = toQueryStateValue(newValue), _a))), opts); | ||
| // force re-render | ||
| setR(function (rC) { return rC + 1; }); | ||
| }, [itemName, ref, resetQueryStateItem]); | ||
| var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
| var currentValue = (_a = (itemName in currentState | ||
| ? parseQueryStateValue(currentState[itemName], defaultValue) | ||
| : defaultValue)) !== null && _a !== void 0 ? _a : defaultValue; | ||
| return [currentValue, dispatch]; | ||
| } | ||
| function sameAsJsonString(compareValueA, compareValueB) { | ||
| return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
| } | ||
| function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
| function useQueryState(itemName, initialState, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| var reducer = useCallback(function (prevState, action) { | ||
| if (action && typeof action === 'function') { | ||
| return action(prevState); | ||
| } | ||
| return action; | ||
| }, []); | ||
| if (typeof initialState === 'function') { | ||
| return useQueryReducer(itemName, reducer, undefined, initialState, queryStateOpts); | ||
| } | ||
| return useQueryReducer(itemName, reducer, initialState, queryStateOpts); | ||
| } | ||
@@ -213,7 +204,7 @@ | ||
| return; | ||
| var hashChangeHandler = function () { | ||
| var popstateHandler = function () { | ||
| setR(function (r) { return r + 1; }); | ||
| }; | ||
| window.addEventListener('popstate', hashChangeHandler, false); | ||
| return function () { return window.removeEventListener('popstate', hashChangeHandler, false); }; | ||
| window.addEventListener('popstate', popstateHandler, false); | ||
| return function () { return window.removeEventListener('popstate', popstateHandler, false); }; | ||
| }, [enabled]); | ||
@@ -225,5 +216,12 @@ return locationStateInterface; | ||
| var locationStateOptsDefaults = Object.freeze({}); | ||
| function useLocationState(itemName, defaultValue, _a) { | ||
| var locationStateInterface = (_a === void 0 ? locationStateOptsDefaults : _a).locationStateInterface; | ||
| defaultValue = useState(defaultValue)[0]; | ||
| function useLocationReducer(itemName, reducer, initialStateOrInitialArg, maybeInitStateFnOrOpts, opts) { | ||
| var locationStateInterface = (opts || | ||
| (typeof maybeInitStateFnOrOpts === 'object' && maybeInitStateFnOrOpts) || | ||
| locationStateOptsDefaults).locationStateInterface; | ||
| // itemName & defaultValue is not allowed to be changed after init | ||
| var defaultValue = useState(function () { | ||
| return maybeInitStateFnOrOpts && typeof maybeInitStateFnOrOpts === 'function' | ||
| ? maybeInitStateFnOrOpts(initialStateOrInitialArg) | ||
| : initialStateOrInitialArg; | ||
| })[0]; | ||
| // throw for invalid values like functions | ||
@@ -234,3 +232,3 @@ if (!validTypes.includes(typeof defaultValue)) { | ||
| itemName = useState(function () { | ||
| var suffixObscurer = typeof btoa !== "undefined" ? btoa : (function (s) { return s; }); | ||
| var suffixObscurer = typeof btoa !== 'undefined' ? btoa : function (s) { return s; }; | ||
| var suffix = suffixObscurer(Array.isArray(defaultValue) ? 'array' : typeof defaultValue).replace(/=/g, ''); | ||
@@ -242,4 +240,5 @@ return itemName + "__" + suffix; | ||
| var activeLSI = locationStateInterface || standardLSI; | ||
| var ref = useRef({ | ||
| var ref = useRefLatest({ | ||
| activeLSI: activeLSI, | ||
| reducer: reducer, | ||
| }); | ||
@@ -259,17 +258,10 @@ var currentState = activeLSI.getLocationState(); | ||
| activeLSI.setLocationState(newState, opts); | ||
| }, [itemName]); | ||
| var setLocationStateItem = useCallback(function (newValueOrFn, opts) { | ||
| }, [itemName, ref]); | ||
| var dispatchAction = useCallback(function (action, opts) { | ||
| var _a; | ||
| if (opts === void 0) { opts = {}; } | ||
| var _b = ref.current.activeLSI, getLocationState = _b.getLocationState, setLocationState = _b.setLocationState; | ||
| var newValue; | ||
| var _b = ref.current, reducer = _b.reducer, _c = _b.activeLSI, getLocationState = _c.getLocationState, setLocationState = _c.setLocationState; | ||
| var currentState = getLocationState(); | ||
| var currentValue = itemName in currentState ? currentState[itemName] : defaultValue; | ||
| if (typeof newValueOrFn === 'function') { | ||
| // @ts-ignore | ||
| newValue = newValueOrFn(currentValue); | ||
| } | ||
| else { | ||
| newValue = newValueOrFn; | ||
| } | ||
| var newValue = reducer(currentValue, action); | ||
| if (newValue === defaultValue) { | ||
@@ -286,12 +278,76 @@ return resetLocationStateItem(opts); | ||
| _a); | ||
| setLocationState(__assign(__assign({}, getLocationState()), stateExtendOverwrite), opts); | ||
| }, [defaultValue, itemName, resetLocationStateItem]); | ||
| setLocationState(__assign(__assign({}, currentState), stateExtendOverwrite), opts); | ||
| }, [defaultValue, itemName, ref, resetLocationStateItem]); | ||
| return [value, dispatchAction]; | ||
| } | ||
| var locationStateOptsDefaults$1 = Object.freeze({}); | ||
| function useLocationState(itemName, initialState, opts) { | ||
| if (opts === void 0) { opts = locationStateOptsDefaults$1; } | ||
| if (typeof initialState === 'function') { | ||
| return useLocationReducer(itemName, stateReducer, undefined, initialState, opts); | ||
| } | ||
| return useLocationReducer(itemName, stateReducer, initialState, opts); | ||
| } | ||
| function stateReducer(prevState, action) { | ||
| if (action && typeof action === 'function') { | ||
| return action(prevState); | ||
| } | ||
| return action; | ||
| } | ||
| function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| var queryStringInterface = queryStateOpts.queryStringInterface; | ||
| var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
| var activeQSI = queryStringInterface || hashQSI; | ||
| var queryString = activeQSI.getQueryString(); | ||
| var _a = useState(), setLatestMergedQueryString = _a[1]; | ||
| var queryState = useMemo(function () { return (__assign(__assign({}, defaultQueryState), parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
| var ref = useRef({ | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }); | ||
| var setQueryState = useCallback(function (newState, opts) { | ||
| var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
| var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
| var stripOverwrite = {}; | ||
| // when a params are set to the same value as in the defaults | ||
| // we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
| if (stripDefaults) { | ||
| Object.entries(newState).forEach(function (_a) { | ||
| var key = _a[0]; | ||
| if (defaultQueryState[key] === newState[key]) { | ||
| stripOverwrite[key] = null; | ||
| } | ||
| }); | ||
| } | ||
| // retrieve the last value (by re-executing the search getter) | ||
| var currentQueryState = __assign(__assign({}, defaultQueryState), parseQueryState(activeQSI.getQueryString())); | ||
| var mergedQueryString = createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
| activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
| // triggers an update (in case the QueryStringInterface misses to do so) | ||
| setLatestMergedQueryString(mergedQueryString); | ||
| }, []); | ||
| useEffect(function () { | ||
| ref.current = { | ||
| activeLSI: activeLSI, | ||
| defaultQueryState: defaultQueryState, | ||
| queryStateOpts: queryStateOpts, | ||
| activeQSI: activeQSI, | ||
| }; | ||
| }); | ||
| return [value, setLocationStateItem]; | ||
| return [queryState, setQueryState]; | ||
| } | ||
| export { LOCATION_STATE_KEY, useHashQueryState, useLocationState, useQueryState }; | ||
| function useHashQueryStateObj(defaultQueryState, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryStateObj(defaultQueryState, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| } | ||
| function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
| if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
| var hashQSI = useHashQueryStringInterface(); | ||
| return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
| } | ||
| export { LOCATION_STATE_KEY, useHashQueryState, useHashQueryStateObj, useLocationReducer, useLocationState, useQueryReducer, useQueryState }; |
@@ -1,2 +0,4 @@ | ||
| import { LocationStateOpts, SetLocationState } from './useLocationState.types'; | ||
| export default function useLocationState<S>(itemName: string, defaultValue: S | (() => S), { locationStateInterface }?: LocationStateOpts): [S, SetLocationState<S>]; | ||
| import { LocationStateOpts } from './useLocationState.types'; | ||
| import { LocationDispatch } from './useLocationReducer'; | ||
| import { LazyValueFn, SetStateAction } from '../types/sharedTypes'; | ||
| export declare function useLocationState<S>(itemName: string, initialState: S | LazyValueFn<S>, opts?: LocationStateOpts): [S, LocationDispatch<SetStateAction<S>>]; |
@@ -0,1 +1,2 @@ | ||
| import { SetStateAction } from '../types/sharedTypes'; | ||
| export declare const LOCATION_STATE_KEY = "__useLocationState"; | ||
@@ -14,4 +15,2 @@ export declare type LocationStateValue<K = unknown> = string | number | boolean | undefined | Date | Array<K>; | ||
| } | ||
| declare type SetStateAction<S> = S | ((prevState: S) => S); | ||
| export declare type SetLocationState<T> = (newValue: SetStateAction<T>, opts?: SetLocationStateOptions) => void; | ||
| export {}; |
| import { QueryState } from 'query-state-core'; | ||
| import { QueryStateOptsSetInterface } from './useQueryState.types'; | ||
| import { QueryStateOptsSetInterface, QueryStateType } from './useQueryState.types'; | ||
| export declare function useHashQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts?: QueryStateOptsSetInterface): [Record<string, import("query-state-core").QueryStateValue>, import("./useQueryState.types").SetQueryStateFn<T>]; | ||
| export default function useHashQueryState<T>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOptsSetInterface): [T, import("./useQueryState.types").SetQueryStateItemFn<T>]; | ||
| export declare function useHashQueryState<T extends QueryStateType>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOptsSetInterface): [T, import("./useQueryReducer").QueryDispatch<import("../use-location-state").SetStateAction<T>>]; |
@@ -1,2 +0,4 @@ | ||
| import { QueryStateOpts, SetQueryStateItemFn } from './useQueryState.types'; | ||
| export default function useQueryState<T>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOpts): [T, SetQueryStateItemFn<T>]; | ||
| import { QueryStateOpts } from './useQueryState.types'; | ||
| import { QueryDispatch } from './useQueryReducer'; | ||
| import { LazyValueFn, SetStateAction } from '../types/sharedTypes'; | ||
| export declare function useQueryState<S>(itemName: string, initialState: S | LazyValueFn<S>, queryStateOpts?: QueryStateOpts): [S, QueryDispatch<SetStateAction<S>>]; |
| import { QueryStateMerge } from 'query-state-core'; | ||
| export declare type QueryString = string; | ||
| export declare type SetQueryStateFn<T> = (newState: QueryStateMerge, opts?: SetQueryStringOptions) => void; | ||
| export declare type SetQueryStateItemFn<T> = (newValue: T, opts?: SetQueryStringOptions) => void; | ||
| export interface QueryStringInterface { | ||
@@ -19,1 +18,2 @@ getQueryString: () => QueryString; | ||
| }; | ||
| export declare type QueryStateType = string | number | boolean | Date | string[]; |
| import { QueryState } from 'query-state-core'; | ||
| import { QueryStateOpts, SetQueryStateFn } from './useQueryState.types'; | ||
| export default function useQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts: QueryStateOpts): [QueryState, SetQueryStateFn<T>]; | ||
| export declare function useQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts: QueryStateOpts): [QueryState, SetQueryStateFn<T>]; |
+7
-7
@@ -11,5 +11,5 @@ { | ||
| "dependencies": { | ||
| "query-state-core": "^2.3.0" | ||
| "query-state-core": "^2.4.0" | ||
| }, | ||
| "version": "2.3.1", | ||
| "version": "2.4.0", | ||
| "author": "Felix Leupold <felix@xiel.de>", | ||
@@ -21,6 +21,6 @@ "homepage": "https://github.com/xiel/use-location-state", | ||
| "react": "^16.9.0", | ||
| "rollup": "^1.19.3", | ||
| "rollup-plugin-typescript2": "^0.24.0", | ||
| "tslib": "^1.9.3", | ||
| "typescript": "^3.6.3" | ||
| "rollup": ">=2.0.0", | ||
| "rollup-plugin-typescript2": ">=0.26.0", | ||
| "tslib": "*", | ||
| "typescript": "*" | ||
| }, | ||
@@ -43,3 +43,3 @@ "files": [ | ||
| }, | ||
| "gitHead": "2248d0e2266c0e971551fe70bcf82fb6941ff2c2" | ||
| "gitHead": "378cd4bffb30a0f96f0d68b1959fb5050114a5cc" | ||
| } |
+39
-15
@@ -1,5 +0,6 @@ | ||
| <h1 style="width: 100%; text-align: center;"> { useLocationState, useQueryState }</h1> | ||
| <div style="width: 100%; text-align: center;"> | ||
| <h1>{ useLocationState, useQueryState }</h1> | ||
| </div> | ||
| [](https://www.npmjs.com/package/use-location-state) | ||
| [](https://greenkeeper.io/) | ||
| [](https://codecov.io/gh/xiel/use-location-state) | ||
@@ -15,7 +16,7 @@  | ||
| - makes it easy to share the application in a customizable state | ||
| - __`useLocationState(name, defaultValue)`__ | ||
| - **`useLocationState(name, defaultValue)`** | ||
| - restores the latest value after navigation actions (back/forward), by keeping value in `history.state` | ||
| - supported value types: `string | number | boolean | Date | Array | Object` | ||
| - handles complex & nested values - all values that can be serialized are supported | ||
| - __`useQueryState(name, defaultValue)`__ | ||
| - **`useQueryState(name, defaultValue)`** | ||
| - restores the latest value from URL (`location.href`) and after navigation actions (back/forward) | ||
@@ -25,3 +26,2 @@ - supported value types: `string | number | boolean | Date | string[]` | ||
| - invalid entries from the query string are discarded and the component will receive the defaultValue instead | ||
@@ -36,9 +36,9 @@ <img style="display: block; margin: auto;" src="https://repository-images.githubusercontent.com/182417896/058a9d00-e2e1-11e9-8467-8923219ec500" /> | ||
| Using __`react-router`__ or another popular router? For the best experience install one of the [router integrations](#router-integration-optional). | ||
| Using **`react-router`** or another popular router? For the best experience install one of the [router integrations](#router-integration-optional). | ||
| ## Usage | ||
| `useLocationState()` and `useQueryState()` work similar to the `useState()` [hook](https://reactjs.org/docs/hooks-overview.html#state-hook), as they also return the current value and a update function in a tuple `[currentValue, updateValueFn]`. | ||
| `useLocationState()` and `useQueryState()` work similar to the `useState()` [hook](https://reactjs.org/docs/hooks-overview.html#state-hook), as they also return the current value and a update function in a tuple `[currentValue, updateValueFn]`. | ||
| The *important difference* is that __you must pass a name__ before your __default value__ for your state. | ||
| The _important difference_ is that **you must pass a name** before your **default value** for your state. | ||
@@ -63,2 +63,3 @@ ```javascript | ||
| ``` | ||
| The updated state will be restored when the pages reloads and after the user navigated to a new page and comes back using a back/forward action. | ||
@@ -68,3 +69,3 @@ | ||
| `useQueryState()` is a great, when you want to store information about the current state of you app in the URL. | ||
| `useQueryState()` is a great, when you want to store information about the current state of you app in the URL. | ||
@@ -74,2 +75,3 @@ ```javascript | ||
| ``` | ||
| The name you pass will be used as a parameter name in the query string, when setting a new value: | ||
@@ -80,2 +82,3 @@ | ||
| ``` | ||
| After calling the update function `setValue()` with a new value, the state will be saved withing the query string of the browser, so that the new state is reproducable after reloads or history navigation (using forward / back button) or by loading the same URL anywhere else. | ||
@@ -92,3 +95,3 @@ | ||
| In cases where you want the updated state to be represented as a __new entry in the history__ you can pass a options object to the set function, with the method property set to `'push'`. | ||
| In cases where you want the updated state to be represented as a **new entry in the history** you can pass a options object to the set function, with the method property set to `'push'`. | ||
@@ -102,2 +105,3 @@ ```javascript | ||
| ### Example | ||
| ```javascript | ||
@@ -110,3 +114,5 @@ import { useQueryState } from 'use-location-state' | ||
| <div> | ||
| <button type="button" onClick={() => setActive(!active)}>Toggle</button> | ||
| <button type="button" onClick={() => setActive(!active)}> | ||
| Toggle | ||
| </button> | ||
| {active && <p>Some active content</p>} | ||
@@ -117,2 +123,3 @@ </div> | ||
| ``` | ||
| <a href="https://codesandbox.io/embed/zqm4o19yrx"> | ||
@@ -122,3 +129,2 @@ <img width="150" alt="Example in CodeSandbox" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
| ### Example with multiple useQueryState hooks in one component | ||
@@ -136,2 +142,3 @@ | ||
| ``` | ||
| <a href="https://codesandbox.io/embed/github/xiel/use-location-state/tree/master/src/examples/use-location-state/?fontsize=14&module=%2Fsrc%2Fpages%2FQueryStateDemo.tsx"> | ||
@@ -145,3 +152,3 @@ <img width="150" alt="Example in CodeSandbox" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
| We plan to provide clean and easy-to-use integrations for all popular routers. | ||
| We plan to provide clean and easy-to-use integrations for all popular routers. | ||
| At the moment we provide integrations for: | ||
@@ -154,9 +161,13 @@ | ||
| ``` | ||
| ```javascript | ||
| import { useLocationState, useQueryState } from 'react-router-use-location-state' | ||
| ``` | ||
| Usage works the same as described above, except that the URL will look like this now: | ||
| ```javascript | ||
| http://localhost:3000/?itemName=different+value | ||
| ``` | ||
| <a href="https://codesandbox.io/s/github/xiel/use-location-state/tree/master/src/examples/react-router-use-location-state?fontsize=14&module=%2Fsrc%2Fpages%2FQueryStateDemo.tsx"> | ||
@@ -166,2 +177,15 @@ <img width="150" alt="Edit react-router-use-location-state-example" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
| ### Gatsby & @reach/router | ||
| Gatsby & Reach Router are supported. Gatsby currently always scrolls up on location (state) changes. To keep the scroll position, when you update location state using the update function of `useLocationState`, add these lines to the **gatsby-browser.js** file in gatsby root folder. | ||
| ```javascript | ||
| // keeps same scroll pos when history state is pushed/replaced (same location === same position) | ||
| // see: https://www.gatsbyjs.org/docs/browser-apis/#shouldUpdateScroll | ||
| exports.shouldUpdateScroll = ({ routerProps, getSavedScrollPosition }) => { | ||
| const currentPosition = getSavedScrollPosition(routerProps.location) | ||
| return currentPosition || true | ||
| } | ||
| ``` | ||
| ### More routers soon - work in progress | ||
@@ -176,4 +200,4 @@ | ||
| ```javascript | ||
| import 'react-app-polyfill/ie11'; | ||
| import 'react-app-polyfill/stable'; | ||
| import 'react-app-polyfill/ie11' | ||
| import 'react-app-polyfill/stable' | ||
| ``` |
Mixed license
LicensePackage contains multiple licenses.
Found 1 instance in 1 package
52247
23.57%31
106.67%0
-100%767
23.91%187
14.72%Updated