focusable-element-evaluate.js 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. import { closest } from '../../core/utils';
  2. function focusableElementEvaluate(node, options, virtualNode) {
  3. /**
  4. * Note:
  5. * Check
  6. * - if element is focusable
  7. * - if element is in focus order via `tabindex`
  8. */
  9. if (
  10. virtualNode.hasAttr('contenteditable') &&
  11. isContenteditable(virtualNode)
  12. ) {
  13. return true;
  14. }
  15. const isFocusable = virtualNode.isFocusable;
  16. let tabIndex = parseInt(virtualNode.attr('tabindex'), 10);
  17. tabIndex = !isNaN(tabIndex) ? tabIndex : null;
  18. return tabIndex ? isFocusable && tabIndex >= 0 : isFocusable;
  19. // contenteditable is focusable when it is an empty string (whitespace
  20. // is not considered empty) or "true". if the value is "false"
  21. // you can't edit it, but if it's anything else it inherits the value
  22. // from the first valid ancestor
  23. // @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable
  24. function isContenteditable(vNode) {
  25. const contenteditable = vNode.attr('contenteditable');
  26. if (contenteditable === 'true' || contenteditable === '') {
  27. return true;
  28. }
  29. if (contenteditable === 'false') {
  30. return false;
  31. }
  32. const ancestor = closest(virtualNode.parent, '[contenteditable]');
  33. if (!ancestor) {
  34. return false;
  35. }
  36. return isContenteditable(ancestor);
  37. }
  38. }
  39. export default focusableElementEvaluate;