@vialiq/web-components 0.18.0 → 0.20.0

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.
@@ -22,6 +22,8 @@
22
22
  }
23
23
  overlays = [];
24
24
  _previousOverflow = null;
25
+ _previousPaddingRight = null;
26
+ _inertedElements = [];
25
27
  /**
26
28
  * Registers an element as an active overlay.
27
29
  * Calculates and returns the appropriate z-index for this overlay.
@@ -30,7 +32,7 @@
30
32
  * @param type The type of overlay, used to determine behaviors like scroll-locking.
31
33
  * @param scrollStrategy How this overlay interacts with background scrolling.
32
34
  * @returns The calculated z-index to be applied to the element.
33
- */ register(element, type = 'dropdown', scrollStrategy) {
35
+ */ register(element, type = 'dropdown', scrollStrategy, options) {
34
36
  this.unregister(element); // Ensure no duplicates
35
37
  let highestZIndex = this.getBaseZIndex(element);
36
38
  if (this.overlays.length > 0) {
@@ -43,9 +45,11 @@
43
45
  element,
44
46
  type,
45
47
  zIndex: newZIndex,
46
- scrollStrategy: finalStrategy
48
+ scrollStrategy: finalStrategy,
49
+ noBackdrop: options?.noBackdrop
47
50
  });
48
51
  this._updateBodyScroll();
52
+ this._syncInertState();
49
53
  return newZIndex;
50
54
  }
51
55
  /**
@@ -56,6 +60,7 @@
56
60
  */ unregister(element) {
57
61
  this.overlays = this.overlays.filter((o)=>o.element !== element);
58
62
  this._updateBodyScroll();
63
+ this._syncInertState();
59
64
  }
60
65
  /**
61
66
  * Gets the assigned z-index for an element if it is currently registered.
@@ -78,6 +83,46 @@
78
83
  return topOverlay.element === element;
79
84
  }
80
85
  /**
86
+ * Syncs the `inert` attribute on `document.body` children based on the active overlay stack.
87
+ * Modals with a backdrop trap focus globally, so everything beneath them must be `inert`.
88
+ */ _syncInertState() {
89
+ if (typeof document === 'undefined') return;
90
+ // Find the topmost modal that requires a backdrop
91
+ const blockingOverlays = this.overlays.filter((o)=>o.type === 'modal' && !o.noBackdrop);
92
+ const topBlocking = blockingOverlays.length > 0 ? blockingOverlays[blockingOverlays.length - 1] : null;
93
+ if (!topBlocking) {
94
+ // If no blocking overlays, clear all inert state
95
+ this._inertedElements.forEach((el)=>{
96
+ el.inert = false;
97
+ });
98
+ this._inertedElements = [];
99
+ return;
100
+ }
101
+ // Determine which overlays should NOT be inert (the top blocking one and any above it)
102
+ const activeOverlayElements = new Set();
103
+ const topBlockingIndex = this.overlays.indexOf(topBlocking);
104
+ for(let i = topBlockingIndex; i < this.overlays.length; i++){
105
+ activeOverlayElements.add(this.overlays[i].element);
106
+ }
107
+ // Mark children of body
108
+ Array.from(document.body.children).forEach((child)=>{
109
+ const el = child;
110
+ // Never make the active overlays inert
111
+ if (activeOverlayElements.has(el)) {
112
+ if (this._inertedElements.includes(el)) {
113
+ el.inert = false;
114
+ this._inertedElements = this._inertedElements.filter((e)=>e !== el);
115
+ }
116
+ return;
117
+ }
118
+ // If it's not an active overlay, and not already inert, make it inert
119
+ if (!el.inert) {
120
+ el.inert = true;
121
+ this._inertedElements.push(el);
122
+ }
123
+ });
124
+ }
125
+ /**
81
126
  * Locks or unlocks the document.body scroll based on the active overlays.
82
127
  * Modals (and other overlays with scrollStrategy='block') require the body
83
128
  * to be unscrollable. It applies a utility class `vi-scroll-locked` to the body.
@@ -86,9 +131,17 @@
86
131
  if (hasBlock) {
87
132
  // Prevent double-setting if already locked
88
133
  if (!document.body.classList.contains('vi-scroll-locked')) {
134
+ // Calculate scrollbar width before removing overflow
135
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
89
136
  document.body.classList.add('vi-scroll-locked');
90
137
  this._previousOverflow = document.body.style.getPropertyValue('overflow') || null;
138
+ this._previousPaddingRight = document.body.style.getPropertyValue('padding-right') || null;
91
139
  document.body.style.setProperty('overflow', 'hidden', 'important');
140
+ // Apply compensation padding to prevent layout shift
141
+ if (scrollbarWidth > 0) {
142
+ const currentPadding = parseFloat(window.getComputedStyle(document.body).paddingRight || '0');
143
+ document.body.style.setProperty('padding-right', `${currentPadding + scrollbarWidth}px`, 'important');
144
+ }
92
145
  }
93
146
  } else {
94
147
  if (document.body.classList.contains('vi-scroll-locked')) {
@@ -98,7 +151,13 @@
98
151
  } else {
99
152
  document.body.style.removeProperty('overflow');
100
153
  }
154
+ if (this._previousPaddingRight !== null) {
155
+ document.body.style.setProperty('padding-right', this._previousPaddingRight);
156
+ } else {
157
+ document.body.style.removeProperty('padding-right');
158
+ }
101
159
  this._previousOverflow = null;
160
+ this._previousPaddingRight = null;
102
161
  }
103
162
  }
104
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vialiq/web-components",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -103,7 +103,7 @@
103
103
  },
104
104
  "peerDependencies": {
105
105
  "@floating-ui/dom": ">=1.0.0",
106
- "@vialiq/flux-ui": ">=0.0.4 <0.1.0",
106
+ "@vialiq/flux-ui": "^0.16.0",
107
107
  "@vialiq/icons": ">=0.0.3 <0.1.0",
108
108
  "lit": "^3.0.0"
109
109
  },
@@ -2,7 +2,7 @@ import { unsafeCSS, css, nothing, html } from 'lit';
2
2
  import { customElement, property, state, query } from 'lit/decorators.js';
3
3
  import { V as ViElement } from '../vi-element-C6GfDPs3.js';
4
4
  import { autoUpdate, offset, flip, shift, arrow, computePosition } from '@floating-ui/dom';
5
- import { O as OverlayManager } from '../overlay-manager-xco6S92C.js';
5
+ import { O as OverlayManager } from '../overlay-manager-Ch_6fr_D.js';
6
6
 
7
7
  const tooltipStyles = "@charset \"UTF-8\";@layer reset,components,utilities;.tooltip-panel{position:fixed;z-index:var(--vi-tooltip-z-index, var(--vi-tooltip-z-index, 1070));pointer-events:none;opacity:0;transform:scale(.95);transition:opacity .15s ease-out,transform .15s ease-out;margin:0;border:none;background:transparent;padding:0;overflow:visible;font-family:var(--vi-font-family-base, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif)}.tooltip-panel[popover]:popover-open{display:block;pointer-events:auto;opacity:1;transform:scale(1)}.tooltip-panel{transition-property:opacity,transform,display,overlay;transition-behavior:allow-discrete}@media(prefers-reduced-motion:reduce){.tooltip-panel{transition:none;transform:none}}.tooltip-content{background-color:var(--vi-tooltip-background, var(--vi-layer-inverse, #111827));color:var(--vi-tooltip-color, var(--vi-text-primary-inverse, #ffffff));font-size:var(--vi-tooltip-font-size, 12px);line-height:1.4;padding:var(--vi-tooltip-padding, 6px 10px);border-radius:var(--vi-tooltip-border-radius, 4px);box-shadow:var(--vi-tooltip-shadow, var(--vi-shadow-md, 0 4px 6px -1px rgba(0, 0, 0, .1)));max-width:var(--vi-tooltip-max-width, 240px);word-wrap:break-word;white-space:normal;position:relative}.tooltip-arrow{position:absolute;width:0;height:0;border-style:solid;border-color:transparent;pointer-events:none}.tooltip-panel[placement^=top] .tooltip-arrow,.tooltip-panel[data-placement^=top] .tooltip-arrow{bottom:calc(-1 * var(--vi-tooltip-arrow-size, 6px));left:50%;transform:translate(-50%);border-width:var(--vi-tooltip-arrow-size, 6px) var(--vi-tooltip-arrow-size, 6px) 0;border-top-color:var(--vi-tooltip-background, var(--vi-layer-inverse, #111827))}.tooltip-panel[placement^=bottom] .tooltip-arrow,.tooltip-panel[data-placement^=bottom] .tooltip-arrow{top:calc(-1 * var(--vi-tooltip-arrow-size, 6px));left:50%;transform:translate(-50%);border-width:0 var(--vi-tooltip-arrow-size, 6px) var(--vi-tooltip-arrow-size, 6px);border-bottom-color:var(--vi-tooltip-background, var(--vi-layer-inverse, #111827))}.tooltip-panel[placement=left] .tooltip-arrow,.tooltip-panel[data-placement=left] .tooltip-arrow{right:calc(-1 * var(--vi-tooltip-arrow-size, 6px));top:50%;transform:translateY(-50%);border-width:var(--vi-tooltip-arrow-size, 6px) 0 var(--vi-tooltip-arrow-size, 6px) var(--vi-tooltip-arrow-size, 6px);border-left-color:var(--vi-tooltip-background, var(--vi-layer-inverse, #111827))}.tooltip-panel[placement=right] .tooltip-arrow,.tooltip-panel[data-placement=right] .tooltip-arrow{left:calc(-1 * var(--vi-tooltip-arrow-size, 6px));top:50%;transform:translateY(-50%);border-width:var(--vi-tooltip-arrow-size, 6px) var(--vi-tooltip-arrow-size, 6px) var(--vi-tooltip-arrow-size, 6px) 0;border-right-color:var(--vi-tooltip-background, var(--vi-layer-inverse, #111827))}.tooltip-panel[placement$=-start] .tooltip-arrow,.tooltip-panel[data-placement$=-start] .tooltip-arrow{left:12px;transform:none}.tooltip-panel[placement$=-end] .tooltip-arrow,.tooltip-panel[data-placement$=-end] .tooltip-arrow{left:auto;right:12px;transform:none}:host{display:inline-block}";
8
8