Draw the slider on M3's own specs table
The md handle is 52px, not the 44 the MDC tokens gave it; the value indicator is M3's 44x48 label container, not Flutter's 32px pill; and a stop indicator, a tick and the inset icon now take the "on" colour of the part of the track they sit on, which M3's nine colour roles spell out and the library had inverted. Space held with an arrow moves by the same large interval as PageUp, M3's "Space & Arrows" row. Plan step 20, findings IN-04, IN-05, IN-06 and IN-24. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
da4952e684
commit
66f9d36a37
+60
-4
@@ -18,7 +18,9 @@
|
||||
* - Range: the handles never cross; an input that would pass the other is held at its value
|
||||
* before any listener (x-model, wire:model) reads it.
|
||||
* - PageUp and PageDown move by Compose's page: a tenth of the steps, at least one and at most
|
||||
* ten (arrows, Home and End are the inputs' own).
|
||||
* ten (arrows, Home and End are the inputs' own). An arrow pressed while Space is held moves by
|
||||
* that same large interval, which is M3's "Space & Arrows" keyboard row; in a right-to-left
|
||||
* slider the left and right arrows swap, as they do natively.
|
||||
* - Ticks hide while they would sit closer than 8px (Material Components' tick_min_spacing).
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
@@ -203,6 +205,8 @@ function slider(root) {
|
||||
let release = null
|
||||
// Focus this script gave an input on a press, which draws no ring until a key is pressed.
|
||||
let focusedByPointer = null
|
||||
// Space held down, which turns the arrows into M3's large interval.
|
||||
let spaceHeld = false
|
||||
|
||||
const listen = (target, type, handler, capture = false) => {
|
||||
target.addEventListener(type, handler, capture)
|
||||
@@ -386,15 +390,31 @@ function slider(root) {
|
||||
listen(input, 'focus', () => showFocus(input, focusedByPointer !== input && input.matches(':focus-visible')))
|
||||
listen(input, 'blur', () => {
|
||||
focusedByPointer = null
|
||||
spaceHeld = false
|
||||
showFocus(input, false)
|
||||
})
|
||||
|
||||
// slideOnKeyEvents: PageUp and PageDown move a tenth of the steps, one to ten of them.
|
||||
// slideOnKeyEvents: PageUp and PageDown move a tenth of the steps, one to ten of them —
|
||||
// and so do the arrows while Space is held, M3's large interval.
|
||||
listen(input, 'keydown', (event) => {
|
||||
focusedByPointer = null
|
||||
showFocus(input, true)
|
||||
|
||||
if (!['PageUp', 'PageDown'].includes(event.key) || input.disabled) {
|
||||
if (input.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === ' ' || event.code === 'Space') {
|
||||
// Space alone does nothing to a range input; hold the page still while it waits.
|
||||
spaceHeld = true
|
||||
event.preventDefault()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const direction = largeStepDirection(event)
|
||||
|
||||
if (direction === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -404,12 +424,48 @@ function slider(root) {
|
||||
const steps = step === null ? 100 : Math.max(Math.round((max - min) / step), 1)
|
||||
const delta = ((max - min) / steps) * clamp(Math.floor(steps / 10), 1, 10)
|
||||
|
||||
if (commit(inputs.indexOf(input), Number.parseFloat(input.value) + (event.key === 'PageUp' ? delta : -delta))) {
|
||||
if (commit(inputs.indexOf(input), Number.parseFloat(input.value) + delta * direction)) {
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }))
|
||||
}
|
||||
})
|
||||
|
||||
listen(input, 'keyup', (event) => {
|
||||
if (event.key === ' ' || event.code === 'Space') {
|
||||
spaceHeld = false
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/** +1, -1 or 0: which way a key moves the value by one large interval. */
|
||||
function largeStepDirection(event) {
|
||||
if (event.key === 'PageUp') {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (event.key === 'PageDown') {
|
||||
return -1
|
||||
}
|
||||
|
||||
if (!spaceHeld) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const rtl = getComputedStyle(root).direction === 'rtl'
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
return 1
|
||||
case 'ArrowDown':
|
||||
return -1
|
||||
case 'ArrowRight':
|
||||
return rtl ? -1 : 1
|
||||
case 'ArrowLeft':
|
||||
return rtl ? 1 : -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Before x-model or wire:model reads it, hold a range input at its neighbour instead of passing it.
|
||||
listen(
|
||||
root,
|
||||
|
||||
Reference in New Issue
Block a user