Skip to content

forms(qml): SlotRegistry.byKind -- one host control per kind of control (fixes #812) - #816

Merged
Yaraslaut merged 1 commit into
masterfrom
feature/forms-slot-by-kind
Sep 25, 2026
Merged

Yaraslaut merged 1 commit into
masterfrom
feature/forms-slot-by-kind

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

Fixes #812. byType keys on the JSON type, which does not name a control (Quantity and nested object are both "object", Choice is "integer", enum and Timestamp are "string"), so a host supplying all controls from its own kit had to register per field.

  • Field descriptors gain kind, chosen in the order fieldJsonLiteral picks its encoder: objectArray, array, enum, choice, datetime, date, quantity, integer, boolean, number, object, string.
  • SlotRegistry.byKind(kind, component); resolve(action, field, xWidget, unitAscii, jsonType, kind) — kind optional, order field → x-widget → unit → kind → type. Five-argument callers unchanged.
  • Spec: docs/spec/forms/forms.md "Theming / component-override registry" (kind table).

Tests (MSVC 14.51, Qt 6.11.1): new tst_SlotRegistryByKind.qml — one member of every kind in schemaJson shape, with competing byType slots registered; removing the tier reddens 4 of 5 cases. forms_qml_logic 324 passed.

Touches the same resolve(...) call as #809 (slotClaims); resolved on the combined branch.

🤖 Generated with Claude Code

…ol (fixes #812)

`byType` keys on the JSON type, which does not name a control: a Quantity and
a nested object are both "object", a Choice is "integer", an enum and a
Timestamp are "string". A host whose every control comes from its own kit
therefore had to register byField per action and field, or byUnit per unit.

Every field descriptor now carries `kind` -- the control DynamicForm would
draw, decided in the order fieldJsonLiteral picks its encoder: objectArray,
array, enum, choice, datetime, date, quantity, integer, boolean, number,
object, string. `SlotRegistry.byKind(kind, component)` registers for it, and
`resolve()` takes `kind` as an optional sixth argument, consulted after unit
and before type, so the five-argument call resolves exactly as before and a
field / x-widget / unit registration still wins.

tst_SlotRegistryByKind.qml builds one member of every kind in the shape
schemaJson<A>() emits, with a byType slot registered for each JSON type in
play, and asserts the byKind slot is the one loaded. Removing the tier from
resolve() reddens 4 of its 5 cases. forms_qml_logic: 324 passed on MSVC 14.51
/ Qt 6.11.1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Yaraslaut added a commit that referenced this pull request Sep 25, 2026
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819)

#810 made DynamicForm's chrome replaceable. The two composing views still
hard-coded theirs -- title, column headers, row cells, Open / row-action /
collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next
and the step counter -- and, more to the point, never gave the DynamicForms
they embed a slotRegistry at all: a host's field slots and form chrome stopped
at the view's edge, so even a fully registered kit drew built-in editors.

  - `slotRegistry` on both views, handed to modalForm / detailForm and to every
    wizard step.
  - CollectionView roles: collectionHeader (title, columns, actions, fire),
    collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire),
    confirmDialog (message, action, row, accept, reject -- loaded only while an
    action waits) and editorDialog (title, open, close, and a contentItem the
    editor form is reparented into).
  - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle)
    and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the
    built-in gate: the step's action must have replied ok.
  - DateTimePicker gets no chrome: a host replaces the whole picker with a
    field slot, byKind("datetime") from #816.

Nothing registered, nothing changes: tst_collectionview.qml and
tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins
each role, the embedded forms receiving the registry, and a fully chromed
collection screen with the editor open showing no visible built-in Label or
Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of
them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1.

Stacked on #810 (byChrome / resolveChrome).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Yaraslaut
Yaraslaut merged commit 86c7139 into master Sep 25, 2026
60 of 62 checks passed
Yaraslaut added a commit that referenced this pull request Sep 25, 2026
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819)

hard-coded theirs -- title, column headers, row cells, Open / row-action /
collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next
and the step counter -- and, more to the point, never gave the DynamicForms
they embed a slotRegistry at all: a host's field slots and form chrome stopped
at the view's edge, so even a fully registered kit drew built-in editors.

  - `slotRegistry` on both views, handed to modalForm / detailForm and to every
    wizard step.
  - CollectionView roles: collectionHeader (title, columns, actions, fire),
    collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire),
    confirmDialog (message, action, row, accept, reject -- loaded only while an
    action waits) and editorDialog (title, open, close, and a contentItem the
    editor form is reparented into).
  - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle)
    and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the
    built-in gate: the step's action must have replied ok.
  - DateTimePicker gets no chrome: a host replaces the whole picker with a
    field slot, byKind("datetime") from #816.

Nothing registered, nothing changes: tst_collectionview.qml and
tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins
each role, the embedded forms receiving the registry, and a fully chromed
collection screen with the editor open showing no visible built-in Label or
Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of
them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1.

Stacked on #810 (byChrome / resolveChrome).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Yaraslaut added a commit that referenced this pull request Sep 25, 2026
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819)

hard-coded theirs -- title, column headers, row cells, Open / row-action /
collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next
and the step counter -- and, more to the point, never gave the DynamicForms
they embed a slotRegistry at all: a host's field slots and form chrome stopped
at the view's edge, so even a fully registered kit drew built-in editors.

  - `slotRegistry` on both views, handed to modalForm / detailForm and to every
    wizard step.
  - CollectionView roles: collectionHeader (title, columns, actions, fire),
    collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire),
    confirmDialog (message, action, row, accept, reject -- loaded only while an
    action waits) and editorDialog (title, open, close, and a contentItem the
    editor form is reparented into).
  - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle)
    and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the
    built-in gate: the step's action must have replied ok.
  - DateTimePicker gets no chrome: a host replaces the whole picker with a
    field slot, byKind("datetime") from #816.

Nothing registered, nothing changes: tst_collectionview.qml and
tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins
each role, the embedded forms receiving the registry, and a fully chromed
collection screen with the editor open showing no visible built-in Label or
Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of
them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1.

Stacked on #810 (byChrome / resolveChrome).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Yaraslaut added a commit that referenced this pull request Sep 25, 2026
…tainers and buttons, not only its controls (#810)

* forms(qml): chrome slots -- a host replaces DynamicForm's labels, containers and buttons, not only its controls

SlotRegistry lets a host swap a field's *control*, but everything around the
controls stayed built-in: the bold caption and red `*`, the help line, the
section heading and accordion toggle, the TabBar, the action-type heading, the
status line, the Submit button, the monospace JSON preview and the reply line.
A host whose look comes from one UI kit therefore could not get a form that
looked like the rest of the app, whatever slots it registered.

`SlotRegistry.byChrome(role, component)` / `resolveChrome(role)` register one
Component per role -- fieldLabel, fieldHelp, section, accordion (falls back to
section), tabset, header, status, submitButton, preview, result -- and
DynamicForm loads it in place of the built-in, which is hidden rather than
drawn beside it. Each chrome item is handed only the members it declares
(`bindChrome`), as bindings where the value changes: a label gets `required`
(including requiredWhen) and `invalid` (typed text that does not encode, via
the new `fieldInvalid(name)`); the status line's text moved into
`DynamicForm.statusText` so the built-in and a chrome read one source.

Container chrome (section / accordion / tabset) declares a `contentItem`, and
the form creates its field grid inside it. The built-in grid's Repeater is
emptied under a chrome, so each field exists once and its `field_<name>`
objectName stays unique -- prefill, resetFields() and name-based lookups keep
working. A tabset chrome owns `currentIndex`; the form rebuilds the selected
tab's fields on a switch exactly as the built-in tab bar does. A chrome
submit button goes through `submit()`, so the `ready` guard still holds.

Nothing registered, nothing changes: the existing 317 QML cases are untouched
and green. The new tst_DynamicFormChrome.qml (13 cases) pins each role, and a
form with every role registered showing no visible built-in Label, Button or
TabBar. Restoring the section Repeater under a chrome reddens the
fields-created-once case. forms_qml_logic: 330 passed on MSVC 14.51 / Qt
6.11.1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* forms(qml): CollectionView and WizardView chrome through SlotRegistry.byChrome, and the registry reaches the forms they embed (fixes #813) (#819)

hard-coded theirs -- title, column headers, row cells, Open / row-action /
collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next
and the step counter -- and, more to the point, never gave the DynamicForms
they embed a slotRegistry at all: a host's field slots and form chrome stopped
at the view's edge, so even a fully registered kit drew built-in editors.

  - `slotRegistry` on both views, handed to modalForm / detailForm and to every
    wizard step.
  - CollectionView roles: collectionHeader (title, columns, actions, fire),
    collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire),
    confirmDialog (message, action, row, accept, reject -- loaded only while an
    action waits) and editorDialog (title, open, close, and a contentItem the
    editor form is reparented into).
  - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle)
    and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the
    built-in gate: the step's action must have replied ok.
  - DateTimePicker gets no chrome: a host replaces the whole picker with a
    field slot, byKind("datetime") from #816.

Nothing registered, nothing changes: tst_collectionview.qml and
tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins
each role, the embedded forms receiving the registry, and a fully chromed
collection screen with the editor open showing no visible built-in Label or
Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of
them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1.

Stacked on #810 (byChrome / resolveChrome).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

forms(qml): SlotRegistry has no tier by renderer kind, so a host cannot restyle every Quantity / Choice / enum / date-time control at once

1 participant