Skip to content

Next-gen: @javaabu/forms v1.0 #17

Open

Description

@n4ff4h

React version of javaabu/forms, published as @javaabu/forms. The repo has a v0 @javaabu/react-forms built only on Onu; rework it to be UI-framework-agnostic, with Onu and base shadcn/ui adapters, native Inertia and Wayfinder support, model binding, automatic errors and @javaabu/i18n strings.

Package: @javaabu/forms · Target: v1.0 · Wave: 1
Depends on: @javaabu/onu, @javaabu/i18n

Built to the next-gen general rules: CI with test and coverage badges, full docs for people and agents, Laravel Boost guideline and skill, Javaabu codestyle, PHP 8.4 / Laravel 12+ (Laravel packages) or TypeScript (JS packages), Dhivehi and RTL, Blade and Inertia React for views, overridable controllers and policies with javaabu/permissions.

Checklist

Developed by an agent orchestrated from the Javaabu next-gen plan. Cross-package requests go in the dependency's repo with the cross-package label.

Activity

  1. added
    next-genNext-gen Javaabu packages
    epicTracks a whole package
    on Nov 4, 2026
  2. n4ff4h commented on Nov 4, 2026

    @n4ff4h
    CollaboratorAuthor

    Implementation plan

    All work happens on the next-gen branch; one PR into main at the end.

    Architecture

    src/
      core/        no UI imports: FormsProvider, adapter registry, binding / old input, errors, field registry, Form submit logic, strings
      components/  the Blade components (Text, Select2, Checkbox, Table, ...). They resolve names, ids, values and errors, then render adapter slots
      adapters/
        html/      plain elements. The fallback for any slot an adapter leaves out, and the reference implementation
        onu/       @javaabu/forms/onu (+ /onu/editor and /onu/maps for the heavy Onu entries)
        shadcn/    @javaabu/forms/shadcn: createShadcnAdapter({ Input, Select, Checkbox, ... })
      inertia/     @javaabu/forms/inertia: router integration (visit, page errors and bags, Link). @inertiajs/react is an optional peer
      testing/     @javaabu/forms/testing: adapter conformance kit
    
    • Adapter = a plain object { name, components: Partial<Slots>, confirm?, toast? }. Resolution order for each slot: <FormsProvider components> override, then the ui adapter, then the HTML base. Adapters can therefore be partial, and you can combine several by spreading them ({ ...onu, ...onuEditor }).
    • Slots are named after the Blade components where they map one to one (Input, Textarea, Checkbox, Radio, Select, Date, File, Image, Number, Wysiwyg, MapInput, Button, LinkButton, ButtonGroup, Alert, Card*, Accordion, Tabs, NavTabs, Modal, Status, Table*, EmptyState, Pagination). They also cover the scaffolding: Form, Field, Label, RequiredMarker, HelpText, FieldErrors, ErrorSummary, Link, Icon, ActionMenu, DescriptionList.
    • Core owns the state. Every control is controlled by the core (value + onValueChange, or native props with a composed onChange for native-element slots). Ids, aria-invalid and aria-describedby come from the core. Native FormData stays the source of truth on submit, as in Blade. Adapters only render.
    • Strings use @javaabu/i18n with Blade's keys (forms::strings.nothing_selected). Lines the app loads (from lang/vendor/forms/{locale}/strings.php) win over the bundled en/dv defaults. Generated labels go through __(), as Blade's trans() does.

    Public API sketch

    import { FormsProvider, Form, Text, Select2, Submit } from "@javaabu/forms"
    import { onu } from "@javaabu/forms/onu"
    import { inertia } from "@javaabu/forms/inertia"
    import { store, update } from "@/actions/App/Http/Controllers/UserController" // Wayfinder
    
    <FormsProvider ui={onu} router={inertia} components={{ Select: MySelect }}>
      <Form model={user} action={update}>   {/* Wayfinder: called with the model, PUT spoofed */}
        <Text name="name" required />
        <Select2 name="country" options={countries} relation />
        <Submit />
      </Form>
    </FormsProvider>
    
    // Inertia useForm, with no glue code: fields bind to form.data, and errors, processing and progress come from the form
    const form = useForm({ name: "" })
    <Form form={form} action={store()}>...</Form>

    Submit modes, in order: form (Inertia useForm), then onSubmit, then the provider router (Inertia visit, or the core's fetch router for JSON 422 handling), then native submit. Errors come from Inertia page props (with errorBag), a 422 response, or the errors prop. Keys work in dot or bracket notation, plus items.0.name and tags.*. The ErrorSummary component focuses the first invalid field.

    Order of work

    1. Foundations: TypeScript build, dist, examples, CI and coverage #1 and Rename the package to @javaabu/forms #2 foundations and rename: ESM + CJS + d.ts, a prepare script, coverage and Codecov, examples, badges on next-gen
    2. UI-framework-agnostic core with a component adapter registry #3 core and adapter registry, Onu adapter #4 moving the Onu adapter (existing tests pass through it), Adapter contract for other UI frameworks #6 the contract, HTML adapter and conformance kit
    3. Use @javaabu/i18n for every string #11 i18n, Form model binding and old input #9 binding and old input, Automatic error display #10 errors
    4. Native Laravel Wayfinder support #8 Wayfinder, Native Laravel Inertia support #7 Inertia
    5. Base shadcn/ui adapter #5 shadcn adapter, tested against vendored stock shadcn components
    6. Component parity with javaabu/forms v2 #12 docs/parity.md (kept up to date throughout), Dhivehi localization and RTL #15 Dhivehi and RTL, Documentation for people and agents #13 docs and llms.txt, Laravel Boost guideline and skill #14 Boost

    Decisions and open questions

    • No IIFE build. The package is a React component library with peer dependencies, so a <script> build makes no sense. ESM and CJS only.
    • @javaabu/i18n dependency. It's a regular dependency for now, on github:Javaabu/i18n#build-on-git-install (the PR Foundations: TypeScript build, dist, examples, CI and coverage #1 branch, which has prepare), so CI can install it. I'll switch to #main once Build dist when installed from Git i18n#1 is merged, and to a peer dependency once it's on npm.
    • react-hook-form. The form prop of v0 (passed through to Onu's Form) becomes Inertia's useForm. To use react-hook-form, use onSubmit. This is noted in the migration docs.
    • Wysiwyg and MapInput move into the main entry (their logic is light). The heavy Onu parts move to @javaabu/forms/onu/editor and /onu/maps.
    • New component. ErrorSummary has no Blade v1 equivalent. It's listed in docs/parity.md so that v2 can add <x-forms::error-summary>.
  3. n4ff4h commented on Nov 4, 2026

    @n4ff4h
    CollaboratorAuthor

    Final summary

    All next-gen issues are closed except #16, which needs a human. The work is in PR #19 (next-gen → main), left open for you to review and merge.

    What was built

    • @javaabu/forms: the React version of javaabu/forms, with a UI-framework-agnostic core in src/core (no UI imports). Entry points:
      • . (components, provider, hooks, helpers, the adapter and router contracts, fetchRouter)
      • /html (the default adapter)
      • /onu, /onu/editor and /onu/maps
      • /shadcn (createShadcnAdapter)
      • /inertia (the router and inertiaLinks)
      • /testing (the adapter conformance kit, with 21 cases)
    • Adapters: HTML, Onu and shadcn (tested against stock new-york-v4 components) all pass the conformance kit.
    • Inertia: visits with files, method spoofing, error bags, progress and preserved state; useForm() binding; no glue code. Wayfinder: route objects, .form() variants and route functions with model binding. Without Inertia: fetchRouter, or a native submit.
    • Laravel behaviour: binding, old input and errors are checked against Blade.
    • Strings: @javaabu/i18n with Blade's keys, plus Dhivehi and RTL.
    • Parity: docs/parity.md, settled with the javaabu/forms v2 agent in Parity with javaabu/forms v2: defaults, Blade-only attributes and string keys #18.
    • Docs: Docusaurus pages, llms.txt, AGENTS.md, and the Laravel Boost guideline and javaabu-react-forms skill. The docs are kept in sync by src/docs.test.ts.
    • Examples: a page per integration, verified in headless Chromium. That check found and fixed a real bug: loading submit buttons didn't submit.
    • CI: lint, format, typecheck, 204 tests with coverage (thresholds at lines 85%, currently about 89%), build and examples, running on next-gen and on PRs.

    Intentionally out of scope

    • No IIFE / <script> build: this is a React library with peer dependencies.
    • Blade-only attributes (floating, dateFormat, the select2 icon picker, jsonEncode, …) are listed in docs/parity.md.
    • Image, Pagination, NavTabs and Map have no shadcn implementation. They use the HTML adapter, or you can replace them through components.
    • The Onu maps adapter is typechecked but not covered by tests, because it needs Google Maps.

    What you need to do

    1. Codecov: add CODECOV_TOKEN. Uploads currently fail with "Token required", and the badge stays empty until then.
    2. @javaabu/i18n dependency: it uses github:Javaabu/i18n#build-on-git-install, the branch of Build dist when installed from Git i18n#1, so CI can build it. After that PR merges, switch it to #main. After i18n is on npm, switch it to a version range, ideally as a peer.
    3. PR @javaabu/forms v1.0: UI-agnostic core, Onu and shadcn adapters, Inertia and Wayfinder #19: review and merge next-gen into main. Then release with changesets (pnpm changeset version, then a v* tag). Nothing has been tagged or published.
    4. Javaabu Docs: register the docs at docs.javaabu.com (Register with Javaabu Docs (docs.javaabu.com) #16).
    5. Dhivehi review: 41 Dhivehi lines need a native speaker. They're listed in docs/advanced-usage/dhivehi-and-rtl.md.
    6. Onu: Accordion: keep closed items' content mounted (forceMount) for forms onu#60 asks for accordions to keep closed items mounted for forms. Onu has no next-gen / cross-package labels, and I didn't create them.
    7. Dependents installing from Git with pnpm 10.34 or later must allow the build by its exact tarball URL, or run pnpm approve-builds. This is documented in the installation page.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicTracks a whole packagenext-genNext-gen Javaabu packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions