Let a button group own its selection
Plan step 22, actions.md § Missing (Selection-required / multi-select semantics): M3 lists single-select, multi-select and selection-required as button-group configurations, and `<x-button-group connected>` left selection entirely to the caller's own `aria-pressed`. `selection="single|multi"`, with `required`, takes `aria-pressed` over: pressing a button writes its `value` to `wire:model` or `x-model`, deselects the others in `single`, and refuses the press that would leave nothing selected. With no model it reads the buttons' own `aria-pressed` once and goes on from there. `<x-group>` and this do not absorb one another, and the header and SKILL.md say why: `<x-group>` is for a choice whose options are data — it renders real inputs, posts in a plain form and paints its own segments — and stays the first thing to reach for; a selection group governs buttons the caller writes, manages state and shape, and leaves each button to draw its own colours from its own `:selected`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
5d0e9bc12f
commit
6af501c966
@@ -36,6 +36,53 @@ it('squares a group, and a choice drawn as one', function () {
|
||||
->toContain('data-shape="round"');
|
||||
});
|
||||
|
||||
it('takes over aria-pressed for a group that carries a selection', function () {
|
||||
$html = (string) $this->blade('<x-button-group connected selection="single" required label="View"><x-button label="Day" value="day" :selected="true" /></x-button-group>');
|
||||
|
||||
expect($html)
|
||||
->toContain('data-selection="single"')
|
||||
->toContain('data-selection-required')
|
||||
->toContain('multiple: false')
|
||||
->toContain('required: true')
|
||||
->toContain('value: null')
|
||||
->toContain('x-on:click="press($event)"')
|
||||
// No model: the group takes the state from the buttons' own aria-pressed and goes on.
|
||||
->toContain('x-modelable="value"')
|
||||
->and((string) $this->blade('<x-button-group connected selection="multi"><x-button label="Bold" value="bold" :selected="false" /></x-button-group>'))
|
||||
->toContain('multiple: true')
|
||||
->toContain('required: false')
|
||||
->toContain('value: []')
|
||||
->and((string) $this->blade('<x-button-group connected><x-button label="Day" /></x-button-group>'))
|
||||
->not->toContain('data-selection')
|
||||
->not->toContain('press($event)');
|
||||
});
|
||||
|
||||
it('entangles a selection group with the property it binds, and keeps wire:model off the div', function () {
|
||||
$component = new class extends Component
|
||||
{
|
||||
public string $view = 'week';
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return <<<'BLADE'
|
||||
<div>
|
||||
<x-button-group connected selection="single" required wire:model.live="view" label="View">
|
||||
<x-button label="Day" value="day" :selected="$view === 'day'" />
|
||||
<x-button label="Week" value="week" :selected="$view === 'week'" />
|
||||
</x-button-group>
|
||||
</div>
|
||||
BLADE;
|
||||
}
|
||||
};
|
||||
|
||||
$html = Livewire::test($component)->assertSet('view', 'week')->html();
|
||||
|
||||
expect($html)
|
||||
->toContain('data-selection="single"')
|
||||
->toMatch('/value: window\.Livewire\.find\(/')
|
||||
->and(substr_count($html, 'wire:model.live="view"'))->toBe(0);
|
||||
});
|
||||
|
||||
it('never wraps a group onto a second line', function () {
|
||||
expect((string) $this->blade('<x-button-group><x-button label="Day" /></x-button-group>'))
|
||||
->not->toContain('flex-wrap');
|
||||
|
||||
Reference in New Issue
Block a user