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
+16
-41
@@ -226,34 +226,18 @@ const isLastFocalItemAtEndOfContainer = (list, space) => {
|
||||
}
|
||||
|
||||
const firstIndexAfterFocalRangeWithSize = (list, size) => {
|
||||
for (let index = list.lastFocalIndex; index < list.keylines.length; index++) {
|
||||
if (list.keylines[index].size === size) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
const index = list.keylines.findIndex((keyline, i) => i >= list.lastFocalIndex && keyline.size === size)
|
||||
|
||||
return list.keylines.length - 1
|
||||
return index === -1 ? list.keylines.length - 1 : index
|
||||
}
|
||||
|
||||
const lastIndexBeforeFocalRangeWithSize = (list, size) => {
|
||||
for (let index = list.firstFocalIndex - 1; index >= 0; index--) {
|
||||
if (list.keylines[index].size === size) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
const index = list.keylines.findLastIndex((keyline, i) => i < list.firstFocalIndex && keyline.size === size)
|
||||
|
||||
return 0
|
||||
return index === -1 ? 0 : index
|
||||
}
|
||||
|
||||
const keylineBefore = (list, unadjustedOffset) => {
|
||||
for (let index = list.keylines.length - 1; index >= 0; index--) {
|
||||
if (list.keylines[index].unadjustedOffset < unadjustedOffset) {
|
||||
return list.keylines[index]
|
||||
}
|
||||
}
|
||||
|
||||
return list.keylines[0]
|
||||
}
|
||||
const keylineBefore = (list, unadjustedOffset) => list.keylines.findLast((keyline) => keyline.unadjustedOffset < unadjustedOffset) ?? list.keylines[0]
|
||||
|
||||
const keylineAfter = (list, unadjustedOffset) => list.keylines.find((keyline) => keyline.unadjustedOffset >= unadjustedOffset) ?? list.keylines.at(-1)
|
||||
|
||||
@@ -817,7 +801,7 @@ document.addEventListener('alpine:init', () => {
|
||||
target: null,
|
||||
targetAt: 0,
|
||||
settle: null,
|
||||
listeners: [],
|
||||
controller: null,
|
||||
mutations: null,
|
||||
resizes: null,
|
||||
reducedMotion: null,
|
||||
@@ -828,17 +812,20 @@ document.addEventListener('alpine:init', () => {
|
||||
const scroller = this.$refs.scroller
|
||||
|
||||
state.reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)')
|
||||
state.controller = new AbortController()
|
||||
|
||||
this.listen(scroller, 'scroll', () => this.scrolled(), { passive: true })
|
||||
const signal = state.controller.signal
|
||||
|
||||
scroller.addEventListener('scroll', () => this.scrolled(), { passive: true, signal })
|
||||
|
||||
// A scroll the person makes themselves is theirs to end wherever it ends.
|
||||
for (const type of ['pointerdown', 'wheel', 'touchstart']) {
|
||||
this.listen(scroller, type, () => (state.target = null), { passive: true })
|
||||
scroller.addEventListener(type, () => (state.target = null), { passive: true, signal })
|
||||
}
|
||||
this.listen(scroller, 'keydown', (event) => this.navigate(event))
|
||||
this.listen(scroller, 'focusin', (event) => this.reveal(event))
|
||||
this.listen(scroller, 'click', (event) => this.open(event))
|
||||
this.listen(state.reducedMotion, 'change', () => this.schedule())
|
||||
scroller.addEventListener('keydown', (event) => this.navigate(event), { signal })
|
||||
scroller.addEventListener('focusin', (event) => this.reveal(event), { signal })
|
||||
scroller.addEventListener('click', (event) => this.open(event), { signal })
|
||||
state.reducedMotion.addEventListener('change', () => this.schedule(), { signal })
|
||||
|
||||
state.resizes = new ResizeObserver(() => this.refresh())
|
||||
state.resizes.observe(scroller)
|
||||
@@ -859,11 +846,6 @@ document.addEventListener('alpine:init', () => {
|
||||
return element === this.$root || state.items.some((item) => item.element === element || item.surface === element)
|
||||
},
|
||||
|
||||
listen(target, type, handler, options) {
|
||||
target.addEventListener(type, handler, options)
|
||||
state.listeners.push(() => target.removeEventListener(type, handler, options))
|
||||
},
|
||||
|
||||
/** Measures the container and items, and builds the strategy for this width. */
|
||||
refresh() {
|
||||
const root = this.$root
|
||||
@@ -1098,13 +1080,6 @@ document.addEventListener('alpine:init', () => {
|
||||
})
|
||||
},
|
||||
|
||||
/** The item nearest the current scroll position. */
|
||||
current() {
|
||||
const scroll = this.scrollOffset()
|
||||
|
||||
return state.snaps.reduce((best, snap, index) => (Math.abs(snap - scroll) < Math.abs(state.snaps[best] - scroll) ? index : best), 0)
|
||||
},
|
||||
|
||||
/** Where the carousel is headed: an unfinished scroll's target, or where it is. */
|
||||
heading() {
|
||||
const moving = state.target !== null && performance.now() - state.targetAt < TARGET_MS
|
||||
@@ -1235,7 +1210,7 @@ document.addEventListener('alpine:init', () => {
|
||||
destroy() {
|
||||
cancelAnimationFrame(state.frame)
|
||||
clearTimeout(state.settle)
|
||||
state.listeners.forEach((remove) => remove())
|
||||
state.controller?.abort()
|
||||
state.resizes?.disconnect()
|
||||
state.mutations?.disconnect()
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user