Cut duplicated and speculative code across the package
An over-engineering audit of the whole tree, applied in five reviewed batches. Behaviour stays the same except where UPGRADE.md says otherwise. PHP: the showcase and error-page stylesheets are prebuilt into resources/dist by bin/stylesheets.mjs, through Vite's own postcss-import (first occurrence kept, the order an application's build gives), instead of Stylesheets::bundle() inlining imports on every request; only the import walk DesignGuard needs stays. SchemeStylesheet::withProfiles() replaces three copies of the scheme-plus-profiles loop, material:scheme leaves spec and contrast checks to the node script that already made them, and the error page's scheme cache, the hashed view namespace, the translations path with no lang/ folder and DesignGuard's 1.x-name hints are gone. JS: the androidx shape port progress.js and both bin scripts each carried lives once in resources/js/shapes.js (the generated SVGs are unchanged); util.js holds ringIndex(), ms(), reopenGuard() and remember(), which were written out several times; listeners are released through AbortController; tooltip.js's hoverPopover() serves the rich tooltip too. CSS: every rule for an element inside the navigation rail queries `--md-navigation-rail-value` instead of repeating the seven collapsed conditions under five media branches; badge, alert, progress, slider and button read one non-inheriting colour-role table (components/color.css); the dialog chrome, the submenu's popover chrome, the chip's state layer and touch target, and the visually-hidden inputs use the shared rules they copied; foundation/tokens.css is folded into foundation.css. Views: Support\Field and Support\Link replace the error-key, bound-value and link-attribute blocks copied into the fields and link components; the timepicker period group, the menu filter and the showcase head are partials; the datepicker's steppers and entry fields are loops; component docblocks no longer restate SKILL.md. Tests and tooling: one dataset-driven ComponentStylesheetsTest replaces four per-group files, DesignGuardTest and the layout-component tests use datasets, browser tests share one ready() helper, CSS parsing lives in ComponentStylesheet alone. docs/audits and the finding IDs citing it are removed, as are pestphp/pest-plugin-laravel, the unused composer scripts and check:font; the lint job runs in the feature job, which now installs node packages so the prebuilt-stylesheet staleness test runs in CI. Feature suite 1177 passed, Chrome browser suite 299 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
471d927e64
commit
247c596c3a
@@ -76,11 +76,9 @@
|
||||
$mode = in_array($mode, ['docked', 'modal', 'input'], true) ? $mode : 'docked';
|
||||
$id = $attributes->get('id') ?? 'field-'.substr(md5($model.'|'.$label.'|datepicker'), 0, 12);
|
||||
$anchor = '--material-datepicker-'.preg_replace('/[^A-Za-z0-9_-]/', '-', $id);
|
||||
// A plain form's field is named, not bound: its errors are under its name (`files[]` → `files`, `a[b]` → `a.b`).
|
||||
$errorKey = $model ?? (filled($attributes->get('name')) ? str_replace(['[]', '[', ']'], ['', '.', ''], (string) $attributes->get('name')) : null);
|
||||
$messages = $errorKey !== null && isset($errors)
|
||||
? array_values(array_unique(\Illuminate\Support\Arr::flatten([$errors->get($errorKey), $errors->get($errorKey.'.*')])))
|
||||
: [];
|
||||
$field = \NoNameWeb\LivewireMaterial\Support\Field::class;
|
||||
$errorKey = $field::key($model, $attributes->get('name'));
|
||||
$messages = $field::messages($errors ?? null, $errorKey, wildcard: true);
|
||||
$locale = str_replace('_', '-', app()->getLocale());
|
||||
$weekStart = (is_int($weekStart) || is_string($weekStart)) && preg_match('/^[0-6]\z/', (string) $weekStart) === 1 ? (int) $weekStart : null;
|
||||
$format = is_string($format) && preg_match('/^(dd|MM|yyyy)([.\/-])(dd|MM|yyyy)\2(dd|MM|yyyy)\z/', $format, $units) === 1 && count(array_unique([$units[1], $units[3], $units[4]])) === 3
|
||||
@@ -100,10 +98,7 @@
|
||||
};
|
||||
|
||||
// Rendered as the bound property already says, so the field does not change once Alpine starts.
|
||||
$current = $value;
|
||||
if ($model !== null && ($component = \Livewire\Livewire::current()) !== null) {
|
||||
$current = data_get($component, $model);
|
||||
}
|
||||
$current = $field::bound($model, $value);
|
||||
$current = $range
|
||||
? ['start' => $toIso(data_get($current, 'start')), 'end' => $toIso(data_get($current, 'end'))]
|
||||
: $toIso($current);
|
||||
@@ -343,45 +338,32 @@
|
||||
</div>
|
||||
|
||||
<div data-md-datepicker-nav data-md-docked x-show="presentation === 'docked'">
|
||||
<span data-md-datepicker-stepper>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_left" :tooltip="__('Previous month')" x-on:click="step(-1)" x-bind:disabled="view !== 'days' || ! canStep(-1)" />
|
||||
{{-- Months and years: the same stepper either side of a menu button, a step of
|
||||
1 or 12 apart. --}}
|
||||
@foreach ([
|
||||
['unit' => 'months', 'step' => 1, 'label' => 'monthLabel', 'previous' => __('Previous month'), 'next' => __('Next month'), 'switch' => __('Switch to selecting a month')],
|
||||
['unit' => 'years', 'step' => 12, 'label' => 'yearLabel', 'previous' => __('Previous year'), 'next' => __('Next year'), 'switch' => __('Switch to selecting a year')],
|
||||
] as $stepper)
|
||||
<span data-md-datepicker-stepper>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_left" :tooltip="$stepper['previous']" x-on:click="step(-{{ $stepper['step'] }})" x-bind:disabled="view !== 'days' || ! canStep(-{{ $stepper['step'] }})" />
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="md-state-layer md-focus-ring"
|
||||
data-md-datepicker-menu-button="{{ $stepper['unit'] }}"
|
||||
x-on:click="toggleView('{{ $stepper['unit'] }}')"
|
||||
x-bind:aria-expanded="(view === '{{ $stepper['unit'] }}').toString()"
|
||||
x-bind:aria-label="{{ $stepper['label'] }} + ', ' + @js($stepper['switch'])"
|
||||
>
|
||||
<span x-text="{{ $stepper['label'] }}"></span>
|
||||
<x-livewire-material::icon name="arrow_drop_down" size="18" data-md-datepicker-menu-arrow />
|
||||
</button>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_right" :tooltip="$stepper['next']" x-on:click="step({{ $stepper['step'] }})" x-bind:disabled="view !== 'days' || ! canStep({{ $stepper['step'] }})" />
|
||||
</span>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="md-state-layer md-focus-ring"
|
||||
data-md-datepicker-menu-button="months"
|
||||
x-on:click="toggleView('months')"
|
||||
x-bind:aria-expanded="(view === 'months').toString()"
|
||||
x-bind:aria-label="monthLabel + ', ' + @js(__('Switch to selecting a month'))"
|
||||
>
|
||||
<span x-text="monthLabel"></span>
|
||||
<x-livewire-material::icon name="arrow_drop_down" size="18" data-md-datepicker-menu-arrow />
|
||||
</button>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_right" :tooltip="__('Next month')" x-on:click="step(1)" x-bind:disabled="view !== 'days' || ! canStep(1)" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span data-md-datepicker-stepper>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_left" :tooltip="__('Previous year')" x-on:click="step(-12)" x-bind:disabled="view !== 'days' || ! canStep(-12)" />
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="md-state-layer md-focus-ring"
|
||||
data-md-datepicker-menu-button="years"
|
||||
x-on:click="toggleView('years')"
|
||||
x-bind:aria-expanded="(view === 'years').toString()"
|
||||
x-bind:aria-label="yearLabel + ', ' + @js(__('Switch to selecting a year'))"
|
||||
>
|
||||
<span x-text="yearLabel"></span>
|
||||
<x-livewire-material::icon name="arrow_drop_down" size="18" data-md-datepicker-menu-arrow />
|
||||
</button>
|
||||
<span data-md-datepicker-arrows x-bind:data-md-concealed="view !== 'days' ? '' : null">
|
||||
<x-livewire-material::button icon="chevron_right" :tooltip="__('Next year')" x-on:click="step(12)" x-bind:disabled="view !== 'days' || ! canStep(12)" />
|
||||
</span>
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<table role="grid" aria-labelledby="{{ $id }}-month" x-show="view === 'days'" x-on:keydown="gridKey($event)" data-md-datepicker-grid>
|
||||
@@ -479,40 +461,29 @@
|
||||
|
||||
<div x-show="typing" data-md-datepicker-entry>
|
||||
<div @if ($range) data-md-range @endif data-md-datepicker-entry-fields>
|
||||
<x-livewire-material::field id="{{ $id }}-entry" :label="$range ? __('Start date') : __('Date')" :$variant x-bind:data-md-invalid="entryError !== '' ? '' : null">
|
||||
<input
|
||||
id="{{ $id }}-entry"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
placeholder=" "
|
||||
x-bind:placeholder="format.placeholder"
|
||||
x-bind:aria-invalid="entryError !== '' ? 'true' : null"
|
||||
aria-describedby="{{ $id }}-entry-support"
|
||||
x-ref="entry"
|
||||
x-model="entry"
|
||||
x-on:input="typeEntry()"
|
||||
x-on:keydown.enter.prevent="confirm()"
|
||||
data-md-field-control
|
||||
/>
|
||||
</x-livewire-material::field>
|
||||
|
||||
@if ($range)
|
||||
<x-livewire-material::field id="{{ $id }}-entry-end" :label="__('End date')" :$variant x-bind:data-md-invalid="entryError !== '' ? '' : null">
|
||||
@foreach ($range ? [
|
||||
['id' => "{$id}-entry", 'label' => __('Start date'), 'model' => 'entry', 'ref' => true],
|
||||
['id' => "{$id}-entry-end", 'label' => __('End date'), 'model' => 'entryEnd', 'ref' => false],
|
||||
] : [
|
||||
['id' => "{$id}-entry", 'label' => __('Date'), 'model' => 'entry', 'ref' => true],
|
||||
] as $entry)
|
||||
<x-livewire-material::field id="{{ $entry['id'] }}" :label="$entry['label']" :$variant x-bind:data-md-invalid="entryError !== '' ? '' : null">
|
||||
<input
|
||||
id="{{ $id }}-entry-end"
|
||||
id="{{ $entry['id'] }}"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
placeholder=" "
|
||||
x-bind:placeholder="format.placeholder"
|
||||
x-bind:aria-invalid="entryError !== '' ? 'true' : null"
|
||||
aria-describedby="{{ $id }}-entry-support"
|
||||
x-model="entryEnd"
|
||||
@if ($entry['ref']) x-ref="entry" @endif
|
||||
x-model="{{ $entry['model'] }}"
|
||||
x-on:input="typeEntry()"
|
||||
x-on:keydown.enter.prevent="confirm()"
|
||||
data-md-field-control
|
||||
/>
|
||||
</x-livewire-material::field>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div id="{{ $id }}-entry-support" data-md-datepicker-support>
|
||||
|
||||
Reference in New Issue
Block a user