Skip to content

upgrade: context package upgrade for Solid 2.0#907

Open
davedbase wants to merge 4 commits into
solidjs-community:nextfrom
davedbase:update/v2/context
Open

upgrade: context package upgrade for Solid 2.0#907
davedbase wants to merge 4 commits into
solidjs-community:nextfrom
davedbase:update/v2/context

Conversation

@davedbase
Copy link
Copy Markdown
Member

@davedbase davedbase commented May 21, 2026

Migrates @solid-primitives/context to Solid.js 2.0 (beta.13) and adds three quality-of-life additions to the API.


Solid 2.0 migration (breaking)

  • Context.Provider removed — In Solid 2.0, the Context object itself is the provider component. createContextProvider and MultiProvider updated; <MyCtx.Provider value={...}> becomes <MyCtx value={...}>.
  • ContextProviderComponent import fixed — Previously imported from an internal node_modules path; now a proper export from solid-js.
  • JSX.ElementElement — Public API types now use Element from solid-js (renderer-neutral), matching the Solid 2.0 type model.
  • MultiProvider cleanup — Removed the .Provider fallback branch; Context is always a function in Solid 2.0.
  • Peer deps: solid-js@^2.0.0-beta.13 and @solidjs/web@^2.0.0-beta.13 required.
  • Version bumped to 1.0.0 (major).

Noteworthy Solid 2.0 behaviour: context providers now wrap children in a lazy memo (children(() => props.children)). Tests that previously used bare createRoot(() => { <Provider/>; }) never forced child evaluation. The MultiProvider browser test was updated to use render() so the DOM renderer drives evaluation of the lazy memo chain.


New exports

createStrictContextProvider

Like createContextProvider without defaults, but with the contract made explicit in types: the hook returns T (never T | undefined), and Solid throws ContextNotFoundError at runtime when called outside a provider. Accepts an optional { name } for DevTools labeling.

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

// No `!` needed — type is T, throws if no provider
const { user } = useAuth();

createLayeredContext

Each provider extends the parent context value rather than replacing it. The factory receives (props, parent) where parent is the nearest enclosing provider's value (falling back to defaults at the root). You control the merge strategy.

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

<ThemeProvider primary="red">            // { primary: "red",   secondary: "gray" }
  <ThemeProvider primary="green">        // { primary: "green", secondary: "gray" }
    <App />
  </ThemeProvider>
</ThemeProvider>

Useful for themes, permission layers, i18n patches, and any context where child providers should inherit what they don't explicitly override.

ContextProviderOptions + name on createContextProvider

All three primitives accept { name?: string } for the Solid DevTools Symbol label. On createContextProvider it's the third argument (with-defaults overload only):

createContextProvider(factory, defaultTheme, { name: "Theme" })

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * Added two new context creation utilities for advanced context patterns
  * Optional debug names for context providers improve DevTools labeling

* **Breaking Changes**
  * Requires Solid.js v2.0 (beta.13)
  * Provider usage pattern updated; context objects used directly
  * Multi-context composition API simplified

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/solidjs-community/solid-primitives/pull/907?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@davedbase davedbase added this to the Solid 2.0 Migration milestone May 21, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 21, 2026

🦋 Changeset detected

Latest commit: f6df19c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solid-primitives/context Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@davedbase davedbase marked this pull request as ready for review May 23, 2026 16:05
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 671d2390-dd74-4fc8-b78d-0776f2fa9a76

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/context/test/index.test.tsx (1)

148-155: ⚡ Quick win

Assert the specific strict-context failure, not just “any throw”.

.toThrow() will also pass on unrelated render failures, so this doesn't really lock down the advertised ContextNotFoundError contract. Match the error name/message here so regressions stay visible.

Suggested assertion tightening
     expect(() => {
       render(() => {
         useStrict();
         return "";
       }, document.createElement("div"));
-    }).toThrow();
+    }).toThrow(/ContextNotFoundError/);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/context/test/index.test.tsx` around lines 148 - 155, The test
currently asserts any throw from rendering useStrict(), which is too broad;
update the assertion to specifically expect the strict-context failure by
asserting the thrown error is the ContextNotFoundError (or matches its exact
name/message). Locate the test that calls createStrictContextProvider and
invokes useStrict() in the render block, then replace the generic
expect(...).toThrow() with an assertion that checks for ContextNotFoundError
(e.g., toThrowError matching the error's name or exact message or using
instanceof ContextNotFoundError) so the test fails on unrelated errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/context/src/index.ts`:
- Around line 54-60: Add an overload for createContextProvider that accepts
defaults: undefined so callers can pass an options object without a typed
default; specifically add a signature like createContextProvider<T, P extends
ContextProviderProps>(factoryFn: (props: P) => T, defaults: undefined, options?:
ContextProviderOptions): [provider: ContextProvider<P>, useContext: () => T |
undefined] (place this overload before the broader defaults:T overload to avoid
ambiguity), ensuring it matches the runtime behavior that allows (factoryFn,
undefined, options).

---

Nitpick comments:
In `@packages/context/test/index.test.tsx`:
- Around line 148-155: The test currently asserts any throw from rendering
useStrict(), which is too broad; update the assertion to specifically expect the
strict-context failure by asserting the thrown error is the ContextNotFoundError
(or matches its exact name/message). Locate the test that calls
createStrictContextProvider and invokes useStrict() in the render block, then
replace the generic expect(...).toThrow() with an assertion that checks for
ContextNotFoundError (e.g., toThrowError matching the error's name or exact
message or using instanceof ContextNotFoundError) so the test fails on unrelated
errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fc3a7746-eaf5-4850-aaa8-b0c5406cc244

📥 Commits

Reviewing files that changed from the base of the PR and between 8e8ff1e and 943027f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • .changeset/context-solid2-migration.md
  • packages/context/CHANGELOG.md
  • packages/context/README.md
  • packages/context/dev/index.tsx
  • packages/context/package.json
  • packages/context/src/index.ts
  • packages/context/test/index.test.tsx
  • packages/context/test/server.test.tsx

Comment thread packages/context/src/index.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant