Skip to content

fix: restore string[] choices, optional icons, and fix nested ChoiceGroup crash#168

Merged
brillout merged 3 commits into
mainfrom
claude/practical-babbage-nhat4t
Jun 22, 2026
Merged

fix: restore string[] choices, optional icons, and fix nested ChoiceGroup crash#168
brillout merged 3 commits into
mainfrom
claude/practical-babbage-nhat4t

Conversation

@brillout

Copy link
Copy Markdown
Owner

Why

Dependabot bump vikejs/vike#3362 (@brillout/docpress 0.16.39 → 0.16.43) breaks vike's docs CI in two ways. Both are docpress regressions in 0.16.43. This PR fixes them; with these changes vike needs no config change.

Fix 1 — +choices API backward compatibility

The icons feature (#153) changed each choice from a plain string to { name; icon; iconStyle? } with a required icon. That is a breaking change:

  • Type error — configs passing string[] (like vike's choices: ['React', 'Vue', 'Solid']) no longer satisfy Config['choices'].
  • Build crash — at runtime, group resolution matches by choice.name, which is undefined for plain strings, so the build throws [Wrong Usage] Missing group name for [React,Vue,Solid].

Also, requiring an icon on every choice is impractical (e.g. vike's Other server choice has no logo).

Changes:

  • Choice.choices now accepts string | { name; icon?; iconStyle? }; icon is optional and a plain string is shorthand for { name }.
  • Added normalizeChoice/normalizeChoices, applied at every read site (build-time resolution + the Tabs and CustomSelect components) so the rest of the code only deals with normalized objects.
  • The icon <img> is rendered only when an icon is defined.

Fix 2 — crash on nested ChoiceGroupContainer

Independently, a toggleable code block (TS/JS via remarkDetype, or an npm command via remarkPkgManager) nested inside other markup (a <Warning>, a blockquote, …) within a :::Choice is emitted as a nested ChoiceGroupContainer. The choiceGroupAll injection pass return 'skip's into containers, so the nested one renders without the attribute and choiceGroupAll.some(...) throws Cannot read properties of undefined (reading 'some') during pre-rendering (hit by vike's bodyHtmlEnd and clientOnly-helper pages).

This was previously masked by the Fix‑1 build error. The minimal, safe fix here guards the access — consistent with the already‑guarded .map two lines below; the container's choices still toggle via the shared/global selector (verified in the rendered HTML).

Note: the deeper root cause is that remarkDetype/remarkPkgManager compute the nesting level from the immediate parent, so a code block nested inside non‑choice markup is mistaken for top‑level and wrongly wrapped in its own container. A more thorough fix would resolve the level from ancestors so no phantom nested container is created. Happy to follow up with that if preferred.

Verification

Against a local build of this branch linked into vike's docs:

  • docpress: build ✓, test:types ✓, test:units ✓, demo vike build
  • vike docs (unchanged string[] config): tsc ✓ and vike build ✓ (351 pages pre-rendered)
  • Type-checked string[], object-with-optional-icon, and mixed choice formats

Follow-up for vike#3362

After release, vike's bump should target the new version (≥ next patch); no change to vike's +docpress.tsx is needed thanks to the restored string[] support.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 3 commits June 22, 2026 07:33
The `+choices` icons feature (#153) changed each choice from a plain
`string` to `{ name; icon; iconStyle? }` with a *required* `icon`, which
is a breaking change: existing configs that pass `string[]` (e.g. vike's
docs) stop type-checking and crash at build time with "Missing group name"
because the runtime resolves groups by `choice.name`.

Restore backward compatibility and relax the requirement:
- `Choice.choices` now accepts `string | { name; icon?; iconStyle? }`,
  with `icon` optional (a plain string is shorthand for `{ name }`).
- Add `normalizeChoice`/`normalizeChoices` and normalize at every read
  site (build-time resolution + the `Tabs`/`CustomSelect` components) so
  the rest of the code only ever deals with normalized objects.
- Only render the icon `<img>` when an icon is actually defined.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NAf7Qiofocsfume76cRNwk
When a toggleable code block (TS/JS via detype, or an npm command via
pkgManager) is nested inside other JSX/markup (e.g. a `<Warning>` or a
blockquote) within a `:::Choice`, it is emitted as a *nested*
`ChoiceGroupContainer`. The `choiceGroupAll` injection pass skips
descendants of a container, so the nested one renders without the
attribute and `choiceGroupAll.some(...)` throws.

Guard the access (consistent with the already-guarded `.map` just below):
a container without `choiceGroupAll` simply renders no redundant select —
its choices still toggle via the shared/global selector.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NAf7Qiofocsfume76cRNwk
Address review feedback:
- Rename `normalizeChoices` to `resolveChoices` and have it operate on the
  whole choices config, applied once per environment: when building the
  merged config in `resolveChoiceGroupNodes`, and in `resolvePageContext`
  (exposed as `pageContext.resolved.choices`). `Tabs`/`CustomSelect` now
  read already-resolved choices instead of normalizing at every call site.
- Drop the inline comments (keep JSDoc).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NAf7Qiofocsfume76cRNwk
@brillout brillout merged commit 7844b7e into main Jun 22, 2026
1 check passed
@brillout brillout deleted the claude/practical-babbage-nhat4t branch June 22, 2026 08:04
@brillout

Copy link
Copy Markdown
Owner Author

@phonzammi Because Other in https://vike.dev/server#get-started doesn't have an icon.

@phonzammi

Copy link
Copy Markdown
Collaborator

Thank you.

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.

3 participants