@kodaris/krubble-app-components 1.0.67 → 1.0.68
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/dist/chatbot.d.ts +36 -27
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +429 -321
- package/dist/chatbot.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/krubble-app.bundled.js +3200 -521
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +395 -298
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +3198 -519
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +395 -298
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/dist/router.d.ts +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +8 -2
- package/dist/router.js.map +1 -1
- package/dist/scaffold/nav-item-edit.d.ts.map +1 -1
- package/dist/scaffold/nav-item-edit.js.map +1 -1
- package/dist/scaffold.d.ts +12 -12
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +196 -92
- package/dist/scaffold.js.map +1 -1
- package/dist/screen-detail.js +2 -2
- package/dist/screen-nav.d.ts +4 -4
- package/dist/screen-nav.d.ts.map +1 -1
- package/dist/screen-nav.js +14 -10
- package/dist/screen-nav.js.map +1 -1
- package/dist/subbar.d.ts.map +1 -1
- package/dist/subbar.js +43 -10
- package/dist/subbar.js.map +1 -1
- package/package.json +4 -3
|
@@ -356,18 +356,6 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
356
356
|
* Default icon for nav items without an icon (shown at top level)
|
|
357
357
|
*/
|
|
358
358
|
this.defaultNavItemIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="10"/></svg>';
|
|
359
|
-
this.navItemsExpanded = new Set();
|
|
360
|
-
this.navQuery = '';
|
|
361
|
-
this.activeNavItemId = null;
|
|
362
|
-
this.isNavScrolled = false;
|
|
363
|
-
this.isNavOpened = localStorage.getItem('kr-scaffold-nav-opened') !== 'false';
|
|
364
|
-
this.isEditing = false;
|
|
365
|
-
this.isUserMenuOpen = false;
|
|
366
|
-
this.pref = { nav: {} };
|
|
367
|
-
this.draggedNavItemId = null;
|
|
368
|
-
this.navItemDropTargetId = null;
|
|
369
|
-
this.navItemDropPosition = 'above';
|
|
370
|
-
this.pendingRequests = 0;
|
|
371
359
|
this.originalFetch = null;
|
|
372
360
|
this.originalXhrOpen = null;
|
|
373
361
|
this.navItemDragPreview = null;
|
|
@@ -403,6 +391,18 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
403
391
|
* Breadcrumbs to display in the subbar
|
|
404
392
|
*/
|
|
405
393
|
this.breadcrumbs = [];
|
|
394
|
+
this.navItemsExpanded = new Set();
|
|
395
|
+
this.navQuery = '';
|
|
396
|
+
this.activeNavItemId = null;
|
|
397
|
+
this.isNavScrolled = false;
|
|
398
|
+
this.isNavOpened = localStorage.getItem('kr-scaffold-nav-opened') !== 'false';
|
|
399
|
+
this.isEditing = false;
|
|
400
|
+
this.isUserMenuOpen = false;
|
|
401
|
+
this.pref = { nav: {} };
|
|
402
|
+
this.draggedNavItemId = null;
|
|
403
|
+
this.navItemDropTargetId = null;
|
|
404
|
+
this.navItemDropPosition = 'above';
|
|
405
|
+
this.pendingRequests = 0;
|
|
406
406
|
this.boundHandleMouseMove = this.handleMouseMove.bind(this);
|
|
407
407
|
this.boundHandleMouseUp = this.handleMouseUp.bind(this);
|
|
408
408
|
}
|
|
@@ -436,8 +436,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
436
436
|
* Updates `pendingRequests` state when requests start/complete.
|
|
437
437
|
*/
|
|
438
438
|
installFetchInterceptor() {
|
|
439
|
-
if (this.originalFetch)
|
|
439
|
+
if (this.originalFetch) {
|
|
440
440
|
return;
|
|
441
|
+
}
|
|
441
442
|
const scaffold = this;
|
|
442
443
|
// Intercept fetch
|
|
443
444
|
this.originalFetch = window.fetch.bind(window);
|
|
@@ -488,17 +489,23 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
488
489
|
* - resolveUrl(item) = "/operations/settings" (used for href and URL comparison)
|
|
489
490
|
*/
|
|
490
491
|
resolveUrl(item) {
|
|
491
|
-
if (!item.url)
|
|
492
|
+
if (!item.url) {
|
|
492
493
|
return '#';
|
|
494
|
+
}
|
|
493
495
|
// External URLs - return as-is
|
|
494
496
|
if (item.external) {
|
|
495
497
|
return item.url;
|
|
496
498
|
}
|
|
497
499
|
// Remove leading slash from url if present, then combine with base
|
|
498
|
-
|
|
500
|
+
let path = item.url;
|
|
501
|
+
if (item.url.startsWith('/')) {
|
|
502
|
+
path = item.url.slice(1);
|
|
503
|
+
}
|
|
499
504
|
const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
|
|
500
|
-
|
|
501
|
-
|
|
505
|
+
if (baseHref.endsWith('/')) {
|
|
506
|
+
return baseHref + path;
|
|
507
|
+
}
|
|
508
|
+
return baseHref + '/' + path;
|
|
502
509
|
}
|
|
503
510
|
// =========================================================================
|
|
504
511
|
// Navigation Data
|
|
@@ -527,11 +534,15 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
527
534
|
if (item.type === 'group' && item.children) {
|
|
528
535
|
item.children.forEach((child, childIndex) => {
|
|
529
536
|
const childOverride = this.pref.nav[child.id];
|
|
537
|
+
let parentId = item.id;
|
|
538
|
+
if (childOverride?.parentId !== undefined) {
|
|
539
|
+
parentId = childOverride.parentId;
|
|
540
|
+
}
|
|
530
541
|
result.push({
|
|
531
542
|
...child,
|
|
532
543
|
...childOverride,
|
|
533
544
|
order: childOverride?.order ?? child.order ?? childIndex,
|
|
534
|
-
parentId
|
|
545
|
+
parentId,
|
|
535
546
|
});
|
|
536
547
|
});
|
|
537
548
|
}
|
|
@@ -674,14 +685,18 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
674
685
|
toggleNavItem(itemId) {
|
|
675
686
|
const navItem = this.shadowRoot?.querySelector(`.nav-item[data-id="${itemId}"]`);
|
|
676
687
|
const groupEl = navItem?.nextElementSibling;
|
|
677
|
-
if (!groupEl)
|
|
688
|
+
if (!groupEl) {
|
|
678
689
|
return;
|
|
690
|
+
}
|
|
679
691
|
if (this.navItemsExpanded.has(itemId)) {
|
|
680
692
|
this.navItemsExpanded.delete(itemId);
|
|
681
693
|
groupEl.animate([
|
|
682
694
|
{ height: `${groupEl.scrollHeight}px` },
|
|
683
695
|
{ height: '0px' }
|
|
684
|
-
], {
|
|
696
|
+
], {
|
|
697
|
+
duration: 300,
|
|
698
|
+
easing: 'ease-in-out'
|
|
699
|
+
}).onfinish = () => {
|
|
685
700
|
groupEl.classList.remove('nav-group--expanded');
|
|
686
701
|
};
|
|
687
702
|
}
|
|
@@ -691,7 +706,10 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
691
706
|
groupEl.animate([
|
|
692
707
|
{ height: '0px' },
|
|
693
708
|
{ height: `${groupEl.scrollHeight}px` }
|
|
694
|
-
], {
|
|
709
|
+
], {
|
|
710
|
+
duration: 300,
|
|
711
|
+
easing: 'ease-in-out'
|
|
712
|
+
});
|
|
695
713
|
}
|
|
696
714
|
this.requestUpdate();
|
|
697
715
|
}
|
|
@@ -786,14 +804,18 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
786
804
|
this.pref.nav = {};
|
|
787
805
|
}
|
|
788
806
|
savePref() {
|
|
789
|
-
if (this.userType === 'customer')
|
|
807
|
+
if (this.userType === 'customer') {
|
|
790
808
|
return;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
809
|
+
}
|
|
810
|
+
let url = '/api/system/preference/json/scaffold?global=true';
|
|
811
|
+
let method = 'POST';
|
|
812
|
+
if (this.pref.uuid) {
|
|
813
|
+
url = `/api/system/preference/json/scaffold/${this.pref.uuid}?global=true`;
|
|
814
|
+
method = 'PUT';
|
|
815
|
+
}
|
|
794
816
|
KRHttp.fetch({
|
|
795
817
|
url,
|
|
796
|
-
method
|
|
818
|
+
method,
|
|
797
819
|
body: JSON.stringify({ nav: this.pref.nav }),
|
|
798
820
|
})
|
|
799
821
|
.then((response) => response.json())
|
|
@@ -806,8 +828,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
806
828
|
});
|
|
807
829
|
}
|
|
808
830
|
loadPref() {
|
|
809
|
-
if (this.userType === 'customer')
|
|
831
|
+
if (this.userType === 'customer') {
|
|
810
832
|
return;
|
|
833
|
+
}
|
|
811
834
|
KRHttp.fetch({
|
|
812
835
|
url: '/api/system/preference/json/scaffold?global=true',
|
|
813
836
|
method: 'GET',
|
|
@@ -824,21 +847,36 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
824
847
|
});
|
|
825
848
|
}
|
|
826
849
|
handleNavItemContextMenu(e, item) {
|
|
827
|
-
if (!this.isEditing)
|
|
850
|
+
if (!this.isEditing) {
|
|
828
851
|
return;
|
|
852
|
+
}
|
|
829
853
|
e.preventDefault();
|
|
830
854
|
KRContextMenu.open({
|
|
831
855
|
x: e.clientX,
|
|
832
856
|
y: e.clientY,
|
|
833
857
|
items: [
|
|
834
|
-
{
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
858
|
+
{
|
|
859
|
+
id: 'edit',
|
|
860
|
+
label: 'Edit Item'
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
id: 'divider-1',
|
|
864
|
+
label: '',
|
|
865
|
+
divider: true
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
id: 'add-above',
|
|
869
|
+
label: 'Add Item Above'
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
id: 'add-below',
|
|
873
|
+
label: 'Add Item Below'
|
|
874
|
+
},
|
|
838
875
|
],
|
|
839
876
|
}).then((result) => {
|
|
840
|
-
if (!result)
|
|
877
|
+
if (!result) {
|
|
841
878
|
return;
|
|
879
|
+
}
|
|
842
880
|
switch (result.id) {
|
|
843
881
|
case 'edit':
|
|
844
882
|
this.openNavItemEdit(item);
|
|
@@ -864,8 +902,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
864
902
|
openNavItemEdit(item) {
|
|
865
903
|
KRDialog.open(KRNavItemEdit, { data: item }).afterClosed().then((res) => {
|
|
866
904
|
const result = res;
|
|
867
|
-
if (!result)
|
|
905
|
+
if (!result) {
|
|
868
906
|
return;
|
|
907
|
+
}
|
|
869
908
|
if (!this.pref.nav[item.id]) {
|
|
870
909
|
this.pref.nav[item.id] = {};
|
|
871
910
|
}
|
|
@@ -892,7 +931,13 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
892
931
|
.filter(i => i.parentId === targetItem.parentId)
|
|
893
932
|
.sort((a, b) => a.order - b.order);
|
|
894
933
|
const targetIndex = siblings.findIndex(i => i.id === targetItem.id);
|
|
895
|
-
|
|
934
|
+
let newOrder;
|
|
935
|
+
if (position === 'above') {
|
|
936
|
+
newOrder = targetIndex;
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
newOrder = targetIndex + 1;
|
|
940
|
+
}
|
|
896
941
|
// Shift existing items to make room for the new item
|
|
897
942
|
siblings.forEach((sibling, index) => {
|
|
898
943
|
if (index >= newOrder) {
|
|
@@ -929,8 +974,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
929
974
|
* @param item - The nav item being pressed
|
|
930
975
|
*/
|
|
931
976
|
handleNavItemMouseDown(e, item) {
|
|
932
|
-
if (!this.isEditing)
|
|
977
|
+
if (!this.isEditing) {
|
|
933
978
|
return;
|
|
979
|
+
}
|
|
934
980
|
e.preventDefault();
|
|
935
981
|
this.draggedNavItemId = item.id;
|
|
936
982
|
this.navItemDragStartY = e.clientY;
|
|
@@ -948,8 +994,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
948
994
|
* @param e - The mouse event
|
|
949
995
|
*/
|
|
950
996
|
handleMouseMove(e) {
|
|
951
|
-
if (!this.draggedNavItemId)
|
|
997
|
+
if (!this.draggedNavItemId) {
|
|
952
998
|
return;
|
|
999
|
+
}
|
|
953
1000
|
// Start dragging after moving a few pixels (to distinguish from clicks)
|
|
954
1001
|
if (!this.isNavItemDragging && Math.abs(e.clientY - this.navItemDragStartY) > 5) {
|
|
955
1002
|
this.isNavItemDragging = true;
|
|
@@ -965,8 +1012,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
965
1012
|
this.shadowRoot?.appendChild(this.navItemDragPreview);
|
|
966
1013
|
}
|
|
967
1014
|
}
|
|
968
|
-
if (!this.isNavItemDragging)
|
|
1015
|
+
if (!this.isNavItemDragging) {
|
|
969
1016
|
return;
|
|
1017
|
+
}
|
|
970
1018
|
// Update preview position
|
|
971
1019
|
if (this.navItemDragPreview) {
|
|
972
1020
|
this.navItemDragPreview.style.left = `${e.clientX + 10}px`;
|
|
@@ -1017,14 +1065,16 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1017
1065
|
updateNavItemDropTarget(e) {
|
|
1018
1066
|
// Get all nav items in shadow DOM
|
|
1019
1067
|
const navItems = this.shadowRoot?.querySelectorAll('.nav-item[data-id]');
|
|
1020
|
-
if (!navItems)
|
|
1068
|
+
if (!navItems) {
|
|
1021
1069
|
return;
|
|
1070
|
+
}
|
|
1022
1071
|
let foundTarget = false;
|
|
1023
1072
|
navItems.forEach((el) => {
|
|
1024
1073
|
const rect = el.getBoundingClientRect();
|
|
1025
1074
|
const itemId = el.getAttribute('data-id');
|
|
1026
|
-
if (!itemId || itemId === this.draggedNavItemId)
|
|
1075
|
+
if (!itemId || itemId === this.draggedNavItemId) {
|
|
1027
1076
|
return;
|
|
1077
|
+
}
|
|
1028
1078
|
// Skip if mouse is outside this element
|
|
1029
1079
|
if (e.clientX < rect.left || e.clientX > rect.right ||
|
|
1030
1080
|
e.clientY < rect.top || e.clientY > rect.bottom) {
|
|
@@ -1061,11 +1111,22 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1061
1111
|
}
|
|
1062
1112
|
else {
|
|
1063
1113
|
// Regular items only support above/below, not center
|
|
1064
|
-
|
|
1114
|
+
if (y < rect.height / 2) {
|
|
1115
|
+
position = 'above';
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
position = 'below';
|
|
1119
|
+
}
|
|
1065
1120
|
this.clearNavItemDragExpandTimeout();
|
|
1066
1121
|
}
|
|
1067
1122
|
// Determine what the new parent would be
|
|
1068
|
-
|
|
1123
|
+
let newParentId;
|
|
1124
|
+
if (position === 'center') {
|
|
1125
|
+
newParentId = item.id;
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
newParentId = item.parentId;
|
|
1129
|
+
}
|
|
1069
1130
|
const draggedItem = this.getComputedNav().find(i => i.id === this.draggedNavItemId);
|
|
1070
1131
|
// Don't show drop indicator if invalid drop:
|
|
1071
1132
|
// 1. Can't drop an item into itself (newParentId === draggedNavItemId)
|
|
@@ -1125,13 +1186,15 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1125
1186
|
* with new order values for the dragged item and shifts siblings as needed.
|
|
1126
1187
|
*/
|
|
1127
1188
|
executeNavItemDrop() {
|
|
1128
|
-
if (!this.draggedNavItemId || !this.navItemDropTargetId)
|
|
1189
|
+
if (!this.draggedNavItemId || !this.navItemDropTargetId) {
|
|
1129
1190
|
return;
|
|
1191
|
+
}
|
|
1130
1192
|
const allItems = this.getComputedNav();
|
|
1131
1193
|
const draggedItem = allItems.find(i => i.id === this.draggedNavItemId);
|
|
1132
1194
|
const targetItem = allItems.find(i => i.id === this.navItemDropTargetId);
|
|
1133
|
-
if (!draggedItem || !targetItem)
|
|
1195
|
+
if (!draggedItem || !targetItem) {
|
|
1134
1196
|
return;
|
|
1197
|
+
}
|
|
1135
1198
|
// Determine the new parentId for the dragged item
|
|
1136
1199
|
let newParentId;
|
|
1137
1200
|
if (this.navItemDropPosition === 'center' && targetItem.type === 'group') {
|
|
@@ -1143,8 +1206,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1143
1206
|
else {
|
|
1144
1207
|
newParentId = targetItem.parentId;
|
|
1145
1208
|
}
|
|
1146
|
-
if (newParentId === this.draggedNavItemId)
|
|
1209
|
+
if (newParentId === this.draggedNavItemId) {
|
|
1147
1210
|
return;
|
|
1211
|
+
}
|
|
1148
1212
|
// Get siblings in the destination parent
|
|
1149
1213
|
const siblings = allItems
|
|
1150
1214
|
.filter(i => i.parentId === newParentId && i.id !== this.draggedNavItemId)
|
|
@@ -1215,8 +1279,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1215
1279
|
// Rendering
|
|
1216
1280
|
// =========================================================================
|
|
1217
1281
|
renderNormalFooter() {
|
|
1218
|
-
if (!this.user)
|
|
1282
|
+
if (!this.user) {
|
|
1219
1283
|
return A;
|
|
1284
|
+
}
|
|
1220
1285
|
const initials = this.user.name
|
|
1221
1286
|
.split(' ')
|
|
1222
1287
|
.map((part) => part[0])
|
|
@@ -1313,7 +1378,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1313
1378
|
stroke="currentColor"
|
|
1314
1379
|
stroke-width="2"
|
|
1315
1380
|
>
|
|
1316
|
-
<path
|
|
1381
|
+
<path
|
|
1382
|
+
d="M6 9l6 6 6-6"
|
|
1383
|
+
stroke-linecap="round"
|
|
1384
|
+
stroke-linejoin="round"
|
|
1385
|
+
/>
|
|
1317
1386
|
</svg>
|
|
1318
1387
|
</button>
|
|
1319
1388
|
<div class=${e({
|
|
@@ -1365,7 +1434,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1365
1434
|
</div>
|
|
1366
1435
|
|
|
1367
1436
|
${this.subbar ? b `
|
|
1368
|
-
<kr-subbar
|
|
1437
|
+
<kr-subbar
|
|
1438
|
+
menu
|
|
1439
|
+
.breadcrumbs=${this.breadcrumbs}
|
|
1440
|
+
@menu-click=${this.handleMenuClick}
|
|
1441
|
+
>
|
|
1369
1442
|
<slot name="subbar"></slot>
|
|
1370
1443
|
</kr-subbar>
|
|
1371
1444
|
` : A}
|
|
@@ -1381,7 +1454,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1381
1454
|
${this.label
|
|
1382
1455
|
? b `<span class="nav-title">${this.label}</span>`
|
|
1383
1456
|
: this.logo
|
|
1384
|
-
? b `<img
|
|
1457
|
+
? b `<img
|
|
1458
|
+
class="nav-logo"
|
|
1459
|
+
src=${this.logo}
|
|
1460
|
+
alt="Logo"
|
|
1461
|
+
/>`
|
|
1385
1462
|
: A}
|
|
1386
1463
|
</div>
|
|
1387
1464
|
<div class="nav-content" @scroll=${this.handleNavScroll}>
|
|
@@ -1389,7 +1466,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1389
1466
|
<div class="nav-search">
|
|
1390
1467
|
<div class="nav-search__wrapper">
|
|
1391
1468
|
<span class="nav-search__icon">
|
|
1392
|
-
<svg
|
|
1469
|
+
<svg
|
|
1470
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1471
|
+
viewBox="0 0 24 24"
|
|
1472
|
+
fill="currentColor"
|
|
1473
|
+
>
|
|
1393
1474
|
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
|
1394
1475
|
</svg>
|
|
1395
1476
|
</span>
|
|
@@ -1402,7 +1483,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1402
1483
|
/>
|
|
1403
1484
|
${this.navQuery ? b `
|
|
1404
1485
|
<button class="nav-search__clear" @click=${this.handleNavQueryClear}>
|
|
1405
|
-
<svg
|
|
1486
|
+
<svg
|
|
1487
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1488
|
+
viewBox="0 0 24 24"
|
|
1489
|
+
fill="currentColor"
|
|
1490
|
+
>
|
|
1406
1491
|
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
|
|
1407
1492
|
</svg>
|
|
1408
1493
|
</button>
|
|
@@ -1594,7 +1679,7 @@ KRScaffold.styles = i$4 `
|
|
|
1594
1679
|
.nav-content {
|
|
1595
1680
|
flex: 1;
|
|
1596
1681
|
overflow-y: auto;
|
|
1597
|
-
padding: 0 9px
|
|
1682
|
+
padding: 0 9px 12px 8px;
|
|
1598
1683
|
}
|
|
1599
1684
|
|
|
1600
1685
|
.nav-footer {
|
|
@@ -1714,7 +1799,7 @@ KRScaffold.styles = i$4 `
|
|
|
1714
1799
|
|
|
1715
1800
|
.breadcrumbs {
|
|
1716
1801
|
height: 32px;
|
|
1717
|
-
padding: 0
|
|
1802
|
+
padding: 0 16px;
|
|
1718
1803
|
display: flex;
|
|
1719
1804
|
align-items: center;
|
|
1720
1805
|
gap: 6px;
|
|
@@ -1808,7 +1893,7 @@ KRScaffold.styles = i$4 `
|
|
|
1808
1893
|
white-space: nowrap;
|
|
1809
1894
|
overflow: hidden;
|
|
1810
1895
|
text-overflow: ellipsis;
|
|
1811
|
-
letter-spacing: 0.
|
|
1896
|
+
letter-spacing: 0.14px;
|
|
1812
1897
|
}
|
|
1813
1898
|
|
|
1814
1899
|
.nav-item__chevron {
|
|
@@ -1863,7 +1948,7 @@ KRScaffold.styles = i$4 `
|
|
|
1863
1948
|
font-size: 11px;
|
|
1864
1949
|
font-weight: 600;
|
|
1865
1950
|
text-transform: uppercase;
|
|
1866
|
-
letter-spacing: 0.
|
|
1951
|
+
letter-spacing: 0.55px;
|
|
1867
1952
|
color: var(--kr-scaffold-nav-text);
|
|
1868
1953
|
opacity: 0.6;
|
|
1869
1954
|
}
|
|
@@ -1986,7 +2071,7 @@ KRScaffold.styles = i$4 `
|
|
|
1986
2071
|
|
|
1987
2072
|
.breadcrumbs {
|
|
1988
2073
|
height: 32px;
|
|
1989
|
-
padding: 0
|
|
2074
|
+
padding: 0 16px;
|
|
1990
2075
|
display: flex;
|
|
1991
2076
|
align-items: center;
|
|
1992
2077
|
gap: 6px;
|
|
@@ -2154,6 +2239,61 @@ KRScaffold.styles = i$4 `
|
|
|
2154
2239
|
}
|
|
2155
2240
|
}
|
|
2156
2241
|
`;
|
|
2242
|
+
__decorate$5([
|
|
2243
|
+
n({ type: String })
|
|
2244
|
+
], KRScaffold.prototype, "logo", void 0);
|
|
2245
|
+
__decorate$5([
|
|
2246
|
+
n({ type: String })
|
|
2247
|
+
], KRScaffold.prototype, "label", void 0);
|
|
2248
|
+
__decorate$5([
|
|
2249
|
+
n({
|
|
2250
|
+
type: String,
|
|
2251
|
+
attribute: 'home-url'
|
|
2252
|
+
})
|
|
2253
|
+
], KRScaffold.prototype, "homeUrl", void 0);
|
|
2254
|
+
__decorate$5([
|
|
2255
|
+
n({
|
|
2256
|
+
type: String,
|
|
2257
|
+
reflect: true
|
|
2258
|
+
})
|
|
2259
|
+
], KRScaffold.prototype, "scheme", void 0);
|
|
2260
|
+
__decorate$5([
|
|
2261
|
+
n({ type: Array })
|
|
2262
|
+
], KRScaffold.prototype, "nav", void 0);
|
|
2263
|
+
__decorate$5([
|
|
2264
|
+
n({
|
|
2265
|
+
type: Boolean,
|
|
2266
|
+
attribute: 'nav-icons-displayed',
|
|
2267
|
+
reflect: true
|
|
2268
|
+
})
|
|
2269
|
+
], KRScaffold.prototype, "navIconsDisplayed", void 0);
|
|
2270
|
+
__decorate$5([
|
|
2271
|
+
n({
|
|
2272
|
+
type: Boolean,
|
|
2273
|
+
attribute: 'nav-expanded'
|
|
2274
|
+
})
|
|
2275
|
+
], KRScaffold.prototype, "navExpanded", void 0);
|
|
2276
|
+
__decorate$5([
|
|
2277
|
+
n({ type: Object })
|
|
2278
|
+
], KRScaffold.prototype, "user", void 0);
|
|
2279
|
+
__decorate$5([
|
|
2280
|
+
n({ type: Boolean })
|
|
2281
|
+
], KRScaffold.prototype, "subbar", void 0);
|
|
2282
|
+
__decorate$5([
|
|
2283
|
+
n({
|
|
2284
|
+
type: Boolean,
|
|
2285
|
+
attribute: 'nav-enabled'
|
|
2286
|
+
})
|
|
2287
|
+
], KRScaffold.prototype, "navEnabled", void 0);
|
|
2288
|
+
__decorate$5([
|
|
2289
|
+
n({
|
|
2290
|
+
type: String,
|
|
2291
|
+
attribute: 'user-type'
|
|
2292
|
+
})
|
|
2293
|
+
], KRScaffold.prototype, "userType", void 0);
|
|
2294
|
+
__decorate$5([
|
|
2295
|
+
n({ type: Array })
|
|
2296
|
+
], KRScaffold.prototype, "breadcrumbs", void 0);
|
|
2157
2297
|
__decorate$5([
|
|
2158
2298
|
r()
|
|
2159
2299
|
], KRScaffold.prototype, "navItemsExpanded", void 0);
|
|
@@ -2190,42 +2330,6 @@ __decorate$5([
|
|
|
2190
2330
|
__decorate$5([
|
|
2191
2331
|
r()
|
|
2192
2332
|
], KRScaffold.prototype, "pendingRequests", void 0);
|
|
2193
|
-
__decorate$5([
|
|
2194
|
-
n({ type: String })
|
|
2195
|
-
], KRScaffold.prototype, "logo", void 0);
|
|
2196
|
-
__decorate$5([
|
|
2197
|
-
n({ type: String })
|
|
2198
|
-
], KRScaffold.prototype, "label", void 0);
|
|
2199
|
-
__decorate$5([
|
|
2200
|
-
n({ type: String, attribute: 'home-url' })
|
|
2201
|
-
], KRScaffold.prototype, "homeUrl", void 0);
|
|
2202
|
-
__decorate$5([
|
|
2203
|
-
n({ type: String, reflect: true })
|
|
2204
|
-
], KRScaffold.prototype, "scheme", void 0);
|
|
2205
|
-
__decorate$5([
|
|
2206
|
-
n({ type: Array })
|
|
2207
|
-
], KRScaffold.prototype, "nav", void 0);
|
|
2208
|
-
__decorate$5([
|
|
2209
|
-
n({ type: Boolean, attribute: 'nav-icons-displayed', reflect: true })
|
|
2210
|
-
], KRScaffold.prototype, "navIconsDisplayed", void 0);
|
|
2211
|
-
__decorate$5([
|
|
2212
|
-
n({ type: Boolean, attribute: 'nav-expanded' })
|
|
2213
|
-
], KRScaffold.prototype, "navExpanded", void 0);
|
|
2214
|
-
__decorate$5([
|
|
2215
|
-
n({ type: Object })
|
|
2216
|
-
], KRScaffold.prototype, "user", void 0);
|
|
2217
|
-
__decorate$5([
|
|
2218
|
-
n({ type: Boolean })
|
|
2219
|
-
], KRScaffold.prototype, "subbar", void 0);
|
|
2220
|
-
__decorate$5([
|
|
2221
|
-
n({ type: Boolean, attribute: 'nav-enabled' })
|
|
2222
|
-
], KRScaffold.prototype, "navEnabled", void 0);
|
|
2223
|
-
__decorate$5([
|
|
2224
|
-
n({ type: String, attribute: 'user-type' })
|
|
2225
|
-
], KRScaffold.prototype, "userType", void 0);
|
|
2226
|
-
__decorate$5([
|
|
2227
|
-
n({ type: Array })
|
|
2228
|
-
], KRScaffold.prototype, "breadcrumbs", void 0);
|
|
2229
2333
|
KRScaffold = __decorate$5([
|
|
2230
2334
|
t$1('kr-scaffold')
|
|
2231
2335
|
], KRScaffold);
|
|
@@ -2246,7 +2350,7 @@ var __decorate$4 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
2246
2350
|
* <kr-screen-nav
|
|
2247
2351
|
* label="Acme Corporation"
|
|
2248
2352
|
* subLabel="Company"
|
|
2249
|
-
* .
|
|
2353
|
+
* .items=${[
|
|
2250
2354
|
* { id: 'overview', label: 'Overview', url: '/companies/123/overview' },
|
|
2251
2355
|
* { id: 'contacts', label: 'Contacts', url: '/companies/123/contacts' },
|
|
2252
2356
|
* { id: 'activity', label: 'Activity', url: '/companies/123/activity' },
|
|
@@ -2261,7 +2365,7 @@ var __decorate$4 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
2261
2365
|
*
|
|
2262
2366
|
* @property {string} label - Main label (e.g., entity name like "Acme Corporation")
|
|
2263
2367
|
* @property {string} subLabel - Sub label (e.g., entity type like "Company")
|
|
2264
|
-
* @property {KRScreenNavItem[]}
|
|
2368
|
+
* @property {KRScreenNavItem[]} items - Navigation items as JSON array
|
|
2265
2369
|
* @property {string} activeId - Currently active item ID
|
|
2266
2370
|
*/
|
|
2267
2371
|
let KRScreenNav = class KRScreenNav extends i$1 {
|
|
@@ -2278,7 +2382,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2278
2382
|
/**
|
|
2279
2383
|
* Navigation items
|
|
2280
2384
|
*/
|
|
2281
|
-
this.
|
|
2385
|
+
this.items = [];
|
|
2282
2386
|
/**
|
|
2283
2387
|
* Currently active item ID. Auto-detected from the URL by default.
|
|
2284
2388
|
* Can be set explicitly by the parent to override.
|
|
@@ -2290,7 +2394,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2290
2394
|
}
|
|
2291
2395
|
connectedCallback() {
|
|
2292
2396
|
super.connectedCallback();
|
|
2293
|
-
// Defer so property bindings (.
|
|
2397
|
+
// Defer so property bindings (.items) have been applied
|
|
2294
2398
|
requestAnimationFrame(() => this.syncActiveFromUrl());
|
|
2295
2399
|
window.addEventListener('popstate', this.handlePopstate);
|
|
2296
2400
|
}
|
|
@@ -2329,7 +2433,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2329
2433
|
}
|
|
2330
2434
|
syncActiveFromUrl() {
|
|
2331
2435
|
const pathname = window.location.pathname;
|
|
2332
|
-
const match = this.
|
|
2436
|
+
const match = this.items.find((item) => {
|
|
2333
2437
|
if (!item.url) {
|
|
2334
2438
|
return false;
|
|
2335
2439
|
}
|
|
@@ -2357,9 +2461,12 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2357
2461
|
` : A}
|
|
2358
2462
|
<div class="nav-content">
|
|
2359
2463
|
<div class="nav-items">
|
|
2360
|
-
${this.
|
|
2464
|
+
${this.items.map((item) => b `
|
|
2361
2465
|
<a
|
|
2362
|
-
class
|
|
2466
|
+
class=${e({
|
|
2467
|
+
'nav-item': true,
|
|
2468
|
+
'nav-item--active': item.id === this.activeId
|
|
2469
|
+
})}
|
|
2363
2470
|
href=${item.url || '#'}
|
|
2364
2471
|
@click=${(e) => this.handleNavItemClick(e, item)}
|
|
2365
2472
|
>
|
|
@@ -2422,7 +2529,7 @@ KRScreenNav.styles = i$4 `
|
|
|
2422
2529
|
.nav-content {
|
|
2423
2530
|
flex: 1;
|
|
2424
2531
|
overflow-y: auto;
|
|
2425
|
-
padding: 0 0
|
|
2532
|
+
padding: 0 0 12px;
|
|
2426
2533
|
}
|
|
2427
2534
|
|
|
2428
2535
|
.nav-items {
|
|
@@ -2436,7 +2543,7 @@ KRScreenNav.styles = i$4 `
|
|
|
2436
2543
|
padding: 0 12px;
|
|
2437
2544
|
height: 32px;
|
|
2438
2545
|
line-height: 32px;
|
|
2439
|
-
letter-spacing: 0.
|
|
2546
|
+
letter-spacing: 0.13px;
|
|
2440
2547
|
color: rgb(32, 33, 36);
|
|
2441
2548
|
text-decoration: none;
|
|
2442
2549
|
font-size: 13px;
|
|
@@ -2477,7 +2584,7 @@ __decorate$4([
|
|
|
2477
2584
|
], KRScreenNav.prototype, "subLabel", void 0);
|
|
2478
2585
|
__decorate$4([
|
|
2479
2586
|
n({ type: Array })
|
|
2480
|
-
], KRScreenNav.prototype, "
|
|
2587
|
+
], KRScreenNav.prototype, "items", void 0);
|
|
2481
2588
|
__decorate$4([
|
|
2482
2589
|
n({ type: String })
|
|
2483
2590
|
], KRScreenNav.prototype, "activeId", void 0);
|
|
@@ -2547,7 +2654,7 @@ KRScreenDetail.styles = i$4 `
|
|
|
2547
2654
|
display: flex;
|
|
2548
2655
|
align-items: center;
|
|
2549
2656
|
justify-content: space-between;
|
|
2550
|
-
padding: 0
|
|
2657
|
+
padding: 0 24px;
|
|
2551
2658
|
background: #ffffff;
|
|
2552
2659
|
border-bottom: 1px solid #e5e7eb;
|
|
2553
2660
|
flex-shrink: 0;
|
|
@@ -2569,7 +2676,7 @@ KRScreenDetail.styles = i$4 `
|
|
|
2569
2676
|
.content {
|
|
2570
2677
|
flex: 1;
|
|
2571
2678
|
overflow-y: auto;
|
|
2572
|
-
padding:
|
|
2679
|
+
padding: 24px;
|
|
2573
2680
|
display: flex;
|
|
2574
2681
|
justify-content: center;
|
|
2575
2682
|
}
|
|
@@ -2610,7 +2717,10 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2610
2717
|
this.menu = false;
|
|
2611
2718
|
}
|
|
2612
2719
|
_handleMenuClick() {
|
|
2613
|
-
this.dispatchEvent(new CustomEvent('menu-click', {
|
|
2720
|
+
this.dispatchEvent(new CustomEvent('menu-click', {
|
|
2721
|
+
bubbles: true,
|
|
2722
|
+
composed: true
|
|
2723
|
+
}));
|
|
2614
2724
|
}
|
|
2615
2725
|
/**
|
|
2616
2726
|
* Resolves a breadcrumb URL by prepending the base href.
|
|
@@ -2627,13 +2737,19 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2627
2737
|
* - resolveUrl(crumb) = "/operations/settings" (used for href)
|
|
2628
2738
|
*/
|
|
2629
2739
|
resolveUrl(crumb) {
|
|
2630
|
-
if (!crumb.url)
|
|
2740
|
+
if (!crumb.url) {
|
|
2631
2741
|
return '#';
|
|
2742
|
+
}
|
|
2632
2743
|
// Remove leading slash from url if present, then combine with base
|
|
2633
|
-
|
|
2744
|
+
let path = crumb.url;
|
|
2745
|
+
if (crumb.url.startsWith('/')) {
|
|
2746
|
+
path = crumb.url.slice(1);
|
|
2747
|
+
}
|
|
2634
2748
|
const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
|
|
2635
|
-
|
|
2636
|
-
|
|
2749
|
+
if (baseHref.endsWith('/')) {
|
|
2750
|
+
return baseHref + path;
|
|
2751
|
+
}
|
|
2752
|
+
return baseHref + '/' + path;
|
|
2637
2753
|
}
|
|
2638
2754
|
/**
|
|
2639
2755
|
* Handles click on a breadcrumb link.
|
|
@@ -2665,10 +2781,31 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2665
2781
|
return b `
|
|
2666
2782
|
${this.menu ? b `
|
|
2667
2783
|
<div class="menu" @click=${this._handleMenuClick}>
|
|
2668
|
-
<svg
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2784
|
+
<svg
|
|
2785
|
+
class="menu__icon"
|
|
2786
|
+
viewBox="0 0 24 24"
|
|
2787
|
+
fill="none"
|
|
2788
|
+
stroke="currentColor"
|
|
2789
|
+
stroke-width="2"
|
|
2790
|
+
>
|
|
2791
|
+
<line
|
|
2792
|
+
x1="3"
|
|
2793
|
+
y1="6"
|
|
2794
|
+
x2="21"
|
|
2795
|
+
y2="6"
|
|
2796
|
+
></line>
|
|
2797
|
+
<line
|
|
2798
|
+
x1="3"
|
|
2799
|
+
y1="12"
|
|
2800
|
+
x2="21"
|
|
2801
|
+
y2="12"
|
|
2802
|
+
></line>
|
|
2803
|
+
<line
|
|
2804
|
+
x1="3"
|
|
2805
|
+
y1="18"
|
|
2806
|
+
x2="21"
|
|
2807
|
+
y2="18"
|
|
2808
|
+
></line>
|
|
2672
2809
|
</svg>
|
|
2673
2810
|
</div>
|
|
2674
2811
|
` : A}
|
|
@@ -2678,7 +2815,10 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2678
2815
|
return b `
|
|
2679
2816
|
${index > 0 ? b `<span class="breadcrumb-separator">/</span>` : ''}
|
|
2680
2817
|
<a
|
|
2681
|
-
class=${e({
|
|
2818
|
+
class=${e({
|
|
2819
|
+
'breadcrumb': true,
|
|
2820
|
+
'breadcrumb--current': isCurrent
|
|
2821
|
+
})}
|
|
2682
2822
|
href=${this.resolveUrl(crumb)}
|
|
2683
2823
|
@click=${(e) => this._handleBreadcrumbClick(e, crumb, isCurrent)}
|
|
2684
2824
|
>${crumb.label}</a>
|
|
@@ -2847,7 +2987,10 @@ class KRRouter {
|
|
|
2847
2987
|
for (const route of routes) {
|
|
2848
2988
|
const routeSegments = route.path.split('/').filter(s => s);
|
|
2849
2989
|
if (routeSegments.length === 0 && segments.length === 0) {
|
|
2850
|
-
return [{
|
|
2990
|
+
return [{
|
|
2991
|
+
route,
|
|
2992
|
+
params: {}
|
|
2993
|
+
}];
|
|
2851
2994
|
}
|
|
2852
2995
|
if (routeSegments.length === 0) {
|
|
2853
2996
|
continue;
|
|
@@ -2874,7 +3017,10 @@ class KRRouter {
|
|
|
2874
3017
|
if (remaining.length > 0 && !route.children) {
|
|
2875
3018
|
continue;
|
|
2876
3019
|
}
|
|
2877
|
-
const result = [{
|
|
3020
|
+
const result = [{
|
|
3021
|
+
route,
|
|
3022
|
+
params
|
|
3023
|
+
}];
|
|
2878
3024
|
if (route.children && remaining.length > 0) {
|
|
2879
3025
|
const childMatches = KRRouter.matchRoutes(route.children, remaining);
|
|
2880
3026
|
if (childMatches.length > 0) {
|
|
@@ -2954,101 +3100,2532 @@ KRRouterOutlet = __decorate$1([
|
|
|
2954
3100
|
t$1('kr-router-outlet')
|
|
2955
3101
|
], KRRouterOutlet);
|
|
2956
3102
|
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3103
|
+
/**
|
|
3104
|
+
* marked v12.0.2 - a markdown parser
|
|
3105
|
+
* Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)
|
|
3106
|
+
* https://github.com/markedjs/marked
|
|
3107
|
+
*/
|
|
3108
|
+
|
|
3109
|
+
/**
|
|
3110
|
+
* DO NOT EDIT THIS FILE
|
|
3111
|
+
* The code in this file is generated from files in ./src/
|
|
3112
|
+
*/
|
|
3113
|
+
|
|
3114
|
+
/**
|
|
3115
|
+
* Gets the original marked default options.
|
|
3116
|
+
*/
|
|
3117
|
+
function _getDefaults() {
|
|
3118
|
+
return {
|
|
3119
|
+
async: false,
|
|
3120
|
+
breaks: false,
|
|
3121
|
+
extensions: null,
|
|
3122
|
+
gfm: true,
|
|
3123
|
+
hooks: null,
|
|
3124
|
+
pedantic: false,
|
|
3125
|
+
renderer: null,
|
|
3126
|
+
silent: false,
|
|
3127
|
+
tokenizer: null,
|
|
3128
|
+
walkTokens: null
|
|
3129
|
+
};
|
|
3130
|
+
}
|
|
3131
|
+
let _defaults = _getDefaults();
|
|
3132
|
+
function changeDefaults(newDefaults) {
|
|
3133
|
+
_defaults = newDefaults;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
/**
|
|
3137
|
+
* Helpers
|
|
3138
|
+
*/
|
|
3139
|
+
const escapeTest = /[&<>"']/;
|
|
3140
|
+
const escapeReplace = new RegExp(escapeTest.source, 'g');
|
|
3141
|
+
const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
|
|
3142
|
+
const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
|
|
3143
|
+
const escapeReplacements = {
|
|
3144
|
+
'&': '&',
|
|
3145
|
+
'<': '<',
|
|
3146
|
+
'>': '>',
|
|
3147
|
+
'"': '"',
|
|
3148
|
+
"'": '''
|
|
2962
3149
|
};
|
|
3150
|
+
const getEscapeReplacement = (ch) => escapeReplacements[ch];
|
|
3151
|
+
function escape$1(html, encode) {
|
|
3152
|
+
if (encode) {
|
|
3153
|
+
if (escapeTest.test(html)) {
|
|
3154
|
+
return html.replace(escapeReplace, getEscapeReplacement);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
else {
|
|
3158
|
+
if (escapeTestNoEncode.test(html)) {
|
|
3159
|
+
return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
return html;
|
|
3163
|
+
}
|
|
3164
|
+
const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
|
|
3165
|
+
function unescape(html) {
|
|
3166
|
+
// explicitly match decimal, hex, and named HTML entities
|
|
3167
|
+
return html.replace(unescapeTest, (_, n) => {
|
|
3168
|
+
n = n.toLowerCase();
|
|
3169
|
+
if (n === 'colon')
|
|
3170
|
+
return ':';
|
|
3171
|
+
if (n.charAt(0) === '#') {
|
|
3172
|
+
return n.charAt(1) === 'x'
|
|
3173
|
+
? String.fromCharCode(parseInt(n.substring(2), 16))
|
|
3174
|
+
: String.fromCharCode(+n.substring(1));
|
|
3175
|
+
}
|
|
3176
|
+
return '';
|
|
3177
|
+
});
|
|
3178
|
+
}
|
|
3179
|
+
const caret = /(^|[^\[])\^/g;
|
|
3180
|
+
function edit(regex, opt) {
|
|
3181
|
+
let source = typeof regex === 'string' ? regex : regex.source;
|
|
3182
|
+
opt = opt || '';
|
|
3183
|
+
const obj = {
|
|
3184
|
+
replace: (name, val) => {
|
|
3185
|
+
let valSource = typeof val === 'string' ? val : val.source;
|
|
3186
|
+
valSource = valSource.replace(caret, '$1');
|
|
3187
|
+
source = source.replace(name, valSource);
|
|
3188
|
+
return obj;
|
|
3189
|
+
},
|
|
3190
|
+
getRegex: () => {
|
|
3191
|
+
return new RegExp(source, opt);
|
|
3192
|
+
}
|
|
3193
|
+
};
|
|
3194
|
+
return obj;
|
|
3195
|
+
}
|
|
3196
|
+
function cleanUrl(href) {
|
|
3197
|
+
try {
|
|
3198
|
+
href = encodeURI(href).replace(/%25/g, '%');
|
|
3199
|
+
}
|
|
3200
|
+
catch (e) {
|
|
3201
|
+
return null;
|
|
3202
|
+
}
|
|
3203
|
+
return href;
|
|
3204
|
+
}
|
|
3205
|
+
const noopTest = { exec: () => null };
|
|
3206
|
+
function splitCells(tableRow, count) {
|
|
3207
|
+
// ensure that every cell-delimiting pipe has a space
|
|
3208
|
+
// before it to distinguish it from an escaped pipe
|
|
3209
|
+
const row = tableRow.replace(/\|/g, (match, offset, str) => {
|
|
3210
|
+
let escaped = false;
|
|
3211
|
+
let curr = offset;
|
|
3212
|
+
while (--curr >= 0 && str[curr] === '\\')
|
|
3213
|
+
escaped = !escaped;
|
|
3214
|
+
if (escaped) {
|
|
3215
|
+
// odd number of slashes means | is escaped
|
|
3216
|
+
// so we leave it alone
|
|
3217
|
+
return '|';
|
|
3218
|
+
}
|
|
3219
|
+
else {
|
|
3220
|
+
// add space before unescaped |
|
|
3221
|
+
return ' |';
|
|
3222
|
+
}
|
|
3223
|
+
}), cells = row.split(/ \|/);
|
|
3224
|
+
let i = 0;
|
|
3225
|
+
// First/last cell in a row cannot be empty if it has no leading/trailing pipe
|
|
3226
|
+
if (!cells[0].trim()) {
|
|
3227
|
+
cells.shift();
|
|
3228
|
+
}
|
|
3229
|
+
if (cells.length > 0 && !cells[cells.length - 1].trim()) {
|
|
3230
|
+
cells.pop();
|
|
3231
|
+
}
|
|
3232
|
+
if (count) {
|
|
3233
|
+
if (cells.length > count) {
|
|
3234
|
+
cells.splice(count);
|
|
3235
|
+
}
|
|
3236
|
+
else {
|
|
3237
|
+
while (cells.length < count)
|
|
3238
|
+
cells.push('');
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
for (; i < cells.length; i++) {
|
|
3242
|
+
// leading or trailing whitespace is ignored per the gfm spec
|
|
3243
|
+
cells[i] = cells[i].trim().replace(/\\\|/g, '|');
|
|
3244
|
+
}
|
|
3245
|
+
return cells;
|
|
3246
|
+
}
|
|
2963
3247
|
/**
|
|
2964
|
-
*
|
|
2965
|
-
*
|
|
2966
|
-
* Accepts a `send` callback that returns a streaming Response (SSE format).
|
|
2967
|
-
* Parses the stream for text tokens, status updates, errors, and frontend actions.
|
|
2968
|
-
* When an ACTION event arrives, dispatches a cancelable `action` custom event.
|
|
2969
|
-
* If not prevented, executes the native browser action (reload, navigate, etc.).
|
|
2970
|
-
*
|
|
2971
|
-
* ## SSE Stream Format
|
|
2972
|
-
* The component expects `data:` lines with JSON payloads containing a `type` field:
|
|
2973
|
-
* - `STATUS` — `{ type: "STATUS", message: "Thinking..." }`
|
|
2974
|
-
* - `RESPONSE_PART` — `{ type: "RESPONSE_PART", message: "token text" }`
|
|
2975
|
-
* - `ACTION` — `{ type: "ACTION", action: "RELOAD" }` (see KRChatbotAction)
|
|
2976
|
-
* - `ERROR` — `{ type: "ERROR", message: "Something went wrong" }`
|
|
2977
|
-
* - `HEARTBEAT` — `{ type: "HEARTBEAT" }` (ignored)
|
|
2978
|
-
*
|
|
2979
|
-
* The final event should include `finished: true` to signal stream completion.
|
|
2980
|
-
*
|
|
2981
|
-
* ## Usage
|
|
2982
|
-
* ```html
|
|
2983
|
-
* <kr-chatbot
|
|
2984
|
-
* title="AI Assistant"
|
|
2985
|
-
* .send=${(params) => {
|
|
2986
|
-
* return fetch('/api/ai/chat/stream', {
|
|
2987
|
-
* method: 'POST',
|
|
2988
|
-
* headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' },
|
|
2989
|
-
* credentials: 'include',
|
|
2990
|
-
* body: JSON.stringify({ userText: params.message })
|
|
2991
|
-
* });
|
|
2992
|
-
* }}
|
|
2993
|
-
* ></kr-chatbot>
|
|
2994
|
-
* ```
|
|
2995
|
-
*
|
|
2996
|
-
* @slot - Optional slot content displayed above the messages area
|
|
3248
|
+
* Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
|
|
3249
|
+
* /c*$/ is vulnerable to REDOS.
|
|
2997
3250
|
*
|
|
2998
|
-
* @
|
|
2999
|
-
* @
|
|
3251
|
+
* @param str
|
|
3252
|
+
* @param c
|
|
3253
|
+
* @param invert Remove suffix of non-c chars instead. Default falsey.
|
|
3000
3254
|
*/
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3255
|
+
function rtrim(str, c, invert) {
|
|
3256
|
+
const l = str.length;
|
|
3257
|
+
if (l === 0) {
|
|
3258
|
+
return '';
|
|
3259
|
+
}
|
|
3260
|
+
// Length of suffix matching the invert condition.
|
|
3261
|
+
let suffLen = 0;
|
|
3262
|
+
// Step left until we fail to match the invert condition.
|
|
3263
|
+
while (suffLen < l) {
|
|
3264
|
+
const currChar = str.charAt(l - suffLen - 1);
|
|
3265
|
+
if (currChar === c && true) {
|
|
3266
|
+
suffLen++;
|
|
3267
|
+
}
|
|
3268
|
+
else {
|
|
3269
|
+
break;
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
return str.slice(0, l - suffLen);
|
|
3273
|
+
}
|
|
3274
|
+
function findClosingBracket(str, b) {
|
|
3275
|
+
if (str.indexOf(b[1]) === -1) {
|
|
3276
|
+
return -1;
|
|
3277
|
+
}
|
|
3278
|
+
let level = 0;
|
|
3279
|
+
for (let i = 0; i < str.length; i++) {
|
|
3280
|
+
if (str[i] === '\\') {
|
|
3281
|
+
i++;
|
|
3282
|
+
}
|
|
3283
|
+
else if (str[i] === b[0]) {
|
|
3284
|
+
level++;
|
|
3285
|
+
}
|
|
3286
|
+
else if (str[i] === b[1]) {
|
|
3287
|
+
level--;
|
|
3288
|
+
if (level < 0) {
|
|
3289
|
+
return i;
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
return -1;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
function outputLink(cap, link, raw, lexer) {
|
|
3297
|
+
const href = link.href;
|
|
3298
|
+
const title = link.title ? escape$1(link.title) : null;
|
|
3299
|
+
const text = cap[1].replace(/\\([\[\]])/g, '$1');
|
|
3300
|
+
if (cap[0].charAt(0) !== '!') {
|
|
3301
|
+
lexer.state.inLink = true;
|
|
3302
|
+
const token = {
|
|
3303
|
+
type: 'link',
|
|
3304
|
+
raw,
|
|
3305
|
+
href,
|
|
3306
|
+
title,
|
|
3307
|
+
text,
|
|
3308
|
+
tokens: lexer.inlineTokens(text)
|
|
3309
|
+
};
|
|
3310
|
+
lexer.state.inLink = false;
|
|
3311
|
+
return token;
|
|
3312
|
+
}
|
|
3313
|
+
return {
|
|
3314
|
+
type: 'image',
|
|
3315
|
+
raw,
|
|
3316
|
+
href,
|
|
3317
|
+
title,
|
|
3318
|
+
text: escape$1(text)
|
|
3319
|
+
};
|
|
3320
|
+
}
|
|
3321
|
+
function indentCodeCompensation(raw, text) {
|
|
3322
|
+
const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
|
|
3323
|
+
if (matchIndentToCode === null) {
|
|
3324
|
+
return text;
|
|
3325
|
+
}
|
|
3326
|
+
const indentToCode = matchIndentToCode[1];
|
|
3327
|
+
return text
|
|
3328
|
+
.split('\n')
|
|
3329
|
+
.map(node => {
|
|
3330
|
+
const matchIndentInNode = node.match(/^\s+/);
|
|
3331
|
+
if (matchIndentInNode === null) {
|
|
3332
|
+
return node;
|
|
3333
|
+
}
|
|
3334
|
+
const [indentInNode] = matchIndentInNode;
|
|
3335
|
+
if (indentInNode.length >= indentToCode.length) {
|
|
3336
|
+
return node.slice(indentToCode.length);
|
|
3337
|
+
}
|
|
3338
|
+
return node;
|
|
3339
|
+
})
|
|
3340
|
+
.join('\n');
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3343
|
+
* Tokenizer
|
|
3344
|
+
*/
|
|
3345
|
+
class _Tokenizer {
|
|
3346
|
+
options;
|
|
3347
|
+
rules; // set by the lexer
|
|
3348
|
+
lexer; // set by the lexer
|
|
3349
|
+
constructor(options) {
|
|
3350
|
+
this.options = options || _defaults;
|
|
3351
|
+
}
|
|
3352
|
+
space(src) {
|
|
3353
|
+
const cap = this.rules.block.newline.exec(src);
|
|
3354
|
+
if (cap && cap[0].length > 0) {
|
|
3355
|
+
return {
|
|
3356
|
+
type: 'space',
|
|
3357
|
+
raw: cap[0]
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
code(src) {
|
|
3362
|
+
const cap = this.rules.block.code.exec(src);
|
|
3363
|
+
if (cap) {
|
|
3364
|
+
const text = cap[0].replace(/^ {1,4}/gm, '');
|
|
3365
|
+
return {
|
|
3366
|
+
type: 'code',
|
|
3367
|
+
raw: cap[0],
|
|
3368
|
+
codeBlockStyle: 'indented',
|
|
3369
|
+
text: !this.options.pedantic
|
|
3370
|
+
? rtrim(text, '\n')
|
|
3371
|
+
: text
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
fences(src) {
|
|
3376
|
+
const cap = this.rules.block.fences.exec(src);
|
|
3377
|
+
if (cap) {
|
|
3378
|
+
const raw = cap[0];
|
|
3379
|
+
const text = indentCodeCompensation(raw, cap[3] || '');
|
|
3380
|
+
return {
|
|
3381
|
+
type: 'code',
|
|
3382
|
+
raw,
|
|
3383
|
+
lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],
|
|
3384
|
+
text
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
heading(src) {
|
|
3389
|
+
const cap = this.rules.block.heading.exec(src);
|
|
3390
|
+
if (cap) {
|
|
3391
|
+
let text = cap[2].trim();
|
|
3392
|
+
// remove trailing #s
|
|
3393
|
+
if (/#$/.test(text)) {
|
|
3394
|
+
const trimmed = rtrim(text, '#');
|
|
3395
|
+
if (this.options.pedantic) {
|
|
3396
|
+
text = trimmed.trim();
|
|
3397
|
+
}
|
|
3398
|
+
else if (!trimmed || / $/.test(trimmed)) {
|
|
3399
|
+
// CommonMark requires space before trailing #s
|
|
3400
|
+
text = trimmed.trim();
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
return {
|
|
3404
|
+
type: 'heading',
|
|
3405
|
+
raw: cap[0],
|
|
3406
|
+
depth: cap[1].length,
|
|
3407
|
+
text,
|
|
3408
|
+
tokens: this.lexer.inline(text)
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
hr(src) {
|
|
3413
|
+
const cap = this.rules.block.hr.exec(src);
|
|
3414
|
+
if (cap) {
|
|
3415
|
+
return {
|
|
3416
|
+
type: 'hr',
|
|
3417
|
+
raw: cap[0]
|
|
3418
|
+
};
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
blockquote(src) {
|
|
3422
|
+
const cap = this.rules.block.blockquote.exec(src);
|
|
3423
|
+
if (cap) {
|
|
3424
|
+
// precede setext continuation with 4 spaces so it isn't a setext
|
|
3425
|
+
let text = cap[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, '\n $1');
|
|
3426
|
+
text = rtrim(text.replace(/^ *>[ \t]?/gm, ''), '\n');
|
|
3427
|
+
const top = this.lexer.state.top;
|
|
3428
|
+
this.lexer.state.top = true;
|
|
3429
|
+
const tokens = this.lexer.blockTokens(text);
|
|
3430
|
+
this.lexer.state.top = top;
|
|
3431
|
+
return {
|
|
3432
|
+
type: 'blockquote',
|
|
3433
|
+
raw: cap[0],
|
|
3434
|
+
tokens,
|
|
3435
|
+
text
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
list(src) {
|
|
3440
|
+
let cap = this.rules.block.list.exec(src);
|
|
3441
|
+
if (cap) {
|
|
3442
|
+
let bull = cap[1].trim();
|
|
3443
|
+
const isordered = bull.length > 1;
|
|
3444
|
+
const list = {
|
|
3445
|
+
type: 'list',
|
|
3446
|
+
raw: '',
|
|
3447
|
+
ordered: isordered,
|
|
3448
|
+
start: isordered ? +bull.slice(0, -1) : '',
|
|
3449
|
+
loose: false,
|
|
3450
|
+
items: []
|
|
3451
|
+
};
|
|
3452
|
+
bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
|
|
3453
|
+
if (this.options.pedantic) {
|
|
3454
|
+
bull = isordered ? bull : '[*+-]';
|
|
3455
|
+
}
|
|
3456
|
+
// Get next list item
|
|
3457
|
+
const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
|
|
3458
|
+
let raw = '';
|
|
3459
|
+
let itemContents = '';
|
|
3460
|
+
let endsWithBlankLine = false;
|
|
3461
|
+
// Check if current bullet point can start a new List Item
|
|
3462
|
+
while (src) {
|
|
3463
|
+
let endEarly = false;
|
|
3464
|
+
if (!(cap = itemRegex.exec(src))) {
|
|
3465
|
+
break;
|
|
3466
|
+
}
|
|
3467
|
+
if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)
|
|
3468
|
+
break;
|
|
3469
|
+
}
|
|
3470
|
+
raw = cap[0];
|
|
3471
|
+
src = src.substring(raw.length);
|
|
3472
|
+
let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length));
|
|
3473
|
+
let nextLine = src.split('\n', 1)[0];
|
|
3474
|
+
let indent = 0;
|
|
3475
|
+
if (this.options.pedantic) {
|
|
3476
|
+
indent = 2;
|
|
3477
|
+
itemContents = line.trimStart();
|
|
3478
|
+
}
|
|
3479
|
+
else {
|
|
3480
|
+
indent = cap[2].search(/[^ ]/); // Find first non-space char
|
|
3481
|
+
indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
|
|
3482
|
+
itemContents = line.slice(indent);
|
|
3483
|
+
indent += cap[1].length;
|
|
3484
|
+
}
|
|
3485
|
+
let blankLine = false;
|
|
3486
|
+
if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line
|
|
3487
|
+
raw += nextLine + '\n';
|
|
3488
|
+
src = src.substring(nextLine.length + 1);
|
|
3489
|
+
endEarly = true;
|
|
3490
|
+
}
|
|
3491
|
+
if (!endEarly) {
|
|
3492
|
+
const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`);
|
|
3493
|
+
const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
|
|
3494
|
+
const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
|
|
3495
|
+
const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
|
|
3496
|
+
// Check if following lines should be included in List Item
|
|
3497
|
+
while (src) {
|
|
3498
|
+
const rawLine = src.split('\n', 1)[0];
|
|
3499
|
+
nextLine = rawLine;
|
|
3500
|
+
// Re-align to follow commonmark nesting rules
|
|
3501
|
+
if (this.options.pedantic) {
|
|
3502
|
+
nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
|
|
3503
|
+
}
|
|
3504
|
+
// End list item if found code fences
|
|
3505
|
+
if (fencesBeginRegex.test(nextLine)) {
|
|
3506
|
+
break;
|
|
3507
|
+
}
|
|
3508
|
+
// End list item if found start of new heading
|
|
3509
|
+
if (headingBeginRegex.test(nextLine)) {
|
|
3510
|
+
break;
|
|
3511
|
+
}
|
|
3512
|
+
// End list item if found start of new bullet
|
|
3513
|
+
if (nextBulletRegex.test(nextLine)) {
|
|
3514
|
+
break;
|
|
3515
|
+
}
|
|
3516
|
+
// Horizontal rule found
|
|
3517
|
+
if (hrRegex.test(src)) {
|
|
3518
|
+
break;
|
|
3519
|
+
}
|
|
3520
|
+
if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible
|
|
3521
|
+
itemContents += '\n' + nextLine.slice(indent);
|
|
3522
|
+
}
|
|
3523
|
+
else {
|
|
3524
|
+
// not enough indentation
|
|
3525
|
+
if (blankLine) {
|
|
3526
|
+
break;
|
|
3527
|
+
}
|
|
3528
|
+
// paragraph continuation unless last line was a different block level element
|
|
3529
|
+
if (line.search(/[^ ]/) >= 4) { // indented code block
|
|
3530
|
+
break;
|
|
3531
|
+
}
|
|
3532
|
+
if (fencesBeginRegex.test(line)) {
|
|
3533
|
+
break;
|
|
3534
|
+
}
|
|
3535
|
+
if (headingBeginRegex.test(line)) {
|
|
3536
|
+
break;
|
|
3537
|
+
}
|
|
3538
|
+
if (hrRegex.test(line)) {
|
|
3539
|
+
break;
|
|
3540
|
+
}
|
|
3541
|
+
itemContents += '\n' + nextLine;
|
|
3542
|
+
}
|
|
3543
|
+
if (!blankLine && !nextLine.trim()) { // Check if current line is blank
|
|
3544
|
+
blankLine = true;
|
|
3545
|
+
}
|
|
3546
|
+
raw += rawLine + '\n';
|
|
3547
|
+
src = src.substring(rawLine.length + 1);
|
|
3548
|
+
line = nextLine.slice(indent);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
if (!list.loose) {
|
|
3552
|
+
// If the previous item ended with a blank line, the list is loose
|
|
3553
|
+
if (endsWithBlankLine) {
|
|
3554
|
+
list.loose = true;
|
|
3555
|
+
}
|
|
3556
|
+
else if (/\n *\n *$/.test(raw)) {
|
|
3557
|
+
endsWithBlankLine = true;
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
let istask = null;
|
|
3561
|
+
let ischecked;
|
|
3562
|
+
// Check for task list items
|
|
3563
|
+
if (this.options.gfm) {
|
|
3564
|
+
istask = /^\[[ xX]\] /.exec(itemContents);
|
|
3565
|
+
if (istask) {
|
|
3566
|
+
ischecked = istask[0] !== '[ ] ';
|
|
3567
|
+
itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
list.items.push({
|
|
3571
|
+
type: 'list_item',
|
|
3572
|
+
raw,
|
|
3573
|
+
task: !!istask,
|
|
3574
|
+
checked: ischecked,
|
|
3575
|
+
loose: false,
|
|
3576
|
+
text: itemContents,
|
|
3577
|
+
tokens: []
|
|
3578
|
+
});
|
|
3579
|
+
list.raw += raw;
|
|
3580
|
+
}
|
|
3581
|
+
// Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
|
|
3582
|
+
list.items[list.items.length - 1].raw = raw.trimEnd();
|
|
3583
|
+
(list.items[list.items.length - 1]).text = itemContents.trimEnd();
|
|
3584
|
+
list.raw = list.raw.trimEnd();
|
|
3585
|
+
// Item child tokens handled here at end because we needed to have the final item to trim it first
|
|
3586
|
+
for (let i = 0; i < list.items.length; i++) {
|
|
3587
|
+
this.lexer.state.top = false;
|
|
3588
|
+
list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
|
|
3589
|
+
if (!list.loose) {
|
|
3590
|
+
// Check if list should be loose
|
|
3591
|
+
const spacers = list.items[i].tokens.filter(t => t.type === 'space');
|
|
3592
|
+
const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw));
|
|
3593
|
+
list.loose = hasMultipleLineBreaks;
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
// Set all items to loose if list is loose
|
|
3597
|
+
if (list.loose) {
|
|
3598
|
+
for (let i = 0; i < list.items.length; i++) {
|
|
3599
|
+
list.items[i].loose = true;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
return list;
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
html(src) {
|
|
3606
|
+
const cap = this.rules.block.html.exec(src);
|
|
3607
|
+
if (cap) {
|
|
3608
|
+
const token = {
|
|
3609
|
+
type: 'html',
|
|
3610
|
+
block: true,
|
|
3611
|
+
raw: cap[0],
|
|
3612
|
+
pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
|
|
3613
|
+
text: cap[0]
|
|
3614
|
+
};
|
|
3615
|
+
return token;
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
def(src) {
|
|
3619
|
+
const cap = this.rules.block.def.exec(src);
|
|
3620
|
+
if (cap) {
|
|
3621
|
+
const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
|
|
3622
|
+
const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';
|
|
3623
|
+
const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];
|
|
3624
|
+
return {
|
|
3625
|
+
type: 'def',
|
|
3626
|
+
tag,
|
|
3627
|
+
raw: cap[0],
|
|
3628
|
+
href,
|
|
3629
|
+
title
|
|
3630
|
+
};
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
table(src) {
|
|
3634
|
+
const cap = this.rules.block.table.exec(src);
|
|
3635
|
+
if (!cap) {
|
|
3636
|
+
return;
|
|
3637
|
+
}
|
|
3638
|
+
if (!/[:|]/.test(cap[2])) {
|
|
3639
|
+
// delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
const headers = splitCells(cap[1]);
|
|
3643
|
+
const aligns = cap[2].replace(/^\||\| *$/g, '').split('|');
|
|
3644
|
+
const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : [];
|
|
3645
|
+
const item = {
|
|
3646
|
+
type: 'table',
|
|
3647
|
+
raw: cap[0],
|
|
3648
|
+
header: [],
|
|
3649
|
+
align: [],
|
|
3650
|
+
rows: []
|
|
3651
|
+
};
|
|
3652
|
+
if (headers.length !== aligns.length) {
|
|
3653
|
+
// header and align columns must be equal, rows can be different.
|
|
3654
|
+
return;
|
|
3655
|
+
}
|
|
3656
|
+
for (const align of aligns) {
|
|
3657
|
+
if (/^ *-+: *$/.test(align)) {
|
|
3658
|
+
item.align.push('right');
|
|
3659
|
+
}
|
|
3660
|
+
else if (/^ *:-+: *$/.test(align)) {
|
|
3661
|
+
item.align.push('center');
|
|
3662
|
+
}
|
|
3663
|
+
else if (/^ *:-+ *$/.test(align)) {
|
|
3664
|
+
item.align.push('left');
|
|
3665
|
+
}
|
|
3666
|
+
else {
|
|
3667
|
+
item.align.push(null);
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
for (const header of headers) {
|
|
3671
|
+
item.header.push({
|
|
3672
|
+
text: header,
|
|
3673
|
+
tokens: this.lexer.inline(header)
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
3676
|
+
for (const row of rows) {
|
|
3677
|
+
item.rows.push(splitCells(row, item.header.length).map(cell => {
|
|
3678
|
+
return {
|
|
3679
|
+
text: cell,
|
|
3680
|
+
tokens: this.lexer.inline(cell)
|
|
3681
|
+
};
|
|
3682
|
+
}));
|
|
3683
|
+
}
|
|
3684
|
+
return item;
|
|
3685
|
+
}
|
|
3686
|
+
lheading(src) {
|
|
3687
|
+
const cap = this.rules.block.lheading.exec(src);
|
|
3688
|
+
if (cap) {
|
|
3689
|
+
return {
|
|
3690
|
+
type: 'heading',
|
|
3691
|
+
raw: cap[0],
|
|
3692
|
+
depth: cap[2].charAt(0) === '=' ? 1 : 2,
|
|
3693
|
+
text: cap[1],
|
|
3694
|
+
tokens: this.lexer.inline(cap[1])
|
|
3695
|
+
};
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
paragraph(src) {
|
|
3699
|
+
const cap = this.rules.block.paragraph.exec(src);
|
|
3700
|
+
if (cap) {
|
|
3701
|
+
const text = cap[1].charAt(cap[1].length - 1) === '\n'
|
|
3702
|
+
? cap[1].slice(0, -1)
|
|
3703
|
+
: cap[1];
|
|
3704
|
+
return {
|
|
3705
|
+
type: 'paragraph',
|
|
3706
|
+
raw: cap[0],
|
|
3707
|
+
text,
|
|
3708
|
+
tokens: this.lexer.inline(text)
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
text(src) {
|
|
3713
|
+
const cap = this.rules.block.text.exec(src);
|
|
3714
|
+
if (cap) {
|
|
3715
|
+
return {
|
|
3716
|
+
type: 'text',
|
|
3717
|
+
raw: cap[0],
|
|
3718
|
+
text: cap[0],
|
|
3719
|
+
tokens: this.lexer.inline(cap[0])
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
escape(src) {
|
|
3724
|
+
const cap = this.rules.inline.escape.exec(src);
|
|
3725
|
+
if (cap) {
|
|
3726
|
+
return {
|
|
3727
|
+
type: 'escape',
|
|
3728
|
+
raw: cap[0],
|
|
3729
|
+
text: escape$1(cap[1])
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
tag(src) {
|
|
3734
|
+
const cap = this.rules.inline.tag.exec(src);
|
|
3735
|
+
if (cap) {
|
|
3736
|
+
if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
|
|
3737
|
+
this.lexer.state.inLink = true;
|
|
3738
|
+
}
|
|
3739
|
+
else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
|
|
3740
|
+
this.lexer.state.inLink = false;
|
|
3741
|
+
}
|
|
3742
|
+
if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
3743
|
+
this.lexer.state.inRawBlock = true;
|
|
3744
|
+
}
|
|
3745
|
+
else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
3746
|
+
this.lexer.state.inRawBlock = false;
|
|
3747
|
+
}
|
|
3748
|
+
return {
|
|
3749
|
+
type: 'html',
|
|
3750
|
+
raw: cap[0],
|
|
3751
|
+
inLink: this.lexer.state.inLink,
|
|
3752
|
+
inRawBlock: this.lexer.state.inRawBlock,
|
|
3753
|
+
block: false,
|
|
3754
|
+
text: cap[0]
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
link(src) {
|
|
3759
|
+
const cap = this.rules.inline.link.exec(src);
|
|
3760
|
+
if (cap) {
|
|
3761
|
+
const trimmedUrl = cap[2].trim();
|
|
3762
|
+
if (!this.options.pedantic && /^</.test(trimmedUrl)) {
|
|
3763
|
+
// commonmark requires matching angle brackets
|
|
3764
|
+
if (!(/>$/.test(trimmedUrl))) {
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
// ending angle bracket cannot be escaped
|
|
3768
|
+
const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
|
|
3769
|
+
if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
else {
|
|
3774
|
+
// find closing parenthesis
|
|
3775
|
+
const lastParenIndex = findClosingBracket(cap[2], '()');
|
|
3776
|
+
if (lastParenIndex > -1) {
|
|
3777
|
+
const start = cap[0].indexOf('!') === 0 ? 5 : 4;
|
|
3778
|
+
const linkLen = start + cap[1].length + lastParenIndex;
|
|
3779
|
+
cap[2] = cap[2].substring(0, lastParenIndex);
|
|
3780
|
+
cap[0] = cap[0].substring(0, linkLen).trim();
|
|
3781
|
+
cap[3] = '';
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
let href = cap[2];
|
|
3785
|
+
let title = '';
|
|
3786
|
+
if (this.options.pedantic) {
|
|
3787
|
+
// split pedantic href and title
|
|
3788
|
+
const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
|
|
3789
|
+
if (link) {
|
|
3790
|
+
href = link[1];
|
|
3791
|
+
title = link[3];
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
else {
|
|
3795
|
+
title = cap[3] ? cap[3].slice(1, -1) : '';
|
|
3796
|
+
}
|
|
3797
|
+
href = href.trim();
|
|
3798
|
+
if (/^</.test(href)) {
|
|
3799
|
+
if (this.options.pedantic && !(/>$/.test(trimmedUrl))) {
|
|
3800
|
+
// pedantic allows starting angle bracket without ending angle bracket
|
|
3801
|
+
href = href.slice(1);
|
|
3802
|
+
}
|
|
3803
|
+
else {
|
|
3804
|
+
href = href.slice(1, -1);
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
return outputLink(cap, {
|
|
3808
|
+
href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,
|
|
3809
|
+
title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title
|
|
3810
|
+
}, cap[0], this.lexer);
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
reflink(src, links) {
|
|
3814
|
+
let cap;
|
|
3815
|
+
if ((cap = this.rules.inline.reflink.exec(src))
|
|
3816
|
+
|| (cap = this.rules.inline.nolink.exec(src))) {
|
|
3817
|
+
const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' ');
|
|
3818
|
+
const link = links[linkString.toLowerCase()];
|
|
3819
|
+
if (!link) {
|
|
3820
|
+
const text = cap[0].charAt(0);
|
|
3821
|
+
return {
|
|
3822
|
+
type: 'text',
|
|
3823
|
+
raw: text,
|
|
3824
|
+
text
|
|
3825
|
+
};
|
|
3826
|
+
}
|
|
3827
|
+
return outputLink(cap, link, cap[0], this.lexer);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
emStrong(src, maskedSrc, prevChar = '') {
|
|
3831
|
+
let match = this.rules.inline.emStrongLDelim.exec(src);
|
|
3832
|
+
if (!match)
|
|
3833
|
+
return;
|
|
3834
|
+
// _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
|
|
3835
|
+
if (match[3] && prevChar.match(/[\p{L}\p{N}]/u))
|
|
3836
|
+
return;
|
|
3837
|
+
const nextChar = match[1] || match[2] || '';
|
|
3838
|
+
if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
|
|
3839
|
+
// unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)
|
|
3840
|
+
const lLength = [...match[0]].length - 1;
|
|
3841
|
+
let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
|
|
3842
|
+
const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
|
|
3843
|
+
endReg.lastIndex = 0;
|
|
3844
|
+
// Clip maskedSrc to same section of string as src (move to lexer?)
|
|
3845
|
+
maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
|
|
3846
|
+
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
3847
|
+
rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
|
|
3848
|
+
if (!rDelim)
|
|
3849
|
+
continue; // skip single * in __abc*abc__
|
|
3850
|
+
rLength = [...rDelim].length;
|
|
3851
|
+
if (match[3] || match[4]) { // found another Left Delim
|
|
3852
|
+
delimTotal += rLength;
|
|
3853
|
+
continue;
|
|
3854
|
+
}
|
|
3855
|
+
else if (match[5] || match[6]) { // either Left or Right Delim
|
|
3856
|
+
if (lLength % 3 && !((lLength + rLength) % 3)) {
|
|
3857
|
+
midDelimTotal += rLength;
|
|
3858
|
+
continue; // CommonMark Emphasis Rules 9-10
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
delimTotal -= rLength;
|
|
3862
|
+
if (delimTotal > 0)
|
|
3863
|
+
continue; // Haven't found enough closing delimiters
|
|
3864
|
+
// Remove extra characters. *a*** -> *a*
|
|
3865
|
+
rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
|
|
3866
|
+
// char length can be >1 for unicode characters;
|
|
3867
|
+
const lastCharLength = [...match[0]][0].length;
|
|
3868
|
+
const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
|
|
3869
|
+
// Create `em` if smallest delimiter has odd char count. *a***
|
|
3870
|
+
if (Math.min(lLength, rLength) % 2) {
|
|
3871
|
+
const text = raw.slice(1, -1);
|
|
3872
|
+
return {
|
|
3873
|
+
type: 'em',
|
|
3874
|
+
raw,
|
|
3875
|
+
text,
|
|
3876
|
+
tokens: this.lexer.inlineTokens(text)
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3879
|
+
// Create 'strong' if smallest delimiter has even char count. **a***
|
|
3880
|
+
const text = raw.slice(2, -2);
|
|
3881
|
+
return {
|
|
3882
|
+
type: 'strong',
|
|
3883
|
+
raw,
|
|
3884
|
+
text,
|
|
3885
|
+
tokens: this.lexer.inlineTokens(text)
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
codespan(src) {
|
|
3891
|
+
const cap = this.rules.inline.code.exec(src);
|
|
3892
|
+
if (cap) {
|
|
3893
|
+
let text = cap[2].replace(/\n/g, ' ');
|
|
3894
|
+
const hasNonSpaceChars = /[^ ]/.test(text);
|
|
3895
|
+
const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
|
|
3896
|
+
if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
|
|
3897
|
+
text = text.substring(1, text.length - 1);
|
|
3898
|
+
}
|
|
3899
|
+
text = escape$1(text, true);
|
|
3900
|
+
return {
|
|
3901
|
+
type: 'codespan',
|
|
3902
|
+
raw: cap[0],
|
|
3903
|
+
text
|
|
3904
|
+
};
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
br(src) {
|
|
3908
|
+
const cap = this.rules.inline.br.exec(src);
|
|
3909
|
+
if (cap) {
|
|
3910
|
+
return {
|
|
3911
|
+
type: 'br',
|
|
3912
|
+
raw: cap[0]
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
del(src) {
|
|
3917
|
+
const cap = this.rules.inline.del.exec(src);
|
|
3918
|
+
if (cap) {
|
|
3919
|
+
return {
|
|
3920
|
+
type: 'del',
|
|
3921
|
+
raw: cap[0],
|
|
3922
|
+
text: cap[2],
|
|
3923
|
+
tokens: this.lexer.inlineTokens(cap[2])
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
autolink(src) {
|
|
3928
|
+
const cap = this.rules.inline.autolink.exec(src);
|
|
3929
|
+
if (cap) {
|
|
3930
|
+
let text, href;
|
|
3931
|
+
if (cap[2] === '@') {
|
|
3932
|
+
text = escape$1(cap[1]);
|
|
3933
|
+
href = 'mailto:' + text;
|
|
3934
|
+
}
|
|
3935
|
+
else {
|
|
3936
|
+
text = escape$1(cap[1]);
|
|
3937
|
+
href = text;
|
|
3938
|
+
}
|
|
3939
|
+
return {
|
|
3940
|
+
type: 'link',
|
|
3941
|
+
raw: cap[0],
|
|
3942
|
+
text,
|
|
3943
|
+
href,
|
|
3944
|
+
tokens: [
|
|
3945
|
+
{
|
|
3946
|
+
type: 'text',
|
|
3947
|
+
raw: text,
|
|
3948
|
+
text
|
|
3949
|
+
}
|
|
3950
|
+
]
|
|
3951
|
+
};
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
url(src) {
|
|
3955
|
+
let cap;
|
|
3956
|
+
if (cap = this.rules.inline.url.exec(src)) {
|
|
3957
|
+
let text, href;
|
|
3958
|
+
if (cap[2] === '@') {
|
|
3959
|
+
text = escape$1(cap[0]);
|
|
3960
|
+
href = 'mailto:' + text;
|
|
3961
|
+
}
|
|
3962
|
+
else {
|
|
3963
|
+
// do extended autolink path validation
|
|
3964
|
+
let prevCapZero;
|
|
3965
|
+
do {
|
|
3966
|
+
prevCapZero = cap[0];
|
|
3967
|
+
cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';
|
|
3968
|
+
} while (prevCapZero !== cap[0]);
|
|
3969
|
+
text = escape$1(cap[0]);
|
|
3970
|
+
if (cap[1] === 'www.') {
|
|
3971
|
+
href = 'http://' + cap[0];
|
|
3972
|
+
}
|
|
3973
|
+
else {
|
|
3974
|
+
href = cap[0];
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
return {
|
|
3978
|
+
type: 'link',
|
|
3979
|
+
raw: cap[0],
|
|
3980
|
+
text,
|
|
3981
|
+
href,
|
|
3982
|
+
tokens: [
|
|
3983
|
+
{
|
|
3984
|
+
type: 'text',
|
|
3985
|
+
raw: text,
|
|
3986
|
+
text
|
|
3987
|
+
}
|
|
3988
|
+
]
|
|
3989
|
+
};
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
inlineText(src) {
|
|
3993
|
+
const cap = this.rules.inline.text.exec(src);
|
|
3994
|
+
if (cap) {
|
|
3995
|
+
let text;
|
|
3996
|
+
if (this.lexer.state.inRawBlock) {
|
|
3997
|
+
text = cap[0];
|
|
3998
|
+
}
|
|
3999
|
+
else {
|
|
4000
|
+
text = escape$1(cap[0]);
|
|
4001
|
+
}
|
|
4002
|
+
return {
|
|
4003
|
+
type: 'text',
|
|
4004
|
+
raw: cap[0],
|
|
4005
|
+
text
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
/**
|
|
4012
|
+
* Block-Level Grammar
|
|
4013
|
+
*/
|
|
4014
|
+
const newline = /^(?: *(?:\n|$))+/;
|
|
4015
|
+
const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/;
|
|
4016
|
+
const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
|
|
4017
|
+
const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
|
|
4018
|
+
const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
|
|
4019
|
+
const bullet = /(?:[*+-]|\d{1,9}[.)])/;
|
|
4020
|
+
const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/)
|
|
4021
|
+
.replace(/bull/g, bullet) // lists can interrupt
|
|
4022
|
+
.replace(/blockCode/g, / {4}/) // indented code blocks can interrupt
|
|
4023
|
+
.replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt
|
|
4024
|
+
.replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt
|
|
4025
|
+
.replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt
|
|
4026
|
+
.replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt
|
|
4027
|
+
.getRegex();
|
|
4028
|
+
const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
|
|
4029
|
+
const blockText = /^[^\n]+/;
|
|
4030
|
+
const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
|
|
4031
|
+
const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/)
|
|
4032
|
+
.replace('label', _blockLabel)
|
|
4033
|
+
.replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/)
|
|
4034
|
+
.getRegex();
|
|
4035
|
+
const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/)
|
|
4036
|
+
.replace(/bull/g, bullet)
|
|
4037
|
+
.getRegex();
|
|
4038
|
+
const _tag = 'address|article|aside|base|basefont|blockquote|body|caption'
|
|
4039
|
+
+ '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
|
|
4040
|
+
+ '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
|
|
4041
|
+
+ '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
|
|
4042
|
+
+ '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'
|
|
4043
|
+
+ '|tr|track|ul';
|
|
4044
|
+
const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
|
|
4045
|
+
const html = edit('^ {0,3}(?:' // optional indentation
|
|
4046
|
+
+ '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
|
|
4047
|
+
+ '|comment[^\\n]*(\\n+|$)' // (2)
|
|
4048
|
+
+ '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
|
|
4049
|
+
+ '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
|
|
4050
|
+
+ '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
|
|
4051
|
+
+ '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
|
|
4052
|
+
+ '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
|
|
4053
|
+
+ '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
|
|
4054
|
+
+ ')', 'i')
|
|
4055
|
+
.replace('comment', _comment)
|
|
4056
|
+
.replace('tag', _tag)
|
|
4057
|
+
.replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
|
|
4058
|
+
.getRegex();
|
|
4059
|
+
const paragraph = edit(_paragraph)
|
|
4060
|
+
.replace('hr', hr)
|
|
4061
|
+
.replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
|
|
4062
|
+
.replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
|
|
4063
|
+
.replace('|table', '')
|
|
4064
|
+
.replace('blockquote', ' {0,3}>')
|
|
4065
|
+
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
4066
|
+
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
4067
|
+
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
4068
|
+
.replace('tag', _tag) // pars can be interrupted by type (6) html blocks
|
|
4069
|
+
.getRegex();
|
|
4070
|
+
const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/)
|
|
4071
|
+
.replace('paragraph', paragraph)
|
|
4072
|
+
.getRegex();
|
|
4073
|
+
/**
|
|
4074
|
+
* Normal Block Grammar
|
|
4075
|
+
*/
|
|
4076
|
+
const blockNormal = {
|
|
4077
|
+
blockquote,
|
|
4078
|
+
code: blockCode,
|
|
4079
|
+
def,
|
|
4080
|
+
fences,
|
|
4081
|
+
heading,
|
|
4082
|
+
hr,
|
|
4083
|
+
html,
|
|
4084
|
+
lheading,
|
|
4085
|
+
list,
|
|
4086
|
+
newline,
|
|
4087
|
+
paragraph,
|
|
4088
|
+
table: noopTest,
|
|
4089
|
+
text: blockText
|
|
4090
|
+
};
|
|
4091
|
+
/**
|
|
4092
|
+
* GFM Block Grammar
|
|
4093
|
+
*/
|
|
4094
|
+
const gfmTable = edit('^ *([^\\n ].*)\\n' // Header
|
|
4095
|
+
+ ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align
|
|
4096
|
+
+ '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells
|
|
4097
|
+
.replace('hr', hr)
|
|
4098
|
+
.replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
|
|
4099
|
+
.replace('blockquote', ' {0,3}>')
|
|
4100
|
+
.replace('code', ' {4}[^\\n]')
|
|
4101
|
+
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
4102
|
+
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
4103
|
+
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
4104
|
+
.replace('tag', _tag) // tables can be interrupted by type (6) html blocks
|
|
4105
|
+
.getRegex();
|
|
4106
|
+
const blockGfm = {
|
|
4107
|
+
...blockNormal,
|
|
4108
|
+
table: gfmTable,
|
|
4109
|
+
paragraph: edit(_paragraph)
|
|
4110
|
+
.replace('hr', hr)
|
|
4111
|
+
.replace('heading', ' {0,3}#{1,6}(?:\\s|$)')
|
|
4112
|
+
.replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs
|
|
4113
|
+
.replace('table', gfmTable) // interrupt paragraphs with table
|
|
4114
|
+
.replace('blockquote', ' {0,3}>')
|
|
4115
|
+
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
4116
|
+
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
4117
|
+
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
4118
|
+
.replace('tag', _tag) // pars can be interrupted by type (6) html blocks
|
|
4119
|
+
.getRegex()
|
|
4120
|
+
};
|
|
4121
|
+
/**
|
|
4122
|
+
* Pedantic grammar (original John Gruber's loose markdown specification)
|
|
4123
|
+
*/
|
|
4124
|
+
const blockPedantic = {
|
|
4125
|
+
...blockNormal,
|
|
4126
|
+
html: edit('^ *(?:comment *(?:\\n|\\s*$)'
|
|
4127
|
+
+ '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
|
|
4128
|
+
+ '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
|
|
4129
|
+
.replace('comment', _comment)
|
|
4130
|
+
.replace(/tag/g, '(?!(?:'
|
|
4131
|
+
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
|
|
4132
|
+
+ '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
|
|
4133
|
+
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
|
|
4134
|
+
.getRegex(),
|
|
4135
|
+
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
|
|
4136
|
+
heading: /^(#{1,6})(.*)(?:\n+|$)/,
|
|
4137
|
+
fences: noopTest, // fences not supported
|
|
4138
|
+
lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
|
|
4139
|
+
paragraph: edit(_paragraph)
|
|
4140
|
+
.replace('hr', hr)
|
|
4141
|
+
.replace('heading', ' *#{1,6} *[^\n]')
|
|
4142
|
+
.replace('lheading', lheading)
|
|
4143
|
+
.replace('|table', '')
|
|
4144
|
+
.replace('blockquote', ' {0,3}>')
|
|
4145
|
+
.replace('|fences', '')
|
|
4146
|
+
.replace('|list', '')
|
|
4147
|
+
.replace('|html', '')
|
|
4148
|
+
.replace('|tag', '')
|
|
4149
|
+
.getRegex()
|
|
4150
|
+
};
|
|
4151
|
+
/**
|
|
4152
|
+
* Inline-Level Grammar
|
|
4153
|
+
*/
|
|
4154
|
+
const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
|
|
4155
|
+
const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
|
|
4156
|
+
const br = /^( {2,}|\\)\n(?!\s*$)/;
|
|
4157
|
+
const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
|
|
4158
|
+
// list of unicode punctuation marks, plus any missing characters from CommonMark spec
|
|
4159
|
+
const _punctuation = '\\p{P}\\p{S}';
|
|
4160
|
+
const punctuation = edit(/^((?![*_])[\spunctuation])/, 'u')
|
|
4161
|
+
.replace(/punctuation/g, _punctuation).getRegex();
|
|
4162
|
+
// sequences em should skip over [title](link), `code`, <html>
|
|
4163
|
+
const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
|
|
4164
|
+
const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u')
|
|
4165
|
+
.replace(/punct/g, _punctuation)
|
|
4166
|
+
.getRegex();
|
|
4167
|
+
const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong
|
|
4168
|
+
+ '|[^*]+(?=[^*])' // Consume to delim
|
|
4169
|
+
+ '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter
|
|
4170
|
+
+ '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter
|
|
4171
|
+
+ '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter
|
|
4172
|
+
+ '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter
|
|
4173
|
+
+ '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter
|
|
4174
|
+
+ '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter
|
|
4175
|
+
.replace(/punct/g, _punctuation)
|
|
4176
|
+
.getRegex();
|
|
4177
|
+
// (6) Not allowed for _
|
|
4178
|
+
const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong
|
|
4179
|
+
+ '|[^_]+(?=[^_])' // Consume to delim
|
|
4180
|
+
+ '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter
|
|
4181
|
+
+ '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter
|
|
4182
|
+
+ '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter
|
|
4183
|
+
+ '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter
|
|
4184
|
+
+ '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter
|
|
4185
|
+
.replace(/punct/g, _punctuation)
|
|
4186
|
+
.getRegex();
|
|
4187
|
+
const anyPunctuation = edit(/\\([punct])/, 'gu')
|
|
4188
|
+
.replace(/punct/g, _punctuation)
|
|
4189
|
+
.getRegex();
|
|
4190
|
+
const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/)
|
|
4191
|
+
.replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)
|
|
4192
|
+
.replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)
|
|
4193
|
+
.getRegex();
|
|
4194
|
+
const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();
|
|
4195
|
+
const tag = edit('^comment'
|
|
4196
|
+
+ '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
|
|
4197
|
+
+ '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
|
|
4198
|
+
+ '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
|
|
4199
|
+
+ '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
|
|
4200
|
+
+ '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>') // CDATA section
|
|
4201
|
+
.replace('comment', _inlineComment)
|
|
4202
|
+
.replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/)
|
|
4203
|
+
.getRegex();
|
|
4204
|
+
const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
|
|
4205
|
+
const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/)
|
|
4206
|
+
.replace('label', _inlineLabel)
|
|
4207
|
+
.replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/)
|
|
4208
|
+
.replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/)
|
|
4209
|
+
.getRegex();
|
|
4210
|
+
const reflink = edit(/^!?\[(label)\]\[(ref)\]/)
|
|
4211
|
+
.replace('label', _inlineLabel)
|
|
4212
|
+
.replace('ref', _blockLabel)
|
|
4213
|
+
.getRegex();
|
|
4214
|
+
const nolink = edit(/^!?\[(ref)\](?:\[\])?/)
|
|
4215
|
+
.replace('ref', _blockLabel)
|
|
4216
|
+
.getRegex();
|
|
4217
|
+
const reflinkSearch = edit('reflink|nolink(?!\\()', 'g')
|
|
4218
|
+
.replace('reflink', reflink)
|
|
4219
|
+
.replace('nolink', nolink)
|
|
4220
|
+
.getRegex();
|
|
4221
|
+
/**
|
|
4222
|
+
* Normal Inline Grammar
|
|
4223
|
+
*/
|
|
4224
|
+
const inlineNormal = {
|
|
4225
|
+
_backpedal: noopTest, // only used for GFM url
|
|
4226
|
+
anyPunctuation,
|
|
4227
|
+
autolink,
|
|
4228
|
+
blockSkip,
|
|
4229
|
+
br,
|
|
4230
|
+
code: inlineCode,
|
|
4231
|
+
del: noopTest,
|
|
4232
|
+
emStrongLDelim,
|
|
4233
|
+
emStrongRDelimAst,
|
|
4234
|
+
emStrongRDelimUnd,
|
|
4235
|
+
escape,
|
|
4236
|
+
link,
|
|
4237
|
+
nolink,
|
|
4238
|
+
punctuation,
|
|
4239
|
+
reflink,
|
|
4240
|
+
reflinkSearch,
|
|
4241
|
+
tag,
|
|
4242
|
+
text: inlineText,
|
|
4243
|
+
url: noopTest
|
|
4244
|
+
};
|
|
4245
|
+
/**
|
|
4246
|
+
* Pedantic Inline Grammar
|
|
4247
|
+
*/
|
|
4248
|
+
const inlinePedantic = {
|
|
4249
|
+
...inlineNormal,
|
|
4250
|
+
link: edit(/^!?\[(label)\]\((.*?)\)/)
|
|
4251
|
+
.replace('label', _inlineLabel)
|
|
4252
|
+
.getRegex(),
|
|
4253
|
+
reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
|
|
4254
|
+
.replace('label', _inlineLabel)
|
|
4255
|
+
.getRegex()
|
|
4256
|
+
};
|
|
4257
|
+
/**
|
|
4258
|
+
* GFM Inline Grammar
|
|
4259
|
+
*/
|
|
4260
|
+
const inlineGfm = {
|
|
4261
|
+
...inlineNormal,
|
|
4262
|
+
escape: edit(escape).replace('])', '~|])').getRegex(),
|
|
4263
|
+
url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i')
|
|
4264
|
+
.replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)
|
|
4265
|
+
.getRegex(),
|
|
4266
|
+
_backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
|
|
4267
|
+
del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
|
|
4268
|
+
text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
|
|
4269
|
+
};
|
|
4270
|
+
/**
|
|
4271
|
+
* GFM + Line Breaks Inline Grammar
|
|
4272
|
+
*/
|
|
4273
|
+
const inlineBreaks = {
|
|
4274
|
+
...inlineGfm,
|
|
4275
|
+
br: edit(br).replace('{2,}', '*').getRegex(),
|
|
4276
|
+
text: edit(inlineGfm.text)
|
|
4277
|
+
.replace('\\b_', '\\b_| {2,}\\n')
|
|
4278
|
+
.replace(/\{2,\}/g, '*')
|
|
4279
|
+
.getRegex()
|
|
4280
|
+
};
|
|
4281
|
+
/**
|
|
4282
|
+
* exports
|
|
4283
|
+
*/
|
|
4284
|
+
const block = {
|
|
4285
|
+
normal: blockNormal,
|
|
4286
|
+
gfm: blockGfm,
|
|
4287
|
+
pedantic: blockPedantic
|
|
4288
|
+
};
|
|
4289
|
+
const inline = {
|
|
4290
|
+
normal: inlineNormal,
|
|
4291
|
+
gfm: inlineGfm,
|
|
4292
|
+
breaks: inlineBreaks,
|
|
4293
|
+
pedantic: inlinePedantic
|
|
4294
|
+
};
|
|
4295
|
+
|
|
4296
|
+
/**
|
|
4297
|
+
* Block Lexer
|
|
4298
|
+
*/
|
|
4299
|
+
class _Lexer {
|
|
4300
|
+
tokens;
|
|
4301
|
+
options;
|
|
4302
|
+
state;
|
|
4303
|
+
tokenizer;
|
|
4304
|
+
inlineQueue;
|
|
4305
|
+
constructor(options) {
|
|
4306
|
+
// TokenList cannot be created in one go
|
|
4307
|
+
this.tokens = [];
|
|
4308
|
+
this.tokens.links = Object.create(null);
|
|
4309
|
+
this.options = options || _defaults;
|
|
4310
|
+
this.options.tokenizer = this.options.tokenizer || new _Tokenizer();
|
|
4311
|
+
this.tokenizer = this.options.tokenizer;
|
|
4312
|
+
this.tokenizer.options = this.options;
|
|
4313
|
+
this.tokenizer.lexer = this;
|
|
4314
|
+
this.inlineQueue = [];
|
|
4315
|
+
this.state = {
|
|
4316
|
+
inLink: false,
|
|
4317
|
+
inRawBlock: false,
|
|
4318
|
+
top: true
|
|
4319
|
+
};
|
|
4320
|
+
const rules = {
|
|
4321
|
+
block: block.normal,
|
|
4322
|
+
inline: inline.normal
|
|
4323
|
+
};
|
|
4324
|
+
if (this.options.pedantic) {
|
|
4325
|
+
rules.block = block.pedantic;
|
|
4326
|
+
rules.inline = inline.pedantic;
|
|
4327
|
+
}
|
|
4328
|
+
else if (this.options.gfm) {
|
|
4329
|
+
rules.block = block.gfm;
|
|
4330
|
+
if (this.options.breaks) {
|
|
4331
|
+
rules.inline = inline.breaks;
|
|
4332
|
+
}
|
|
4333
|
+
else {
|
|
4334
|
+
rules.inline = inline.gfm;
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
this.tokenizer.rules = rules;
|
|
4338
|
+
}
|
|
4339
|
+
/**
|
|
4340
|
+
* Expose Rules
|
|
4341
|
+
*/
|
|
4342
|
+
static get rules() {
|
|
4343
|
+
return {
|
|
4344
|
+
block,
|
|
4345
|
+
inline
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
/**
|
|
4349
|
+
* Static Lex Method
|
|
4350
|
+
*/
|
|
4351
|
+
static lex(src, options) {
|
|
4352
|
+
const lexer = new _Lexer(options);
|
|
4353
|
+
return lexer.lex(src);
|
|
4354
|
+
}
|
|
4355
|
+
/**
|
|
4356
|
+
* Static Lex Inline Method
|
|
4357
|
+
*/
|
|
4358
|
+
static lexInline(src, options) {
|
|
4359
|
+
const lexer = new _Lexer(options);
|
|
4360
|
+
return lexer.inlineTokens(src);
|
|
4361
|
+
}
|
|
4362
|
+
/**
|
|
4363
|
+
* Preprocessing
|
|
4364
|
+
*/
|
|
4365
|
+
lex(src) {
|
|
4366
|
+
src = src
|
|
4367
|
+
.replace(/\r\n|\r/g, '\n');
|
|
4368
|
+
this.blockTokens(src, this.tokens);
|
|
4369
|
+
for (let i = 0; i < this.inlineQueue.length; i++) {
|
|
4370
|
+
const next = this.inlineQueue[i];
|
|
4371
|
+
this.inlineTokens(next.src, next.tokens);
|
|
4372
|
+
}
|
|
4373
|
+
this.inlineQueue = [];
|
|
4374
|
+
return this.tokens;
|
|
4375
|
+
}
|
|
4376
|
+
blockTokens(src, tokens = []) {
|
|
4377
|
+
if (this.options.pedantic) {
|
|
4378
|
+
src = src.replace(/\t/g, ' ').replace(/^ +$/gm, '');
|
|
4379
|
+
}
|
|
4380
|
+
else {
|
|
4381
|
+
src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
|
|
4382
|
+
return leading + ' '.repeat(tabs.length);
|
|
4383
|
+
});
|
|
4384
|
+
}
|
|
4385
|
+
let token;
|
|
4386
|
+
let lastToken;
|
|
4387
|
+
let cutSrc;
|
|
4388
|
+
let lastParagraphClipped;
|
|
4389
|
+
while (src) {
|
|
4390
|
+
if (this.options.extensions
|
|
4391
|
+
&& this.options.extensions.block
|
|
4392
|
+
&& this.options.extensions.block.some((extTokenizer) => {
|
|
4393
|
+
if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
|
|
4394
|
+
src = src.substring(token.raw.length);
|
|
4395
|
+
tokens.push(token);
|
|
4396
|
+
return true;
|
|
4397
|
+
}
|
|
4398
|
+
return false;
|
|
4399
|
+
})) {
|
|
4400
|
+
continue;
|
|
4401
|
+
}
|
|
4402
|
+
// newline
|
|
4403
|
+
if (token = this.tokenizer.space(src)) {
|
|
4404
|
+
src = src.substring(token.raw.length);
|
|
4405
|
+
if (token.raw.length === 1 && tokens.length > 0) {
|
|
4406
|
+
// if there's a single \n as a spacer, it's terminating the last line,
|
|
4407
|
+
// so move it there so that we don't get unnecessary paragraph tags
|
|
4408
|
+
tokens[tokens.length - 1].raw += '\n';
|
|
4409
|
+
}
|
|
4410
|
+
else {
|
|
4411
|
+
tokens.push(token);
|
|
4412
|
+
}
|
|
4413
|
+
continue;
|
|
4414
|
+
}
|
|
4415
|
+
// code
|
|
4416
|
+
if (token = this.tokenizer.code(src)) {
|
|
4417
|
+
src = src.substring(token.raw.length);
|
|
4418
|
+
lastToken = tokens[tokens.length - 1];
|
|
4419
|
+
// An indented code block cannot interrupt a paragraph.
|
|
4420
|
+
if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
|
|
4421
|
+
lastToken.raw += '\n' + token.raw;
|
|
4422
|
+
lastToken.text += '\n' + token.text;
|
|
4423
|
+
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
4424
|
+
}
|
|
4425
|
+
else {
|
|
4426
|
+
tokens.push(token);
|
|
4427
|
+
}
|
|
4428
|
+
continue;
|
|
4429
|
+
}
|
|
4430
|
+
// fences
|
|
4431
|
+
if (token = this.tokenizer.fences(src)) {
|
|
4432
|
+
src = src.substring(token.raw.length);
|
|
4433
|
+
tokens.push(token);
|
|
4434
|
+
continue;
|
|
4435
|
+
}
|
|
4436
|
+
// heading
|
|
4437
|
+
if (token = this.tokenizer.heading(src)) {
|
|
4438
|
+
src = src.substring(token.raw.length);
|
|
4439
|
+
tokens.push(token);
|
|
4440
|
+
continue;
|
|
4441
|
+
}
|
|
4442
|
+
// hr
|
|
4443
|
+
if (token = this.tokenizer.hr(src)) {
|
|
4444
|
+
src = src.substring(token.raw.length);
|
|
4445
|
+
tokens.push(token);
|
|
4446
|
+
continue;
|
|
4447
|
+
}
|
|
4448
|
+
// blockquote
|
|
4449
|
+
if (token = this.tokenizer.blockquote(src)) {
|
|
4450
|
+
src = src.substring(token.raw.length);
|
|
4451
|
+
tokens.push(token);
|
|
4452
|
+
continue;
|
|
4453
|
+
}
|
|
4454
|
+
// list
|
|
4455
|
+
if (token = this.tokenizer.list(src)) {
|
|
4456
|
+
src = src.substring(token.raw.length);
|
|
4457
|
+
tokens.push(token);
|
|
4458
|
+
continue;
|
|
4459
|
+
}
|
|
4460
|
+
// html
|
|
4461
|
+
if (token = this.tokenizer.html(src)) {
|
|
4462
|
+
src = src.substring(token.raw.length);
|
|
4463
|
+
tokens.push(token);
|
|
4464
|
+
continue;
|
|
4465
|
+
}
|
|
4466
|
+
// def
|
|
4467
|
+
if (token = this.tokenizer.def(src)) {
|
|
4468
|
+
src = src.substring(token.raw.length);
|
|
4469
|
+
lastToken = tokens[tokens.length - 1];
|
|
4470
|
+
if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
|
|
4471
|
+
lastToken.raw += '\n' + token.raw;
|
|
4472
|
+
lastToken.text += '\n' + token.raw;
|
|
4473
|
+
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
4474
|
+
}
|
|
4475
|
+
else if (!this.tokens.links[token.tag]) {
|
|
4476
|
+
this.tokens.links[token.tag] = {
|
|
4477
|
+
href: token.href,
|
|
4478
|
+
title: token.title
|
|
4479
|
+
};
|
|
4480
|
+
}
|
|
4481
|
+
continue;
|
|
4482
|
+
}
|
|
4483
|
+
// table (gfm)
|
|
4484
|
+
if (token = this.tokenizer.table(src)) {
|
|
4485
|
+
src = src.substring(token.raw.length);
|
|
4486
|
+
tokens.push(token);
|
|
4487
|
+
continue;
|
|
4488
|
+
}
|
|
4489
|
+
// lheading
|
|
4490
|
+
if (token = this.tokenizer.lheading(src)) {
|
|
4491
|
+
src = src.substring(token.raw.length);
|
|
4492
|
+
tokens.push(token);
|
|
4493
|
+
continue;
|
|
4494
|
+
}
|
|
4495
|
+
// top-level paragraph
|
|
4496
|
+
// prevent paragraph consuming extensions by clipping 'src' to extension start
|
|
4497
|
+
cutSrc = src;
|
|
4498
|
+
if (this.options.extensions && this.options.extensions.startBlock) {
|
|
4499
|
+
let startIndex = Infinity;
|
|
4500
|
+
const tempSrc = src.slice(1);
|
|
4501
|
+
let tempStart;
|
|
4502
|
+
this.options.extensions.startBlock.forEach((getStartIndex) => {
|
|
4503
|
+
tempStart = getStartIndex.call({ lexer: this }, tempSrc);
|
|
4504
|
+
if (typeof tempStart === 'number' && tempStart >= 0) {
|
|
4505
|
+
startIndex = Math.min(startIndex, tempStart);
|
|
4506
|
+
}
|
|
4507
|
+
});
|
|
4508
|
+
if (startIndex < Infinity && startIndex >= 0) {
|
|
4509
|
+
cutSrc = src.substring(0, startIndex + 1);
|
|
4510
|
+
}
|
|
4511
|
+
}
|
|
4512
|
+
if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
|
|
4513
|
+
lastToken = tokens[tokens.length - 1];
|
|
4514
|
+
if (lastParagraphClipped && lastToken.type === 'paragraph') {
|
|
4515
|
+
lastToken.raw += '\n' + token.raw;
|
|
4516
|
+
lastToken.text += '\n' + token.text;
|
|
4517
|
+
this.inlineQueue.pop();
|
|
4518
|
+
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
4519
|
+
}
|
|
4520
|
+
else {
|
|
4521
|
+
tokens.push(token);
|
|
4522
|
+
}
|
|
4523
|
+
lastParagraphClipped = (cutSrc.length !== src.length);
|
|
4524
|
+
src = src.substring(token.raw.length);
|
|
4525
|
+
continue;
|
|
4526
|
+
}
|
|
4527
|
+
// text
|
|
4528
|
+
if (token = this.tokenizer.text(src)) {
|
|
4529
|
+
src = src.substring(token.raw.length);
|
|
4530
|
+
lastToken = tokens[tokens.length - 1];
|
|
4531
|
+
if (lastToken && lastToken.type === 'text') {
|
|
4532
|
+
lastToken.raw += '\n' + token.raw;
|
|
4533
|
+
lastToken.text += '\n' + token.text;
|
|
4534
|
+
this.inlineQueue.pop();
|
|
4535
|
+
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
4536
|
+
}
|
|
4537
|
+
else {
|
|
4538
|
+
tokens.push(token);
|
|
4539
|
+
}
|
|
4540
|
+
continue;
|
|
4541
|
+
}
|
|
4542
|
+
if (src) {
|
|
4543
|
+
const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
|
|
4544
|
+
if (this.options.silent) {
|
|
4545
|
+
console.error(errMsg);
|
|
4546
|
+
break;
|
|
4547
|
+
}
|
|
4548
|
+
else {
|
|
4549
|
+
throw new Error(errMsg);
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
this.state.top = true;
|
|
4554
|
+
return tokens;
|
|
4555
|
+
}
|
|
4556
|
+
inline(src, tokens = []) {
|
|
4557
|
+
this.inlineQueue.push({ src, tokens });
|
|
4558
|
+
return tokens;
|
|
4559
|
+
}
|
|
4560
|
+
/**
|
|
4561
|
+
* Lexing/Compiling
|
|
4562
|
+
*/
|
|
4563
|
+
inlineTokens(src, tokens = []) {
|
|
4564
|
+
let token, lastToken, cutSrc;
|
|
4565
|
+
// String with links masked to avoid interference with em and strong
|
|
4566
|
+
let maskedSrc = src;
|
|
4567
|
+
let match;
|
|
4568
|
+
let keepPrevChar, prevChar;
|
|
4569
|
+
// Mask out reflinks
|
|
4570
|
+
if (this.tokens.links) {
|
|
4571
|
+
const links = Object.keys(this.tokens.links);
|
|
4572
|
+
if (links.length > 0) {
|
|
4573
|
+
while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
|
|
4574
|
+
if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
|
|
4575
|
+
maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
// Mask out other blocks
|
|
4581
|
+
while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
|
|
4582
|
+
maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
|
|
4583
|
+
}
|
|
4584
|
+
// Mask out escaped characters
|
|
4585
|
+
while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
|
|
4586
|
+
maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
|
|
4587
|
+
}
|
|
4588
|
+
while (src) {
|
|
4589
|
+
if (!keepPrevChar) {
|
|
4590
|
+
prevChar = '';
|
|
4591
|
+
}
|
|
4592
|
+
keepPrevChar = false;
|
|
4593
|
+
// extensions
|
|
4594
|
+
if (this.options.extensions
|
|
4595
|
+
&& this.options.extensions.inline
|
|
4596
|
+
&& this.options.extensions.inline.some((extTokenizer) => {
|
|
4597
|
+
if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
|
|
4598
|
+
src = src.substring(token.raw.length);
|
|
4599
|
+
tokens.push(token);
|
|
4600
|
+
return true;
|
|
4601
|
+
}
|
|
4602
|
+
return false;
|
|
4603
|
+
})) {
|
|
4604
|
+
continue;
|
|
4605
|
+
}
|
|
4606
|
+
// escape
|
|
4607
|
+
if (token = this.tokenizer.escape(src)) {
|
|
4608
|
+
src = src.substring(token.raw.length);
|
|
4609
|
+
tokens.push(token);
|
|
4610
|
+
continue;
|
|
4611
|
+
}
|
|
4612
|
+
// tag
|
|
4613
|
+
if (token = this.tokenizer.tag(src)) {
|
|
4614
|
+
src = src.substring(token.raw.length);
|
|
4615
|
+
lastToken = tokens[tokens.length - 1];
|
|
4616
|
+
if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
4617
|
+
lastToken.raw += token.raw;
|
|
4618
|
+
lastToken.text += token.text;
|
|
4619
|
+
}
|
|
4620
|
+
else {
|
|
4621
|
+
tokens.push(token);
|
|
4622
|
+
}
|
|
4623
|
+
continue;
|
|
4624
|
+
}
|
|
4625
|
+
// link
|
|
4626
|
+
if (token = this.tokenizer.link(src)) {
|
|
4627
|
+
src = src.substring(token.raw.length);
|
|
4628
|
+
tokens.push(token);
|
|
4629
|
+
continue;
|
|
4630
|
+
}
|
|
4631
|
+
// reflink, nolink
|
|
4632
|
+
if (token = this.tokenizer.reflink(src, this.tokens.links)) {
|
|
4633
|
+
src = src.substring(token.raw.length);
|
|
4634
|
+
lastToken = tokens[tokens.length - 1];
|
|
4635
|
+
if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
4636
|
+
lastToken.raw += token.raw;
|
|
4637
|
+
lastToken.text += token.text;
|
|
4638
|
+
}
|
|
4639
|
+
else {
|
|
4640
|
+
tokens.push(token);
|
|
4641
|
+
}
|
|
4642
|
+
continue;
|
|
4643
|
+
}
|
|
4644
|
+
// em & strong
|
|
4645
|
+
if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
|
|
4646
|
+
src = src.substring(token.raw.length);
|
|
4647
|
+
tokens.push(token);
|
|
4648
|
+
continue;
|
|
4649
|
+
}
|
|
4650
|
+
// code
|
|
4651
|
+
if (token = this.tokenizer.codespan(src)) {
|
|
4652
|
+
src = src.substring(token.raw.length);
|
|
4653
|
+
tokens.push(token);
|
|
4654
|
+
continue;
|
|
4655
|
+
}
|
|
4656
|
+
// br
|
|
4657
|
+
if (token = this.tokenizer.br(src)) {
|
|
4658
|
+
src = src.substring(token.raw.length);
|
|
4659
|
+
tokens.push(token);
|
|
4660
|
+
continue;
|
|
4661
|
+
}
|
|
4662
|
+
// del (gfm)
|
|
4663
|
+
if (token = this.tokenizer.del(src)) {
|
|
4664
|
+
src = src.substring(token.raw.length);
|
|
4665
|
+
tokens.push(token);
|
|
4666
|
+
continue;
|
|
4667
|
+
}
|
|
4668
|
+
// autolink
|
|
4669
|
+
if (token = this.tokenizer.autolink(src)) {
|
|
4670
|
+
src = src.substring(token.raw.length);
|
|
4671
|
+
tokens.push(token);
|
|
4672
|
+
continue;
|
|
4673
|
+
}
|
|
4674
|
+
// url (gfm)
|
|
4675
|
+
if (!this.state.inLink && (token = this.tokenizer.url(src))) {
|
|
4676
|
+
src = src.substring(token.raw.length);
|
|
4677
|
+
tokens.push(token);
|
|
4678
|
+
continue;
|
|
4679
|
+
}
|
|
4680
|
+
// text
|
|
4681
|
+
// prevent inlineText consuming extensions by clipping 'src' to extension start
|
|
4682
|
+
cutSrc = src;
|
|
4683
|
+
if (this.options.extensions && this.options.extensions.startInline) {
|
|
4684
|
+
let startIndex = Infinity;
|
|
4685
|
+
const tempSrc = src.slice(1);
|
|
4686
|
+
let tempStart;
|
|
4687
|
+
this.options.extensions.startInline.forEach((getStartIndex) => {
|
|
4688
|
+
tempStart = getStartIndex.call({ lexer: this }, tempSrc);
|
|
4689
|
+
if (typeof tempStart === 'number' && tempStart >= 0) {
|
|
4690
|
+
startIndex = Math.min(startIndex, tempStart);
|
|
4691
|
+
}
|
|
4692
|
+
});
|
|
4693
|
+
if (startIndex < Infinity && startIndex >= 0) {
|
|
4694
|
+
cutSrc = src.substring(0, startIndex + 1);
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
if (token = this.tokenizer.inlineText(cutSrc)) {
|
|
4698
|
+
src = src.substring(token.raw.length);
|
|
4699
|
+
if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
|
|
4700
|
+
prevChar = token.raw.slice(-1);
|
|
4701
|
+
}
|
|
4702
|
+
keepPrevChar = true;
|
|
4703
|
+
lastToken = tokens[tokens.length - 1];
|
|
4704
|
+
if (lastToken && lastToken.type === 'text') {
|
|
4705
|
+
lastToken.raw += token.raw;
|
|
4706
|
+
lastToken.text += token.text;
|
|
4707
|
+
}
|
|
4708
|
+
else {
|
|
4709
|
+
tokens.push(token);
|
|
4710
|
+
}
|
|
4711
|
+
continue;
|
|
4712
|
+
}
|
|
4713
|
+
if (src) {
|
|
4714
|
+
const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
|
|
4715
|
+
if (this.options.silent) {
|
|
4716
|
+
console.error(errMsg);
|
|
4717
|
+
break;
|
|
4718
|
+
}
|
|
4719
|
+
else {
|
|
4720
|
+
throw new Error(errMsg);
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
return tokens;
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
|
|
4728
|
+
/**
|
|
4729
|
+
* Renderer
|
|
4730
|
+
*/
|
|
4731
|
+
class _Renderer {
|
|
4732
|
+
options;
|
|
4733
|
+
constructor(options) {
|
|
4734
|
+
this.options = options || _defaults;
|
|
4735
|
+
}
|
|
4736
|
+
code(code, infostring, escaped) {
|
|
4737
|
+
const lang = (infostring || '').match(/^\S*/)?.[0];
|
|
4738
|
+
code = code.replace(/\n$/, '') + '\n';
|
|
4739
|
+
if (!lang) {
|
|
4740
|
+
return '<pre><code>'
|
|
4741
|
+
+ (escaped ? code : escape$1(code, true))
|
|
4742
|
+
+ '</code></pre>\n';
|
|
4743
|
+
}
|
|
4744
|
+
return '<pre><code class="language-'
|
|
4745
|
+
+ escape$1(lang)
|
|
4746
|
+
+ '">'
|
|
4747
|
+
+ (escaped ? code : escape$1(code, true))
|
|
4748
|
+
+ '</code></pre>\n';
|
|
4749
|
+
}
|
|
4750
|
+
blockquote(quote) {
|
|
4751
|
+
return `<blockquote>\n${quote}</blockquote>\n`;
|
|
4752
|
+
}
|
|
4753
|
+
html(html, block) {
|
|
4754
|
+
return html;
|
|
4755
|
+
}
|
|
4756
|
+
heading(text, level, raw) {
|
|
4757
|
+
// ignore IDs
|
|
4758
|
+
return `<h${level}>${text}</h${level}>\n`;
|
|
4759
|
+
}
|
|
4760
|
+
hr() {
|
|
4761
|
+
return '<hr>\n';
|
|
4762
|
+
}
|
|
4763
|
+
list(body, ordered, start) {
|
|
4764
|
+
const type = ordered ? 'ol' : 'ul';
|
|
4765
|
+
const startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
|
|
4766
|
+
return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
|
|
4767
|
+
}
|
|
4768
|
+
listitem(text, task, checked) {
|
|
4769
|
+
return `<li>${text}</li>\n`;
|
|
4770
|
+
}
|
|
4771
|
+
checkbox(checked) {
|
|
4772
|
+
return '<input '
|
|
4773
|
+
+ (checked ? 'checked="" ' : '')
|
|
4774
|
+
+ 'disabled="" type="checkbox">';
|
|
4775
|
+
}
|
|
4776
|
+
paragraph(text) {
|
|
4777
|
+
return `<p>${text}</p>\n`;
|
|
4778
|
+
}
|
|
4779
|
+
table(header, body) {
|
|
4780
|
+
if (body)
|
|
4781
|
+
body = `<tbody>${body}</tbody>`;
|
|
4782
|
+
return '<table>\n'
|
|
4783
|
+
+ '<thead>\n'
|
|
4784
|
+
+ header
|
|
4785
|
+
+ '</thead>\n'
|
|
4786
|
+
+ body
|
|
4787
|
+
+ '</table>\n';
|
|
4788
|
+
}
|
|
4789
|
+
tablerow(content) {
|
|
4790
|
+
return `<tr>\n${content}</tr>\n`;
|
|
4791
|
+
}
|
|
4792
|
+
tablecell(content, flags) {
|
|
4793
|
+
const type = flags.header ? 'th' : 'td';
|
|
4794
|
+
const tag = flags.align
|
|
4795
|
+
? `<${type} align="${flags.align}">`
|
|
4796
|
+
: `<${type}>`;
|
|
4797
|
+
return tag + content + `</${type}>\n`;
|
|
4798
|
+
}
|
|
4799
|
+
/**
|
|
4800
|
+
* span level renderer
|
|
4801
|
+
*/
|
|
4802
|
+
strong(text) {
|
|
4803
|
+
return `<strong>${text}</strong>`;
|
|
4804
|
+
}
|
|
4805
|
+
em(text) {
|
|
4806
|
+
return `<em>${text}</em>`;
|
|
4807
|
+
}
|
|
4808
|
+
codespan(text) {
|
|
4809
|
+
return `<code>${text}</code>`;
|
|
4810
|
+
}
|
|
4811
|
+
br() {
|
|
4812
|
+
return '<br>';
|
|
4813
|
+
}
|
|
4814
|
+
del(text) {
|
|
4815
|
+
return `<del>${text}</del>`;
|
|
4816
|
+
}
|
|
4817
|
+
link(href, title, text) {
|
|
4818
|
+
const cleanHref = cleanUrl(href);
|
|
4819
|
+
if (cleanHref === null) {
|
|
4820
|
+
return text;
|
|
4821
|
+
}
|
|
4822
|
+
href = cleanHref;
|
|
4823
|
+
let out = '<a href="' + href + '"';
|
|
4824
|
+
if (title) {
|
|
4825
|
+
out += ' title="' + title + '"';
|
|
4826
|
+
}
|
|
4827
|
+
out += '>' + text + '</a>';
|
|
4828
|
+
return out;
|
|
4829
|
+
}
|
|
4830
|
+
image(href, title, text) {
|
|
4831
|
+
const cleanHref = cleanUrl(href);
|
|
4832
|
+
if (cleanHref === null) {
|
|
4833
|
+
return text;
|
|
4834
|
+
}
|
|
4835
|
+
href = cleanHref;
|
|
4836
|
+
let out = `<img src="${href}" alt="${text}"`;
|
|
4837
|
+
if (title) {
|
|
4838
|
+
out += ` title="${title}"`;
|
|
4839
|
+
}
|
|
4840
|
+
out += '>';
|
|
4841
|
+
return out;
|
|
4842
|
+
}
|
|
4843
|
+
text(text) {
|
|
4844
|
+
return text;
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4848
|
+
/**
|
|
4849
|
+
* TextRenderer
|
|
4850
|
+
* returns only the textual part of the token
|
|
4851
|
+
*/
|
|
4852
|
+
class _TextRenderer {
|
|
4853
|
+
// no need for block level renderers
|
|
4854
|
+
strong(text) {
|
|
4855
|
+
return text;
|
|
4856
|
+
}
|
|
4857
|
+
em(text) {
|
|
4858
|
+
return text;
|
|
4859
|
+
}
|
|
4860
|
+
codespan(text) {
|
|
4861
|
+
return text;
|
|
4862
|
+
}
|
|
4863
|
+
del(text) {
|
|
4864
|
+
return text;
|
|
4865
|
+
}
|
|
4866
|
+
html(text) {
|
|
4867
|
+
return text;
|
|
4868
|
+
}
|
|
4869
|
+
text(text) {
|
|
4870
|
+
return text;
|
|
4871
|
+
}
|
|
4872
|
+
link(href, title, text) {
|
|
4873
|
+
return '' + text;
|
|
4874
|
+
}
|
|
4875
|
+
image(href, title, text) {
|
|
4876
|
+
return '' + text;
|
|
4877
|
+
}
|
|
4878
|
+
br() {
|
|
4879
|
+
return '';
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
|
|
4883
|
+
/**
|
|
4884
|
+
* Parsing & Compiling
|
|
4885
|
+
*/
|
|
4886
|
+
class _Parser {
|
|
4887
|
+
options;
|
|
4888
|
+
renderer;
|
|
4889
|
+
textRenderer;
|
|
4890
|
+
constructor(options) {
|
|
4891
|
+
this.options = options || _defaults;
|
|
4892
|
+
this.options.renderer = this.options.renderer || new _Renderer();
|
|
4893
|
+
this.renderer = this.options.renderer;
|
|
4894
|
+
this.renderer.options = this.options;
|
|
4895
|
+
this.textRenderer = new _TextRenderer();
|
|
4896
|
+
}
|
|
4897
|
+
/**
|
|
4898
|
+
* Static Parse Method
|
|
4899
|
+
*/
|
|
4900
|
+
static parse(tokens, options) {
|
|
4901
|
+
const parser = new _Parser(options);
|
|
4902
|
+
return parser.parse(tokens);
|
|
4903
|
+
}
|
|
4904
|
+
/**
|
|
4905
|
+
* Static Parse Inline Method
|
|
4906
|
+
*/
|
|
4907
|
+
static parseInline(tokens, options) {
|
|
4908
|
+
const parser = new _Parser(options);
|
|
4909
|
+
return parser.parseInline(tokens);
|
|
4910
|
+
}
|
|
4911
|
+
/**
|
|
4912
|
+
* Parse Loop
|
|
4913
|
+
*/
|
|
4914
|
+
parse(tokens, top = true) {
|
|
4915
|
+
let out = '';
|
|
4916
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
4917
|
+
const token = tokens[i];
|
|
4918
|
+
// Run any renderer extensions
|
|
4919
|
+
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
4920
|
+
const genericToken = token;
|
|
4921
|
+
const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
|
|
4922
|
+
if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(genericToken.type)) {
|
|
4923
|
+
out += ret || '';
|
|
4924
|
+
continue;
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
switch (token.type) {
|
|
4928
|
+
case 'space': {
|
|
4929
|
+
continue;
|
|
4930
|
+
}
|
|
4931
|
+
case 'hr': {
|
|
4932
|
+
out += this.renderer.hr();
|
|
4933
|
+
continue;
|
|
4934
|
+
}
|
|
4935
|
+
case 'heading': {
|
|
4936
|
+
const headingToken = token;
|
|
4937
|
+
out += this.renderer.heading(this.parseInline(headingToken.tokens), headingToken.depth, unescape(this.parseInline(headingToken.tokens, this.textRenderer)));
|
|
4938
|
+
continue;
|
|
4939
|
+
}
|
|
4940
|
+
case 'code': {
|
|
4941
|
+
const codeToken = token;
|
|
4942
|
+
out += this.renderer.code(codeToken.text, codeToken.lang, !!codeToken.escaped);
|
|
4943
|
+
continue;
|
|
4944
|
+
}
|
|
4945
|
+
case 'table': {
|
|
4946
|
+
const tableToken = token;
|
|
4947
|
+
let header = '';
|
|
4948
|
+
// header
|
|
4949
|
+
let cell = '';
|
|
4950
|
+
for (let j = 0; j < tableToken.header.length; j++) {
|
|
4951
|
+
cell += this.renderer.tablecell(this.parseInline(tableToken.header[j].tokens), { header: true, align: tableToken.align[j] });
|
|
4952
|
+
}
|
|
4953
|
+
header += this.renderer.tablerow(cell);
|
|
4954
|
+
let body = '';
|
|
4955
|
+
for (let j = 0; j < tableToken.rows.length; j++) {
|
|
4956
|
+
const row = tableToken.rows[j];
|
|
4957
|
+
cell = '';
|
|
4958
|
+
for (let k = 0; k < row.length; k++) {
|
|
4959
|
+
cell += this.renderer.tablecell(this.parseInline(row[k].tokens), { header: false, align: tableToken.align[k] });
|
|
4960
|
+
}
|
|
4961
|
+
body += this.renderer.tablerow(cell);
|
|
4962
|
+
}
|
|
4963
|
+
out += this.renderer.table(header, body);
|
|
4964
|
+
continue;
|
|
4965
|
+
}
|
|
4966
|
+
case 'blockquote': {
|
|
4967
|
+
const blockquoteToken = token;
|
|
4968
|
+
const body = this.parse(blockquoteToken.tokens);
|
|
4969
|
+
out += this.renderer.blockquote(body);
|
|
4970
|
+
continue;
|
|
4971
|
+
}
|
|
4972
|
+
case 'list': {
|
|
4973
|
+
const listToken = token;
|
|
4974
|
+
const ordered = listToken.ordered;
|
|
4975
|
+
const start = listToken.start;
|
|
4976
|
+
const loose = listToken.loose;
|
|
4977
|
+
let body = '';
|
|
4978
|
+
for (let j = 0; j < listToken.items.length; j++) {
|
|
4979
|
+
const item = listToken.items[j];
|
|
4980
|
+
const checked = item.checked;
|
|
4981
|
+
const task = item.task;
|
|
4982
|
+
let itemBody = '';
|
|
4983
|
+
if (item.task) {
|
|
4984
|
+
const checkbox = this.renderer.checkbox(!!checked);
|
|
4985
|
+
if (loose) {
|
|
4986
|
+
if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
|
|
4987
|
+
item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
|
|
4988
|
+
if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
|
|
4989
|
+
item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
else {
|
|
4993
|
+
item.tokens.unshift({
|
|
4994
|
+
type: 'text',
|
|
4995
|
+
text: checkbox + ' '
|
|
4996
|
+
});
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4999
|
+
else {
|
|
5000
|
+
itemBody += checkbox + ' ';
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
itemBody += this.parse(item.tokens, loose);
|
|
5004
|
+
body += this.renderer.listitem(itemBody, task, !!checked);
|
|
5005
|
+
}
|
|
5006
|
+
out += this.renderer.list(body, ordered, start);
|
|
5007
|
+
continue;
|
|
5008
|
+
}
|
|
5009
|
+
case 'html': {
|
|
5010
|
+
const htmlToken = token;
|
|
5011
|
+
out += this.renderer.html(htmlToken.text, htmlToken.block);
|
|
5012
|
+
continue;
|
|
5013
|
+
}
|
|
5014
|
+
case 'paragraph': {
|
|
5015
|
+
const paragraphToken = token;
|
|
5016
|
+
out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens));
|
|
5017
|
+
continue;
|
|
5018
|
+
}
|
|
5019
|
+
case 'text': {
|
|
5020
|
+
let textToken = token;
|
|
5021
|
+
let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;
|
|
5022
|
+
while (i + 1 < tokens.length && tokens[i + 1].type === 'text') {
|
|
5023
|
+
textToken = tokens[++i];
|
|
5024
|
+
body += '\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);
|
|
5025
|
+
}
|
|
5026
|
+
out += top ? this.renderer.paragraph(body) : body;
|
|
5027
|
+
continue;
|
|
5028
|
+
}
|
|
5029
|
+
default: {
|
|
5030
|
+
const errMsg = 'Token with "' + token.type + '" type was not found.';
|
|
5031
|
+
if (this.options.silent) {
|
|
5032
|
+
console.error(errMsg);
|
|
5033
|
+
return '';
|
|
5034
|
+
}
|
|
5035
|
+
else {
|
|
5036
|
+
throw new Error(errMsg);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
return out;
|
|
5042
|
+
}
|
|
5043
|
+
/**
|
|
5044
|
+
* Parse Inline Tokens
|
|
5045
|
+
*/
|
|
5046
|
+
parseInline(tokens, renderer) {
|
|
5047
|
+
renderer = renderer || this.renderer;
|
|
5048
|
+
let out = '';
|
|
5049
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
5050
|
+
const token = tokens[i];
|
|
5051
|
+
// Run any renderer extensions
|
|
5052
|
+
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
5053
|
+
const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
|
|
5054
|
+
if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
|
|
5055
|
+
out += ret || '';
|
|
5056
|
+
continue;
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
switch (token.type) {
|
|
5060
|
+
case 'escape': {
|
|
5061
|
+
const escapeToken = token;
|
|
5062
|
+
out += renderer.text(escapeToken.text);
|
|
5063
|
+
break;
|
|
5064
|
+
}
|
|
5065
|
+
case 'html': {
|
|
5066
|
+
const tagToken = token;
|
|
5067
|
+
out += renderer.html(tagToken.text);
|
|
5068
|
+
break;
|
|
5069
|
+
}
|
|
5070
|
+
case 'link': {
|
|
5071
|
+
const linkToken = token;
|
|
5072
|
+
out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer));
|
|
5073
|
+
break;
|
|
5074
|
+
}
|
|
5075
|
+
case 'image': {
|
|
5076
|
+
const imageToken = token;
|
|
5077
|
+
out += renderer.image(imageToken.href, imageToken.title, imageToken.text);
|
|
5078
|
+
break;
|
|
5079
|
+
}
|
|
5080
|
+
case 'strong': {
|
|
5081
|
+
const strongToken = token;
|
|
5082
|
+
out += renderer.strong(this.parseInline(strongToken.tokens, renderer));
|
|
5083
|
+
break;
|
|
5084
|
+
}
|
|
5085
|
+
case 'em': {
|
|
5086
|
+
const emToken = token;
|
|
5087
|
+
out += renderer.em(this.parseInline(emToken.tokens, renderer));
|
|
5088
|
+
break;
|
|
5089
|
+
}
|
|
5090
|
+
case 'codespan': {
|
|
5091
|
+
const codespanToken = token;
|
|
5092
|
+
out += renderer.codespan(codespanToken.text);
|
|
5093
|
+
break;
|
|
5094
|
+
}
|
|
5095
|
+
case 'br': {
|
|
5096
|
+
out += renderer.br();
|
|
5097
|
+
break;
|
|
5098
|
+
}
|
|
5099
|
+
case 'del': {
|
|
5100
|
+
const delToken = token;
|
|
5101
|
+
out += renderer.del(this.parseInline(delToken.tokens, renderer));
|
|
5102
|
+
break;
|
|
5103
|
+
}
|
|
5104
|
+
case 'text': {
|
|
5105
|
+
const textToken = token;
|
|
5106
|
+
out += renderer.text(textToken.text);
|
|
5107
|
+
break;
|
|
5108
|
+
}
|
|
5109
|
+
default: {
|
|
5110
|
+
const errMsg = 'Token with "' + token.type + '" type was not found.';
|
|
5111
|
+
if (this.options.silent) {
|
|
5112
|
+
console.error(errMsg);
|
|
5113
|
+
return '';
|
|
5114
|
+
}
|
|
5115
|
+
else {
|
|
5116
|
+
throw new Error(errMsg);
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
return out;
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
|
|
5125
|
+
class _Hooks {
|
|
5126
|
+
options;
|
|
5127
|
+
constructor(options) {
|
|
5128
|
+
this.options = options || _defaults;
|
|
5129
|
+
}
|
|
5130
|
+
static passThroughHooks = new Set([
|
|
5131
|
+
'preprocess',
|
|
5132
|
+
'postprocess',
|
|
5133
|
+
'processAllTokens'
|
|
5134
|
+
]);
|
|
5135
|
+
/**
|
|
5136
|
+
* Process markdown before marked
|
|
5137
|
+
*/
|
|
5138
|
+
preprocess(markdown) {
|
|
5139
|
+
return markdown;
|
|
5140
|
+
}
|
|
5141
|
+
/**
|
|
5142
|
+
* Process HTML after marked is finished
|
|
5143
|
+
*/
|
|
5144
|
+
postprocess(html) {
|
|
5145
|
+
return html;
|
|
5146
|
+
}
|
|
5147
|
+
/**
|
|
5148
|
+
* Process all tokens before walk tokens
|
|
5149
|
+
*/
|
|
5150
|
+
processAllTokens(tokens) {
|
|
5151
|
+
return tokens;
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
5154
|
+
|
|
5155
|
+
class Marked {
|
|
5156
|
+
defaults = _getDefaults();
|
|
5157
|
+
options = this.setOptions;
|
|
5158
|
+
parse = this.#parseMarkdown(_Lexer.lex, _Parser.parse);
|
|
5159
|
+
parseInline = this.#parseMarkdown(_Lexer.lexInline, _Parser.parseInline);
|
|
5160
|
+
Parser = _Parser;
|
|
5161
|
+
Renderer = _Renderer;
|
|
5162
|
+
TextRenderer = _TextRenderer;
|
|
5163
|
+
Lexer = _Lexer;
|
|
5164
|
+
Tokenizer = _Tokenizer;
|
|
5165
|
+
Hooks = _Hooks;
|
|
5166
|
+
constructor(...args) {
|
|
5167
|
+
this.use(...args);
|
|
5168
|
+
}
|
|
5169
|
+
/**
|
|
5170
|
+
* Run callback for every token
|
|
5171
|
+
*/
|
|
5172
|
+
walkTokens(tokens, callback) {
|
|
5173
|
+
let values = [];
|
|
5174
|
+
for (const token of tokens) {
|
|
5175
|
+
values = values.concat(callback.call(this, token));
|
|
5176
|
+
switch (token.type) {
|
|
5177
|
+
case 'table': {
|
|
5178
|
+
const tableToken = token;
|
|
5179
|
+
for (const cell of tableToken.header) {
|
|
5180
|
+
values = values.concat(this.walkTokens(cell.tokens, callback));
|
|
5181
|
+
}
|
|
5182
|
+
for (const row of tableToken.rows) {
|
|
5183
|
+
for (const cell of row) {
|
|
5184
|
+
values = values.concat(this.walkTokens(cell.tokens, callback));
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
break;
|
|
5188
|
+
}
|
|
5189
|
+
case 'list': {
|
|
5190
|
+
const listToken = token;
|
|
5191
|
+
values = values.concat(this.walkTokens(listToken.items, callback));
|
|
5192
|
+
break;
|
|
5193
|
+
}
|
|
5194
|
+
default: {
|
|
5195
|
+
const genericToken = token;
|
|
5196
|
+
if (this.defaults.extensions?.childTokens?.[genericToken.type]) {
|
|
5197
|
+
this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
|
|
5198
|
+
const tokens = genericToken[childTokens].flat(Infinity);
|
|
5199
|
+
values = values.concat(this.walkTokens(tokens, callback));
|
|
5200
|
+
});
|
|
5201
|
+
}
|
|
5202
|
+
else if (genericToken.tokens) {
|
|
5203
|
+
values = values.concat(this.walkTokens(genericToken.tokens, callback));
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
return values;
|
|
5209
|
+
}
|
|
5210
|
+
use(...args) {
|
|
5211
|
+
const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
|
|
5212
|
+
args.forEach((pack) => {
|
|
5213
|
+
// copy options to new object
|
|
5214
|
+
const opts = { ...pack };
|
|
5215
|
+
// set async to true if it was set to true before
|
|
5216
|
+
opts.async = this.defaults.async || opts.async || false;
|
|
5217
|
+
// ==-- Parse "addon" extensions --== //
|
|
5218
|
+
if (pack.extensions) {
|
|
5219
|
+
pack.extensions.forEach((ext) => {
|
|
5220
|
+
if (!ext.name) {
|
|
5221
|
+
throw new Error('extension name required');
|
|
5222
|
+
}
|
|
5223
|
+
if ('renderer' in ext) { // Renderer extensions
|
|
5224
|
+
const prevRenderer = extensions.renderers[ext.name];
|
|
5225
|
+
if (prevRenderer) {
|
|
5226
|
+
// Replace extension with func to run new extension but fall back if false
|
|
5227
|
+
extensions.renderers[ext.name] = function (...args) {
|
|
5228
|
+
let ret = ext.renderer.apply(this, args);
|
|
5229
|
+
if (ret === false) {
|
|
5230
|
+
ret = prevRenderer.apply(this, args);
|
|
5231
|
+
}
|
|
5232
|
+
return ret;
|
|
5233
|
+
};
|
|
5234
|
+
}
|
|
5235
|
+
else {
|
|
5236
|
+
extensions.renderers[ext.name] = ext.renderer;
|
|
5237
|
+
}
|
|
5238
|
+
}
|
|
5239
|
+
if ('tokenizer' in ext) { // Tokenizer Extensions
|
|
5240
|
+
if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
|
|
5241
|
+
throw new Error("extension level must be 'block' or 'inline'");
|
|
5242
|
+
}
|
|
5243
|
+
const extLevel = extensions[ext.level];
|
|
5244
|
+
if (extLevel) {
|
|
5245
|
+
extLevel.unshift(ext.tokenizer);
|
|
5246
|
+
}
|
|
5247
|
+
else {
|
|
5248
|
+
extensions[ext.level] = [ext.tokenizer];
|
|
5249
|
+
}
|
|
5250
|
+
if (ext.start) { // Function to check for start of token
|
|
5251
|
+
if (ext.level === 'block') {
|
|
5252
|
+
if (extensions.startBlock) {
|
|
5253
|
+
extensions.startBlock.push(ext.start);
|
|
5254
|
+
}
|
|
5255
|
+
else {
|
|
5256
|
+
extensions.startBlock = [ext.start];
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
else if (ext.level === 'inline') {
|
|
5260
|
+
if (extensions.startInline) {
|
|
5261
|
+
extensions.startInline.push(ext.start);
|
|
5262
|
+
}
|
|
5263
|
+
else {
|
|
5264
|
+
extensions.startInline = [ext.start];
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
}
|
|
5269
|
+
if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens
|
|
5270
|
+
extensions.childTokens[ext.name] = ext.childTokens;
|
|
5271
|
+
}
|
|
5272
|
+
});
|
|
5273
|
+
opts.extensions = extensions;
|
|
5274
|
+
}
|
|
5275
|
+
// ==-- Parse "overwrite" extensions --== //
|
|
5276
|
+
if (pack.renderer) {
|
|
5277
|
+
const renderer = this.defaults.renderer || new _Renderer(this.defaults);
|
|
5278
|
+
for (const prop in pack.renderer) {
|
|
5279
|
+
if (!(prop in renderer)) {
|
|
5280
|
+
throw new Error(`renderer '${prop}' does not exist`);
|
|
5281
|
+
}
|
|
5282
|
+
if (prop === 'options') {
|
|
5283
|
+
// ignore options property
|
|
5284
|
+
continue;
|
|
5285
|
+
}
|
|
5286
|
+
const rendererProp = prop;
|
|
5287
|
+
const rendererFunc = pack.renderer[rendererProp];
|
|
5288
|
+
const prevRenderer = renderer[rendererProp];
|
|
5289
|
+
// Replace renderer with func to run extension, but fall back if false
|
|
5290
|
+
renderer[rendererProp] = (...args) => {
|
|
5291
|
+
let ret = rendererFunc.apply(renderer, args);
|
|
5292
|
+
if (ret === false) {
|
|
5293
|
+
ret = prevRenderer.apply(renderer, args);
|
|
5294
|
+
}
|
|
5295
|
+
return ret || '';
|
|
5296
|
+
};
|
|
5297
|
+
}
|
|
5298
|
+
opts.renderer = renderer;
|
|
5299
|
+
}
|
|
5300
|
+
if (pack.tokenizer) {
|
|
5301
|
+
const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
|
|
5302
|
+
for (const prop in pack.tokenizer) {
|
|
5303
|
+
if (!(prop in tokenizer)) {
|
|
5304
|
+
throw new Error(`tokenizer '${prop}' does not exist`);
|
|
5305
|
+
}
|
|
5306
|
+
if (['options', 'rules', 'lexer'].includes(prop)) {
|
|
5307
|
+
// ignore options, rules, and lexer properties
|
|
5308
|
+
continue;
|
|
5309
|
+
}
|
|
5310
|
+
const tokenizerProp = prop;
|
|
5311
|
+
const tokenizerFunc = pack.tokenizer[tokenizerProp];
|
|
5312
|
+
const prevTokenizer = tokenizer[tokenizerProp];
|
|
5313
|
+
// Replace tokenizer with func to run extension, but fall back if false
|
|
5314
|
+
// @ts-expect-error cannot type tokenizer function dynamically
|
|
5315
|
+
tokenizer[tokenizerProp] = (...args) => {
|
|
5316
|
+
let ret = tokenizerFunc.apply(tokenizer, args);
|
|
5317
|
+
if (ret === false) {
|
|
5318
|
+
ret = prevTokenizer.apply(tokenizer, args);
|
|
5319
|
+
}
|
|
5320
|
+
return ret;
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
opts.tokenizer = tokenizer;
|
|
5324
|
+
}
|
|
5325
|
+
// ==-- Parse Hooks extensions --== //
|
|
5326
|
+
if (pack.hooks) {
|
|
5327
|
+
const hooks = this.defaults.hooks || new _Hooks();
|
|
5328
|
+
for (const prop in pack.hooks) {
|
|
5329
|
+
if (!(prop in hooks)) {
|
|
5330
|
+
throw new Error(`hook '${prop}' does not exist`);
|
|
5331
|
+
}
|
|
5332
|
+
if (prop === 'options') {
|
|
5333
|
+
// ignore options property
|
|
5334
|
+
continue;
|
|
5335
|
+
}
|
|
5336
|
+
const hooksProp = prop;
|
|
5337
|
+
const hooksFunc = pack.hooks[hooksProp];
|
|
5338
|
+
const prevHook = hooks[hooksProp];
|
|
5339
|
+
if (_Hooks.passThroughHooks.has(prop)) {
|
|
5340
|
+
// @ts-expect-error cannot type hook function dynamically
|
|
5341
|
+
hooks[hooksProp] = (arg) => {
|
|
5342
|
+
if (this.defaults.async) {
|
|
5343
|
+
return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {
|
|
5344
|
+
return prevHook.call(hooks, ret);
|
|
5345
|
+
});
|
|
5346
|
+
}
|
|
5347
|
+
const ret = hooksFunc.call(hooks, arg);
|
|
5348
|
+
return prevHook.call(hooks, ret);
|
|
5349
|
+
};
|
|
5350
|
+
}
|
|
5351
|
+
else {
|
|
5352
|
+
// @ts-expect-error cannot type hook function dynamically
|
|
5353
|
+
hooks[hooksProp] = (...args) => {
|
|
5354
|
+
let ret = hooksFunc.apply(hooks, args);
|
|
5355
|
+
if (ret === false) {
|
|
5356
|
+
ret = prevHook.apply(hooks, args);
|
|
5357
|
+
}
|
|
5358
|
+
return ret;
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
opts.hooks = hooks;
|
|
5363
|
+
}
|
|
5364
|
+
// ==-- Parse WalkTokens extensions --== //
|
|
5365
|
+
if (pack.walkTokens) {
|
|
5366
|
+
const walkTokens = this.defaults.walkTokens;
|
|
5367
|
+
const packWalktokens = pack.walkTokens;
|
|
5368
|
+
opts.walkTokens = function (token) {
|
|
5369
|
+
let values = [];
|
|
5370
|
+
values.push(packWalktokens.call(this, token));
|
|
5371
|
+
if (walkTokens) {
|
|
5372
|
+
values = values.concat(walkTokens.call(this, token));
|
|
5373
|
+
}
|
|
5374
|
+
return values;
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5377
|
+
this.defaults = { ...this.defaults, ...opts };
|
|
5378
|
+
});
|
|
5379
|
+
return this;
|
|
5380
|
+
}
|
|
5381
|
+
setOptions(opt) {
|
|
5382
|
+
this.defaults = { ...this.defaults, ...opt };
|
|
5383
|
+
return this;
|
|
5384
|
+
}
|
|
5385
|
+
lexer(src, options) {
|
|
5386
|
+
return _Lexer.lex(src, options ?? this.defaults);
|
|
5387
|
+
}
|
|
5388
|
+
parser(tokens, options) {
|
|
5389
|
+
return _Parser.parse(tokens, options ?? this.defaults);
|
|
5390
|
+
}
|
|
5391
|
+
#parseMarkdown(lexer, parser) {
|
|
5392
|
+
return (src, options) => {
|
|
5393
|
+
const origOpt = { ...options };
|
|
5394
|
+
const opt = { ...this.defaults, ...origOpt };
|
|
5395
|
+
// Show warning if an extension set async to true but the parse was called with async: false
|
|
5396
|
+
if (this.defaults.async === true && origOpt.async === false) {
|
|
5397
|
+
if (!opt.silent) {
|
|
5398
|
+
console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.');
|
|
5399
|
+
}
|
|
5400
|
+
opt.async = true;
|
|
5401
|
+
}
|
|
5402
|
+
const throwError = this.#onError(!!opt.silent, !!opt.async);
|
|
5403
|
+
// throw error in case of non string input
|
|
5404
|
+
if (typeof src === 'undefined' || src === null) {
|
|
5405
|
+
return throwError(new Error('marked(): input parameter is undefined or null'));
|
|
5406
|
+
}
|
|
5407
|
+
if (typeof src !== 'string') {
|
|
5408
|
+
return throwError(new Error('marked(): input parameter is of type '
|
|
5409
|
+
+ Object.prototype.toString.call(src) + ', string expected'));
|
|
5410
|
+
}
|
|
5411
|
+
if (opt.hooks) {
|
|
5412
|
+
opt.hooks.options = opt;
|
|
5413
|
+
}
|
|
5414
|
+
if (opt.async) {
|
|
5415
|
+
return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
|
|
5416
|
+
.then(src => lexer(src, opt))
|
|
5417
|
+
.then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens)
|
|
5418
|
+
.then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
|
|
5419
|
+
.then(tokens => parser(tokens, opt))
|
|
5420
|
+
.then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
|
|
5421
|
+
.catch(throwError);
|
|
5422
|
+
}
|
|
5423
|
+
try {
|
|
5424
|
+
if (opt.hooks) {
|
|
5425
|
+
src = opt.hooks.preprocess(src);
|
|
5426
|
+
}
|
|
5427
|
+
let tokens = lexer(src, opt);
|
|
5428
|
+
if (opt.hooks) {
|
|
5429
|
+
tokens = opt.hooks.processAllTokens(tokens);
|
|
5430
|
+
}
|
|
5431
|
+
if (opt.walkTokens) {
|
|
5432
|
+
this.walkTokens(tokens, opt.walkTokens);
|
|
5433
|
+
}
|
|
5434
|
+
let html = parser(tokens, opt);
|
|
5435
|
+
if (opt.hooks) {
|
|
5436
|
+
html = opt.hooks.postprocess(html);
|
|
5437
|
+
}
|
|
5438
|
+
return html;
|
|
5439
|
+
}
|
|
5440
|
+
catch (e) {
|
|
5441
|
+
return throwError(e);
|
|
5442
|
+
}
|
|
5443
|
+
};
|
|
5444
|
+
}
|
|
5445
|
+
#onError(silent, async) {
|
|
5446
|
+
return (e) => {
|
|
5447
|
+
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
|
5448
|
+
if (silent) {
|
|
5449
|
+
const msg = '<p>An error occurred:</p><pre>'
|
|
5450
|
+
+ escape$1(e.message + '', true)
|
|
5451
|
+
+ '</pre>';
|
|
5452
|
+
if (async) {
|
|
5453
|
+
return Promise.resolve(msg);
|
|
5454
|
+
}
|
|
5455
|
+
return msg;
|
|
5456
|
+
}
|
|
5457
|
+
if (async) {
|
|
5458
|
+
return Promise.reject(e);
|
|
5459
|
+
}
|
|
5460
|
+
throw e;
|
|
5461
|
+
};
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
|
|
5465
|
+
const markedInstance = new Marked();
|
|
5466
|
+
function marked(src, opt) {
|
|
5467
|
+
return markedInstance.parse(src, opt);
|
|
5468
|
+
}
|
|
5469
|
+
/**
|
|
5470
|
+
* Sets the default options.
|
|
5471
|
+
*
|
|
5472
|
+
* @param options Hash of options
|
|
5473
|
+
*/
|
|
5474
|
+
marked.options =
|
|
5475
|
+
marked.setOptions = function (options) {
|
|
5476
|
+
markedInstance.setOptions(options);
|
|
5477
|
+
marked.defaults = markedInstance.defaults;
|
|
5478
|
+
changeDefaults(marked.defaults);
|
|
5479
|
+
return marked;
|
|
5480
|
+
};
|
|
5481
|
+
/**
|
|
5482
|
+
* Gets the original marked default options.
|
|
5483
|
+
*/
|
|
5484
|
+
marked.getDefaults = _getDefaults;
|
|
5485
|
+
marked.defaults = _defaults;
|
|
5486
|
+
/**
|
|
5487
|
+
* Use Extension
|
|
5488
|
+
*/
|
|
5489
|
+
marked.use = function (...args) {
|
|
5490
|
+
markedInstance.use(...args);
|
|
5491
|
+
marked.defaults = markedInstance.defaults;
|
|
5492
|
+
changeDefaults(marked.defaults);
|
|
5493
|
+
return marked;
|
|
5494
|
+
};
|
|
5495
|
+
/**
|
|
5496
|
+
* Run callback for every token
|
|
5497
|
+
*/
|
|
5498
|
+
marked.walkTokens = function (tokens, callback) {
|
|
5499
|
+
return markedInstance.walkTokens(tokens, callback);
|
|
5500
|
+
};
|
|
5501
|
+
/**
|
|
5502
|
+
* Compiles markdown to HTML without enclosing `p` tag.
|
|
5503
|
+
*
|
|
5504
|
+
* @param src String of markdown source to be compiled
|
|
5505
|
+
* @param options Hash of options
|
|
5506
|
+
* @return String of compiled HTML
|
|
5507
|
+
*/
|
|
5508
|
+
marked.parseInline = markedInstance.parseInline;
|
|
5509
|
+
/**
|
|
5510
|
+
* Expose
|
|
5511
|
+
*/
|
|
5512
|
+
marked.Parser = _Parser;
|
|
5513
|
+
marked.parser = _Parser.parse;
|
|
5514
|
+
marked.Renderer = _Renderer;
|
|
5515
|
+
marked.TextRenderer = _TextRenderer;
|
|
5516
|
+
marked.Lexer = _Lexer;
|
|
5517
|
+
marked.lexer = _Lexer.lex;
|
|
5518
|
+
marked.Tokenizer = _Tokenizer;
|
|
5519
|
+
marked.Hooks = _Hooks;
|
|
5520
|
+
marked.parse = marked;
|
|
5521
|
+
marked.options;
|
|
5522
|
+
marked.setOptions;
|
|
5523
|
+
marked.use;
|
|
5524
|
+
marked.walkTokens;
|
|
5525
|
+
marked.parseInline;
|
|
5526
|
+
_Parser.parse;
|
|
5527
|
+
_Lexer.lex;
|
|
5528
|
+
|
|
5529
|
+
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
5530
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5531
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5532
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5533
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5534
|
+
};
|
|
5535
|
+
/**
|
|
5536
|
+
* AI chatbot component with SSE streaming.
|
|
5537
|
+
*
|
|
5538
|
+
* Accepts a `send` callback that returns a streaming Response (SSE format).
|
|
5539
|
+
* Parses the stream for text tokens, status updates, and errors.
|
|
5540
|
+
* Dispatches a `stream-event` custom event for every SSE message so consumers can react.
|
|
5541
|
+
*
|
|
5542
|
+
* ## SSE Stream Format
|
|
5543
|
+
* The component expects `data:` lines with JSON payloads containing a `type` field:
|
|
5544
|
+
* - `STATUS` — `{ type: "STATUS", message: "Thinking..." }`
|
|
5545
|
+
* - `RESPONSE_PART` — `{ type: "RESPONSE_PART", message: "token text" }`
|
|
5546
|
+
* - `TOOL_RESULT` — `{ type: "TOOL_RESULT", message: "tool_name", data: {...} }`
|
|
5547
|
+
* - `ERROR` — `{ type: "ERROR", message: "Something went wrong" }`
|
|
5548
|
+
* - `HEARTBEAT` — `{ type: "HEARTBEAT" }` (ignored)
|
|
5549
|
+
*
|
|
5550
|
+
* The final event should include `finished: true` to signal stream completion.
|
|
5551
|
+
*
|
|
5552
|
+
* ## Usage
|
|
5553
|
+
* ```html
|
|
5554
|
+
* <kr-chatbot
|
|
5555
|
+
* title="AI Assistant"
|
|
5556
|
+
* .send=${(params) => {
|
|
5557
|
+
* return fetch('/api/ai/chat/stream', {
|
|
5558
|
+
* method: 'POST',
|
|
5559
|
+
* headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' },
|
|
5560
|
+
* credentials: 'include',
|
|
5561
|
+
* body: JSON.stringify({ userText: params.message })
|
|
5562
|
+
* });
|
|
5563
|
+
* }}
|
|
5564
|
+
* ></kr-chatbot>
|
|
5565
|
+
* ```
|
|
5566
|
+
*
|
|
5567
|
+
* @slot - Optional slot content displayed above the messages area
|
|
5568
|
+
*
|
|
5569
|
+
* @fires message-submit - When the user sends a message. Cancelable. Detail: `{ message: string }`
|
|
5570
|
+
* @fires stream-event - Dispatched for every SSE message received. Detail contains the parsed event data.
|
|
5571
|
+
*/
|
|
5572
|
+
let KRChatbot = class KRChatbot extends i$1 {
|
|
5573
|
+
constructor() {
|
|
5574
|
+
super(...arguments);
|
|
5575
|
+
// --- Private properties ---
|
|
5576
|
+
this._reader = null;
|
|
5577
|
+
this._decoder = new TextDecoder();
|
|
5578
|
+
this._buffer = '';
|
|
5579
|
+
this._userHasScrolledUp = false;
|
|
5580
|
+
this._isDragging = false;
|
|
5581
|
+
this._isResizing = false;
|
|
5582
|
+
this._overlay = null;
|
|
5583
|
+
this._resizeDir = '';
|
|
5584
|
+
this._dragStartX = 0;
|
|
5585
|
+
this._dragStartY = 0;
|
|
5586
|
+
this._dragStartLeft = 0;
|
|
5587
|
+
this._dragStartTop = 0;
|
|
5588
|
+
this._resizeStartW = 0;
|
|
5589
|
+
this._resizeStartH = 0;
|
|
5590
|
+
// --- @property (public API) ---
|
|
5591
|
+
/**
|
|
5592
|
+
* Callback function for sending messages. Receives the user's message and
|
|
5593
|
+
* current conversation history. Must return a Response with a streaming SSE body.
|
|
5594
|
+
*/
|
|
5595
|
+
this.send = null;
|
|
5596
|
+
/**
|
|
5597
|
+
* Callback function called when the user clears the conversation.
|
|
5598
|
+
* Must return a Promise — messages are only cleared if it resolves.
|
|
5599
|
+
*/
|
|
5600
|
+
this.clear = null;
|
|
5601
|
+
/**
|
|
5602
|
+
* Callback function called on init to load existing conversation messages.
|
|
5603
|
+
* Must return a Promise that resolves with an array of KRChatbotMessage.
|
|
5604
|
+
*/
|
|
5605
|
+
this.load = null;
|
|
5606
|
+
/**
|
|
5607
|
+
* Conversation messages. Can be set externally for initial messages.
|
|
5608
|
+
* Updated internally as the conversation progresses.
|
|
5609
|
+
*/
|
|
5610
|
+
this.messages = [];
|
|
5611
|
+
/**
|
|
5612
|
+
* Header title text.
|
|
5613
|
+
*/
|
|
5614
|
+
this.title = 'Kat';
|
|
5615
|
+
/**
|
|
5616
|
+
* Header subtitle text (shown below title with a green status dot).
|
|
5617
|
+
*/
|
|
5618
|
+
this.subtitle = '';
|
|
5619
|
+
/**
|
|
5620
|
+
* Input placeholder text.
|
|
5621
|
+
*/
|
|
5622
|
+
this.placeholder = 'Type a message...';
|
|
5623
|
+
/**
|
|
5624
|
+
* Whether the chat panel is open. Only relevant in floating mode.
|
|
5625
|
+
*/
|
|
5626
|
+
this.opened = false;
|
|
5627
|
+
// --- @state (internal) ---
|
|
5628
|
+
this._inputValue = '';
|
|
3052
5629
|
this._isStreaming = false;
|
|
3053
5630
|
this._statusText = '';
|
|
3054
5631
|
this._error = '';
|
|
@@ -3057,9 +5634,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3057
5634
|
let newLeft = this._dragStartLeft + (e.clientX - this._dragStartX);
|
|
3058
5635
|
let newTop = this._dragStartTop + (e.clientY - this._dragStartY);
|
|
3059
5636
|
const w = this._panelEl.offsetWidth;
|
|
3060
|
-
const h = this._panelEl.offsetHeight;
|
|
3061
5637
|
newLeft = Math.max(-w + 48, Math.min(newLeft, window.innerWidth - 48));
|
|
3062
|
-
newTop = Math.max(
|
|
5638
|
+
newTop = Math.max(0, Math.min(newTop, window.innerHeight - 48));
|
|
3063
5639
|
this._panelEl.style.left = newLeft + 'px';
|
|
3064
5640
|
this._panelEl.style.top = newTop + 'px';
|
|
3065
5641
|
}
|
|
@@ -3078,21 +5654,15 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3078
5654
|
newW = Math.max(minW, Math.min(this._resizeStartW + dx, maxW));
|
|
3079
5655
|
}
|
|
3080
5656
|
if (this._resizeDir.includes('w')) {
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
newW = proposedW;
|
|
3084
|
-
newLeft = this._dragStartLeft + dx;
|
|
3085
|
-
}
|
|
5657
|
+
newW = Math.max(minW, Math.min(this._resizeStartW - dx, maxW));
|
|
5658
|
+
newLeft = this._dragStartLeft + (this._resizeStartW - newW);
|
|
3086
5659
|
}
|
|
3087
5660
|
if (this._resizeDir.includes('s')) {
|
|
3088
5661
|
newH = Math.max(minH, Math.min(this._resizeStartH + dy, maxH));
|
|
3089
5662
|
}
|
|
3090
5663
|
if (this._resizeDir.includes('n')) {
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
newH = proposedH;
|
|
3094
|
-
newTop = this._dragStartTop + dy;
|
|
3095
|
-
}
|
|
5664
|
+
newH = Math.max(minH, Math.min(this._resizeStartH - dy, maxH));
|
|
5665
|
+
newTop = this._dragStartTop + (this._resizeStartH - newH);
|
|
3096
5666
|
}
|
|
3097
5667
|
newLeft = Math.max(0, newLeft);
|
|
3098
5668
|
newTop = Math.max(0, newTop);
|
|
@@ -3105,17 +5675,30 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3105
5675
|
this._handleMouseUp = () => {
|
|
3106
5676
|
if (this._isDragging) {
|
|
3107
5677
|
this._isDragging = false;
|
|
3108
|
-
this._panelEl.classList.remove('
|
|
5678
|
+
this._panelEl.classList.remove('panel--dragging');
|
|
3109
5679
|
}
|
|
3110
5680
|
if (this._isResizing) {
|
|
3111
5681
|
this._isResizing = false;
|
|
3112
|
-
this._panelEl.classList.remove('
|
|
5682
|
+
this._panelEl.classList.remove('panel--resizing');
|
|
3113
5683
|
}
|
|
5684
|
+
this._hideOverlay();
|
|
3114
5685
|
document.removeEventListener('mousemove', this._handleMouseMove);
|
|
3115
5686
|
document.removeEventListener('mouseup', this._handleMouseUp);
|
|
5687
|
+
this._saveState();
|
|
3116
5688
|
};
|
|
3117
5689
|
}
|
|
3118
5690
|
// --- Lifecycle ---
|
|
5691
|
+
connectedCallback() {
|
|
5692
|
+
super.connectedCallback();
|
|
5693
|
+
if (this.load) {
|
|
5694
|
+
this.load().then((messages) => {
|
|
5695
|
+
if (messages && messages.length) {
|
|
5696
|
+
this.messages = messages;
|
|
5697
|
+
}
|
|
5698
|
+
}).catch(() => { });
|
|
5699
|
+
}
|
|
5700
|
+
this._restoreState();
|
|
5701
|
+
}
|
|
3119
5702
|
disconnectedCallback() {
|
|
3120
5703
|
super.disconnectedCallback();
|
|
3121
5704
|
if (this._reader) {
|
|
@@ -3127,7 +5710,7 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3127
5710
|
}
|
|
3128
5711
|
updated(changed) {
|
|
3129
5712
|
if (changed.has('messages') || changed.has('_statusText')) {
|
|
3130
|
-
if (!this._userHasScrolledUp && this._messagesEl) {
|
|
5713
|
+
if (!this._userHasScrolledUp && !this._isStreaming && this._messagesEl) {
|
|
3131
5714
|
requestAnimationFrame(() => {
|
|
3132
5715
|
if (this._messagesEl) {
|
|
3133
5716
|
this._messagesEl.scrollTop = this._messagesEl.scrollHeight;
|
|
@@ -3151,6 +5734,38 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3151
5734
|
this._handleStop();
|
|
3152
5735
|
}
|
|
3153
5736
|
// --- Private methods ---
|
|
5737
|
+
/**
|
|
5738
|
+
* Shows a full-viewport transparent overlay during drag/resize operations.
|
|
5739
|
+
*
|
|
5740
|
+
* This overlay solves a critical rendering issue when the chatbot is used inside
|
|
5741
|
+
* a page that contains iframes (e.g., the AI editor shell where the page content
|
|
5742
|
+
* is rendered in an iframe and the chatbot floats on top).
|
|
5743
|
+
*
|
|
5744
|
+
* Without the overlay, modifying the iframe's `pointer-events` style during drag
|
|
5745
|
+
* (to prevent it from swallowing mousemove events) causes Chrome to recalculate
|
|
5746
|
+
* compositing layers. This layer recalculation blocks the browser from repainting
|
|
5747
|
+
* the chatbot panel's style changes (width/height/position) even though they are
|
|
5748
|
+
* correctly applied to the DOM. The result is that the panel appears frozen while
|
|
5749
|
+
* the user drags, despite the inline styles updating on every mousemove.
|
|
5750
|
+
*
|
|
5751
|
+
* The overlay approach avoids this entirely: instead of touching the iframe's styles,
|
|
5752
|
+
* we place a transparent div (z-index 9999) above the iframe but below the chatbot
|
|
5753
|
+
* (z-index 10000). This div intercepts all mouse events that would otherwise hit the
|
|
5754
|
+
* iframe, without triggering any compositing layer changes on the iframe itself.
|
|
5755
|
+
*/
|
|
5756
|
+
_showOverlay() {
|
|
5757
|
+
if (!this._overlay) {
|
|
5758
|
+
this._overlay = document.createElement('div');
|
|
5759
|
+
this._overlay.style.cssText = 'position:fixed; inset:0; z-index:9999; display:none;';
|
|
5760
|
+
document.body.appendChild(this._overlay);
|
|
5761
|
+
}
|
|
5762
|
+
this._overlay.style.display = 'block';
|
|
5763
|
+
}
|
|
5764
|
+
_hideOverlay() {
|
|
5765
|
+
if (this._overlay) {
|
|
5766
|
+
this._overlay.style.display = 'none';
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
3154
5769
|
_handleHeaderMouseDown(e) {
|
|
3155
5770
|
// Ignore clicks on buttons inside the header
|
|
3156
5771
|
if (e.target.closest('button')) {
|
|
@@ -3160,7 +5775,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3160
5775
|
return;
|
|
3161
5776
|
}
|
|
3162
5777
|
this._isDragging = true;
|
|
3163
|
-
this._panelEl.classList.add('
|
|
5778
|
+
this._panelEl.classList.add('panel--dragging');
|
|
5779
|
+
this._showOverlay();
|
|
3164
5780
|
const rect = this._panelEl.getBoundingClientRect();
|
|
3165
5781
|
this._panelEl.style.left = rect.left + 'px';
|
|
3166
5782
|
this._panelEl.style.top = rect.top + 'px';
|
|
@@ -3181,7 +5797,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3181
5797
|
}
|
|
3182
5798
|
this._isResizing = true;
|
|
3183
5799
|
this._resizeDir = e.currentTarget.dataset.dir || '';
|
|
3184
|
-
this._panelEl.classList.add('
|
|
5800
|
+
this._panelEl.classList.add('panel--resizing');
|
|
5801
|
+
this._showOverlay();
|
|
3185
5802
|
const rect = this._panelEl.getBoundingClientRect();
|
|
3186
5803
|
this._panelEl.style.left = rect.left + 'px';
|
|
3187
5804
|
this._panelEl.style.top = rect.top + 'px';
|
|
@@ -3201,16 +5818,75 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3201
5818
|
}
|
|
3202
5819
|
_handleToggle() {
|
|
3203
5820
|
this.opened = !this.opened;
|
|
3204
|
-
// Reset position when opening so it returns to default bottom-right
|
|
3205
5821
|
if (this.opened && this._panelEl) {
|
|
3206
|
-
this.
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
this.
|
|
5822
|
+
this._applyStoredLayout();
|
|
5823
|
+
}
|
|
5824
|
+
this._saveState();
|
|
5825
|
+
}
|
|
5826
|
+
_saveState() {
|
|
5827
|
+
try {
|
|
5828
|
+
const state = { opened: String(this.opened) };
|
|
5829
|
+
if (this._panelEl) {
|
|
5830
|
+
const s = this._panelEl.style;
|
|
5831
|
+
if (s.left) {
|
|
5832
|
+
state.left = s.left;
|
|
5833
|
+
}
|
|
5834
|
+
if (s.top) {
|
|
5835
|
+
state.top = s.top;
|
|
5836
|
+
}
|
|
5837
|
+
if (s.width) {
|
|
5838
|
+
state.width = s.width;
|
|
5839
|
+
}
|
|
5840
|
+
if (s.height) {
|
|
5841
|
+
state.height = s.height;
|
|
5842
|
+
}
|
|
5843
|
+
if (s.position) {
|
|
5844
|
+
state.position = s.position;
|
|
5845
|
+
}
|
|
5846
|
+
}
|
|
5847
|
+
localStorage.setItem('kr-chatbot-state', JSON.stringify(state));
|
|
5848
|
+
}
|
|
5849
|
+
catch { /* localStorage not available */ }
|
|
5850
|
+
}
|
|
5851
|
+
_restoreState() {
|
|
5852
|
+
try {
|
|
5853
|
+
const raw = localStorage.getItem('kr-chatbot-state');
|
|
5854
|
+
if (!raw) {
|
|
5855
|
+
return;
|
|
5856
|
+
}
|
|
5857
|
+
const state = JSON.parse(raw);
|
|
5858
|
+
if (state.opened === 'true') {
|
|
5859
|
+
this.opened = true;
|
|
5860
|
+
// Apply layout after first render
|
|
5861
|
+
this.updateComplete.then(() => this._applyStoredLayout());
|
|
5862
|
+
}
|
|
5863
|
+
}
|
|
5864
|
+
catch { /* localStorage not available */ }
|
|
5865
|
+
}
|
|
5866
|
+
_applyStoredLayout() {
|
|
5867
|
+
try {
|
|
5868
|
+
const raw = localStorage.getItem('kr-chatbot-state');
|
|
5869
|
+
if (!raw || !this._panelEl) {
|
|
5870
|
+
return;
|
|
5871
|
+
}
|
|
5872
|
+
const state = JSON.parse(raw);
|
|
5873
|
+
if (state.position) {
|
|
5874
|
+
this._panelEl.style.position = state.position;
|
|
5875
|
+
}
|
|
5876
|
+
if (state.left) {
|
|
5877
|
+
this._panelEl.style.left = state.left;
|
|
5878
|
+
}
|
|
5879
|
+
if (state.top) {
|
|
5880
|
+
this._panelEl.style.top = state.top;
|
|
5881
|
+
}
|
|
5882
|
+
if (state.width) {
|
|
5883
|
+
this._panelEl.style.width = state.width;
|
|
5884
|
+
}
|
|
5885
|
+
if (state.height) {
|
|
5886
|
+
this._panelEl.style.height = state.height;
|
|
5887
|
+
}
|
|
3213
5888
|
}
|
|
5889
|
+
catch { /* localStorage not available */ }
|
|
3214
5890
|
}
|
|
3215
5891
|
_handleInputChange(e) {
|
|
3216
5892
|
this._inputValue = e.target.value;
|
|
@@ -3260,6 +5936,27 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3260
5936
|
}];
|
|
3261
5937
|
this._isStreaming = true;
|
|
3262
5938
|
this._statusText = '';
|
|
5939
|
+
// Scroll user's message to the top (Gemini-style).
|
|
5940
|
+
// Set min-height on the assistant message = container height so there's enough
|
|
5941
|
+
// scroll room below the user message to push it to the top.
|
|
5942
|
+
this.updateComplete.then(() => {
|
|
5943
|
+
if (!this._messagesEl) {
|
|
5944
|
+
return;
|
|
5945
|
+
}
|
|
5946
|
+
// Clear min-height from previous responses
|
|
5947
|
+
this._messagesEl.querySelectorAll('.message--assistant').forEach((el) => {
|
|
5948
|
+
el.style.minHeight = '';
|
|
5949
|
+
});
|
|
5950
|
+
const allMsgEls = this._messagesEl.querySelectorAll('.message');
|
|
5951
|
+
const userMsgEl = allMsgEls[this.messages.length - 2];
|
|
5952
|
+
const assistantMsgEl = allMsgEls[this.messages.length - 1];
|
|
5953
|
+
if (assistantMsgEl) {
|
|
5954
|
+
assistantMsgEl.style.minHeight = this._messagesEl.clientHeight + 'px';
|
|
5955
|
+
}
|
|
5956
|
+
if (userMsgEl) {
|
|
5957
|
+
this._messagesEl.scrollTop = userMsgEl.offsetTop - this._messagesEl.offsetTop - 24;
|
|
5958
|
+
}
|
|
5959
|
+
});
|
|
3263
5960
|
this.send({
|
|
3264
5961
|
message: messageText,
|
|
3265
5962
|
messages: this.messages.slice(0, -1),
|
|
@@ -3387,49 +6084,6 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3387
6084
|
}
|
|
3388
6085
|
}
|
|
3389
6086
|
}
|
|
3390
|
-
else if (data.type === 'ACTION') {
|
|
3391
|
-
const action = data;
|
|
3392
|
-
const actionEvent = new CustomEvent('action', {
|
|
3393
|
-
detail: {
|
|
3394
|
-
action: action,
|
|
3395
|
-
},
|
|
3396
|
-
bubbles: true,
|
|
3397
|
-
composed: true,
|
|
3398
|
-
cancelable: true,
|
|
3399
|
-
});
|
|
3400
|
-
this.dispatchEvent(actionEvent);
|
|
3401
|
-
if (!actionEvent.defaultPrevented) {
|
|
3402
|
-
if (action.action === 'RELOAD') {
|
|
3403
|
-
location.reload();
|
|
3404
|
-
}
|
|
3405
|
-
else if (action.action === 'NAVIGATE') {
|
|
3406
|
-
if (action.data && action.data.url) {
|
|
3407
|
-
window.location.href = action.data.url;
|
|
3408
|
-
}
|
|
3409
|
-
}
|
|
3410
|
-
else if (action.action === 'OPEN_TAB') {
|
|
3411
|
-
if (action.data && action.data.url) {
|
|
3412
|
-
window.open(action.data.url, '_blank');
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
else if (action.action === 'UPDATE_HTML') {
|
|
3416
|
-
if (action.data && action.data.selector && action.data.html) {
|
|
3417
|
-
const el = document.querySelector(action.data.selector);
|
|
3418
|
-
if (el) {
|
|
3419
|
-
el.innerHTML = action.data.html;
|
|
3420
|
-
}
|
|
3421
|
-
}
|
|
3422
|
-
}
|
|
3423
|
-
else if (action.action === 'SCROLL_TO') {
|
|
3424
|
-
if (action.data && action.data.selector) {
|
|
3425
|
-
const el = document.querySelector(action.data.selector);
|
|
3426
|
-
if (el) {
|
|
3427
|
-
el.scrollIntoView({ behavior: 'smooth' });
|
|
3428
|
-
}
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3432
|
-
}
|
|
3433
6087
|
else if (data.type === 'ERROR') {
|
|
3434
6088
|
this._handleStreamError(String(data.message || 'Unknown error'));
|
|
3435
6089
|
}
|
|
@@ -3463,157 +6117,192 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3463
6117
|
}
|
|
3464
6118
|
}
|
|
3465
6119
|
}
|
|
3466
|
-
/**
|
|
3467
|
-
* Lightweight text formatting for assistant messages.
|
|
3468
|
-
* Handles code blocks, inline code, bold, and line breaks.
|
|
3469
|
-
* Escapes HTML entities first to prevent XSS.
|
|
3470
|
-
*/
|
|
3471
|
-
_formatAssistantContent(text) {
|
|
3472
|
-
// Escape HTML entities
|
|
3473
|
-
let escaped = text
|
|
3474
|
-
.replace(/&/g, '&')
|
|
3475
|
-
.replace(/</g, '<')
|
|
3476
|
-
.replace(/>/g, '>')
|
|
3477
|
-
.replace(/"/g, '"')
|
|
3478
|
-
.replace(/'/g, ''');
|
|
3479
|
-
// Code blocks: ```...```
|
|
3480
|
-
escaped = escaped.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre><code>$2</code></pre>');
|
|
3481
|
-
// Inline code: `...`
|
|
3482
|
-
escaped = escaped.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
3483
|
-
// Bold: **...**
|
|
3484
|
-
escaped = escaped.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
3485
|
-
// Split on code blocks to only convert newlines outside of pre tags
|
|
3486
|
-
const parts = escaped.split(/(<pre><code>[\s\S]*?<\/code><\/pre>)/g);
|
|
3487
|
-
for (let i = 0; i < parts.length; i++) {
|
|
3488
|
-
// Skip code blocks (odd indices from the split)
|
|
3489
|
-
if (i % 2 === 0) {
|
|
3490
|
-
// Convert double newlines to paragraph breaks
|
|
3491
|
-
parts[i] = parts[i].replace(/\n\n/g, '</p><p>');
|
|
3492
|
-
// Convert single newlines to line breaks
|
|
3493
|
-
parts[i] = parts[i].replace(/\n/g, '<br>');
|
|
3494
|
-
}
|
|
3495
|
-
}
|
|
3496
|
-
escaped = parts.join('');
|
|
3497
|
-
// Wrap in paragraph if we inserted paragraph breaks
|
|
3498
|
-
if (escaped.includes('</p><p>')) {
|
|
3499
|
-
escaped = '<p>' + escaped + '</p>';
|
|
3500
|
-
}
|
|
3501
|
-
return escaped;
|
|
3502
|
-
}
|
|
3503
6120
|
// --- Render ---
|
|
3504
6121
|
render() {
|
|
3505
6122
|
return b `
|
|
3506
6123
|
<button
|
|
3507
6124
|
class=${e({
|
|
3508
|
-
'
|
|
3509
|
-
'
|
|
6125
|
+
'toggle': true,
|
|
6126
|
+
'toggle--hidden': this.opened,
|
|
3510
6127
|
})}
|
|
3511
6128
|
@click=${this._handleToggle}
|
|
3512
6129
|
title="Open chat"
|
|
3513
6130
|
>
|
|
3514
|
-
<svg
|
|
6131
|
+
<svg
|
|
6132
|
+
viewBox="0 0 24 24"
|
|
6133
|
+
fill="none"
|
|
6134
|
+
stroke="currentColor"
|
|
6135
|
+
stroke-width="2"
|
|
6136
|
+
stroke-linecap="round"
|
|
6137
|
+
class="toggle-icon"
|
|
6138
|
+
>
|
|
3515
6139
|
<path d="M12 2C6.48 2 2 6.03 2 11c0 2.61 1.19 4.94 3.05 6.55L4 22l4.8-2.4C9.82 19.85 10.88 20 12 20c5.52 0 10-4.03 10-9S17.52 2 12 2z"/>
|
|
3516
6140
|
<path d="M8 11h.01M12 11h.01M16 11h.01" stroke-width="2.5"/>
|
|
3517
6141
|
</svg>
|
|
3518
6142
|
</button>
|
|
3519
6143
|
|
|
3520
6144
|
<div class=${e({
|
|
3521
|
-
'
|
|
3522
|
-
'
|
|
6145
|
+
'panel': true,
|
|
6146
|
+
'panel--opened': this.opened,
|
|
3523
6147
|
})}>
|
|
3524
|
-
<div
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
<div
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
6148
|
+
<div
|
|
6149
|
+
class="resize resize--n"
|
|
6150
|
+
data-dir="n"
|
|
6151
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6152
|
+
></div>
|
|
6153
|
+
<div
|
|
6154
|
+
class="resize resize--s"
|
|
6155
|
+
data-dir="s"
|
|
6156
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6157
|
+
></div>
|
|
6158
|
+
<div
|
|
6159
|
+
class="resize resize--w"
|
|
6160
|
+
data-dir="w"
|
|
6161
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6162
|
+
></div>
|
|
6163
|
+
<div
|
|
6164
|
+
class="resize resize--e"
|
|
6165
|
+
data-dir="e"
|
|
6166
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6167
|
+
></div>
|
|
6168
|
+
<div
|
|
6169
|
+
class="resize resize--nw"
|
|
6170
|
+
data-dir="nw"
|
|
6171
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6172
|
+
></div>
|
|
6173
|
+
<div
|
|
6174
|
+
class="resize resize--ne"
|
|
6175
|
+
data-dir="ne"
|
|
6176
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6177
|
+
></div>
|
|
6178
|
+
<div
|
|
6179
|
+
class="resize resize--sw"
|
|
6180
|
+
data-dir="sw"
|
|
6181
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6182
|
+
></div>
|
|
6183
|
+
<div
|
|
6184
|
+
class="resize resize--se"
|
|
6185
|
+
data-dir="se"
|
|
6186
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6187
|
+
></div>
|
|
6188
|
+
<div class="header" @mousedown=${this._handleHeaderMouseDown}>
|
|
6189
|
+
<div class="header-left">
|
|
6190
|
+
<div class="header-info">
|
|
6191
|
+
<span class="header-title">${this.title}</span>
|
|
3541
6192
|
${this.subtitle ? b `
|
|
3542
|
-
<span class="
|
|
6193
|
+
<span class="header-subtitle">${this.subtitle}</span>
|
|
3543
6194
|
` : A}
|
|
3544
6195
|
</div>
|
|
3545
6196
|
</div>
|
|
3546
|
-
<div class="
|
|
6197
|
+
<div class="header-actions">
|
|
3547
6198
|
${this.messages.length > 0 ? b `
|
|
3548
|
-
<button
|
|
3549
|
-
|
|
3550
|
-
|
|
6199
|
+
<button
|
|
6200
|
+
class="header-action"
|
|
6201
|
+
@click=${this._handleClear}
|
|
6202
|
+
title="Clear conversation"
|
|
6203
|
+
>
|
|
6204
|
+
<svg
|
|
6205
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6206
|
+
fill="none"
|
|
6207
|
+
viewBox="0 0 24 24"
|
|
6208
|
+
stroke-width="1.5"
|
|
6209
|
+
stroke="currentColor"
|
|
6210
|
+
class="header-action-icon"
|
|
6211
|
+
>
|
|
6212
|
+
<path
|
|
6213
|
+
stroke-linecap="round"
|
|
6214
|
+
stroke-linejoin="round"
|
|
6215
|
+
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
|
6216
|
+
/>
|
|
3551
6217
|
</svg>
|
|
3552
6218
|
</button>
|
|
3553
6219
|
` : A}
|
|
3554
|
-
<button
|
|
3555
|
-
|
|
3556
|
-
|
|
6220
|
+
<button
|
|
6221
|
+
class="header-action"
|
|
6222
|
+
@click=${this._handleToggle}
|
|
6223
|
+
title="Close"
|
|
6224
|
+
>
|
|
6225
|
+
<svg
|
|
6226
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6227
|
+
fill="none"
|
|
6228
|
+
viewBox="0 0 24 24"
|
|
6229
|
+
stroke-width="2"
|
|
6230
|
+
stroke="currentColor"
|
|
6231
|
+
class="header-action-icon"
|
|
6232
|
+
>
|
|
6233
|
+
<path
|
|
6234
|
+
stroke-linecap="round"
|
|
6235
|
+
stroke-linejoin="round"
|
|
6236
|
+
d="M6 18 18 6M6 6l12 12"
|
|
6237
|
+
/>
|
|
3557
6238
|
</svg>
|
|
3558
6239
|
</button>
|
|
3559
6240
|
</div>
|
|
3560
6241
|
</div>
|
|
3561
6242
|
|
|
3562
|
-
<div class="
|
|
6243
|
+
<div class="messages" @scroll=${this._handleMessagesScroll}>
|
|
3563
6244
|
${this.messages.length === 0 ? b `
|
|
3564
|
-
<div class="
|
|
3565
|
-
<
|
|
3566
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.087.16 2.185.283 3.293.369V21l4.076-4.076a1.526 1.526 0 0 1 1.037-.443 48.282 48.282 0 0 0 5.68-.494c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
|
3567
|
-
</svg>
|
|
3568
|
-
<span class="chatbot__empty-text">How can I help?</span>
|
|
6245
|
+
<div class="empty">
|
|
6246
|
+
<span class="empty-text">What can I help you with?</span>
|
|
3569
6247
|
</div>
|
|
3570
6248
|
` : A}
|
|
3571
6249
|
${this.messages.map((msg) => b `
|
|
3572
6250
|
<div class=${e({
|
|
3573
|
-
'
|
|
3574
|
-
'
|
|
3575
|
-
'
|
|
6251
|
+
'message': true,
|
|
6252
|
+
'message--user': msg.role === 'user',
|
|
6253
|
+
'message--assistant': msg.role === 'assistant',
|
|
3576
6254
|
})}>
|
|
3577
6255
|
${msg.reasoning ? b `
|
|
3578
|
-
<details class="
|
|
6256
|
+
<details class="reasoning">
|
|
3579
6257
|
<summary>Thinking</summary>
|
|
3580
|
-
<div class="
|
|
6258
|
+
<div class="reasoning-content">${msg.reasoning}</div>
|
|
3581
6259
|
</details>
|
|
3582
6260
|
` : A}
|
|
3583
|
-
|
|
3584
|
-
|
|
6261
|
+
${msg.content ? b `
|
|
6262
|
+
<div class="message-content">
|
|
6263
|
+
${msg.role === 'user'
|
|
3585
6264
|
? msg.content
|
|
3586
|
-
: o(
|
|
3587
|
-
|
|
6265
|
+
: o(marked.parse(msg.content, { breaks: true }))}
|
|
6266
|
+
</div>
|
|
6267
|
+
` : A}
|
|
6268
|
+
${msg.role === 'assistant' && this._isStreaming && msg === this.messages[this.messages.length - 1] ? b `
|
|
6269
|
+
<div class="typing">
|
|
6270
|
+
<span></span>
|
|
6271
|
+
<span></span>
|
|
6272
|
+
<span></span>
|
|
6273
|
+
</div>
|
|
6274
|
+
` : A}
|
|
3588
6275
|
</div>
|
|
3589
6276
|
`)}
|
|
3590
|
-
${this._statusText ? b `
|
|
3591
|
-
<div class="chatbot__message chatbot__message--assistant">
|
|
3592
|
-
<div class="chatbot__typing">
|
|
3593
|
-
<span></span>
|
|
3594
|
-
<span></span>
|
|
3595
|
-
<span></span>
|
|
3596
|
-
</div>
|
|
3597
|
-
</div>
|
|
3598
|
-
` : A}
|
|
3599
6277
|
</div>
|
|
3600
6278
|
|
|
3601
6279
|
${this._error ? b `
|
|
3602
|
-
<div class="
|
|
6280
|
+
<div class="error">
|
|
3603
6281
|
<span>${this._error}</span>
|
|
3604
|
-
<button class="
|
|
3605
|
-
<svg
|
|
3606
|
-
|
|
6282
|
+
<button class="error-dismiss" @click=${this._handleErrorDismiss}>
|
|
6283
|
+
<svg
|
|
6284
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6285
|
+
fill="none"
|
|
6286
|
+
viewBox="0 0 24 24"
|
|
6287
|
+
stroke-width="2"
|
|
6288
|
+
stroke="currentColor"
|
|
6289
|
+
class="error-dismiss-icon"
|
|
6290
|
+
>
|
|
6291
|
+
<path
|
|
6292
|
+
stroke-linecap="round"
|
|
6293
|
+
stroke-linejoin="round"
|
|
6294
|
+
d="M6 18 18 6M6 6l12 12"
|
|
6295
|
+
/>
|
|
3607
6296
|
</svg>
|
|
3608
6297
|
</button>
|
|
3609
6298
|
</div>
|
|
3610
6299
|
` : A}
|
|
3611
6300
|
|
|
3612
|
-
<div class="
|
|
3613
|
-
<div class="
|
|
3614
|
-
<button class="
|
|
6301
|
+
<div class="footer">
|
|
6302
|
+
<div class="input-wrapper">
|
|
6303
|
+
<button class="input-plus" title="Attach">+</button>
|
|
3615
6304
|
<textarea
|
|
3616
|
-
class="
|
|
6305
|
+
class="input"
|
|
3617
6306
|
.value=${this._inputValue}
|
|
3618
6307
|
placeholder=${this.placeholder}
|
|
3619
6308
|
rows="1"
|
|
@@ -3621,21 +6310,45 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3621
6310
|
@keydown=${this._handleKeyDown}
|
|
3622
6311
|
></textarea>
|
|
3623
6312
|
${this._isStreaming ? b `
|
|
3624
|
-
<button
|
|
3625
|
-
|
|
3626
|
-
|
|
6313
|
+
<button
|
|
6314
|
+
class="stop"
|
|
6315
|
+
@click=${this._handleStop}
|
|
6316
|
+
title="Stop generating"
|
|
6317
|
+
>
|
|
6318
|
+
<svg
|
|
6319
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6320
|
+
fill="currentColor"
|
|
6321
|
+
viewBox="0 0 24 24"
|
|
6322
|
+
class="stop-icon"
|
|
6323
|
+
>
|
|
6324
|
+
<rect
|
|
6325
|
+
x="6"
|
|
6326
|
+
y="6"
|
|
6327
|
+
width="12"
|
|
6328
|
+
height="12"
|
|
6329
|
+
rx="2"
|
|
6330
|
+
/>
|
|
3627
6331
|
</svg>
|
|
3628
6332
|
</button>
|
|
3629
6333
|
` : b `
|
|
3630
6334
|
<button
|
|
3631
6335
|
class=${e({
|
|
3632
|
-
'
|
|
3633
|
-
'
|
|
6336
|
+
'send': true,
|
|
6337
|
+
'send--disabled': !this._inputValue.trim(),
|
|
3634
6338
|
})}
|
|
3635
6339
|
@click=${this._handleSubmit}
|
|
3636
6340
|
title="Send message"
|
|
3637
6341
|
>
|
|
3638
|
-
<svg
|
|
6342
|
+
<svg
|
|
6343
|
+
width="16"
|
|
6344
|
+
height="16"
|
|
6345
|
+
viewBox="0 0 24 24"
|
|
6346
|
+
fill="none"
|
|
6347
|
+
stroke="currentColor"
|
|
6348
|
+
stroke-width="2.5"
|
|
6349
|
+
stroke-linecap="round"
|
|
6350
|
+
class="send-icon"
|
|
6351
|
+
>
|
|
3639
6352
|
<path d="M12 19V5M5 12l7-7 7 7"/>
|
|
3640
6353
|
</svg>
|
|
3641
6354
|
</button>
|
|
@@ -3666,7 +6379,6 @@ KRChatbot.styles = i$4 `
|
|
|
3666
6379
|
--kr-chatbot-text: #1a1a2e;
|
|
3667
6380
|
--kr-chatbot-text-secondary: #64668b;
|
|
3668
6381
|
--kr-chatbot-user-bg: #e9e9e980;
|
|
3669
|
-
--kr-chatbot-user-text: #1a1a2e;
|
|
3670
6382
|
--kr-chatbot-error-bg: #fef2f2;
|
|
3671
6383
|
--kr-chatbot-error-text: #dc2626;
|
|
3672
6384
|
--kr-chatbot-success: #00b894;
|
|
@@ -3683,7 +6395,7 @@ KRChatbot.styles = i$4 `
|
|
|
3683
6395
|
}
|
|
3684
6396
|
|
|
3685
6397
|
/* Toggle button */
|
|
3686
|
-
.
|
|
6398
|
+
.toggle {
|
|
3687
6399
|
width: var(--kr-chatbot-toggle-size);
|
|
3688
6400
|
height: var(--kr-chatbot-toggle-size);
|
|
3689
6401
|
border-radius: 18px;
|
|
@@ -3698,24 +6410,24 @@ KRChatbot.styles = i$4 `
|
|
|
3698
6410
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
3699
6411
|
}
|
|
3700
6412
|
|
|
3701
|
-
.
|
|
6413
|
+
.toggle:hover {
|
|
3702
6414
|
transform: scale(1.05);
|
|
3703
6415
|
box-shadow: 0 6px 32px rgba(22, 48, 82, 0.5);
|
|
3704
6416
|
}
|
|
3705
6417
|
|
|
3706
|
-
.
|
|
6418
|
+
.toggle--hidden {
|
|
3707
6419
|
transform: scale(0);
|
|
3708
6420
|
opacity: 0;
|
|
3709
6421
|
pointer-events: none;
|
|
3710
6422
|
}
|
|
3711
6423
|
|
|
3712
|
-
.
|
|
6424
|
+
.toggle-icon {
|
|
3713
6425
|
width: 26px;
|
|
3714
6426
|
height: 26px;
|
|
3715
6427
|
}
|
|
3716
6428
|
|
|
3717
6429
|
/* Panel */
|
|
3718
|
-
.
|
|
6430
|
+
.panel {
|
|
3719
6431
|
display: none;
|
|
3720
6432
|
flex-direction: column;
|
|
3721
6433
|
background: var(--kr-chatbot-bg);
|
|
@@ -3733,7 +6445,7 @@ KRChatbot.styles = i$4 `
|
|
|
3733
6445
|
transform-origin: bottom right;
|
|
3734
6446
|
}
|
|
3735
6447
|
|
|
3736
|
-
.
|
|
6448
|
+
.panel--opened {
|
|
3737
6449
|
display: flex;
|
|
3738
6450
|
}
|
|
3739
6451
|
|
|
@@ -3749,49 +6461,35 @@ KRChatbot.styles = i$4 `
|
|
|
3749
6461
|
}
|
|
3750
6462
|
|
|
3751
6463
|
/* Header */
|
|
3752
|
-
.
|
|
3753
|
-
padding:
|
|
3754
|
-
|
|
3755
|
-
|
|
6464
|
+
.header {
|
|
6465
|
+
padding: 0 16px 0 24px;
|
|
6466
|
+
height: 64px;
|
|
6467
|
+
background: #ffffff;
|
|
6468
|
+
color: #000000;
|
|
6469
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
|
3756
6470
|
display: flex;
|
|
3757
6471
|
align-items: center;
|
|
3758
6472
|
justify-content: space-between;
|
|
3759
6473
|
flex-shrink: 0;
|
|
3760
6474
|
}
|
|
3761
6475
|
|
|
3762
|
-
.
|
|
6476
|
+
.header-left {
|
|
3763
6477
|
display: flex;
|
|
3764
6478
|
align-items: center;
|
|
3765
6479
|
gap: 10px;
|
|
3766
6480
|
}
|
|
3767
6481
|
|
|
3768
|
-
|
|
3769
|
-
display: flex;
|
|
3770
|
-
flex-direction: column;
|
|
3771
|
-
gap: 2px;
|
|
3772
|
-
opacity: 0.35;
|
|
3773
|
-
}
|
|
3774
|
-
|
|
3775
|
-
.chatbot__header-drag-hint span {
|
|
3776
|
-
display: block;
|
|
3777
|
-
width: 14px;
|
|
3778
|
-
height: 2px;
|
|
3779
|
-
background: white;
|
|
3780
|
-
border-radius: 1px;
|
|
3781
|
-
}
|
|
3782
|
-
|
|
3783
|
-
.chatbot__header-info {
|
|
6482
|
+
.header-info {
|
|
3784
6483
|
display: flex;
|
|
3785
6484
|
flex-direction: column;
|
|
3786
6485
|
}
|
|
3787
6486
|
|
|
3788
|
-
.
|
|
3789
|
-
font-size:
|
|
6487
|
+
.header-title {
|
|
6488
|
+
font-size: 16px;
|
|
3790
6489
|
font-weight: 600;
|
|
3791
|
-
letter-spacing: -0.2px;
|
|
3792
6490
|
}
|
|
3793
6491
|
|
|
3794
|
-
.
|
|
6492
|
+
.header-subtitle {
|
|
3795
6493
|
color: rgba(255, 255, 255, 0.5);
|
|
3796
6494
|
font-size: 11px;
|
|
3797
6495
|
display: flex;
|
|
@@ -3799,7 +6497,7 @@ KRChatbot.styles = i$4 `
|
|
|
3799
6497
|
gap: 4px;
|
|
3800
6498
|
}
|
|
3801
6499
|
|
|
3802
|
-
.
|
|
6500
|
+
.header-subtitle::before {
|
|
3803
6501
|
content: '';
|
|
3804
6502
|
width: 5px;
|
|
3805
6503
|
height: 5px;
|
|
@@ -3807,18 +6505,18 @@ KRChatbot.styles = i$4 `
|
|
|
3807
6505
|
border-radius: 50%;
|
|
3808
6506
|
}
|
|
3809
6507
|
|
|
3810
|
-
.
|
|
6508
|
+
.header-actions {
|
|
3811
6509
|
display: flex;
|
|
3812
6510
|
align-items: center;
|
|
3813
6511
|
gap: 4px;
|
|
3814
6512
|
}
|
|
3815
6513
|
|
|
3816
|
-
.
|
|
3817
|
-
width:
|
|
3818
|
-
height:
|
|
6514
|
+
.header-action {
|
|
6515
|
+
width: 32px;
|
|
6516
|
+
height: 32px;
|
|
3819
6517
|
background: transparent;
|
|
3820
6518
|
border: none;
|
|
3821
|
-
color:
|
|
6519
|
+
color: rgb(0 0 0 / 70%);
|
|
3822
6520
|
border-radius: 8px;
|
|
3823
6521
|
cursor: pointer;
|
|
3824
6522
|
display: flex;
|
|
@@ -3827,18 +6525,18 @@ KRChatbot.styles = i$4 `
|
|
|
3827
6525
|
transition: all 0.15s;
|
|
3828
6526
|
}
|
|
3829
6527
|
|
|
3830
|
-
.
|
|
3831
|
-
background: rgba(
|
|
3832
|
-
color:
|
|
6528
|
+
.header-action:hover {
|
|
6529
|
+
background: rgba(0, 0, 0, 0.05);
|
|
6530
|
+
color: #000000;
|
|
3833
6531
|
}
|
|
3834
6532
|
|
|
3835
|
-
.
|
|
3836
|
-
width:
|
|
3837
|
-
height:
|
|
6533
|
+
.header-action-icon {
|
|
6534
|
+
width: 20px;
|
|
6535
|
+
height: 20px;
|
|
3838
6536
|
}
|
|
3839
6537
|
|
|
3840
6538
|
/* Messages */
|
|
3841
|
-
.
|
|
6539
|
+
.messages {
|
|
3842
6540
|
flex: 1;
|
|
3843
6541
|
overflow-y: auto;
|
|
3844
6542
|
padding: 32px;
|
|
@@ -3849,20 +6547,20 @@ KRChatbot.styles = i$4 `
|
|
|
3849
6547
|
background: white;
|
|
3850
6548
|
}
|
|
3851
6549
|
|
|
3852
|
-
.
|
|
6550
|
+
.messages::-webkit-scrollbar {
|
|
3853
6551
|
width: 4px;
|
|
3854
6552
|
}
|
|
3855
6553
|
|
|
3856
|
-
.
|
|
6554
|
+
.messages::-webkit-scrollbar-track {
|
|
3857
6555
|
background: transparent;
|
|
3858
6556
|
}
|
|
3859
6557
|
|
|
3860
|
-
.
|
|
6558
|
+
.messages::-webkit-scrollbar-thumb {
|
|
3861
6559
|
background: rgba(0, 0, 0, 0.08);
|
|
3862
6560
|
border-radius: 2px;
|
|
3863
6561
|
}
|
|
3864
6562
|
|
|
3865
|
-
.
|
|
6563
|
+
.empty {
|
|
3866
6564
|
flex: 1;
|
|
3867
6565
|
display: flex;
|
|
3868
6566
|
flex-direction: column;
|
|
@@ -3872,17 +6570,12 @@ KRChatbot.styles = i$4 `
|
|
|
3872
6570
|
gap: 8px;
|
|
3873
6571
|
}
|
|
3874
6572
|
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
opacity: 0.4;
|
|
3879
|
-
}
|
|
3880
|
-
|
|
3881
|
-
.chatbot__empty-text {
|
|
3882
|
-
font-size: 13px;
|
|
6573
|
+
.empty-text {
|
|
6574
|
+
font-size: 14px;
|
|
6575
|
+
color: rgb(0 0 0 / 80%);
|
|
3883
6576
|
}
|
|
3884
6577
|
|
|
3885
|
-
.
|
|
6578
|
+
.message {
|
|
3886
6579
|
display: flex;
|
|
3887
6580
|
flex-direction: column;
|
|
3888
6581
|
max-width: 100%;
|
|
@@ -3900,40 +6593,41 @@ KRChatbot.styles = i$4 `
|
|
|
3900
6593
|
}
|
|
3901
6594
|
}
|
|
3902
6595
|
|
|
3903
|
-
.
|
|
6596
|
+
.message--user {
|
|
3904
6597
|
align-self: flex-end;
|
|
3905
6598
|
align-items: flex-end;
|
|
3906
6599
|
max-width: 85%;
|
|
3907
6600
|
}
|
|
3908
6601
|
|
|
3909
|
-
.
|
|
6602
|
+
.message--assistant {
|
|
3910
6603
|
align-self: flex-start;
|
|
6604
|
+
gap: 24px;
|
|
3911
6605
|
}
|
|
3912
6606
|
|
|
3913
|
-
.
|
|
6607
|
+
.message-content {
|
|
3914
6608
|
line-height: 1.7;
|
|
3915
6609
|
word-wrap: break-word;
|
|
3916
6610
|
overflow-wrap: break-word;
|
|
3917
6611
|
}
|
|
3918
6612
|
|
|
3919
|
-
.
|
|
6613
|
+
.message--user .message-content {
|
|
3920
6614
|
display: inline-block;
|
|
3921
6615
|
background: var(--kr-chatbot-user-bg);
|
|
3922
|
-
color:
|
|
6616
|
+
color: #000000;
|
|
3923
6617
|
padding: 10px 16px;
|
|
3924
6618
|
border-radius: 20px;
|
|
3925
6619
|
border-bottom-right-radius: 6px;
|
|
3926
6620
|
font-size: 14px;
|
|
3927
6621
|
}
|
|
3928
6622
|
|
|
3929
|
-
.
|
|
6623
|
+
.message--assistant .message-content {
|
|
3930
6624
|
background: transparent;
|
|
3931
|
-
color:
|
|
6625
|
+
color: #000000;
|
|
3932
6626
|
padding: 0;
|
|
3933
6627
|
font-size: 14px;
|
|
3934
6628
|
}
|
|
3935
6629
|
|
|
3936
|
-
.
|
|
6630
|
+
.message--assistant .message-content pre {
|
|
3937
6631
|
background: #1e1e1e;
|
|
3938
6632
|
color: #d4d4d4;
|
|
3939
6633
|
padding: 12px;
|
|
@@ -3944,67 +6638,57 @@ KRChatbot.styles = i$4 `
|
|
|
3944
6638
|
line-height: 1.4;
|
|
3945
6639
|
}
|
|
3946
6640
|
|
|
3947
|
-
.
|
|
6641
|
+
.message--assistant .message-content code {
|
|
3948
6642
|
font-family: 'SF Mono', 'Fira Code', Monaco, monospace;
|
|
3949
6643
|
font-size: 13px;
|
|
3950
6644
|
}
|
|
3951
6645
|
|
|
3952
|
-
.
|
|
6646
|
+
.message--assistant .message-content :not(pre) > code {
|
|
3953
6647
|
background: rgba(0, 0, 0, 0.06);
|
|
3954
6648
|
padding: 2px 5px;
|
|
3955
6649
|
border-radius: 3px;
|
|
3956
6650
|
}
|
|
3957
6651
|
|
|
3958
|
-
.
|
|
6652
|
+
.message--assistant .message-content strong {
|
|
3959
6653
|
font-weight: 600;
|
|
3960
6654
|
}
|
|
3961
6655
|
|
|
3962
|
-
.
|
|
6656
|
+
.message--assistant .message-content p {
|
|
3963
6657
|
margin: 0 0 8px 0;
|
|
3964
6658
|
}
|
|
3965
6659
|
|
|
3966
|
-
.
|
|
6660
|
+
.message--assistant .message-content p:last-child {
|
|
3967
6661
|
margin-bottom: 0;
|
|
3968
6662
|
}
|
|
3969
6663
|
|
|
3970
6664
|
/* Reasoning */
|
|
3971
|
-
.
|
|
3972
|
-
margin-bottom: 8px;
|
|
6665
|
+
.reasoning {
|
|
3973
6666
|
border-radius: 6px;
|
|
3974
|
-
background:
|
|
6667
|
+
background: rgb(244 244 244 / 80%);
|
|
3975
6668
|
font-size: 12px;
|
|
3976
6669
|
}
|
|
3977
6670
|
|
|
3978
|
-
.
|
|
6671
|
+
.reasoning summary {
|
|
3979
6672
|
cursor: pointer;
|
|
3980
|
-
padding: 6px 10px;
|
|
3981
|
-
color:
|
|
3982
|
-
font-style: italic;
|
|
6673
|
+
padding: 6px 10px 6px 10px;
|
|
6674
|
+
color: black;
|
|
3983
6675
|
user-select: none;
|
|
3984
6676
|
}
|
|
3985
6677
|
|
|
3986
|
-
.
|
|
6678
|
+
.reasoning-content {
|
|
3987
6679
|
padding: 6px 10px 10px;
|
|
3988
|
-
color:
|
|
3989
|
-
line-height: 1.5;
|
|
6680
|
+
color: black;
|
|
3990
6681
|
white-space: pre-wrap;
|
|
3991
6682
|
word-wrap: break-word;
|
|
3992
6683
|
}
|
|
3993
6684
|
|
|
3994
|
-
|
|
3995
|
-
.chatbot__status {
|
|
3996
|
-
font-size: 13px;
|
|
3997
|
-
color: var(--kr-chatbot-text-secondary);
|
|
3998
|
-
font-style: italic;
|
|
3999
|
-
}
|
|
4000
|
-
|
|
4001
|
-
.chatbot__typing {
|
|
6685
|
+
.typing {
|
|
4002
6686
|
display: flex;
|
|
4003
6687
|
gap: 4px;
|
|
4004
6688
|
padding: 4px 0;
|
|
4005
6689
|
}
|
|
4006
6690
|
|
|
4007
|
-
.
|
|
6691
|
+
.typing span {
|
|
4008
6692
|
width: 6px;
|
|
4009
6693
|
height: 6px;
|
|
4010
6694
|
background: var(--kr-chatbot-text-secondary);
|
|
@@ -4013,11 +6697,11 @@ KRChatbot.styles = i$4 `
|
|
|
4013
6697
|
opacity: 0.4;
|
|
4014
6698
|
}
|
|
4015
6699
|
|
|
4016
|
-
.
|
|
6700
|
+
.typing span:nth-child(2) {
|
|
4017
6701
|
animation-delay: 0.2s;
|
|
4018
6702
|
}
|
|
4019
6703
|
|
|
4020
|
-
.
|
|
6704
|
+
.typing span:nth-child(3) {
|
|
4021
6705
|
animation-delay: 0.4s;
|
|
4022
6706
|
}
|
|
4023
6707
|
|
|
@@ -4033,7 +6717,7 @@ KRChatbot.styles = i$4 `
|
|
|
4033
6717
|
}
|
|
4034
6718
|
|
|
4035
6719
|
/* Error */
|
|
4036
|
-
.
|
|
6720
|
+
.error {
|
|
4037
6721
|
padding: 8px 16px;
|
|
4038
6722
|
background: var(--kr-chatbot-error-bg);
|
|
4039
6723
|
color: var(--kr-chatbot-error-text);
|
|
@@ -4045,7 +6729,7 @@ KRChatbot.styles = i$4 `
|
|
|
4045
6729
|
flex-shrink: 0;
|
|
4046
6730
|
}
|
|
4047
6731
|
|
|
4048
|
-
.
|
|
6732
|
+
.error-dismiss {
|
|
4049
6733
|
background: none;
|
|
4050
6734
|
border: none;
|
|
4051
6735
|
color: var(--kr-chatbot-error-text);
|
|
@@ -4056,19 +6740,19 @@ KRChatbot.styles = i$4 `
|
|
|
4056
6740
|
flex-shrink: 0;
|
|
4057
6741
|
}
|
|
4058
6742
|
|
|
4059
|
-
.
|
|
6743
|
+
.error-dismiss-icon {
|
|
4060
6744
|
width: 14px;
|
|
4061
6745
|
height: 14px;
|
|
4062
6746
|
}
|
|
4063
6747
|
|
|
4064
6748
|
/* Footer / Input */
|
|
4065
|
-
.
|
|
4066
|
-
padding:
|
|
6749
|
+
.footer {
|
|
6750
|
+
padding: 16px 16px 16px;
|
|
4067
6751
|
flex-shrink: 0;
|
|
4068
6752
|
background: white;
|
|
4069
6753
|
}
|
|
4070
6754
|
|
|
4071
|
-
.
|
|
6755
|
+
.input-wrapper {
|
|
4072
6756
|
display: flex;
|
|
4073
6757
|
align-items: center;
|
|
4074
6758
|
gap: 4px;
|
|
@@ -4079,12 +6763,12 @@ KRChatbot.styles = i$4 `
|
|
|
4079
6763
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
4080
6764
|
}
|
|
4081
6765
|
|
|
4082
|
-
.
|
|
6766
|
+
.input-wrapper:focus-within {
|
|
4083
6767
|
border-color: #b0b0b0;
|
|
4084
6768
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04);
|
|
4085
6769
|
}
|
|
4086
6770
|
|
|
4087
|
-
.
|
|
6771
|
+
.input-plus {
|
|
4088
6772
|
width: 34px;
|
|
4089
6773
|
height: 34px;
|
|
4090
6774
|
border: none;
|
|
@@ -4101,11 +6785,11 @@ KRChatbot.styles = i$4 `
|
|
|
4101
6785
|
transition: background 0.15s;
|
|
4102
6786
|
}
|
|
4103
6787
|
|
|
4104
|
-
.
|
|
6788
|
+
.input-plus:hover {
|
|
4105
6789
|
background: #f8f9fc;
|
|
4106
6790
|
}
|
|
4107
6791
|
|
|
4108
|
-
.
|
|
6792
|
+
.input {
|
|
4109
6793
|
flex: 1;
|
|
4110
6794
|
border: none;
|
|
4111
6795
|
outline: none;
|
|
@@ -4117,14 +6801,14 @@ KRChatbot.styles = i$4 `
|
|
|
4117
6801
|
min-height: 26px;
|
|
4118
6802
|
max-height: 120px;
|
|
4119
6803
|
background: transparent;
|
|
4120
|
-
color:
|
|
6804
|
+
color: black;
|
|
4121
6805
|
}
|
|
4122
6806
|
|
|
4123
|
-
.
|
|
6807
|
+
.input::placeholder {
|
|
4124
6808
|
color: #b0b0b0;
|
|
4125
6809
|
}
|
|
4126
6810
|
|
|
4127
|
-
.
|
|
6811
|
+
.send {
|
|
4128
6812
|
width: 34px;
|
|
4129
6813
|
height: 34px;
|
|
4130
6814
|
border-radius: 50%;
|
|
@@ -4139,25 +6823,25 @@ KRChatbot.styles = i$4 `
|
|
|
4139
6823
|
transition: all 0.15s;
|
|
4140
6824
|
}
|
|
4141
6825
|
|
|
4142
|
-
.
|
|
6826
|
+
.send:hover {
|
|
4143
6827
|
background: var(--kr-chatbot-primary-hover);
|
|
4144
6828
|
}
|
|
4145
6829
|
|
|
4146
|
-
.
|
|
6830
|
+
.send--disabled {
|
|
4147
6831
|
opacity: 0.4;
|
|
4148
6832
|
cursor: default;
|
|
4149
6833
|
}
|
|
4150
6834
|
|
|
4151
|
-
.
|
|
6835
|
+
.send--disabled:hover {
|
|
4152
6836
|
background: var(--kr-chatbot-primary);
|
|
4153
6837
|
}
|
|
4154
6838
|
|
|
4155
|
-
.
|
|
6839
|
+
.send-icon {
|
|
4156
6840
|
width: 16px;
|
|
4157
6841
|
height: 16px;
|
|
4158
6842
|
}
|
|
4159
6843
|
|
|
4160
|
-
.
|
|
6844
|
+
.stop {
|
|
4161
6845
|
width: 34px;
|
|
4162
6846
|
height: 34px;
|
|
4163
6847
|
border-radius: 50%;
|
|
@@ -4172,62 +6856,51 @@ KRChatbot.styles = i$4 `
|
|
|
4172
6856
|
transition: all 0.15s;
|
|
4173
6857
|
}
|
|
4174
6858
|
|
|
4175
|
-
.
|
|
6859
|
+
.stop:hover {
|
|
4176
6860
|
background: #b91c1c;
|
|
4177
6861
|
}
|
|
4178
6862
|
|
|
4179
|
-
.
|
|
6863
|
+
.stop-icon {
|
|
4180
6864
|
width: 14px;
|
|
4181
6865
|
height: 14px;
|
|
4182
6866
|
}
|
|
4183
6867
|
|
|
4184
6868
|
/* Header drag cursor */
|
|
4185
|
-
.
|
|
6869
|
+
.header {
|
|
4186
6870
|
cursor: grab;
|
|
4187
6871
|
user-select: none;
|
|
4188
6872
|
}
|
|
4189
6873
|
|
|
4190
|
-
.
|
|
6874
|
+
.header:active {
|
|
4191
6875
|
cursor: grabbing;
|
|
4192
6876
|
}
|
|
4193
6877
|
|
|
4194
6878
|
/* Drag / Resize states */
|
|
4195
|
-
.
|
|
4196
|
-
.
|
|
6879
|
+
.panel--dragging,
|
|
6880
|
+
.panel--resizing {
|
|
4197
6881
|
transition: none;
|
|
4198
6882
|
user-select: none;
|
|
4199
6883
|
}
|
|
4200
6884
|
|
|
4201
|
-
.
|
|
6885
|
+
.panel--dragging {
|
|
4202
6886
|
box-shadow: 0 32px 96px rgba(0, 0, 0, 0.18), 0 12px 40px rgba(0, 0, 0, 0.1);
|
|
4203
6887
|
}
|
|
4204
6888
|
|
|
4205
6889
|
/* Resize handles */
|
|
4206
|
-
.
|
|
6890
|
+
.resize {
|
|
4207
6891
|
position: absolute;
|
|
4208
6892
|
z-index: 10;
|
|
4209
6893
|
}
|
|
4210
6894
|
|
|
4211
|
-
.
|
|
4212
|
-
.
|
|
4213
|
-
.
|
|
4214
|
-
.
|
|
4215
|
-
.
|
|
4216
|
-
.
|
|
4217
|
-
.
|
|
4218
|
-
.
|
|
6895
|
+
.resize--n { top: -4px; left: 12px; right: 12px; height: 8px; cursor: n-resize; }
|
|
6896
|
+
.resize--s { bottom: -4px; left: 12px; right: 12px; height: 8px; cursor: s-resize; }
|
|
6897
|
+
.resize--w { left: -4px; top: 12px; bottom: 12px; width: 8px; cursor: w-resize; }
|
|
6898
|
+
.resize--e { right: -4px; top: 12px; bottom: 12px; width: 8px; cursor: e-resize; }
|
|
6899
|
+
.resize--nw { top: -4px; left: -4px; width: 16px; height: 16px; cursor: nw-resize; }
|
|
6900
|
+
.resize--ne { top: -4px; right: -4px; width: 16px; height: 16px; cursor: ne-resize; }
|
|
6901
|
+
.resize--sw { bottom: -4px; left: -4px; width: 16px; height: 16px; cursor: sw-resize; }
|
|
6902
|
+
.resize--se { bottom: -4px; right: -4px; width: 16px; height: 16px; cursor: se-resize; }
|
|
4219
6903
|
|
|
4220
|
-
.chatbot__resize--se::after {
|
|
4221
|
-
content: '';
|
|
4222
|
-
position: absolute;
|
|
4223
|
-
bottom: 7px;
|
|
4224
|
-
right: 7px;
|
|
4225
|
-
width: 10px;
|
|
4226
|
-
height: 10px;
|
|
4227
|
-
border-right: 2px solid rgba(0, 0, 0, 0.12);
|
|
4228
|
-
border-bottom: 2px solid rgba(0, 0, 0, 0.12);
|
|
4229
|
-
border-radius: 0 0 3px 0;
|
|
4230
|
-
}
|
|
4231
6904
|
`;
|
|
4232
6905
|
__decorate([
|
|
4233
6906
|
n({ attribute: false })
|
|
@@ -4235,6 +6908,9 @@ __decorate([
|
|
|
4235
6908
|
__decorate([
|
|
4236
6909
|
n({ attribute: false })
|
|
4237
6910
|
], KRChatbot.prototype, "clear", void 0);
|
|
6911
|
+
__decorate([
|
|
6912
|
+
n({ attribute: false })
|
|
6913
|
+
], KRChatbot.prototype, "load", void 0);
|
|
4238
6914
|
__decorate([
|
|
4239
6915
|
n({ attribute: false })
|
|
4240
6916
|
], KRChatbot.prototype, "messages", void 0);
|
|
@@ -4248,7 +6924,10 @@ __decorate([
|
|
|
4248
6924
|
n({ type: String })
|
|
4249
6925
|
], KRChatbot.prototype, "placeholder", void 0);
|
|
4250
6926
|
__decorate([
|
|
4251
|
-
n({
|
|
6927
|
+
n({
|
|
6928
|
+
type: Boolean,
|
|
6929
|
+
reflect: true
|
|
6930
|
+
})
|
|
4252
6931
|
], KRChatbot.prototype, "opened", void 0);
|
|
4253
6932
|
__decorate([
|
|
4254
6933
|
r()
|
|
@@ -4263,13 +6942,13 @@ __decorate([
|
|
|
4263
6942
|
r()
|
|
4264
6943
|
], KRChatbot.prototype, "_error", void 0);
|
|
4265
6944
|
__decorate([
|
|
4266
|
-
e$3('.
|
|
6945
|
+
e$3('.panel')
|
|
4267
6946
|
], KRChatbot.prototype, "_panelEl", void 0);
|
|
4268
6947
|
__decorate([
|
|
4269
|
-
e$3('.
|
|
6948
|
+
e$3('.messages')
|
|
4270
6949
|
], KRChatbot.prototype, "_messagesEl", void 0);
|
|
4271
6950
|
__decorate([
|
|
4272
|
-
e$3('.
|
|
6951
|
+
e$3('.input')
|
|
4273
6952
|
], KRChatbot.prototype, "_inputEl", void 0);
|
|
4274
6953
|
KRChatbot = __decorate([
|
|
4275
6954
|
t$1('kr-chatbot')
|