Add hint-class to the group and icon-class to menu items

<x-group hint-class> adds classes to the hint, as the text fields'
hint-class does, and a validation message still replaces the hint.
<x-menu-item icon-class> adds classes to the leading icon, for an icon
whose colour means something of its own, such as a sport's glyph.

A colour class there has to win over the component's own colour, and
which of two colour utilities wins depends on the order Tailwind emits
them (text-error comes before text-on-surface-variant). So when either
prop is given, the component's own colour is written with a :where()
variant that carries no specificity, as the fields' hint colour sits
in the components layer. A disabled item's icon stays disabled. Without
the props the markup is unchanged. The skill now also lists the fields'
hint-class, which it had left out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHoXZSHc8gGpZjFmA5fPc2
This commit is contained in:
Andreas Reinhold / reini
2026-09-13 18:18:39 +02:00
co-authored by Claude Opus 5
parent a83d7f62ea
commit ab7317faae
8 changed files with 111 additions and 15 deletions
+14 -4
View File
@@ -12,13 +12,19 @@
default), `filled` or `outlined`, as for toggle buttons. The segments share the row unless
`inline`. An option with `'disabled' => true` greys its own segment.
ReStride's props, kept: `label`, `hint`, `name` (needed with `x-model`, which names no
property), `options`, `option-value`, `option-label`; plus `option-icon`, `size`, `variant`,
`multiple`, `inline`. A validation message for the bound property replaces the hint. --}}
ReStride's props, kept: `label`, `hint`, `hint-class`, `name` (needed with `x-model`, which
names no property), `options`, `option-value`, `option-label`; plus `option-icon`, `size`,
`variant`, `multiple`, `inline`. A validation message for the bound property replaces the hint.
`hint-class` adds classes to the hint, as on `<x-field>`: a colour there paints it
(`hint-class="text-warning"` for a hint that warns). The hint's own colour then carries no
specificity, as the field's does in the components layer, because which of two colour
utilities wins depends on the order Tailwind emits them. --}}
@props([
'label' => null,
'hint' => null,
'hintClass' => null,
'name' => null,
'options' => [],
'optionValue' => 'id',
@@ -46,6 +52,10 @@
'xl' => 'h-34 gap-4 px-16 type-headline-lg',
][$size];
$hintClasses = filled($hintClass)
? \Illuminate\Support\Arr::toCssClasses(['mt-1 type-body-sm [:where(&)]:text-on-surface-variant', $hintClass])
: 'mt-1 type-body-sm text-on-surface-variant';
$iconSize = ['xs' => 'size-5', 'sm' => 'size-5', 'md' => 'size-6', 'lg' => 'size-8', 'xl' => 'size-10'][$size];
$colours = match ($variant) {
@@ -94,6 +104,6 @@
<p class="mt-1 type-body-sm text-error">{{ $message }}</p>
@endforeach
@elseif (filled($hint))
<p class="mt-1 type-body-sm text-on-surface-variant">{{ $hint }}</p>
<p class="{{ $hintClasses }}">{{ $hint }}</p>
@endif
</fieldset>
+22 -7
View File
@@ -1,11 +1,18 @@
{{-- One item in an `<x-menu>`: an action, a link, or a choice.
`label`, a leading `icon`, an `icon-right`, a `description` under the label and a
`shortcut` at the end (M3's trailing supporting text: "⌘C"). `link` makes it an anchor, with
`wire:navigate` unless `external` or `no-wire-navigate`. `selected` (true or false) makes it a
`menuitemcheckbox` with `aria-checked`; a selected item takes Expressive's selected shape and
tertiary-container. `disabled` keeps it in the list, out of reach. `keep-open` leaves the menu
open when it is activated for a choice the person may want to change twice.
`label`, a leading `icon` (`icon-class` adds classes to it), an `icon-right`, a `description`
under the label and a `shortcut` at the end (M3's trailing supporting text: "⌘C"). `link`
makes it an anchor, with `wire:navigate` unless `external` or `no-wire-navigate`. `selected`
(true or false) makes it a `menuitemcheckbox` with `aria-checked`; a selected item takes
Expressive's selected shape and tertiary-container. `disabled` keeps it in the list, out of
reach. `keep-open` leaves the menu open when it is activated for a choice the person may
want to change twice.
`icon-class` is for an icon whose colour means something of its own, a sport's glyph in the
sport's colour (`icon-class="text-sport-run"`). A colour there paints the icon, a selected
item's too: the icon's own colour then carries no specificity, because which of two colour
utilities wins depends on the order Tailwind emits them. A disabled item's icon stays
disabled.
44px tall (SegmentedMenuTokens.Item), body-large label, 20px icons, 4px corners that open to
12px at the ends of the list. --}}
@@ -13,6 +20,7 @@
@props([
'label' => null,
'icon' => null,
'iconClass' => null,
'iconRight' => null,
'description' => null,
'shortcut' => null,
@@ -56,11 +64,18 @@
$selected === true => 'text-on-tertiary-container',
default => 'text-on-surface-variant',
};
$leadingIcon = match (true) {
blank($iconClass) => 'size-5 '.$iconInk,
$disabled => \Illuminate\Support\Arr::toCssClasses(['size-5', $iconClass, 'text-on-surface/38!']),
$selected === true => \Illuminate\Support\Arr::toCssClasses(['size-5 [:where(&)]:text-on-tertiary-container', $iconClass]),
default => \Illuminate\Support\Arr::toCssClasses(['size-5 [:where(&)]:text-on-surface-variant', $iconClass]),
};
@endphp
<{{ $tag }} {{ $attributes }}>
@if ($icon)
<x-livewire-material::icon :name="$icon" :filled="$selected === true" :class="'size-5 '.$iconInk" />
<x-livewire-material::icon :name="$icon" :filled="$selected === true" :class="$leadingIcon" />
@endif
<span class="min-w-0 flex-1">