@machinemetrics/mm-react-blocks
v0.1.2
Published
Closed-config composite ("blocks") components for MachineMetrics applications, built on @machinemetrics/mm-react-components primitives.
Readme
@machinemetrics/mm-react-blocks
Closed-config composite ("blocks") components for MachineMetrics applications.
Blocks peer-depend on @machinemetrics/mm-react-components for primitives,
tokens, and theme — they never fork them.
Three blocks ship today: ControlBar, PageHeader and SplitTimeline. The
rest of the repo is the toolchain, guardrails and CI shape described in the
bootstrap proposal. Full context: mm-plans repo,
carbide-dsl/mm-react-blocks-proposal.md.
Consuming a block
npm install @machinemetrics/mm-react-blocksAn app must import BOTH stylesheets, the peer's first:
import '@machinemetrics/mm-react-components/styles';
import '@machinemetrics/mm-react-blocks/styles';The peer's sheet defines the palette tokens (--purple-500, --yellow-400
and the rest). This package's sheet only references them. Import this one
alone and every themed colour resolves to nothing, with no error in the
console and no build warning. The block still renders, which is what makes
the failure easy to miss.
The Carbide subtree also needs the carbide class on an ancestor element, the
same requirement mm-react-components documents.
The block contract
- A block's props are closed typed config — no
children, noclassName/style, no render props/ReactNodeprops. Icons only as typed component references. - Every variant is a literal union or enum; arrays are bounded and typed.
- Blocks import primitives from
@machinemetrics/mm-react-components; primitives never import blocks. - A block's props type must be expressible as a strict JSON schema minus callbacks — every block is a Carbide DSL vocabulary candidate by construction, admitted through the vocabulary-decision process.
Lint-enforced today (eslint.config.ts, scoped to
src/components/blocks/**/*Props): the className/children/style
half of rule 1, both identifier-spelled (className: string) and
quoted-string-literal-key ('className': string) forms.
Review-enforced (not statically checkable cheaply, so not lint rules):
the render-prop/ReactNode-prop half of rule 1, rule 2 (literal-union
variants, bounded arrays), rule 3 (import direction — blocks → primitives,
never the reverse), and rule 4 (JSON-schema expressibility). These are
checked at block-admission review time, same group as Carbide DSL
vocabulary decisions.
Theme tokens (interim)
The design ruling for how blocks get semantic-color utilities (bg-muted,
text-foreground, etc.) is a tokens-only @theme export from the peer
(deferred to mm-react-components 1.6.5). Until that ships, src/lib/styles.css
vendors the peer's @theme inline color/radius mapping verbatim (values
reference the peer's own tokens — var() indirections, plus the peer's
three calc(var(--radius) ± N) radius steps — so resolved values can't
drift; only the mapping list can). npm run check:token-emission (part of
verify) fails loudly if that vendored block goes missing or stops mapping
real utilities.
Development
npm install
npm run dev # preview shell at http://localhost:5173
npm run verify # lint + type-check + test:unit + build + token-emission + externals
npm test # playwright visual suite (light + dark)See AGENTS.md for the contract summary agents should follow when adding a
block, and the proposal doc for full context (what moves here, versioning,
consumer impact).
