Skip to content

Commit

Permalink
Add options to disable history or to debounce it
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloricciuti committed Jan 13, 2023
1 parent e172196 commit dbe3bb0
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 13 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,37 @@ An url like this `/?state=N4IgbghgNgrgpiAXCAsgTwAQGMD2OoYCO8ATpgA4QkQC2cALnCSAL5
```typescript
$store.state.value; //My cool query parameter
```

## Store options

Both functions accept a configuration object that contains the following properties:

### debounceHistory

The number of milliseconds to delay the writing of the history when the state changes. This is to avoid cluttering the history of the user especially when a store is bound to an input text (every keystroke would cause a new history entry). It defaults to 0. If set a new entry in the history will be added only after `debounceHistory` seconds of "inactivity".

### pushHistory

A boolean defining if the history have to be written at all. If set to false no new history entries will be written to the history stack (the URL will still update but the user will not be able to go back with the browser).

### How to use it

To set the configuration object you can pass it as a third parameter in case of `queryParam` or the second in case of `queryParameters`.

```svelte
<script lang="ts">
import { ssp, queryParameters, queryParam } from "sveltekit-search-params";
const name = queryParam("name", ssp.string(), {
debounceHistory: 500, //a new history entry will be created after 500ms of this store not changing
});
const count = queryParam("count", ssp.number(), {
debounceHistory: 1500, //a new history entry will be created after 1500ms of this store not changing
})
const store = queryParameters({
username: true,
isCool: ssp.boolean(true),
}, {
pushHistory: false, //no new history entries for this store
});
</script>
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sveltekit-search-params",
"version": "0.1.14",
"version": "1.0.0",
"repository": "git+https://github.com/paoloricciuti/sveltekit-search-params.git",
"author": "Paolo Ricciuti",
"license": "MIT",
Expand Down
69 changes: 57 additions & 12 deletions src/lib/sveltekit-search-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,28 @@ import { decompressFromEncodedURIComponent, compressToEncodedURIComponent } from
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function noop<T>(value: T) { }

const GOTO_OPTIONS = {
keepFocus: true,
noScroll: true,
replaceState: true,
};

const GOTO_OPTIONS_PUSH = {
keepFocus: true,
noScroll: true,
replaceState: false,
};


export type EncodeAndDecodeOptions<T = any> = {
encode: (value: T) => string;
decode: (value: string | null) => T | null;
defaultValue?: T,
defaultValue?: T;
};

export type StoreOptions = {
debounceHistory?: number;
pushHistory?: boolean;
};

type LooseAutocomplete<T> = {
Expand Down Expand Up @@ -108,13 +126,23 @@ export const ssp = {
}),
};

type SetTimeout = ReturnType<typeof setTimeout>;

const batchedUpdates = new Set<(query: URLSearchParams) => void>();

let batchTimeout: ReturnType<typeof setTimeout>;
let batchTimeout: SetTimeout;

const defaultedParams = new Set<string>();

export function queryParameters<T extends object>(options?: Options<T>): Writable<LooseAutocomplete<T>> {
const debouncedTimeouts = new Map<string, SetTimeout>();

export function queryParameters<T extends object>(
options?: Options<T>,
{
debounceHistory = 0,
pushHistory = true,
}: StoreOptions = {},
): Writable<LooseAutocomplete<T>> {
const { set: _set, subscribe } = writable<LooseAutocomplete<T>>();
const setRef: { value: Writable<T>["set"]; } = { value: noop };
const unsubPage = page.subscribe(($page) => {
Expand All @@ -141,10 +169,13 @@ export function queryParameters<T extends object>(options?: Options<T>): Writabl
batchedUpdates.forEach((batched) => {
batched(query);
});
goto(`?${query}`, {
keepFocus: true,
noScroll: true,
});
goto(`?${query}`, GOTO_OPTIONS);
clearTimeout(debouncedTimeouts.get("queryParameters"));
if (pushHistory) {
debouncedTimeouts.set("queryParameters", setTimeout(() => {
goto("", GOTO_OPTIONS_PUSH);
}, debounceHistory));
}
batchedUpdates.clear();
});
};
Expand Down Expand Up @@ -181,7 +212,18 @@ const DEFAULT_ENCODER_DECODER: EncodeAndDecodeOptions = {
decode: (value: string | null) => value ? value.toString() : null,
};

export function queryParam<T = string>(name: string, { encode: encode = DEFAULT_ENCODER_DECODER.encode, decode: decode = DEFAULT_ENCODER_DECODER.decode, defaultValue }: EncodeAndDecodeOptions<T> = DEFAULT_ENCODER_DECODER): Writable<T | null> {
export function queryParam<T = string>(
name: string,
{
encode: encode = DEFAULT_ENCODER_DECODER.encode,
decode: decode = DEFAULT_ENCODER_DECODER.decode,
defaultValue
}: EncodeAndDecodeOptions<T> = DEFAULT_ENCODER_DECODER,
{
debounceHistory = 0,
pushHistory = true,
}: StoreOptions = {}
): Writable<T | null> {
const { set: _set, subscribe } = writable<T | null>();
const setRef: { value: Writable<T | null>["set"]; } = { value: noop };
const unsubPage = page.subscribe(($page) => {
Expand All @@ -201,10 +243,13 @@ export function queryParam<T = string>(name: string, { encode: encode = DEFAULT_
batchedUpdates.forEach((batched) => {
batched(query);
});
goto(`?${query}`, {
keepFocus: true,
noScroll: true,
});
goto(`?${query}`, GOTO_OPTIONS);
clearTimeout(debouncedTimeouts.get(name));
if (pushHistory) {
debouncedTimeouts.set(name, setTimeout(() => {
goto("", GOTO_OPTIONS_PUSH);
}, debounceHistory));
}
batchedUpdates.clear();
});
};
Expand Down

0 comments on commit dbe3bb0

Please sign in to comment.