@smkit/ui
Version:
UI Kit of SberMarketing
142 lines (141 loc) • 4.33 kB
JavaScript
import { get, derived, writable } from 'svelte/store';
import { isBrowser } from '../utils';
import { z } from 'zod';
export const searchTerm = writable('');
export function cachedDerived(stores, callback, settings) {
let oldValue;
let timeout;
const store = derived(stores, ($stores, set, update) => {
if (JSON.stringify(oldValue) === JSON.stringify($stores))
return;
oldValue = structuredClone($stores);
if (settings?.delay) {
clearTimeout(timeout);
timeout = setTimeout(async () => {
callback($stores, set, update);
}, settings.delay);
}
else {
callback($stores, set, update);
}
});
return store;
}
export function storable(data, storeKey, schema, version = '0') {
const store = writable(data);
if (!isBrowser) {
return store;
}
const { subscribe, set: _set, update } = store;
const key = `storable_${storeKey}_v${version}`;
function set(n) {
schema?.parse(n);
localStorage[key] = JSON.stringify(n);
_set(n);
}
let saved = localStorage[key] ? JSON.parse(localStorage[key]) : data;
const parsed = schema?.safeParse(saved);
if (parsed?.error) {
console.warn(`Found difference between schema and LocalStorage for ${storeKey}:`, parsed.error);
saved = data;
}
set(saved);
return {
subscribe,
set,
update: (callback) => {
const updatedStore = callback(get(store));
set(updatedStore);
}
};
}
export function overridable(store, onChange) {
const update = (updater, sideEffect) => {
store.update((curr) => {
const next = updater(curr);
let res = next;
if (onChange) {
res = onChange({ curr, next });
}
sideEffect && sideEffect(next);
return res;
});
};
const set = (curr) => {
update(() => curr);
};
return {
...store,
update,
set
};
}
export function debouncedWritable(baseValue, delay) {
const { subscribe, set, update } = writable(baseValue);
let timeout;
function delayedSet(newValue) {
clearTimeout(timeout);
timeout = setTimeout(() => {
set(newValue);
}, delay || 100);
}
return { set: delayedSet, subscribe, update };
}
export function urlParamsWritable(value, key = 'saved', compress = false, delay = 100) {
const getSearchParams = (field, url) => {
let decoded = null;
try {
decoded = url.searchParams.get(field);
if (!decoded)
return null;
decoded = decodeURIComponent(decoded);
if (compress) {
decoded = unzipurl(decoded);
}
if (typeof value === 'object') {
decoded = JSON.parse(decoded);
}
}
catch (e) {
console.error(`Unexpected searchParams value for ${field}: ${e}`);
}
return decoded;
};
const encodeJSON = (data) => {
if (compress) {
return zipurl(JSON.stringify(data));
}
return JSON.stringify(data);
};
const updateSearchParams = (kv) => {
if (!isBrowser || !window)
return;
const url = new URL(window.location.toString());
if (!url)
return;
for (const [k, v] of Object.entries(kv)) {
if (v) {
const encodedValue = typeof value === 'object' ? encodeJSON(v) : v.toString();
url.searchParams.set(encodeURIComponent(k), encodeURIComponent(encodedValue));
}
else {
url.searchParams.delete(k);
}
}
history.pushState({}, `updated ${key}`, url);
};
const saved = isBrowser ? getSearchParams(key, new URL(location.href)) || value : value;
const store = writable(saved);
let timeout;
store.subscribe((v) => {
if (!delay) {
updateSearchParams({ [key]: v });
return;
}
clearTimeout(timeout);
timeout = setTimeout(() => {
updateSearchParams({ [key]: v });
}, delay);
});
return store;
}