@nectary/components 5.18.3 → 5.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle.js +124 -24
- package/field-v2/global/index.d.ts +1 -0
- package/field-v2/global/index.js +2 -0
- package/field-v2/index.d.ts +21 -0
- package/field-v2/index.js +159 -0
- package/field-v2/types.d.ts +58 -0
- package/field-v2/types.js +1 -0
- package/link/index.d.ts +3 -0
- package/link/index.js +56 -7
- package/link/types.d.ts +2 -0
- package/package.json +2 -2
- package/readme.md +2 -2
- package/rich-text/index.js +1 -0
- package/rich-text/utils.js +14 -5
- package/rich-textarea/utils.js +42 -12
- package/utils/component-names.d.ts +2 -2
- package/utils/component-names.js +1 -0
- package/utils/element.d.ts +1 -0
- package/utils/markdown.d.ts +4 -1
- package/utils/markdown.js +13 -1
package/bundle.js
CHANGED
|
@@ -1070,23 +1070,30 @@ class CodeTag extends NectaryElement {
|
|
|
1070
1070
|
}
|
|
1071
1071
|
}
|
|
1072
1072
|
defineCustomElement("sinch-code-tag", CodeTag);
|
|
1073
|
-
const templateHTML$14 = '<style>:host{display:inline}a{font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap;--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-initial)}a:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover);--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-hover)}a:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([standalone]){display:block}:host([standalone]) a{display:block;font:var(--sinch-comp-link-standalone-font-initial);font-size:inherit;line-height:inherit;text-decoration:none;width:fit-content}#external-icon,#standalone-icon{display:none;height:1em}#icon-prefix{display:none;margin-left:-.25em}:host([external]:not([standalone])) #external-icon{display:inline-block;margin-left:.25em;vertical-align:-.2em;--sinch-global-size-icon:1em}:host([standalone][external]) #external-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([standalone]) #icon-prefix{display:inline}:host([standalone]:not([external])) #standalone-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([disabled]) a{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled);--sinch-global-color-icon:var(--sinch-comp-link-color-disabled-icon-initial)}#content{white-space:var(--sinch-global-text-white-space,normal)}</style><a referrerpolicy="no-referer"><span id="content"></span> <span id="icon-prefix"> </span><sinch-icon icons-version="2" name="fa-arrow-up-right" id="external-icon"></sinch-icon><sinch-icon icons-version="2" name="fa-arrow-right" id="standalone-icon"></sinch-icon></a>';
|
|
1073
|
+
const templateHTML$14 = '<style>:host{display:inline}a{font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap;--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-initial)}a:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover);--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-hover)}a:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([standalone]){display:block}:host([standalone]) a{display:block;font:var(--sinch-comp-link-standalone-font-initial);font-size:inherit;line-height:inherit;text-decoration:none;width:fit-content}#external-icon,#standalone-icon{display:none;height:1em}#icon-prefix{display:none;margin-left:-.25em}:host([external]:not([standalone])) #external-icon{display:inline-block;margin-left:.25em;vertical-align:-.2em;--sinch-global-size-icon:1em}:host([standalone][external]) #external-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([standalone]) #icon-prefix{display:inline}:host([standalone]:not([external])) #standalone-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([disabled]) a{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled);--sinch-global-color-icon:var(--sinch-comp-link-color-disabled-icon-initial)}#content{white-space:var(--sinch-global-text-white-space,normal)}button{display:none;border:none;background:0 0;padding:0;margin:0;cursor:pointer;font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap}button:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover)}button:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([disabled]) button{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled)}#button-content{white-space:var(--sinch-global-text-white-space,normal)}:host([preventdefault]:not([use-history])) a{display:none}:host([preventdefault]:not([use-history])) button{display:inline}</style><a referrerpolicy="no-referer"><span id="content"></span> <span id="icon-prefix"> </span><sinch-icon icons-version="2" name="fa-arrow-up-right" id="external-icon"></sinch-icon><sinch-icon icons-version="2" name="fa-arrow-right" id="standalone-icon"></sinch-icon></a><button type="button"><span id="button-content"></span></button>';
|
|
1074
1074
|
const template$14 = document.createElement("template");
|
|
1075
1075
|
template$14.innerHTML = templateHTML$14;
|
|
1076
1076
|
class Link extends NectaryElement {
|
|
1077
1077
|
#$anchor;
|
|
1078
1078
|
#$text;
|
|
1079
|
+
#$button;
|
|
1080
|
+
#$buttonText;
|
|
1079
1081
|
constructor() {
|
|
1080
1082
|
super();
|
|
1081
1083
|
const shadowRoot = this.attachShadow();
|
|
1082
1084
|
shadowRoot.appendChild(template$14.content.cloneNode(true));
|
|
1083
1085
|
this.#$anchor = shadowRoot.querySelector("a");
|
|
1084
1086
|
this.#$text = shadowRoot.querySelector("#content");
|
|
1087
|
+
this.#$button = shadowRoot.querySelector("button");
|
|
1088
|
+
this.#$buttonText = shadowRoot.querySelector("#button-content");
|
|
1085
1089
|
}
|
|
1086
1090
|
connectedCallback() {
|
|
1087
1091
|
this.#$anchor.addEventListener("click", this.#onAnchorClick);
|
|
1088
1092
|
this.#$anchor.addEventListener("focus", this.#onAnchorFocus);
|
|
1089
1093
|
this.#$anchor.addEventListener("blur", this.#onAnchorBlur);
|
|
1094
|
+
this.#$button.addEventListener("click", this.#onButtonClick);
|
|
1095
|
+
this.#$button.addEventListener("focus", this.#onAnchorFocus);
|
|
1096
|
+
this.#$button.addEventListener("blur", this.#onAnchorBlur);
|
|
1090
1097
|
this.addEventListener("-click", this.#onClickReactHandler);
|
|
1091
1098
|
this.addEventListener("-focus", this.#onFocusReactHandler);
|
|
1092
1099
|
this.addEventListener("-blur", this.#onBlurReactHandler);
|
|
@@ -1095,6 +1102,9 @@ class Link extends NectaryElement {
|
|
|
1095
1102
|
this.#$anchor.removeEventListener("click", this.#onAnchorClick);
|
|
1096
1103
|
this.#$anchor.removeEventListener("focus", this.#onAnchorFocus);
|
|
1097
1104
|
this.#$anchor.removeEventListener("blur", this.#onAnchorBlur);
|
|
1105
|
+
this.#$button.removeEventListener("click", this.#onButtonClick);
|
|
1106
|
+
this.#$button.removeEventListener("focus", this.#onAnchorFocus);
|
|
1107
|
+
this.#$button.removeEventListener("blur", this.#onAnchorBlur);
|
|
1098
1108
|
this.removeEventListener("-click", this.#onClickReactHandler);
|
|
1099
1109
|
this.removeEventListener("-focus", this.#onFocusReactHandler);
|
|
1100
1110
|
this.removeEventListener("-blur", this.#onBlurReactHandler);
|
|
@@ -1103,19 +1113,38 @@ class Link extends NectaryElement {
|
|
|
1103
1113
|
return [
|
|
1104
1114
|
"text",
|
|
1105
1115
|
"href",
|
|
1116
|
+
"content-as-code",
|
|
1106
1117
|
"use-history",
|
|
1107
1118
|
"external",
|
|
1108
1119
|
"standalone",
|
|
1109
1120
|
"disabled"
|
|
1110
1121
|
];
|
|
1111
1122
|
}
|
|
1123
|
+
#renderContent() {
|
|
1124
|
+
const text = getAttribute(this, "text", "");
|
|
1125
|
+
const asCode = getBooleanAttribute(this, "content-as-code");
|
|
1126
|
+
this.#$text.textContent = "";
|
|
1127
|
+
this.#$buttonText.textContent = "";
|
|
1128
|
+
if (asCode && text !== "") {
|
|
1129
|
+
const $code = document.createElement("sinch-code-tag");
|
|
1130
|
+
$code.text = text;
|
|
1131
|
+
this.#$text.appendChild($code);
|
|
1132
|
+
const $buttonCode = document.createElement("sinch-code-tag");
|
|
1133
|
+
$buttonCode.text = text;
|
|
1134
|
+
this.#$buttonText.appendChild($buttonCode);
|
|
1135
|
+
} else {
|
|
1136
|
+
this.#$text.textContent = text;
|
|
1137
|
+
this.#$buttonText.textContent = text;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1112
1140
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
1113
1141
|
if (isAttrEqual(oldVal, newVal)) {
|
|
1114
1142
|
return;
|
|
1115
1143
|
}
|
|
1116
1144
|
switch (name) {
|
|
1117
|
-
case "text":
|
|
1118
|
-
|
|
1145
|
+
case "text":
|
|
1146
|
+
case "content-as-code": {
|
|
1147
|
+
this.#renderContent();
|
|
1119
1148
|
break;
|
|
1120
1149
|
}
|
|
1121
1150
|
case "href": {
|
|
@@ -1132,7 +1161,11 @@ class Link extends NectaryElement {
|
|
|
1132
1161
|
}
|
|
1133
1162
|
case "standalone":
|
|
1134
1163
|
case "disabled": {
|
|
1135
|
-
|
|
1164
|
+
const isTrue = isAttrTrue(newVal);
|
|
1165
|
+
updateBooleanAttribute(this, name, isTrue);
|
|
1166
|
+
if (name === "disabled") {
|
|
1167
|
+
this.#$button.disabled = isTrue;
|
|
1168
|
+
}
|
|
1136
1169
|
break;
|
|
1137
1170
|
}
|
|
1138
1171
|
case "external": {
|
|
@@ -1149,6 +1182,12 @@ class Link extends NectaryElement {
|
|
|
1149
1182
|
set text(value) {
|
|
1150
1183
|
updateAttribute(this, "text", value);
|
|
1151
1184
|
}
|
|
1185
|
+
get contentAsCode() {
|
|
1186
|
+
return getBooleanAttribute(this, "content-as-code");
|
|
1187
|
+
}
|
|
1188
|
+
set contentAsCode(value) {
|
|
1189
|
+
updateBooleanAttribute(this, "content-as-code", value);
|
|
1190
|
+
}
|
|
1152
1191
|
get href() {
|
|
1153
1192
|
return getAttribute(this, "href", "");
|
|
1154
1193
|
}
|
|
@@ -1185,15 +1224,24 @@ class Link extends NectaryElement {
|
|
|
1185
1224
|
get preventDefault() {
|
|
1186
1225
|
return getBooleanAttribute(this, "preventdefault");
|
|
1187
1226
|
}
|
|
1227
|
+
get #$activeElement() {
|
|
1228
|
+
return this.preventDefault && !this["use-history"] ? this.#$button : this.#$anchor;
|
|
1229
|
+
}
|
|
1188
1230
|
get focusable() {
|
|
1189
1231
|
return true;
|
|
1190
1232
|
}
|
|
1191
1233
|
focus() {
|
|
1192
|
-
this.#$
|
|
1234
|
+
this.#$activeElement.focus();
|
|
1193
1235
|
}
|
|
1194
1236
|
blur() {
|
|
1195
|
-
this.#$
|
|
1237
|
+
this.#$activeElement.blur();
|
|
1196
1238
|
}
|
|
1239
|
+
#onButtonClick = () => {
|
|
1240
|
+
if (this.disabled) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
this.dispatchEvent(new CustomEvent("-click"));
|
|
1244
|
+
};
|
|
1197
1245
|
#onAnchorClick = (e) => {
|
|
1198
1246
|
if (this.preventDefault) {
|
|
1199
1247
|
e.preventDefault();
|
|
@@ -1346,6 +1394,7 @@ const regEm2Underscore = new RegExp("(?<!\\\\)__(?<em2>.+?)(?<!\\\\)__");
|
|
|
1346
1394
|
const regEm1Underscore = new RegExp("(?<!\\\\)_(?<em1>.+?)(?<!\\\\)_");
|
|
1347
1395
|
const regCodeTag = new RegExp("(?<!\\\\)`(?<code>.+?)(?<!\\\\)`");
|
|
1348
1396
|
const regStrikethrough = new RegExp("(?<!\\\\)~~(?<strike>.+?)(?<!\\\\)~~");
|
|
1397
|
+
const regButtonPlaceholder = new RegExp("(?<!\\\\)\\[\\[(?<button>[a-zA-Z0-9_-]+)\\]\\]");
|
|
1349
1398
|
const regLink = new RegExp("(?<!\\\\)!?\\[(?<linktext>[^\\]]*?)\\]\\((?<linkhref>[^)]+?)\\)(\\{(?<linkattrs>[^)]+?)\\})?");
|
|
1350
1399
|
const regChip = new RegExp("(?<!\\\\)\\{\\{(?<chip>[a-zA-Z0-9_-]+)\\}\\}");
|
|
1351
1400
|
const regEmoji = new RegExp("(?<emoji>(?![0-9*#])\\p{Emoji})", "u");
|
|
@@ -1355,6 +1404,7 @@ const regEscapedChars = /\\(?<escaped>[\\\*_\[\]`~\{\}])/;
|
|
|
1355
1404
|
const allRegs = [
|
|
1356
1405
|
regEscapedChars,
|
|
1357
1406
|
regCodeTag,
|
|
1407
|
+
regButtonPlaceholder,
|
|
1358
1408
|
regLink,
|
|
1359
1409
|
regChip,
|
|
1360
1410
|
regEm3Star,
|
|
@@ -1398,13 +1448,23 @@ const createLineParser = (visitor) => function parseLine(regs, md, context = INI
|
|
|
1398
1448
|
visitor.escaped(groups.escaped);
|
|
1399
1449
|
continue;
|
|
1400
1450
|
}
|
|
1451
|
+
if (groups?.button != null) {
|
|
1452
|
+
visitor.buttonPlaceholder(groups.button);
|
|
1453
|
+
continue;
|
|
1454
|
+
}
|
|
1401
1455
|
if (groups?.linkhref != null) {
|
|
1402
|
-
|
|
1456
|
+
const rawText = groups.linktext;
|
|
1457
|
+
const isCode = rawText.length >= 2 && rawText.startsWith("`") && rawText.endsWith("`") && !rawText.slice(1, -1).includes("`");
|
|
1458
|
+
const linkText = isCode ? rawText.slice(1, -1) : rawText;
|
|
1459
|
+
visitor.link(linkText, groups.linkhref, groups.linkattrs?.split(" "), isCode);
|
|
1403
1460
|
}
|
|
1404
1461
|
if (groups?.code != null) {
|
|
1405
1462
|
visitor.codetag(groups.code);
|
|
1406
1463
|
}
|
|
1407
1464
|
if (groups?.chip != null) {
|
|
1465
|
+
if (visitor.linkPlaceholder(groups.chip)) {
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1408
1468
|
visitor.tag(groups.chip);
|
|
1409
1469
|
}
|
|
1410
1470
|
if (groups?.emoji != null) {
|
|
@@ -1523,14 +1583,14 @@ const createParseVisitor$1 = (doc) => {
|
|
|
1523
1583
|
let $li = null;
|
|
1524
1584
|
const $lists = [];
|
|
1525
1585
|
return {
|
|
1526
|
-
// Add new escaped method to handle escaped characters
|
|
1527
1586
|
escaped(char) {
|
|
1528
|
-
const $
|
|
1587
|
+
const $inline = doc.createElement("SPAN");
|
|
1588
|
+
$inline.append(doc.createTextNode(char));
|
|
1529
1589
|
if ($p != null) {
|
|
1530
|
-
$p.appendChild($
|
|
1590
|
+
$p.appendChild($inline);
|
|
1531
1591
|
} else {
|
|
1532
1592
|
this.paragraph();
|
|
1533
|
-
$p.appendChild($
|
|
1593
|
+
$p.appendChild($inline);
|
|
1534
1594
|
}
|
|
1535
1595
|
},
|
|
1536
1596
|
emoji(emojiChar) {
|
|
@@ -1545,6 +1605,9 @@ const createParseVisitor$1 = (doc) => {
|
|
|
1545
1605
|
$codeTag.text = text;
|
|
1546
1606
|
$p.appendChild($codeTag);
|
|
1547
1607
|
},
|
|
1608
|
+
linkPlaceholder(_name) {
|
|
1609
|
+
return false;
|
|
1610
|
+
},
|
|
1548
1611
|
tag(text) {
|
|
1549
1612
|
const $chip = doc.createElement("sinch-rich-textarea-chip");
|
|
1550
1613
|
const resolved = chipResolver?.(text);
|
|
@@ -1560,6 +1623,9 @@ const createParseVisitor$1 = (doc) => {
|
|
|
1560
1623
|
}
|
|
1561
1624
|
$p.appendChild($chip);
|
|
1562
1625
|
},
|
|
1626
|
+
buttonPlaceholder(name) {
|
|
1627
|
+
this.inline(`[[${name}]]`, {});
|
|
1628
|
+
},
|
|
1563
1629
|
inline(text, { isBold, isItalic, isStrikethrough }) {
|
|
1564
1630
|
const $inline = doc.createElement("SPAN");
|
|
1565
1631
|
$inline.append(doc.createTextNode(text));
|
|
@@ -1578,10 +1644,13 @@ const createParseVisitor$1 = (doc) => {
|
|
|
1578
1644
|
const $br = doc.createElement("br");
|
|
1579
1645
|
$p.appendChild($br);
|
|
1580
1646
|
},
|
|
1581
|
-
link(text, href, attributes) {
|
|
1647
|
+
link(text, href, attributes, isCode) {
|
|
1582
1648
|
const $link = doc.createElement("sinch-link");
|
|
1583
1649
|
$link.text = text;
|
|
1584
1650
|
$link.href = href;
|
|
1651
|
+
if (isCode === true) {
|
|
1652
|
+
$link.contentAsCode = true;
|
|
1653
|
+
}
|
|
1585
1654
|
if (attributes != null) {
|
|
1586
1655
|
attributes.forEach((attr) => {
|
|
1587
1656
|
if (attr.startsWith("#")) {
|
|
@@ -1745,6 +1814,7 @@ class RichText extends NectaryElement {
|
|
|
1745
1814
|
#handleElementClick = (e) => {
|
|
1746
1815
|
const eventTarget = e.target;
|
|
1747
1816
|
const elementClickEvent = new CustomEvent("-element-click");
|
|
1817
|
+
Object.defineProperty(elementClickEvent, "target", { value: eventTarget });
|
|
1748
1818
|
Object.defineProperty(elementClickEvent, "currentTarget", { value: eventTarget });
|
|
1749
1819
|
this.dispatchEvent(elementClickEvent);
|
|
1750
1820
|
};
|
|
@@ -8947,14 +9017,28 @@ const copyFormatName = ($source, $target) => {
|
|
|
8947
9017
|
$target.className = $inline.className;
|
|
8948
9018
|
if (isFormatLink($inline)) {
|
|
8949
9019
|
$target.setAttribute(LINK_HREF_ATTR_NAME, $inline.getAttribute(LINK_HREF_ATTR_NAME) ?? "");
|
|
9020
|
+
} else {
|
|
9021
|
+
$target.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
8950
9022
|
}
|
|
8951
9023
|
};
|
|
8952
9024
|
const setInlineFormat = ($n, formatName, shouldEnable) => {
|
|
8953
9025
|
if (shouldEnable) {
|
|
8954
|
-
if (formatName === "c"
|
|
8955
|
-
$n
|
|
8956
|
-
|
|
8957
|
-
|
|
9026
|
+
if (formatName === "c") {
|
|
9027
|
+
if (isFormatName($n, "l")) {
|
|
9028
|
+
$n.className = "l";
|
|
9029
|
+
} else {
|
|
9030
|
+
$n.className = "";
|
|
9031
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
9032
|
+
}
|
|
9033
|
+
} else if (formatName === "l") {
|
|
9034
|
+
if (!isFormatName($n, "c")) {
|
|
9035
|
+
$n.className = "";
|
|
9036
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
9037
|
+
} else {
|
|
9038
|
+
$n.className = "c";
|
|
9039
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
9040
|
+
}
|
|
9041
|
+
} else if (isFormatName($n, "c") || isFormatName($n, "l")) {
|
|
8958
9042
|
$n.className = "";
|
|
8959
9043
|
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
8960
9044
|
}
|
|
@@ -8995,14 +9079,14 @@ const areSameInlineFormat = ($a, $b) => {
|
|
|
8995
9079
|
if ($a.classList.length !== $b.classList.length) {
|
|
8996
9080
|
return false;
|
|
8997
9081
|
}
|
|
8998
|
-
if ($a.className === "l") {
|
|
8999
|
-
return $b.className === "l" && $a.getAttribute(LINK_HREF_ATTR_NAME) === $b.getAttribute(LINK_HREF_ATTR_NAME);
|
|
9000
|
-
}
|
|
9001
9082
|
for (let i = 0; i < $a.classList.length; i++) {
|
|
9002
9083
|
if (!$b.classList.contains($a.classList[i])) {
|
|
9003
9084
|
return false;
|
|
9004
9085
|
}
|
|
9005
9086
|
}
|
|
9087
|
+
if ($a.classList.contains("l")) {
|
|
9088
|
+
return $a.getAttribute(LINK_HREF_ATTR_NAME) === $b.getAttribute(LINK_HREF_ATTR_NAME);
|
|
9089
|
+
}
|
|
9006
9090
|
return true;
|
|
9007
9091
|
};
|
|
9008
9092
|
const createInlineWithText = (data2, doc) => {
|
|
@@ -10282,6 +10366,11 @@ const serializeDescriptorReducer = (range) => (state, $n) => {
|
|
|
10282
10366
|
if (isEmptyText(text)) {
|
|
10283
10367
|
return state;
|
|
10284
10368
|
}
|
|
10369
|
+
if (isFormatCodetag($n) && isFormatLink($n)) {
|
|
10370
|
+
const href = $n.getAttribute(LINK_HREF_ATTR_NAME) ?? "#";
|
|
10371
|
+
state.push({ isCodetag: true, isLink: true, text, href });
|
|
10372
|
+
return state;
|
|
10373
|
+
}
|
|
10285
10374
|
if (isFormatCodetag($n)) {
|
|
10286
10375
|
state.push({ isCodetag: true, text });
|
|
10287
10376
|
return state;
|
|
@@ -10332,7 +10421,8 @@ const MD_PARAGRAPH_JOIN = "\n\n";
|
|
|
10332
10421
|
const serializeTextReducer = (state, desc, i, descArray) => {
|
|
10333
10422
|
const { chunks } = state;
|
|
10334
10423
|
if (desc.isLink === true) {
|
|
10335
|
-
|
|
10424
|
+
const inner = desc.isCodetag === true ? `${MD_CODETAG_TOKEN}${desc.text}${MD_CODETAG_TOKEN}` : desc.text;
|
|
10425
|
+
chunks.push(`[${inner}](${desc.href})`);
|
|
10336
10426
|
return state;
|
|
10337
10427
|
}
|
|
10338
10428
|
if (desc.isEmoji === true) {
|
|
@@ -10513,12 +10603,12 @@ const createParseVisitor = (doc) => {
|
|
|
10513
10603
|
let isFirstListItem = false;
|
|
10514
10604
|
return {
|
|
10515
10605
|
escaped(char) {
|
|
10516
|
-
const $
|
|
10606
|
+
const $inline = createInlineWithText(char, doc);
|
|
10517
10607
|
if ($currentBlock != null) {
|
|
10518
|
-
$currentBlock.appendChild($
|
|
10608
|
+
$currentBlock.appendChild($inline);
|
|
10519
10609
|
} else {
|
|
10520
10610
|
this.paragraph();
|
|
10521
|
-
$currentBlock.appendChild($
|
|
10611
|
+
$currentBlock.appendChild($inline);
|
|
10522
10612
|
}
|
|
10523
10613
|
},
|
|
10524
10614
|
emoji(emojiChar) {
|
|
@@ -10530,11 +10620,18 @@ const createParseVisitor = (doc) => {
|
|
|
10530
10620
|
setInlineFormat($inline, "c", true);
|
|
10531
10621
|
$currentBlock.appendChild($inline);
|
|
10532
10622
|
},
|
|
10623
|
+
linkPlaceholder(_name) {
|
|
10624
|
+
return false;
|
|
10625
|
+
},
|
|
10533
10626
|
tag(text) {
|
|
10534
10627
|
const resolved = chipResolver?.(text);
|
|
10535
10628
|
const $tag = createTag(text, doc, resolved?.color ?? chipColor, resolved?.icon ?? chipIcon);
|
|
10536
10629
|
$currentBlock.appendChild($tag);
|
|
10537
10630
|
},
|
|
10631
|
+
buttonPlaceholder(name) {
|
|
10632
|
+
const $inline = createInlineWithText(`[[${name}]]`, doc);
|
|
10633
|
+
$currentBlock.appendChild($inline);
|
|
10634
|
+
},
|
|
10538
10635
|
inline(text, { isBold, isItalic, isStrikethrough }) {
|
|
10539
10636
|
const $inline = createInlineWithText(text, doc);
|
|
10540
10637
|
setInlineFormat($inline, "b", isBold === true);
|
|
@@ -10548,8 +10645,11 @@ const createParseVisitor = (doc) => {
|
|
|
10548
10645
|
$root.appendChild($currentBlock);
|
|
10549
10646
|
}
|
|
10550
10647
|
},
|
|
10551
|
-
link(text, href) {
|
|
10648
|
+
link(text, href, _attributes, isCode) {
|
|
10552
10649
|
const $link = createLink(text, href, doc);
|
|
10650
|
+
if (isCode === true) {
|
|
10651
|
+
setInlineFormat($link, "c", true);
|
|
10652
|
+
}
|
|
10553
10653
|
$currentBlock.appendChild($link);
|
|
10554
10654
|
},
|
|
10555
10655
|
list(isOrdered) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../types';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import '../rich-text';
|
|
2
|
+
import { NectaryElement } from '../utils';
|
|
3
|
+
export * from './types';
|
|
4
|
+
export declare class FieldV2 extends NectaryElement {
|
|
5
|
+
#private;
|
|
6
|
+
constructor();
|
|
7
|
+
connectedCallback(): void;
|
|
8
|
+
disconnectedCallback(): void;
|
|
9
|
+
static get observedAttributes(): string[];
|
|
10
|
+
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
11
|
+
set label(value: string | null);
|
|
12
|
+
get label(): string | null;
|
|
13
|
+
set optionalText(value: string | null);
|
|
14
|
+
get optionalText(): string | null;
|
|
15
|
+
set additionalText(value: string | null);
|
|
16
|
+
get additionalText(): string | null;
|
|
17
|
+
set invalidText(value: string | null);
|
|
18
|
+
get invalidText(): string | null;
|
|
19
|
+
set disabled(isDisabled: boolean);
|
|
20
|
+
get disabled(): boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import "../rich-text/index.js";
|
|
2
|
+
import { getAttribute, setClass, isAttrEqual, updateBooleanAttribute, isAttrTrue, updateAttribute, getBooleanAttribute } from "../utils/dom.js";
|
|
3
|
+
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
4
|
+
import { getFirstSlotElement } from "../utils/slot.js";
|
|
5
|
+
import { getReactEventHandler } from "../utils/get-react-event-handler.js";
|
|
6
|
+
const templateHTML = '<style>:host{display:block}#wrapper{display:flex;flex-direction:column;width:100%}#top{display:flex;align-items:baseline;height:24px;margin-bottom:2px}#bottom{display:flex;flex-direction:column;align-items:baseline;width:100%}#top.empty{display:none}#label,#optional{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#label{font:var(--sinch-comp-field-font-label);color:var(--sinch-comp-field-color-default-label-initial)}#optional{flex:1;font:var(--sinch-comp-field-font-optional);color:var(--sinch-comp-field-color-default-optional-initial);text-align:right}#additional{flex:1;text-align:left;line-height:20px;margin-top:2px;white-space:normal;overflow:visible;--sinch-comp-rich-text-font:var(--sinch-comp-field-font-additional);--sinch-global-color-text:var(--sinch-comp-field-color-default-additional-initial);--sinch-comp-link-color-default-text-initial:var(--sinch-comp-field-color-default-additional-initial);--sinch-comp-link-color-default-text-hover:var(--sinch-comp-field-color-default-additional-initial)}#additional:is([text=""],:not([text])){display:none}#invalid{font:var(--sinch-comp-field-font-invalid);color:var(--sinch-comp-field-color-invalid-text-initial);line-height:20px;margin-top:2px;white-space:normal;overflow:visible;--sinch-comp-rich-text-font:var(--sinch-comp-field-font-invalid);--sinch-global-color-text:var(--sinch-comp-field-color-invalid-text-initial);--sinch-comp-link-color-default-text-initial:var(--sinch-comp-field-color-invalid-text-initial);--sinch-comp-link-color-default-text-hover:var(--sinch-comp-field-color-invalid-text-initial)}#invalid:is([text=""],:not([text])){display:none}#tooltip{align-self:center;margin:0 8px;display:flex}#tooltip.empty{display:none}:host([disabled]) #label{color:var(--sinch-comp-field-color-disabled-label-initial)}:host([disabled]) #additional{--sinch-global-color-text:var(--sinch-comp-field-color-disabled-additional-initial);--sinch-comp-link-color-default-text-initial:var(--sinch-comp-field-color-disabled-additional-initial);--sinch-comp-link-color-default-text-hover:var(--sinch-comp-field-color-disabled-additional-initial)}:host([disabled]) #optional{color:var(--sinch-comp-field-color-disabled-optional-initial)}</style><div id="wrapper"><div id="top"><label id="label" for="input"></label><div id="tooltip"><slot name="tooltip"></slot></div><span id="optional"></span></div><slot name="input"></slot><div id="bottom"><sinch-rich-text id="additional"></sinch-rich-text><sinch-rich-text id="invalid"></sinch-rich-text></div></div>';
|
|
7
|
+
const template = document.createElement("template");
|
|
8
|
+
template.innerHTML = templateHTML;
|
|
9
|
+
class FieldV2 extends NectaryElement {
|
|
10
|
+
#topSection;
|
|
11
|
+
#$label;
|
|
12
|
+
#$optionalText;
|
|
13
|
+
#$additionalText;
|
|
14
|
+
#$invalidText;
|
|
15
|
+
#$inputSlot;
|
|
16
|
+
#$tooltipWrapper;
|
|
17
|
+
#$tooltipSlot;
|
|
18
|
+
#controller = null;
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
const shadowRoot = this.attachShadow();
|
|
22
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
23
|
+
this.#topSection = shadowRoot.querySelector("#top");
|
|
24
|
+
this.#$label = shadowRoot.querySelector("#label");
|
|
25
|
+
this.#$optionalText = shadowRoot.querySelector("#optional");
|
|
26
|
+
this.#$additionalText = shadowRoot.querySelector("#additional");
|
|
27
|
+
this.#$invalidText = shadowRoot.querySelector("#invalid");
|
|
28
|
+
this.#$inputSlot = shadowRoot.querySelector('slot[name="input"]');
|
|
29
|
+
this.#$tooltipSlot = shadowRoot.querySelector('slot[name="tooltip"]');
|
|
30
|
+
this.#$tooltipWrapper = shadowRoot.querySelector("#tooltip");
|
|
31
|
+
}
|
|
32
|
+
connectedCallback() {
|
|
33
|
+
this.#controller = new AbortController();
|
|
34
|
+
const { signal } = this.#controller;
|
|
35
|
+
const options = { signal };
|
|
36
|
+
this.#shouldShowTopSection();
|
|
37
|
+
this.#$label.addEventListener("click", this.#onLabelClick, options);
|
|
38
|
+
this.#$tooltipSlot.addEventListener("slotchange", this.#onTooltipSlotChange, options);
|
|
39
|
+
this.#$inputSlot.addEventListener("slotchange", this.#onInputSlotChange, options);
|
|
40
|
+
this.#$additionalText.addEventListener("-element-click", this.#onRichTextElementClick, options);
|
|
41
|
+
this.#$invalidText.addEventListener("-element-click", this.#onRichTextElementClick, options);
|
|
42
|
+
this.addEventListener("-element-click", this.#onElementClickReactHandler, options);
|
|
43
|
+
}
|
|
44
|
+
disconnectedCallback() {
|
|
45
|
+
this.#controller.abort();
|
|
46
|
+
this.#controller = null;
|
|
47
|
+
}
|
|
48
|
+
static get observedAttributes() {
|
|
49
|
+
return [
|
|
50
|
+
"label",
|
|
51
|
+
"optionaltext",
|
|
52
|
+
"additionaltext",
|
|
53
|
+
"invalidtext",
|
|
54
|
+
"disabled"
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
#shouldShowTopSection() {
|
|
58
|
+
const label = getAttribute(this, "label");
|
|
59
|
+
const optionaltext = getAttribute(this, "optionaltext");
|
|
60
|
+
setClass(this.#topSection, "empty", label === null && optionaltext === null);
|
|
61
|
+
}
|
|
62
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
63
|
+
switch (name) {
|
|
64
|
+
case "label": {
|
|
65
|
+
this.#$label.textContent = newVal;
|
|
66
|
+
this.#syncInputAriaLabel(newVal);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "optionaltext": {
|
|
70
|
+
this.#$optionalText.textContent = newVal;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case "additionaltext": {
|
|
74
|
+
updateAttribute(this.#$additionalText, "text", newVal);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case "invalidtext": {
|
|
78
|
+
updateAttribute(this.#$invalidText, "text", newVal);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case "disabled": {
|
|
82
|
+
if (isAttrEqual(oldVal, newVal)) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
updateBooleanAttribute(this, name, isAttrTrue(newVal));
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.#shouldShowTopSection();
|
|
90
|
+
}
|
|
91
|
+
set label(value) {
|
|
92
|
+
updateAttribute(this, "label", value);
|
|
93
|
+
}
|
|
94
|
+
get label() {
|
|
95
|
+
return getAttribute(this, "label");
|
|
96
|
+
}
|
|
97
|
+
set optionalText(value) {
|
|
98
|
+
updateAttribute(this, "optionaltext", value);
|
|
99
|
+
}
|
|
100
|
+
get optionalText() {
|
|
101
|
+
return getAttribute(this, "optionaltext");
|
|
102
|
+
}
|
|
103
|
+
set additionalText(value) {
|
|
104
|
+
updateAttribute(this, "additionaltext", value);
|
|
105
|
+
}
|
|
106
|
+
get additionalText() {
|
|
107
|
+
return getAttribute(this, "additionaltext");
|
|
108
|
+
}
|
|
109
|
+
set invalidText(value) {
|
|
110
|
+
updateAttribute(this, "invalidtext", value);
|
|
111
|
+
}
|
|
112
|
+
get invalidText() {
|
|
113
|
+
return getAttribute(this, "invalidtext");
|
|
114
|
+
}
|
|
115
|
+
set disabled(isDisabled) {
|
|
116
|
+
updateBooleanAttribute(this, "disabled", isDisabled);
|
|
117
|
+
}
|
|
118
|
+
get disabled() {
|
|
119
|
+
return getBooleanAttribute(this, "disabled");
|
|
120
|
+
}
|
|
121
|
+
#onRichTextElementClick = (e) => {
|
|
122
|
+
if (this.disabled) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const forwarded = new CustomEvent("-element-click");
|
|
126
|
+
const originalTarget = e.currentTarget;
|
|
127
|
+
Object.defineProperty(forwarded, "target", { value: originalTarget });
|
|
128
|
+
Object.defineProperty(forwarded, "currentTarget", { value: originalTarget });
|
|
129
|
+
this.dispatchEvent(forwarded);
|
|
130
|
+
};
|
|
131
|
+
#onElementClickReactHandler = (e) => {
|
|
132
|
+
getReactEventHandler(this, "on-element-click")?.(e);
|
|
133
|
+
getReactEventHandler(this, "onElementClick")?.(e);
|
|
134
|
+
};
|
|
135
|
+
#onLabelClick = () => {
|
|
136
|
+
getFirstSlotElement(this.#$inputSlot)?.focus?.();
|
|
137
|
+
};
|
|
138
|
+
#onTooltipSlotChange = () => {
|
|
139
|
+
setClass(this.#$tooltipWrapper, "empty", this.#$tooltipSlot.assignedElements().length === 0);
|
|
140
|
+
};
|
|
141
|
+
#syncInputAriaLabel(labelText) {
|
|
142
|
+
const inputElement = getFirstSlotElement(this.#$inputSlot);
|
|
143
|
+
if (inputElement === null) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (labelText != null && labelText.length > 0) {
|
|
147
|
+
inputElement.setAttribute("aria-label", labelText);
|
|
148
|
+
} else {
|
|
149
|
+
inputElement.removeAttribute("aria-label");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
#onInputSlotChange = () => {
|
|
153
|
+
this.#syncInputAriaLabel(this.#$label.textContent);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
defineCustomElement("sinch-field-v2", FieldV2);
|
|
157
|
+
export {
|
|
158
|
+
FieldV2
|
|
159
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ElementClickedEvent } from '../rich-text/types';
|
|
2
|
+
import type { NectaryComponentReactByType, NectaryComponentVanillaByType, NectaryComponentReact, NectaryComponentVanilla } from '../types';
|
|
3
|
+
export type TSinchFieldV2Events = {
|
|
4
|
+
/** Forwarded click from links in additionalText / invalidText */
|
|
5
|
+
'-element-click'?: (e: ElementClickedEvent) => void;
|
|
6
|
+
};
|
|
7
|
+
export type TSinchFieldV2Props = {
|
|
8
|
+
/** Label that shows in UI */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** @hidden */
|
|
11
|
+
optionalText?: string;
|
|
12
|
+
/** Additional text */
|
|
13
|
+
additionalText?: string;
|
|
14
|
+
/** Invalid text, controls the overall invalid state of the text field */
|
|
15
|
+
invalidText?: string;
|
|
16
|
+
/** Disabled */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type TSinchFieldV2Style = {
|
|
20
|
+
'--sinch-comp-field-font-label'?: string;
|
|
21
|
+
'--sinch-comp-field-font-optional'?: string;
|
|
22
|
+
'--sinch-comp-field-font-additional'?: string;
|
|
23
|
+
'--sinch-comp-field-font-invalid'?: string;
|
|
24
|
+
'--sinch-comp-field-color-default-label-initial'?: string;
|
|
25
|
+
'--sinch-comp-field-color-default-optional-initial'?: string;
|
|
26
|
+
'--sinch-comp-field-color-default-additional-initial'?: string;
|
|
27
|
+
'--sinch-comp-field-color-disabled-label-initial'?: string;
|
|
28
|
+
'--sinch-comp-field-color-disabled-optional-initial'?: string;
|
|
29
|
+
'--sinch-comp-field-color-disabled-additional-initial'?: string;
|
|
30
|
+
'--sinch-comp-field-color-invalid-text-initial'?: string;
|
|
31
|
+
};
|
|
32
|
+
export type TSinchFieldV2 = {
|
|
33
|
+
props: TSinchFieldV2Props;
|
|
34
|
+
events: TSinchFieldV2Events;
|
|
35
|
+
style: TSinchFieldV2Style;
|
|
36
|
+
};
|
|
37
|
+
export type TSinchFieldV2Element = NectaryComponentVanillaByType<TSinchFieldV2>;
|
|
38
|
+
export type TSinchFieldV2React = NectaryComponentReactByType<TSinchFieldV2>;
|
|
39
|
+
declare global {
|
|
40
|
+
interface NectaryComponentMap {
|
|
41
|
+
'sinch-field-v2': TSinchFieldV2;
|
|
42
|
+
}
|
|
43
|
+
interface HTMLElementTagNameMap {
|
|
44
|
+
'sinch-field-v2': NectaryComponentVanilla<'sinch-field-v2'>;
|
|
45
|
+
}
|
|
46
|
+
namespace JSX {
|
|
47
|
+
interface IntrinsicElements {
|
|
48
|
+
'sinch-field-v2': NectaryComponentReact<'sinch-field-v2'>;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
declare module 'react' {
|
|
53
|
+
namespace JSX {
|
|
54
|
+
interface IntrinsicElements extends globalThis.JSX.IntrinsicElements {
|
|
55
|
+
'sinch-field-v2': NectaryComponentReact<'sinch-field-v2'>;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/link/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import '../code-tag';
|
|
1
2
|
import '../icon';
|
|
2
3
|
import { NectaryElement } from '../utils';
|
|
3
4
|
export * from './types';
|
|
@@ -10,6 +11,8 @@ export declare class Link extends NectaryElement {
|
|
|
10
11
|
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
11
12
|
get text(): string;
|
|
12
13
|
set text(value: string);
|
|
14
|
+
get contentAsCode(): boolean;
|
|
15
|
+
set contentAsCode(value: boolean);
|
|
13
16
|
get href(): string;
|
|
14
17
|
set href(value: string);
|
|
15
18
|
set 'use-history'(value: boolean);
|
package/link/index.js
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
|
+
import "../code-tag/index.js";
|
|
1
2
|
import "../icon/index.js";
|
|
2
|
-
import { isAttrEqual, updateAttribute, updateBooleanAttribute, isAttrTrue
|
|
3
|
+
import { getAttribute, getBooleanAttribute, isAttrEqual, updateAttribute, updateBooleanAttribute, isAttrTrue } from "../utils/dom.js";
|
|
3
4
|
import { defineCustomElement, NectaryElement } from "../utils/element.js";
|
|
4
5
|
import { getReactEventHandler } from "../utils/get-react-event-handler.js";
|
|
5
|
-
const templateHTML = '<style>:host{display:inline}a{font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap;--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-initial)}a:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover);--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-hover)}a:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([standalone]){display:block}:host([standalone]) a{display:block;font:var(--sinch-comp-link-standalone-font-initial);font-size:inherit;line-height:inherit;text-decoration:none;width:fit-content}#external-icon,#standalone-icon{display:none;height:1em}#icon-prefix{display:none;margin-left:-.25em}:host([external]:not([standalone])) #external-icon{display:inline-block;margin-left:.25em;vertical-align:-.2em;--sinch-global-size-icon:1em}:host([standalone][external]) #external-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([standalone]) #icon-prefix{display:inline}:host([standalone]:not([external])) #standalone-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([disabled]) a{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled);--sinch-global-color-icon:var(--sinch-comp-link-color-disabled-icon-initial)}#content{white-space:var(--sinch-global-text-white-space,normal)}</style><a referrerpolicy="no-referer"><span id="content"></span> <span id="icon-prefix"> </span><sinch-icon icons-version="2" name="fa-arrow-up-right" id="external-icon"></sinch-icon><sinch-icon icons-version="2" name="fa-arrow-right" id="standalone-icon"></sinch-icon></a>';
|
|
6
|
+
const templateHTML = '<style>:host{display:inline}a{font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap;--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-initial)}a:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover);--sinch-global-color-icon:var(--sinch-comp-link-color-default-icon-hover)}a:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([standalone]){display:block}:host([standalone]) a{display:block;font:var(--sinch-comp-link-standalone-font-initial);font-size:inherit;line-height:inherit;text-decoration:none;width:fit-content}#external-icon,#standalone-icon{display:none;height:1em}#icon-prefix{display:none;margin-left:-.25em}:host([external]:not([standalone])) #external-icon{display:inline-block;margin-left:.25em;vertical-align:-.2em;--sinch-global-size-icon:1em}:host([standalone][external]) #external-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([standalone]) #icon-prefix{display:inline}:host([standalone]:not([external])) #standalone-icon{display:inline-block;vertical-align:-.4em;--sinch-global-size-icon:1.5em}:host([disabled]) a{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled);--sinch-global-color-icon:var(--sinch-comp-link-color-disabled-icon-initial)}#content{white-space:var(--sinch-global-text-white-space,normal)}button{display:none;border:none;background:0 0;padding:0;margin:0;cursor:pointer;font:var(--sinch-comp-link-default-font-initial);font-size:inherit;line-height:inherit;text-decoration:var(--sinch-comp-link-default-text-decoration-initial);color:var(--sinch-comp-link-color-default-text-initial);border-radius:.5em;white-space:nowrap}button:hover{text-decoration:var(--sinch-comp-link-default-text-decoration-hover);color:var(--sinch-comp-link-color-default-text-hover)}button:focus-visible{outline:2px solid var(--sinch-comp-link-color-default-outline-focus);outline-offset:2px}:host([disabled]) button{color:var(--sinch-comp-link-color-disabled-text-initial);pointer-events:none;cursor:initial;text-decoration:var(--sinch-comp-link-default-text-decoration-disabled)}#button-content{white-space:var(--sinch-global-text-white-space,normal)}:host([preventdefault]:not([use-history])) a{display:none}:host([preventdefault]:not([use-history])) button{display:inline}</style><a referrerpolicy="no-referer"><span id="content"></span> <span id="icon-prefix"> </span><sinch-icon icons-version="2" name="fa-arrow-up-right" id="external-icon"></sinch-icon><sinch-icon icons-version="2" name="fa-arrow-right" id="standalone-icon"></sinch-icon></a><button type="button"><span id="button-content"></span></button>';
|
|
6
7
|
const template = document.createElement("template");
|
|
7
8
|
template.innerHTML = templateHTML;
|
|
8
9
|
class Link extends NectaryElement {
|
|
9
10
|
#$anchor;
|
|
10
11
|
#$text;
|
|
12
|
+
#$button;
|
|
13
|
+
#$buttonText;
|
|
11
14
|
constructor() {
|
|
12
15
|
super();
|
|
13
16
|
const shadowRoot = this.attachShadow();
|
|
14
17
|
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
15
18
|
this.#$anchor = shadowRoot.querySelector("a");
|
|
16
19
|
this.#$text = shadowRoot.querySelector("#content");
|
|
20
|
+
this.#$button = shadowRoot.querySelector("button");
|
|
21
|
+
this.#$buttonText = shadowRoot.querySelector("#button-content");
|
|
17
22
|
}
|
|
18
23
|
connectedCallback() {
|
|
19
24
|
this.#$anchor.addEventListener("click", this.#onAnchorClick);
|
|
20
25
|
this.#$anchor.addEventListener("focus", this.#onAnchorFocus);
|
|
21
26
|
this.#$anchor.addEventListener("blur", this.#onAnchorBlur);
|
|
27
|
+
this.#$button.addEventListener("click", this.#onButtonClick);
|
|
28
|
+
this.#$button.addEventListener("focus", this.#onAnchorFocus);
|
|
29
|
+
this.#$button.addEventListener("blur", this.#onAnchorBlur);
|
|
22
30
|
this.addEventListener("-click", this.#onClickReactHandler);
|
|
23
31
|
this.addEventListener("-focus", this.#onFocusReactHandler);
|
|
24
32
|
this.addEventListener("-blur", this.#onBlurReactHandler);
|
|
@@ -27,6 +35,9 @@ class Link extends NectaryElement {
|
|
|
27
35
|
this.#$anchor.removeEventListener("click", this.#onAnchorClick);
|
|
28
36
|
this.#$anchor.removeEventListener("focus", this.#onAnchorFocus);
|
|
29
37
|
this.#$anchor.removeEventListener("blur", this.#onAnchorBlur);
|
|
38
|
+
this.#$button.removeEventListener("click", this.#onButtonClick);
|
|
39
|
+
this.#$button.removeEventListener("focus", this.#onAnchorFocus);
|
|
40
|
+
this.#$button.removeEventListener("blur", this.#onAnchorBlur);
|
|
30
41
|
this.removeEventListener("-click", this.#onClickReactHandler);
|
|
31
42
|
this.removeEventListener("-focus", this.#onFocusReactHandler);
|
|
32
43
|
this.removeEventListener("-blur", this.#onBlurReactHandler);
|
|
@@ -35,19 +46,38 @@ class Link extends NectaryElement {
|
|
|
35
46
|
return [
|
|
36
47
|
"text",
|
|
37
48
|
"href",
|
|
49
|
+
"content-as-code",
|
|
38
50
|
"use-history",
|
|
39
51
|
"external",
|
|
40
52
|
"standalone",
|
|
41
53
|
"disabled"
|
|
42
54
|
];
|
|
43
55
|
}
|
|
56
|
+
#renderContent() {
|
|
57
|
+
const text = getAttribute(this, "text", "");
|
|
58
|
+
const asCode = getBooleanAttribute(this, "content-as-code");
|
|
59
|
+
this.#$text.textContent = "";
|
|
60
|
+
this.#$buttonText.textContent = "";
|
|
61
|
+
if (asCode && text !== "") {
|
|
62
|
+
const $code = document.createElement("sinch-code-tag");
|
|
63
|
+
$code.text = text;
|
|
64
|
+
this.#$text.appendChild($code);
|
|
65
|
+
const $buttonCode = document.createElement("sinch-code-tag");
|
|
66
|
+
$buttonCode.text = text;
|
|
67
|
+
this.#$buttonText.appendChild($buttonCode);
|
|
68
|
+
} else {
|
|
69
|
+
this.#$text.textContent = text;
|
|
70
|
+
this.#$buttonText.textContent = text;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
44
73
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
45
74
|
if (isAttrEqual(oldVal, newVal)) {
|
|
46
75
|
return;
|
|
47
76
|
}
|
|
48
77
|
switch (name) {
|
|
49
|
-
case "text":
|
|
50
|
-
|
|
78
|
+
case "text":
|
|
79
|
+
case "content-as-code": {
|
|
80
|
+
this.#renderContent();
|
|
51
81
|
break;
|
|
52
82
|
}
|
|
53
83
|
case "href": {
|
|
@@ -64,7 +94,11 @@ class Link extends NectaryElement {
|
|
|
64
94
|
}
|
|
65
95
|
case "standalone":
|
|
66
96
|
case "disabled": {
|
|
67
|
-
|
|
97
|
+
const isTrue = isAttrTrue(newVal);
|
|
98
|
+
updateBooleanAttribute(this, name, isTrue);
|
|
99
|
+
if (name === "disabled") {
|
|
100
|
+
this.#$button.disabled = isTrue;
|
|
101
|
+
}
|
|
68
102
|
break;
|
|
69
103
|
}
|
|
70
104
|
case "external": {
|
|
@@ -81,6 +115,12 @@ class Link extends NectaryElement {
|
|
|
81
115
|
set text(value) {
|
|
82
116
|
updateAttribute(this, "text", value);
|
|
83
117
|
}
|
|
118
|
+
get contentAsCode() {
|
|
119
|
+
return getBooleanAttribute(this, "content-as-code");
|
|
120
|
+
}
|
|
121
|
+
set contentAsCode(value) {
|
|
122
|
+
updateBooleanAttribute(this, "content-as-code", value);
|
|
123
|
+
}
|
|
84
124
|
get href() {
|
|
85
125
|
return getAttribute(this, "href", "");
|
|
86
126
|
}
|
|
@@ -117,15 +157,24 @@ class Link extends NectaryElement {
|
|
|
117
157
|
get preventDefault() {
|
|
118
158
|
return getBooleanAttribute(this, "preventdefault");
|
|
119
159
|
}
|
|
160
|
+
get #$activeElement() {
|
|
161
|
+
return this.preventDefault && !this["use-history"] ? this.#$button : this.#$anchor;
|
|
162
|
+
}
|
|
120
163
|
get focusable() {
|
|
121
164
|
return true;
|
|
122
165
|
}
|
|
123
166
|
focus() {
|
|
124
|
-
this.#$
|
|
167
|
+
this.#$activeElement.focus();
|
|
125
168
|
}
|
|
126
169
|
blur() {
|
|
127
|
-
this.#$
|
|
170
|
+
this.#$activeElement.blur();
|
|
128
171
|
}
|
|
172
|
+
#onButtonClick = () => {
|
|
173
|
+
if (this.disabled) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
this.dispatchEvent(new CustomEvent("-click"));
|
|
177
|
+
};
|
|
129
178
|
#onAnchorClick = (e) => {
|
|
130
179
|
if (this.preventDefault) {
|
|
131
180
|
e.preventDefault();
|
package/link/types.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export type TSinchLinkProps = {
|
|
|
14
14
|
standalone?: boolean;
|
|
15
15
|
/** Prevents default behaviour on hyperlink click */
|
|
16
16
|
preventDefault?: boolean;
|
|
17
|
+
/** Render link text as code (e.g. for Markdown `` [`word`](url) ``) */
|
|
18
|
+
contentAsCode?: boolean;
|
|
17
19
|
/** Label that is used for a11y – might be different from `text` */
|
|
18
20
|
'aria-label': string;
|
|
19
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nectary/components",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.19.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"**/*/*.css",
|
|
6
6
|
"**/*/*.json",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@babel/runtime": "^7.22.15",
|
|
27
|
-
"@nectary/assets": "3.
|
|
27
|
+
"@nectary/assets": "3.5.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@babel/cli": "^7.22.15",
|
package/readme.md
CHANGED
|
@@ -10,7 +10,7 @@ Design System's framework-agnostic Component Library implementation.
|
|
|
10
10
|
|
|
11
11
|
Add the component library dependency to `package.json`:
|
|
12
12
|
|
|
13
|
-
```
|
|
13
|
+
```bash
|
|
14
14
|
npm install @nectary/components
|
|
15
15
|
# or
|
|
16
16
|
yarn add @nectary/components
|
|
@@ -74,7 +74,7 @@ Use it in React/Vue/Angular/etc, for example:
|
|
|
74
74
|
<sinch-button value="Click me" onClick={() => console.log('click')}></sinch-button>
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
⚠️ Note
|
|
77
|
+
> ⚠️ Note: it's not allowed to self-close custom element tags.
|
|
78
78
|
|
|
79
79
|
## Testing
|
|
80
80
|
|
package/rich-text/index.js
CHANGED
|
@@ -110,6 +110,7 @@ class RichText extends NectaryElement {
|
|
|
110
110
|
#handleElementClick = (e) => {
|
|
111
111
|
const eventTarget = e.target;
|
|
112
112
|
const elementClickEvent = new CustomEvent("-element-click");
|
|
113
|
+
Object.defineProperty(elementClickEvent, "target", { value: eventTarget });
|
|
113
114
|
Object.defineProperty(elementClickEvent, "currentTarget", { value: eventTarget });
|
|
114
115
|
this.dispatchEvent(elementClickEvent);
|
|
115
116
|
};
|
package/rich-text/utils.js
CHANGED
|
@@ -24,14 +24,14 @@ const createParseVisitor = (doc) => {
|
|
|
24
24
|
let $li = null;
|
|
25
25
|
const $lists = [];
|
|
26
26
|
return {
|
|
27
|
-
// Add new escaped method to handle escaped characters
|
|
28
27
|
escaped(char) {
|
|
29
|
-
const $
|
|
28
|
+
const $inline = doc.createElement("SPAN");
|
|
29
|
+
$inline.append(doc.createTextNode(char));
|
|
30
30
|
if ($p != null) {
|
|
31
|
-
$p.appendChild($
|
|
31
|
+
$p.appendChild($inline);
|
|
32
32
|
} else {
|
|
33
33
|
this.paragraph();
|
|
34
|
-
$p.appendChild($
|
|
34
|
+
$p.appendChild($inline);
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
emoji(emojiChar) {
|
|
@@ -46,6 +46,9 @@ const createParseVisitor = (doc) => {
|
|
|
46
46
|
$codeTag.text = text;
|
|
47
47
|
$p.appendChild($codeTag);
|
|
48
48
|
},
|
|
49
|
+
linkPlaceholder(_name) {
|
|
50
|
+
return false;
|
|
51
|
+
},
|
|
49
52
|
tag(text) {
|
|
50
53
|
const $chip = doc.createElement("sinch-rich-textarea-chip");
|
|
51
54
|
const resolved = chipResolver?.(text);
|
|
@@ -61,6 +64,9 @@ const createParseVisitor = (doc) => {
|
|
|
61
64
|
}
|
|
62
65
|
$p.appendChild($chip);
|
|
63
66
|
},
|
|
67
|
+
buttonPlaceholder(name) {
|
|
68
|
+
this.inline(`[[${name}]]`, {});
|
|
69
|
+
},
|
|
64
70
|
inline(text, { isBold, isItalic, isStrikethrough }) {
|
|
65
71
|
const $inline = doc.createElement("SPAN");
|
|
66
72
|
$inline.append(doc.createTextNode(text));
|
|
@@ -79,10 +85,13 @@ const createParseVisitor = (doc) => {
|
|
|
79
85
|
const $br = doc.createElement("br");
|
|
80
86
|
$p.appendChild($br);
|
|
81
87
|
},
|
|
82
|
-
link(text, href, attributes) {
|
|
88
|
+
link(text, href, attributes, isCode) {
|
|
83
89
|
const $link = doc.createElement("sinch-link");
|
|
84
90
|
$link.text = text;
|
|
85
91
|
$link.href = href;
|
|
92
|
+
if (isCode === true) {
|
|
93
|
+
$link.contentAsCode = true;
|
|
94
|
+
}
|
|
86
95
|
if (attributes != null) {
|
|
87
96
|
attributes.forEach((attr) => {
|
|
88
97
|
if (attr.startsWith("#")) {
|
package/rich-textarea/utils.js
CHANGED
|
@@ -176,14 +176,28 @@ const copyFormatName = ($source, $target) => {
|
|
|
176
176
|
$target.className = $inline.className;
|
|
177
177
|
if (isFormatLink($inline)) {
|
|
178
178
|
$target.setAttribute(LINK_HREF_ATTR_NAME, $inline.getAttribute(LINK_HREF_ATTR_NAME) ?? "");
|
|
179
|
+
} else {
|
|
180
|
+
$target.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
179
181
|
}
|
|
180
182
|
};
|
|
181
183
|
const setInlineFormat = ($n, formatName, shouldEnable) => {
|
|
182
184
|
if (shouldEnable) {
|
|
183
|
-
if (formatName === "c"
|
|
184
|
-
$n
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
if (formatName === "c") {
|
|
186
|
+
if (isFormatName($n, "l")) {
|
|
187
|
+
$n.className = "l";
|
|
188
|
+
} else {
|
|
189
|
+
$n.className = "";
|
|
190
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
191
|
+
}
|
|
192
|
+
} else if (formatName === "l") {
|
|
193
|
+
if (!isFormatName($n, "c")) {
|
|
194
|
+
$n.className = "";
|
|
195
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
196
|
+
} else {
|
|
197
|
+
$n.className = "c";
|
|
198
|
+
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
199
|
+
}
|
|
200
|
+
} else if (isFormatName($n, "c") || isFormatName($n, "l")) {
|
|
187
201
|
$n.className = "";
|
|
188
202
|
$n.removeAttribute(LINK_HREF_ATTR_NAME);
|
|
189
203
|
}
|
|
@@ -224,14 +238,14 @@ const areSameInlineFormat = ($a, $b) => {
|
|
|
224
238
|
if ($a.classList.length !== $b.classList.length) {
|
|
225
239
|
return false;
|
|
226
240
|
}
|
|
227
|
-
if ($a.className === "l") {
|
|
228
|
-
return $b.className === "l" && $a.getAttribute(LINK_HREF_ATTR_NAME) === $b.getAttribute(LINK_HREF_ATTR_NAME);
|
|
229
|
-
}
|
|
230
241
|
for (let i = 0; i < $a.classList.length; i++) {
|
|
231
242
|
if (!$b.classList.contains($a.classList[i])) {
|
|
232
243
|
return false;
|
|
233
244
|
}
|
|
234
245
|
}
|
|
246
|
+
if ($a.classList.contains("l")) {
|
|
247
|
+
return $a.getAttribute(LINK_HREF_ATTR_NAME) === $b.getAttribute(LINK_HREF_ATTR_NAME);
|
|
248
|
+
}
|
|
235
249
|
return true;
|
|
236
250
|
};
|
|
237
251
|
const createInlineWithText = (data, doc) => {
|
|
@@ -1511,6 +1525,11 @@ const serializeDescriptorReducer = (range) => (state, $n) => {
|
|
|
1511
1525
|
if (isEmptyText(text)) {
|
|
1512
1526
|
return state;
|
|
1513
1527
|
}
|
|
1528
|
+
if (isFormatCodetag($n) && isFormatLink($n)) {
|
|
1529
|
+
const href = $n.getAttribute(LINK_HREF_ATTR_NAME) ?? "#";
|
|
1530
|
+
state.push({ isCodetag: true, isLink: true, text, href });
|
|
1531
|
+
return state;
|
|
1532
|
+
}
|
|
1514
1533
|
if (isFormatCodetag($n)) {
|
|
1515
1534
|
state.push({ isCodetag: true, text });
|
|
1516
1535
|
return state;
|
|
@@ -1561,7 +1580,8 @@ const MD_PARAGRAPH_JOIN = "\n\n";
|
|
|
1561
1580
|
const serializeTextReducer = (state, desc, i, descArray) => {
|
|
1562
1581
|
const { chunks } = state;
|
|
1563
1582
|
if (desc.isLink === true) {
|
|
1564
|
-
|
|
1583
|
+
const inner = desc.isCodetag === true ? `${MD_CODETAG_TOKEN}${desc.text}${MD_CODETAG_TOKEN}` : desc.text;
|
|
1584
|
+
chunks.push(`[${inner}](${desc.href})`);
|
|
1565
1585
|
return state;
|
|
1566
1586
|
}
|
|
1567
1587
|
if (desc.isEmoji === true) {
|
|
@@ -1742,12 +1762,12 @@ const createParseVisitor = (doc) => {
|
|
|
1742
1762
|
let isFirstListItem = false;
|
|
1743
1763
|
return {
|
|
1744
1764
|
escaped(char) {
|
|
1745
|
-
const $
|
|
1765
|
+
const $inline = createInlineWithText(char, doc);
|
|
1746
1766
|
if ($currentBlock != null) {
|
|
1747
|
-
$currentBlock.appendChild($
|
|
1767
|
+
$currentBlock.appendChild($inline);
|
|
1748
1768
|
} else {
|
|
1749
1769
|
this.paragraph();
|
|
1750
|
-
$currentBlock.appendChild($
|
|
1770
|
+
$currentBlock.appendChild($inline);
|
|
1751
1771
|
}
|
|
1752
1772
|
},
|
|
1753
1773
|
emoji(emojiChar) {
|
|
@@ -1759,11 +1779,18 @@ const createParseVisitor = (doc) => {
|
|
|
1759
1779
|
setInlineFormat($inline, "c", true);
|
|
1760
1780
|
$currentBlock.appendChild($inline);
|
|
1761
1781
|
},
|
|
1782
|
+
linkPlaceholder(_name) {
|
|
1783
|
+
return false;
|
|
1784
|
+
},
|
|
1762
1785
|
tag(text) {
|
|
1763
1786
|
const resolved = chipResolver?.(text);
|
|
1764
1787
|
const $tag = createTag(text, doc, resolved?.color ?? chipColor, resolved?.icon ?? chipIcon);
|
|
1765
1788
|
$currentBlock.appendChild($tag);
|
|
1766
1789
|
},
|
|
1790
|
+
buttonPlaceholder(name) {
|
|
1791
|
+
const $inline = createInlineWithText(`[[${name}]]`, doc);
|
|
1792
|
+
$currentBlock.appendChild($inline);
|
|
1793
|
+
},
|
|
1767
1794
|
inline(text, { isBold, isItalic, isStrikethrough }) {
|
|
1768
1795
|
const $inline = createInlineWithText(text, doc);
|
|
1769
1796
|
setInlineFormat($inline, "b", isBold === true);
|
|
@@ -1777,8 +1804,11 @@ const createParseVisitor = (doc) => {
|
|
|
1777
1804
|
$root.appendChild($currentBlock);
|
|
1778
1805
|
}
|
|
1779
1806
|
},
|
|
1780
|
-
link(text, href) {
|
|
1807
|
+
link(text, href, _attributes, isCode) {
|
|
1781
1808
|
const $link = createLink(text, href, doc);
|
|
1809
|
+
if (isCode === true) {
|
|
1810
|
+
setInlineFormat($link, "c", true);
|
|
1811
|
+
}
|
|
1782
1812
|
$currentBlock.appendChild($link);
|
|
1783
1813
|
},
|
|
1784
1814
|
list(isOrdered) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const BASE_COMPONENT_NAMES_LIST: readonly ["accordion-item", "accordion", "action-menu-option", "action-menu", "alert", "avatar", "badge", "button-group-item", "button-group", "button", "card-container", "card-v2-title", "card-v2", "checkbox", "chip", "code-tag", "color-menu-option", "color-menu", "color-swatch", "date-picker", "dialog", "emoji-picker", "emoji", "field", "file-drop", "file-picker", "file-status", "flag", "grid-item", "grid", "help-tooltip", "icon", "inline-alert", "input", "link", "list-item", "list", "pagination", "persistent-overlay", "pop", "popover", "progress-stepper-item", "progress-stepper", "progress", "radio-option", "radio", "rich-text", "rich-textarea", "rich-textarea-chip", "segment-collapse", "segmented-control-option", "segmented-control", "segmented-icon-control-option", "segmented-icon-control", "select-button", "select-menu-option", "select-menu", "sheet", "sheet-title", "skeleton-item", "skeleton", "spinner", "stop-events", "table-body", "table-cell", "table-head-cell", "table-head", "table-row", "table", "tabs-icon-option", "tabs-option", "tabs", "tag", "text", "textarea", "time-picker", "title", "toast-manager", "toast", "toggle", "tooltip"];
|
|
2
|
-
export declare const BASE_COMPONENT_NAMES: Set<"pop" | "button" | "dialog" | "input" | "link" | "progress" | "table" | "textarea" | "title" | "accordion-item" | "accordion" | "action-menu-option" | "action-menu" | "alert" | "avatar" | "badge" | "button-group-item" | "button-group" | "card-container" | "card-v2-title" | "card-v2" | "checkbox" | "chip" | "code-tag" | "color-menu-option" | "color-menu" | "color-swatch" | "date-picker" | "emoji-picker" | "emoji" | "field" | "file-drop" | "file-picker" | "file-status" | "flag" | "grid-item" | "grid" | "help-tooltip" | "icon" | "inline-alert" | "list-item" | "list" | "pagination" | "persistent-overlay" | "popover" | "progress-stepper-item" | "progress-stepper" | "radio-option" | "radio" | "rich-text" | "rich-textarea" | "rich-textarea-chip" | "segment-collapse" | "segmented-control-option" | "segmented-control" | "segmented-icon-control-option" | "segmented-icon-control" | "select-button" | "select-menu-option" | "select-menu" | "sheet" | "sheet-title" | "skeleton-item" | "skeleton" | "spinner" | "stop-events" | "table-body" | "table-cell" | "table-head-cell" | "table-head" | "table-row" | "tabs-icon-option" | "tabs-option" | "tabs" | "tag" | "text" | "time-picker" | "toast-manager" | "toast" | "toggle" | "tooltip">;
|
|
1
|
+
export declare const BASE_COMPONENT_NAMES_LIST: readonly ["accordion-item", "accordion", "action-menu-option", "action-menu", "alert", "avatar", "badge", "button-group-item", "button-group", "button", "card-container", "card-v2-title", "card-v2", "checkbox", "chip", "code-tag", "color-menu-option", "color-menu", "color-swatch", "date-picker", "dialog", "emoji-picker", "emoji", "field", "field-v2", "file-drop", "file-picker", "file-status", "flag", "grid-item", "grid", "help-tooltip", "icon", "inline-alert", "input", "link", "list-item", "list", "pagination", "persistent-overlay", "pop", "popover", "progress-stepper-item", "progress-stepper", "progress", "radio-option", "radio", "rich-text", "rich-textarea", "rich-textarea-chip", "segment-collapse", "segmented-control-option", "segmented-control", "segmented-icon-control-option", "segmented-icon-control", "select-button", "select-menu-option", "select-menu", "sheet", "sheet-title", "skeleton-item", "skeleton", "spinner", "stop-events", "table-body", "table-cell", "table-head-cell", "table-head", "table-row", "table", "tabs-icon-option", "tabs-option", "tabs", "tag", "text", "textarea", "time-picker", "title", "toast-manager", "toast", "toggle", "tooltip"];
|
|
2
|
+
export declare const BASE_COMPONENT_NAMES: Set<"pop" | "button" | "dialog" | "input" | "link" | "progress" | "table" | "textarea" | "title" | "accordion-item" | "accordion" | "action-menu-option" | "action-menu" | "alert" | "avatar" | "badge" | "button-group-item" | "button-group" | "card-container" | "card-v2-title" | "card-v2" | "checkbox" | "chip" | "code-tag" | "color-menu-option" | "color-menu" | "color-swatch" | "date-picker" | "emoji-picker" | "emoji" | "field" | "field-v2" | "file-drop" | "file-picker" | "file-status" | "flag" | "grid-item" | "grid" | "help-tooltip" | "icon" | "inline-alert" | "list-item" | "list" | "pagination" | "persistent-overlay" | "popover" | "progress-stepper-item" | "progress-stepper" | "radio-option" | "radio" | "rich-text" | "rich-textarea" | "rich-textarea-chip" | "segment-collapse" | "segmented-control-option" | "segmented-control" | "segmented-icon-control-option" | "segmented-icon-control" | "select-button" | "select-menu-option" | "select-menu" | "sheet" | "sheet-title" | "skeleton-item" | "skeleton" | "spinner" | "stop-events" | "table-body" | "table-cell" | "table-head-cell" | "table-head" | "table-row" | "tabs-icon-option" | "tabs-option" | "tabs" | "tag" | "text" | "time-picker" | "toast-manager" | "toast" | "toggle" | "tooltip">;
|
|
3
3
|
export type ComponentName = `sinch-${typeof BASE_COMPONENT_NAMES_LIST[number]}`;
|
package/utils/component-names.js
CHANGED
package/utils/element.d.ts
CHANGED
package/utils/markdown.d.ts
CHANGED
|
@@ -5,10 +5,13 @@ export type TMarkdownInlineParams = {
|
|
|
5
5
|
};
|
|
6
6
|
export type TMarkdownParseVisitor = {
|
|
7
7
|
escaped(char: string): void;
|
|
8
|
-
link(text: string, href: string, attributes?: string[]): void;
|
|
8
|
+
link(text: string, href: string, attributes?: string[], isCode?: boolean): void;
|
|
9
9
|
emoji(emojiChar: string): void;
|
|
10
10
|
codetag(text: string): void;
|
|
11
|
+
/** Returns true if placeholder was handled as a link; false to fall through to tag (chip). */
|
|
12
|
+
linkPlaceholder(name: string): boolean;
|
|
11
13
|
tag(username: string): void;
|
|
14
|
+
buttonPlaceholder(name: string): void;
|
|
12
15
|
inline(text: string, params: TMarkdownInlineParams): void;
|
|
13
16
|
linebreak(): void;
|
|
14
17
|
paragraph(): void;
|
package/utils/markdown.js
CHANGED
|
@@ -8,6 +8,7 @@ const regEm2Underscore = new RegExp("(?<!\\\\)__(?<em2>.+?)(?<!\\\\)__");
|
|
|
8
8
|
const regEm1Underscore = new RegExp("(?<!\\\\)_(?<em1>.+?)(?<!\\\\)_");
|
|
9
9
|
const regCodeTag = new RegExp("(?<!\\\\)`(?<code>.+?)(?<!\\\\)`");
|
|
10
10
|
const regStrikethrough = new RegExp("(?<!\\\\)~~(?<strike>.+?)(?<!\\\\)~~");
|
|
11
|
+
const regButtonPlaceholder = new RegExp("(?<!\\\\)\\[\\[(?<button>[a-zA-Z0-9_-]+)\\]\\]");
|
|
11
12
|
const regLink = new RegExp("(?<!\\\\)!?\\[(?<linktext>[^\\]]*?)\\]\\((?<linkhref>[^)]+?)\\)(\\{(?<linkattrs>[^)]+?)\\})?");
|
|
12
13
|
const regChip = new RegExp("(?<!\\\\)\\{\\{(?<chip>[a-zA-Z0-9_-]+)\\}\\}");
|
|
13
14
|
const regEmoji = new RegExp("(?<emoji>(?![0-9*#])\\p{Emoji})", "u");
|
|
@@ -17,6 +18,7 @@ const regEscapedChars = /\\(?<escaped>[\\\*_\[\]`~\{\}])/;
|
|
|
17
18
|
const allRegs = [
|
|
18
19
|
regEscapedChars,
|
|
19
20
|
regCodeTag,
|
|
21
|
+
regButtonPlaceholder,
|
|
20
22
|
regLink,
|
|
21
23
|
regChip,
|
|
22
24
|
regEm3Star,
|
|
@@ -60,13 +62,23 @@ const createLineParser = (visitor) => function parseLine(regs, md, context = INI
|
|
|
60
62
|
visitor.escaped(groups.escaped);
|
|
61
63
|
continue;
|
|
62
64
|
}
|
|
65
|
+
if (groups?.button != null) {
|
|
66
|
+
visitor.buttonPlaceholder(groups.button);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
63
69
|
if (groups?.linkhref != null) {
|
|
64
|
-
|
|
70
|
+
const rawText = groups.linktext;
|
|
71
|
+
const isCode = rawText.length >= 2 && rawText.startsWith("`") && rawText.endsWith("`") && !rawText.slice(1, -1).includes("`");
|
|
72
|
+
const linkText = isCode ? rawText.slice(1, -1) : rawText;
|
|
73
|
+
visitor.link(linkText, groups.linkhref, groups.linkattrs?.split(" "), isCode);
|
|
65
74
|
}
|
|
66
75
|
if (groups?.code != null) {
|
|
67
76
|
visitor.codetag(groups.code);
|
|
68
77
|
}
|
|
69
78
|
if (groups?.chip != null) {
|
|
79
|
+
if (visitor.linkPlaceholder(groups.chip)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
70
82
|
visitor.tag(groups.chip);
|
|
71
83
|
}
|
|
72
84
|
if (groups?.emoji != null) {
|