ExamplesPlaygroundReference Source

coral-spectrum/coral-component-anchorbutton/src/scripts/AnchorButton.js

  1. /**
  2. * Copyright 2019 Adobe. All rights reserved.
  3. * This file is licensed to you under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License. You may obtain a copy
  5. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. *
  7. * Unless required by applicable law or agreed to in writing, software distributed under
  8. * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  9. * OF ANY KIND, either express or implied. See the License for the specific language
  10. * governing permissions and limitations under the License.
  11. */
  12.  
  13. import {BaseComponent} from '../../../coral-base-component';
  14. import {BaseButton} from '../../../coral-base-button';
  15. import {transform, commons} from '../../../coral-utils';
  16. import {Decorator} from '../../../coral-decorator';
  17.  
  18. // Key code
  19. const SPACE = 32;
  20.  
  21. /**
  22. @class Coral.AnchorButton
  23. @classdesc A Link component rendering as a button allowing us to style an anchor element that both looks and behaves
  24. like a button rather than a link. It can receive keyboard focus regardless of whether or not it has an <code>href</code>
  25. attribute, can be activated using either the <code>SPACE</code> key or the <code>ENTER</code> key, and is identified to
  26. assistive technology as a button element.
  27. @htmltag coral-anchorbutton
  28. @htmlbasetag a
  29. @extends {HTMLAnchorElement}
  30. @extends {BaseComponent}
  31. @extends {BaseButton}
  32. */
  33. const AnchorButton = Decorator(class extends BaseButton(BaseComponent(HTMLAnchorElement)) {
  34. /** @ignore */
  35. constructor() {
  36. super();
  37.  
  38. // Events
  39. this._delegateEvents(commons.extend(this._events, {
  40. keydown: '_onKeyDown',
  41. keyup: '_onKeyUp'
  42. }));
  43.  
  44. // cannot use the events hash because events on disabled items are not reported
  45. this.addEventListener('click', this._onDisabledClick.bind(this));
  46. }
  47.  
  48. /**
  49. Disables the button from user interaction.
  50.  
  51. @type {Boolean}
  52. @default false
  53. @htmlattribute disabled
  54. @htmlattributereflected
  55. */
  56. get disabled() {
  57. return this._disabled || false;
  58. }
  59.  
  60. set disabled(value) {
  61. this._disabled = transform.booleanAttr(value);
  62. this._reflectAttribute('disabled', this._disabled);
  63.  
  64. this.classList.toggle('is-disabled', this._disabled);
  65. this.setAttribute('tabindex', this._disabled ? '-1' : '0');
  66. this[this._disabled ? 'setAttribute' : 'removeAttribute']('aria-disabled', this._disabled);
  67. }
  68.  
  69. /**
  70. Keyboard handling per the WAI-ARIA button widget design pattern:
  71. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role
  72.  
  73. @ignore
  74. */
  75. _onKeyDown(event) {
  76. if (event.keyCode === SPACE) {
  77. event.preventDefault();
  78. this.click();
  79. this.classList.add('is-selected');
  80. }
  81. }
  82.  
  83. /** @ignore */
  84. _onKeyUp(event) {
  85. if (event.keyCode === SPACE) {
  86. event.preventDefault();
  87. this.classList.remove('is-selected');
  88. }
  89. }
  90.  
  91. /** @ignore */
  92. _onDisabledClick(event) {
  93. if (this.disabled) {
  94. event.preventDefault();
  95. }
  96. }
  97.  
  98. // Override content zone name
  99. get _contentZones() {
  100. return {'coral-anchorbutton-label': 'label'};
  101. }
  102.  
  103. /** @ignore */
  104. static get observedAttributes() {
  105. return super.observedAttributes.concat(['disabled']);
  106. }
  107.  
  108. /** @ignore */
  109. render() {
  110. super.render();
  111.  
  112. // a11y
  113. this.setAttribute('role', 'button');
  114. if (!this.disabled) {
  115. // Force tabindex and aria-disabled attribute reflection
  116. this.setAttribute('tabindex', '0');
  117. this.removeAttribute('aria-disabled');
  118. }
  119. }
  120. });
  121.  
  122. export default AnchorButton;