@nectary/components 2.1.2 → 2.1.3
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.
- package/dialog/index.js +1 -1
- package/dialog/utils.d.ts +2 -0
- package/dialog/utils.js +18 -0
- package/package.json +1 -1
- package/pop/index.js +60 -5
- package/pop/utils.d.ts +2 -2
- package/pop/utils.js +8 -4
package/dialog/index.js
CHANGED
|
@@ -2,9 +2,9 @@ import '../icon-button';
|
|
|
2
2
|
import '../icon';
|
|
3
3
|
import '../stop-events';
|
|
4
4
|
import '../title';
|
|
5
|
-
import { disableScroll, enableScroll } from '../pop/utils';
|
|
6
5
|
import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement, updateBooleanAttribute, setClass, isTargetEqual } from '../utils';
|
|
7
6
|
const templateHTML = '<style>:host{display:contents;--sinch-comp-dialog-max-width:512px;--sinch-comp-dialog-max-height:50vh}#dialog{position:fixed;left:0;right:0;margin:auto;display:flex;flex-direction:column;padding:24px 0;max-width:var(--sinch-comp-dialog-max-width);max-height:unset;border-radius:var(--sinch-comp-dialog-shape-radius);box-sizing:border-box;contain:content;background-color:var(--sinch-comp-dialog-color-default-background-initial);border:none;box-shadow:var(--sinch-comp-dialog-shadow);outline:0}#dialog:not([open]){display:none}dialog::backdrop{background-color:#000;opacity:.55}#header{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start;margin-bottom:12px;padding:0 24px}#caption{--sinch-global-color-text:var(--sinch-comp-dialog-color-default-title-initial);--sinch-comp-title-font:var(--sinch-comp-dialog-font-title)}#content{min-height:0;overflow:auto;max-height:var(--sinch-comp-dialog-max-height);padding:4px 24px}#action{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;margin-top:20px;padding:0 24px}#action.empty{display:none}#close{position:relative;left:4px;top:-4px;--sinch-global-color-icon:var(--sinch-comp-dialog-color-default-icon-initial)}</style><dialog id="dialog"><div id="header"><sinch-title id="caption" type="m" level="3" ellipsis></sinch-title><sinch-icon-button id="close" size="s"><sinch-icon id="icon-close" slot="icon" name="close"></sinch-icon></sinch-icon-button></div><div id="content"><sinch-stop-events events="close"><slot name="content"></slot></sinch-stop-events></div><div id="action"><sinch-stop-events events="close"><slot name="buttons"></slot></sinch-stop-events></div></dialog>';
|
|
7
|
+
import { disableScroll, enableScroll } from './utils';
|
|
8
8
|
const template = document.createElement('template');
|
|
9
9
|
template.innerHTML = templateHTML;
|
|
10
10
|
defineCustomElement('sinch-dialog', class extends NectaryElement {
|
package/dialog/utils.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const bodyEl = document.body;
|
|
2
|
+
export const disableScroll = () => {
|
|
3
|
+
bodyEl.__dialog_counter__ = (bodyEl.__dialog_counter__ ?? 0) + 1;
|
|
4
|
+
if (bodyEl.__dialog_counter__ === 1) {
|
|
5
|
+
const scrollWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
6
|
+
bodyEl.style.overflow = 'hidden';
|
|
7
|
+
if (scrollWidth > 0) {
|
|
8
|
+
bodyEl.style.setProperty('padding-right', `${scrollWidth}px`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const enableScroll = () => {
|
|
13
|
+
bodyEl.__dialog_counter__ = Math.max(0, (bodyEl.__dialog_counter__ ?? 0) - 1);
|
|
14
|
+
if (bodyEl.__dialog_counter__ === 0) {
|
|
15
|
+
bodyEl.style.overflow = '';
|
|
16
|
+
bodyEl.style.removeProperty('padding-right');
|
|
17
|
+
}
|
|
18
|
+
};
|
package/package.json
CHANGED
package/pop/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCustomElement, getBooleanAttribute, getLiteralAttribute, getRect, isAttrTrue, updateLiteralAttribute, getReactEventHandler, updateBooleanAttribute, NectaryElement, throttleAnimationFrame, isElementFocused, updateIntegerAttribute, getIntegerAttribute, getFirstFocusableElement, getFirstSlotElement, Context, subscribeContext, isTargetEqual } from '../utils';
|
|
2
2
|
const templateHTML = '<style>:host{display:contents;position:relative}dialog{position:fixed;left:0;top:0;margin:0;outline:0;padding:0;border:none;box-sizing:border-box;max-width:unset;max-height:unset;z-index:1;background:0 0;overflow:visible}dialog:not([open]){display:none}dialog::backdrop{background-color:transparent}#content{position:relative;z-index:1}#target-open{display:flex;flex-direction:column;position:absolute;left:0;top:0}#focus{display:none;position:absolute;width:0;height:0}</style><slot id="target" name="target" aria-haspopup="dialog" aria-expanded="false"></slot><div id="focus"></div><dialog id="dialog"><div id="target-open"><slot name="target-open"></slot></div><div id="content"><slot name="content"></slot></div></dialog>';
|
|
3
|
-
import {
|
|
3
|
+
import { disableOverscroll, enableOverscroll, orientationValues } from './utils';
|
|
4
4
|
const template = document.createElement('template');
|
|
5
5
|
template.innerHTML = templateHTML;
|
|
6
6
|
defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
@@ -17,6 +17,8 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
|
17
17
|
#keydownContext;
|
|
18
18
|
#visibilityContext;
|
|
19
19
|
#targetStyleValue = null;
|
|
20
|
+
#modalWidth = 0;
|
|
21
|
+
#modalHeight = 0;
|
|
20
22
|
constructor() {
|
|
21
23
|
super();
|
|
22
24
|
const shadowRoot = this.attachShadow();
|
|
@@ -201,7 +203,10 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
|
201
203
|
}
|
|
202
204
|
}
|
|
203
205
|
}
|
|
204
|
-
|
|
206
|
+
disableOverscroll();
|
|
207
|
+
window.addEventListener('scroll', this.#updatePosition, {
|
|
208
|
+
passive: false
|
|
209
|
+
});
|
|
205
210
|
window.addEventListener('resize', this.#onResize);
|
|
206
211
|
requestAnimationFrame(() => {
|
|
207
212
|
if (this.isConnected && this.#$dialog.open) {
|
|
@@ -242,14 +247,18 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
|
242
247
|
if (this.#targetActiveElement !== null) {
|
|
243
248
|
if (!isElementFocused(this.#targetActiveElement)) {
|
|
244
249
|
this.#$targetSlot.addEventListener('focus', this.#stopEventPropagation, true);
|
|
245
|
-
this.#targetActiveElement.focus(
|
|
250
|
+
this.#targetActiveElement.focus({
|
|
251
|
+
preventScroll: true
|
|
252
|
+
});
|
|
246
253
|
this.#$targetSlot.removeEventListener('focus', this.#stopEventPropagation, true);
|
|
247
254
|
if (!isElementFocused(this.#targetActiveElement)) {
|
|
248
255
|
const $targetEl = this.#targetActiveElement;
|
|
249
256
|
requestAnimationFrame(() => {
|
|
250
257
|
if (this.isConnected && !this.#$dialog.open) {
|
|
251
258
|
this.#$targetSlot.addEventListener('focus', this.#stopEventPropagation, true);
|
|
252
|
-
$targetEl.focus(
|
|
259
|
+
$targetEl.focus({
|
|
260
|
+
preventScroll: true
|
|
261
|
+
});
|
|
253
262
|
this.#$targetSlot.removeEventListener('focus', this.#stopEventPropagation, true);
|
|
254
263
|
}
|
|
255
264
|
});
|
|
@@ -257,14 +266,58 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
|
257
266
|
this.#targetActiveElement = null;
|
|
258
267
|
}
|
|
259
268
|
}
|
|
260
|
-
|
|
269
|
+
enableOverscroll();
|
|
261
270
|
this.#resizeThrottle.cancel();
|
|
262
271
|
window.removeEventListener('resize', this.#onResize);
|
|
272
|
+
window.removeEventListener('scroll', this.#updatePosition);
|
|
263
273
|
this.#$contentSlot.removeEventListener('slotchange', this.#onContentSlotChange);
|
|
264
274
|
}
|
|
265
275
|
#onResize = () => {
|
|
266
276
|
this.#resizeThrottle.fn();
|
|
267
277
|
};
|
|
278
|
+
#updatePosition = () => {
|
|
279
|
+
const targetRect = this.modal ? this.#getTargetRect() : this.#$targetWrapper.getBoundingClientRect();
|
|
280
|
+
const orient = this.orientation;
|
|
281
|
+
const modalWidth = this.#modalWidth;
|
|
282
|
+
const modalHeight = this.#modalHeight;
|
|
283
|
+
const inset = this.inset;
|
|
284
|
+
let xPos = 0;
|
|
285
|
+
let yPos = 0;
|
|
286
|
+
if (orient === 'bottom-right' || orient === 'top-right' || orient === 'top-stretch' || orient === 'bottom-stretch') {
|
|
287
|
+
xPos = targetRect.x;
|
|
288
|
+
}
|
|
289
|
+
if (orient === 'bottom-left' || orient === 'top-left') {
|
|
290
|
+
xPos = targetRect.x + targetRect.width - modalWidth;
|
|
291
|
+
}
|
|
292
|
+
if (orient === 'bottom-center' || orient === 'top-center') {
|
|
293
|
+
xPos = targetRect.x + targetRect.width / 2 - modalWidth / 2;
|
|
294
|
+
}
|
|
295
|
+
if (orient === 'center-right') {
|
|
296
|
+
xPos = targetRect.x + targetRect.width;
|
|
297
|
+
}
|
|
298
|
+
if (orient === 'center-left') {
|
|
299
|
+
xPos = targetRect.x - modalWidth;
|
|
300
|
+
}
|
|
301
|
+
if (orient === 'bottom-left' || orient === 'bottom-right' || orient === 'bottom-stretch' || orient === 'bottom-center') {
|
|
302
|
+
yPos = targetRect.y + targetRect.height;
|
|
303
|
+
}
|
|
304
|
+
if (orient === 'top-left' || orient === 'top-right' || orient === 'top-stretch' || orient === 'top-center') {
|
|
305
|
+
yPos = targetRect.y - modalHeight;
|
|
306
|
+
}
|
|
307
|
+
if (orient === 'center-left' || orient === 'center-right') {
|
|
308
|
+
yPos = targetRect.y + targetRect.height / 2 - modalHeight / 2;
|
|
309
|
+
}
|
|
310
|
+
const clampedXPos = Math.max(inset, Math.min(xPos, window.innerWidth - modalWidth - inset));
|
|
311
|
+
const clampedYPos = Math.max(inset, Math.min(yPos, window.innerHeight - modalHeight - inset));
|
|
312
|
+
this.#$dialog.style.setProperty('left', `${clampedXPos}px`);
|
|
313
|
+
this.#$dialog.style.setProperty('top', `${clampedYPos}px`);
|
|
314
|
+
if (!this.modal) {
|
|
315
|
+
const targetLeftPos = targetRect.x - clampedXPos;
|
|
316
|
+
const targetTopPos = targetRect.y - clampedYPos;
|
|
317
|
+
this.#$targetOpenWrapper.style.setProperty('left', `${targetLeftPos}px`);
|
|
318
|
+
this.#$targetOpenWrapper.style.setProperty('top', `${targetTopPos}px`);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
268
321
|
#updateOrientation = () => {
|
|
269
322
|
this.#$dialog.style.setProperty('width', 'max-content');
|
|
270
323
|
const targetRect = this.#getTargetRect();
|
|
@@ -276,6 +329,8 @@ defineCustomElement('sinch-pop', class extends NectaryElement {
|
|
|
276
329
|
const inset = this.inset;
|
|
277
330
|
let xPos = 0;
|
|
278
331
|
let yPos = 0;
|
|
332
|
+
this.#modalHeight = modalHeight;
|
|
333
|
+
this.#modalWidth = modalWidth;
|
|
279
334
|
if (orient === 'bottom-right' || orient === 'top-right' || orient === 'top-stretch' || orient === 'bottom-stretch') {
|
|
280
335
|
xPos = targetRect.x;
|
|
281
336
|
}
|
package/pop/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { TSinchPopOrientation } from './types';
|
|
2
2
|
export declare const orientationValues: readonly TSinchPopOrientation[];
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
3
|
+
export declare const disableOverscroll: () => void;
|
|
4
|
+
export declare const enableOverscroll: () => void;
|
package/pop/utils.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
export const orientationValues = ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'bottom-stretch', 'bottom-center', 'top-stretch', 'top-center', 'center-left', 'center-right'];
|
|
2
2
|
const bodyEl = document.body;
|
|
3
|
-
export const
|
|
4
|
-
bodyEl.style.overflow = 'hidden';
|
|
3
|
+
export const disableOverscroll = () => {
|
|
5
4
|
bodyEl.__pop_counter__ = (bodyEl.__pop_counter__ ?? 0) + 1;
|
|
5
|
+
if (bodyEl.__pop_counter__ === 1) {
|
|
6
|
+
bodyEl.style.setProperty('overscroll-behavior', 'none');
|
|
7
|
+
document.documentElement.style.setProperty('overscroll-behavior', 'none');
|
|
8
|
+
}
|
|
6
9
|
};
|
|
7
|
-
export const
|
|
10
|
+
export const enableOverscroll = () => {
|
|
8
11
|
bodyEl.__pop_counter__ = Math.max(0, (bodyEl.__pop_counter__ ?? 0) - 1);
|
|
9
12
|
if (bodyEl.__pop_counter__ === 0) {
|
|
10
|
-
|
|
13
|
+
bodyEl.style.removeProperty('overscroll-behavior');
|
|
14
|
+
document.documentElement.style.removeProperty('overscroll-behavior');
|
|
11
15
|
}
|
|
12
16
|
};
|