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

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

## Breaking Changes

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

- `Context` is now used directly as the provider component — `Context.Provider` no longer exists in Solid 2.0. `createContextProvider` and `MultiProvider` both reflect this change.
- `ContextProviderComponent` is now a proper export from `solid-js`; the previous workaround importing from an internal `node_modules` path has been removed.
- `JSX.Element` replaced with `Element` from `solid-js` throughout the public API types, matching Solid 2.0's renderer-neutral type model.
- `MultiProvider` no longer falls back to accessing `.Provider` on non-function items — contexts passed in `values` must be functions (which all `Context` objects now are in Solid 2.0).
20 changes: 20 additions & 0 deletions packages/context/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# @solid-primitives/context

## 1.0.0

### Major Changes

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

#### Breaking Changes

- **Peer dependencies**: `solid-js@^2.0.0-beta.13` and `@solidjs/web@^2.0.0-beta.13` are now required.
- `Context` is now used directly as the provider component — `Context.Provider` no longer exists in Solid 2.0. `createContextProvider` and `MultiProvider` both reflect this change.
- `ContextProviderComponent` is now a proper export from `solid-js`; the previous workaround importing from an internal `node_modules` path has been removed.
- `JSX.Element` replaced with `Element` from `solid-js` throughout the public API types.
- `MultiProvider` no longer falls back to accessing `.Provider` on non-function items — contexts passed in `values` must be functions (which all `Context` objects are in Solid 2.0).

#### New Exports

- **`createStrictContextProvider`** — Like `createContextProvider` without defaults, but with the intent made explicit in types: the hook returns `T` (never `undefined`) and Solid throws `ContextNotFoundError` at runtime when used outside a provider. Accepts an optional `{ name }` option.
- **`createLayeredContext`** — Like `createContextProvider`, but each provider in the tree extends the parent context value rather than replacing it. The factory receives both `props` and the nearest parent context value. Requires a `defaults` base value.
- **`ContextProviderOptions`** — Exported type `{ name?: string }` for the third argument of `createContextProvider` and `createStrictContextProvider`/`createLayeredContext`'s second argument.

## 0.3.2

### Patch Changes
Expand Down
78 changes: 69 additions & 9 deletions packages/context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
Primitives simplifying the creation and use of SolidJS Context API.

- [`createContextProvider`](#createcontextprovider) - Create the Context Provider component and useContext function with types inferred from the factory function.
- [`createStrictContextProvider`](#createstrictcontextprovider) - Like `createContextProvider`, but throws when the context is used outside a provider instead of returning `undefined`.
- [`createLayeredContext`](#createlayeredcontext) - Like `createContextProvider`, but each provider extends the parent context value rather than replacing it.
- [`MultiProvider`](#multiprovider) - A component that allows you to provide multiple contexts at once.

## Installation
Expand All @@ -23,6 +25,8 @@ pnpm add @solid-primitives/context
yarn add @solid-primitives/context
```

Requires `solid-js@^2.0.0-beta.13` and `@solidjs/web@^2.0.0-beta.13`.

## `createContextProvider`

Create the Context Provider component and useContext function with types inferred from the factory function.
Expand Down Expand Up @@ -72,16 +76,72 @@ const [CounterProvider, useCounter] = createContextProvider(
const { count } = useCounter();
```

Definite context types without defaults:
### Debug name

An optional `name` can be passed as part of the third argument. It labels the context's Symbol for Solid DevTools and improves `ContextNotFoundError` stack traces (dev mode only).

```ts
const useDefiniteCounter = () => useCounter()!;
const [ThemeProvider, useTheme] = createContextProvider(
() => createTheme(),
defaultTheme,
{ name: "Theme" },
);
```

### Demo

https://codesandbox.io/s/solid-primitives-context-demo-oqyie2?file=/index.tsx

## `createStrictContextProvider`

Like `createContextProvider` without defaults, but with an explicit contract: if the hook is called outside a provider, Solid throws a `ContextNotFoundError` at runtime. The return type of the hook is `T` (never `undefined`), so no null-check is needed at the call site.

```tsx
import { createStrictContextProvider } from "@solid-primitives/context";

const [AuthProvider, useAuth] = createStrictContextProvider(
() => {
const [user, setUser] = createSignal<User | null>(null);
return { user, setUser };
},
{ name: "Auth" },
);

// No `!` needed — type is T, not T | undefined
const { user } = useAuth();
```

Use `createStrictContextProvider` when a context is required by contract (e.g. a form context that must be inside `<Form>`). Use `createContextProvider` with defaults when a sensible fallback exists.

## `createLayeredContext`

Like `createContextProvider`, but each provider in the tree *extends* the parent context value rather than replacing it entirely. The factory function receives the nearest parent's context value as its second argument.

This is useful for incremental overrides such as themes, permissions layers, or i18n patches where a child provider should inherit what it does not explicitly change.

```tsx
import { createLayeredContext } from "@solid-primitives/context";

const [ThemeProvider, useTheme] = createLayeredContext(
(props: { primary?: string; secondary?: string }, parent) => ({
...parent,
primary: props.primary ?? parent.primary,
secondary: props.secondary ?? parent.secondary,
}),
{ primary: "blue", secondary: "gray" }, // base defaults
);

// Root: { primary: "red", secondary: "gray" }
<ThemeProvider primary="red">
{/* Nested: { primary: "green", secondary: "gray" } — secondary inherited */}
<ThemeProvider primary="green">
<App />
</ThemeProvider>
</ThemeProvider>;
```

`createLayeredContext` always requires a `defaults` value (the base used when no parent provider wraps the component). The hook return type is always `T` (never `undefined`).

## `MultiProvider`

A component that allows you to provide multiple contexts at once.
Expand All @@ -99,17 +159,17 @@ It will work exactly like nesting multiple providers as separate components, but
import { MultiProvider } from "@solid-primitives/context";

// before
<FooContext.Provider value={"foo"}>
<BarContext.Provider value={"bar"}>
<BazContext.Provider value={"baz"}>
<FooContext value={"foo"}>
<BarContext value={"bar"}>
<BazContext value={"baz"}>
<MyCustomProviderComponent value={"hello-world"}>
<BoundContextProvider>
<App />
</BoundContextProvider>
</MyCustomProviderComponent>
</BazContext.Provider>
</BarContext.Provider>
</FooContext.Provider>;
</BazContext>
</BarContext>
</FooContext>;

// after
<MultiProvider
Expand All @@ -128,7 +188,7 @@ import { MultiProvider } from "@solid-primitives/context";
```

> **Warning**
> Components and values passed to `MultiProvider` will be evaluated only once, so make sure that the structure is static. If is isn't, please use nested provider components instead.
> Components and values passed to `MultiProvider` will be evaluated only once, so make sure that the structure is static. If it isn't, please use nested provider components instead.

## Changelog

Expand Down
7 changes: 2 additions & 5 deletions packages/context/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const Counter: Component = () => {
const TestCtx = createContext<{ title: string }>();

const BoundProvider: FlowComponent = props => (
<TestCtx.Provider value={{ title: "foo" }}>{props.children}</TestCtx.Provider>
<TestCtx value={{ title: "foo" }}>{props.children}</TestCtx>
);

const App: Component = () => {
Expand All @@ -47,11 +47,8 @@ const App: Component = () => {
<MultiProvider
values={[
[TestCtx, { title: "Hello Context" }],
[TestCtx.Provider, { title: "Hello Provider" }],
[TestCtx, { title: 123 }],
[TestCtx.Provider, { title: 321 }],
[TestCtx, { title: "Hello Provider" }],
[TestCtx, undefined],
[TestCtx.Provider, undefined],
BoundProvider,
CounterProvider,
]}
Expand Down
10 changes: 7 additions & 3 deletions packages/context/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solid-primitives/context",
"version": "0.3.2",
"version": "1.0.0",
"description": "Primitives simplifying or extending the SolidJS Context API",
"author": "Damian Tarnawski @thetarnav <gthetarnav@gmail.com>",
"license": "MIT",
Expand All @@ -17,6 +17,8 @@
"stage": 2,
"list": [
"createContextProvider",
"createStrictContextProvider",
"createLayeredContext",
"MultiProvider"
],
"category": "Control Flow"
Expand Down Expand Up @@ -51,10 +53,12 @@
"primitives"
],
"peerDependencies": {
"solid-js": "^1.6.12"
"@solidjs/web": "^2.0.0-beta.13",
"solid-js": "^2.0.0-beta.13"
},
"typesVersions": {},
"devDependencies": {
"solid-js": "^1.9.7"
"@solidjs/web": "2.0.0-beta.13",
"solid-js": "2.0.0-beta.13"
}
}
Loading