From b867699409b18a1936b0c684f242c3d5e73d4fd0 Mon Sep 17 00:00:00 2001 From: Geoffrey Eisenbarth Date: Fri, 30 Aug 2024 20:00:55 -0500 Subject: [PATCH 1/5] Fix typo. --- src/core/sanitize.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/sanitize.css b/src/core/sanitize.css index f2c8f26..9906d65 100644 --- a/src/core/sanitize.css +++ b/src/core/sanitize.css @@ -116,7 +116,7 @@ button, input, select { * Correct the inability to style buttons in iOS and Safari. */ -button, [type="button"], [type="reset"], [type="submit"]) { +button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } From 4bb5e633d5bfef45e866e506d6effe680ebb3c27 Mon Sep 17 00:00:00 2001 From: Geoffrey Eisenbarth Date: Fri, 30 Aug 2024 20:48:54 -0500 Subject: [PATCH 2/5] Fix loop. --- src/js/19.js | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/js/19.js b/src/js/19.js index 43c797b..d238888 100644 --- a/src/js/19.js +++ b/src/js/19.js @@ -1,4 +1,4 @@ -/** +/** * a DOM helper library. * "1 US$ = 18.5842 TR₺ · Oct 16, 2022, 20:52 UTC" */ @@ -42,13 +42,13 @@ /** * Creates a logging function. * The {@link scope} will be prepended to each message logged. - * + * * We usually use `ilog` as a name for the resulting function. * It returns its last argument, * which makes it easier to log intermediate values in an expression: - * + * * const x = a + ilog("b:", b); // x = a + b - * + * * @param {string} scope The name of the component/module/etc. that will use this logger. * @returns {Logger} The `ilog` function. */ @@ -103,14 +103,14 @@ export function traverse( ? $(root, selector) : $$(root, selector).at(-1); } - + if (!current) return wrapIt(); - + // Traverse left to right, bottom to top. // // (begin ascii art diagram) // (R) - // / \ + // / \ // (r) (4) <- return value // / | \ / \ // current -> (1) (2) (3) (*) (*) @@ -118,11 +118,11 @@ export function traverse( // // In the diagram above, 1, 2, 3 are tested by the selector (assuming we // start at 1). Then, having run out of siblings, we move up (as many times - // as needed) before advancing, ending up at 4. + // as needed) before advancing, ending up at 4. // // To "test" an element, ee call Element#matches, then if that returns false, // querySelector. The querySelector call is how the items marked with - // asterisks can be checked. + // asterisks can be checked. let cursor = current; while (true) { while (cursor[advance] === null) { // 3 @@ -169,7 +169,7 @@ export function $$(scope, sel) { * @property {EventTarget} target * @property {string} type * @property {EventListener} listener - * @property {object} options + * @property {object} options */ /** @@ -211,7 +211,7 @@ export function off({ target, type, listener, options }) { /** * "Halt" an event -- convenient wrapper for `preventDefault`, `stopPropagation`, and `stopImmediatePropagation`. * @param {string} o - How to halt. Space-separated list of "default", "bubbling" and "propagation". - * @param {Event} e - The event. + * @param {Event} e - The event. */ export function halt(o, e) { for (const t of o.split(" ")) { @@ -226,7 +226,7 @@ export function halt(o, e) { /** * Decorator for any event listener to call {@link halt}. - * + * * on(el, "click", halts("default", e => ...)) * * @template {Event} T @@ -251,13 +251,13 @@ export function dispatch(el, type, detail, options) { /** * Get, remove or set an attribute. - * + * * - attr(el, "name") Get the attribute "name" * - attr(el, "name", "value") Set the attribute "name" to "value" * - attr(el, "name", null) Remove the attribute "name" * - attr(el, [ nameA: "valueA", nameB: "valueB" ]) Set the attributes name-a to "valueA", name-b to "valueB" - * - * @param {Element} el + * + * @param {Element} el * @param {string | Record} name - The attribute name **or** a map of names to values. * If an object is passed, camelCase attribute names will be converted to kebab-case. * @param {unknown} value - The value of the attribute, when setting. Pass `null` to remove an attribute. @@ -333,9 +333,9 @@ export function htmlescape(s) { * Template literal that escapes HTML in interpolated values and returns a DocumentFragment. * Can also be called with a string to parse it as HTML. * To let trusted HTML through escaping, parse it first: - * + * * html`

My trusted markup: ${html(trustedMarkup)}

` - * + * * @param {TemplateStringsArray | string} str * @param {...unknown} values * @returns {DocumentFragment} @@ -421,10 +421,10 @@ export function prev(root, selector, current, options = {}) { /** * Create a handler for keyboard events using a keyboard shortcut DSL. - * + * * - "ArrowLeft" * - "Ctrl+Alt+3" - * + * * @param {Record} hotkeys * @returns KeyboardEventListener */ @@ -440,7 +440,7 @@ export function hotkey(hotkeys) { const tokens = hotkeySpec.split("+"), key = /** @type {string} */ (tokens.pop()); let modifiers = 0 | 0; - for (const token in tokens) + for (const token of tokens) switch (token.toLowerCase()) { case "alt": modifiers |= alt; break; case "ctrl": modifiers |= ctrl; break; @@ -460,8 +460,8 @@ export function hotkey(hotkeys) { /** * Debounce a function. - * - * @template {unknown[]} TArgs + * + * @template {unknown[]} TArgs * @param {number} t The debounce time. * @param {(...args: TArgs) => void} f The function. * @param {object} [options] @@ -507,13 +507,13 @@ export function behavior(selector, init) { /** * @template TData * @typedef {object} Repeater - * + * * @property {(datum: TData) => string} idOf * Returns the HTML id for a given data value. - * + * * @property {(datum: TData, ctx: { id: string }) => ChildNode} create * Creates a an element for a data value. - * + * * @property {(el: Element, datum: TData) => Element | null} update * Update an element for a new data value. */ From 866f86c4e0c8e67cd643af08cdc5565f8aaa7be6 Mon Sep 17 00:00:00 2001 From: Geoffrey Eisenbarth Date: Tue, 29 Oct 2024 07:29:45 -0500 Subject: [PATCH 3/5] Initial commit. --- src/aria.css | 46 +++++++++++ www/docs/40-aria.md | 190 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 235 insertions(+), 1 deletion(-) diff --git a/src/aria.css b/src/aria.css index 6a57157..af110a0 100644 --- a/src/aria.css +++ b/src/aria.css @@ -116,3 +116,49 @@ width: fit-content; text-align: center; } + +label:has([role=switch]:last-child) { + display: flex; + justify-content: space-between; +} +label[for] + [role=switch] { + padding-block: calc(var(--gap) / 4); +} + +label[for]:has(+ [role=switch]), +label[for] + [role=switch], +[role=switch]:has(+ label[for]), +[role=switch] + label[for] { + display: inline-block; +} + +[role=switch], [aria-pressed] { + --toggle-border-width: 0.2em; + all: unset; + appearance: none; + cursor: pointer; + transition: all 0.25s ease-in-out; + vertical-align: bottom; + + &::before, &::after { + content: ''; + display: inline-block; + height: var(--rhythm); + border: var(--toggle-border-width) solid var(--graphical-fg); + } + &::before { + width: calc(2 * var(--rhythm)); + background-color: var(--bg); + border-radius: var(--rhythm); + } + &::after { + width: var(--rhythm); + background-color: var(--interactive-bg); + border-radius: 50%; + transform: translateX(calc(-2 * var(--rhythm))); + } + &:is(:checked, [aria-pressed=true]) { + &::before { background-color: var(--accent); } + &::after { transform: translateX(calc(-1 * var(--rhythm))); } + } +} diff --git a/www/docs/40-aria.md b/www/docs/40-aria.md index 92da6f3..b8887ea 100644 --- a/www/docs/40-aria.md +++ b/www/docs/40-aria.md @@ -165,7 +165,7 @@ The fiex direction will be set based on `aria-orientation`. ## Feed -Use `feed` role with `
` children — see [WAI: Feed][]. Nested feeds are supported. +Use `feed` role with `
` children — see [WAI: Feed][]. Nested feeds are supported. To get the actual behavior of an accessible feed, you can use [Missing.js § Feed](/docs/js#feed). @@ -200,3 +200,191 @@ To get the actual behavior of an accessible feed, you can use [Missing.js § [WAI: Menu]: https://www.w3.org/WAI/ARIA/apg/patterns/feed/ + + +## Toggle Switch + +Use `switch` role with `` or `aria-pressed` with ` + + +
+ Button toggles, flipped + + +
+ + ~~~ + +
+
+ Button toggles + + +
+
+ Button toggles, flipped + + +
+
+ + TODO +
    +
  • RTL +
  • Indeterminate state +
+ From 91d35121e1a4459fdd3a1e51219756e96fefe2c6 Mon Sep 17 00:00:00 2001 From: Geoffrey Eisenbarth Date: Wed, 30 Oct 2024 09:26:21 -0500 Subject: [PATCH 4/5] Determine markup. --- src/aria.css | 26 ++++++++++++++++++++------ www/docs/40-aria.md | 40 ++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/aria.css b/src/aria.css index af110a0..82b69a0 100644 --- a/src/aria.css +++ b/src/aria.css @@ -119,24 +119,25 @@ label:has([role=switch]:last-child) { display: flex; + gap: var(--gap); justify-content: space-between; } -label[for] + [role=switch] { - padding-block: calc(var(--gap) / 4); -} label[for]:has(+ [role=switch]), label[for] + [role=switch], [role=switch]:has(+ label[for]), [role=switch] + label[for] { display: inline-block; + padding-block: calc(var(--gap) / 4); } [role=switch], [aria-pressed] { - --toggle-border-width: 0.2em; + --toggle-border-width: 0.15em; all: unset; appearance: none; cursor: pointer; + display: grid !important; + grid-gap: 0; transition: all 0.25s ease-in-out; vertical-align: bottom; @@ -150,15 +151,28 @@ label[for] + [role=switch], width: calc(2 * var(--rhythm)); background-color: var(--bg); border-radius: var(--rhythm); + grid-row: 1; + grid-column: 1 / 3; } &::after { width: var(--rhythm); background-color: var(--interactive-bg); border-radius: 50%; - transform: translateX(calc(-2 * var(--rhythm))); + grid-row: 1; + grid-column: 1 / 2; } &:is(:checked, [aria-pressed=true]) { &::before { background-color: var(--accent); } - &::after { transform: translateX(calc(-1 * var(--rhythm))); } + &::after { grid-column: 2 / 3; } + } + + &:is(:hover, :focus-visible) { + /* Reset button styles */ + filter: unset; + box-shadow: none; + } + &:active { + box-shadow: none; + color: inherit; } } diff --git a/www/docs/40-aria.md b/www/docs/40-aria.md index b8887ea..1748783 100644 --- a/www/docs/40-aria.md +++ b/www/docs/40-aria.md @@ -221,7 +221,7 @@ Using `` degrades nicely in the absense of JavaScript and also allows for Toggle me