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
16 changes: 16 additions & 0 deletions .changeset/mutation-observer-solid2-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@solid-primitives/mutation-observer": major
---

Migrate to Solid.js v2.0 (beta.10)

## Breaking Changes

**Peer dependencies**: `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10` are now required.

### `@solid-primitives/mutation-observer`

- `onMount` replaced with `onSettled` — observation starts after the component fully settles (async-aware) rather than after initial synchronous render
- `isServer` now imported from `@solidjs/web`; `isSupported` returns `false` on the server without touching `window`
- `start()` is a no-op on the server, guarding against missing DOM globals in Node.js
- Added `test/server.test.ts` to verify safe SSR behavior
15 changes: 15 additions & 0 deletions packages/mutation-observer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# @solid-primitives/mutation-observer

## 2.0.0

### Major Changes

- Migrate to Solid.js v2.0 (beta.10)

## Breaking Changes

**Peer dependencies**: `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10` are now required.

- `onMount` replaced with `onSettled` — observation starts after the component fully settles (async-aware) rather than after the initial synchronous render
- `isServer` is now imported from `@solidjs/web`; `isSupported` returns `false` on the server without checking `window`
- `start()` is a no-op on the server (guards against missing DOM globals in Node.js)
- Added `server.test.ts` to verify safe SSR behavior

## 1.2.3

### Patch Changes
Expand Down
10 changes: 8 additions & 2 deletions packages/mutation-observer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ Primitive providing the ability to watch for changes made to the DOM tree. A wra
npm install @solid-primitives/mutation-observer
# or
yarn add @solid-primitives/mutation-observer
# or
pnpm add @solid-primitives/mutation-observer
```

**Requires** `solid-js` and `@solidjs/web` >= `2.0.0-beta.10` as peer dependencies.

## How to use it

### createMutationObserver
Expand Down Expand Up @@ -49,13 +53,15 @@ createMutationObserver(
e => {...}
);

// Primitive return usefull values:
// Primitive return useful values:
const [observe, {start, stop, instance}] = createMutationObserver(el, options, handler)

observe(el1, { childList: true })
stop()
```

The primitive automatically starts observing after the component settles (via `onSettled`) and disconnects on cleanup. You can also control observation manually with `start()` and `stop()`.

### Directive Usage

```tsx
Expand All @@ -73,7 +79,7 @@ import { mutationObserver } from "@solid-primitives/mutation-observer";
// has to be used in code to avoid tree-shaking it:
mutationObserver;

<div use:mutationObserver={[{ childList: true }, e => {...}]}>...</div>
<div use:mutationObserver={[{ childList: true }, e => {...}]}></div>
```

### Types
Expand Down
9 changes: 5 additions & 4 deletions packages/mutation-observer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solid-primitives/mutation-observer",
"version": "1.2.3",
"version": "2.0.0",
"description": "Primitive providing the ability to watch for changes made to the DOM tree.",
"author": "Damian Tarnawski @thetarnav <gthetarnav@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -47,14 +47,15 @@
"test:ssr": "pnpm run vitest --mode ssr"
},
"devDependencies": {
"@solid-primitives/composites": "^1.1.1",
"solid-js": "^1.9.7"
"@solidjs/web": "2.0.0-beta.10",
"solid-js": "2.0.0-beta.10"
},
"dependencies": {
"@solid-primitives/utils": "workspace:^"
},
"peerDependencies": {
"solid-js": "^1.6.12"
"@solidjs/web": "^2.0.0-beta.10",
"solid-js": "^2.0.0-beta.10"
},
"typesVersions": {}
}
27 changes: 16 additions & 11 deletions packages/mutation-observer/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { onCleanup, onMount } from "solid-js";
import { onCleanup, onSettled } from "solid-js";
import type { JSX } from "solid-js";
import { isServer } from "@solidjs/web";
import { access, asArray, type MaybeAccessor } from "@solid-primitives/utils";

export type MutationObserverAdd = (
Expand Down Expand Up @@ -34,27 +35,26 @@ export type E = JSX.Element;

/**
* Primitive providing the ability to watch for changes being made to the DOM tree.
*
*
* @param initial html elements to be observed by the MutationObserver
* @param options MutationObserver options
* @param callback function called by MutationObserver when DOM tree mutation is triggered
*
*
* @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/mutation-observer
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
*
*
* @example
* ```ts
* let ref: !HTMLElement;
* let ref: HTMLElement;
* const [observe, { start, stop, instance }] = createMutationObserver(
* () => ref,
* { attributes: true, subtree: true },
* records => console.log(records)
* );
*
*
* // Usage as a directive
* const [mutationObserver] = createMutationObserver([], e => {...})

<div use:mutationObserver={{ childList: true }}>...</div>
* <div use:mutationObserver={{ childList: true }}>...</div>
* ```
*/
export function createMutationObserver(
Expand All @@ -74,7 +74,7 @@ export function createMutationObserver(
c?: MutationCallback,
): MutationObserverReturn {
let defaultOptions: MutationObserverInit, callback: MutationCallback;
const isSupported = typeof window !== "undefined" && "MutationObserver" in window;
const isSupported = !isServer;
if (typeof b === "function") {
defaultOptions = {};
callback = b;
Expand All @@ -86,13 +86,18 @@ export function createMutationObserver(
const add: MutationObserverAdd = (el, options) =>
instance?.observe(el, access(options) ?? defaultOptions);
const start = () => {
if (!isSupported) return;
asArray(access(initial)).forEach(item => {
item instanceof Node ? add(item, defaultOptions) : add(item[0], item[1]);
});
};
const stop = () => instance?.disconnect();
onMount(start);
onCleanup(stop);

if (isSupported) {
onSettled(start);
onCleanup(stop);
}

return [
add,
{
Expand Down
30 changes: 30 additions & 0 deletions packages/mutation-observer/test/server.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { createRoot } from "solid-js";
import { createMutationObserver, mutationObserver } from "../src/index.js";

describe("SSR", () => {
it("createMutationObserver is a noop on the server", () =>
createRoot(dispose => {
const fakeNode = {} as Node;
const [add, { start, stop, instance, isSupported }] = createMutationObserver(
fakeNode,
{ childList: true },
_ => {},
);

expect(isSupported).toBe(false);
expect(instance).toBeUndefined();
expect(() => start()).not.toThrow();
expect(() => stop()).not.toThrow();
expect(() => add(fakeNode)).not.toThrow();

dispose();
}));

it("mutationObserver directive is a noop on the server", () =>
createRoot(dispose => {
const fakeEl = {} as Element;
expect(() => mutationObserver(fakeEl, () => [{ childList: true }, _ => {}])).not.toThrow();
dispose();
}));
});
41 changes: 5 additions & 36 deletions pnpm-lock.yaml

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