label2.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. import { q as queryElementRoots, o as closestElementCrossShadowBoundary } from './dom.js';
  7. /**
  8. * Exported for testing purposes only
  9. *
  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 && queryElementRoots(componentEl, { selector: `${labelTagName}[for="${id}"]` });
  23. if (forLabel) {
  24. return forLabel;
  25. }
  26. const parentLabel = 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. * @param component
  54. */
  55. function connectLabel(component) {
  56. const labelEl = findLabelForComponent(component.el);
  57. if (onLabelClickMap.has(labelEl) || (!labelEl && unlabeledComponents.has(component))) {
  58. return;
  59. }
  60. const boundOnLabelDisconnected = onLabelDisconnected.bind(component);
  61. if (labelEl) {
  62. component.labelEl = labelEl;
  63. const boundOnLabelClick = onLabelClick.bind(component);
  64. onLabelClickMap.set(component.labelEl, boundOnLabelClick);
  65. component.labelEl.addEventListener(labelClickEvent, boundOnLabelClick);
  66. unlabeledComponents.delete(component);
  67. document.removeEventListener(labelConnectedEvent, onLabelConnectedMap.get(component));
  68. onLabelDisconnectedMap.set(component, boundOnLabelDisconnected);
  69. document.addEventListener(labelDisconnectedEvent, boundOnLabelDisconnected);
  70. }
  71. else if (!unlabeledComponents.has(component)) {
  72. boundOnLabelDisconnected();
  73. document.removeEventListener(labelDisconnectedEvent, onLabelDisconnectedMap.get(component));
  74. }
  75. }
  76. /**
  77. * Helper to tear down label interactions on disconnectedCallback on labelable components.
  78. *
  79. * @param component
  80. */
  81. function disconnectLabel(component) {
  82. unlabeledComponents.delete(component);
  83. document.removeEventListener(labelConnectedEvent, onLabelConnectedMap.get(component));
  84. document.removeEventListener(labelDisconnectedEvent, onLabelDisconnectedMap.get(component));
  85. onLabelConnectedMap.delete(component);
  86. onLabelDisconnectedMap.delete(component);
  87. if (!component.labelEl) {
  88. return;
  89. }
  90. const boundOnLabelClick = onLabelClickMap.get(component.labelEl);
  91. component.labelEl.removeEventListener(labelClickEvent, boundOnLabelClick);
  92. onLabelClickMap.delete(component.labelEl);
  93. }
  94. /**
  95. * Helper to get the label text from a component.
  96. *
  97. * @param component
  98. */
  99. function getLabelText(component) {
  100. var _a, _b;
  101. return component.label || ((_b = (_a = component.labelEl) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || "";
  102. }
  103. function onLabelClick(event) {
  104. if (this.disabled) {
  105. return;
  106. }
  107. const containedLabelableChildClicked = this.el.contains(event.detail.sourceEvent.target);
  108. if (containedLabelableChildClicked) {
  109. return;
  110. }
  111. this.onLabelClick(event);
  112. }
  113. function onLabelConnected() {
  114. if (unlabeledComponents.has(this)) {
  115. connectLabel(this);
  116. }
  117. }
  118. function onLabelDisconnected() {
  119. unlabeledComponents.add(this);
  120. const boundOnLabelConnected = onLabelConnectedMap.get(this) || onLabelConnected.bind(this);
  121. onLabelConnectedMap.set(this, boundOnLabelConnected);
  122. document.addEventListener(labelConnectedEvent, boundOnLabelConnected);
  123. }
  124. export { labelDisconnectedEvent as a, connectLabel as c, disconnectLabel as d, getLabelText as g, labelConnectedEvent as l };