@github/markdown-toolbar-element
Advanced tools
+71
-6
@@ -5,2 +5,16 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } | ||
| const buttonSelectors = ['[data-md-button]', 'md-header', 'md-bold', 'md-italic', 'md-quote', 'md-code', 'md-link', 'md-image', 'md-unordered-list', 'md-ordered-list', 'md-task-list', 'md-mention', 'md-ref']; | ||
| function getButtons(toolbar) { | ||
| const els = []; | ||
| for (const button of toolbar.querySelectorAll(buttonSelectors.join(', '))) { | ||
| // Skip buttons that are hidden, either via `hidden` attribute or CSS: | ||
| if (button.hidden || button.offsetWidth <= 0 && button.offsetHeight <= 0) continue; | ||
| if (button.closest('markdown-toolbar') === toolbar) els.push(button); | ||
| } | ||
| return els; | ||
| } | ||
| function keydown(fn) { | ||
@@ -32,6 +46,2 @@ return function (event) { | ||
| connectedCallback() { | ||
| if (!this.hasAttribute('tabindex')) { | ||
| this.setAttribute('tabindex', '0'); | ||
| } | ||
| if (!this.hasAttribute('role')) { | ||
@@ -288,2 +298,7 @@ this.setAttribute('role', 'button'); | ||
| connectedCallback() { | ||
| if (!this.hasAttribute('role')) { | ||
| this.setAttribute('role', 'toolbar'); | ||
| } | ||
| this.addEventListener('keydown', focusKeydown); | ||
| const fn = shortcut.bind(null, this); | ||
@@ -295,2 +310,7 @@ | ||
| } | ||
| this.setAttribute('tabindex', '0'); | ||
| this.addEventListener('focus', onToolbarFocus, { | ||
| once: true | ||
| }); | ||
| } | ||
@@ -305,2 +325,4 @@ | ||
| } | ||
| this.removeEventListener('keydown', focusKeydown); | ||
| } | ||
@@ -317,2 +339,45 @@ | ||
| function onToolbarFocus(_ref) { | ||
| let { | ||
| target | ||
| } = _ref; | ||
| if (!(target instanceof Element)) return; | ||
| target.removeAttribute('tabindex'); | ||
| let tabindex = '0'; | ||
| for (const button of getButtons(target)) { | ||
| button.setAttribute('tabindex', tabindex); | ||
| if (tabindex === '0') { | ||
| button.focus(); | ||
| tabindex = '-1'; | ||
| } | ||
| } | ||
| } | ||
| function focusKeydown(event) { | ||
| const key = event.key; | ||
| if (key !== 'ArrowRight' && key !== 'ArrowLeft' && key !== 'Home' && key !== 'End') return; | ||
| const toolbar = event.currentTarget; | ||
| if (!(toolbar instanceof HTMLElement)) return; | ||
| const buttons = getButtons(toolbar); | ||
| const index = buttons.indexOf(event.target); | ||
| const length = buttons.length; | ||
| if (index === -1) return; | ||
| let n = 0; | ||
| if (key === 'ArrowLeft') n = index - 1; | ||
| if (key === 'ArrowRight') n = index + 1; | ||
| if (key === 'End') n = length - 1; | ||
| if (n < 0) n = length - 1; | ||
| if (n > length - 1) n = 0; | ||
| for (let i = 0; i < length; i += 1) { | ||
| buttons[i].setAttribute('tabindex', i === n ? '0' : '-1'); | ||
| } // Need to stop home/end scrolling: | ||
| event.preventDefault(); | ||
| buttons[n].focus(); | ||
| } | ||
| const shortcutListeners = new WeakMap(); | ||
@@ -367,3 +432,3 @@ | ||
| function insertText(textarea, _ref) { | ||
| function insertText(textarea, _ref2) { | ||
| let { | ||
@@ -373,3 +438,3 @@ text, | ||
| selectionEnd | ||
| } = _ref; | ||
| } = _ref2; | ||
| const originalSelectionStart = textarea.selectionStart; | ||
@@ -376,0 +441,0 @@ const before = textarea.value.slice(0, originalSelectionStart); |
+71
-6
@@ -25,2 +25,16 @@ (function (global, factory) { | ||
| const buttonSelectors = ['[data-md-button]', 'md-header', 'md-bold', 'md-italic', 'md-quote', 'md-code', 'md-link', 'md-image', 'md-unordered-list', 'md-ordered-list', 'md-task-list', 'md-mention', 'md-ref']; | ||
| function getButtons(toolbar) { | ||
| const els = []; | ||
| for (const button of toolbar.querySelectorAll(buttonSelectors.join(', '))) { | ||
| // Skip buttons that are hidden, either via `hidden` attribute or CSS: | ||
| if (button.hidden || button.offsetWidth <= 0 && button.offsetHeight <= 0) continue; | ||
| if (button.closest('markdown-toolbar') === toolbar) els.push(button); | ||
| } | ||
| return els; | ||
| } | ||
| function keydown(fn) { | ||
@@ -52,6 +66,2 @@ return function (event) { | ||
| connectedCallback() { | ||
| if (!this.hasAttribute('tabindex')) { | ||
| this.setAttribute('tabindex', '0'); | ||
| } | ||
| if (!this.hasAttribute('role')) { | ||
@@ -308,2 +318,7 @@ this.setAttribute('role', 'button'); | ||
| connectedCallback() { | ||
| if (!this.hasAttribute('role')) { | ||
| this.setAttribute('role', 'toolbar'); | ||
| } | ||
| this.addEventListener('keydown', focusKeydown); | ||
| const fn = shortcut.bind(null, this); | ||
@@ -315,2 +330,7 @@ | ||
| } | ||
| this.setAttribute('tabindex', '0'); | ||
| this.addEventListener('focus', onToolbarFocus, { | ||
| once: true | ||
| }); | ||
| } | ||
@@ -325,2 +345,4 @@ | ||
| } | ||
| this.removeEventListener('keydown', focusKeydown); | ||
| } | ||
@@ -337,2 +359,45 @@ | ||
| function onToolbarFocus(_ref) { | ||
| let { | ||
| target | ||
| } = _ref; | ||
| if (!(target instanceof Element)) return; | ||
| target.removeAttribute('tabindex'); | ||
| let tabindex = '0'; | ||
| for (const button of getButtons(target)) { | ||
| button.setAttribute('tabindex', tabindex); | ||
| if (tabindex === '0') { | ||
| button.focus(); | ||
| tabindex = '-1'; | ||
| } | ||
| } | ||
| } | ||
| function focusKeydown(event) { | ||
| const key = event.key; | ||
| if (key !== 'ArrowRight' && key !== 'ArrowLeft' && key !== 'Home' && key !== 'End') return; | ||
| const toolbar = event.currentTarget; | ||
| if (!(toolbar instanceof HTMLElement)) return; | ||
| const buttons = getButtons(toolbar); | ||
| const index = buttons.indexOf(event.target); | ||
| const length = buttons.length; | ||
| if (index === -1) return; | ||
| let n = 0; | ||
| if (key === 'ArrowLeft') n = index - 1; | ||
| if (key === 'ArrowRight') n = index + 1; | ||
| if (key === 'End') n = length - 1; | ||
| if (n < 0) n = length - 1; | ||
| if (n > length - 1) n = 0; | ||
| for (let i = 0; i < length; i += 1) { | ||
| buttons[i].setAttribute('tabindex', i === n ? '0' : '-1'); | ||
| } // Need to stop home/end scrolling: | ||
| event.preventDefault(); | ||
| buttons[n].focus(); | ||
| } | ||
| const shortcutListeners = new WeakMap(); | ||
@@ -387,3 +452,3 @@ | ||
| function insertText(textarea, _ref) { | ||
| function insertText(textarea, _ref2) { | ||
| let { | ||
@@ -393,3 +458,3 @@ text, | ||
| selectionEnd | ||
| } = _ref; | ||
| } = _ref2; | ||
| const originalSelectionStart = textarea.selectionStart; | ||
@@ -396,0 +461,0 @@ const before = textarea.value.slice(0, originalSelectionStart); |
+1
-1
| { | ||
| "name": "@github/markdown-toolbar-element", | ||
| "version": "1.1.1", | ||
| "version": "1.2.0", | ||
| "description": "Markdown formatting buttons for text inputs.", | ||
@@ -5,0 +5,0 @@ "repository": "github/markdown-toolbar-element", |
+3
-0
@@ -31,2 +31,3 @@ # <markdown-toolbar> element | ||
| <md-ref>ref</md-ref> | ||
| <button data-md-button>Custom button</button> | ||
| </markdown-toolbar> | ||
@@ -36,2 +37,4 @@ <textarea id="textarea_id"></textarea> | ||
| `<markdown-toolbar>` comes with focus management as advised in [WAI-ARIA Authoring Practices 1.1: Toolbar Design Pattern](https://www.w3.org/TR/wai-aria-practices-1.1/examples/toolbar/toolbar.html). The `md-*` buttons that ship with this package are automatically managed. Add a `data-md-button` attribute to any custom toolbar items to enroll them into focus management. | ||
| ## Browser support | ||
@@ -38,0 +41,0 @@ |
50040
9.69%1296
8.72%60
5.26%