label-165fc611.js 4.9 KB

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