label-28060b83.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*!
  2. * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
  4. * v1.0.0-beta.97
  5. */
  6. 'use strict';
  7. const dom = require('./dom-2ec8c9ed.js');
  8. /**
  9. * Exported for testing purposes only
  10. *
  11. * @internal
  12. */
  13. const labelClickEvent = "calciteInternalLabelClick";
  14. const labelConnectedEvent = "calciteInternalLabelConnected";
  15. const labelDisconnectedEvent = "calciteInternaLabelDisconnected";
  16. const labelTagName = "calcite-label";
  17. const onLabelClickMap = new WeakMap();
  18. const onLabelConnectedMap = new WeakMap();
  19. const onLabelDisconnectedMap = new WeakMap();
  20. const unlabeledComponents = new Set();
  21. const findLabelForComponent = (componentEl) => {
  22. const { id } = componentEl;
  23. const forLabel = id && dom.queryElementRoots(componentEl, { selector: `${labelTagName}[for="${id}"]` });
  24. if (forLabel) {
  25. return forLabel;
  26. }
  27. const parentLabel = dom.closestElementCrossShadowBoundary(componentEl, labelTagName);
  28. if (!parentLabel ||
  29. // labelable components within other custom elements are not considered labelable
  30. hasAncestorCustomElements(parentLabel, componentEl)) {
  31. return null;
  32. }
  33. return parentLabel;
  34. };
  35. function hasAncestorCustomElements(label, componentEl) {
  36. let traversedElements;
  37. const customElementAncestorCheckEventType = "custom-element-ancestor-check";
  38. const listener = (event) => {
  39. event.stopImmediatePropagation();
  40. const composedPath = event.composedPath();
  41. traversedElements = composedPath.slice(composedPath.indexOf(componentEl), composedPath.indexOf(label));
  42. };
  43. label.addEventListener(customElementAncestorCheckEventType, listener, { once: true });
  44. componentEl.dispatchEvent(new CustomEvent(customElementAncestorCheckEventType, { composed: true, bubbles: true }));
  45. label.removeEventListener(customElementAncestorCheckEventType, listener);
  46. const ancestorCustomElements = traversedElements
  47. .filter((el) => el !== componentEl && el !== label)
  48. .filter((el) => { var _a; return (_a = el.tagName) === null || _a === void 0 ? void 0 : _a.includes("-"); });
  49. return ancestorCustomElements.length > 0;
  50. }
  51. /**
  52. * Helper to set up label interactions on connectedCallback.
  53. *
  54. * @param component
  55. */
  56. function connectLabel(component) {
  57. const labelEl = findLabelForComponent(component.el);
  58. if (onLabelClickMap.has(labelEl) || (!labelEl && unlabeledComponents.has(component))) {
  59. return;
  60. }
  61. const boundOnLabelDisconnected = onLabelDisconnected.bind(component);
  62. if (labelEl) {
  63. component.labelEl = labelEl;
  64. const boundOnLabelClick = onLabelClick.bind(component);
  65. onLabelClickMap.set(component.labelEl, boundOnLabelClick);
  66. component.labelEl.addEventListener(labelClickEvent, boundOnLabelClick);
  67. unlabeledComponents.delete(component);
  68. document.removeEventListener(labelConnectedEvent, onLabelConnectedMap.get(component));
  69. onLabelDisconnectedMap.set(component, boundOnLabelDisconnected);
  70. document.addEventListener(labelDisconnectedEvent, boundOnLabelDisconnected);
  71. }
  72. else if (!unlabeledComponents.has(component)) {
  73. boundOnLabelDisconnected();
  74. document.removeEventListener(labelDisconnectedEvent, onLabelDisconnectedMap.get(component));
  75. }
  76. }
  77. /**
  78. * Helper to tear down label interactions on disconnectedCallback on labelable components.
  79. *
  80. * @param component
  81. */
  82. function disconnectLabel(component) {
  83. unlabeledComponents.delete(component);
  84. document.removeEventListener(labelConnectedEvent, onLabelConnectedMap.get(component));
  85. document.removeEventListener(labelDisconnectedEvent, onLabelDisconnectedMap.get(component));
  86. onLabelConnectedMap.delete(component);
  87. onLabelDisconnectedMap.delete(component);
  88. if (!component.labelEl) {
  89. return;
  90. }
  91. const boundOnLabelClick = onLabelClickMap.get(component.labelEl);
  92. component.labelEl.removeEventListener(labelClickEvent, boundOnLabelClick);
  93. onLabelClickMap.delete(component.labelEl);
  94. }
  95. /**
  96. * Helper to get the label text from a component.
  97. *
  98. * @param component
  99. */
  100. function getLabelText(component) {
  101. var _a, _b;
  102. return component.label || ((_b = (_a = component.labelEl) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || "";
  103. }
  104. function onLabelClick(event) {
  105. if (this.disabled) {
  106. return;
  107. }
  108. const containedLabelableChildClicked = this.el.contains(event.detail.sourceEvent.target);
  109. if (containedLabelableChildClicked) {
  110. return;
  111. }
  112. this.onLabelClick(event);
  113. }
  114. function onLabelConnected() {
  115. if (unlabeledComponents.has(this)) {
  116. connectLabel(this);
  117. }
  118. }
  119. function onLabelDisconnected() {
  120. unlabeledComponents.add(this);
  121. const boundOnLabelConnected = onLabelConnectedMap.get(this) || onLabelConnected.bind(this);
  122. onLabelConnectedMap.set(this, boundOnLabelConnected);
  123. document.addEventListener(labelConnectedEvent, boundOnLabelConnected);
  124. }
  125. exports.connectLabel = connectLabel;
  126. exports.disconnectLabel = disconnectLabel;
  127. exports.getLabelText = getLabelText;
  128. exports.labelConnectedEvent = labelConnectedEvent;
  129. exports.labelDisconnectedEvent = labelDisconnectedEvent;