Basil
Basil
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
Oh, it's certainly not production ready. It doesn't support Maps or Sets, since my project doesn't use those, but here you go:
/** Applies Immer patches mutatively. */
function applyPatches(patches: Patch[]) {
batch(() => {
for (const { path, op, value } of patches) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let base: any = get;
for (let i = 0; i < path.length - 1; i++) {
const frag = path[i];
base = base[frag];
}
const key = path[path.length - 1];

// Doesn't support `Map`s and `Set`s, but that doesn't matter, as we don't use them.
switch (op) {
case 'replace': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L244
base[key] = value;
break;
}
case 'add': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L262
if (Array.isArray(base)) {
key === '-'
? base.push(value)
: base.splice(key as number, 0, value);
} else base[key] = value;
break;
}
case 'remove': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L273
if (Array.isArray(base)) base.splice(key as number, 1);
else delete base[key];
break;
}
}
}
});
}
/** Applies Immer patches mutatively. */
function applyPatches(patches: Patch[]) {
batch(() => {
for (const { path, op, value } of patches) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let base: any = get;
for (let i = 0; i < path.length - 1; i++) {
const frag = path[i];
base = base[frag];
}
const key = path[path.length - 1];

// Doesn't support `Map`s and `Set`s, but that doesn't matter, as we don't use them.
switch (op) {
case 'replace': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L244
base[key] = value;
break;
}
case 'add': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L262
if (Array.isArray(base)) {
key === '-'
? base.push(value)
: base.splice(key as number, 0, value);
} else base[key] = value;
break;
}
case 'remove': {
// TODO: Handle `Map`s and `Set`s differently
// https://github.com/immerjs/immer/blob/8e465ab7f4d53525e72bc6b78e9204cb897cf528/src/plugins/patches.ts#L273
if (Array.isArray(base)) base.splice(key as number, 1);
else delete base[key];
break;
}
}
}
});
}
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
After re-reading this, I got the idea of re-implementing Immer's applyPatches, but in a mutative way, which solved my issue.
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
Also, when you have nested createMutables, calling unwrap only unwraps the top-most value, and structuredClone still fails if any sub-properties aren't unwrapped.
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
Example:
import { createEffect } from 'solid-js';
import { captureStoreUpdates } from '@solid-primitives/deep';
import { createMutable } from 'solid-js/store';

class Subclass {
someVal: number;

constructor(i: number) {
this.someVal = i;

return createMutable(this);
}
}

class Root {
arr: Subclass[];
val: number;

constructor() {
this.arr = [
new Subclass(3),
new Subclass(8),
new Subclass(1),
new Subclass(4)
];

this.val = 9;

return createMutable(this);
}
}

export default function App() {
const store = new Root();

const getDelta = captureStoreUpdates(store);

createEffect(() => {
const delta = getDelta();
console.log('delta:', ...delta.map(a => a.path));
});

function storeUpdate() {
console.log('pre:', store.arr[1].someVal);

store.arr[1].someVal = 0;

console.log('post:', store.arr[1].someVal);
}

return (
<>
<button onClick={storeUpdate}>Update</button>
<p>{store.arr[1].someVal}</p>
<p>{store.val}</p>
</>
);
}
import { createEffect } from 'solid-js';
import { captureStoreUpdates } from '@solid-primitives/deep';
import { createMutable } from 'solid-js/store';

class Subclass {
someVal: number;

constructor(i: number) {
this.someVal = i;

return createMutable(this);
}
}

class Root {
arr: Subclass[];
val: number;

constructor() {
this.arr = [
new Subclass(3),
new Subclass(8),
new Subclass(1),
new Subclass(4)
];

this.val = 9;

return createMutable(this);
}
}

export default function App() {
const store = new Root();

const getDelta = captureStoreUpdates(store);

createEffect(() => {
const delta = getDelta();
console.log('delta:', ...delta.map(a => a.path));
});

function storeUpdate() {
console.log('pre:', store.arr[1].someVal);

store.arr[1].someVal = 0;

console.log('post:', store.arr[1].someVal);
}

return (
<>
<button onClick={storeUpdate}>Update</button>
<p>{store.arr[1].someVal}</p>
<p>{store.val}</p>
</>
);
}
When running store.arr[1].someVal = 0;, the path of the delta that gets generated is ['arr', 1], instead of the expected ['arr', 1, 'someVal']. It stores an instance of the Subclass class instead of just a number.
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
Wrapping things in createMutable does help, but the granularity is lost; updating a value in a class causes captureStoreUpdates to return an instance of the class, instead of just the one property.
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
I'm messing around with that right now, but SolidJS stores in general don't seem to support reactivity with classes.
12 replies
SSolidJS
Created by Basil on 3/14/2024 in #support
Using SolidJS's produce(), but with Immer-style patch generation?
Immer has copy-on-write, so if I do something like this:
set(
solidProduce(
s => immerProduceWithPatches(s,
draft => {
draft.someParam = 7;
}
)
)
);
set(
solidProduce(
s => immerProduceWithPatches(s,
draft => {
draft.someParam = 7;
}
)
)
);
immerProduceWithPatches will generate patches, but it will not be changed on the underlying s object that Solid's produce (solidProduce here) gives you. Even applyPatches is copy-on-write, so it has the same issue.
12 replies
SSolidJS
Created by Basil on 1/23/2024 in #support
Nested Immer "produce" signals with components
Is it even possible to do this reactively?
7 replies
SSolidJS
Created by Basil on 1/23/2024 in #support
Nested Immer "produce" signals with components
If you mean something like:
const [store, setStore] = createStore(someDeeplyNestedObject);

setStore('some', 'path', produce(draft => {
draft.val = true;
});
const [store, setStore] = createStore(someDeeplyNestedObject);

setStore('some', 'path', produce(draft => {
draft.val = true;
});
I don't think that would work with the patch generation, since it would just make the patches relative to .some.path and you couldn't just put that into a undo/redo context.
7 replies
SSolidJS
Created by Basil on 1/23/2024 in #support
Nested Immer "produce" signals with components
Would you even be able to use stores with Immer? Since Immer returns a completely new object, using the store setter to set the object would mean you won't get the fine-grained reactivity, right?
7 replies
SSolidJS
Created by Basil on 1/23/2024 in #support
Nested Immer "produce" signals with components
Or, what do you mean by that?
7 replies
SSolidJS
Created by Basil on 1/23/2024 in #support
Nested Immer "produce" signals with components
I'm using Immer (and its produce function) to generate patches and so I can deal with reactivity on classes/nested classes.
7 replies
SSolidJS
Created by Basil on 1/4/2024 in #support
Good library for handling combobox-style search UI? (with Pagefind)
I ended up just moving focus based on arrow keys (I don't know if it interferes with accessibility, but I don't think it should), but I'm pretty sure I've used that library before. Thanks for making it :)
4 replies
SSolidJS
Created by Basil on 1/4/2024 in #support
Good library for handling combobox-style search UI? (with Pagefind)
Would it suffice to have a keydown handlers for the up and down arrow keys that moves focus up and down between the element and a focus trap?
4 replies