[#17] Added a toggle switch widget.#28
Conversation
📝 WalkthroughWalkthroughAdds a two-option ChangesToggle widget
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Terminal
participant KeyParser
participant ToggleWidget
participant WidgetRunner
Terminal->>KeyParser: read and parse keypress
KeyParser->>ToggleWidget: dispatch parsed key
ToggleWidget->>ToggleWidget: flip or select value
ToggleWidget->>WidgetRunner: accept or cancel state
WidgetRunner->>Terminal: render selected value
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
This comment has been minimized.
This comment has been minimized.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #28 +/- ##
==========================================
- Coverage 98.96% 98.92% -0.04%
==========================================
Files 58 59 +1
Lines 1445 1493 +48
==========================================
+ Hits 1430 1477 +47
- Misses 15 16 +1 ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Builder/Form.php (1)
292-337: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftApply toggle validation to direct
Configinputs too.
Tui::__construct()accepts an already-builtConfigand bypassesForm::build(). Callers can therefore construct aConfigcontaining malformed toggle fields without the two-option/default invariant being checked. Move this validation into a sharedConfigvalidation path or validate incomingConfigobjects at the TUI boundary.🤖 Prompt for 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. In `@src/Builder/Form.php` around lines 292 - 337, Ensure toggle invariants are enforced for already-built Config instances passed through Tui::__construct(), not only during Form::build(). Move assertToggleOptions() or equivalent logic into a shared Config validation path, or invoke it when Tui receives a Config, while preserving the two-option count and literal-default checks; update relevant callers/tests accordingly.
🤖 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 `@playground/3-widgets/widget-toggle.php`:
- Line 35: Update the implode separator in the terminal rendering call to use
the project-approved newline constant or helper, such as PHP_EOL, instead of the
double-quoted "\n" string; follow the single-quote convention for any remaining
string literals.
In `@src/Builder/FieldBuilder.php`:
- Around line 368-371: Update the toggle default logic in FieldBuilder to return
the first option’s value rather than its key. Use the first element from
$this->options and preserve its original string type, avoiding array_key_first()
and numeric-string key coercion before the value reaches WidgetFactory and
schema output.
- Around line 363-366: Update the toggle-default validation used by
Form::assertToggleOptions() so every non-closure default is checked against the
toggle option keys, including null, numeric, and array values, instead of
validating only strings. Reject any unmatched default before it reaches
Engine::resolveInitial() or SchemaGenerator, while preserving closure defaults;
ensure WidgetFactory receives only valid option-key defaults.
In `@src/Builder/Form.php`:
- Around line 331-335: Update the toggle default validation in FieldBuilder to
validate every non-closure default, not just strings: treat the default as valid
only when it matches an option key, while allowing closures for runtime
resolution. Preserve the existing ConfigException details and add regression
tests covering boolean and numeric invalid defaults.
In `@src/Schema/SchemaValidator.php`:
- Around line 161-164: Update SchemaValidator::checkOptions() so numeric-string
option keys remain valid: normalize array_keys($field->options) to strings
before the strict in_array() comparison, or validate against each Option::value
while preserving string types. Keep the existing error message and behavior for
non-matching values.
In `@src/Widget/ToggleWidget.php`:
- Around line 108-113: Declare ext-mbstring as a required Composer platform
dependency in composer.json, since ToggleWidget::applyChar() uses
mb_strtolower() and mb_substr() and otherwise fails when the extension is
unavailable.
---
Outside diff comments:
In `@src/Builder/Form.php`:
- Around line 292-337: Ensure toggle invariants are enforced for already-built
Config instances passed through Tui::__construct(), not only during
Form::build(). Move assertToggleOptions() or equivalent logic into a shared
Config validation path, or invoke it when Tui receives a Config, while
preserving the two-option count and literal-default checks; update relevant
callers/tests accordingly.
🪄 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: db5e71d7-647e-406a-aa22-0796a03b194e
⛔ Files ignored due to path filters (8)
docs/assets/widget-toggle-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-toggle-ascii.svgis excluded by!**/*.svgdocs/assets/widget-toggle-no-ansi.svgis excluded by!**/*.svgdocs/assets/widget-toggle.svgis excluded by!**/*.svgdocs/assets/widgets-ascii-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets-ascii.svgis excluded by!**/*.svgdocs/assets/widgets-no-ansi.svgis excluded by!**/*.svgdocs/assets/widgets.svgis excluded by!**/*.svg
📒 Files selected for processing (18)
README.mddocs/util/update-assets.phpplayground/3-widgets/show.phpplayground/3-widgets/widget-toggle.phpplayground/3-widgets/widgets.phpsrc/Builder/FieldBuilder.phpsrc/Builder/Form.phpsrc/Builder/PanelBuilder.phpsrc/Config/FieldType.phpsrc/Schema/SchemaValidator.phpsrc/Widget/ToggleWidget.phpsrc/Widget/WidgetFactory.phptests/phpunit/Unit/Builder/FormTest.phptests/phpunit/Unit/Resolver/InputResolverTest.phptests/phpunit/Unit/Schema/SchemaGeneratorTest.phptests/phpunit/Unit/Schema/SchemaValidatorTest.phptests/phpunit/Unit/Widget/ToggleWidgetTest.phptests/phpunit/Unit/Widget/WidgetFactoryTest.php
|
Closes #17
Summary
Adds a
togglewidget: a compact inline switch between two labeled values, for on/off settings with custom labels (Enabled/Disabled,Public/Private) whereconfirm's yes/no framing doesn't fit and a fullselectlist is more than the choice needs. It's a two-optionselectin its data and return type, driven byconfirm-style interaction: arrows or Space flip between the two states, Enter accepts, and typing the first letter of a label jumps straight to that side. Headless collection and the generated JSON schema treat it like any other option field, so a value that isn't one of the two options gets rejected the same way a badselectanswer would.Changes
ToggleWidget(two-option data model likeSelectWidget,confirm-style flip interaction on Left/Right/Up/Down/Space, first-letter selection, inline rendering that reuses the existingradio()and label-highlight theme atoms - Unicode and ASCII, no new theme method).FieldType::Toggle,PanelBuilder::toggle(),WidgetFactorywiring, and an implicit default of the first option's value when none is declared, since a toggle always holds one of its two values.Form::build()asserts a toggle field declares exactly two options and that any non-closure default - of any type - is one of the option values (an invalid default fails fast rather than being silently coerced);SchemaValidator::checkOptions()rejects a headless value that isn't one of the two options, same asselect/search. Option membership is compared against eachOption::value, so numeric-string values like'0'and'1'are not coerced by array keys.ext-mbstringincomposer.json. The library already relies onmbstringacross the render layer (Ansi,Box,DefaultTheme); the toggle's first-letter selection uses it too, so the requirement is now explicit.ToggleWidgetTest(flip via Space and each arrow, first-letter selection including the label-collision case, accept/cancel, default seeding, Unicode/ASCII rendering) plus additions toFormTest(two-options and invalid-defaultConfigExceptions across string/bool/int/null, numeric-string options),WidgetFactoryTest,InputResolverTest(headless coercion), andSchemaGeneratorTest/SchemaValidatorTest(option membership including numeric-string values).### Togglesubsection (widget count bumped to twelve), aplayground/3-widgets/widget-toggle.phpdemo, the montage scripts (show.php,widgets.php) anddocs/util/update-assets.phpupdated, and regeneratedwidget-toggle*.svg/widgets*.svgassets.Screenshots
N/A - terminal TUI library, no web UI. The widget's rendered appearance is captured in the committed
docs/assets/widget-toggle*.svgassets and shown in the README.Before / After
Summary by CodeRabbit
New Features
Documentation