Take full on the searchable choice and the pickers, as on every field

`full` takes the 40rem bound off `[data-md-field]` from `medium`, and
`<x-input>`, `<x-password>`, `<x-textarea>`, `<x-select>` and `<x-file>`
pass it to the field they draw. `<x-choices searchable>`,
`<x-datepicker>` and `<x-timepicker>` draw the same field but did not
declare the prop, and their roots only forward `class` and `style`, so
`full` reached no element and the field stopped at 40rem: ReStride's
time zone choice stood narrower than the rows filling its card.

The three now declare `full` and pass it to their field (the date
picker's own field, not the dialog's entry fields). `<x-choices>`' chips
are not a field and have no bound, so they take `full` and render
nothing for it, and a call site can switch `searchable` on and off
without it. The docblocks and the skill list every component that takes
it.

The browser test that bounds a field at 600px now measures a bounded
and a `full` searchable choice, date picker and time picker too; it
fails without the change in Chrome, Firefox and Safari. A feature test
renders `full` on every field-shaped component and none on the chips.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-17 07:04:12 +02:00
co-authored by Claude Opus 5
parent 6d4487feb3
commit 7aa6dc7d33
7 changed files with 60 additions and 14 deletions
+13 -1
View File
@@ -443,6 +443,12 @@ function fieldWidthProbe(int $width)
<x-input id="bounded" label="Bounded" />
<x-input id="narrow" label="Narrow" class="probe-narrow" />
<x-input id="full" label="Full" full />
<x-choices id="choices-bounded" label="Time zone" searchable :options="[['id' => 'Europe/Zurich', 'name' => 'Zurich']]" />
<x-choices id="choices-full" label="Time zone" searchable full :options="[['id' => 'Europe/Zurich', 'name' => 'Zurich']]" />
<x-datepicker id="date-bounded" label="Starts" />
<x-datepicker id="date-full" label="Starts" full />
<x-timepicker id="time-bounded" label="At" />
<x-timepicker id="time-full" label="At" full />
</div>
</body>
</html>
@@ -459,10 +465,16 @@ it('bounds a field to 40rem from 600px, unless the caller\'s width rule or full
->assertScript("({$width('narrow')}) === 200")
->assertScript("({$width('full')}) === 1400");
fieldWidthProbe(600)
$page = fieldWidthProbe(600)
->assertScript("({$width('bounded')}) === 640")
->assertScript("({$width('narrow')}) === 200")
->assertScript("({$width('full')}) === 1400");
// The fields the searchable choice and the pickers draw take `full` as the others do.
foreach (['choices', 'date', 'time'] as $field) {
expect($page->script($width("{$field}-bounded")))->toBe(640)
->and($page->script($width("{$field}-full")))->toBe(1400);
}
});
it('draws the field at M3\'s geometry and the file picker\'s button as a tonal pill', function () {
+22
View File
@@ -201,6 +201,28 @@ it('bounds a field\'s width from medium unless it is told to fill its pane', fun
expect((string) $this->blade('<x-input label="Share name" full />'))->toContain('data-md-full')
->and((string) $this->blade('<x-textarea label="Message" full />'))->toContain('data-md-full')
->and((string) $this->blade('<x-input label="Share name" />'))->not->toContain('data-md-full');
// Every field-shaped component takes it: the searchable choice and the pickers draw a field too.
$zones = "[['id' => 'Europe/Zurich', 'name' => 'Zurich']]";
foreach ([
'<x-password label="Password" full />',
'<x-select label="Expires" full />',
'<x-file label="Photos" full />',
"<x-choices label=\"Time zone\" searchable full :options=\"{$zones}\" />",
'<x-datepicker label="Starts" full />',
'<x-datepicker label="Trip" range full />',
'<x-timepicker label="At" full />',
] as $blade) {
expect(substr_count((string) $this->blade($blade), 'data-md-full'))->toBe(1, $blade);
}
expect((string) $this->blade("<x-choices label=\"Time zone\" searchable :options=\"{$zones}\" />"))->not->toContain('data-md-full')
->and((string) $this->blade('<x-datepicker label="Starts" />'))->not->toContain('data-md-full')
->and((string) $this->blade('<x-timepicker label="At" />'))->not->toContain('data-md-full')
// Chips are no field and have no bound to take off: `full` is taken, and reaches no element.
->and((string) $this->blade("<x-choices label=\"Days\" full :options=\"{$zones}\" />"))->not->toMatch('/\\bfull\\b|data-md-full/')
->and((string) $this->blade("<x-choices label=\"Days\" single full :options=\"{$zones}\" />"))->not->toMatch('/\\bfull\\b|data-md-full/');
});
it('lays out a form with its actions under an optional divider', function () {