vroqjs.com

99-reference/v02-component-migration-plan.md

v02 component migration plan

v02 component migration plan

This file records the migration plan for the v02 component API unification work.

Use this file together with:

  • 99-reference/component-vocabulary.md
  • 99-reference/component-api-conventions.md

Why this migration exists

The old v02 component layer had several problems that made app creation and maintenance harder, especially for LLMs:

  • too many public call signatures
  • positional arguments with different meanings in different component families
  • binding-first APIs mixed with props-first APIs
  • convenience wrappers that expanded the public API surface
  • incomplete public exports in ui.js
  • component contracts that were implicit instead of explicit
  • weak runtime guidance when a component was called incorrectly

The goal of this migration is to make component code:

  • easier to read
  • easier to document
  • easier to validate
  • easier to generate correctly with LLMs
  • easier to keep consistent across the framework

What we want to improve

1. One clear public component shape

Public components should use only these canonical forms:

Component({ ...props })
Component({ ...props }, ...children)

Rules:

  • leaf and widget components use Component({ ...props })
  • container components use Component({ ...props }, ...children)
  • no public positional content arguments
  • no public binding-first signatures
  • no multiple public overloads for the same component

2. Global vocabulary for props

All components should prefer the shared vocabulary from component-vocabulary.md.

Examples:

  • text
  • label
  • icon
  • value
  • checked
  • onChange
  • onClick
  • tone
  • variant
  • size
  • disabled
  • loading
  • class
  • className
  • style

The framework should reduce local synonyms and one-off prop names.

3. Explicit component contracts

Each migrated component should define an explicit allowedProps object.

Example:

export const textAllowedProps = {
  text: { type: "content", required: true },
  tone: { type: "string", values: ["text", "muted", "primary", "danger"] },
  size: { type: "string", values: ["h1", "h2", "h3", "h4", "h5", "h6", "body", "small", "tiny"] }
}

This helps with:

  • LLM readability
  • validation
  • future documentation generation
  • consistent prop naming

4. Shared validation helper

All migrated components should use the shared helper:

import { validateProps } from "../system/ui/props.js"

Pattern:

validateProps("ComponentName", props, allowedProps)

The framework should fail early when a component receives:

  • the wrong call shape
  • unsupported props
  • invalid values for enumerated props
  • missing required props

5. Smaller public API surface

Where possible, remove specialized wrappers and use variants instead.

Prefer:

Button({ label: "Save", tone: "primary" })
Button({ label: "Delete", tone: "danger" })
Button({ label: "Cancel", variant: "ghost" })

instead of:

PrimaryButton(...)
DangerButton(...)
GhostButton(...)

6. Public UI entrypoint discipline

Apps should import public components from:

/vroqjs/ui.js

ui.js should stay aligned with the migrated public API surface.

7. Demo app as migration safety net

The demo app in:

demo/r01

is the visual and manual test surface for this migration.

After each framework change:

1. patch the component 2. patch internal dependents if needed 3. patch the demo app 4. reload and test manually 5. update docs

Current migration principles

During this migration:

  • do not keep old public signatures once a component is migrated
  • prefer explicit contracts over convenience magic
  • prefer shared helpers over repeated local validation logic
  • patch framework dependents when a migrated component is used internally
  • keep runtime stable; most changes should stay in the component layer

Step-by-step migration plan

Step 1 — Define the vocabulary and conventions

Status: done

Completed work:

  • created 99-reference/component-vocabulary.md
  • created 99-reference/component-api-conventions.md
  • defined the canonical public component forms
  • defined the shared prop vocabulary

Step 2 — Create the demo app migration surface

Status: done

Completed work:

  • created demo/r01
  • used it as showcase and manual test app
  • began patching it to canonical APIs as components were migrated

Step 3 — Create shared validation helper

Status: done

Completed work:

  • created vroqjs/v02/system/ui/props.js
  • moved validateProps into shared helper code
  • documented that migrated components must use it

Step 4 — Migrate typography primitives

Status: in progress

Completed work:

  • migrated Text
  • migrated text helpers to object-first props
  • removed old positional public Text(...) usage
  • patched demo app Text calls

Still to watch:

  • patch internal users of Text when they still call it with legacy signatures

Step 5 — Migrate action primitives

Status: in progress

Completed work:

  • migrated Badge
  • migrated Button
  • migrated IconButton
  • removed public special button wrappers from ui.js
  • patched Dialog to use Button variants instead of special wrappers
  • patched demo app Badge and Button calls

Still to watch:

  • patch internal users of Button and IconButton when old signatures remain

Step 6 — Migrate segmented selection components

Status: in progress

Completed work:

  • migrated Segmented
  • patched it to use the new Button({ ...props }) form

Still to watch:

  • ensure supporting components allow required event props like onKeyDown

Step 7 — Migrate controlled input components

Status: done

Completed work:

  • migrated TextInput
  • migrated Checkbox
  • migrated Tabs
  • added explicit allowedProps
  • added shared validateProps usage
  • patched demo app to canonical controlled APIs

Target APIs:

TextInput({ value, onChange, label, placeholder, helper, error, success })
Checkbox({ checked, onChange, label, description })
Tabs({ value, onChange, items, variant, size, stretch, scroll })

Required work for each component:

  • define allowedProps
  • call validateProps
  • remove legacy binding-first and positional public API
  • patch internal users
  • patch demo app after migration
  • update docs/examples after migration

Step 8 — Migrate remaining interactive components

Status: mostly done

Completed work:

  • migrated ComboBox
  • migrated Slider
  • migrated Modal
  • migrated Toast
  • migrated TreeView

Still to evaluate:

  • Drawer
  • Toolbar
  • Navbar
  • ContextMenu

Priority rule:

  • migrate components with the most confusing signatures first
  • migrate components with the largest impact on app code before low-impact utility components

Step 9 — Normalize internal framework usage

Status: ongoing

Every time a component is migrated:

  • search framework components for old usage
  • patch internal calls to canonical props-first form
  • remove reliance on deleted wrappers or positional helper signatures

This is required because the framework itself is a consumer of the public component layer.

Step 10 — Update docs continuously

Status: ongoing

As each component family is migrated:

  • update examples to canonical API only
  • remove docs that teach old signatures
  • keep vocabulary and conventions docs aligned with the real code
  • use migrated components in the demo app as canonical examples

Step 11 — Keep the public API small and strict

Status: ongoing

After migration of a family:

  • do not add compatibility overloads back
  • do not add convenience wrappers unless they clearly reduce cognitive load
  • prefer variants and vocabulary over alias components
  • keep validation strict enough to catch wrong usage quickly

Step 12 — Final cleanup after major families are migrated

Status: later

After the main component families are migrated:

  • review ui.js exports
  • review demo app for remaining old patterns
  • review internal components for old calls
  • review docs for old examples
  • remove dead code or helpers that only existed for old signatures

Current migration status summary

Already migrated:

  • Text
  • Badge
  • Button
  • IconButton
  • Segmented
  • TextInput
  • Checkbox
  • Tabs
  • ComboBox
  • Slider
  • Modal
  • Toast
  • TreeView
  • CodeEditor
  • Scheme
  • Dialog

Partially migrated / still needs follow-up:

  • Card
  • Drawer
  • Toolbar
  • Navbar
  • ContextMenu

Standard checklist for each migrated component

For every component migration, follow this checklist:

1. read the current component source fully 2. define allowedProps 3. import and use validateProps 4. convert public API to object-first props 5. remove old public signatures 6. patch internal framework callers 7. patch the demo app 8. reload and manually test 9. update docs/examples 10. move to the next component only when the framework is working again

Final target state

This migration is successful when:

  • public components use only props-first APIs
  • component contracts are explicit in code
  • validation is shared and consistent
  • docs teach one canonical API style
  • the demo app uses only canonical APIs
  • LLMs can read a component file and quickly understand how to call it correctly