Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/refs-solid2-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@solid-primitives/refs": major
---

Migrate to Solid.js 2.0 (beta.10).

**Breaking changes:**

- Requires `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10`
- Removed deprecated re-exports of `ResolvedChildren` and `ResolvedJSXElement` from `solid-js/types`
- `Refs` and `Ref` components now use split `createEffect` (compute/apply) instead of the removed `createComputed`; the callback fires asynchronously on the next microtask after children change (consistent with Solid 2.0's deferred reactivity model)
2 changes: 1 addition & 1 deletion packages/refs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface ButtonProps {

function Button(props: ButtonProps) {
let ref: HTMLButtonElement | undefined;
onMount(() => {
onSettled(() => {
// use the local ref
});

Expand Down
10 changes: 6 additions & 4 deletions packages/refs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solid-primitives/refs",
"version": "1.1.3",
"version": "2.0.0",
"description": "Library of primitives, components and directives for SolidJS that help managing references to JSX elements.",
"author": "Damian Tarnawski @thetarnav <gthetarnav@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -41,7 +41,7 @@
"scripts": {
"dev": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/dev.ts",
"build": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/build.ts",
"vitest": "vitest -c ../../configs/vitest.config.ts",
"vitest": "vitest -c vitest.config.ts",
"test": "pnpm run vitest",
"test:ssr": "pnpm run vitest --mode ssr"
},
Expand All @@ -55,10 +55,12 @@
"@solid-primitives/utils": "workspace:^"
},
"devDependencies": {
"solid-js": "^1.9.7",
"@solidjs/web": "2.0.0-beta.10",
"solid-js": "2.0.0-beta.10",
"solid-transition-group": "^0.2.3"
},
"peerDependencies": {
"solid-js": "^1.6.12"
"@solidjs/web": "^2.0.0-beta.10",
"solid-js": "^2.0.0-beta.10"
}
}
32 changes: 16 additions & 16 deletions packages/refs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ import { chain, arrayEquals } from "@solid-primitives/utils";
import {
type Accessor,
children,
createComputed,
createEffect,
createMemo,
type JSX,
onCleanup,
untrack,
} from "solid-js";
import { isServer } from "solid-js/web";

// TODO delete in next major version
export type { ResolvedChildren, ResolvedJSXElement } from "solid-js/types/reactive/signal.js";
import { isServer } from "@solidjs/web";

/**
* Type for the `ref` prop
Expand Down Expand Up @@ -235,11 +231,13 @@ export function Refs(props: { ref: Ref<Element[]>; children: JSX.Element }): JSX

let prev: Element[] = [];

createComputed(() => {
const els = resolved.toArray().filter(defaultElementPredicate);
if (!arrayEquals(prev, els)) untrack(() => cb(els));
prev = els;
}, []);
createEffect(
() => resolved.toArray().filter(defaultElementPredicate),
(els: Element[]) => {
if (!arrayEquals(prev, els)) cb(els);
prev = els;
},
);
onCleanup(() => prev.length && cb([]));

return resolved as unknown as JSX.Element;
Expand Down Expand Up @@ -267,11 +265,13 @@ export function Ref(props: { ref: Ref<Element | undefined>; children: JSX.Elemen

let prev: Element | undefined;

createComputed(() => {
const el = resolved.toArray().find(defaultElementPredicate);
if (el !== prev) untrack(() => cb(el));
prev = el;
});
createEffect(
() => resolved.toArray().find(defaultElementPredicate),
(el: Element | undefined) => {
if (el !== prev) cb(el);
prev = el;
},
);

onCleanup(() => prev && cb(undefined));

Expand Down
6 changes: 4 additions & 2 deletions packages/refs/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, expect } from "vitest";
import { createRoot, createSignal } from "solid-js";
import { createRoot, createSignal, flush } from "solid-js";
import { removeItems } from "@solid-primitives/utils/immutable";
import { getResolvedElements, resolveElements } from "../src/index.js";

Expand Down Expand Up @@ -41,15 +41,17 @@ describe("resolveElements", () => {
test("returned signals reflect changes to source", () => {
createRoot(dispose => {
const _source = [undefined, el2, el1, "HELLO", el3];
const [source, setSource] = createSignal(_source);
const [source, setSource] = createSignal(_source, { ownedWrite: true });

const els = resolveElements(source);
expect(els()).toEqual([el2, el1, el3]);

setSource(p => [...p, el4]);
flush();
expect(els()).toEqual([el2, el1, el3, el4]);

setSource(p => removeItems(p, el1, el2, undefined));
flush();
expect(els(), "3 1").toEqual([el3, el4]);

dispose();
Expand Down
40 changes: 24 additions & 16 deletions packages/refs/test/mergeRefs.test.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import { describe, test, expect } from "vitest";
import { createRoot, onMount } from "solid-js";
import { mergeRefs, RefProps } from "../src/index.js";
import { mergeRefs } from "../src/index.js";

describe("mergeRefs", () => {
test("passes ref to props and local var", () =>
createRoot(dispose => {
let local!: HTMLButtonElement;
let forwared!: HTMLButtonElement;
test("chains multiple ref callbacks", () => {
let local: HTMLButtonElement | undefined;
let forwarded: HTMLButtonElement | undefined;
const el = document.createElement("button") as HTMLButtonElement;

const Button = (props: RefProps<HTMLButtonElement>) => {
return <button ref={mergeRefs(el => (local = el), props.ref)} />;
};
const merged = mergeRefs<HTMLButtonElement>(
e => (local = e),
e => (forwarded = e),
);
merged(el);

<Button ref={forwared} />;
expect(local).instanceOf(HTMLButtonElement);
expect(forwarded).instanceOf(HTMLButtonElement);
expect(local).toBe(el);
expect(forwarded).toBe(el);
});

onMount(() => {
expect(local).instanceOf(HTMLButtonElement);
expect(forwared).instanceOf(HTMLButtonElement);
dispose();
});
}));
test("ignores undefined refs", () => {
const el = document.createElement("button") as HTMLButtonElement;
let called = false;
const merged = mergeRefs<HTMLButtonElement>(undefined, e => {
called = true;
});
merged(el);
expect(called).toBe(true);
});
});
2 changes: 1 addition & 1 deletion packages/refs/test/server.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { renderToString } from "solid-js/web";
import { renderToString } from "@solidjs/web";
import { describe, expect, test } from "vitest";
import { resolveElements, resolveFirst } from "../src/index.js";

Expand Down
46 changes: 46 additions & 0 deletions packages/refs/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { defineConfig } from "vitest/config";
import solidPlugin from "vite-plugin-solid";
import * as utils from "../../scripts/utils/index.js";

const package_name = utils.getPackageNameFromCWD();

if (package_name != null) {
utils.log_info("Testing " + package_name + " package...");
}

export default defineConfig(({ mode }) => {
const testSSR = mode === "test:ssr" || mode === "ssr";

return {
plugins: [
solidPlugin({
hot: false,
solid: {
generate: testSSR ? "ssr" : "dom",
omitNestedClosingTags: false,
moduleName: "@solidjs/web",
},
}),
],
test: {
watch: false,
isolate: false,
passWithNoTests: true,
environment: testSSR ? "node" : "jsdom",
transformMode: {
web: [/\.[jt]sx$/],
},
...(testSSR
? { include: ["test/server.test.{ts,tsx}"] }
: {
include: ["test/*.test.{ts,tsx}"],
exclude: ["test/server.test.{ts,tsx}"],
}),
},
resolve: {
conditions: testSSR
? ["@solid-primitives/source", "node"]
: ["@solid-primitives/source", "browser", "development"],
},
};
});
28 changes: 25 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.