@nectary/components 5.30.0 → 5.31.1
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/bundle.js +328 -19
- package/package.json +1 -1
- package/pop/index.d.ts +1 -0
- package/pop/index.js +5 -2
- package/pop/types.d.ts +2 -0
- package/select-menu/index.js +20 -5
- package/select-menu/types.d.ts +2 -0
- package/select-menu-option/index.d.ts +2 -0
- package/select-menu-option/index.js +7 -1
- package/select-menu-option/types.d.ts +2 -0
- package/tooltip/index.js +293 -11
- package/tooltip/tooltip-state.d.ts +1 -0
- package/tooltip/tooltip-state.js +3 -0
package/bundle.js
CHANGED
|
@@ -3466,6 +3466,9 @@ class Pop extends NectaryElement {
|
|
|
3466
3466
|
get shouldCloseOnBackdropClick() {
|
|
3467
3467
|
return !getBooleanAttribute(this, "disable-backdrop-close");
|
|
3468
3468
|
}
|
|
3469
|
+
get shouldRestoreFocusOnClose() {
|
|
3470
|
+
return !getBooleanAttribute(this, "disable-focus-restore");
|
|
3471
|
+
}
|
|
3469
3472
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
3470
3473
|
if (isAttrEqual(oldVal, newVal)) {
|
|
3471
3474
|
return;
|
|
@@ -3651,7 +3654,7 @@ class Pop extends NectaryElement {
|
|
|
3651
3654
|
if (isNonModal && !effectiveAllowScroll) {
|
|
3652
3655
|
this.#restoreTransferredTarget();
|
|
3653
3656
|
}
|
|
3654
|
-
if (this.#targetActiveElement !== null) {
|
|
3657
|
+
if (this.shouldRestoreFocusOnClose && this.#targetActiveElement !== null) {
|
|
3655
3658
|
if (!isElementFocused(this.#targetActiveElement)) {
|
|
3656
3659
|
this.#$targetSlot.addEventListener("focus", this.#stopEventPropagation, true);
|
|
3657
3660
|
this.#targetActiveElement.focus({ preventScroll: true });
|
|
@@ -3666,9 +3669,9 @@ class Pop extends NectaryElement {
|
|
|
3666
3669
|
}
|
|
3667
3670
|
});
|
|
3668
3671
|
}
|
|
3669
|
-
this.#targetActiveElement = null;
|
|
3670
3672
|
}
|
|
3671
3673
|
}
|
|
3674
|
+
this.#targetActiveElement = null;
|
|
3672
3675
|
if (!effectiveAllowScroll) {
|
|
3673
3676
|
enableOverscroll();
|
|
3674
3677
|
} else {
|
|
@@ -3827,6 +3830,9 @@ class TooltipState {
|
|
|
3827
3830
|
#timerId = null;
|
|
3828
3831
|
#state = "hide";
|
|
3829
3832
|
#options;
|
|
3833
|
+
get isInHideState() {
|
|
3834
|
+
return this.#state === "hide";
|
|
3835
|
+
}
|
|
3830
3836
|
constructor(options) {
|
|
3831
3837
|
this.#options = options;
|
|
3832
3838
|
}
|
|
@@ -3983,10 +3989,15 @@ const SHOW_DELAY_SLOW = 1e3;
|
|
|
3983
3989
|
const SHOW_DELAY_FAST = 250;
|
|
3984
3990
|
const HIDE_DELAY = 0;
|
|
3985
3991
|
const ANIMATION_DURATION = 100;
|
|
3992
|
+
const FOCUSABLE_OUTSIDE_TARGET_SELECTOR = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"]), [contenteditable=""], [contenteditable="true"]';
|
|
3986
3993
|
const OVERLAP_TOLERANCE = 1;
|
|
3987
3994
|
const MAX_ZERO_DIMENSION_PLACEMENT_RETRIES = 8;
|
|
3988
3995
|
const MIN_FIRST_REVEAL_STABILITY_FRAMES = 3;
|
|
3989
3996
|
const MAX_FIRST_REVEAL_STABILITY_FRAMES = 6;
|
|
3997
|
+
let activeTooltip = null;
|
|
3998
|
+
let focusedTooltip = null;
|
|
3999
|
+
let hoveredTooltip = null;
|
|
4000
|
+
let suspendedFocusedTooltip = null;
|
|
3990
4001
|
const template$T = document.createElement("template");
|
|
3991
4002
|
template$T.innerHTML = templateHTML$T;
|
|
3992
4003
|
class Tooltip extends NectaryElement {
|
|
@@ -3996,10 +4007,15 @@ class Tooltip extends NectaryElement {
|
|
|
3996
4007
|
#$contentWrapper;
|
|
3997
4008
|
#$tip;
|
|
3998
4009
|
#$target;
|
|
4010
|
+
#targetElements = [];
|
|
3999
4011
|
#resizeObserver = null;
|
|
4000
4012
|
#tooltipState;
|
|
4001
4013
|
#animation = null;
|
|
4002
4014
|
#shouldReduceMotion = false;
|
|
4015
|
+
#hasFocus = false;
|
|
4016
|
+
#suppressFocusIn = false;
|
|
4017
|
+
#suppressedFocusOutArmed = false;
|
|
4018
|
+
#isSuspendedByHover = false;
|
|
4003
4019
|
#isSubscribed = false;
|
|
4004
4020
|
#controller;
|
|
4005
4021
|
#placementScheduled = false;
|
|
@@ -4036,6 +4052,7 @@ class Tooltip extends NectaryElement {
|
|
|
4036
4052
|
};
|
|
4037
4053
|
this.setAttribute("role", "tooltip");
|
|
4038
4054
|
this.#$pop.addEventListener("-close", this.#onPopClose, options);
|
|
4055
|
+
this.#$target.addEventListener("slotchange", this.#onTargetSlotChange, options);
|
|
4039
4056
|
this.addEventListener("-show", this.#onShowReactHandler, options);
|
|
4040
4057
|
this.addEventListener("-hide", this.#onHideReactHandler, options);
|
|
4041
4058
|
this.#resizeObserver = new ResizeObserver(() => {
|
|
@@ -4044,10 +4061,23 @@ class Tooltip extends NectaryElement {
|
|
|
4044
4061
|
this.#resizeObserver.observe(this.#$content);
|
|
4045
4062
|
updateAttribute(this.#$pop, "orientation", getPopOrientation$1(this.orientation));
|
|
4046
4063
|
updateBooleanAttribute(this.#$pop, "hide-outside-viewport", !this.showOutsideViewport);
|
|
4064
|
+
updateBooleanAttribute(this.#$pop, "disable-focus-restore", true);
|
|
4047
4065
|
this.#updateText();
|
|
4048
4066
|
}
|
|
4049
4067
|
disconnectedCallback() {
|
|
4050
4068
|
super.disconnectedCallback();
|
|
4069
|
+
if (activeTooltip === this) {
|
|
4070
|
+
activeTooltip = null;
|
|
4071
|
+
}
|
|
4072
|
+
if (focusedTooltip === this) {
|
|
4073
|
+
focusedTooltip = null;
|
|
4074
|
+
}
|
|
4075
|
+
if (hoveredTooltip === this) {
|
|
4076
|
+
hoveredTooltip = null;
|
|
4077
|
+
}
|
|
4078
|
+
if (suspendedFocusedTooltip === this) {
|
|
4079
|
+
suspendedFocusedTooltip = null;
|
|
4080
|
+
}
|
|
4051
4081
|
this.#tooltipState.destroy();
|
|
4052
4082
|
this.#controller.abort();
|
|
4053
4083
|
this.#controller = null;
|
|
@@ -4165,14 +4195,217 @@ class Tooltip extends NectaryElement {
|
|
|
4165
4195
|
this.#tooltipState.destroy();
|
|
4166
4196
|
};
|
|
4167
4197
|
#onMouseEnter = () => {
|
|
4198
|
+
this.#claimHoverOwnership();
|
|
4199
|
+
this.#suspendFocusedTooltip();
|
|
4200
|
+
this.#closeActiveTooltip();
|
|
4168
4201
|
this.#tooltipState.show();
|
|
4169
4202
|
};
|
|
4170
|
-
#
|
|
4171
|
-
|
|
4203
|
+
#onContentMouseEnter = () => {
|
|
4204
|
+
this.#claimHoverOwnership();
|
|
4205
|
+
if (this.#hasFocus) {
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
this.#suspendFocusedTooltip();
|
|
4209
|
+
this.#closeActiveTooltip();
|
|
4210
|
+
this.#tooltipState.show();
|
|
4211
|
+
};
|
|
4212
|
+
#onFocusIn = () => {
|
|
4213
|
+
if (this.#suppressFocusIn) {
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
this.#closeFocusedTooltip();
|
|
4217
|
+
this.#closeActiveTooltip();
|
|
4218
|
+
this.#hasFocus = true;
|
|
4219
|
+
focusedTooltip = this;
|
|
4220
|
+
this.#tooltipState.show();
|
|
4221
|
+
};
|
|
4222
|
+
#closeFocusedTooltip() {
|
|
4223
|
+
if (!this.#isOtherUncontrolledTooltip(focusedTooltip)) {
|
|
4224
|
+
return;
|
|
4225
|
+
}
|
|
4226
|
+
const previousFocusedTooltip = focusedTooltip;
|
|
4227
|
+
previousFocusedTooltip.#clearTrackedFocus();
|
|
4228
|
+
previousFocusedTooltip.#tooltipState.destroy();
|
|
4229
|
+
}
|
|
4230
|
+
#closeActiveTooltip() {
|
|
4231
|
+
if (this.#isOtherUncontrolledTooltip(activeTooltip) && !activeTooltip.#hasFocus) {
|
|
4232
|
+
activeTooltip.#tooltipState.destroy();
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
#suspendFocusedTooltip() {
|
|
4236
|
+
if (this.#isOtherUncontrolledTooltip(focusedTooltip)) {
|
|
4237
|
+
suspendedFocusedTooltip = focusedTooltip;
|
|
4238
|
+
focusedTooltip.#suppressFocusIn = true;
|
|
4239
|
+
focusedTooltip.#isSuspendedByHover = true;
|
|
4240
|
+
focusedTooltip.#armSuppressedFocusOut();
|
|
4241
|
+
if (!focusedTooltip.#tooltipState.isInHideState) {
|
|
4242
|
+
focusedTooltip.#tooltipState.destroy();
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
#resumeFocusedTooltip() {
|
|
4247
|
+
const tooltipToResume = suspendedFocusedTooltip;
|
|
4248
|
+
if (tooltipToResume === null || tooltipToResume === this) {
|
|
4249
|
+
return;
|
|
4250
|
+
}
|
|
4251
|
+
if (hoveredTooltip !== null) {
|
|
4252
|
+
if (hoveredTooltip === this && !this.#isPointerWithinHoverSurface()) {
|
|
4253
|
+
this.#releaseHoverOwnership();
|
|
4254
|
+
} else {
|
|
4255
|
+
return;
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
if (!tooltipToResume.#isSuspendedByHover) {
|
|
4259
|
+
if (suspendedFocusedTooltip === tooltipToResume) {
|
|
4260
|
+
suspendedFocusedTooltip = null;
|
|
4261
|
+
}
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
const activeEl = document.activeElement;
|
|
4265
|
+
if (activeEl instanceof HTMLElement && tooltipToResume.#isFocusableOutsideTarget(activeEl)) {
|
|
4266
|
+
tooltipToResume.#clearTrackedFocus();
|
|
4267
|
+
return;
|
|
4268
|
+
}
|
|
4269
|
+
tooltipToResume.#clearFocusSuppression();
|
|
4270
|
+
tooltipToResume.#hasFocus = true;
|
|
4271
|
+
focusedTooltip = tooltipToResume;
|
|
4272
|
+
suspendedFocusedTooltip = null;
|
|
4273
|
+
tooltipToResume.#tooltipState.show();
|
|
4274
|
+
}
|
|
4275
|
+
#isOtherUncontrolledTooltip(tooltip) {
|
|
4276
|
+
return tooltip !== null && tooltip !== this && tooltip.isOpenedControlled !== true;
|
|
4277
|
+
}
|
|
4278
|
+
#claimHoverOwnership() {
|
|
4279
|
+
hoveredTooltip = this;
|
|
4280
|
+
}
|
|
4281
|
+
#releaseHoverOwnership() {
|
|
4282
|
+
if (hoveredTooltip === this) {
|
|
4283
|
+
hoveredTooltip = null;
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
#isPointerWithinHoverSurface() {
|
|
4287
|
+
return this.#$contentWrapper.matches(":hover") || this.#$target.assignedElements().some((el) => el.matches(":hover"));
|
|
4288
|
+
}
|
|
4289
|
+
#finalizeFocusOut() {
|
|
4290
|
+
if (!this.isDomConnected) {
|
|
4291
|
+
return;
|
|
4292
|
+
}
|
|
4293
|
+
const activeEl = document.activeElement;
|
|
4294
|
+
if (activeEl instanceof Node) {
|
|
4295
|
+
if (this.#targetContains(activeEl) || this.shadowRoot?.contains(activeEl) === true) {
|
|
4296
|
+
return;
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
this.#clearTrackedFocus();
|
|
4300
|
+
this.#tooltipState.hide();
|
|
4301
|
+
}
|
|
4302
|
+
#onFocusOut = (e) => {
|
|
4303
|
+
if (this.#isSuspendedByHover) {
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
if (e.relatedTarget instanceof Node) {
|
|
4307
|
+
if (this.#targetContains(e.relatedTarget) || this.shadowRoot?.contains(e.relatedTarget) === true) {
|
|
4308
|
+
return;
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
requestAnimationFrame(() => {
|
|
4312
|
+
this.#finalizeFocusOut();
|
|
4313
|
+
});
|
|
4314
|
+
};
|
|
4315
|
+
#onMouseLeave = () => {
|
|
4316
|
+
requestAnimationFrame(() => {
|
|
4317
|
+
if (!this.isDomConnected) {
|
|
4318
|
+
return;
|
|
4319
|
+
}
|
|
4320
|
+
if (this.#isPointerWithinHoverSurface()) {
|
|
4321
|
+
this.#claimHoverOwnership();
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
this.#releaseHoverOwnership();
|
|
4325
|
+
if (this.#hasFocus) {
|
|
4326
|
+
return;
|
|
4327
|
+
}
|
|
4172
4328
|
this.#tooltipState.hide();
|
|
4329
|
+
});
|
|
4330
|
+
};
|
|
4331
|
+
#targetContains(node) {
|
|
4332
|
+
return this.#$target.assignedElements().some((el) => el.contains(node));
|
|
4333
|
+
}
|
|
4334
|
+
#getTargetElements() {
|
|
4335
|
+
return this.#$target.assignedElements().filter((el) => el instanceof HTMLElement);
|
|
4336
|
+
}
|
|
4337
|
+
#isFocusableOutsideTarget(el) {
|
|
4338
|
+
if (this.#targetContains(el) || this.shadowRoot?.contains(el) === true || this.#isFocusInFloatingLayer(el)) {
|
|
4339
|
+
return false;
|
|
4173
4340
|
}
|
|
4341
|
+
return el.matches(FOCUSABLE_OUTSIDE_TARGET_SELECTOR);
|
|
4342
|
+
}
|
|
4343
|
+
#isFocusInFloatingLayer(el) {
|
|
4344
|
+
return el.tagName === "SINCH-POP" || el.tagName === "SINCH-TOOLTIP";
|
|
4345
|
+
}
|
|
4346
|
+
#clearFocusSuppression() {
|
|
4347
|
+
this.#suppressFocusIn = false;
|
|
4348
|
+
this.#isSuspendedByHover = false;
|
|
4349
|
+
if (this.#suppressedFocusOutArmed) {
|
|
4350
|
+
this.#$target.removeEventListener("focusout", this.#onSuppressedFocusOut);
|
|
4351
|
+
this.#suppressedFocusOutArmed = false;
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
#clearTrackedFocus() {
|
|
4355
|
+
this.#hasFocus = false;
|
|
4356
|
+
if (focusedTooltip === this) {
|
|
4357
|
+
focusedTooltip = null;
|
|
4358
|
+
}
|
|
4359
|
+
if (suspendedFocusedTooltip === this) {
|
|
4360
|
+
suspendedFocusedTooltip = null;
|
|
4361
|
+
}
|
|
4362
|
+
this.#clearFocusSuppression();
|
|
4363
|
+
}
|
|
4364
|
+
#armSuppressedFocusOut() {
|
|
4365
|
+
if (this.#suppressedFocusOutArmed || this.#controller === null) {
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4368
|
+
this.#suppressedFocusOutArmed = true;
|
|
4369
|
+
const options = { signal: this.#controller.signal };
|
|
4370
|
+
this.#$target.addEventListener("focusout", this.#onSuppressedFocusOut, options);
|
|
4371
|
+
}
|
|
4372
|
+
#onSuppressedFocusOut = (e) => {
|
|
4373
|
+
if (e.relatedTarget instanceof Node) {
|
|
4374
|
+
if (this.#targetContains(e.relatedTarget) || this.shadowRoot?.contains(e.relatedTarget) === true) {
|
|
4375
|
+
return;
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
requestAnimationFrame(() => {
|
|
4379
|
+
if (!this.isDomConnected) {
|
|
4380
|
+
return;
|
|
4381
|
+
}
|
|
4382
|
+
if (this.#targetContainsFocus()) {
|
|
4383
|
+
return;
|
|
4384
|
+
}
|
|
4385
|
+
if (this.#isSuspendedByHover) {
|
|
4386
|
+
if (e.relatedTarget instanceof HTMLElement && this.#isFocusInFloatingLayer(e.relatedTarget)) {
|
|
4387
|
+
return;
|
|
4388
|
+
}
|
|
4389
|
+
const activeEl2 = document.activeElement;
|
|
4390
|
+
if (activeEl2 instanceof HTMLElement && this.#isFocusInFloatingLayer(activeEl2)) {
|
|
4391
|
+
return;
|
|
4392
|
+
}
|
|
4393
|
+
if (activeEl2 instanceof HTMLElement && this.#isFocusableOutsideTarget(activeEl2)) {
|
|
4394
|
+
this.#clearTrackedFocus();
|
|
4395
|
+
}
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
const activeEl = document.activeElement;
|
|
4399
|
+
if (activeEl instanceof HTMLElement && this.#isFocusInFloatingLayer(activeEl)) {
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
this.#clearTrackedFocus();
|
|
4403
|
+
});
|
|
4174
4404
|
};
|
|
4175
4405
|
#onScroll = () => {
|
|
4406
|
+
if (this.#hasFocus) {
|
|
4407
|
+
return;
|
|
4408
|
+
}
|
|
4176
4409
|
this.#tooltipState.destroy();
|
|
4177
4410
|
};
|
|
4178
4411
|
// Tooltip begins to wait for SHOW_DELAY on mouseenter
|
|
@@ -4185,6 +4418,7 @@ class Tooltip extends NectaryElement {
|
|
|
4185
4418
|
// SHOW_DELAY ended, tooltip can be shown with animation
|
|
4186
4419
|
#onStateShowEnd = () => {
|
|
4187
4420
|
const revealRequestId = ++this.#revealRequestId;
|
|
4421
|
+
activeTooltip = this;
|
|
4188
4422
|
this.#dispatchShowEvent();
|
|
4189
4423
|
updateBooleanAttribute(this.#$pop, "open", true);
|
|
4190
4424
|
this.#schedulePlacement();
|
|
@@ -4258,12 +4492,30 @@ class Tooltip extends NectaryElement {
|
|
|
4258
4492
|
this.#dispatchHideEvent();
|
|
4259
4493
|
updateBooleanAttribute(this.#$pop, "open", false);
|
|
4260
4494
|
}
|
|
4495
|
+
if (activeTooltip === this) {
|
|
4496
|
+
activeTooltip = null;
|
|
4497
|
+
}
|
|
4498
|
+
if (!this.#isSuspendedByHover) {
|
|
4499
|
+
if (!this.#targetContainsFocus()) {
|
|
4500
|
+
this.#clearTrackedFocus();
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4261
4503
|
this.#resetTipOrientation();
|
|
4262
4504
|
this.#resetContentOffset();
|
|
4263
4505
|
this.#zeroDimensionPlacementRetries = 0;
|
|
4264
4506
|
this.#unsubscribeMouseLeaveEvents();
|
|
4265
4507
|
this.#unsubscribeScroll();
|
|
4508
|
+
if (!this.#isPointerWithinHoverSurface()) {
|
|
4509
|
+
this.#releaseHoverOwnership();
|
|
4510
|
+
}
|
|
4511
|
+
if (!this.#hasFocus) {
|
|
4512
|
+
this.#resumeFocusedTooltip();
|
|
4513
|
+
}
|
|
4266
4514
|
};
|
|
4515
|
+
#targetContainsFocus() {
|
|
4516
|
+
const activeEl = document.activeElement;
|
|
4517
|
+
return activeEl instanceof Node && this.#targetContains(activeEl);
|
|
4518
|
+
}
|
|
4267
4519
|
#resetTipOrientation() {
|
|
4268
4520
|
this.#$tip.style.top = "";
|
|
4269
4521
|
this.#$tip.style.left = "";
|
|
@@ -4410,28 +4662,64 @@ class Tooltip extends NectaryElement {
|
|
|
4410
4662
|
if (!this.isDomConnected || this.#isSubscribed) {
|
|
4411
4663
|
return;
|
|
4412
4664
|
}
|
|
4413
|
-
|
|
4414
|
-
|
|
4665
|
+
const options = { signal: this.#controller.signal };
|
|
4666
|
+
this.#targetElements = this.#getTargetElements();
|
|
4667
|
+
if (this.#targetElements.length === 0) {
|
|
4668
|
+
requestAnimationFrame(() => {
|
|
4669
|
+
if (!this.isDomConnected || this.#isSubscribed || this.text.length === 0) {
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
this.#subscribeMouseEnterEvent();
|
|
4673
|
+
});
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
4676
|
+
this.#targetElements.forEach((el) => {
|
|
4677
|
+
el.addEventListener("mouseenter", this.#onMouseEnter, options);
|
|
4415
4678
|
});
|
|
4679
|
+
this.#$target.addEventListener("focusin", this.#onFocusIn, options);
|
|
4416
4680
|
this.#isSubscribed = true;
|
|
4417
4681
|
}
|
|
4418
4682
|
#unsubscribeMouseEnterEvent() {
|
|
4419
|
-
this
|
|
4683
|
+
this.#targetElements.forEach((el) => {
|
|
4684
|
+
el.removeEventListener("mouseenter", this.#onMouseEnter);
|
|
4685
|
+
});
|
|
4686
|
+
this.#$target.removeEventListener("focusin", this.#onFocusIn);
|
|
4687
|
+
this.#targetElements = [];
|
|
4420
4688
|
this.#isSubscribed = false;
|
|
4421
4689
|
}
|
|
4422
4690
|
#subscribeMouseLeaveEvents() {
|
|
4423
4691
|
const options = { signal: this.#controller.signal };
|
|
4424
|
-
this
|
|
4425
|
-
|
|
4426
|
-
|
|
4692
|
+
this.#targetElements.forEach((el) => {
|
|
4693
|
+
el.addEventListener("mousedown", this.#onMouseDown, options);
|
|
4694
|
+
el.addEventListener("mouseleave", this.#onMouseLeave, options);
|
|
4695
|
+
});
|
|
4696
|
+
this.#$target.addEventListener("focusout", this.#onFocusOut, options);
|
|
4697
|
+
this.#$contentWrapper.addEventListener("mouseenter", this.#onContentMouseEnter, options);
|
|
4427
4698
|
this.#$contentWrapper.addEventListener("mouseleave", this.#onMouseLeave, options);
|
|
4428
4699
|
}
|
|
4429
4700
|
#unsubscribeMouseLeaveEvents() {
|
|
4430
|
-
this
|
|
4431
|
-
|
|
4432
|
-
|
|
4701
|
+
this.#targetElements.forEach((el) => {
|
|
4702
|
+
el.removeEventListener("mousedown", this.#onMouseDown);
|
|
4703
|
+
el.removeEventListener("mouseleave", this.#onMouseLeave);
|
|
4704
|
+
});
|
|
4705
|
+
this.#$target.removeEventListener("focusout", this.#onFocusOut);
|
|
4706
|
+
this.#$contentWrapper.removeEventListener("mouseenter", this.#onContentMouseEnter);
|
|
4433
4707
|
this.#$contentWrapper.removeEventListener("mouseleave", this.#onMouseLeave);
|
|
4434
4708
|
}
|
|
4709
|
+
#onTargetSlotChange = () => {
|
|
4710
|
+
if (!this.isDomConnected || this.text.length === 0) {
|
|
4711
|
+
return;
|
|
4712
|
+
}
|
|
4713
|
+
const isOpen = this.#isOpen();
|
|
4714
|
+
if (this.#isSubscribed) {
|
|
4715
|
+
this.#unsubscribeMouseLeaveEvents();
|
|
4716
|
+
this.#unsubscribeMouseEnterEvent();
|
|
4717
|
+
}
|
|
4718
|
+
this.#subscribeMouseEnterEvent();
|
|
4719
|
+
if (isOpen) {
|
|
4720
|
+
this.#subscribeMouseLeaveEvents();
|
|
4721
|
+
}
|
|
4722
|
+
};
|
|
4435
4723
|
#subscribeScroll() {
|
|
4436
4724
|
window.addEventListener("wheel", this.#onScroll, true);
|
|
4437
4725
|
}
|
|
@@ -12599,7 +12887,7 @@ class SelectButton extends NectaryElement {
|
|
|
12599
12887
|
};
|
|
12600
12888
|
}
|
|
12601
12889
|
defineCustomElement("sinch-select-button", SelectButton);
|
|
12602
|
-
const templateHTML$i = '<style>:host{display:block}#wrapper{display:flex;position:relative;box-sizing:border-box;min-height:40px;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;background-color:var(--sinch-comp-select-menu-color-default-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-default-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-select-menu-size-icon)}#content{flex:1;min-width:0;--sinch-comp-text-font:var(--sinch-comp-select-menu-font-option)}#icon-check{display:none;margin-right:-6px}:host([data-checked]) #icon-check{display:block}:host([data-selected])>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-selected)}:host(:hover)>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-hover)}:host([disabled])>#wrapper{cursor:initial;pointer-events:none;background-color:var(--sinch-comp-select-menu-color-disabled-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-disabled-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-disabled-icon-initial)}::slotted([slot=icon]){margin-left:-6px}::slotted([slot=content]){pointer-events:none;flex:1}</style><div id="wrapper"><slot name="icon"></slot><slot name="content"></slot><sinch-text id="content" type="m" ellipsis></sinch-text><sinch-icon icons-version="2" name="fa-check" id="icon-check"></sinch-icon></div>';
|
|
12890
|
+
const templateHTML$i = '<style>:host{display:block}#wrapper{display:flex;position:relative;box-sizing:border-box;min-height:40px;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;background-color:var(--sinch-comp-select-menu-color-default-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-default-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-select-menu-size-icon)}#content{flex:1;min-width:0;--sinch-comp-text-font:var(--sinch-comp-select-menu-font-option)}#icon-check{display:none;margin-right:-6px}:host([data-checked]:not([action])) #icon-check{display:block}:host([data-selected])>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-selected)}:host(:hover)>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-hover)}:host([disabled])>#wrapper{cursor:initial;pointer-events:none;background-color:var(--sinch-comp-select-menu-color-disabled-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-disabled-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-disabled-icon-initial)}::slotted([slot=icon]){margin-left:-6px}::slotted([slot=content]){pointer-events:none;flex:1}</style><div id="wrapper"><slot name="icon"></slot><slot name="content"></slot><sinch-text id="content" type="m" ellipsis></sinch-text><sinch-icon icons-version="2" name="fa-check" id="icon-check"></sinch-icon></div>';
|
|
12603
12891
|
const template$i = document.createElement("template");
|
|
12604
12892
|
template$i.innerHTML = templateHTML$i;
|
|
12605
12893
|
class SelectMenuOption extends NectaryElement {
|
|
@@ -12665,6 +12953,12 @@ class SelectMenuOption extends NectaryElement {
|
|
|
12665
12953
|
get disabled() {
|
|
12666
12954
|
return getBooleanAttribute(this, "disabled");
|
|
12667
12955
|
}
|
|
12956
|
+
set action(isAction) {
|
|
12957
|
+
updateBooleanAttribute(this, "action", isAction);
|
|
12958
|
+
}
|
|
12959
|
+
get action() {
|
|
12960
|
+
return getBooleanAttribute(this, "action");
|
|
12961
|
+
}
|
|
12668
12962
|
matchesSearch(searchValue) {
|
|
12669
12963
|
return this.text.toLowerCase().includes(searchValue.toLowerCase());
|
|
12670
12964
|
}
|
|
@@ -12736,6 +13030,7 @@ class SelectMenu extends NectaryElement {
|
|
|
12736
13030
|
options
|
|
12737
13031
|
);
|
|
12738
13032
|
this.addEventListener("-change", this.#onChangeReactHandler, options);
|
|
13033
|
+
this.addEventListener("-action", this.#onActionReactHandler, options);
|
|
12739
13034
|
subscribeContext(
|
|
12740
13035
|
this,
|
|
12741
13036
|
"keydown",
|
|
@@ -12894,7 +13189,7 @@ class SelectMenu extends NectaryElement {
|
|
|
12894
13189
|
this.focus();
|
|
12895
13190
|
if (!isTargetEqual(e, this.#$listbox) && !getBooleanAttribute($elem, "disabled")) {
|
|
12896
13191
|
this.#selectOption($elem);
|
|
12897
|
-
this.#
|
|
13192
|
+
this.#handleDispatch($elem);
|
|
12898
13193
|
}
|
|
12899
13194
|
};
|
|
12900
13195
|
#onSearchChange = (e) => {
|
|
@@ -12959,7 +13254,7 @@ class SelectMenu extends NectaryElement {
|
|
|
12959
13254
|
const $option = this.#findSelectedOption();
|
|
12960
13255
|
if ($option !== null) {
|
|
12961
13256
|
e.preventDefault();
|
|
12962
|
-
this.#
|
|
13257
|
+
this.#handleDispatch($option);
|
|
12963
13258
|
}
|
|
12964
13259
|
break;
|
|
12965
13260
|
}
|
|
@@ -12975,6 +13270,13 @@ class SelectMenu extends NectaryElement {
|
|
|
12975
13270
|
}
|
|
12976
13271
|
}
|
|
12977
13272
|
}
|
|
13273
|
+
#handleDispatch = (option) => {
|
|
13274
|
+
if (getBooleanAttribute(option, "action")) {
|
|
13275
|
+
this.#dispatchActionEvent(option);
|
|
13276
|
+
} else {
|
|
13277
|
+
this.#dispatchChangeEvent(option);
|
|
13278
|
+
}
|
|
13279
|
+
};
|
|
12978
13280
|
#onOptionSlotChange = () => {
|
|
12979
13281
|
const searchable = this.searchable;
|
|
12980
13282
|
const options = this.#getOptionElements();
|
|
@@ -12990,7 +13292,7 @@ class SelectMenu extends NectaryElement {
|
|
|
12990
13292
|
if (this.multiple) {
|
|
12991
13293
|
const values = unpackCsv(csv);
|
|
12992
13294
|
for (const $option of this.#getOptionElements()) {
|
|
12993
|
-
const isChecked = !getBooleanAttribute($option, "disabled") && values.includes(getAttribute($option, "value", ""));
|
|
13295
|
+
const isChecked = !getBooleanAttribute($option, "disabled") && !getBooleanAttribute($option, "action") && values.includes(getAttribute($option, "value", ""));
|
|
12994
13296
|
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
12995
13297
|
}
|
|
12996
13298
|
const formData = new FormData();
|
|
@@ -13001,7 +13303,7 @@ class SelectMenu extends NectaryElement {
|
|
|
13001
13303
|
} else {
|
|
13002
13304
|
const value = getFirstCsvValue(csv);
|
|
13003
13305
|
for (const $option of this.#getOptionElements()) {
|
|
13004
|
-
const isChecked = !getBooleanAttribute($option, "disabled") && value === getAttribute($option, "value", "");
|
|
13306
|
+
const isChecked = !getBooleanAttribute($option, "disabled") && !getBooleanAttribute($option, "action") && value === getAttribute($option, "value", "");
|
|
13005
13307
|
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
13006
13308
|
}
|
|
13007
13309
|
setFormValue(this.#internals, value ?? "");
|
|
@@ -13090,7 +13392,7 @@ class SelectMenu extends NectaryElement {
|
|
|
13090
13392
|
const elements = this.#getOptionElements();
|
|
13091
13393
|
const value = this.multiple ? getFirstCsvValue(this.value) : this.value;
|
|
13092
13394
|
for (const $el of elements) {
|
|
13093
|
-
if (!getBooleanAttribute($el, "disabled") && getAttribute($el, "value") === value) {
|
|
13395
|
+
if (!getBooleanAttribute($el, "disabled") && !getBooleanAttribute($el, "action") && getAttribute($el, "value") === value) {
|
|
13094
13396
|
return $el;
|
|
13095
13397
|
}
|
|
13096
13398
|
}
|
|
@@ -13108,10 +13410,17 @@ class SelectMenu extends NectaryElement {
|
|
|
13108
13410
|
) : value;
|
|
13109
13411
|
this.dispatchEvent(new CustomEvent("-change", { detail: result }));
|
|
13110
13412
|
}
|
|
13413
|
+
#dispatchActionEvent($opt) {
|
|
13414
|
+
this.dispatchEvent(new CustomEvent("-action", { detail: $opt.value }));
|
|
13415
|
+
}
|
|
13111
13416
|
#onChangeReactHandler = (e) => {
|
|
13112
13417
|
getReactEventHandler(this, "on-change")?.(e);
|
|
13113
13418
|
getReactEventHandler(this, "onChange")?.(e);
|
|
13114
13419
|
};
|
|
13420
|
+
#onActionReactHandler = (e) => {
|
|
13421
|
+
getReactEventHandler(this, "on-action")?.(e);
|
|
13422
|
+
getReactEventHandler(this, "onAction")?.(e);
|
|
13423
|
+
};
|
|
13115
13424
|
#onSearchChangeReactHandler = (e) => {
|
|
13116
13425
|
getReactEventHandler(this, "on-search-change")?.(e);
|
|
13117
13426
|
getReactEventHandler(this, "onSearchChange")?.(e);
|
package/package.json
CHANGED
package/pop/index.d.ts
CHANGED
|
@@ -27,5 +27,6 @@ export declare class Pop extends NectaryElement {
|
|
|
27
27
|
get footprintRect(): TRect;
|
|
28
28
|
get popoverRect(): TRect;
|
|
29
29
|
get shouldCloseOnBackdropClick(): boolean;
|
|
30
|
+
get shouldRestoreFocusOnClose(): boolean;
|
|
30
31
|
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
31
32
|
}
|
package/pop/index.js
CHANGED
|
@@ -128,6 +128,9 @@ class Pop extends NectaryElement {
|
|
|
128
128
|
get shouldCloseOnBackdropClick() {
|
|
129
129
|
return !getBooleanAttribute(this, "disable-backdrop-close");
|
|
130
130
|
}
|
|
131
|
+
get shouldRestoreFocusOnClose() {
|
|
132
|
+
return !getBooleanAttribute(this, "disable-focus-restore");
|
|
133
|
+
}
|
|
131
134
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
132
135
|
if (isAttrEqual(oldVal, newVal)) {
|
|
133
136
|
return;
|
|
@@ -313,7 +316,7 @@ class Pop extends NectaryElement {
|
|
|
313
316
|
if (isNonModal && !effectiveAllowScroll) {
|
|
314
317
|
this.#restoreTransferredTarget();
|
|
315
318
|
}
|
|
316
|
-
if (this.#targetActiveElement !== null) {
|
|
319
|
+
if (this.shouldRestoreFocusOnClose && this.#targetActiveElement !== null) {
|
|
317
320
|
if (!isElementFocused(this.#targetActiveElement)) {
|
|
318
321
|
this.#$targetSlot.addEventListener("focus", this.#stopEventPropagation, true);
|
|
319
322
|
this.#targetActiveElement.focus({ preventScroll: true });
|
|
@@ -328,9 +331,9 @@ class Pop extends NectaryElement {
|
|
|
328
331
|
}
|
|
329
332
|
});
|
|
330
333
|
}
|
|
331
|
-
this.#targetActiveElement = null;
|
|
332
334
|
}
|
|
333
335
|
}
|
|
336
|
+
this.#targetActiveElement = null;
|
|
334
337
|
if (!effectiveAllowScroll) {
|
|
335
338
|
enableOverscroll();
|
|
336
339
|
} else {
|
package/pop/types.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export type TSinchPopOrientation = 'top-left' | 'top-right' | 'bottom-left' | 'b
|
|
|
3
3
|
export type TSinchPopProps = {
|
|
4
4
|
/** Allow scrolling of the page when pop is open */
|
|
5
5
|
'allow-scroll'?: boolean;
|
|
6
|
+
/** Skip restoring the previously focused target when the pop closes */
|
|
7
|
+
'disable-focus-restore'?: boolean;
|
|
6
8
|
/** Open/close state */
|
|
7
9
|
open: boolean;
|
|
8
10
|
/** Orientation, where it *points to* from origin */
|
package/select-menu/index.js
CHANGED
|
@@ -71,6 +71,7 @@ class SelectMenu extends NectaryElement {
|
|
|
71
71
|
options
|
|
72
72
|
);
|
|
73
73
|
this.addEventListener("-change", this.#onChangeReactHandler, options);
|
|
74
|
+
this.addEventListener("-action", this.#onActionReactHandler, options);
|
|
74
75
|
subscribeContext(
|
|
75
76
|
this,
|
|
76
77
|
"keydown",
|
|
@@ -229,7 +230,7 @@ class SelectMenu extends NectaryElement {
|
|
|
229
230
|
this.focus();
|
|
230
231
|
if (!isTargetEqual(e, this.#$listbox) && !getBooleanAttribute($elem, "disabled")) {
|
|
231
232
|
this.#selectOption($elem);
|
|
232
|
-
this.#
|
|
233
|
+
this.#handleDispatch($elem);
|
|
233
234
|
}
|
|
234
235
|
};
|
|
235
236
|
#onSearchChange = (e) => {
|
|
@@ -294,7 +295,7 @@ class SelectMenu extends NectaryElement {
|
|
|
294
295
|
const $option = this.#findSelectedOption();
|
|
295
296
|
if ($option !== null) {
|
|
296
297
|
e.preventDefault();
|
|
297
|
-
this.#
|
|
298
|
+
this.#handleDispatch($option);
|
|
298
299
|
}
|
|
299
300
|
break;
|
|
300
301
|
}
|
|
@@ -310,6 +311,13 @@ class SelectMenu extends NectaryElement {
|
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
}
|
|
314
|
+
#handleDispatch = (option) => {
|
|
315
|
+
if (getBooleanAttribute(option, "action")) {
|
|
316
|
+
this.#dispatchActionEvent(option);
|
|
317
|
+
} else {
|
|
318
|
+
this.#dispatchChangeEvent(option);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
313
321
|
#onOptionSlotChange = () => {
|
|
314
322
|
const searchable = this.searchable;
|
|
315
323
|
const options = this.#getOptionElements();
|
|
@@ -325,7 +333,7 @@ class SelectMenu extends NectaryElement {
|
|
|
325
333
|
if (this.multiple) {
|
|
326
334
|
const values = unpackCsv(csv);
|
|
327
335
|
for (const $option of this.#getOptionElements()) {
|
|
328
|
-
const isChecked = !getBooleanAttribute($option, "disabled") && values.includes(getAttribute($option, "value", ""));
|
|
336
|
+
const isChecked = !getBooleanAttribute($option, "disabled") && !getBooleanAttribute($option, "action") && values.includes(getAttribute($option, "value", ""));
|
|
329
337
|
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
330
338
|
}
|
|
331
339
|
const formData = new FormData();
|
|
@@ -336,7 +344,7 @@ class SelectMenu extends NectaryElement {
|
|
|
336
344
|
} else {
|
|
337
345
|
const value = getFirstCsvValue(csv);
|
|
338
346
|
for (const $option of this.#getOptionElements()) {
|
|
339
|
-
const isChecked = !getBooleanAttribute($option, "disabled") && value === getAttribute($option, "value", "");
|
|
347
|
+
const isChecked = !getBooleanAttribute($option, "disabled") && !getBooleanAttribute($option, "action") && value === getAttribute($option, "value", "");
|
|
340
348
|
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
341
349
|
}
|
|
342
350
|
setFormValue(this.#internals, value ?? "");
|
|
@@ -425,7 +433,7 @@ class SelectMenu extends NectaryElement {
|
|
|
425
433
|
const elements = this.#getOptionElements();
|
|
426
434
|
const value = this.multiple ? getFirstCsvValue(this.value) : this.value;
|
|
427
435
|
for (const $el of elements) {
|
|
428
|
-
if (!getBooleanAttribute($el, "disabled") && getAttribute($el, "value") === value) {
|
|
436
|
+
if (!getBooleanAttribute($el, "disabled") && !getBooleanAttribute($el, "action") && getAttribute($el, "value") === value) {
|
|
429
437
|
return $el;
|
|
430
438
|
}
|
|
431
439
|
}
|
|
@@ -443,10 +451,17 @@ class SelectMenu extends NectaryElement {
|
|
|
443
451
|
) : value;
|
|
444
452
|
this.dispatchEvent(new CustomEvent("-change", { detail: result }));
|
|
445
453
|
}
|
|
454
|
+
#dispatchActionEvent($opt) {
|
|
455
|
+
this.dispatchEvent(new CustomEvent("-action", { detail: $opt.value }));
|
|
456
|
+
}
|
|
446
457
|
#onChangeReactHandler = (e) => {
|
|
447
458
|
getReactEventHandler(this, "on-change")?.(e);
|
|
448
459
|
getReactEventHandler(this, "onChange")?.(e);
|
|
449
460
|
};
|
|
461
|
+
#onActionReactHandler = (e) => {
|
|
462
|
+
getReactEventHandler(this, "on-action")?.(e);
|
|
463
|
+
getReactEventHandler(this, "onAction")?.(e);
|
|
464
|
+
};
|
|
450
465
|
#onSearchChangeReactHandler = (e) => {
|
|
451
466
|
getReactEventHandler(this, "on-search-change")?.(e);
|
|
452
467
|
getReactEventHandler(this, "onSearchChange")?.(e);
|
package/select-menu/types.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type TSinchSelectMenuEvents = {
|
|
|
24
24
|
'-search-change'?: (e: CustomEvent<string>) => void;
|
|
25
25
|
/** Change value handler */
|
|
26
26
|
'-change'?: (e: CustomEvent<string>) => void;
|
|
27
|
+
/** Action option activated handler — detail is the action option's value */
|
|
28
|
+
'-action'?: (e: CustomEvent<string>) => void;
|
|
27
29
|
};
|
|
28
30
|
export type TSinchSelectMenuStyle = {
|
|
29
31
|
'--sinch-comp-select-menu-color-default-title-initial'?: string;
|
|
@@ -14,5 +14,7 @@ export declare class SelectMenuOption extends NectaryElement {
|
|
|
14
14
|
get text(): string;
|
|
15
15
|
set disabled(isDisabled: boolean);
|
|
16
16
|
get disabled(): boolean;
|
|
17
|
+
set action(isAction: boolean);
|
|
18
|
+
get action(): boolean;
|
|
17
19
|
matchesSearch(searchValue: string): boolean;
|
|
18
20
|
}
|
|
@@ -2,7 +2,7 @@ import "../icon/index.js";
|
|
|
2
2
|
import "../text/index.js";
|
|
3
3
|
import { isAttrEqual, updateBooleanAttribute, isAttrTrue, updateExplicitBooleanAttribute, updateAttribute, getAttribute, getBooleanAttribute } from "../utils/dom.js";
|
|
4
4
|
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
5
|
-
const templateHTML = '<style>:host{display:block}#wrapper{display:flex;position:relative;box-sizing:border-box;min-height:40px;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;background-color:var(--sinch-comp-select-menu-color-default-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-default-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-select-menu-size-icon)}#content{flex:1;min-width:0;--sinch-comp-text-font:var(--sinch-comp-select-menu-font-option)}#icon-check{display:none;margin-right:-6px}:host([data-checked]) #icon-check{display:block}:host([data-selected])>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-selected)}:host(:hover)>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-hover)}:host([disabled])>#wrapper{cursor:initial;pointer-events:none;background-color:var(--sinch-comp-select-menu-color-disabled-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-disabled-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-disabled-icon-initial)}::slotted([slot=icon]){margin-left:-6px}::slotted([slot=content]){pointer-events:none;flex:1}</style><div id="wrapper"><slot name="icon"></slot><slot name="content"></slot><sinch-text id="content" type="m" ellipsis></sinch-text><sinch-icon icons-version="2" name="fa-check" id="icon-check"></sinch-icon></div>';
|
|
5
|
+
const templateHTML = '<style>:host{display:block}#wrapper{display:flex;position:relative;box-sizing:border-box;min-height:40px;padding:8px 16px;align-items:center;gap:10px;user-select:none;cursor:pointer;background-color:var(--sinch-comp-select-menu-color-default-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-default-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-select-menu-size-icon)}#content{flex:1;min-width:0;--sinch-comp-text-font:var(--sinch-comp-select-menu-font-option)}#icon-check{display:none;margin-right:-6px}:host([data-checked]:not([action])) #icon-check{display:block}:host([data-selected])>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-selected)}:host(:hover)>#wrapper{background-color:var(--sinch-comp-select-menu-color-default-background-hover)}:host([disabled])>#wrapper{cursor:initial;pointer-events:none;background-color:var(--sinch-comp-select-menu-color-disabled-background-initial);--sinch-global-color-text:var(--sinch-comp-select-menu-color-disabled-option-initial);--sinch-global-color-icon:var(--sinch-comp-select-menu-color-disabled-icon-initial)}::slotted([slot=icon]){margin-left:-6px}::slotted([slot=content]){pointer-events:none;flex:1}</style><div id="wrapper"><slot name="icon"></slot><slot name="content"></slot><sinch-text id="content" type="m" ellipsis></sinch-text><sinch-icon icons-version="2" name="fa-check" id="icon-check"></sinch-icon></div>';
|
|
6
6
|
const template = document.createElement("template");
|
|
7
7
|
template.innerHTML = templateHTML;
|
|
8
8
|
class SelectMenuOption extends NectaryElement {
|
|
@@ -68,6 +68,12 @@ class SelectMenuOption extends NectaryElement {
|
|
|
68
68
|
get disabled() {
|
|
69
69
|
return getBooleanAttribute(this, "disabled");
|
|
70
70
|
}
|
|
71
|
+
set action(isAction) {
|
|
72
|
+
updateBooleanAttribute(this, "action", isAction);
|
|
73
|
+
}
|
|
74
|
+
get action() {
|
|
75
|
+
return getBooleanAttribute(this, "action");
|
|
76
|
+
}
|
|
71
77
|
matchesSearch(searchValue) {
|
|
72
78
|
return this.text.toLowerCase().includes(searchValue.toLowerCase());
|
|
73
79
|
}
|
|
@@ -6,6 +6,8 @@ export type TSinchSelectMenuOptionProps = {
|
|
|
6
6
|
text: string;
|
|
7
7
|
/** Disabled state */
|
|
8
8
|
disabled?: boolean;
|
|
9
|
+
/** Marks this option as an action — activating it triggers an action event instead of changing the select value */
|
|
10
|
+
action?: boolean;
|
|
9
11
|
/** Label that is used for a11y */
|
|
10
12
|
'aria-label': string;
|
|
11
13
|
};
|
package/tooltip/index.js
CHANGED
|
@@ -13,10 +13,15 @@ const SHOW_DELAY_SLOW = 1e3;
|
|
|
13
13
|
const SHOW_DELAY_FAST = 250;
|
|
14
14
|
const HIDE_DELAY = 0;
|
|
15
15
|
const ANIMATION_DURATION = 100;
|
|
16
|
+
const FOCUSABLE_OUTSIDE_TARGET_SELECTOR = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"]), [contenteditable=""], [contenteditable="true"]';
|
|
16
17
|
const OVERLAP_TOLERANCE = 1;
|
|
17
18
|
const MAX_ZERO_DIMENSION_PLACEMENT_RETRIES = 8;
|
|
18
19
|
const MIN_FIRST_REVEAL_STABILITY_FRAMES = 3;
|
|
19
20
|
const MAX_FIRST_REVEAL_STABILITY_FRAMES = 6;
|
|
21
|
+
let activeTooltip = null;
|
|
22
|
+
let focusedTooltip = null;
|
|
23
|
+
let hoveredTooltip = null;
|
|
24
|
+
let suspendedFocusedTooltip = null;
|
|
20
25
|
const template = document.createElement("template");
|
|
21
26
|
template.innerHTML = templateHTML;
|
|
22
27
|
class Tooltip extends NectaryElement {
|
|
@@ -26,10 +31,15 @@ class Tooltip extends NectaryElement {
|
|
|
26
31
|
#$contentWrapper;
|
|
27
32
|
#$tip;
|
|
28
33
|
#$target;
|
|
34
|
+
#targetElements = [];
|
|
29
35
|
#resizeObserver = null;
|
|
30
36
|
#tooltipState;
|
|
31
37
|
#animation = null;
|
|
32
38
|
#shouldReduceMotion = false;
|
|
39
|
+
#hasFocus = false;
|
|
40
|
+
#suppressFocusIn = false;
|
|
41
|
+
#suppressedFocusOutArmed = false;
|
|
42
|
+
#isSuspendedByHover = false;
|
|
33
43
|
#isSubscribed = false;
|
|
34
44
|
#controller;
|
|
35
45
|
#placementScheduled = false;
|
|
@@ -66,6 +76,7 @@ class Tooltip extends NectaryElement {
|
|
|
66
76
|
};
|
|
67
77
|
this.setAttribute("role", "tooltip");
|
|
68
78
|
this.#$pop.addEventListener("-close", this.#onPopClose, options);
|
|
79
|
+
this.#$target.addEventListener("slotchange", this.#onTargetSlotChange, options);
|
|
69
80
|
this.addEventListener("-show", this.#onShowReactHandler, options);
|
|
70
81
|
this.addEventListener("-hide", this.#onHideReactHandler, options);
|
|
71
82
|
this.#resizeObserver = new ResizeObserver(() => {
|
|
@@ -74,10 +85,23 @@ class Tooltip extends NectaryElement {
|
|
|
74
85
|
this.#resizeObserver.observe(this.#$content);
|
|
75
86
|
updateAttribute(this.#$pop, "orientation", getPopOrientation(this.orientation));
|
|
76
87
|
updateBooleanAttribute(this.#$pop, "hide-outside-viewport", !this.showOutsideViewport);
|
|
88
|
+
updateBooleanAttribute(this.#$pop, "disable-focus-restore", true);
|
|
77
89
|
this.#updateText();
|
|
78
90
|
}
|
|
79
91
|
disconnectedCallback() {
|
|
80
92
|
super.disconnectedCallback();
|
|
93
|
+
if (activeTooltip === this) {
|
|
94
|
+
activeTooltip = null;
|
|
95
|
+
}
|
|
96
|
+
if (focusedTooltip === this) {
|
|
97
|
+
focusedTooltip = null;
|
|
98
|
+
}
|
|
99
|
+
if (hoveredTooltip === this) {
|
|
100
|
+
hoveredTooltip = null;
|
|
101
|
+
}
|
|
102
|
+
if (suspendedFocusedTooltip === this) {
|
|
103
|
+
suspendedFocusedTooltip = null;
|
|
104
|
+
}
|
|
81
105
|
this.#tooltipState.destroy();
|
|
82
106
|
this.#controller.abort();
|
|
83
107
|
this.#controller = null;
|
|
@@ -195,14 +219,217 @@ class Tooltip extends NectaryElement {
|
|
|
195
219
|
this.#tooltipState.destroy();
|
|
196
220
|
};
|
|
197
221
|
#onMouseEnter = () => {
|
|
222
|
+
this.#claimHoverOwnership();
|
|
223
|
+
this.#suspendFocusedTooltip();
|
|
224
|
+
this.#closeActiveTooltip();
|
|
225
|
+
this.#tooltipState.show();
|
|
226
|
+
};
|
|
227
|
+
#onContentMouseEnter = () => {
|
|
228
|
+
this.#claimHoverOwnership();
|
|
229
|
+
if (this.#hasFocus) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.#suspendFocusedTooltip();
|
|
233
|
+
this.#closeActiveTooltip();
|
|
198
234
|
this.#tooltipState.show();
|
|
199
235
|
};
|
|
200
|
-
#
|
|
201
|
-
if (
|
|
236
|
+
#onFocusIn = () => {
|
|
237
|
+
if (this.#suppressFocusIn) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
this.#closeFocusedTooltip();
|
|
241
|
+
this.#closeActiveTooltip();
|
|
242
|
+
this.#hasFocus = true;
|
|
243
|
+
focusedTooltip = this;
|
|
244
|
+
this.#tooltipState.show();
|
|
245
|
+
};
|
|
246
|
+
#closeFocusedTooltip() {
|
|
247
|
+
if (!this.#isOtherUncontrolledTooltip(focusedTooltip)) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const previousFocusedTooltip = focusedTooltip;
|
|
251
|
+
previousFocusedTooltip.#clearTrackedFocus();
|
|
252
|
+
previousFocusedTooltip.#tooltipState.destroy();
|
|
253
|
+
}
|
|
254
|
+
#closeActiveTooltip() {
|
|
255
|
+
if (this.#isOtherUncontrolledTooltip(activeTooltip) && !activeTooltip.#hasFocus) {
|
|
256
|
+
activeTooltip.#tooltipState.destroy();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
#suspendFocusedTooltip() {
|
|
260
|
+
if (this.#isOtherUncontrolledTooltip(focusedTooltip)) {
|
|
261
|
+
suspendedFocusedTooltip = focusedTooltip;
|
|
262
|
+
focusedTooltip.#suppressFocusIn = true;
|
|
263
|
+
focusedTooltip.#isSuspendedByHover = true;
|
|
264
|
+
focusedTooltip.#armSuppressedFocusOut();
|
|
265
|
+
if (!focusedTooltip.#tooltipState.isInHideState) {
|
|
266
|
+
focusedTooltip.#tooltipState.destroy();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
#resumeFocusedTooltip() {
|
|
271
|
+
const tooltipToResume = suspendedFocusedTooltip;
|
|
272
|
+
if (tooltipToResume === null || tooltipToResume === this) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (hoveredTooltip !== null) {
|
|
276
|
+
if (hoveredTooltip === this && !this.#isPointerWithinHoverSurface()) {
|
|
277
|
+
this.#releaseHoverOwnership();
|
|
278
|
+
} else {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!tooltipToResume.#isSuspendedByHover) {
|
|
283
|
+
if (suspendedFocusedTooltip === tooltipToResume) {
|
|
284
|
+
suspendedFocusedTooltip = null;
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const activeEl = document.activeElement;
|
|
289
|
+
if (activeEl instanceof HTMLElement && tooltipToResume.#isFocusableOutsideTarget(activeEl)) {
|
|
290
|
+
tooltipToResume.#clearTrackedFocus();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
tooltipToResume.#clearFocusSuppression();
|
|
294
|
+
tooltipToResume.#hasFocus = true;
|
|
295
|
+
focusedTooltip = tooltipToResume;
|
|
296
|
+
suspendedFocusedTooltip = null;
|
|
297
|
+
tooltipToResume.#tooltipState.show();
|
|
298
|
+
}
|
|
299
|
+
#isOtherUncontrolledTooltip(tooltip) {
|
|
300
|
+
return tooltip !== null && tooltip !== this && tooltip.isOpenedControlled !== true;
|
|
301
|
+
}
|
|
302
|
+
#claimHoverOwnership() {
|
|
303
|
+
hoveredTooltip = this;
|
|
304
|
+
}
|
|
305
|
+
#releaseHoverOwnership() {
|
|
306
|
+
if (hoveredTooltip === this) {
|
|
307
|
+
hoveredTooltip = null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
#isPointerWithinHoverSurface() {
|
|
311
|
+
return this.#$contentWrapper.matches(":hover") || this.#$target.assignedElements().some((el) => el.matches(":hover"));
|
|
312
|
+
}
|
|
313
|
+
#finalizeFocusOut() {
|
|
314
|
+
if (!this.isDomConnected) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const activeEl = document.activeElement;
|
|
318
|
+
if (activeEl instanceof Node) {
|
|
319
|
+
if (this.#targetContains(activeEl) || this.shadowRoot?.contains(activeEl) === true) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
this.#clearTrackedFocus();
|
|
324
|
+
this.#tooltipState.hide();
|
|
325
|
+
}
|
|
326
|
+
#onFocusOut = (e) => {
|
|
327
|
+
if (this.#isSuspendedByHover) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (e.relatedTarget instanceof Node) {
|
|
331
|
+
if (this.#targetContains(e.relatedTarget) || this.shadowRoot?.contains(e.relatedTarget) === true) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
requestAnimationFrame(() => {
|
|
336
|
+
this.#finalizeFocusOut();
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
#onMouseLeave = () => {
|
|
340
|
+
requestAnimationFrame(() => {
|
|
341
|
+
if (!this.isDomConnected) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (this.#isPointerWithinHoverSurface()) {
|
|
345
|
+
this.#claimHoverOwnership();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
this.#releaseHoverOwnership();
|
|
349
|
+
if (this.#hasFocus) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
202
352
|
this.#tooltipState.hide();
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
#targetContains(node) {
|
|
356
|
+
return this.#$target.assignedElements().some((el) => el.contains(node));
|
|
357
|
+
}
|
|
358
|
+
#getTargetElements() {
|
|
359
|
+
return this.#$target.assignedElements().filter((el) => el instanceof HTMLElement);
|
|
360
|
+
}
|
|
361
|
+
#isFocusableOutsideTarget(el) {
|
|
362
|
+
if (this.#targetContains(el) || this.shadowRoot?.contains(el) === true || this.#isFocusInFloatingLayer(el)) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
return el.matches(FOCUSABLE_OUTSIDE_TARGET_SELECTOR);
|
|
366
|
+
}
|
|
367
|
+
#isFocusInFloatingLayer(el) {
|
|
368
|
+
return el.tagName === "SINCH-POP" || el.tagName === "SINCH-TOOLTIP";
|
|
369
|
+
}
|
|
370
|
+
#clearFocusSuppression() {
|
|
371
|
+
this.#suppressFocusIn = false;
|
|
372
|
+
this.#isSuspendedByHover = false;
|
|
373
|
+
if (this.#suppressedFocusOutArmed) {
|
|
374
|
+
this.#$target.removeEventListener("focusout", this.#onSuppressedFocusOut);
|
|
375
|
+
this.#suppressedFocusOutArmed = false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
#clearTrackedFocus() {
|
|
379
|
+
this.#hasFocus = false;
|
|
380
|
+
if (focusedTooltip === this) {
|
|
381
|
+
focusedTooltip = null;
|
|
382
|
+
}
|
|
383
|
+
if (suspendedFocusedTooltip === this) {
|
|
384
|
+
suspendedFocusedTooltip = null;
|
|
385
|
+
}
|
|
386
|
+
this.#clearFocusSuppression();
|
|
387
|
+
}
|
|
388
|
+
#armSuppressedFocusOut() {
|
|
389
|
+
if (this.#suppressedFocusOutArmed || this.#controller === null) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
this.#suppressedFocusOutArmed = true;
|
|
393
|
+
const options = { signal: this.#controller.signal };
|
|
394
|
+
this.#$target.addEventListener("focusout", this.#onSuppressedFocusOut, options);
|
|
395
|
+
}
|
|
396
|
+
#onSuppressedFocusOut = (e) => {
|
|
397
|
+
if (e.relatedTarget instanceof Node) {
|
|
398
|
+
if (this.#targetContains(e.relatedTarget) || this.shadowRoot?.contains(e.relatedTarget) === true) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
203
401
|
}
|
|
402
|
+
requestAnimationFrame(() => {
|
|
403
|
+
if (!this.isDomConnected) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (this.#targetContainsFocus()) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (this.#isSuspendedByHover) {
|
|
410
|
+
if (e.relatedTarget instanceof HTMLElement && this.#isFocusInFloatingLayer(e.relatedTarget)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const activeEl2 = document.activeElement;
|
|
414
|
+
if (activeEl2 instanceof HTMLElement && this.#isFocusInFloatingLayer(activeEl2)) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (activeEl2 instanceof HTMLElement && this.#isFocusableOutsideTarget(activeEl2)) {
|
|
418
|
+
this.#clearTrackedFocus();
|
|
419
|
+
}
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const activeEl = document.activeElement;
|
|
423
|
+
if (activeEl instanceof HTMLElement && this.#isFocusInFloatingLayer(activeEl)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this.#clearTrackedFocus();
|
|
427
|
+
});
|
|
204
428
|
};
|
|
205
429
|
#onScroll = () => {
|
|
430
|
+
if (this.#hasFocus) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
206
433
|
this.#tooltipState.destroy();
|
|
207
434
|
};
|
|
208
435
|
// Tooltip begins to wait for SHOW_DELAY on mouseenter
|
|
@@ -215,6 +442,7 @@ class Tooltip extends NectaryElement {
|
|
|
215
442
|
// SHOW_DELAY ended, tooltip can be shown with animation
|
|
216
443
|
#onStateShowEnd = () => {
|
|
217
444
|
const revealRequestId = ++this.#revealRequestId;
|
|
445
|
+
activeTooltip = this;
|
|
218
446
|
this.#dispatchShowEvent();
|
|
219
447
|
updateBooleanAttribute(this.#$pop, "open", true);
|
|
220
448
|
this.#schedulePlacement();
|
|
@@ -288,12 +516,30 @@ class Tooltip extends NectaryElement {
|
|
|
288
516
|
this.#dispatchHideEvent();
|
|
289
517
|
updateBooleanAttribute(this.#$pop, "open", false);
|
|
290
518
|
}
|
|
519
|
+
if (activeTooltip === this) {
|
|
520
|
+
activeTooltip = null;
|
|
521
|
+
}
|
|
522
|
+
if (!this.#isSuspendedByHover) {
|
|
523
|
+
if (!this.#targetContainsFocus()) {
|
|
524
|
+
this.#clearTrackedFocus();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
291
527
|
this.#resetTipOrientation();
|
|
292
528
|
this.#resetContentOffset();
|
|
293
529
|
this.#zeroDimensionPlacementRetries = 0;
|
|
294
530
|
this.#unsubscribeMouseLeaveEvents();
|
|
295
531
|
this.#unsubscribeScroll();
|
|
532
|
+
if (!this.#isPointerWithinHoverSurface()) {
|
|
533
|
+
this.#releaseHoverOwnership();
|
|
534
|
+
}
|
|
535
|
+
if (!this.#hasFocus) {
|
|
536
|
+
this.#resumeFocusedTooltip();
|
|
537
|
+
}
|
|
296
538
|
};
|
|
539
|
+
#targetContainsFocus() {
|
|
540
|
+
const activeEl = document.activeElement;
|
|
541
|
+
return activeEl instanceof Node && this.#targetContains(activeEl);
|
|
542
|
+
}
|
|
297
543
|
#resetTipOrientation() {
|
|
298
544
|
this.#$tip.style.top = "";
|
|
299
545
|
this.#$tip.style.left = "";
|
|
@@ -440,28 +686,64 @@ class Tooltip extends NectaryElement {
|
|
|
440
686
|
if (!this.isDomConnected || this.#isSubscribed) {
|
|
441
687
|
return;
|
|
442
688
|
}
|
|
443
|
-
|
|
444
|
-
|
|
689
|
+
const options = { signal: this.#controller.signal };
|
|
690
|
+
this.#targetElements = this.#getTargetElements();
|
|
691
|
+
if (this.#targetElements.length === 0) {
|
|
692
|
+
requestAnimationFrame(() => {
|
|
693
|
+
if (!this.isDomConnected || this.#isSubscribed || this.text.length === 0) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
this.#subscribeMouseEnterEvent();
|
|
697
|
+
});
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
this.#targetElements.forEach((el) => {
|
|
701
|
+
el.addEventListener("mouseenter", this.#onMouseEnter, options);
|
|
445
702
|
});
|
|
703
|
+
this.#$target.addEventListener("focusin", this.#onFocusIn, options);
|
|
446
704
|
this.#isSubscribed = true;
|
|
447
705
|
}
|
|
448
706
|
#unsubscribeMouseEnterEvent() {
|
|
449
|
-
this
|
|
707
|
+
this.#targetElements.forEach((el) => {
|
|
708
|
+
el.removeEventListener("mouseenter", this.#onMouseEnter);
|
|
709
|
+
});
|
|
710
|
+
this.#$target.removeEventListener("focusin", this.#onFocusIn);
|
|
711
|
+
this.#targetElements = [];
|
|
450
712
|
this.#isSubscribed = false;
|
|
451
713
|
}
|
|
452
714
|
#subscribeMouseLeaveEvents() {
|
|
453
715
|
const options = { signal: this.#controller.signal };
|
|
454
|
-
this
|
|
455
|
-
|
|
456
|
-
|
|
716
|
+
this.#targetElements.forEach((el) => {
|
|
717
|
+
el.addEventListener("mousedown", this.#onMouseDown, options);
|
|
718
|
+
el.addEventListener("mouseleave", this.#onMouseLeave, options);
|
|
719
|
+
});
|
|
720
|
+
this.#$target.addEventListener("focusout", this.#onFocusOut, options);
|
|
721
|
+
this.#$contentWrapper.addEventListener("mouseenter", this.#onContentMouseEnter, options);
|
|
457
722
|
this.#$contentWrapper.addEventListener("mouseleave", this.#onMouseLeave, options);
|
|
458
723
|
}
|
|
459
724
|
#unsubscribeMouseLeaveEvents() {
|
|
460
|
-
this
|
|
461
|
-
|
|
462
|
-
|
|
725
|
+
this.#targetElements.forEach((el) => {
|
|
726
|
+
el.removeEventListener("mousedown", this.#onMouseDown);
|
|
727
|
+
el.removeEventListener("mouseleave", this.#onMouseLeave);
|
|
728
|
+
});
|
|
729
|
+
this.#$target.removeEventListener("focusout", this.#onFocusOut);
|
|
730
|
+
this.#$contentWrapper.removeEventListener("mouseenter", this.#onContentMouseEnter);
|
|
463
731
|
this.#$contentWrapper.removeEventListener("mouseleave", this.#onMouseLeave);
|
|
464
732
|
}
|
|
733
|
+
#onTargetSlotChange = () => {
|
|
734
|
+
if (!this.isDomConnected || this.text.length === 0) {
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const isOpen = this.#isOpen();
|
|
738
|
+
if (this.#isSubscribed) {
|
|
739
|
+
this.#unsubscribeMouseLeaveEvents();
|
|
740
|
+
this.#unsubscribeMouseEnterEvent();
|
|
741
|
+
}
|
|
742
|
+
this.#subscribeMouseEnterEvent();
|
|
743
|
+
if (isOpen) {
|
|
744
|
+
this.#subscribeMouseLeaveEvents();
|
|
745
|
+
}
|
|
746
|
+
};
|
|
465
747
|
#subscribeScroll() {
|
|
466
748
|
window.addEventListener("wheel", this.#onScroll, true);
|
|
467
749
|
}
|