-
Notifications
You must be signed in to change notification settings - Fork 45
[Fixes #448] Draft PR for VPAT Compliance #449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
omargfh
wants to merge
53
commits into
main
Choose a base branch
from
feat/kbd-vpat-compliance
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
13fa598
[#448] Bugfix: Make Forever buttons accessible with Tab
omargfh e33b5ab
[#448] Bugfix: Make switches accessible with Tab and usable with Enter
omargfh 200d195
[#448] Feat: Add Keyboard Listener class to manage keybinds
omargfh 725baf9
[#448] Feat: Add keybinds help component
omargfh cd90046
[#448] Feat: Add utility selector for focus-able elements
omargfh aca4a63
[#448] Feat: Add keybinds and hook them into Skeleton, hook keybind h…
omargfh 4654f2c
[#448, #docs] Handle Shift+digit KBD combos edge case in KeyboardList…
omargfh 7da81f7
[#448] Add focus API to Code and Info tab editors
omargfh be59570
[#448] Refactor tabs into accessible TabWidget component
omargfh 58d92b7
[#448] Update keybinds
omargfh 6df5ec0
Editor: Update .vscode
omargfh 32a0ca5
[#448] Add utility function to sort widgets by position in row-major …
omargfh 6aff7ad
[#448] Refactor KeyboardListener for Mousetrap
omargfh 926a243
[#448] Prevent pointer events on widgets when overlay is present
omargfh 786f9e3
[#448] Rename platformCmdKey to modKey and change ctrl+t to alt+t
omargfh d687567
[#448] Add tabindex, aria-label, inheritable attrs
omargfh fef06e9
[#448] Set up events to update sorting keys on widgets
omargfh 394a8ed
[#448] Lint: Nit types, if/else, returns, gaurds, template syntax, et…
omargfh d62e52a
[#448] Bugfix: Add keyboard listener for Enter/Space to Forever Button
omargfh f6bd6de
[#448] Minor: Add `id` field to RactiveCustomSlider
omargfh 105e53d
[#448] Minor: Add Mod+I to switch input mode for slider widget
omargfh fce2878
[#448] Minor(refactor): Swap focus/toggle keybind shortcuts
omargfh 50c351a
[#448] Minor: use canonical mousetrap spelling for escape key
omargfh 351a309
[#448] Lint/Minor: Lint export keyword and add new helper to accessib…
omargfh 12f9c91
[#448] Major: Add global on-activateClick.
omargfh 4998447
[#448] Minor: Add per-component local config to Code Container
omargfh 1a7da40
[#448] Minor: Pass tabindex to CodeEditor directly in input widgets
omargfh 1765753
[#448] Minor(Bugfix): Documentation top-bar link is focusable and nav…
omargfh a07050f
[#448] Minor: Add global on-copy event.
omargfh f70feb5
[#448] Minor: Bind Ctrl+C to copy current value
omargfh 2cbd460
[#448] Minor: Add Ctrl+0 to focus first widget in model
omargfh 2c8499c
[#448] Minor(fix): Consolidate Help/KeyboardHelp into one modal
omargfh efac9c6
[#448] Minor(refactor): Store canonical reference to the tabindex val…
omargfh 1ed53ec
[#448] Minor(ux): Focus edit form's first input on appearance
omargfh 295edd3
[#448] Minor(feat): Context menu kbd navigable & tabindex order
omargfh 73ecd1f
[#448] Minor(feature, refactor): Add KBD for adding widget and widget…
omargfh 4694ae8
[#448] Minor(refactor): Create new accessibility events source file f…
omargfh f350913
[#448] Minor(feature, refactor) Add paste event to sliders; refactor …
omargfh 62ce3fb
[#448] Minor(feature): Add KBD to nudge widgets a far distance
omargfh 0a7024b
[#448] Minor(fix): Better implementation for selecting first widget
omargfh ae31195
[#448] Minor(a11y): Better ARIA.
omargfh 00c9ee4
[#448] Forward keybinds from main window to iframe for keyhandling an…
omargfh 2315ba6
[#448] Add help shortcut to main window
omargfh 0364066
[#448] Minor(bugfix): Proper tab wrapping
omargfh 319a980
[#448] Minor(a11y): Fix tabindex and refocus after compilation relate…
omargfh 300ecc7
[#448] Minor(UX): better hint label for keyboard shortcuts
omargfh 00633d0
[#448] Minor(UX): more prominent focus ring for widgets
omargfh 04dac05
[#448] Minor(UX): override tab to use specialized positional + tabind…
omargfh 3da3704
Feature: Add Toast notifications
omargfh 5894750
[#448] Minor(UX): Change copy alert to toast
omargfh c21aa60
[#448] Fix(UX): Output values copy event uses internal variable
omargfh 1f033b2
[#448] Fix(UX): Input variables copy internal value on Mod+C
omargfh e41d0b8
Lint: stylistic consistency for [#448]
omargfh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,14 @@ | ||
| { | ||
| "files.watcherExclude": { | ||
| "**/target": true | ||
| } | ||
| }, | ||
|
|
||
| "editor.tabSize": 2, | ||
| "editor.detectIndentation": false, | ||
| "editor.formatOnSave": true, | ||
| "editor.insertSpaces": true, | ||
| "editor.rulers": [80, 100, 120], | ||
| "editor.trimAutoWhitespace": true, | ||
| "editor.renderFinalNewline": "on", | ||
| "editor.renderWhitespace": "all", | ||
| } |
62 changes: 62 additions & 0 deletions
62
app/assets/javascripts/beak/widgets/accessibility/events.coffee
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
|
|
||
| import { isMac, isToggleKeydownEvent } from "./utils.js" | ||
|
|
||
| # (HTMLElement, (Object) => Void) => Void | ||
| ractiveAccessibleClickEvent = (node, fire) -> | ||
| clickHandler = (event) -> | ||
| fire({ node: node, original: event }) | ||
|
|
||
| keydownHandler = (event) -> | ||
| if isToggleKeydownEvent(event) | ||
| event.preventDefault() | ||
| fire({ node: node, original: event }) | ||
|
|
||
| node.addEventListener('click', clickHandler, false) | ||
| node.addEventListener('keydown', keydownHandler, false) | ||
|
|
||
| return { | ||
| teardown: -> | ||
| node.removeEventListener('click', clickHandler, false) | ||
| node.removeEventListener('keydown', keydownHandler, false) | ||
| } | ||
|
|
||
| # (HTMLElement, (Object) => Void) => Void | ||
| ractiveCopyEvent = (node, fire) -> | ||
| keydownHandler = (event) -> | ||
| modKey = if isMac then event.metaKey else event.ctrlKey | ||
| copyKey = event.key is 'c' | ||
| matchKey = modKey and copyKey | ||
|
|
||
| if matchKey | ||
| fire({ node: node, original: event }) | ||
|
|
||
| node.addEventListener('keydown', keydownHandler, false) | ||
|
|
||
| return { | ||
| teardown: -> | ||
| node.removeEventListener('keydown', keydownHandler, false) | ||
| } | ||
|
|
||
| # (HTMLElement, (Object) => Void) => Void | ||
| ractivePasteEvent = (node, fire) -> | ||
| keydownHandler = (event) -> | ||
| modKey = if isMac then event.metaKey else event.ctrlKey | ||
| pasteKey = event.key is 'v' | ||
| matchKey = modKey and pasteKey | ||
|
|
||
| if matchKey | ||
| fire({ node: node, original: event }) | ||
|
|
||
| node.addEventListener('keydown', keydownHandler, false) | ||
|
|
||
| return { | ||
| teardown: -> | ||
| node.removeEventListener('keydown', keydownHandler, false) | ||
| } | ||
|
|
||
|
|
||
| export { | ||
| ractiveAccessibleClickEvent, | ||
| ractiveCopyEvent, | ||
| ractivePasteEvent | ||
| } |
45 changes: 45 additions & 0 deletions
45
app/assets/javascripts/beak/widgets/accessibility/key-combo.coffee
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { isMac } from "./utils.js" | ||
|
|
||
| class KeyCombo | ||
| # (String) => Unit | ||
| constructor: (comboStr) -> | ||
| @comboStr = comboStr | ||
| [@key, parts...] = comboStr.toLowerCase().split('+').map((x) => x.trim()).reverse() | ||
| @modifiers = { | ||
| ctrl: parts.includes('ctrl') or parts.includes('control') | ||
| , alt: parts.includes('alt') or parts.includes('option') | ||
| , shift: parts.includes('shift') | ||
| , meta: parts.includes('meta') or parts.includes('cmd') or parts.includes('command') or parts.includes('mod') | ||
| } | ||
|
|
||
| # { [key: String]: String } | ||
| keyStringTable: { | ||
| up: "↑", | ||
| down: "↓", | ||
| left: "←", | ||
| right: "→", | ||
| escape: "Esc", | ||
| } | ||
|
|
||
| # () => Array[String] | ||
| getKeys: -> | ||
| modifierKeys = Object.entries(@modifiers).filter(([_, v]) => v).map(([mod, _]) => | ||
| switch mod | ||
| when 'ctrl' then if isMac then 'Control' else 'Ctrl' | ||
| when 'alt' then if isMac then '⌥' else 'Alt' | ||
| when 'shift' then '⇧' | ||
| when 'meta' then if isMac then '⌘' else 'Meta' | ||
| ) | ||
|
|
||
| mainKey = if Object.prototype.hasOwnProperty.call(@keyStringTable, @key) | ||
| @keyStringTable[@key] | ||
| else | ||
| @key[0].toUpperCase() + @key.slice(1).toLowerCase() | ||
|
|
||
| [...modifierKeys, mainKey] | ||
|
|
||
| # () => String | ||
| toString: -> | ||
| @getKeys().join(' + ') | ||
|
|
||
| export { KeyCombo } | ||
68 changes: 68 additions & 0 deletions
68
app/assets/javascripts/beak/widgets/accessibility/keybind.coffee
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import { isMac } from "./utils.js" | ||
| import { KeyCombo } from "./key-combo.js" | ||
|
|
||
| # Keybind[mousetrap, ractive] | ||
| # mousetrap: Mousetrap | ||
| # ractive: Ractive | ||
| export class Keybind | ||
| id: undefined # String | ||
| cb: undefined # (ractive, KeyboardEvent, combo) => Boolean | Unit | ||
| combos: undefined # Array[KeyCombo] | ||
| metadata: {} # { description: String, docs: String, hidden?: Boolean } | ||
| options: {} # { type: "keydown" | "keyup" | "keypress", bind: Boolean, preventDefault: Boolean } | ||
|
|
||
| # parameters: | ||
| # id: String | ||
| # cb: (ractive, KeyboardEvent, combo) => Boolean | Unit | ||
| # comboStrs: Array[String] (see https://craig.is/killing/mice; excluding sequences) | ||
| # metadata: { description: String, docs: String } | undefined | ||
| # options: { type: "keydown" | "keyup" | "keypress", bind: Boolean, preventDefault: Boolean } | undefined | ||
| constructor: (@id, @cb, comboStrs, @metadata, options) -> | ||
| @options = { type: "keydown", bind: true, preventDefault: false, ...options } | ||
| @combos = comboStrs.map((comboStr) -> new KeyCombo(comboStr)) | ||
| Object.defineProperty(this, 'comboStrs', { | ||
| get: => @combos.map((combo) -> combo.comboStr) | ||
| }) | ||
|
|
||
| # (mousetrap, ractive, ((ractive) => Boolean) | undefined) => Unit | ||
| bind: (mousetrap, ractive, check) -> | ||
| if @options.bind is true | ||
| mousetrap.bind(@comboStrs, (e, combo) => | ||
| if not check or check(ractive) and @cb? | ||
| if @options.preventDefault and e.preventDefault? | ||
| e.preventDefault() | ||
| return @cb(ractive, e, combo) | ||
| , @options.type) | ||
|
|
||
| # (mousetrap) => Unit | ||
| unbind: (mousetrap) -> | ||
| if @options.bind is true | ||
| mousetrap.unbind(@comboStrs, @options.type) | ||
|
|
||
| # KeybindGroup[mousetrap, ractive] | ||
| # mousetrap: Mousetrap | ||
| # ractive: Ractive | ||
| export class KeybindGroup | ||
| # name: String | ||
| # description: String | undefined | ||
| # conditions: Array[((ractive) => Boolean)] | ||
| # keybinds (keybinds): Array[Keybind] | ||
| constructor: (name, description, conditions, keybinds) -> | ||
| @name = name | ||
| @description = description | ||
| @conditions = conditions | ||
| @keybinds = keybinds | ||
|
|
||
| # ractive => Boolean | ||
omargfh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| meetsConditions: (ractive) -> | ||
| return @conditions.every((condition) => condition(ractive)) | ||
|
|
||
| # (mousetrap, ractive) => Unit | ||
| bind: (mousetrap, ractive) -> | ||
| @keybinds.forEach((keybind) => | ||
| keybind.bind(mousetrap, ractive, @meetsConditions.bind(this)) | ||
| ) | ||
|
|
||
| # (mousetrap) => Unit | ||
| unbind: (mousetrap) -> | ||
| @keybinds.forEach((keybind) -> keybind.unbind(mousetrap)) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.