Skip to content

feat: author the auth kit and password field as Layouts - #229

Closed
pathscale wants to merge 11 commits into
masterfrom
feat/auth-family-layouts
Closed

feat: author the auth kit and password field as Layouts#229
pathscale wants to merge 11 commits into
masterfrom
feat/auth-family-layouts

Conversation

@pathscale

Copy link
Copy Markdown
Owner

What

The auth kit and password field were exported from @pathscale/ui but were never authored as Layouts. They are the only components in the library without a recipe, and they are absent from dist/layouts.manifest.json.

That combination is worse than it sounds: because they are exported, an application imports them normally and typechecks fine, then the application compiler hard-fails the build.

LoginPage.tsx:74:10: error: no Layout found for public export `AuthCard` imported from "@pathscale/ui" as `AuthCard`

Ten components are ported: AuthCard, AuthErrorMessage, AuthFieldGroup, AuthFooterLinks, AuthForm, AuthPoweredBy, AuthSubmitButton, AuthSuccessMessage, PasswordField, PasswordRequirements. (password-rules is a function barrel with no component and needs nothing.)

Public API

Unchanged. Every prop keeps its name, type and default, so no consumer edit is required. What changed is where presentation lives:

  • Inline Tailwind and local ALIGN_CLASS / GAP_CLASS records become recipe axes (gap, align, variant) resolved from one compiled table.
  • BEM classes move into a per-component .css file, matching every other component here.
  • Per-item and per-row state (AuthFooterLinks disabled, PasswordRequirements passed) moves onto data-* attributes styled by the recipe instead of a class ternary at each branch.
  • AuthCard gains named slots: header, headings, title, description, branding, body, footer.
  • AuthSubmitButton drops its variant translation helper. The four variants it accepted were already named exactly as Button names them, so it forwards rather than mapping.
  • PasswordField's pure helpers move to PasswordField.interactions.ts, following the split Slider already uses. They remain exported from the component's barrel, and the existing tests import them from the new path.

Two things worth knowing for the next port

A .layout.tsx template resolves free identifiers against props. A bare queueMicrotask(...) in a template compiles to props.queueMicrotask(...), which then fails typecheck as unknown. document is on the known-globals list; queueMicrotask is not. The deferred restore moved into the interactions module for this reason, which is the better split anyway.

Adding a component forces a full regeneration, and a full pass reports every diagnostic in the library. The 1,819 pre-existing ones are recorded in layouts.lint-baseline.json, so only genuinely new diagnostics fail. New components have to satisfy the rules the baseline is suppressing elsewhere: declare a root slot, render every slot declared, and keep the recipe a statically analyzable object literal (no CLASSES.base references, which is what Skeleton and Spinner are baselined for).

Verification

  • bun run check green: 102 components pass contract checks, 0 new diagnostics.
  • tsc --noEmit clean.
  • rslib build green. Manifest goes from 231 to 241 components, all ten "kind": "embedded".
  • support.cafe, the app this unblocks, goes from 2 failing files to 130/130 compiling through the application compiler, and its login and signup pages render and behave correctly against this build (recipe classes applied, PasswordField's visibility toggle preserves value, selection and focus, aria-pressed and label update).

Note

docs/ui-usage.md described the auth kit as "thin Tailwind-utility wrappers". That is updated in the same change, as the working agreement requires.

meh added 11 commits August 14, 2026 00:20
AuthFieldGroup was exported from the package but absent from the Layout
manifest, so the application compiler rejected every consumer that imported
it. Presentation moves from inline Tailwind into the recipe, and the gap axis
becomes a declared presentation prop rather than a local class record.
The gap and full-width sizing move out of inline utilities and into the recipe, so a consumer no longer restates the form's spacing to match it.
Delegates to Alert with status=danger as before. The type scale is the recipe's now rather than a call-site class.
Mirrors AuthErrorMessage: Alert with status=success, role=status and aria-live=polite so a screen reader announces it without stealing focus.
Drops the variant translation helper: the four variants it accepted were already named exactly as Button names them, so it forwards instead of mapping.
The align and variant axes become declared presentation parameters instead of two local class records, so the combination is resolved from one compiled table.
Per-item disabled state moves to a data-disabled attribute styled by the recipe rather than a class ternary at each branch. The selectors match =true explicitly: a recipe reports both directions, so a bare presence selector would also match the enabled case.
The header, headings, title, description and branding regions become named slots, so a consumer can target them without reaching for the Tailwind classes that used to be inlined here. bodyClass still merges over the body slot.
Met and unmet appearance moves onto data-passed and into the recipe, so the two states are described in one place instead of a class ternary per row.
The visibility helpers move to PasswordField.interactions.ts, following the split Slider already uses, and the tests import them from there.

Deferring the post-toggle restore also moves into that module. A .layout.tsx template resolves free identifiers against props, so a bare queueMicrotask in the template compiles to props.queueMicrotask, which typechecks as unknown and fails.
The inventory still called these thin Tailwind-utility wrappers, which stopped being true when they gained recipes. Names the presentation parameters and AuthCard's slots so a consumer can find them without reading the source.
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview deployment is ready!

You can view the preview at: https://pr-ui-preview-229.surge.sh

@pathscale pathscale mentioned this pull request Aug 14, 2026
@pathscale

Copy link
Copy Markdown
Owner Author

Superseded by #230, which contains every commit from this branch. Closing so there is one branch and one PR for 2.2.

@pathscale pathscale closed this Aug 14, 2026
@pathscale
pathscale deleted the feat/auth-family-layouts branch August 15, 2026 00:41
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.

1 participant