@stimulus-library/mixins
Version:
A library of useful controllers for Stimulus
146 lines (145 loc) • 4.25 kB
JavaScript
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,
};
}