Skip to content

fix(color-wheel-flower): render standalone instead of crashing the page - #288

Closed
pathscale wants to merge 1 commit into
masterfrom
fix/color-wheel-flower-standalone
Closed

fix(color-wheel-flower): render standalone instead of crashing the page#288
pathscale wants to merge 1 commit into
masterfrom
fix/color-wheel-flower-standalone

Conversation

@pathscale

Copy link
Copy Markdown
Owner

ColorWheelFlower is exported from @pathscale/ui/lab. Rendering one outside a ThemeColorPicker threw, and in Solid 2 a throw during render halts the reactive system — so one component on one route blanked an entire application.

Found by driving js.software's showcase in a browser: /color-picker rendered an empty <body>, with ContextNotFoundError and [REACTIVITY_HALTED] in the console.

Two things had to be true

The context had no default. It was declared createContext<T | undefined>(undefined), and in Solid 2 that is the default-less form — the absence of a default is exactly what makes useContext throw. It was paired with a hook that checked for a missing value and threw a friendlier error, which could never run because useContext threw first, and whose message named ColorPickerContext.Provider, which Solid 2 does not have. The default is now null and the hook returns it.

The component dereferenced it unconditionally. It now falls back to its own props — color / defaultColor, disabled, onChange. Inside a ThemeColorPicker nothing changes: the surrounding context still owns the state. Outside one, a bare <ColorWheelFlower /> renders an uncontrolled flower starting at white.

Why the existing test did not catch it

tests/components/optional-context-defaults.test.ts exempts contexts that are dereferenced directly, arguing that a default would trade a clear error for a null-property crash further from the cause. That argument holds for an internal subcomponent. It does not hold for one the package exports, and this one is exported.

The verifier

A ps-qa check, because what needs proving is that it renders. It asserts the centre petal by name, not the component name: the harness renders the component name on a labelled wrapper whether or not anything mounted, and the first version of this check passed against the unfixed component. That is how the toothless version was caught.

With the context restored to default-less, the check fails:

no node matching "radio:Reset to neutral" exists in the tree; same role present: none

Verification

Check Result
color-wheel-flower ps-qa group, headless profile 3/3 pass
Same group with the fix reverted 1 fail, as quoted above
bun run test 186 pass, 0 fail
bunx tsc --noEmit clean
bun run lint:layouts clean
bun run lint:code fails identically on master; no findings in any file this touches

Release

This wants a 3.1.1. js.software's /color-picker route stays dead until it ships, and its migration PR is held behind that.

`ColorWheelFlower` is exported from `@pathscale/ui/lab`. Rendering one outside
a `ThemeColorPicker` threw, and in Solid 2 a throw during render halts the
reactive system: one component on one route blanked an entire application. The
showcase page for it in js.software was dead, with `ContextNotFoundError` and
`REACTIVITY_HALTED` in the console and an empty body.

Two things had to be true for that.

The context was declared `createContext<T | undefined>(undefined)`. In Solid 2
that is the *default-less* form, and the absence of a default is precisely what
makes `useContext` throw. It was paired with a hook that checked for a missing
value and threw a friendlier error, which could never run because `useContext`
threw first -- and whose message named `ColorPickerContext.Provider`, which
Solid 2 does not have. The default is now `null` and the hook returns it.

The component then dereferenced that context unconditionally. It now falls back
to its own props: `color` / `defaultColor` for the selection, `disabled`, and
`onChange`. Inside a `ThemeColorPicker` nothing changes, the surrounding
context still owns the state. Outside one, a bare `<ColorWheelFlower />`
renders an uncontrolled flower starting at white.

`tests/components/optional-context-defaults.test.ts` did not cover this on
purpose: it exempts contexts that are dereferenced directly, on the argument
that a default would trade a clear error for a null-property crash. That
argument holds for an internal subcomponent and not for an exported one, and
this was exported.

The verifier is a ps-qa check, because the thing to prove is that it renders.
It asserts the centre petal by name rather than the component name, which the
harness renders on a labelled wrapper whether or not anything mounted -- the
first version of this check passed against the unfixed component, which is how
that was found. With the context restored to default-less it fails:

  no node matching "radio:Reset to neutral" exists in the tree
@pathscale

Copy link
Copy Markdown
Owner Author

Rolled into #289 so the four fixes ship as one release. The commit is unchanged.

@pathscale pathscale closed this Sep 8, 2026
@pathscale
pathscale deleted the fix/color-wheel-flower-standalone branch September 12, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant