@nectary/components 5.37.6 → 5.37.8
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 +216 -87
- package/package.json +1 -1
- package/tabs/index.js +101 -9
- package/tabs-icon-option/index.js +28 -10
- package/tabs-option/index.js +26 -8
- package/utils/control-keyboard-navigation.d.ts +1 -0
- package/utils/control-keyboard-navigation.js +9 -3
- package/utils/index.d.ts +1 -0
- package/utils/index.js +2 -0
- package/utils/markdown.js +3 -3
package/bundle.js
CHANGED
|
@@ -1495,9 +1495,9 @@ const regParagraph = /\n{2,}/;
|
|
|
1495
1495
|
const regEm3Star = new RegExp("(?<!\\\\)\\*\\*\\*(?<em3>.+?)(?<!\\\\)\\*\\*\\*");
|
|
1496
1496
|
const regEm2Star = new RegExp("(?<!\\\\)\\*\\*(?<em2>.+?)(?<!\\\\)\\*\\*");
|
|
1497
1497
|
const regEm1Star = new RegExp("(?<!\\\\)\\*(?<em1>.+?)(?<!\\\\)\\*");
|
|
1498
|
-
const regEm3Underscore = new RegExp("(
|
|
1499
|
-
const regEm2Underscore = new RegExp("(
|
|
1500
|
-
const regEm1Underscore = new RegExp("(
|
|
1498
|
+
const regEm3Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])___(?<em3>.+?)(?<!\\\\)___(?![a-zA-Z0-9])");
|
|
1499
|
+
const regEm2Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])__(?<em2>.+?)(?<!\\\\)__(?![a-zA-Z0-9])");
|
|
1500
|
+
const regEm1Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])_(?<em1>.+?)(?<!\\\\)_(?![a-zA-Z0-9])");
|
|
1501
1501
|
const regCodeTag = new RegExp("(?<!\\\\)`(?<code>.+?)(?<!\\\\)`");
|
|
1502
1502
|
const regStrikethrough = new RegExp("(?<!\\\\)~~(?<strike>.+?)(?<!\\\\)~~");
|
|
1503
1503
|
const regButtonPlaceholder = new RegExp("(?<!\\\\)\\[\\[(?<button>[a-zA-Z0-9_-]+)\\]\\]");
|
|
@@ -7378,12 +7378,80 @@ class Popover extends NectaryElement {
|
|
|
7378
7378
|
};
|
|
7379
7379
|
}
|
|
7380
7380
|
defineCustomElement("sinch-popover", Popover);
|
|
7381
|
+
const isActivationKey = (key) => key === "Enter" || key === " ";
|
|
7382
|
+
function createKeyboardNavigation() {
|
|
7383
|
+
return {
|
|
7384
|
+
navigateToNextOption(enabledOptions, forward) {
|
|
7385
|
+
const optionsLength = enabledOptions.length;
|
|
7386
|
+
if (optionsLength === 0) {
|
|
7387
|
+
return;
|
|
7388
|
+
}
|
|
7389
|
+
const currentIndex = enabledOptions.findIndex((option) => option === getDeepActiveElement());
|
|
7390
|
+
let nextIndex;
|
|
7391
|
+
if (currentIndex !== -1) {
|
|
7392
|
+
if (forward) {
|
|
7393
|
+
nextIndex = (currentIndex + 1) % optionsLength;
|
|
7394
|
+
} else {
|
|
7395
|
+
nextIndex = currentIndex === 0 ? optionsLength - 1 : currentIndex - 1;
|
|
7396
|
+
}
|
|
7397
|
+
} else {
|
|
7398
|
+
nextIndex = forward ? 0 : optionsLength - 1;
|
|
7399
|
+
}
|
|
7400
|
+
this.navigateToOption(enabledOptions, nextIndex);
|
|
7401
|
+
},
|
|
7402
|
+
navigateToOption(enabledOptions, index) {
|
|
7403
|
+
const optionsLength = enabledOptions.length;
|
|
7404
|
+
if (enabledOptions.length === 0 || index < 0 || index >= optionsLength) {
|
|
7405
|
+
return;
|
|
7406
|
+
}
|
|
7407
|
+
const option = enabledOptions[index];
|
|
7408
|
+
option.focus();
|
|
7409
|
+
},
|
|
7410
|
+
handleKeyboardNavigation(e, enabledOptions) {
|
|
7411
|
+
switch (e.code) {
|
|
7412
|
+
case "Space":
|
|
7413
|
+
case "Enter": {
|
|
7414
|
+
e.preventDefault();
|
|
7415
|
+
const target = getTargetByAttribute(e, "value");
|
|
7416
|
+
if (target !== null) {
|
|
7417
|
+
target.click();
|
|
7418
|
+
}
|
|
7419
|
+
break;
|
|
7420
|
+
}
|
|
7421
|
+
case "ArrowLeft": {
|
|
7422
|
+
e.preventDefault();
|
|
7423
|
+
this.navigateToNextOption(enabledOptions, false);
|
|
7424
|
+
break;
|
|
7425
|
+
}
|
|
7426
|
+
case "ArrowRight": {
|
|
7427
|
+
e.preventDefault();
|
|
7428
|
+
this.navigateToNextOption(enabledOptions, true);
|
|
7429
|
+
break;
|
|
7430
|
+
}
|
|
7431
|
+
case "Home": {
|
|
7432
|
+
e.preventDefault();
|
|
7433
|
+
this.navigateToOption(enabledOptions, 0);
|
|
7434
|
+
break;
|
|
7435
|
+
}
|
|
7436
|
+
case "End": {
|
|
7437
|
+
e.preventDefault();
|
|
7438
|
+
this.navigateToOption(enabledOptions, enabledOptions.length - 1);
|
|
7439
|
+
break;
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
};
|
|
7444
|
+
}
|
|
7381
7445
|
const templateHTML$P = '<style>:host{display:block}#wrapper{display:flex;width:100%;height:40px;border-bottom:1px solid var(--sinch-comp-tab-color-default-border-initial);box-sizing:border-box}</style><div id="wrapper"><slot></slot></div>';
|
|
7382
7446
|
const template$P = document.createElement("template");
|
|
7383
7447
|
template$P.innerHTML = templateHTML$P;
|
|
7384
7448
|
class Tabs extends NectaryElement {
|
|
7385
7449
|
#$slot;
|
|
7386
7450
|
#controller = null;
|
|
7451
|
+
#enabledOptions = [];
|
|
7452
|
+
#keyboardNav = createKeyboardNavigation();
|
|
7453
|
+
#observer = null;
|
|
7454
|
+
#rovingValue = null;
|
|
7387
7455
|
constructor() {
|
|
7388
7456
|
super();
|
|
7389
7457
|
const shadowRoot = this.attachShadow();
|
|
@@ -7393,14 +7461,28 @@ class Tabs extends NectaryElement {
|
|
|
7393
7461
|
connectedCallback() {
|
|
7394
7462
|
this.#controller = new AbortController();
|
|
7395
7463
|
const { signal } = this.#controller;
|
|
7464
|
+
const options = { signal };
|
|
7396
7465
|
this.setAttribute("role", "tablist");
|
|
7397
|
-
this
|
|
7398
|
-
this.#$slot.addEventListener("
|
|
7399
|
-
this.addEventListener("
|
|
7466
|
+
this.setAttribute("aria-orientation", "horizontal");
|
|
7467
|
+
this.#$slot.addEventListener("option-change", this.#onOptionChange, options);
|
|
7468
|
+
this.#$slot.addEventListener("slotchange", this.#onSlotChange, options);
|
|
7469
|
+
this.#$slot.addEventListener("focusin", this.#onOptionFocusIn, options);
|
|
7470
|
+
this.#$slot.addEventListener("keydown", this.#onOptionKeydown, options);
|
|
7471
|
+
this.addEventListener("-change", this.#onChangeReactHandler, options);
|
|
7472
|
+
this.#observer = new MutationObserver(this.#onOptionMutation);
|
|
7473
|
+
this.#observer.observe(this, {
|
|
7474
|
+
attributes: true,
|
|
7475
|
+
attributeFilter: ["disabled", "value"],
|
|
7476
|
+
childList: true,
|
|
7477
|
+
subtree: true
|
|
7478
|
+
});
|
|
7479
|
+
this.#syncOptions();
|
|
7400
7480
|
}
|
|
7401
7481
|
disconnectedCallback() {
|
|
7402
7482
|
this.#controller.abort();
|
|
7403
7483
|
this.#controller = null;
|
|
7484
|
+
this.#observer?.disconnect();
|
|
7485
|
+
this.#observer = null;
|
|
7404
7486
|
}
|
|
7405
7487
|
static get observedAttributes() {
|
|
7406
7488
|
return ["value"];
|
|
@@ -7426,19 +7508,91 @@ class Tabs extends NectaryElement {
|
|
|
7426
7508
|
}
|
|
7427
7509
|
return null;
|
|
7428
7510
|
}
|
|
7511
|
+
#getOptions() {
|
|
7512
|
+
return this.#$slot.assignedElements();
|
|
7513
|
+
}
|
|
7514
|
+
#updateEnabledOptions(options = this.#getOptions()) {
|
|
7515
|
+
this.#enabledOptions = options.filter((option) => !getBooleanAttribute(option, "disabled"));
|
|
7516
|
+
}
|
|
7517
|
+
#getFocusableOption() {
|
|
7518
|
+
if (this.#enabledOptions.length === 0) {
|
|
7519
|
+
return null;
|
|
7520
|
+
}
|
|
7521
|
+
if (this.#rovingValue !== null) {
|
|
7522
|
+
const rovingOption = this.#enabledOptions.find(
|
|
7523
|
+
(option) => getAttribute(option, "value", "") === this.#rovingValue
|
|
7524
|
+
);
|
|
7525
|
+
if (rovingOption != null) {
|
|
7526
|
+
return rovingOption;
|
|
7527
|
+
}
|
|
7528
|
+
}
|
|
7529
|
+
const selectedOption = this.#enabledOptions.find(
|
|
7530
|
+
(option) => getAttribute(option, "value", "") === this.value
|
|
7531
|
+
);
|
|
7532
|
+
return selectedOption ?? this.#enabledOptions[0];
|
|
7533
|
+
}
|
|
7534
|
+
#syncOptions() {
|
|
7535
|
+
const options = this.#getOptions();
|
|
7536
|
+
this.#updateEnabledOptions(options);
|
|
7537
|
+
const focusableOption = this.#getFocusableOption();
|
|
7538
|
+
this.#rovingValue = focusableOption == null ? null : getAttribute(focusableOption, "value", "");
|
|
7539
|
+
for (const $option of options) {
|
|
7540
|
+
const isDisabled = getBooleanAttribute($option, "disabled");
|
|
7541
|
+
const isChecked = !isDisabled && this.value === getAttribute($option, "value", "");
|
|
7542
|
+
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
7543
|
+
$option.tabIndex = !isDisabled && $option === focusableOption ? 0 : -1;
|
|
7544
|
+
}
|
|
7545
|
+
}
|
|
7429
7546
|
#onSlotChange = () => {
|
|
7430
|
-
this.#
|
|
7547
|
+
this.#syncOptions();
|
|
7431
7548
|
};
|
|
7432
7549
|
#onOptionChange = (e) => {
|
|
7433
7550
|
e.stopPropagation();
|
|
7434
|
-
|
|
7551
|
+
const value = e.detail;
|
|
7552
|
+
this.#rovingValue = value;
|
|
7553
|
+
this.#dispatchChangeEvent(value);
|
|
7435
7554
|
};
|
|
7436
7555
|
#onValueChange(value) {
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
7440
|
-
}
|
|
7556
|
+
this.#rovingValue = value;
|
|
7557
|
+
this.#syncOptions();
|
|
7441
7558
|
}
|
|
7559
|
+
#onOptionFocusIn = (e) => {
|
|
7560
|
+
const target = getTargetByAttribute(e, "value");
|
|
7561
|
+
if (target === null || getBooleanAttribute(target, "disabled")) {
|
|
7562
|
+
return;
|
|
7563
|
+
}
|
|
7564
|
+
this.#rovingValue = getAttribute(target, "value", "");
|
|
7565
|
+
this.#syncOptions();
|
|
7566
|
+
};
|
|
7567
|
+
#onOptionKeydown = (e) => {
|
|
7568
|
+
switch (e.code) {
|
|
7569
|
+
case "ArrowLeft": {
|
|
7570
|
+
e.preventDefault();
|
|
7571
|
+
this.#keyboardNav.navigateToNextOption(this.#enabledOptions, false);
|
|
7572
|
+
break;
|
|
7573
|
+
}
|
|
7574
|
+
case "ArrowRight": {
|
|
7575
|
+
e.preventDefault();
|
|
7576
|
+
this.#keyboardNav.navigateToNextOption(this.#enabledOptions, true);
|
|
7577
|
+
break;
|
|
7578
|
+
}
|
|
7579
|
+
case "Home": {
|
|
7580
|
+
e.preventDefault();
|
|
7581
|
+
this.#keyboardNav.navigateToOption(this.#enabledOptions, 0);
|
|
7582
|
+
break;
|
|
7583
|
+
}
|
|
7584
|
+
case "End": {
|
|
7585
|
+
e.preventDefault();
|
|
7586
|
+
this.#keyboardNav.navigateToOption(this.#enabledOptions, this.#enabledOptions.length - 1);
|
|
7587
|
+
break;
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
};
|
|
7591
|
+
#onOptionMutation = (mutations) => {
|
|
7592
|
+
if (mutations.some((mutation) => mutation.target !== this)) {
|
|
7593
|
+
this.#syncOptions();
|
|
7594
|
+
}
|
|
7595
|
+
};
|
|
7442
7596
|
#dispatchChangeEvent(value) {
|
|
7443
7597
|
this.dispatchEvent(
|
|
7444
7598
|
new CustomEvent("-change", { detail: value })
|
|
@@ -7450,25 +7604,26 @@ class Tabs extends NectaryElement {
|
|
|
7450
7604
|
};
|
|
7451
7605
|
}
|
|
7452
7606
|
defineCustomElement("sinch-tabs", Tabs);
|
|
7453
|
-
const templateHTML$O = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}
|
|
7607
|
+
const templateHTML$O = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}::slotted(*){display:block;pointer-events:none}</style><sinch-tooltip id="tooltip"><div id="button"><slot name="icon"></slot></div></sinch-tooltip>';
|
|
7454
7608
|
const template$O = document.createElement("template");
|
|
7455
7609
|
template$O.innerHTML = templateHTML$O;
|
|
7456
7610
|
class TabsIconOption extends NectaryElement {
|
|
7457
|
-
#$button;
|
|
7458
7611
|
#$tooltip;
|
|
7459
7612
|
constructor() {
|
|
7460
7613
|
super();
|
|
7461
|
-
const shadowRoot = this.attachShadow(
|
|
7614
|
+
const shadowRoot = this.attachShadow();
|
|
7462
7615
|
shadowRoot.appendChild(template$O.content.cloneNode(true));
|
|
7463
|
-
this.#$button = shadowRoot.querySelector("#button");
|
|
7464
7616
|
this.#$tooltip = shadowRoot.querySelector("#tooltip");
|
|
7465
7617
|
}
|
|
7466
7618
|
connectedCallback() {
|
|
7467
7619
|
this.setAttribute("role", "tab");
|
|
7468
|
-
this
|
|
7620
|
+
this.addEventListener("click", this.#onClick);
|
|
7621
|
+
this.addEventListener("keydown", this.#onKeyDown);
|
|
7622
|
+
this.#updateTabIndex();
|
|
7469
7623
|
}
|
|
7470
7624
|
disconnectedCallback() {
|
|
7471
|
-
this
|
|
7625
|
+
this.removeEventListener("click", this.#onClick);
|
|
7626
|
+
this.removeEventListener("keydown", this.#onKeyDown);
|
|
7472
7627
|
}
|
|
7473
7628
|
static get observedAttributes() {
|
|
7474
7629
|
return ["data-checked", "disabled", "aria-label"];
|
|
@@ -7496,7 +7651,8 @@ class TabsIconOption extends NectaryElement {
|
|
|
7496
7651
|
}
|
|
7497
7652
|
case "disabled": {
|
|
7498
7653
|
const isDisabled = isAttrTrue(newVal);
|
|
7499
|
-
this
|
|
7654
|
+
this.#updateTabIndex();
|
|
7655
|
+
updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
|
|
7500
7656
|
updateBooleanAttribute(this, name, isDisabled);
|
|
7501
7657
|
break;
|
|
7502
7658
|
}
|
|
@@ -7510,17 +7666,32 @@ class TabsIconOption extends NectaryElement {
|
|
|
7510
7666
|
return true;
|
|
7511
7667
|
}
|
|
7512
7668
|
focus() {
|
|
7513
|
-
|
|
7669
|
+
HTMLElement.prototype.focus.call(this);
|
|
7514
7670
|
}
|
|
7515
7671
|
blur() {
|
|
7516
|
-
|
|
7672
|
+
HTMLElement.prototype.blur.call(this);
|
|
7673
|
+
}
|
|
7674
|
+
#updateTabIndex() {
|
|
7675
|
+
if (this.disabled) {
|
|
7676
|
+
this.tabIndex = -1;
|
|
7677
|
+
}
|
|
7517
7678
|
}
|
|
7518
7679
|
#onClick = (e) => {
|
|
7680
|
+
if (this.disabled) {
|
|
7681
|
+
return;
|
|
7682
|
+
}
|
|
7519
7683
|
e.stopPropagation();
|
|
7520
7684
|
this.dispatchEvent(
|
|
7521
7685
|
new CustomEvent("option-change", { bubbles: true, detail: this.value })
|
|
7522
7686
|
);
|
|
7523
7687
|
};
|
|
7688
|
+
#onKeyDown = (e) => {
|
|
7689
|
+
if (this.disabled || !isActivationKey(e.key)) {
|
|
7690
|
+
return;
|
|
7691
|
+
}
|
|
7692
|
+
e.preventDefault();
|
|
7693
|
+
this.#onClick(e);
|
|
7694
|
+
};
|
|
7524
7695
|
}
|
|
7525
7696
|
defineCustomElement("sinch-tabs-icon-option", TabsIconOption);
|
|
7526
7697
|
const createDebounce = (delayFn, cancelFn) => (cb) => {
|
|
@@ -13058,65 +13229,6 @@ class SegmentedControlOption extends NectaryElement {
|
|
|
13058
13229
|
};
|
|
13059
13230
|
}
|
|
13060
13231
|
defineCustomElement("sinch-segmented-control-option", SegmentedControlOption);
|
|
13061
|
-
function createKeyboardNavigation() {
|
|
13062
|
-
return {
|
|
13063
|
-
navigateToNextOption(enabledOptions, forward) {
|
|
13064
|
-
const optionsLength = enabledOptions.length;
|
|
13065
|
-
if (optionsLength === 0) {
|
|
13066
|
-
return;
|
|
13067
|
-
}
|
|
13068
|
-
const currentIndex = enabledOptions.findIndex((option) => option === getDeepActiveElement());
|
|
13069
|
-
let nextIndex;
|
|
13070
|
-
if (currentIndex !== -1) {
|
|
13071
|
-
if (forward) {
|
|
13072
|
-
nextIndex = (currentIndex + 1) % optionsLength;
|
|
13073
|
-
} else {
|
|
13074
|
-
nextIndex = currentIndex === 0 ? optionsLength - 1 : currentIndex - 1;
|
|
13075
|
-
}
|
|
13076
|
-
} else {
|
|
13077
|
-
nextIndex = forward ? 0 : optionsLength - 1;
|
|
13078
|
-
}
|
|
13079
|
-
this.navigateToOption(enabledOptions, nextIndex);
|
|
13080
|
-
},
|
|
13081
|
-
navigateToOption(enabledOptions, index) {
|
|
13082
|
-
const optionsLength = enabledOptions.length;
|
|
13083
|
-
if (enabledOptions.length === 0 || index < 0 || index >= optionsLength) {
|
|
13084
|
-
return;
|
|
13085
|
-
}
|
|
13086
|
-
const option = enabledOptions[index];
|
|
13087
|
-
option.focus();
|
|
13088
|
-
},
|
|
13089
|
-
handleKeyboardNavigation(e, enabledOptions) {
|
|
13090
|
-
switch (e.code) {
|
|
13091
|
-
case "Space":
|
|
13092
|
-
case "Enter": {
|
|
13093
|
-
e.preventDefault();
|
|
13094
|
-
const target = getTargetByAttribute(e, "value");
|
|
13095
|
-
if (target !== null) {
|
|
13096
|
-
target.click();
|
|
13097
|
-
}
|
|
13098
|
-
break;
|
|
13099
|
-
}
|
|
13100
|
-
case "ArrowLeft":
|
|
13101
|
-
case "ArrowRight": {
|
|
13102
|
-
e.preventDefault();
|
|
13103
|
-
this.navigateToNextOption(enabledOptions, e.code === "ArrowRight");
|
|
13104
|
-
break;
|
|
13105
|
-
}
|
|
13106
|
-
case "Home": {
|
|
13107
|
-
e.preventDefault();
|
|
13108
|
-
this.navigateToOption(enabledOptions, 0);
|
|
13109
|
-
break;
|
|
13110
|
-
}
|
|
13111
|
-
case "End": {
|
|
13112
|
-
e.preventDefault();
|
|
13113
|
-
this.navigateToOption(enabledOptions, enabledOptions.length - 1);
|
|
13114
|
-
break;
|
|
13115
|
-
}
|
|
13116
|
-
}
|
|
13117
|
-
}
|
|
13118
|
-
};
|
|
13119
|
-
}
|
|
13120
13232
|
const templateHTML$m = '<style>:host{display:block;outline:0}#wrapper{display:flex;flex-direction:row;width:100%;box-sizing:border-box;position:relative;z-index:0}</style><div id="wrapper"><slot></slot></div>';
|
|
13121
13233
|
const template$m = document.createElement("template");
|
|
13122
13234
|
template$m.innerHTML = templateHTML$m;
|
|
@@ -14695,25 +14807,26 @@ class Table extends NectaryElement {
|
|
|
14695
14807
|
}
|
|
14696
14808
|
}
|
|
14697
14809
|
defineCustomElement("sinch-table", Table);
|
|
14698
|
-
const templateHTML$6 = '<style>:host{display:block}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}
|
|
14810
|
+
const templateHTML$6 = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block;pointer-events:none}</style><div id="button"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></div>';
|
|
14699
14811
|
const template$6 = document.createElement("template");
|
|
14700
14812
|
template$6.innerHTML = templateHTML$6;
|
|
14701
14813
|
class TabsOption extends NectaryElement {
|
|
14702
|
-
#$button;
|
|
14703
14814
|
#$text;
|
|
14704
14815
|
constructor() {
|
|
14705
14816
|
super();
|
|
14706
|
-
const shadowRoot = this.attachShadow(
|
|
14817
|
+
const shadowRoot = this.attachShadow();
|
|
14707
14818
|
shadowRoot.appendChild(template$6.content.cloneNode(true));
|
|
14708
|
-
this.#$button = shadowRoot.querySelector("#button");
|
|
14709
14819
|
this.#$text = shadowRoot.querySelector("#text");
|
|
14710
14820
|
}
|
|
14711
14821
|
connectedCallback() {
|
|
14712
14822
|
this.setAttribute("role", "tab");
|
|
14713
14823
|
this.addEventListener("click", this.#onClick);
|
|
14824
|
+
this.addEventListener("keydown", this.#onKeyDown);
|
|
14825
|
+
this.#updateTabIndex();
|
|
14714
14826
|
}
|
|
14715
14827
|
disconnectedCallback() {
|
|
14716
14828
|
this.removeEventListener("click", this.#onClick);
|
|
14829
|
+
this.removeEventListener("keydown", this.#onKeyDown);
|
|
14717
14830
|
}
|
|
14718
14831
|
static get observedAttributes() {
|
|
14719
14832
|
return ["data-checked", "disabled", "text"];
|
|
@@ -14733,7 +14846,8 @@ class TabsOption extends NectaryElement {
|
|
|
14733
14846
|
}
|
|
14734
14847
|
case "disabled": {
|
|
14735
14848
|
const isDisabled = isAttrTrue(newVal);
|
|
14736
|
-
this
|
|
14849
|
+
this.#updateTabIndex();
|
|
14850
|
+
updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
|
|
14737
14851
|
updateBooleanAttribute(this, name, isDisabled);
|
|
14738
14852
|
break;
|
|
14739
14853
|
}
|
|
@@ -14761,17 +14875,32 @@ class TabsOption extends NectaryElement {
|
|
|
14761
14875
|
return true;
|
|
14762
14876
|
}
|
|
14763
14877
|
focus() {
|
|
14764
|
-
|
|
14878
|
+
HTMLElement.prototype.focus.call(this);
|
|
14765
14879
|
}
|
|
14766
14880
|
blur() {
|
|
14767
|
-
|
|
14881
|
+
HTMLElement.prototype.blur.call(this);
|
|
14882
|
+
}
|
|
14883
|
+
#updateTabIndex() {
|
|
14884
|
+
if (this.disabled) {
|
|
14885
|
+
this.tabIndex = -1;
|
|
14886
|
+
}
|
|
14768
14887
|
}
|
|
14769
14888
|
#onClick = (e) => {
|
|
14889
|
+
if (this.disabled) {
|
|
14890
|
+
return;
|
|
14891
|
+
}
|
|
14770
14892
|
e.stopPropagation();
|
|
14771
14893
|
this.dispatchEvent(
|
|
14772
14894
|
new CustomEvent("option-change", { bubbles: true, detail: this.value })
|
|
14773
14895
|
);
|
|
14774
14896
|
};
|
|
14897
|
+
#onKeyDown = (e) => {
|
|
14898
|
+
if (this.disabled || !isActivationKey(e.key)) {
|
|
14899
|
+
return;
|
|
14900
|
+
}
|
|
14901
|
+
e.preventDefault();
|
|
14902
|
+
this.#onClick(e);
|
|
14903
|
+
};
|
|
14775
14904
|
}
|
|
14776
14905
|
defineCustomElement("sinch-tabs-option", TabsOption);
|
|
14777
14906
|
const templateHTML$5 = '<style>:host{display:inline-block;vertical-align:middle;outline:0}:host([ellipsis]){display:inline}#wrapper{display:flex;flex-direction:row;align-items:center;gap:4px;width:100%;height:var(--sinch-comp-tag-size-container-m);padding:0 9px;border:1px solid var(--sinch-comp-tag-border);border-radius:var(--sinch-comp-tag-shape-radius);background-color:var(--sinch-comp-tag-color-default-background);box-sizing:border-box;user-select:none;--sinch-global-color-text:var(--sinch-comp-tag-color-default-foreground);--sinch-global-color-icon:var(--sinch-comp-tag-color-default-foreground);--sinch-global-size-icon:var(--sinch-comp-tag-size-icon-m)}:host([small]) #wrapper{height:var(--sinch-comp-tag-size-container-s);padding:0 8px;--sinch-global-size-icon:var(--sinch-comp-tag-size-icon-s)}#text{flex:1;--sinch-comp-text-font:var(--sinch-comp-tag-font-size-m-label)}:host([small]) #text{--sinch-comp-text-font:var(--sinch-comp-tag-font-size-s-label)}::slotted(*){margin-left:-4px}</style><sinch-tooltip id="tooltip" type="fast"><div id="wrapper"><slot name="icon"></slot><sinch-text id="text" type="s" ellipsis></sinch-text></div></sinch-tooltip>';
|
package/package.json
CHANGED
package/tabs/index.js
CHANGED
|
@@ -2,12 +2,18 @@ import { updateAttribute, getAttribute, getBooleanAttribute, updateBooleanAttrib
|
|
|
2
2
|
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
3
3
|
import { getRect } from "../utils/rect.js";
|
|
4
4
|
import { getReactEventHandler } from "../utils/get-react-event-handler.js";
|
|
5
|
+
import { getTargetByAttribute } from "../utils/event-target.js";
|
|
6
|
+
import { createKeyboardNavigation } from "../utils/control-keyboard-navigation.js";
|
|
5
7
|
const templateHTML = '<style>:host{display:block}#wrapper{display:flex;width:100%;height:40px;border-bottom:1px solid var(--sinch-comp-tab-color-default-border-initial);box-sizing:border-box}</style><div id="wrapper"><slot></slot></div>';
|
|
6
8
|
const template = document.createElement("template");
|
|
7
9
|
template.innerHTML = templateHTML;
|
|
8
10
|
class Tabs extends NectaryElement {
|
|
9
11
|
#$slot;
|
|
10
12
|
#controller = null;
|
|
13
|
+
#enabledOptions = [];
|
|
14
|
+
#keyboardNav = createKeyboardNavigation();
|
|
15
|
+
#observer = null;
|
|
16
|
+
#rovingValue = null;
|
|
11
17
|
constructor() {
|
|
12
18
|
super();
|
|
13
19
|
const shadowRoot = this.attachShadow();
|
|
@@ -17,14 +23,28 @@ class Tabs extends NectaryElement {
|
|
|
17
23
|
connectedCallback() {
|
|
18
24
|
this.#controller = new AbortController();
|
|
19
25
|
const { signal } = this.#controller;
|
|
26
|
+
const options = { signal };
|
|
20
27
|
this.setAttribute("role", "tablist");
|
|
21
|
-
this
|
|
22
|
-
this.#$slot.addEventListener("
|
|
23
|
-
this.addEventListener("
|
|
28
|
+
this.setAttribute("aria-orientation", "horizontal");
|
|
29
|
+
this.#$slot.addEventListener("option-change", this.#onOptionChange, options);
|
|
30
|
+
this.#$slot.addEventListener("slotchange", this.#onSlotChange, options);
|
|
31
|
+
this.#$slot.addEventListener("focusin", this.#onOptionFocusIn, options);
|
|
32
|
+
this.#$slot.addEventListener("keydown", this.#onOptionKeydown, options);
|
|
33
|
+
this.addEventListener("-change", this.#onChangeReactHandler, options);
|
|
34
|
+
this.#observer = new MutationObserver(this.#onOptionMutation);
|
|
35
|
+
this.#observer.observe(this, {
|
|
36
|
+
attributes: true,
|
|
37
|
+
attributeFilter: ["disabled", "value"],
|
|
38
|
+
childList: true,
|
|
39
|
+
subtree: true
|
|
40
|
+
});
|
|
41
|
+
this.#syncOptions();
|
|
24
42
|
}
|
|
25
43
|
disconnectedCallback() {
|
|
26
44
|
this.#controller.abort();
|
|
27
45
|
this.#controller = null;
|
|
46
|
+
this.#observer?.disconnect();
|
|
47
|
+
this.#observer = null;
|
|
28
48
|
}
|
|
29
49
|
static get observedAttributes() {
|
|
30
50
|
return ["value"];
|
|
@@ -50,19 +70,91 @@ class Tabs extends NectaryElement {
|
|
|
50
70
|
}
|
|
51
71
|
return null;
|
|
52
72
|
}
|
|
73
|
+
#getOptions() {
|
|
74
|
+
return this.#$slot.assignedElements();
|
|
75
|
+
}
|
|
76
|
+
#updateEnabledOptions(options = this.#getOptions()) {
|
|
77
|
+
this.#enabledOptions = options.filter((option) => !getBooleanAttribute(option, "disabled"));
|
|
78
|
+
}
|
|
79
|
+
#getFocusableOption() {
|
|
80
|
+
if (this.#enabledOptions.length === 0) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (this.#rovingValue !== null) {
|
|
84
|
+
const rovingOption = this.#enabledOptions.find(
|
|
85
|
+
(option) => getAttribute(option, "value", "") === this.#rovingValue
|
|
86
|
+
);
|
|
87
|
+
if (rovingOption != null) {
|
|
88
|
+
return rovingOption;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const selectedOption = this.#enabledOptions.find(
|
|
92
|
+
(option) => getAttribute(option, "value", "") === this.value
|
|
93
|
+
);
|
|
94
|
+
return selectedOption ?? this.#enabledOptions[0];
|
|
95
|
+
}
|
|
96
|
+
#syncOptions() {
|
|
97
|
+
const options = this.#getOptions();
|
|
98
|
+
this.#updateEnabledOptions(options);
|
|
99
|
+
const focusableOption = this.#getFocusableOption();
|
|
100
|
+
this.#rovingValue = focusableOption == null ? null : getAttribute(focusableOption, "value", "");
|
|
101
|
+
for (const $option of options) {
|
|
102
|
+
const isDisabled = getBooleanAttribute($option, "disabled");
|
|
103
|
+
const isChecked = !isDisabled && this.value === getAttribute($option, "value", "");
|
|
104
|
+
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
105
|
+
$option.tabIndex = !isDisabled && $option === focusableOption ? 0 : -1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
53
108
|
#onSlotChange = () => {
|
|
54
|
-
this.#
|
|
109
|
+
this.#syncOptions();
|
|
55
110
|
};
|
|
56
111
|
#onOptionChange = (e) => {
|
|
57
112
|
e.stopPropagation();
|
|
58
|
-
|
|
113
|
+
const value = e.detail;
|
|
114
|
+
this.#rovingValue = value;
|
|
115
|
+
this.#dispatchChangeEvent(value);
|
|
59
116
|
};
|
|
60
117
|
#onValueChange(value) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
updateBooleanAttribute($option, "data-checked", isChecked);
|
|
64
|
-
}
|
|
118
|
+
this.#rovingValue = value;
|
|
119
|
+
this.#syncOptions();
|
|
65
120
|
}
|
|
121
|
+
#onOptionFocusIn = (e) => {
|
|
122
|
+
const target = getTargetByAttribute(e, "value");
|
|
123
|
+
if (target === null || getBooleanAttribute(target, "disabled")) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
this.#rovingValue = getAttribute(target, "value", "");
|
|
127
|
+
this.#syncOptions();
|
|
128
|
+
};
|
|
129
|
+
#onOptionKeydown = (e) => {
|
|
130
|
+
switch (e.code) {
|
|
131
|
+
case "ArrowLeft": {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
this.#keyboardNav.navigateToNextOption(this.#enabledOptions, false);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "ArrowRight": {
|
|
137
|
+
e.preventDefault();
|
|
138
|
+
this.#keyboardNav.navigateToNextOption(this.#enabledOptions, true);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case "Home": {
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
this.#keyboardNav.navigateToOption(this.#enabledOptions, 0);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case "End": {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
this.#keyboardNav.navigateToOption(this.#enabledOptions, this.#enabledOptions.length - 1);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
#onOptionMutation = (mutations) => {
|
|
154
|
+
if (mutations.some((mutation) => mutation.target !== this)) {
|
|
155
|
+
this.#syncOptions();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
66
158
|
#dispatchChangeEvent(value) {
|
|
67
159
|
this.dispatchEvent(
|
|
68
160
|
new CustomEvent("-change", { detail: value })
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import { updateAttribute, getAttribute, updateBooleanAttribute, getBooleanAttribute, isAttrEqual,
|
|
1
|
+
import { updateAttribute, getAttribute, updateBooleanAttribute, getBooleanAttribute, isAttrEqual, updateExplicitBooleanAttribute, isAttrTrue } from "../utils/dom.js";
|
|
2
2
|
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
3
|
-
|
|
3
|
+
import { isActivationKey } from "../utils/control-keyboard-navigation.js";
|
|
4
|
+
const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}::slotted(*){display:block;pointer-events:none}</style><sinch-tooltip id="tooltip"><div id="button"><slot name="icon"></slot></div></sinch-tooltip>';
|
|
4
5
|
const template = document.createElement("template");
|
|
5
6
|
template.innerHTML = templateHTML;
|
|
6
7
|
class TabsIconOption extends NectaryElement {
|
|
7
|
-
#$button;
|
|
8
8
|
#$tooltip;
|
|
9
9
|
constructor() {
|
|
10
10
|
super();
|
|
11
|
-
const shadowRoot = this.attachShadow(
|
|
11
|
+
const shadowRoot = this.attachShadow();
|
|
12
12
|
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
13
|
-
this.#$button = shadowRoot.querySelector("#button");
|
|
14
13
|
this.#$tooltip = shadowRoot.querySelector("#tooltip");
|
|
15
14
|
}
|
|
16
15
|
connectedCallback() {
|
|
17
16
|
this.setAttribute("role", "tab");
|
|
18
|
-
this
|
|
17
|
+
this.addEventListener("click", this.#onClick);
|
|
18
|
+
this.addEventListener("keydown", this.#onKeyDown);
|
|
19
|
+
this.#updateTabIndex();
|
|
19
20
|
}
|
|
20
21
|
disconnectedCallback() {
|
|
21
|
-
this
|
|
22
|
+
this.removeEventListener("click", this.#onClick);
|
|
23
|
+
this.removeEventListener("keydown", this.#onKeyDown);
|
|
22
24
|
}
|
|
23
25
|
static get observedAttributes() {
|
|
24
26
|
return ["data-checked", "disabled", "aria-label"];
|
|
@@ -46,7 +48,8 @@ class TabsIconOption extends NectaryElement {
|
|
|
46
48
|
}
|
|
47
49
|
case "disabled": {
|
|
48
50
|
const isDisabled = isAttrTrue(newVal);
|
|
49
|
-
this
|
|
51
|
+
this.#updateTabIndex();
|
|
52
|
+
updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
|
|
50
53
|
updateBooleanAttribute(this, name, isDisabled);
|
|
51
54
|
break;
|
|
52
55
|
}
|
|
@@ -60,17 +63,32 @@ class TabsIconOption extends NectaryElement {
|
|
|
60
63
|
return true;
|
|
61
64
|
}
|
|
62
65
|
focus() {
|
|
63
|
-
|
|
66
|
+
HTMLElement.prototype.focus.call(this);
|
|
64
67
|
}
|
|
65
68
|
blur() {
|
|
66
|
-
|
|
69
|
+
HTMLElement.prototype.blur.call(this);
|
|
70
|
+
}
|
|
71
|
+
#updateTabIndex() {
|
|
72
|
+
if (this.disabled) {
|
|
73
|
+
this.tabIndex = -1;
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
76
|
#onClick = (e) => {
|
|
77
|
+
if (this.disabled) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
69
80
|
e.stopPropagation();
|
|
70
81
|
this.dispatchEvent(
|
|
71
82
|
new CustomEvent("option-change", { bubbles: true, detail: this.value })
|
|
72
83
|
);
|
|
73
84
|
};
|
|
85
|
+
#onKeyDown = (e) => {
|
|
86
|
+
if (this.disabled || !isActivationKey(e.key)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
this.#onClick(e);
|
|
91
|
+
};
|
|
74
92
|
}
|
|
75
93
|
defineCustomElement("sinch-tabs-icon-option", TabsIconOption);
|
|
76
94
|
export {
|
package/tabs-option/index.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import "../text/index.js";
|
|
2
|
-
import { isAttrEqual,
|
|
2
|
+
import { isAttrEqual, updateExplicitBooleanAttribute, updateBooleanAttribute, isAttrTrue, updateAttribute, getAttribute, getBooleanAttribute } from "../utils/dom.js";
|
|
3
3
|
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
4
|
-
|
|
4
|
+
import { isActivationKey } from "../utils/control-keyboard-navigation.js";
|
|
5
|
+
const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block;pointer-events:none}</style><div id="button"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></div>';
|
|
5
6
|
const template = document.createElement("template");
|
|
6
7
|
template.innerHTML = templateHTML;
|
|
7
8
|
class TabsOption extends NectaryElement {
|
|
8
|
-
#$button;
|
|
9
9
|
#$text;
|
|
10
10
|
constructor() {
|
|
11
11
|
super();
|
|
12
|
-
const shadowRoot = this.attachShadow(
|
|
12
|
+
const shadowRoot = this.attachShadow();
|
|
13
13
|
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
14
|
-
this.#$button = shadowRoot.querySelector("#button");
|
|
15
14
|
this.#$text = shadowRoot.querySelector("#text");
|
|
16
15
|
}
|
|
17
16
|
connectedCallback() {
|
|
18
17
|
this.setAttribute("role", "tab");
|
|
19
18
|
this.addEventListener("click", this.#onClick);
|
|
19
|
+
this.addEventListener("keydown", this.#onKeyDown);
|
|
20
|
+
this.#updateTabIndex();
|
|
20
21
|
}
|
|
21
22
|
disconnectedCallback() {
|
|
22
23
|
this.removeEventListener("click", this.#onClick);
|
|
24
|
+
this.removeEventListener("keydown", this.#onKeyDown);
|
|
23
25
|
}
|
|
24
26
|
static get observedAttributes() {
|
|
25
27
|
return ["data-checked", "disabled", "text"];
|
|
@@ -39,7 +41,8 @@ class TabsOption extends NectaryElement {
|
|
|
39
41
|
}
|
|
40
42
|
case "disabled": {
|
|
41
43
|
const isDisabled = isAttrTrue(newVal);
|
|
42
|
-
this
|
|
44
|
+
this.#updateTabIndex();
|
|
45
|
+
updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
|
|
43
46
|
updateBooleanAttribute(this, name, isDisabled);
|
|
44
47
|
break;
|
|
45
48
|
}
|
|
@@ -67,17 +70,32 @@ class TabsOption extends NectaryElement {
|
|
|
67
70
|
return true;
|
|
68
71
|
}
|
|
69
72
|
focus() {
|
|
70
|
-
|
|
73
|
+
HTMLElement.prototype.focus.call(this);
|
|
71
74
|
}
|
|
72
75
|
blur() {
|
|
73
|
-
|
|
76
|
+
HTMLElement.prototype.blur.call(this);
|
|
77
|
+
}
|
|
78
|
+
#updateTabIndex() {
|
|
79
|
+
if (this.disabled) {
|
|
80
|
+
this.tabIndex = -1;
|
|
81
|
+
}
|
|
74
82
|
}
|
|
75
83
|
#onClick = (e) => {
|
|
84
|
+
if (this.disabled) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
76
87
|
e.stopPropagation();
|
|
77
88
|
this.dispatchEvent(
|
|
78
89
|
new CustomEvent("option-change", { bubbles: true, detail: this.value })
|
|
79
90
|
);
|
|
80
91
|
};
|
|
92
|
+
#onKeyDown = (e) => {
|
|
93
|
+
if (this.disabled || !isActivationKey(e.key)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
this.#onClick(e);
|
|
98
|
+
};
|
|
81
99
|
}
|
|
82
100
|
defineCustomElement("sinch-tabs-option", TabsOption);
|
|
83
101
|
export {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const isActivationKey: (key: string) => key is " " | "Enter";
|
|
1
2
|
export declare function createKeyboardNavigation(): {
|
|
2
3
|
navigateToNextOption(enabledOptions: Element[], forward: boolean): void;
|
|
3
4
|
navigateToOption(enabledOptions: Element[], index: number): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getDeepActiveElement } from "./dom.js";
|
|
2
2
|
import { getTargetByAttribute } from "./event-target.js";
|
|
3
|
+
const isActivationKey = (key) => key === "Enter" || key === " ";
|
|
3
4
|
function createKeyboardNavigation() {
|
|
4
5
|
return {
|
|
5
6
|
navigateToNextOption(enabledOptions, forward) {
|
|
@@ -39,10 +40,14 @@ function createKeyboardNavigation() {
|
|
|
39
40
|
}
|
|
40
41
|
break;
|
|
41
42
|
}
|
|
42
|
-
case "ArrowLeft":
|
|
43
|
+
case "ArrowLeft": {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
this.navigateToNextOption(enabledOptions, false);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
43
48
|
case "ArrowRight": {
|
|
44
49
|
e.preventDefault();
|
|
45
|
-
this.navigateToNextOption(enabledOptions,
|
|
50
|
+
this.navigateToNextOption(enabledOptions, true);
|
|
46
51
|
break;
|
|
47
52
|
}
|
|
48
53
|
case "Home": {
|
|
@@ -60,5 +65,6 @@ function createKeyboardNavigation() {
|
|
|
60
65
|
};
|
|
61
66
|
}
|
|
62
67
|
export {
|
|
63
|
-
createKeyboardNavigation
|
|
68
|
+
createKeyboardNavigation,
|
|
69
|
+
isActivationKey
|
|
64
70
|
};
|
package/utils/index.d.ts
CHANGED
package/utils/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { debounceAnimationFrame, debounceTimeout } from "./debounce.js";
|
|
|
9
9
|
import { getReactEventHandler } from "./get-react-event-handler.js";
|
|
10
10
|
import { isEmojiString, parseMarkdown } from "./markdown.js";
|
|
11
11
|
import { getTargetAttribute, getTargetByAttribute, getTargetIndexInParent, isTargetEqual } from "./event-target.js";
|
|
12
|
+
import { isActivationKey } from "./control-keyboard-navigation.js";
|
|
12
13
|
import { getUid } from "./uid.js";
|
|
13
14
|
export {
|
|
14
15
|
CSV_DELIMITER,
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
getTransformedAncestor,
|
|
43
44
|
getUid,
|
|
44
45
|
hasClass,
|
|
46
|
+
isActivationKey,
|
|
45
47
|
isAttrEqual,
|
|
46
48
|
isAttrTrue,
|
|
47
49
|
isElementFocused,
|
package/utils/markdown.js
CHANGED
|
@@ -3,9 +3,9 @@ const regParagraph = /\n{2,}/;
|
|
|
3
3
|
const regEm3Star = new RegExp("(?<!\\\\)\\*\\*\\*(?<em3>.+?)(?<!\\\\)\\*\\*\\*");
|
|
4
4
|
const regEm2Star = new RegExp("(?<!\\\\)\\*\\*(?<em2>.+?)(?<!\\\\)\\*\\*");
|
|
5
5
|
const regEm1Star = new RegExp("(?<!\\\\)\\*(?<em1>.+?)(?<!\\\\)\\*");
|
|
6
|
-
const regEm3Underscore = new RegExp("(
|
|
7
|
-
const regEm2Underscore = new RegExp("(
|
|
8
|
-
const regEm1Underscore = new RegExp("(
|
|
6
|
+
const regEm3Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])___(?<em3>.+?)(?<!\\\\)___(?![a-zA-Z0-9])");
|
|
7
|
+
const regEm2Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])__(?<em2>.+?)(?<!\\\\)__(?![a-zA-Z0-9])");
|
|
8
|
+
const regEm1Underscore = new RegExp("(?<![\\\\a-zA-Z0-9])_(?<em1>.+?)(?<!\\\\)_(?![a-zA-Z0-9])");
|
|
9
9
|
const regCodeTag = new RegExp("(?<!\\\\)`(?<code>.+?)(?<!\\\\)`");
|
|
10
10
|
const regStrikethrough = new RegExp("(?<!\\\\)~~(?<strike>.+?)(?<!\\\\)~~");
|
|
11
11
|
const regButtonPlaceholder = new RegExp("(?<!\\\\)\\[\\[(?<button>[a-zA-Z0-9_-]+)\\]\\]");
|