[#91] Added a non-interactive informational note field.#117
Conversation
📝 WalkthroughWalkthroughChangesAdds a non-interactive Note field support
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant PanelController
participant DefaultTheme
participant Engine
User->>PanelController: navigate and edit interactive field
PanelController->>DefaultTheme: render note card
DefaultTheme->>Engine: read current answer values
Engine-->>DefaultTheme: return interpolation values
DefaultTheme-->>User: display note without cursor interaction
PanelController->>Engine: resolve submitted inputs
Engine-->>PanelController: return answers without note fields
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
🚀 Deployed on https://6a62b20d6376dfc4004c3032--tui-docs.netlify.app |
This comment has been minimized.
This comment has been minimized.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #117 +/- ##
==========================================
+ Coverage 98.21% 98.66% +0.45%
==========================================
Files 100 100
Lines 3358 3450 +92
==========================================
+ Hits 3298 3404 +106
+ Misses 60 46 -14 ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Engine/Engine.php`:
- Around line 542-548: Update the fix-up processing near the existing target
check to also skip or reject any fix-up whose `from` field resolves to a
presentational field, before reading from `$values`. Preserve settled target
values when the source is presentational, and add a regression test covering a
fix-up that reads from a note.
In `@src/Theme/DefaultTheme.php`:
- Around line 1008-1018: Extract the shared note-title interpolation and
first-line normalization into a helper near the relevant rendering methods, then
reuse it from renderColumnBlock(), measureColumnBlock(), and renderNoteLines().
Preserve the existing empty-title handling and ensure the helper returns the
same first normalized line currently produced by Strings::interpolate(),
normalizeLines(), and explode().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bd27bc5e-700d-46e7-a79a-378378ecf2c0
📒 Files selected for processing (31)
.claude/demo_content_reference.mdplayground/02-widgets-all-widgets.phpplayground/02-widgets-note.phpsrc/Builder/FieldBuilder.phpsrc/Builder/PanelBuilder.phpsrc/Derive/Derive.phpsrc/Engine/Engine.phpsrc/Model/Field.phpsrc/Model/FieldType.phpsrc/Render/PanelController.phpsrc/Schema/AgentHelp.phpsrc/Schema/SchemaGenerator.phpsrc/Schema/SchemaValidator.phpsrc/Theme/DefaultTheme.phpsrc/Utils/Strings.phpsrc/Widget/WidgetFactory.phptests/phpunit/Fixtures/Form/AllWidgetsForm.phptests/phpunit/Unit/Builder/FormTest.phptests/phpunit/Unit/Engine/EngineConditionalTest.phptests/phpunit/Unit/Engine/EngineNonInteractiveTest.phptests/phpunit/Unit/Model/OptionTest.phptests/phpunit/Unit/Render/PanelControllerTest.phptests/phpunit/Unit/Schema/AgentHelpTest.phptests/phpunit/Unit/Schema/SchemaGeneratorTest.phptests/phpunit/Unit/Schema/SchemaValidatorTest.phptests/phpunit/Unit/Testing/AllWidgetsFormTest.phptests/phpunit/Unit/Theme/ThemeLayoutTest.phptests/phpunit/Unit/Theme/ThemeRenderTest.phptests/phpunit/Unit/Utils/StringsTest.phptests/phpunit/Unit/Widget/WidgetFactoryTest.phptranslations/en.php
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/content/widgets/note.mdx`:
- Around line 22-25: Make the interpolation example around note() self-contained
by adding a preceding declaration or population of the item field before the
description uses {{item}}. Keep the existing note construction intact and ensure
readers can copy the snippet and observe resolved interpolation without relying
on prior form context.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6875935f-48bc-4e10-9d5e-cc0e66108039
⛔ Files ignored due to path filters (24)
docs/assets/widget-note-dark-animated-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-animated-ascii.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-animated-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-animated.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-static-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-static-ascii.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-static-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-dark-static.svgis excluded by!**/*.svgdocs/assets/widget-note-light-animated-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-light-animated-ascii.svgis excluded by!**/*.svgdocs/assets/widget-note-light-animated-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-light-animated.svgis excluded by!**/*.svgdocs/assets/widget-note-light-static-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-light-static-ascii.svgis excluded by!**/*.svgdocs/assets/widget-note-light-static-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-note-light-static.svgis excluded by!**/*.svgdocs/assets/widgets-dark-animated-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets-dark-animated-ascii.svgis excluded by!**/*.svgdocs/assets/widgets-dark-animated-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets-dark-animated.svgis excluded by!**/*.svgdocs/assets/widgets-light-animated-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets-light-animated-ascii.svgis excluded by!**/*.svgdocs/assets/widgets-light-animated-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets-light-animated.svgis excluded by!**/*.svg
📒 Files selected for processing (5)
AGENTS.mddocs/content/widgets/index.mdxdocs/content/widgets/note.mdxdocs/sidebars.jsdocs/util/render-widget-svgs.php
The '{{field}}' token replacement lived privately in 'Derive'. Moved it to 'Strings::interpolate()' so the note field can reuse the same templating without duplicating the callback. 'Derive::compute()' now delegates to it, unchanged in behaviour.
A note renders a title and body inline as a read-only card. The selection cursor skips it, it contributes nothing to the answers payload, and it is absent from headless collection and both machine schemas. Its title and body take the same '{{field}}' templating derived values use, so a note can reflect earlier answers; '->border()' frames the card in the theme's box.
The card is presentational, keyed off a new 'FieldType::isPresentational()': the engine and panel controller exclude it from answers and navigation, while the theme renders it via 'renderNoteLines()'. Declared with 'note(id, title)->description(body)'.
The button selection offset read 'Panel::itemCount()', which counts presentational notes, while the cursor indexes only navigable items. In a modal (or any panel showing buttons) that held a note, the offset was one too high per note, so the highlighted button drifted or vanished. Both the hub and modal frames now derive the offset from 'itemCountFor()', matching the navigation.
A note now never enters the value or source maps: 'resolveAll()' skips it, so it cannot be resolved from a supplied input nor influence a later field's context, and 'ruleMap()' skips it, so it never carries a derive rule that would resolve against a missing source. The engine test proves a note with a validator and a throwing transformer, handed a malformed value, still contributes nothing and never runs either.
The title now splits on its own newlines like the body, so no rendered line carries an embedded newline that would break the box and scroll maths; the grid preview and its measurement take the title's first line, matching how field values already collapse in a one-row cell.
A fix-up sets a field's value, but a note has none. A rule mistakenly targeting a note is now skipped in 'applyFixups()' rather than writing a value into the settled state, so the no-value invariant holds even under a misconfigured form.
…ding. The builder test asserts the field exists before reading its properties, dropping the nullsafe accesses. The all-widgets fixture note uses neutral, widget-focused wording, consistent with the rest of that fixture rather than the produce demo theme.
Split the combined early-continue guards into one condition each, switched a null assertion to 'assertNotInstanceOf()', and used a first-class callable in an 'array_map()' - the modernizations Rector enforces.
A fix-up whose 'from' field is presentational is now skipped as well as one whose 'set' target is: reading a note's absent value would write NULL over the target's settled value. The note-title interpolation and first-line extraction move into 'noteText()' and 'noteTitleFirstLine()', reused by 'renderNoteLines()', 'renderColumnBlock()' and 'measureColumnBlock()'.
Rendered the note widget's 16 SVG variants and added its 'docs/content/widgets/note.mdx' page, sidebar entry and widgets-index entry. Regenerated the all-widgets montage so the gallery includes the note card. Added a 'note' spec to the widget SVG renderer and documented in AGENTS.md that every widget must ship its full SVG set.
…voice. The base docs switched to US spelling and 'kbd' key markup; 'note.mdx' now uses 'behavior'/'color' and Prettier's table formatting, and the note merges into the rewritten widgets index.
90a7239 to
678a3b6
Compare
This comment has been minimized.
This comment has been minimized.
The '{{item}}' example now declares the 'item' text field it reflects, so the snippet demonstrates resolved interpolation when copied as-is.
|
Closes #91
Summary
Adds a
notefield type: a non-interactive, non-blocking informational card. It renders a title and body inline, is skipped by the selection cursor, and contributes nothing to the answers payload. A note is absent from headless collection and from both machine schemas, it honours->when()like any other field, and it interpolates{{field}}tokens in its title and body so it can reflect earlier answers.->border()frames it in the theme's box.Changes
{{field}}interpolation into a sharedStrings::interpolate()helper, reused byDeriveand the new note rendering, instead of duplicating the token-replacement logic.FieldType::Notecase and anisPresentational()predicate that marks a field as display-only.note(id, title)->description(body)->border()builder API onPanelBuilderandFieldBuilder.renderNoteLines()card rendering, plus grid-preview and content-width measurement support for a note.AgentHelp,SchemaGeneratorandSchemaValidator, so a note is never a prompt or a validated answer in the machine-readable schemas.TuiTester-driven interaction tests, and a newplayground/02-widgets-note.phpdemo.docs/content/widgets/note.mdxpage and sidebar entry, and regenerated the all-widgets montage so the gallery includes the note card.AGENTS.mdnow records that every widget must ship its full SVG set.Before / After
Summary by CodeRabbit
{{field}}template interpolation.