Draw the menu without Tailwind
<x-menu> renders data-md-menu with data-md-sheet-at-compact, and its popover data-md-menu-popover with data-md-position and data-md-vibrant; menu.css caps a long menu at 288px so it scrolls instead of running off the top layer (ACT-04) and ties the open/close transition to the trigger's corner (ACT-26), restyles a submenu to open in place inside a sheet-at-compact sheet, and still carries the dropdown a select's picker and a searchable choices field draw, so select.css and choices.css finish their step-36 TODO import. actions.css sheds the state-transition-fast and popover-transition utilities menu-item and menu no longer use; state-transition-default and [data-fab-menu] stay for fab-menu's own rewrite. data-menu, data-menu-filter, data-menu-sheet, data-menu-empty, data-sheet-at-compact, data-vibrant and data-active are renamed to data-md-*, also in menu.js, split-button.css (which renders a <x-menu> and now imports its stylesheet) and AppBarTest's overflow menu (plan step 36, actions). 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
c040925cd4
commit
5cdeec26e8
@@ -33,12 +33,12 @@
|
||||
same key.
|
||||
|
||||
A menu too long for the window scrolls, as M3 asks, rather than running off the edge of the
|
||||
top layer where nothing can reach it: 18rem at most, and less on a short window. The arrow
|
||||
keys, Home, End and typeahead bring the item they move to into view, and a disabled item is
|
||||
among them: M3 keeps one reachable so a person can find out that it exists.
|
||||
top layer where nothing can reach it (ACT-04): 18rem at most, and less on a short window. The
|
||||
arrow keys, Home, End and typeahead bring the item they move to into view, and a disabled
|
||||
item is among them: M3 keeps one reachable so a person can find out that it exists.
|
||||
|
||||
It opens by growing out of the corner nearest its trigger and fades as it goes
|
||||
(`popover-transition`), which is the transition M3 asks to tie a menu to what opened it.
|
||||
It opens by growing out of the corner nearest its trigger and fades as it goes, which is the
|
||||
transition M3 asks to tie a menu to what opened it (ACT-26).
|
||||
|
||||
`filter` is M3's menu as a filtering surface ("autocomplete"): a text field at the top of the
|
||||
list, which stays put while the list scrolls under it, narrowing the items to those whose
|
||||
@@ -79,7 +79,11 @@
|
||||
|
||||
The container is Expressive's standard menu (surface-container-low, 16px corner, elevation
|
||||
2), or `vibrant` in tertiary-container — StandardMenuTokens and VibrantMenuTokens from
|
||||
androidx Compose Material 3 (Apache-2.0). --}}
|
||||
androidx Compose Material 3 (Apache-2.0).
|
||||
|
||||
Drawn by resources/css/components/menu.css, which also draws the dropdown a form's own lists
|
||||
wear — `<x-select>`'s exposed picker and `<x-choices searchable>`'s listbox — so a menu and a
|
||||
form's own dropdowns read as one family (`[data-md-field-menu]`, `[data-md-field-option]`). --}}
|
||||
|
||||
@props([
|
||||
'label' => null,
|
||||
@@ -102,8 +106,8 @@
|
||||
$sheetLabel = filled($label) ? $label : __('Menu');
|
||||
@endphp
|
||||
|
||||
<div x-data="materialMenu" @if ($sheet) data-sheet-at-compact @endif {{ $attributes->class('relative inline-flex') }}>
|
||||
<span x-ref="trigger" class="inline-flex" style="anchor-name: {{ $anchor }}"
|
||||
<div x-data="materialMenu" data-md-menu @if ($sheet) data-md-sheet-at-compact @endif {{ $attributes }}>
|
||||
<span x-ref="trigger" data-md-menu-trigger style="anchor-name: {{ $anchor }}"
|
||||
x-on:click="toggle('first')"
|
||||
x-on:keydown.down.prevent="open('first')"
|
||||
x-on:keydown.up.prevent="open('last')"
|
||||
@@ -115,29 +119,18 @@
|
||||
id="material-menu-{{ $key }}"
|
||||
popover="auto"
|
||||
@unless ($filtering) role="menu" @endunless
|
||||
data-menu
|
||||
@if ($vibrant) data-vibrant @endif
|
||||
data-md-menu-popover
|
||||
data-md-position="{{ $position }}"
|
||||
@if ($vibrant) data-md-vibrant @endif
|
||||
@if ($label && ! $filtering) aria-label="{{ $label }}" @endif
|
||||
tabindex="-1"
|
||||
style="position-anchor: {{ $anchor }}"
|
||||
x-on:keydown="navigate($event)"
|
||||
x-on:click="activate($event)"
|
||||
@class([
|
||||
'm-0 min-w-28 max-w-70 max-h-[min(18rem,calc(100dvh-2rem))] overflow-y-auto border-0 rounded-corner-lg shadow-elevation-2 [inset:auto]',
|
||||
'p-1' => ! $filtering,
|
||||
'my-1 [position-try-fallbacks:flip-block,flip-inline,flip-block_flip-inline]',
|
||||
'popover-transition',
|
||||
'bg-surface-container-low text-on-surface' => ! $vibrant,
|
||||
'bg-tertiary-container text-on-tertiary-container' => $vibrant,
|
||||
'origin-top [position-area:bottom_span-right]' => $position === 'bottom-start',
|
||||
'origin-top [position-area:bottom_span-left]' => $position === 'bottom-end',
|
||||
'origin-bottom [position-area:top_span-right]' => $position === 'top-start',
|
||||
'origin-bottom [position-area:top_span-left]' => $position === 'top-end',
|
||||
])
|
||||
>
|
||||
@if ($filtering)
|
||||
<div data-menu-filter>
|
||||
<x-livewire-material::icon name="search" optical="20" class="size-5 shrink-0" />
|
||||
<div data-md-menu-filter>
|
||||
<x-livewire-material::icon name="search" size="20" />
|
||||
|
||||
<input
|
||||
type="text"
|
||||
@@ -157,10 +150,10 @@
|
||||
'id' => "material-menu-{$key}-list",
|
||||
'role' => 'menu',
|
||||
'aria-label' => $label,
|
||||
], fn ($value): bool => filled($value))) }} class="p-1">
|
||||
], fn ($value): bool => filled($value))) }} data-md-menu-list>
|
||||
{{ $slot }}
|
||||
|
||||
<p data-menu-empty hidden class="px-4 py-3 type-body-md text-on-surface-variant">{{ __('Nothing matches') }}</p>
|
||||
<p data-md-menu-empty hidden>{{ __('Nothing matches') }}</p>
|
||||
</div>
|
||||
@else
|
||||
{{ $slot }}
|
||||
@@ -184,7 +177,7 @@
|
||||
<template x-teleport="body">
|
||||
<div
|
||||
x-ref="sheetHost"
|
||||
data-menu-sheet-host
|
||||
data-md-menu-sheet-host
|
||||
x-on:keydown.capture="sheetKeydown($event)"
|
||||
x-on:click="activate($event)"
|
||||
x-on:input="refine()"
|
||||
@@ -195,9 +188,9 @@
|
||||
<div {{ new \Illuminate\View\ComponentAttributeBag([
|
||||
'wire:key' => 'material-menu-sheet-menu',
|
||||
'id' => "material-menu-{$key}-sheet-menu",
|
||||
]) }} data-menu-sheet class="-mx-6">
|
||||
<div data-menu-filter>
|
||||
<x-livewire-material::icon name="search" optical="20" class="size-5 shrink-0" />
|
||||
]) }} data-md-menu-sheet>
|
||||
<div data-md-menu-filter>
|
||||
<x-livewire-material::icon name="search" size="20" />
|
||||
|
||||
<input
|
||||
type="text"
|
||||
@@ -216,10 +209,10 @@
|
||||
'id' => "material-menu-{$key}-sheet-menu-list",
|
||||
'role' => 'menu',
|
||||
'aria-label' => $label,
|
||||
], fn ($value): bool => filled($value))) }} class="px-2 pt-1">
|
||||
], fn ($value): bool => filled($value))) }} data-md-menu-list>
|
||||
{{ $slot }}
|
||||
|
||||
<p data-menu-empty hidden class="px-4 py-3 type-body-md text-on-surface-variant">{{ __('Nothing matches') }}</p>
|
||||
<p data-md-menu-empty hidden>{{ __('Nothing matches') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@@ -228,7 +221,7 @@
|
||||
'id' => "material-menu-{$key}-sheet-menu",
|
||||
'role' => 'menu',
|
||||
'aria-label' => $label,
|
||||
], fn ($value): bool => filled($value))) }} data-menu-sheet class="-mx-6 px-2">
|
||||
], fn ($value): bool => filled($value))) }} data-md-menu-sheet>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
Reference in New Issue
Block a user