Own all form styling in components; remove form CSS from input.css
Form controls were styled "at a distance": Django renders bare <input>/<select>/<textarea>/<label>, so input.css reached in with ID-scoped #add-form descendant rules plus a global form *:disabled rule and .errorlist. The #add-form ID specificity forced state rules to climb, needed :not([data-search-select-search]) carve-outs, and broke on markup changes — it surfaced as the add_purchase Name/related_game fields not reading as disabled. Components now own all form styling via utilities on the elements themselves: - PrimitiveWidgetsMixin stamps INPUT/SELECT/TEXTAREA_CLASS (incl. disabled: variants) onto native widgets by type, skipping SearchSelect (self-styled) and checkboxes. - New FormFields(form, *, extras=...) renders label + control + errors + row layout with their own classes (replaces form.as_div()); the <form> owns its flex layout. extras appends a node into a named field's row (session timestamp buttons). - AddForm/purchase/session render via FormFields; login too — a new LoginForm(PrimitiveWidgetsMixin, AuthenticationForm) styles its inputs and auth.py renders it via FormFields + a StyledButton (was as_table). - input.css loses the entire #add-form block, the global :disabled rule, and .errorlist. State (disabled:) now lives on the element — no specificity wars, no carve-outs, robust to markup edits. Tests: error rendering uses the component class (not .errorlist); add-form labels/inputs carry their own classes; e2e login fixtures click the Login button by text (submit is now a <button>); Name disabled cursor asserted. CLAUDE.md documents the no-styling-at-a-distance + FormFields conventions. 513 passed; lint/format/ts-check clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ from common.components import (
|
||||
CsrfInput,
|
||||
Div,
|
||||
Element,
|
||||
FormFields,
|
||||
Fragment,
|
||||
GameLink,
|
||||
Icon,
|
||||
@@ -32,7 +33,6 @@ from common.components import (
|
||||
Node,
|
||||
PriceConverted,
|
||||
PurchasePrice,
|
||||
Safe,
|
||||
SelectionFields,
|
||||
StyledButton,
|
||||
TableRow,
|
||||
@@ -296,7 +296,7 @@ def add_purchase(request: HttpRequest, game_id: int = 0) -> HttpResponse:
|
||||
AddForm(
|
||||
form,
|
||||
request=request,
|
||||
fields=Fragment(Safe(form.as_div()), _pricing_controls()),
|
||||
fields=Fragment(FormFields(form), _pricing_controls()),
|
||||
additional_row=_purchase_additional_row(),
|
||||
),
|
||||
title="Add New Purchase",
|
||||
|
||||
Reference in New Issue
Block a user