Liking cljdoc? Tell your friends :D

Backfilling non-docgen Mantine surface via guarded hand-written supplements

The wrapper is docgen-driven, but Mantine's docgen.json omits real surface: provider components (MantineProvider), polymorphic primitives (Box), plain functions (createTheme, rem), package-local hooks (useMantineTheme), whole packages with no components (@mantine/form), and, inconsistently, dot-notation compound parts (Menu.Dropdown, AppShell.Main are absent while Combobox.Dropdown, AppShell.Header are present). Without a fix the wrapper cannot render a screen.

Decision. Backfill omitted surface by hand, in codegen/supplements/*.cljc, rather than teaching the generator to auto-discover it. Two guards keep the hand-written lists honest across version bumps:

  • Collision guard (bb generate): fail when a supplement def name collides with a now-generated def ("docgen grew coverage, delete the supplement entry"), instead of the silent last-wins redefinition the merge would otherwise produce.
  • Compound-part coverage check (bb coverage): enumerate each wrapped component's Capitalized static keys (minus machinery: extend/withProps/displayName/classes/ varsResolver) and fail on any not covered by docgen or a supplement. This check, not a prose list, is the source of truth for the backfill.

Packages with zero docgen components (@mantine/form) are wrapped through a supplement-only package path: the generated namespace's body is entirely its hoisted supplement.

Considered and rejected

  • Teach the generator to auto-discover omissions (runtime introspection of exports and static properties). Rejected: the omitted set is small, enumerable, and slow-moving. A crawler is a whole new discovery mechanism with its own failure modes, and the guards give us drift detection without it. The two guards make the hand-written path safe instead of replacing it.

The conversion boundary (why create-theme converts but form does not)

A companion decision, recorded here so it is not re-litigated per package: the wrapper converts the input construction surface and passes runtime returns through raw.

  • Props convert (clj map → React, kebab→camel). This is the library's core, mechanical value.
  • create-theme wraps clj->js, so theme keys are camelCase-only (unlike props, which also accept kebab). Full prop-style deep conversion was rejected: it would need a second, deeper converter that hard-codes Mantine's theme schema and silently corrupts the freeform parts where map keys are user data (theme.colors names, theme.other).
  • Every hook, including @mantine/form's use-form, is raw passthrough. No js↔clj accessors: the library does not editorialize on return-value shape it cannot know, and a partial veneer over ~6 of @mantine/form's ~40 methods would be both incomplete and inconsistent. Interop conventions are a consumer-layer concern, like the field-DSL the wrapper also declines to bake in.

Addendum: the use* export Drift audit

A third guard now covers the package-local hooks. bb coverage fails on any use* export of a wrapped package other than @mantine/hooks that no def covers, unless it is a Context hook (excluded by rule) or a named exclude with its reason. It closes the gap for supplemented hooks that the compound-part check closes for compound parts.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close