mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
public commit
This commit is contained in:
8
app/src/ui/hooks/use-browser-title.ts
Normal file
8
app/src/ui/hooks/use-browser-title.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
export function useBrowserTitle(path: string[] = []) {
|
||||
useLayoutEffect(() => {
|
||||
const prefix = "BKND";
|
||||
document.title = [prefix, ...path].join(" / ");
|
||||
});
|
||||
}
|
||||
18
app/src/ui/hooks/use-event.ts
Normal file
18
app/src/ui/hooks/use-event.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// Userland polyfill while we wait for the forthcoming
|
||||
// https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
|
||||
// Note: "A high-fidelity polyfill for useEvent is not possible because
|
||||
// there is no lifecycle or Hook in React that we can use to switch
|
||||
// .current at the right timing."
|
||||
// So we will have to make do with this "close enough" approach for now.
|
||||
import { useInsertionEffect, useRef } from "react";
|
||||
|
||||
export const useEvent = <Fn>(fn: Fn | ((...args: any[]) => any) | undefined): Fn => {
|
||||
const ref = useRef([fn, (...args) => ref[0](...args)]).current;
|
||||
// Per Dan Abramov: useInsertionEffect executes marginally closer to the
|
||||
// correct timing for ref synchronization than useLayoutEffect on React 18.
|
||||
// See: https://github.com/facebook/react/pull/25881#issuecomment-1356244360
|
||||
useInsertionEffect(() => {
|
||||
ref[0] = fn;
|
||||
});
|
||||
return ref[1];
|
||||
};
|
||||
47
app/src/ui/hooks/use-search.ts
Normal file
47
app/src/ui/hooks/use-search.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
type Static,
|
||||
type StaticDecode,
|
||||
type TSchema,
|
||||
Type,
|
||||
decodeSearch,
|
||||
encodeSearch,
|
||||
parseDecode
|
||||
} from "core/utils";
|
||||
import { isEqual, transform } from "lodash-es";
|
||||
import { useLocation, useSearch as useWouterSearch } from "wouter";
|
||||
|
||||
// @todo: migrate to Typebox
|
||||
export function useSearch<Schema extends TSchema = TSchema>(
|
||||
schema: Schema,
|
||||
defaultValue?: Partial<StaticDecode<Schema>>
|
||||
) {
|
||||
const searchString = useWouterSearch();
|
||||
const [location, navigate] = useLocation();
|
||||
let value: StaticDecode<Schema> = defaultValue ? parseDecode(schema, defaultValue as any) : {};
|
||||
|
||||
if (searchString.length > 0) {
|
||||
value = parseDecode(schema, decodeSearch(searchString));
|
||||
//console.log("search:decode", value);
|
||||
}
|
||||
|
||||
// @todo: add option to set multiple keys at once
|
||||
function set<Key extends keyof Static<Schema>>(key: Key, value: Static<Schema>[Key]): void {
|
||||
//console.log("set", key, value);
|
||||
const update = parseDecode(schema, { ...decodeSearch(searchString), [key]: value });
|
||||
const search = transform(
|
||||
update as any,
|
||||
(result, value, key) => {
|
||||
if (defaultValue && isEqual(value, defaultValue[key])) return;
|
||||
result[key] = value;
|
||||
},
|
||||
{} as Static<Schema>
|
||||
);
|
||||
const encoded = encodeSearch(search, { encode: false });
|
||||
navigate(location + (encoded.length > 0 ? "?" + encoded : ""));
|
||||
}
|
||||
|
||||
return {
|
||||
value: value as Required<StaticDecode<Schema>>,
|
||||
set
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user