@momentum-design/components 0.129.45 → 0.129.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/browser/index.js +300 -300
  2. package/dist/browser/index.js.map +4 -4
  3. package/dist/components/button/button.component.d.ts +9 -1
  4. package/dist/components/button/button.component.js +13 -2
  5. package/dist/components/combobox/combobox.component.d.ts +1 -1
  6. package/dist/components/combobox/combobox.component.js +2 -5
  7. package/dist/components/dialog/dialog.component.d.ts +19 -7
  8. package/dist/components/dialog/dialog.component.js +40 -14
  9. package/dist/components/menubar/menubar.component.d.ts +6 -0
  10. package/dist/components/menubar/menubar.component.js +30 -26
  11. package/dist/components/menupopover/menupopover.component.d.ts +1 -1
  12. package/dist/components/menupopover/menupopover.component.js +19 -24
  13. package/dist/components/popover/popover.component.d.ts +15 -26
  14. package/dist/components/popover/popover.component.js +46 -54
  15. package/dist/components/searchpopover/searchpopover.component.d.ts +1 -1
  16. package/dist/components/searchpopover/searchpopover.component.js +2 -2
  17. package/dist/components/select/select.component.d.ts +1 -1
  18. package/dist/components/select/select.component.js +5 -3
  19. package/dist/components/text/text.component.d.ts +11 -2
  20. package/dist/components/text/text.component.js +17 -2
  21. package/dist/components/tooltip/tooltip.component.d.ts +13 -1
  22. package/dist/components/tooltip/tooltip.component.js +40 -0
  23. package/dist/components/tooltip/tooltip.constants.d.ts +1 -0
  24. package/dist/components/tooltip/tooltip.constants.js +1 -0
  25. package/dist/custom-elements.json +187 -68
  26. package/dist/utils/controllers/DepthManager.d.ts +202 -0
  27. package/dist/utils/controllers/DepthManager.js +259 -0
  28. package/dist/utils/dom.d.ts +8 -0
  29. package/dist/utils/dom.js +7 -0
  30. package/dist/utils/mixins/BackdropMixin.js +19 -2
  31. package/dist/utils/mixins/FocusTrapMixin.d.ts +0 -0
  32. package/dist/utils/mixins/FocusTrapMixin.js +1 -0
  33. package/dist/utils/mixins/OverflowMixin.d.ts +7 -0
  34. package/dist/utils/mixins/OverflowMixin.js +23 -0
  35. package/package.json +1 -1
  36. package/dist/components/popover/popover.stack.d.ts +0 -53
  37. package/dist/components/popover/popover.stack.js +0 -66
@@ -18,9 +18,9 @@ import { FocusTrapMixin } from '../../utils/mixins/focus/FocusTrapMixin';
18
18
  import { PreventScrollMixin } from '../../utils/mixins/PreventScrollMixin';
19
19
  import { Timers } from '../../utils/controllers/Timers';
20
20
  import { ACTIONS, KeyToActionMixin } from '../../utils/mixins/KeyToActionMixin';
21
+ import { DepthManager } from '../../utils/controllers/DepthManager';
21
22
  import { COLOR, DEFAULTS, POPOVER_PLACEMENT, TIMEOUTS, TRIGGER } from './popover.constants';
22
23
  import { PopoverEventManager } from './popover.events';
23
- import { popoverStack } from './popover.stack';
24
24
  import styles from './popover.styles';
25
25
  import { PopoverUtils } from './popover.utils';
26
26
  /**
@@ -101,21 +101,12 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
101
101
  /**
102
102
  * The effective z-index of the popover.
103
103
  *
104
- * If no explicit `z-index` value is provided, then we calculate
105
- * z-index based on the popover’s nesting depth (`popoverDepth`)
106
- * to ensure proper stacking order among multiple popovers.
107
- *
108
- * The formula used is: `DEFAULTS.Z_INDEX + (popoverDepth * 3)`.
109
- * This approach guarantees that each nested popover appears above its parent.
110
- * Ex: A root-level popover has a z-index of 1000,
111
- * its first-level child popover will have a z-index of 1003,
112
- * and a second-level child popover will have a z-index of 1006, and so on.
113
- *
114
- * When a value is explicitly set, it overrides the internally computed value.
104
+ * If no explicit `z-index` value is provided, then it automatically calculated
105
+ * to ensure proper stacking order among multiple overlays.
115
106
  */
116
107
  get zIndex() {
117
- if (this.internalZIndex === undefined || !Number.isInteger(this.internalZIndex)) {
118
- return DEFAULTS.Z_INDEX + this.popoverDepth * 3;
108
+ if (!Number.isInteger(this.internalZIndex)) {
109
+ return this.depthManager.getHostZIndex();
119
110
  }
120
111
  return this.internalZIndex;
121
112
  }
@@ -136,6 +127,10 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
136
127
  }
137
128
  constructor() {
138
129
  super();
130
+ /** track the depth of the popover for z-index calculation
131
+ * @internal
132
+ */
133
+ this.depthManager = new DepthManager(this);
139
134
  /**
140
135
  * The unique ID of the popover.
141
136
  */
@@ -374,15 +369,6 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
374
369
  this.floatingUICleanupFunction = null;
375
370
  /** @internal */
376
371
  this.shouldSuppressOpening = false;
377
- /**
378
- * At root-level popover starts with a depth of `0`. Each subsequent
379
- * child popover increases the depth by one.
380
- *
381
- * This value is used to compute stacking order (z-index) dynamically,
382
- * ensuring that nested popovers appear above their parent popovers.
383
- * @internal
384
- */
385
- this.popoverDepth = 0;
386
372
  /** @internal */
387
373
  this.timers = new Timers(this);
388
374
  /** @internal */
@@ -465,7 +451,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
465
451
  }
466
452
  if (this.hideOnEscape) {
467
453
  this.removeEventListener('keydown', this.onEscapeKeydown);
468
- document.removeEventListener('keydown', this.onEscapeKeydown, { capture: true });
454
+ document.removeEventListener('keydown', this.onEscapeKeydown);
469
455
  }
470
456
  if (this.hideOnBlur) {
471
457
  this.removeEventListener('focusout', this.onPopoverFocusOut);
@@ -478,7 +464,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
478
464
  * @internal
479
465
  */
480
466
  this.onOutsidePopoverClick = (event) => {
481
- if (popoverStack.peek() !== this)
467
+ if (!this.depthManager.isHostOnTop())
482
468
  return;
483
469
  const path = event.composedPath();
484
470
  const insidePopoverClick = this.contains(event.target) || path.includes(this.triggerElement) || path.includes(this);
@@ -497,7 +483,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
497
483
  * @internal
498
484
  */
499
485
  this.onEscapeKeydown = (event) => {
500
- if (!this.visible || this.getActionForKeyEvent(event) !== ACTIONS.ESCAPE) {
486
+ if (!this.visible || this.getActionForKeyEvent(event) !== ACTIONS.ESCAPE || !this.depthManager.isHostOnTop()) {
501
487
  return;
502
488
  }
503
489
  if (!this.propagateEventOnEscape) {
@@ -614,28 +600,6 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
614
600
  this.timers.clearTimeout(TIMEOUTS.HOVER);
615
601
  this.timers.clearTimeout(TIMEOUTS.CLOSE);
616
602
  };
617
- /**
618
- * Shows the popover.
619
- */
620
- this.show = () => {
621
- if (this.shouldSuppressOpening) {
622
- return;
623
- }
624
- this.cancelCloseDelay();
625
- if (this.visible) {
626
- return;
627
- }
628
- const callback = () => {
629
- this.visible = true;
630
- };
631
- if (this.openDelay > 0) {
632
- this.timers.setTimeout(TIMEOUTS.OPEN, callback, this.openDelay);
633
- }
634
- else {
635
- this.timers.clearTimeout(TIMEOUTS.OPEN);
636
- callback();
637
- }
638
- };
639
603
  /**
640
604
  * Hides the popover.
641
605
  */
@@ -746,6 +710,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
746
710
  animationFrame: this.animationFrame,
747
711
  });
748
712
  };
713
+ this.show = this.show.bind(this);
749
714
  this.utils = new PopoverUtils(this);
750
715
  this.parseTrigger();
751
716
  [this.openDelay, this.closeDelay] = this.utils.setupDelay();
@@ -775,7 +740,6 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
775
740
  }
776
741
  this.utils.cleanupAppendTo();
777
742
  PopoverEventManager.onDestroyedPopover(this);
778
- popoverStack.remove(this);
779
743
  }
780
744
  async updated(changedProperties) {
781
745
  super.updated(changedProperties);
@@ -838,6 +802,15 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
838
802
  }
839
803
  }
840
804
  }
805
+ /** @internal */
806
+ onComponentStackChanged(changed) {
807
+ if (changed === 'removed') {
808
+ this.hide();
809
+ }
810
+ else if (changed === 'moved') {
811
+ this.requestUpdate('zIndex');
812
+ }
813
+ }
841
814
  /**
842
815
  * Handles the popover visibility change and position the popover.
843
816
  * Handles the exit event to close the popover.
@@ -852,8 +825,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
852
825
  return;
853
826
  }
854
827
  if (newValue && !this.shouldSuppressOpening) {
855
- if (popoverStack.peek() !== this) {
856
- this.popoverDepth = popoverStack.push(this);
828
+ if (this.depthManager.pushHost()) {
857
829
  // request update to trigger zIndex recalculation
858
830
  this.requestUpdate('zIndex');
859
831
  }
@@ -896,9 +868,7 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
896
868
  PopoverEventManager.onShowPopover(this);
897
869
  }
898
870
  else {
899
- if (popoverStack.peek() === this) {
900
- popoverStack.pop();
901
- }
871
+ this.depthManager.popHost();
902
872
  // cleanup floating-ui on closing the popover
903
873
  (_a = this.floatingUICleanupFunction) === null || _a === void 0 ? void 0 : _a.call(this);
904
874
  if (this.backdrop) {
@@ -931,6 +901,28 @@ class Popover extends KeyToActionMixin(BackdropMixin(PreventScrollMixin(FocusTra
931
901
  PopoverEventManager.onHidePopover(this);
932
902
  }
933
903
  }
904
+ /**
905
+ * Shows the popover.
906
+ */
907
+ show() {
908
+ if (this.shouldSuppressOpening) {
909
+ return;
910
+ }
911
+ this.cancelCloseDelay();
912
+ if (this.visible) {
913
+ return;
914
+ }
915
+ const callback = () => {
916
+ this.visible = true;
917
+ };
918
+ if (this.openDelay > 0) {
919
+ this.timers.setTimeout(TIMEOUTS.OPEN, callback, this.openDelay);
920
+ }
921
+ else {
922
+ this.timers.clearTimeout(TIMEOUTS.OPEN);
923
+ callback();
924
+ }
925
+ }
934
926
  isEventFromTrigger(event) {
935
927
  var _a;
936
928
  if (!this.triggerID)
@@ -92,7 +92,7 @@ declare class Searchpopover extends Searchfield {
92
92
  * Override this to make sure this stays on top of other components.
93
93
  * @default 1000
94
94
  */
95
- popoverZIndex: number;
95
+ popoverZIndex?: number;
96
96
  /**
97
97
  * The aria-label for the popover within Searchpopover.
98
98
  * Use to provide an accessible name for the popover i.e. "Search results".
@@ -13,7 +13,7 @@ import { property } from 'lit/decorators.js';
13
13
  import { ifDefined } from 'lit/directives/if-defined.js';
14
14
  import { live } from 'lit/directives/live.js';
15
15
  import Searchfield from '../searchfield/searchfield.component';
16
- import { POPOVER_PLACEMENT, DEFAULTS as POPOVER_DEFAULTS } from '../popover/popover.constants';
16
+ import { POPOVER_PLACEMENT } from '../popover/popover.constants';
17
17
  import { DEFAULTS as FORMFIELD_DEFAULTS } from '../formfieldwrapper/formfieldwrapper.constants';
18
18
  import { ROLE } from '../../utils/roles';
19
19
  import styles from './searchpopover.styles';
@@ -111,7 +111,7 @@ class Searchpopover extends Searchfield {
111
111
  * Override this to make sure this stays on top of other components.
112
112
  * @default 1000
113
113
  */
114
- this.popoverZIndex = POPOVER_DEFAULTS.Z_INDEX;
114
+ this.popoverZIndex = undefined;
115
115
  }
116
116
  renderInputElement() {
117
117
  var _a, _b;
@@ -114,7 +114,7 @@ declare class Select extends Select_base implements AssociatedFormControl {
114
114
  * Override this to make sure this stays on top of other components.
115
115
  * @default 1000
116
116
  */
117
- popoverZIndex: number;
117
+ popoverZIndex?: number;
118
118
  /**
119
119
  * Determines whether the dropdown should flip its position when it hits the boundary.
120
120
  * @default false
@@ -131,7 +131,7 @@ class Select extends ListNavigationMixin(CaptureDestroyEventForChildElement(Auto
131
131
  * Override this to make sure this stays on top of other components.
132
132
  * @default 1000
133
133
  */
134
- this.popoverZIndex = POPOVER_DEFAULTS.Z_INDEX;
134
+ this.popoverZIndex = undefined;
135
135
  /**
136
136
  * Determines whether the dropdown should flip its position when it hits the boundary.
137
137
  * @default false
@@ -704,8 +704,10 @@ class Select extends ListNavigationMixin(CaptureDestroyEventForChildElement(Auto
704
704
  boundary="${ifDefined(this.boundary)}"
705
705
  strategy="${ifDefined(this.strategy)}"
706
706
  placement="${this.placement}"
707
- @closebyescape="${() => {
708
- this.displayPopover = false;
707
+ @closebyescape="${(event) => {
708
+ if (event.target === event.currentTarget) {
709
+ this.displayPopover = false;
710
+ }
709
711
  }}"
710
712
  @closebyoutsideclick="${() => {
711
713
  this.displayPopover = false;
@@ -1,6 +1,7 @@
1
1
  import { CSSResult } from 'lit';
2
2
  import { Component } from '../../models';
3
3
  import type { TextType, TagName } from './text.types';
4
+ declare const Text_base: import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/OverflowMixin").OverflowMixinInterface> & typeof Component;
4
5
  /**
5
6
  * Text component for creating styled text elements.
6
7
  * It has to be mounted within the ThemeProvider to access color and font tokens.
@@ -19,7 +20,11 @@ import type { TextType, TagName } from './text.types';
19
20
  *
20
21
  * @csspart text - The text element
21
22
  */
22
- declare class Text extends Component {
23
+ declare class Text extends Text_base {
24
+ /**
25
+ * @internal
26
+ */
27
+ private textPartElement;
23
28
  /**
24
29
  * Specifies the text style to be applied.
25
30
  *
@@ -77,7 +82,11 @@ declare class Text extends Component {
77
82
  * For instance, setting this attribute to `h2` will render the text element as an `h2` element.
78
83
  * Note that the styling is determined by the `type` attribute.
79
84
  */
80
- tagname?: TagName;
85
+ tagname: TagName;
86
+ /**
87
+ * @internal
88
+ */
89
+ protected get overflowElement(): HTMLElement;
81
90
  render(): import("lit-html").TemplateResult<1>;
82
91
  static styles: Array<CSSResult>;
83
92
  }
@@ -8,8 +8,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
10
  import { html } from 'lit';
11
- import { property } from 'lit/decorators.js';
11
+ import { property, query } from 'lit/decorators.js';
12
12
  import { Component } from '../../models';
13
+ import { OverflowMixin } from '../../utils/mixins/OverflowMixin';
13
14
  import styles from './text.styles';
14
15
  import { DEFAULTS, VALID_TEXT_TAGS } from './text.constants';
15
16
  /**
@@ -30,7 +31,7 @@ import { DEFAULTS, VALID_TEXT_TAGS } from './text.constants';
30
31
  *
31
32
  * @csspart text - The text element
32
33
  */
33
- class Text extends Component {
34
+ class Text extends OverflowMixin(Component) {
34
35
  constructor() {
35
36
  super(...arguments);
36
37
  /**
@@ -92,6 +93,16 @@ class Text extends Component {
92
93
  */
93
94
  this.tagname = DEFAULTS.TEXT_ELEMENT_TAGNAME;
94
95
  }
96
+ /**
97
+ * @internal
98
+ */
99
+ get overflowElement() {
100
+ // span and small are inline elements therefore we need to return the host element itself
101
+ if ([VALID_TEXT_TAGS.SPAN, VALID_TEXT_TAGS.SMALL].includes(this.tagname)) {
102
+ return this;
103
+ }
104
+ return this.textPartElement;
105
+ }
95
106
  render() {
96
107
  // Lit does not support dynamically changing values for the tag name of a custom element.
97
108
  // Read more: https://lit.dev/docs/templates/expressions/#invalid-locations
@@ -121,6 +132,10 @@ class Text extends Component {
121
132
  }
122
133
  }
123
134
  Text.styles = [...Component.styles, ...styles];
135
+ __decorate([
136
+ query(`[part='${DEFAULTS.CSS_PART_TEXT}']`),
137
+ __metadata("design:type", HTMLElement)
138
+ ], Text.prototype, "textPartElement", void 0);
124
139
  __decorate([
125
140
  property({ attribute: 'type', reflect: true, type: String }),
126
141
  __metadata("design:type", String)
@@ -38,6 +38,16 @@ declare class Tooltip extends Popover {
38
38
  * @default 'description'
39
39
  */
40
40
  tooltipType: TooltipType;
41
+ /**
42
+ * If true, the tooltip will only be shown when the trigger element's content is overflowing on the x-axis.
43
+ *
44
+ * Supports the following components:
45
+ * - mdc-button
46
+ * - mdc-text
47
+ *
48
+ * @default false
49
+ */
50
+ onlyShowWhenTriggerOverflows: boolean;
41
51
  connectedCallback(): void;
42
52
  /**
43
53
  * Sets the type attribute for the tooltip component.
@@ -61,7 +71,9 @@ declare class Tooltip extends Popover {
61
71
  * @param changedProperties - The changed properties.
62
72
  */
63
73
  private onTooltipTypeUpdated;
64
- update(changedProperties: PropertyValues): Promise<void>;
74
+ protected isOpenUpdated(oldValue: boolean, newValue: boolean): Promise<void>;
75
+ update(changedProperties: PropertyValues<this>): Promise<void>;
76
+ show(): void;
65
77
  static styles: Array<CSSResult>;
66
78
  }
67
79
  export default Tooltip;
@@ -12,6 +12,7 @@ import { v4 as uuidv4 } from 'uuid';
12
12
  import { ROLE } from '../../utils/roles';
13
13
  import Popover from '../popover/popover.component';
14
14
  import { DEFAULTS as POPOVER_DEFAULTS, POPOVER_PLACEMENT } from '../popover/popover.constants';
15
+ import { hasOverflowMixin } from '../../utils/dom';
15
16
  import { DEFAULTS, TOOLTIP_TYPES } from './tooltip.constants';
16
17
  import styles from './tooltip.styles';
17
18
  /**
@@ -52,6 +53,16 @@ class Tooltip extends Popover {
52
53
  * @default 'description'
53
54
  */
54
55
  this.tooltipType = DEFAULTS.TOOLTIP_TYPE;
56
+ /**
57
+ * If true, the tooltip will only be shown when the trigger element's content is overflowing on the x-axis.
58
+ *
59
+ * Supports the following components:
60
+ * - mdc-button
61
+ * - mdc-text
62
+ *
63
+ * @default false
64
+ */
65
+ this.onlyShowWhenTriggerOverflows = DEFAULTS.ONLY_SHOW_WHEN_TRIGGER_OVERFLOWS;
55
66
  }
56
67
  connectedCallback() {
57
68
  super.connectedCallback();
@@ -153,6 +164,23 @@ class Tooltip extends Popover {
153
164
  }
154
165
  }
155
166
  }
167
+ async isOpenUpdated(oldValue, newValue) {
168
+ const { triggerElement } = this;
169
+ if (oldValue === newValue || !triggerElement) {
170
+ return;
171
+ }
172
+ if (!newValue) {
173
+ // Timing is critical when the popover pushed/popped from the stack.
174
+ //
175
+ // Timing here:
176
+ // Tooltip closes -> New Popover opens -> Tooltip popped from the stack -> it popes out the new popover as well.
177
+ //
178
+ // It happens because by default the popped element automatically pop the element above it in the stack.
179
+ // To avoid this, we explicitly remove the tooltip from the stack before it is popped.
180
+ this.depthManager.remove([this]);
181
+ }
182
+ await super.isOpenUpdated(oldValue, newValue);
183
+ }
156
184
  async update(changedProperties) {
157
185
  super.update(changedProperties);
158
186
  if (changedProperties.has('id')) {
@@ -165,10 +193,22 @@ class Tooltip extends Popover {
165
193
  this.onTooltipTypeUpdated(changedProperties);
166
194
  }
167
195
  }
196
+ show() {
197
+ if (this.onlyShowWhenTriggerOverflows && this.triggerElement && hasOverflowMixin(this.triggerElement)) {
198
+ if (!this.triggerElement.isWidthOverflowing()) {
199
+ return;
200
+ }
201
+ }
202
+ super.show();
203
+ }
168
204
  }
169
205
  Tooltip.styles = [...Popover.styles, ...styles];
170
206
  __decorate([
171
207
  property({ type: String, attribute: 'tooltip-type', reflect: true }),
172
208
  __metadata("design:type", String)
173
209
  ], Tooltip.prototype, "tooltipType", void 0);
210
+ __decorate([
211
+ property({ type: Boolean, attribute: 'only-show-when-trigger-overflows', reflect: true }),
212
+ __metadata("design:type", Boolean)
213
+ ], Tooltip.prototype, "onlyShowWhenTriggerOverflows", void 0);
174
214
  export default Tooltip;
@@ -16,5 +16,6 @@ declare const DEFAULTS: {
16
16
  readonly PLACEMENT: "top";
17
17
  readonly SHOW_ARROW: true;
18
18
  readonly TOOLTIP_TYPE: "description";
19
+ readonly ONLY_SHOW_WHEN_TRIGGER_OVERFLOWS: false;
19
20
  };
20
21
  export { DEFAULTS, TAG_NAME, TOOLTIP_TYPES };
@@ -18,5 +18,6 @@ const DEFAULTS = {
18
18
  PLACEMENT: POPOVER_PLACEMENT.TOP,
19
19
  SHOW_ARROW: true,
20
20
  TOOLTIP_TYPE: TOOLTIP_TYPES.DESCRIPTION,
21
+ ONLY_SHOW_WHEN_TRIGGER_OVERFLOWS: false,
21
22
  };
22
23
  export { DEFAULTS, TAG_NAME, TOOLTIP_TYPES };