solid-new-bucket
Version:
Better Signal API for SolidJS
595 lines (584 loc) • 13.9 kB
JavaScript
// src/arrayHelpers.ts
function removeElementsFromArray(arr, filter) {
const idx = [];
arr.forEach((t, i) => {
if (filter(t)) {
idx.push(i);
}
});
return idx.map((i) => arr.splice(i, 1)[0]);
}
function copyOfRange(arr, start, end) {
const r = [];
start = Math.max(0, start);
end = Math.min(arr.length, end);
for (let i = start; i < end; i++) {
r.push(arr[i]);
}
return r;
}
function indexOf(arr, test) {
for (let i = 0; i < arr.length; i++) {
if (test(arr[i])) {
return i;
}
}
return -1;
}
// src/buckets.ts
import { createSignal, createMemo, splitProps, untrack } from "solid-js";
function stampedBucket(value, options) {
if (options?.localStorageName) {
const raw = localStorage.getItem(options.localStorageName);
if (raw) {
if (raw === "undefined") {
value = void 0;
} else {
value = JSON.parse(raw);
}
}
}
const [timestamp, setTimestamp] = createSignal(performance.now());
const v = createMemo(() => {
return {
timestamp: timestamp(),
data: value,
markChanged() {
setTimestamp(performance.now());
}
};
});
const setV = (newValue) => {
value = newValue;
setTimestamp((/* @__PURE__ */ new Date()).getTime());
};
const call = function(updater) {
if (updater) {
options?.beforeUpdate?.(value);
updater(value);
if (options?.localStorageName) {
localStorage.setItem(options.localStorageName, JSON.stringify(value));
}
setTimestamp((/* @__PURE__ */ new Date()).getTime());
options?.afterUpdate?.(value);
}
return v().data;
};
call.map = (mapper) => {
return mapper(v().data);
};
call.markChanged = () => {
setTimestamp((/* @__PURE__ */ new Date()).getTime());
};
call.reset = (v2) => {
setV(v2);
};
return call;
}
function getFieldOfObject(o, paths) {
for (let i = 0; i < paths.length - 1; i++) {
o = o[paths[i]];
if (!o) {
throw new Error(`cannot find ${paths.join(".")} in ${o}`);
}
}
return o[paths[paths.length - 1]];
}
function setFieldOfObject(o, newValue, paths) {
for (let i = 0; i < paths.length - 1; i++) {
o = o[paths[i]];
if (!o) {
throw new Error(`cannot find ${paths.join(".")} in ${o}`);
}
}
o[paths[paths.length - 1]] = newValue;
}
function asBucket(s, path, mapper) {
const getField = (data) => {
let v = getFieldOfObject(data, path);
return mapper ? mapper.from?.(v) : v;
};
const setField = (data, v) => {
if (mapper) {
v = mapper.to?.(v);
}
setFieldOfObject(data, v, path);
};
return (t) => {
if (t != void 0) {
s((data) => {
if (typeof t === "function") {
const oldValue = getField(data);
setField(data, t(oldValue));
} else {
setField(data, t);
}
});
}
return getField(s());
};
}
function asAccessor(v, k) {
return () => {
if (typeof v === "function") {
return v()[k];
}
return v[k];
};
}
function bucket(value, options) {
if (options?.useValueAsAccessor && typeof value === "function") {
const [_, others2] = splitProps(options, ["useValueAsAccessor"]);
const memo = createMemo(() => bucket(value(), others2));
return (t) => {
return memo()(t);
};
}
const [local, others] = options && splitProps(options, ["beforeUpdate", "afterUpdate", "localStorageName"]) || [];
if (local?.localStorageName) {
const raw = localStorage.getItem(local.localStorageName);
if (raw !== null) {
if (raw === "undefined") {
value = void 0;
} else {
value = JSON.parse(raw);
}
}
}
const [v, setV] = createSignal(value, others);
const b = function(t) {
if (t !== void 0) {
const newValue = setV((prev) => {
local?.beforeUpdate?.(prev);
if (typeof t === "function") {
return t(prev);
} else {
return t;
}
});
if (local?.localStorageName) {
localStorage.setItem(local.localStorageName, JSON.stringify(newValue));
}
local?.afterUpdate?.(newValue);
return newValue;
}
return v();
};
Object.defineProperty(b, "value", {
get: function() {
return untrack(v);
}
});
return b;
}
// src/checks.ts
function isNotEmpty(v) {
if (!v) return false;
if (typeof v === "string") {
return v.length > 0;
}
if (typeof v === "object") {
if (Array.isArray(v)) {
return v.length > 0;
}
return Object.keys(v).length > 0;
}
return false;
}
function isNumber(v) {
return typeof v === "number";
}
function compareDateString(a, b) {
return Date.parse(a) - Date.parse(b);
}
function containsAny(a, b) {
for (let i of a) {
for (let j of b) {
if (i === j) {
return true;
}
}
}
return false;
}
// src/wrappers.ts
function wrapDateNumber(v, bits = 2) {
if (v == 0) {
return "0".repeat(bits);
}
let n = v;
while (n > 0) {
n = Math.floor(n / 10);
bits--;
}
return bits > 0 ? "0".repeat(bits) + v : v;
}
function wrapString(v) {
if (typeof v === "string") {
return v;
}
return v?.toString() || "";
}
function wrapNumber(v) {
if (typeof v === "number") {
return v;
}
return 0;
}
// src/converters.ts
function parseTimestamp(timestamp, showTime, showMilliseconds) {
const date = new Date(timestamp);
let r = `${wrapDateNumber(date.getFullYear())}-${wrapDateNumber(date.getMonth() + 1)}-${wrapDateNumber(date.getDate())}`;
if (showTime) {
r += ` ${wrapDateNumber(date.getHours())}:${wrapDateNumber(date.getMinutes())}:${wrapDateNumber(date.getSeconds())}`;
}
if (showMilliseconds) {
r += `.${wrapDateNumber(date.getMilliseconds(), 3)}`;
}
;
return r;
}
function toCapital(v) {
return v.charAt(0).toUpperCase() + v.substring(1);
}
// src/generators.ts
function sequence(start, end, step = 1) {
const r = [];
for (let i = start; i < end; i += step) {
r.push(i);
}
return r;
}
function iterate(size) {
return Array.from(Array(size).keys());
}
// src/others.ts
import { createContext, useContext } from "solid-js";
function useCtx(c, displayName) {
const context2 = useContext(c);
if (!context2) {
throw new Error("cannot find a context of " + (displayName || "unknown"));
}
return context2;
}
function context(displayName) {
const ctx = createContext();
const use = function() {
return useCtx(ctx, displayName);
};
return [ctx, use];
}
function names(...v) {
return v.filter((name) => Boolean(name)).join(" ");
}
function clone(obj) {
const type = typeof obj;
switch (type) {
case "object": {
let r = Array.isArray(obj) ? [] : {};
for (let key of Object.keys(obj)) {
r[key] = clone(obj[key]);
}
return r;
}
default:
return obj;
}
}
// src/conditionals.ts
function conditional(condition, value, defaultValue) {
if (typeof value === "function") {
if (condition) {
const r = value();
if (r) {
return r;
}
}
return defaultValue;
}
if (typeof (value === "string")) {
return condition ? value : defaultValue || "";
}
if (typeof value === "number") {
return condition ? value : defaultValue || 0;
}
if (condition) {
return value;
} else if (defaultValue !== void 0 && defaultValue !== null) {
return defaultValue;
}
}
// src/Handle.ts
import { onCleanup as onCleanup2, onMount, untrack as untrack2 } from "solid-js";
// src/Disposable.ts
import { onCleanup } from "solid-js";
var DisposableSupport = class {
dc = new DisposableCollector();
constructor() {
onCleanup(() => {
this.dc.disposeAll();
});
}
};
var DisposableCollector = class {
dc = [];
size() {
return this.dc.length;
}
collect(disposable) {
this.dc.push(disposable);
}
disposeAll() {
this.dc.forEach((d) => d.dispose());
}
};
// src/SimpleEventRegistry.ts
function forward(params) {
return { action: 0 /* Forward */, params };
}
function terminate(params) {
return { action: 1 /* Terminate */, params };
}
var SimpleEventRegistry = class {
registry = /* @__PURE__ */ new Map();
emit(event, ...args) {
let handlers = this.registry.get(event);
let eventResult;
if (handlers) {
for (const cb of handlers) {
let r = cb(...args);
if (r) {
if (r instanceof Promise) {
throw new Error("emit not support Promise");
}
if (typeof r === "object") {
const { action, params } = r;
if (action === 1 /* Terminate */) {
return params;
} else {
eventResult = params;
}
}
}
}
}
return eventResult;
}
async emitAsync(event, ...args) {
let handlers = this.registry.get(event);
let eventResult;
if (handlers) {
for (const cb of handlers) {
let r = cb(...args);
if (r) {
if (r instanceof Promise) {
r = await r;
}
if (typeof r === "object") {
const { action, params } = r;
if (action === 1 /* Terminate */) {
return params;
} else {
eventResult = params;
}
}
}
}
}
return eventResult;
}
on(event, callback, dc) {
let set = this.registry.get(event);
if (!set) {
set = /* @__PURE__ */ new Set();
this.registry.set(event, set);
}
set.add(callback);
const disposable = { dispose: () => this.off(event, callback) };
if (dc) {
dc.collect(disposable);
} else {
return disposable;
}
}
once(event, callback) {
const disposable = this.on(event, (args) => {
const r = callback(args);
disposable.dispose();
return r;
});
}
off(event, callback) {
let set = this.registry.get(event);
if (set) {
set.delete(callback);
}
}
};
var Trace = class {
constructor(source, parent) {
this.source = source;
this.parent = parent;
}
};
// src/Handle.ts
var ProxyHandlerImpl = class {
target = bucket(null);
mountCallbacks = [];
readyCallbacks = [];
cleanupCallbacks = [];
internalMethods = {
onMount: (callback) => {
if (untrack2(this.target)) {
const collector = new DisposableCollector();
callback(collector);
if (collector.size() > 0) {
this.cleanupCallbacks.push(() => {
collector.disposeAll();
});
}
} else {
this.mountCallbacks.push(callback);
}
},
onReady: (callback) => {
if (untrack2(this.target)) {
const collector = new DisposableCollector();
callback(collector);
if (collector.size() > 0) {
this.cleanupCallbacks.push(() => {
collector.disposeAll();
});
}
} else {
this.readyCallbacks.push(callback);
}
},
onCleanup: (callback) => {
this.cleanupCallbacks.push(callback);
},
mounted: () => {
return Boolean(untrack2(this.target));
},
safeAccess: (k) => {
const t = this.target();
if (t) {
const p = t[k];
if (typeof p === "function") {
return p.bind(t);
}
return p;
}
},
mount: (target) => {
this.target(target);
const collector = new DisposableCollector();
this.mountCallbacks.forEach((c) => c(collector));
if (collector.size() > 0) {
this.cleanupCallbacks.push(() => {
collector.disposeAll();
});
}
if (this.readyCallbacks.length > 0) {
onMount(() => {
const collector2 = new DisposableCollector();
this.readyCallbacks.forEach((c) => c(collector2));
if (collector2.size() > 0) {
this.cleanupCallbacks.push(() => {
collector2.disposeAll();
});
}
;
});
}
},
cleanup: () => {
this.cleanupCallbacks.forEach((c) => c());
this.target(null);
}
};
get(_, methodName, proxy) {
if (methodName in this.internalMethods) {
if (methodName === "mounted") {
return this.internalMethods["mounted"]();
}
return this.internalMethods[methodName];
}
const target = untrack2(this.target);
if (!target) {
throw new Error(`Target is not mounted yet, cannot access ${String(methodName)}.`);
}
const result = target?.[methodName];
if (typeof result === "function") {
return result.bind(target);
}
return result;
}
};
function handle() {
const handler = new ProxyHandlerImpl();
const proxy = new Proxy({}, handler);
return proxy;
}
function completeHandle(target, handle2) {
if (!handle2) return;
const h = handle2;
onMount(() => {
h.mount(target);
});
onCleanup2(() => {
h.cleanup();
});
}
var HandleTarget = class extends DisposableSupport {
constructor(handle2) {
super();
completeHandle(this, handle2);
}
};
var EventSupportedHandleTarget = class extends SimpleEventRegistry {
dc = new DisposableCollector();
constructor(handle2) {
super();
completeHandle(this, handle2);
onCleanup2(() => {
this.dc.disposeAll();
});
}
};
export {
DisposableCollector,
DisposableSupport,
EventSupportedHandleTarget,
HandleTarget,
SimpleEventRegistry,
Trace,
asAccessor,
asBucket,
bucket,
clone,
compareDateString,
completeHandle,
conditional,
containsAny,
context,
copyOfRange,
forward,
handle,
indexOf,
isNotEmpty,
isNumber,
iterate,
names,
parseTimestamp,
removeElementsFromArray,
sequence,
stampedBucket,
terminate,
toCapital,
useCtx,
wrapDateNumber,
wrapNumber,
wrapString
};
//# sourceMappingURL=index.mjs.map