| ... | @@ -41,10 +41,7 @@ const SHAKE = [0, -8, 8, -8, 8, -8, 8, 0].map((x) => ({ transform: `translateX($ | ... | @@ -41,10 +41,7 @@ const SHAKE = [0, -8, 8, -8, 8, -8, 8, 0].map((x) => ({ transform: `translateX($ |
| 41 | const reduced = matchMedia("(prefers-reduced-motion: reduce)"); | 41 | const reduced = matchMedia("(prefers-reduced-motion: reduce)"); |
| 42 | let dialogs = 0; | 42 | let dialogs = 0; |
| 43 | | 43 | |
| 44 | /** | 44 | /** Destructive confirmations focus back; fields with autofocus take precedence. */ |
| 45 | * Enter confirms and Esc, the backdrop, and "back" cancel. Confirm starts focused unless the body has an | | |
| 46 | * `autofocus` field; the browser checks the body's constraints (`required`, `pattern`…) before `onConfirm` runs. | | |
| 47 | */ | | |
| 48 | export const showConfirmDialog = (options: DialogOptions) => open(options); | 45 | export const showConfirmDialog = (options: DialogOptions) => open(options); |
| 49 | | 46 | |
| 50 | /** Like showConfirmDialog with a text field; Enter submits once `validateInput` passes. */ | 47 | /** Like showConfirmDialog with a text field; Enter submits once `validateInput` passes. */ |
| ... | @@ -120,10 +117,10 @@ function open(options: DialogOptions, field?: TextDialogOptions) { | ... | @@ -120,10 +117,10 @@ function open(options: DialogOptions, field?: TextDialogOptions) { |
| 120 | <Show when={options.body}><fieldset disabled={pending()}>{body}</fieldset></Show> | 117 | <Show when={options.body}><fieldset disabled={pending()}>{body}</fieldset></Show> |
| 121 | <Show when={error()}><p class="error" role="alert">{error()}</p></Show> | 118 | <Show when={error()}><p class="error" role="alert">{error()}</p></Show> |
| 122 | <div class="actions"> | 119 | <div class="actions"> |
| 123 | <button type="button" class="button" disabled={pending()} onClick={close}>back<kbd aria-hidden="true">esc</kbd></button> | 120 | <button type="button" class="button" disabled={pending()} autofocus={options.destructive} onClick={close}>back<kbd aria-hidden="true">esc</kbd></button> |
| 124 | {/* aria-disabled rather than disabled while pending, so focus stays put for a retry. */} | 121 | {/* aria-disabled rather than disabled while pending, so focus stays put for a retry. */} |
| 125 | <button type="submit" class="button primary" classList={{ danger: options.destructive }} | 122 | <button type="submit" class="button primary" classList={{ danger: options.destructive }} |
| 126 | autofocus={!field} disabled={!valid()} aria-disabled={pending()} aria-busy={pending()}> | 123 | autofocus={!field && !options.destructive} disabled={!valid()} aria-disabled={pending()} aria-busy={pending()}> |
| 127 | {options.confirmLabel}<kbd aria-hidden="true">enter</kbd> | 124 | {options.confirmLabel}<kbd aria-hidden="true">enter</kbd> |
| 128 | </button> | 125 | </button> |
| 129 | </div> | 126 | </div> |