UNPKG

@stimulus-library/mixins

Version:

A library of useful controllers for Stimulus

146 lines (145 loc) 4.25 kB
import { reactive } from "@stimulus-library/utilities"; import { useEventListener } from "./use_event_listener"; export const StorageSerializers = { boolean: { deserialize: (v) => v === "true", serialize: (v) => String(v), isEmpty: (v) => v === "" || v === null, }, object: { deserialize: (v) => JSON.parse(v), serialize: (v) => { if (typeof v === "string") { return v; } else { return JSON.stringify(v); } }, isEmpty: (v) => { const values = Object.values(JSON.parse(v)); return values.length === 0 || values.every(v => v === "" || v === null); }, }, number: { deserialize: (v) => Number.parseFloat(v), serialize: (v) => String(v), isEmpty: (v) => v === "" || v === null, }, any: { deserialize: (v) => v, serialize: (v) => String(v), isEmpty: (v) => v === "" || v === null, }, string: { deserialize: (v) => v, serialize: (v) => String(v), isEmpty: (v) => v === "" || v === null, }, map: { deserialize: (v) => new Map(JSON.parse(v)), serialize: (v) => JSON.stringify(Array.from(v.entries())), isEmpty: (v) => { const values = Array.from(v.values()); return values.length === 0 || values.every(v => v === "" || v === null); }, }, set: { deserialize: (v) => new Set(JSON.parse(v)), serialize: (v) => JSON.stringify(Array.from(v.entries())), isEmpty: (v) => { const values = Array.from(v.values()); return values.length === 0 || values.every(v => v === "" || v === null); }, }, }; export function useLocalStorage(controller, key, defaultValue, opts) { var _a; let type; const optsMergedWithDefaults = { onChange: null, writeDefaults: true, ...opts, }; const { writeDefaults } = optsMergedWithDefaults; if (defaultValue === null || defaultValue === undefined) { type = "any"; } else if (defaultValue instanceof Set) { type = "set"; } else if (defaultValue instanceof Map) { type = "map"; } else if (typeof defaultValue === "boolean") { type = "boolean"; } else if (typeof defaultValue === "string") { type = "string"; } else if (typeof defaultValue === "object") { type = "object"; } else if (Array.isArray(defaultValue)) { type = "object"; } else if (!Number.isNaN(defaultValue)) { type = "number"; } else { type = "any"; } const onChange = (_a = optsMergedWithDefaults.onChange) === null || _a === void 0 ? void 0 : _a.bind(controller); const data = reactive({ value: defaultValue, }); const storage = localStorage; const serializer = StorageSerializers[type]; const read = () => { const rawValue = storage.getItem(key); if (rawValue == null) { data.value = defaultValue; if (writeDefaults && defaultValue !== null && defaultValue !== undefined) { storage.setItem(key, serializer.serialize(defaultValue)); } } else { data.value = serializer.deserialize(rawValue); } return data.value; }; const write = (value) => { storage.setItem(key, serializer.serialize(value)); if (onChange) { onChange(value, data.value); } data.value = value; }; const clear = () => { storage.removeItem(key); data.value = defaultValue; return data.value; }; const isEmpty = () => { const rawValue = storage.getItem(key); return serializer.isEmpty(rawValue); }; read(); useEventListener(controller, window, "storage", (event) => { if (event.key === key) { write(event.newValue); } }); return { get value() { return read(); }, set value(value) { write(value); }, read, clear, write, isEmpty, }; }