Draw the switch without Tailwind

<x-toggle> renders data-md-toggle, its row (data-md-right), track,
handle and icons as data-md-* attributes; the handle's icons take size
16 and a label-less track md-touch-target (plan step 36). toggle.css
gains the root; a browser test pins the handle's 16px/24px sizes and
16px/36px centres off and on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 14:43:17 +02:00
co-authored by Claude Opus 5
parent 8747163fce
commit b42069503d
4 changed files with 43 additions and 22 deletions
+13 -4
View File
@@ -30,12 +30,12 @@ it('marks a checkbox that is partly ticked', function () {
it('gives a selection control without a label a 48px target', function () {
expect((string) $this->blade('<x-checkbox aria-label="Select all" />'))->toMatch('/<span data-md-checkbox-box\s+class="md-touch-target"\s*>/')
->and((string) $this->blade('<x-toggle aria-label="Public link" />'))->toContain('touch-target')
->and((string) $this->blade('<x-toggle aria-label="Public link" />'))->toMatch('/<span data-md-switch\\s+class="md-touch-target"\\s*>/')
->and((string) $this->blade('<x-radio :options="[[\'id\' => \'a\', \'name\' => \'\']]" />'))->toMatch('/<span data-md-radio-button\\s+class="md-touch-target"\\s*>/');
// A labelled control is pressed anywhere along its row, so it needs no extra target.
expect((string) $this->blade('<x-checkbox label="Notify me" />'))->not->toContain('md-touch-target')
->and((string) $this->blade('<x-toggle label="Public link" />'))->not->toContain('touch-target')
->and((string) $this->blade('<x-toggle label="Public link" />'))->not->toContain('md-touch-target')
->and((string) $this->blade('<x-radio :options="[[\'id\' => \'a\', \'name\' => \'A\']]" />'))->not->toContain('md-touch-target');
});
@@ -124,18 +124,20 @@ it('draws a switch on a checkbox with the switch role', function () {
$html = (string) $this->blade('<x-toggle id="public" label="Public link" wire:model.live="public" right />');
expect($html)
->toContain('<label for="public" data-md-selection-row')
->toMatch('/<div data-md-toggle\s*>/')
->toMatch('/<label for="public" data-md-selection-row\\s+data-md-right\\s*>/')
->toContain('data-md-switch')
->toContain('role="switch"')
->toContain('type="checkbox"')
->toContain('wire:model.live="public"')
->toContain('data-md-switch-handle')
->toContain('flex-row-reverse')
->not->toContain('class=')
->not->toContain('data-md-icons');
});
it('puts icons on a switch\'s handle', function () {
expect((string) $this->blade('<x-toggle label="Wi-Fi" icons />'))->toContain('data-md-icons="both"')->toContain('data-md-switch-on')->toContain('data-md-switch-off')
->and((string) $this->blade('<x-toggle label="Wi-Fi" icons />'))->toContain('--md-icon-size: 16px')
->and((string) $this->blade('<x-toggle label="Wi-Fi" icons="selected" />'))->toContain('data-md-icons="selected"');
});
@@ -162,3 +164,10 @@ it('lays the radio group out from its stylesheet, inline only from 600px', funct
->and((string) $this->blade('<x-radio name="size" class="mt-4" style="order: 1" :options="[[\'id\' => \'s\', \'name\' => \'S\']]" />'))
->toMatch('/data-md-radio\\s+class="mt-4" style="order: 1"/');
});
it('draws the switch from its stylesheet', function () {
expect((string) file_get_contents(__DIR__.'/../../../resources/css/components/toggle.css'))
->toContain("@import './selection.css';")
->toMatch('/\\[data-md-switch\\] \\{[^}]*width: 52px;[^}]*height: 32px;/')
->and((string) file_get_contents(__DIR__.'/../../../resources/css/components.css'))->toContain("@import './components/toggle.css';");
});