Repository navigation
Conversation
….10.64 The Qorus IDE is moving to a calmer design — colour only where something needs a person, panels on one surface edged by one hairline, quiet headings and counts — and every creator, editor and many dialogs there render through FormEngine's compact mode. It was the biggest surface still in the old look: a green Ready and meter, green/amber tinted boxes with coloured count tags, a recessed black Optional box, a dot on every row, upper-case group labels and "SELECT ONE:", red asterisks and a red "This field is required", Yes/No as green/red chips, and the outer panel drawn as a card around its own boxes once a theme gives panels a surface. Other apps use Reqraft, so the new look is opt-in: `appearance="calm"` on FormEngine, published through FormAppearanceContext so nested sub-forms and the field editors a form mounts follow it, and a FormAppearanceProvider for a host that wants to set it once. Every look choice is decided once inside the engine; nothing a row does reads it, so bucketing, counts, validation, templates, search, the optional fields and read mode are the same in both. In the calm look the status boxes are plain panels on the theme's panel surface with label/value rows split by full-width hairlines; labels are grey; group headings, choice headings, radio options and preview labels keep their case; an empty required value reads "Required · add a value" in amber where the value would be (read-only: "Required · not set") instead of an asterisk and a red message; counts are quiet numbers; only Needs attention carries a dot, and a row keeps one only when its value fails; Yes/No are words; Done and Cancel are neutral; the readiness line is one quiet line with a short meter whose done part is grey and only the outstanding part amber; messages under an open field are lines of text; read mode is one hairline-split list flush with its host. The default look is unchanged (the existing FormEngine stories pass as they were). Stories: Form/Engine/FormEngine Appearance, with plays measuring the surfaces, hairlines, case, dots, colours, meter and phone width. Closes #144
|
📦 Prerelease published for this PR: Install it in a consumer (updates yarn add @qoretechnologies/reqraft@0.10.65-pr.145.gc151336Published under the |
qlip visual regression🔍 62 changed, 7 new of 604 snapshots. |
Seen in the Qorus IDE's column drawer: a field's schema note that only
explains ("The type decides which of the fields below apply") drew as a blue
info panel, while in the calm look blue says only "a filter is on" and green
is for a healthy figure. In the calm appearance an info or success note now
takes no intent; warning and danger notes keep theirs, because those are what
a person has to act on. The Calm story asserts the note's surface is grey.
The story frame also fills its width, so it renders the same in the Storybook
UI as in the story run.
Refs #144
TicketHeader passed uppercaseLabels to its description list, so the rail read STATUS / OPENED BY in an app whose theme sets every label in sentence case. Leaving the prop out lets the theme decide; a theme that says nothing still gets uppercase, as before.
A brand-new form opened with "2 need attention" and every empty required
field in amber before anyone had typed, so the first thing a person met
was a list of faults (the Goal-gradient finding of the IDE's UX review).
An empty required field nobody has been to yet is now `pending`: still in
the first box, which reads "To fill in" in the quiet colour, with the
requirement stated plainly ("Required · add a value", "This field is
required") and no amber. It becomes a fault (`todo`, amber) once the
person opens it and leaves it empty, or when the host reports a submit
attempt through the new `revealRequired` prop. Invalid values are faults
from the start, as before.
- readFirst: the `pending` status; `getReadFirstStatus` takes `visited`
(unset means visited, the old behaviour).
- FormEngine: `visitedOptions` (rows opened and left), `revealRequired`,
a fault count for the toolbar and the first box; the box is "Needs
attention" with its amber dot only while it holds a fault;
`compactBoxLabels.pending` renames "To fill in".
- CompactRow / OptionFieldMessages: the requirement is stated with no
intent until the field is visited (`requirementPending`).
- CompactToolbar: "N to fill in →" in the quiet colour; once something
is a fault, "N need attention → · M to fill in", and the meter's amber
run counts faults only.
- Stories about which box a field lands in find the first box under
either name; "Calm Needs Attention" shows the state after a submit
attempt, and "Calm New Form" shows a new form and the visit.
…ngine-calm-appearance # Conflicts: # package.json
…ther The quiet "to fill in" state reached the collapsed rows, the box and the readiness line, but not the line under an open editor: OptionFieldMessages took no requirementPending, so a host that opens the first empty field for typing (the IDE's creators do) showed that one field in amber on a form nobody had touched. The editor's message now follows the same rule as the row (open is not left; a submit attempt reveals all), in the row's faint pending colour. CalmNewForm asserts the open field's message is not amber; it fails without the fix.
…ubmit with where to type
Two seams for a host that draws its own submit control (the IDE's editor rail):
- onAttentionChange reports the readiness line's two numbers ({ count, faults })
whenever they change, so a submit button drawn from them can never disagree
with the form about what is left.
- focusAttentionRequest: each new value opens the first field that needs
attention and puts the caret in it, the answer to a submit that could not go.
The submit button holds the caret at that moment and an open row never takes
a caret held outside it, so the engine lets go of it first; a field that is
already open gets the caret directly.
The arrival opener and the new request share one scan (getAttentionFieldMeta,
openOption), so both pick the same field. The open row's editor cell carries
options-readfirst-row-editor so the caret lands in the control, not the label.
…d in "N need attention →" shows only the fields that are still invalid. The first character typed into an empty required field makes it valid, so the row was filtered out from under the caret mid-word and the rest of the keystrokes went nowhere. An open row now stays while the reader is in it, the same rule its box already follows (stableBucketOf), and leaves the filtered list once it is closed. It mattered more now that a blocked submit turns the filter on and puts the caret in the first field to fill in. The new test types the first letters, waits for the form to take them, then types the rest; it fails without the fix.
…N to fill in →" is a real toggle Two gaps a blocked submit made visible: - A field that opens as a card (a long text, a description, source code) never took the caret on opening; only the inline row did. So clicking Description opened it and left the cursor nowhere, and a submit request opened it without the caret. The card now carries the same row and editor refs as the inline row, so the one tap-to-edit rule covers both shapes. - "N need attention →" / "N to fill in →" was a clickable span: no role, no keyboard, no state. It is a toggle (show only those fields), so it is now a button with aria-pressed, Enter and Space. A host that turns it on for a person reads aria-pressed instead of guessing; the toolbar draws a different link once something becomes a fault, so a mark the host left on the old one was lost and a second press turned the filter back off.
… role="textbox" is text Giving cards the row's caret rule exposed two gaps, found by typing into a job's Source Code after a blocked submit: - A code editor's edit area (Monaco) is a focusable div with role="textbox"; its <textarea> is an aria-hidden IME helper. The text-entry scan knew input, textarea and contenteditable only, so it fell through to the first button: the editor's fullscreen toggle. - A card is a form in its own right, so its first button is one of several and nobody asked for it; a caret there turned the next space typed into a press (the fullscreen editor opened). A card now takes the caret only where text goes (findRowFocusTarget textEntryOnly), and waits for a late editor to mount; an inline row still hands it to its control.
…hrome A job's Source Code opens inline, and its code editor mounts after the row does. Until then the only control in the row is the editor's fullscreen toggle, so the row put the caret there and stopped watching; the next space typed pressed it and the fullscreen editor opened. A control that is not a text box now holds the caret provisionally: when a text box arrives (Monaco's edit area, role="textbox") it takes the caret, unless the reader has moved it since. A row that never grows one, a pick-one, keeps its control, and a picker still opens as before.
…nded Traced live on a job's Source Code: the row did move the caret from the editor's fullscreen toggle to Monaco's edit area when it appeared, but focus() on it did nothing (it is inserted before it can take focus), and the row gave up after that one try. A focus() that did not land no longer settles the caret; the row tries again on the editor's next change, and it watches attribute changes too, since that is how a text box can become focusable after it is inserted. It still stops the moment the reader moves the caret themselves.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, for Filip to review — please don't merge yet.
Closes #144
Why
The Qorus IDE is moving to a calmer design: colour only where something needs a person, panels on one surface edged by one hairline, quiet headings and counts (instruction-files
BRAND_DESIGN.md§1, decisions 001 / 004 / 005 / 006 / 017). Every IDE creator, editor and many dialogs render through FormEngine's compact mode, and it was the biggest surface still in the old look — green Ready and meter, green/amber tinted boxes with coloured count tags, a dot on every row, UPPERCASE group labels and "SELECT ONE:", red asterisks and a red "This field is required", Yes/No as green/red chips, and the outer panel painting a card around its own boxes once a theme gives panels a surface.Other apps use Reqraft too, so the new look is opt-in: nothing changes for a consumer that does not ask for it.
The opt-in
appearance?: 'default' | 'calm'onFormEngine(default'default').FormEnginepublishes it throughFormAppearanceContext. Nestedarg_schemasub-forms and every field editor the form mounts follow it; a form without its ownappearancefollows aFormAppearanceProviderabove it, so a host can also set it once for its whole tree.formAppearance.ts+ the engine's styled parts). Nothing a row does reads it: bucketing, counts, validation, templates, search, the optional fields and read mode (fix(form-engine): read-only is a view, not a disabled editor #107) are identical in both looks.What
calmchangesSections (Needs attention / Set / Optional)
Rows
Headings
ChoiceGroupHeadingfor both choice editors. Radio-group option names and the schema preview's field names are no longer upper-cased.Readiness line
Messages under an open field
Read mode
A new form is not already wrong (both looks)
A brand-new form used to open with "2 need attention" and every required field in amber before anyone had typed, so the first thing a person met was a list of faults. Now:
pending: still in the first box, which reads To fill in in the quiet colour, with the requirement stated plainly ("Required · add a value" / "This field is required") and no intent.todo, amber, under Needs attention with its dot) once the person opens it and leaves it empty, or when the host reports a failed submit with the newrevealRequiredprop. A value that fails validation is a fault from the start, as before. Open is not left: a field the form opens for typing on arrival (the first empty one) says its requirement under the editor in the same quiet colour (OptionFieldMessagestakesrequirementPending).onAttentionChange({ count, faults })reports the readiness line's two numbers, so a submit button drawn from them can never disagree with the form.focusAttentionRequest(bump it per press) opens the first field that needs attention and puts the caret in it, though the submit button holds the caret at that moment; an already-open field gets the caret directly. The arrival opener and the request share one scan.aria-pressed, Enter and Space.compactBoxLabels.pendingrenames "To fill in".getReadFirstStatustakesvisited(unset = visited, the old behaviour);getOptionFieldMessagestakesrequirementPending.formEngineFreshForm.test.tsx,readFirst.test.ts; storyFormEngine Appearance › Calm New Form(a new form, then a visit). Stories about which box a field lands in find the first box under either name;Calm Needs Attentionnow shows the state after a submit attempt.Version
0.10.65: develop published 0.10.64 (the security dependency updates) while this PR was open, so the branch merged develop and bumped once more.
Not in this PR
Stories
Form/Engine/FormEngine Appearance— the same workflow-creator form in both looks:Checks
Run locally on this branch (in a worktree outside
.claude/worktrees, so the pre-push hook ran normally):yarn test— 176 files, 1877 tests, all passyarn lint,yarn build:test,yarn build:test:prod— cleanyarn test:stories FormEngineAppearance— 6/6yarn test:stories FormEngine.stories— 151/151 (the default look is untouched)Version: 0.10.63 — one patch bump, as the PR gate requires. The open #137 claims the same number; whichever merges second rebases and bumps again.
🤖 Generated with Claude Code