@kodaris/krubble-app-components 1.0.66 → 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 +3208 -513
- 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 +3206 -511
- 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 +18 -12
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +208 -88
- 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
|
@@ -342,6 +342,7 @@ var __decorate$5 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
342
342
|
* @property {KRNavItem[]} nav - Navigation items as JSON array
|
|
343
343
|
* @property {KRUser} user - User profile data
|
|
344
344
|
* @property {boolean} navEnabled - Whether to show the nav drawer (menu toggle remains visible when false)
|
|
345
|
+
* @property {'employee'|'customer'} user-type - User type. Customers skip all `/api/system` calls since that endpoint is employee-only. Defaults to 'employee'.
|
|
345
346
|
*
|
|
346
347
|
*
|
|
347
348
|
* TODO
|
|
@@ -355,18 +356,6 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
355
356
|
* Default icon for nav items without an icon (shown at top level)
|
|
356
357
|
*/
|
|
357
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>';
|
|
358
|
-
this.navItemsExpanded = new Set();
|
|
359
|
-
this.navQuery = '';
|
|
360
|
-
this.activeNavItemId = null;
|
|
361
|
-
this.isNavScrolled = false;
|
|
362
|
-
this.isNavOpened = localStorage.getItem('kr-scaffold-nav-opened') !== 'false';
|
|
363
|
-
this.isEditing = false;
|
|
364
|
-
this.isUserMenuOpen = false;
|
|
365
|
-
this.pref = { nav: {} };
|
|
366
|
-
this.draggedNavItemId = null;
|
|
367
|
-
this.navItemDropTargetId = null;
|
|
368
|
-
this.navItemDropPosition = 'above';
|
|
369
|
-
this.pendingRequests = 0;
|
|
370
359
|
this.originalFetch = null;
|
|
371
360
|
this.originalXhrOpen = null;
|
|
372
361
|
this.navItemDragPreview = null;
|
|
@@ -394,18 +383,38 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
394
383
|
* Menu toggle button remains visible and emits menu-click events.
|
|
395
384
|
*/
|
|
396
385
|
this.navEnabled = true;
|
|
386
|
+
/**
|
|
387
|
+
* User type. Set to 'customer' to skip all /api/system calls — customers don't have access to that endpoint.
|
|
388
|
+
*/
|
|
389
|
+
this.userType = 'employee';
|
|
397
390
|
/**
|
|
398
391
|
* Breadcrumbs to display in the subbar
|
|
399
392
|
*/
|
|
400
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;
|
|
401
406
|
this.boundHandleMouseMove = this.handleMouseMove.bind(this);
|
|
402
407
|
this.boundHandleMouseUp = this.handleMouseUp.bind(this);
|
|
403
408
|
}
|
|
404
409
|
connectedCallback() {
|
|
405
410
|
super.connectedCallback();
|
|
406
|
-
this.loadPref();
|
|
407
411
|
this.installFetchInterceptor();
|
|
408
412
|
}
|
|
413
|
+
// Attributes are not reflected into properties until after the first update,
|
|
414
|
+
// so loadPref() must run here (not connectedCallback) for user-type to be set.
|
|
415
|
+
firstUpdated() {
|
|
416
|
+
this.loadPref();
|
|
417
|
+
}
|
|
409
418
|
updated(changedProperties) {
|
|
410
419
|
super.updated(changedProperties);
|
|
411
420
|
if (changedProperties.has('nav') && this.nav.length > 0) {
|
|
@@ -427,8 +436,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
427
436
|
* Updates `pendingRequests` state when requests start/complete.
|
|
428
437
|
*/
|
|
429
438
|
installFetchInterceptor() {
|
|
430
|
-
if (this.originalFetch)
|
|
439
|
+
if (this.originalFetch) {
|
|
431
440
|
return;
|
|
441
|
+
}
|
|
432
442
|
const scaffold = this;
|
|
433
443
|
// Intercept fetch
|
|
434
444
|
this.originalFetch = window.fetch.bind(window);
|
|
@@ -479,17 +489,23 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
479
489
|
* - resolveUrl(item) = "/operations/settings" (used for href and URL comparison)
|
|
480
490
|
*/
|
|
481
491
|
resolveUrl(item) {
|
|
482
|
-
if (!item.url)
|
|
492
|
+
if (!item.url) {
|
|
483
493
|
return '#';
|
|
494
|
+
}
|
|
484
495
|
// External URLs - return as-is
|
|
485
496
|
if (item.external) {
|
|
486
497
|
return item.url;
|
|
487
498
|
}
|
|
488
499
|
// Remove leading slash from url if present, then combine with base
|
|
489
|
-
|
|
500
|
+
let path = item.url;
|
|
501
|
+
if (item.url.startsWith('/')) {
|
|
502
|
+
path = item.url.slice(1);
|
|
503
|
+
}
|
|
490
504
|
const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
|
|
491
|
-
|
|
492
|
-
|
|
505
|
+
if (baseHref.endsWith('/')) {
|
|
506
|
+
return baseHref + path;
|
|
507
|
+
}
|
|
508
|
+
return baseHref + '/' + path;
|
|
493
509
|
}
|
|
494
510
|
// =========================================================================
|
|
495
511
|
// Navigation Data
|
|
@@ -518,11 +534,15 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
518
534
|
if (item.type === 'group' && item.children) {
|
|
519
535
|
item.children.forEach((child, childIndex) => {
|
|
520
536
|
const childOverride = this.pref.nav[child.id];
|
|
537
|
+
let parentId = item.id;
|
|
538
|
+
if (childOverride?.parentId !== undefined) {
|
|
539
|
+
parentId = childOverride.parentId;
|
|
540
|
+
}
|
|
521
541
|
result.push({
|
|
522
542
|
...child,
|
|
523
543
|
...childOverride,
|
|
524
544
|
order: childOverride?.order ?? child.order ?? childIndex,
|
|
525
|
-
parentId
|
|
545
|
+
parentId,
|
|
526
546
|
});
|
|
527
547
|
});
|
|
528
548
|
}
|
|
@@ -665,14 +685,18 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
665
685
|
toggleNavItem(itemId) {
|
|
666
686
|
const navItem = this.shadowRoot?.querySelector(`.nav-item[data-id="${itemId}"]`);
|
|
667
687
|
const groupEl = navItem?.nextElementSibling;
|
|
668
|
-
if (!groupEl)
|
|
688
|
+
if (!groupEl) {
|
|
669
689
|
return;
|
|
690
|
+
}
|
|
670
691
|
if (this.navItemsExpanded.has(itemId)) {
|
|
671
692
|
this.navItemsExpanded.delete(itemId);
|
|
672
693
|
groupEl.animate([
|
|
673
694
|
{ height: `${groupEl.scrollHeight}px` },
|
|
674
695
|
{ height: '0px' }
|
|
675
|
-
], {
|
|
696
|
+
], {
|
|
697
|
+
duration: 300,
|
|
698
|
+
easing: 'ease-in-out'
|
|
699
|
+
}).onfinish = () => {
|
|
676
700
|
groupEl.classList.remove('nav-group--expanded');
|
|
677
701
|
};
|
|
678
702
|
}
|
|
@@ -682,7 +706,10 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
682
706
|
groupEl.animate([
|
|
683
707
|
{ height: '0px' },
|
|
684
708
|
{ height: `${groupEl.scrollHeight}px` }
|
|
685
|
-
], {
|
|
709
|
+
], {
|
|
710
|
+
duration: 300,
|
|
711
|
+
easing: 'ease-in-out'
|
|
712
|
+
});
|
|
686
713
|
}
|
|
687
714
|
this.requestUpdate();
|
|
688
715
|
}
|
|
@@ -777,12 +804,18 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
777
804
|
this.pref.nav = {};
|
|
778
805
|
}
|
|
779
806
|
savePref() {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
807
|
+
if (this.userType === 'customer') {
|
|
808
|
+
return;
|
|
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
|
+
}
|
|
783
816
|
KRHttp.fetch({
|
|
784
817
|
url,
|
|
785
|
-
method
|
|
818
|
+
method,
|
|
786
819
|
body: JSON.stringify({ nav: this.pref.nav }),
|
|
787
820
|
})
|
|
788
821
|
.then((response) => response.json())
|
|
@@ -795,6 +828,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
795
828
|
});
|
|
796
829
|
}
|
|
797
830
|
loadPref() {
|
|
831
|
+
if (this.userType === 'customer') {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
798
834
|
KRHttp.fetch({
|
|
799
835
|
url: '/api/system/preference/json/scaffold?global=true',
|
|
800
836
|
method: 'GET',
|
|
@@ -811,21 +847,36 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
811
847
|
});
|
|
812
848
|
}
|
|
813
849
|
handleNavItemContextMenu(e, item) {
|
|
814
|
-
if (!this.isEditing)
|
|
850
|
+
if (!this.isEditing) {
|
|
815
851
|
return;
|
|
852
|
+
}
|
|
816
853
|
e.preventDefault();
|
|
817
854
|
KRContextMenu.open({
|
|
818
855
|
x: e.clientX,
|
|
819
856
|
y: e.clientY,
|
|
820
857
|
items: [
|
|
821
|
-
{
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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
|
+
},
|
|
825
875
|
],
|
|
826
876
|
}).then((result) => {
|
|
827
|
-
if (!result)
|
|
877
|
+
if (!result) {
|
|
828
878
|
return;
|
|
879
|
+
}
|
|
829
880
|
switch (result.id) {
|
|
830
881
|
case 'edit':
|
|
831
882
|
this.openNavItemEdit(item);
|
|
@@ -851,8 +902,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
851
902
|
openNavItemEdit(item) {
|
|
852
903
|
KRDialog.open(KRNavItemEdit, { data: item }).afterClosed().then((res) => {
|
|
853
904
|
const result = res;
|
|
854
|
-
if (!result)
|
|
905
|
+
if (!result) {
|
|
855
906
|
return;
|
|
907
|
+
}
|
|
856
908
|
if (!this.pref.nav[item.id]) {
|
|
857
909
|
this.pref.nav[item.id] = {};
|
|
858
910
|
}
|
|
@@ -879,7 +931,13 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
879
931
|
.filter(i => i.parentId === targetItem.parentId)
|
|
880
932
|
.sort((a, b) => a.order - b.order);
|
|
881
933
|
const targetIndex = siblings.findIndex(i => i.id === targetItem.id);
|
|
882
|
-
|
|
934
|
+
let newOrder;
|
|
935
|
+
if (position === 'above') {
|
|
936
|
+
newOrder = targetIndex;
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
newOrder = targetIndex + 1;
|
|
940
|
+
}
|
|
883
941
|
// Shift existing items to make room for the new item
|
|
884
942
|
siblings.forEach((sibling, index) => {
|
|
885
943
|
if (index >= newOrder) {
|
|
@@ -916,8 +974,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
916
974
|
* @param item - The nav item being pressed
|
|
917
975
|
*/
|
|
918
976
|
handleNavItemMouseDown(e, item) {
|
|
919
|
-
if (!this.isEditing)
|
|
977
|
+
if (!this.isEditing) {
|
|
920
978
|
return;
|
|
979
|
+
}
|
|
921
980
|
e.preventDefault();
|
|
922
981
|
this.draggedNavItemId = item.id;
|
|
923
982
|
this.navItemDragStartY = e.clientY;
|
|
@@ -935,8 +994,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
935
994
|
* @param e - The mouse event
|
|
936
995
|
*/
|
|
937
996
|
handleMouseMove(e) {
|
|
938
|
-
if (!this.draggedNavItemId)
|
|
997
|
+
if (!this.draggedNavItemId) {
|
|
939
998
|
return;
|
|
999
|
+
}
|
|
940
1000
|
// Start dragging after moving a few pixels (to distinguish from clicks)
|
|
941
1001
|
if (!this.isNavItemDragging && Math.abs(e.clientY - this.navItemDragStartY) > 5) {
|
|
942
1002
|
this.isNavItemDragging = true;
|
|
@@ -952,8 +1012,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
952
1012
|
this.shadowRoot?.appendChild(this.navItemDragPreview);
|
|
953
1013
|
}
|
|
954
1014
|
}
|
|
955
|
-
if (!this.isNavItemDragging)
|
|
1015
|
+
if (!this.isNavItemDragging) {
|
|
956
1016
|
return;
|
|
1017
|
+
}
|
|
957
1018
|
// Update preview position
|
|
958
1019
|
if (this.navItemDragPreview) {
|
|
959
1020
|
this.navItemDragPreview.style.left = `${e.clientX + 10}px`;
|
|
@@ -1004,14 +1065,16 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1004
1065
|
updateNavItemDropTarget(e) {
|
|
1005
1066
|
// Get all nav items in shadow DOM
|
|
1006
1067
|
const navItems = this.shadowRoot?.querySelectorAll('.nav-item[data-id]');
|
|
1007
|
-
if (!navItems)
|
|
1068
|
+
if (!navItems) {
|
|
1008
1069
|
return;
|
|
1070
|
+
}
|
|
1009
1071
|
let foundTarget = false;
|
|
1010
1072
|
navItems.forEach((el) => {
|
|
1011
1073
|
const rect = el.getBoundingClientRect();
|
|
1012
1074
|
const itemId = el.getAttribute('data-id');
|
|
1013
|
-
if (!itemId || itemId === this.draggedNavItemId)
|
|
1075
|
+
if (!itemId || itemId === this.draggedNavItemId) {
|
|
1014
1076
|
return;
|
|
1077
|
+
}
|
|
1015
1078
|
// Skip if mouse is outside this element
|
|
1016
1079
|
if (e.clientX < rect.left || e.clientX > rect.right ||
|
|
1017
1080
|
e.clientY < rect.top || e.clientY > rect.bottom) {
|
|
@@ -1048,11 +1111,22 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1048
1111
|
}
|
|
1049
1112
|
else {
|
|
1050
1113
|
// Regular items only support above/below, not center
|
|
1051
|
-
|
|
1114
|
+
if (y < rect.height / 2) {
|
|
1115
|
+
position = 'above';
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
position = 'below';
|
|
1119
|
+
}
|
|
1052
1120
|
this.clearNavItemDragExpandTimeout();
|
|
1053
1121
|
}
|
|
1054
1122
|
// Determine what the new parent would be
|
|
1055
|
-
|
|
1123
|
+
let newParentId;
|
|
1124
|
+
if (position === 'center') {
|
|
1125
|
+
newParentId = item.id;
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
newParentId = item.parentId;
|
|
1129
|
+
}
|
|
1056
1130
|
const draggedItem = this.getComputedNav().find(i => i.id === this.draggedNavItemId);
|
|
1057
1131
|
// Don't show drop indicator if invalid drop:
|
|
1058
1132
|
// 1. Can't drop an item into itself (newParentId === draggedNavItemId)
|
|
@@ -1112,13 +1186,15 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1112
1186
|
* with new order values for the dragged item and shifts siblings as needed.
|
|
1113
1187
|
*/
|
|
1114
1188
|
executeNavItemDrop() {
|
|
1115
|
-
if (!this.draggedNavItemId || !this.navItemDropTargetId)
|
|
1189
|
+
if (!this.draggedNavItemId || !this.navItemDropTargetId) {
|
|
1116
1190
|
return;
|
|
1191
|
+
}
|
|
1117
1192
|
const allItems = this.getComputedNav();
|
|
1118
1193
|
const draggedItem = allItems.find(i => i.id === this.draggedNavItemId);
|
|
1119
1194
|
const targetItem = allItems.find(i => i.id === this.navItemDropTargetId);
|
|
1120
|
-
if (!draggedItem || !targetItem)
|
|
1195
|
+
if (!draggedItem || !targetItem) {
|
|
1121
1196
|
return;
|
|
1197
|
+
}
|
|
1122
1198
|
// Determine the new parentId for the dragged item
|
|
1123
1199
|
let newParentId;
|
|
1124
1200
|
if (this.navItemDropPosition === 'center' && targetItem.type === 'group') {
|
|
@@ -1130,8 +1206,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1130
1206
|
else {
|
|
1131
1207
|
newParentId = targetItem.parentId;
|
|
1132
1208
|
}
|
|
1133
|
-
if (newParentId === this.draggedNavItemId)
|
|
1209
|
+
if (newParentId === this.draggedNavItemId) {
|
|
1134
1210
|
return;
|
|
1211
|
+
}
|
|
1135
1212
|
// Get siblings in the destination parent
|
|
1136
1213
|
const siblings = allItems
|
|
1137
1214
|
.filter(i => i.parentId === newParentId && i.id !== this.draggedNavItemId)
|
|
@@ -1202,8 +1279,9 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1202
1279
|
// Rendering
|
|
1203
1280
|
// =========================================================================
|
|
1204
1281
|
renderNormalFooter() {
|
|
1205
|
-
if (!this.user)
|
|
1282
|
+
if (!this.user) {
|
|
1206
1283
|
return A;
|
|
1284
|
+
}
|
|
1207
1285
|
const initials = this.user.name
|
|
1208
1286
|
.split(' ')
|
|
1209
1287
|
.map((part) => part[0])
|
|
@@ -1300,7 +1378,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1300
1378
|
stroke="currentColor"
|
|
1301
1379
|
stroke-width="2"
|
|
1302
1380
|
>
|
|
1303
|
-
<path
|
|
1381
|
+
<path
|
|
1382
|
+
d="M6 9l6 6 6-6"
|
|
1383
|
+
stroke-linecap="round"
|
|
1384
|
+
stroke-linejoin="round"
|
|
1385
|
+
/>
|
|
1304
1386
|
</svg>
|
|
1305
1387
|
</button>
|
|
1306
1388
|
<div class=${e({
|
|
@@ -1352,7 +1434,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1352
1434
|
</div>
|
|
1353
1435
|
|
|
1354
1436
|
${this.subbar ? b `
|
|
1355
|
-
<kr-subbar
|
|
1437
|
+
<kr-subbar
|
|
1438
|
+
menu
|
|
1439
|
+
.breadcrumbs=${this.breadcrumbs}
|
|
1440
|
+
@menu-click=${this.handleMenuClick}
|
|
1441
|
+
>
|
|
1356
1442
|
<slot name="subbar"></slot>
|
|
1357
1443
|
</kr-subbar>
|
|
1358
1444
|
` : A}
|
|
@@ -1368,7 +1454,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1368
1454
|
${this.label
|
|
1369
1455
|
? b `<span class="nav-title">${this.label}</span>`
|
|
1370
1456
|
: this.logo
|
|
1371
|
-
? b `<img
|
|
1457
|
+
? b `<img
|
|
1458
|
+
class="nav-logo"
|
|
1459
|
+
src=${this.logo}
|
|
1460
|
+
alt="Logo"
|
|
1461
|
+
/>`
|
|
1372
1462
|
: A}
|
|
1373
1463
|
</div>
|
|
1374
1464
|
<div class="nav-content" @scroll=${this.handleNavScroll}>
|
|
@@ -1376,7 +1466,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1376
1466
|
<div class="nav-search">
|
|
1377
1467
|
<div class="nav-search__wrapper">
|
|
1378
1468
|
<span class="nav-search__icon">
|
|
1379
|
-
<svg
|
|
1469
|
+
<svg
|
|
1470
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1471
|
+
viewBox="0 0 24 24"
|
|
1472
|
+
fill="currentColor"
|
|
1473
|
+
>
|
|
1380
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"/>
|
|
1381
1475
|
</svg>
|
|
1382
1476
|
</span>
|
|
@@ -1389,7 +1483,11 @@ let KRScaffold = class KRScaffold extends i$1 {
|
|
|
1389
1483
|
/>
|
|
1390
1484
|
${this.navQuery ? b `
|
|
1391
1485
|
<button class="nav-search__clear" @click=${this.handleNavQueryClear}>
|
|
1392
|
-
<svg
|
|
1486
|
+
<svg
|
|
1487
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1488
|
+
viewBox="0 0 24 24"
|
|
1489
|
+
fill="currentColor"
|
|
1490
|
+
>
|
|
1393
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"/>
|
|
1394
1492
|
</svg>
|
|
1395
1493
|
</button>
|
|
@@ -1581,7 +1679,7 @@ KRScaffold.styles = i$4 `
|
|
|
1581
1679
|
.nav-content {
|
|
1582
1680
|
flex: 1;
|
|
1583
1681
|
overflow-y: auto;
|
|
1584
|
-
padding: 0 9px
|
|
1682
|
+
padding: 0 9px 12px 8px;
|
|
1585
1683
|
}
|
|
1586
1684
|
|
|
1587
1685
|
.nav-footer {
|
|
@@ -1701,7 +1799,7 @@ KRScaffold.styles = i$4 `
|
|
|
1701
1799
|
|
|
1702
1800
|
.breadcrumbs {
|
|
1703
1801
|
height: 32px;
|
|
1704
|
-
padding: 0
|
|
1802
|
+
padding: 0 16px;
|
|
1705
1803
|
display: flex;
|
|
1706
1804
|
align-items: center;
|
|
1707
1805
|
gap: 6px;
|
|
@@ -1795,7 +1893,7 @@ KRScaffold.styles = i$4 `
|
|
|
1795
1893
|
white-space: nowrap;
|
|
1796
1894
|
overflow: hidden;
|
|
1797
1895
|
text-overflow: ellipsis;
|
|
1798
|
-
letter-spacing: 0.
|
|
1896
|
+
letter-spacing: 0.14px;
|
|
1799
1897
|
}
|
|
1800
1898
|
|
|
1801
1899
|
.nav-item__chevron {
|
|
@@ -1850,7 +1948,7 @@ KRScaffold.styles = i$4 `
|
|
|
1850
1948
|
font-size: 11px;
|
|
1851
1949
|
font-weight: 600;
|
|
1852
1950
|
text-transform: uppercase;
|
|
1853
|
-
letter-spacing: 0.
|
|
1951
|
+
letter-spacing: 0.55px;
|
|
1854
1952
|
color: var(--kr-scaffold-nav-text);
|
|
1855
1953
|
opacity: 0.6;
|
|
1856
1954
|
}
|
|
@@ -1973,7 +2071,7 @@ KRScaffold.styles = i$4 `
|
|
|
1973
2071
|
|
|
1974
2072
|
.breadcrumbs {
|
|
1975
2073
|
height: 32px;
|
|
1976
|
-
padding: 0
|
|
2074
|
+
padding: 0 16px;
|
|
1977
2075
|
display: flex;
|
|
1978
2076
|
align-items: center;
|
|
1979
2077
|
gap: 6px;
|
|
@@ -2141,6 +2239,61 @@ KRScaffold.styles = i$4 `
|
|
|
2141
2239
|
}
|
|
2142
2240
|
}
|
|
2143
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);
|
|
2144
2297
|
__decorate$5([
|
|
2145
2298
|
r()
|
|
2146
2299
|
], KRScaffold.prototype, "navItemsExpanded", void 0);
|
|
@@ -2177,39 +2330,6 @@ __decorate$5([
|
|
|
2177
2330
|
__decorate$5([
|
|
2178
2331
|
r()
|
|
2179
2332
|
], KRScaffold.prototype, "pendingRequests", void 0);
|
|
2180
|
-
__decorate$5([
|
|
2181
|
-
n({ type: String })
|
|
2182
|
-
], KRScaffold.prototype, "logo", void 0);
|
|
2183
|
-
__decorate$5([
|
|
2184
|
-
n({ type: String })
|
|
2185
|
-
], KRScaffold.prototype, "label", void 0);
|
|
2186
|
-
__decorate$5([
|
|
2187
|
-
n({ type: String, attribute: 'home-url' })
|
|
2188
|
-
], KRScaffold.prototype, "homeUrl", void 0);
|
|
2189
|
-
__decorate$5([
|
|
2190
|
-
n({ type: String, reflect: true })
|
|
2191
|
-
], KRScaffold.prototype, "scheme", void 0);
|
|
2192
|
-
__decorate$5([
|
|
2193
|
-
n({ type: Array })
|
|
2194
|
-
], KRScaffold.prototype, "nav", void 0);
|
|
2195
|
-
__decorate$5([
|
|
2196
|
-
n({ type: Boolean, attribute: 'nav-icons-displayed', reflect: true })
|
|
2197
|
-
], KRScaffold.prototype, "navIconsDisplayed", void 0);
|
|
2198
|
-
__decorate$5([
|
|
2199
|
-
n({ type: Boolean, attribute: 'nav-expanded' })
|
|
2200
|
-
], KRScaffold.prototype, "navExpanded", void 0);
|
|
2201
|
-
__decorate$5([
|
|
2202
|
-
n({ type: Object })
|
|
2203
|
-
], KRScaffold.prototype, "user", void 0);
|
|
2204
|
-
__decorate$5([
|
|
2205
|
-
n({ type: Boolean })
|
|
2206
|
-
], KRScaffold.prototype, "subbar", void 0);
|
|
2207
|
-
__decorate$5([
|
|
2208
|
-
n({ type: Boolean, attribute: 'nav-enabled' })
|
|
2209
|
-
], KRScaffold.prototype, "navEnabled", void 0);
|
|
2210
|
-
__decorate$5([
|
|
2211
|
-
n({ type: Array })
|
|
2212
|
-
], KRScaffold.prototype, "breadcrumbs", void 0);
|
|
2213
2333
|
KRScaffold = __decorate$5([
|
|
2214
2334
|
t$1('kr-scaffold')
|
|
2215
2335
|
], KRScaffold);
|
|
@@ -2230,7 +2350,7 @@ var __decorate$4 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
2230
2350
|
* <kr-screen-nav
|
|
2231
2351
|
* label="Acme Corporation"
|
|
2232
2352
|
* subLabel="Company"
|
|
2233
|
-
* .
|
|
2353
|
+
* .items=${[
|
|
2234
2354
|
* { id: 'overview', label: 'Overview', url: '/companies/123/overview' },
|
|
2235
2355
|
* { id: 'contacts', label: 'Contacts', url: '/companies/123/contacts' },
|
|
2236
2356
|
* { id: 'activity', label: 'Activity', url: '/companies/123/activity' },
|
|
@@ -2245,7 +2365,7 @@ var __decorate$4 = (undefined && undefined.__decorate) || function (decorators,
|
|
|
2245
2365
|
*
|
|
2246
2366
|
* @property {string} label - Main label (e.g., entity name like "Acme Corporation")
|
|
2247
2367
|
* @property {string} subLabel - Sub label (e.g., entity type like "Company")
|
|
2248
|
-
* @property {KRScreenNavItem[]}
|
|
2368
|
+
* @property {KRScreenNavItem[]} items - Navigation items as JSON array
|
|
2249
2369
|
* @property {string} activeId - Currently active item ID
|
|
2250
2370
|
*/
|
|
2251
2371
|
let KRScreenNav = class KRScreenNav extends i$1 {
|
|
@@ -2262,7 +2382,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2262
2382
|
/**
|
|
2263
2383
|
* Navigation items
|
|
2264
2384
|
*/
|
|
2265
|
-
this.
|
|
2385
|
+
this.items = [];
|
|
2266
2386
|
/**
|
|
2267
2387
|
* Currently active item ID. Auto-detected from the URL by default.
|
|
2268
2388
|
* Can be set explicitly by the parent to override.
|
|
@@ -2274,7 +2394,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2274
2394
|
}
|
|
2275
2395
|
connectedCallback() {
|
|
2276
2396
|
super.connectedCallback();
|
|
2277
|
-
// Defer so property bindings (.
|
|
2397
|
+
// Defer so property bindings (.items) have been applied
|
|
2278
2398
|
requestAnimationFrame(() => this.syncActiveFromUrl());
|
|
2279
2399
|
window.addEventListener('popstate', this.handlePopstate);
|
|
2280
2400
|
}
|
|
@@ -2313,7 +2433,7 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2313
2433
|
}
|
|
2314
2434
|
syncActiveFromUrl() {
|
|
2315
2435
|
const pathname = window.location.pathname;
|
|
2316
|
-
const match = this.
|
|
2436
|
+
const match = this.items.find((item) => {
|
|
2317
2437
|
if (!item.url) {
|
|
2318
2438
|
return false;
|
|
2319
2439
|
}
|
|
@@ -2341,9 +2461,12 @@ let KRScreenNav = class KRScreenNav extends i$1 {
|
|
|
2341
2461
|
` : A}
|
|
2342
2462
|
<div class="nav-content">
|
|
2343
2463
|
<div class="nav-items">
|
|
2344
|
-
${this.
|
|
2464
|
+
${this.items.map((item) => b `
|
|
2345
2465
|
<a
|
|
2346
|
-
class
|
|
2466
|
+
class=${e({
|
|
2467
|
+
'nav-item': true,
|
|
2468
|
+
'nav-item--active': item.id === this.activeId
|
|
2469
|
+
})}
|
|
2347
2470
|
href=${item.url || '#'}
|
|
2348
2471
|
@click=${(e) => this.handleNavItemClick(e, item)}
|
|
2349
2472
|
>
|
|
@@ -2406,7 +2529,7 @@ KRScreenNav.styles = i$4 `
|
|
|
2406
2529
|
.nav-content {
|
|
2407
2530
|
flex: 1;
|
|
2408
2531
|
overflow-y: auto;
|
|
2409
|
-
padding: 0 0
|
|
2532
|
+
padding: 0 0 12px;
|
|
2410
2533
|
}
|
|
2411
2534
|
|
|
2412
2535
|
.nav-items {
|
|
@@ -2420,7 +2543,7 @@ KRScreenNav.styles = i$4 `
|
|
|
2420
2543
|
padding: 0 12px;
|
|
2421
2544
|
height: 32px;
|
|
2422
2545
|
line-height: 32px;
|
|
2423
|
-
letter-spacing: 0.
|
|
2546
|
+
letter-spacing: 0.13px;
|
|
2424
2547
|
color: rgb(32, 33, 36);
|
|
2425
2548
|
text-decoration: none;
|
|
2426
2549
|
font-size: 13px;
|
|
@@ -2461,7 +2584,7 @@ __decorate$4([
|
|
|
2461
2584
|
], KRScreenNav.prototype, "subLabel", void 0);
|
|
2462
2585
|
__decorate$4([
|
|
2463
2586
|
n({ type: Array })
|
|
2464
|
-
], KRScreenNav.prototype, "
|
|
2587
|
+
], KRScreenNav.prototype, "items", void 0);
|
|
2465
2588
|
__decorate$4([
|
|
2466
2589
|
n({ type: String })
|
|
2467
2590
|
], KRScreenNav.prototype, "activeId", void 0);
|
|
@@ -2531,7 +2654,7 @@ KRScreenDetail.styles = i$4 `
|
|
|
2531
2654
|
display: flex;
|
|
2532
2655
|
align-items: center;
|
|
2533
2656
|
justify-content: space-between;
|
|
2534
|
-
padding: 0
|
|
2657
|
+
padding: 0 24px;
|
|
2535
2658
|
background: #ffffff;
|
|
2536
2659
|
border-bottom: 1px solid #e5e7eb;
|
|
2537
2660
|
flex-shrink: 0;
|
|
@@ -2553,7 +2676,7 @@ KRScreenDetail.styles = i$4 `
|
|
|
2553
2676
|
.content {
|
|
2554
2677
|
flex: 1;
|
|
2555
2678
|
overflow-y: auto;
|
|
2556
|
-
padding:
|
|
2679
|
+
padding: 24px;
|
|
2557
2680
|
display: flex;
|
|
2558
2681
|
justify-content: center;
|
|
2559
2682
|
}
|
|
@@ -2594,7 +2717,10 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2594
2717
|
this.menu = false;
|
|
2595
2718
|
}
|
|
2596
2719
|
_handleMenuClick() {
|
|
2597
|
-
this.dispatchEvent(new CustomEvent('menu-click', {
|
|
2720
|
+
this.dispatchEvent(new CustomEvent('menu-click', {
|
|
2721
|
+
bubbles: true,
|
|
2722
|
+
composed: true
|
|
2723
|
+
}));
|
|
2598
2724
|
}
|
|
2599
2725
|
/**
|
|
2600
2726
|
* Resolves a breadcrumb URL by prepending the base href.
|
|
@@ -2611,13 +2737,19 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2611
2737
|
* - resolveUrl(crumb) = "/operations/settings" (used for href)
|
|
2612
2738
|
*/
|
|
2613
2739
|
resolveUrl(crumb) {
|
|
2614
|
-
if (!crumb.url)
|
|
2740
|
+
if (!crumb.url) {
|
|
2615
2741
|
return '#';
|
|
2742
|
+
}
|
|
2616
2743
|
// Remove leading slash from url if present, then combine with base
|
|
2617
|
-
|
|
2744
|
+
let path = crumb.url;
|
|
2745
|
+
if (crumb.url.startsWith('/')) {
|
|
2746
|
+
path = crumb.url.slice(1);
|
|
2747
|
+
}
|
|
2618
2748
|
const baseHref = document.querySelector('base')?.getAttribute('href') || '/';
|
|
2619
|
-
|
|
2620
|
-
|
|
2749
|
+
if (baseHref.endsWith('/')) {
|
|
2750
|
+
return baseHref + path;
|
|
2751
|
+
}
|
|
2752
|
+
return baseHref + '/' + path;
|
|
2621
2753
|
}
|
|
2622
2754
|
/**
|
|
2623
2755
|
* Handles click on a breadcrumb link.
|
|
@@ -2649,10 +2781,31 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2649
2781
|
return b `
|
|
2650
2782
|
${this.menu ? b `
|
|
2651
2783
|
<div class="menu" @click=${this._handleMenuClick}>
|
|
2652
|
-
<svg
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
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>
|
|
2656
2809
|
</svg>
|
|
2657
2810
|
</div>
|
|
2658
2811
|
` : A}
|
|
@@ -2662,7 +2815,10 @@ let KRSubbar = class KRSubbar extends i$1 {
|
|
|
2662
2815
|
return b `
|
|
2663
2816
|
${index > 0 ? b `<span class="breadcrumb-separator">/</span>` : ''}
|
|
2664
2817
|
<a
|
|
2665
|
-
class=${e({
|
|
2818
|
+
class=${e({
|
|
2819
|
+
'breadcrumb': true,
|
|
2820
|
+
'breadcrumb--current': isCurrent
|
|
2821
|
+
})}
|
|
2666
2822
|
href=${this.resolveUrl(crumb)}
|
|
2667
2823
|
@click=${(e) => this._handleBreadcrumbClick(e, crumb, isCurrent)}
|
|
2668
2824
|
>${crumb.label}</a>
|
|
@@ -2831,7 +2987,10 @@ class KRRouter {
|
|
|
2831
2987
|
for (const route of routes) {
|
|
2832
2988
|
const routeSegments = route.path.split('/').filter(s => s);
|
|
2833
2989
|
if (routeSegments.length === 0 && segments.length === 0) {
|
|
2834
|
-
return [{
|
|
2990
|
+
return [{
|
|
2991
|
+
route,
|
|
2992
|
+
params: {}
|
|
2993
|
+
}];
|
|
2835
2994
|
}
|
|
2836
2995
|
if (routeSegments.length === 0) {
|
|
2837
2996
|
continue;
|
|
@@ -2858,7 +3017,10 @@ class KRRouter {
|
|
|
2858
3017
|
if (remaining.length > 0 && !route.children) {
|
|
2859
3018
|
continue;
|
|
2860
3019
|
}
|
|
2861
|
-
const result = [{
|
|
3020
|
+
const result = [{
|
|
3021
|
+
route,
|
|
3022
|
+
params
|
|
3023
|
+
}];
|
|
2862
3024
|
if (route.children && remaining.length > 0) {
|
|
2863
3025
|
const childMatches = KRRouter.matchRoutes(route.children, remaining);
|
|
2864
3026
|
if (childMatches.length > 0) {
|
|
@@ -2938,97 +3100,2528 @@ KRRouterOutlet = __decorate$1([
|
|
|
2938
3100
|
t$1('kr-router-outlet')
|
|
2939
3101
|
], KRRouterOutlet);
|
|
2940
3102
|
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
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
|
+
"'": '''
|
|
2946
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
|
+
}
|
|
2947
3247
|
/**
|
|
2948
|
-
*
|
|
2949
|
-
*
|
|
2950
|
-
* Accepts a `send` callback that returns a streaming Response (SSE format).
|
|
2951
|
-
* Parses the stream for text tokens, status updates, errors, and frontend actions.
|
|
2952
|
-
* When an ACTION event arrives, dispatches a cancelable `action` custom event.
|
|
2953
|
-
* If not prevented, executes the native browser action (reload, navigate, etc.).
|
|
2954
|
-
*
|
|
2955
|
-
* ## SSE Stream Format
|
|
2956
|
-
* The component expects `data:` lines with JSON payloads containing a `type` field:
|
|
2957
|
-
* - `STATUS` — `{ type: "STATUS", message: "Thinking..." }`
|
|
2958
|
-
* - `RESPONSE_PART` — `{ type: "RESPONSE_PART", message: "token text" }`
|
|
2959
|
-
* - `ACTION` — `{ type: "ACTION", action: "RELOAD" }` (see KRChatbotAction)
|
|
2960
|
-
* - `ERROR` — `{ type: "ERROR", message: "Something went wrong" }`
|
|
2961
|
-
* - `HEARTBEAT` — `{ type: "HEARTBEAT" }` (ignored)
|
|
2962
|
-
*
|
|
2963
|
-
* The final event should include `finished: true` to signal stream completion.
|
|
3248
|
+
* Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
|
|
3249
|
+
* /c*$/ is vulnerable to REDOS.
|
|
2964
3250
|
*
|
|
2965
|
-
*
|
|
2966
|
-
*
|
|
2967
|
-
*
|
|
2968
|
-
* title="AI Assistant"
|
|
2969
|
-
* .send=${(params) => {
|
|
2970
|
-
* return fetch('/api/ai/chat/stream', {
|
|
2971
|
-
* method: 'POST',
|
|
2972
|
-
* headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' },
|
|
2973
|
-
* credentials: 'include',
|
|
2974
|
-
* body: JSON.stringify({ userText: params.message })
|
|
2975
|
-
* });
|
|
2976
|
-
* }}
|
|
2977
|
-
* ></kr-chatbot>
|
|
2978
|
-
* ```
|
|
2979
|
-
*
|
|
2980
|
-
* @slot - Optional slot content displayed above the messages area
|
|
2981
|
-
*
|
|
2982
|
-
* @fires message-submit - When the user sends a message. Cancelable. Detail: `{ message: string }`
|
|
2983
|
-
* @fires action - When the AI requests a frontend action. Cancelable. Detail: `{ action: KRChatbotAction }`
|
|
3251
|
+
* @param str
|
|
3252
|
+
* @param c
|
|
3253
|
+
* @param invert Remove suffix of non-c chars instead. Default falsey.
|
|
2984
3254
|
*/
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
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
|
-
|
|
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.
|
|
3032
5625
|
*/
|
|
3033
5626
|
this.opened = false;
|
|
3034
5627
|
// --- @state (internal) ---
|
|
@@ -3041,9 +5634,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3041
5634
|
let newLeft = this._dragStartLeft + (e.clientX - this._dragStartX);
|
|
3042
5635
|
let newTop = this._dragStartTop + (e.clientY - this._dragStartY);
|
|
3043
5636
|
const w = this._panelEl.offsetWidth;
|
|
3044
|
-
const h = this._panelEl.offsetHeight;
|
|
3045
5637
|
newLeft = Math.max(-w + 48, Math.min(newLeft, window.innerWidth - 48));
|
|
3046
|
-
newTop = Math.max(
|
|
5638
|
+
newTop = Math.max(0, Math.min(newTop, window.innerHeight - 48));
|
|
3047
5639
|
this._panelEl.style.left = newLeft + 'px';
|
|
3048
5640
|
this._panelEl.style.top = newTop + 'px';
|
|
3049
5641
|
}
|
|
@@ -3062,21 +5654,15 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3062
5654
|
newW = Math.max(minW, Math.min(this._resizeStartW + dx, maxW));
|
|
3063
5655
|
}
|
|
3064
5656
|
if (this._resizeDir.includes('w')) {
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
newW = proposedW;
|
|
3068
|
-
newLeft = this._dragStartLeft + dx;
|
|
3069
|
-
}
|
|
5657
|
+
newW = Math.max(minW, Math.min(this._resizeStartW - dx, maxW));
|
|
5658
|
+
newLeft = this._dragStartLeft + (this._resizeStartW - newW);
|
|
3070
5659
|
}
|
|
3071
5660
|
if (this._resizeDir.includes('s')) {
|
|
3072
5661
|
newH = Math.max(minH, Math.min(this._resizeStartH + dy, maxH));
|
|
3073
5662
|
}
|
|
3074
5663
|
if (this._resizeDir.includes('n')) {
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
newH = proposedH;
|
|
3078
|
-
newTop = this._dragStartTop + dy;
|
|
3079
|
-
}
|
|
5664
|
+
newH = Math.max(minH, Math.min(this._resizeStartH - dy, maxH));
|
|
5665
|
+
newTop = this._dragStartTop + (this._resizeStartH - newH);
|
|
3080
5666
|
}
|
|
3081
5667
|
newLeft = Math.max(0, newLeft);
|
|
3082
5668
|
newTop = Math.max(0, newTop);
|
|
@@ -3089,17 +5675,30 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3089
5675
|
this._handleMouseUp = () => {
|
|
3090
5676
|
if (this._isDragging) {
|
|
3091
5677
|
this._isDragging = false;
|
|
3092
|
-
this._panelEl.classList.remove('
|
|
5678
|
+
this._panelEl.classList.remove('panel--dragging');
|
|
3093
5679
|
}
|
|
3094
5680
|
if (this._isResizing) {
|
|
3095
5681
|
this._isResizing = false;
|
|
3096
|
-
this._panelEl.classList.remove('
|
|
5682
|
+
this._panelEl.classList.remove('panel--resizing');
|
|
3097
5683
|
}
|
|
5684
|
+
this._hideOverlay();
|
|
3098
5685
|
document.removeEventListener('mousemove', this._handleMouseMove);
|
|
3099
5686
|
document.removeEventListener('mouseup', this._handleMouseUp);
|
|
5687
|
+
this._saveState();
|
|
3100
5688
|
};
|
|
3101
5689
|
}
|
|
3102
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
|
+
}
|
|
3103
5702
|
disconnectedCallback() {
|
|
3104
5703
|
super.disconnectedCallback();
|
|
3105
5704
|
if (this._reader) {
|
|
@@ -3111,7 +5710,7 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3111
5710
|
}
|
|
3112
5711
|
updated(changed) {
|
|
3113
5712
|
if (changed.has('messages') || changed.has('_statusText')) {
|
|
3114
|
-
if (!this._userHasScrolledUp && this._messagesEl) {
|
|
5713
|
+
if (!this._userHasScrolledUp && !this._isStreaming && this._messagesEl) {
|
|
3115
5714
|
requestAnimationFrame(() => {
|
|
3116
5715
|
if (this._messagesEl) {
|
|
3117
5716
|
this._messagesEl.scrollTop = this._messagesEl.scrollHeight;
|
|
@@ -3135,6 +5734,38 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3135
5734
|
this._handleStop();
|
|
3136
5735
|
}
|
|
3137
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
|
+
}
|
|
3138
5769
|
_handleHeaderMouseDown(e) {
|
|
3139
5770
|
// Ignore clicks on buttons inside the header
|
|
3140
5771
|
if (e.target.closest('button')) {
|
|
@@ -3144,7 +5775,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3144
5775
|
return;
|
|
3145
5776
|
}
|
|
3146
5777
|
this._isDragging = true;
|
|
3147
|
-
this._panelEl.classList.add('
|
|
5778
|
+
this._panelEl.classList.add('panel--dragging');
|
|
5779
|
+
this._showOverlay();
|
|
3148
5780
|
const rect = this._panelEl.getBoundingClientRect();
|
|
3149
5781
|
this._panelEl.style.left = rect.left + 'px';
|
|
3150
5782
|
this._panelEl.style.top = rect.top + 'px';
|
|
@@ -3165,7 +5797,8 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3165
5797
|
}
|
|
3166
5798
|
this._isResizing = true;
|
|
3167
5799
|
this._resizeDir = e.currentTarget.dataset.dir || '';
|
|
3168
|
-
this._panelEl.classList.add('
|
|
5800
|
+
this._panelEl.classList.add('panel--resizing');
|
|
5801
|
+
this._showOverlay();
|
|
3169
5802
|
const rect = this._panelEl.getBoundingClientRect();
|
|
3170
5803
|
this._panelEl.style.left = rect.left + 'px';
|
|
3171
5804
|
this._panelEl.style.top = rect.top + 'px';
|
|
@@ -3185,16 +5818,75 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3185
5818
|
}
|
|
3186
5819
|
_handleToggle() {
|
|
3187
5820
|
this.opened = !this.opened;
|
|
3188
|
-
// Reset position when opening so it returns to default bottom-right
|
|
3189
5821
|
if (this.opened && this._panelEl) {
|
|
3190
|
-
this.
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
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
|
+
}
|
|
3197
5888
|
}
|
|
5889
|
+
catch { /* localStorage not available */ }
|
|
3198
5890
|
}
|
|
3199
5891
|
_handleInputChange(e) {
|
|
3200
5892
|
this._inputValue = e.target.value;
|
|
@@ -3244,6 +5936,27 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3244
5936
|
}];
|
|
3245
5937
|
this._isStreaming = true;
|
|
3246
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
|
+
});
|
|
3247
5960
|
this.send({
|
|
3248
5961
|
message: messageText,
|
|
3249
5962
|
messages: this.messages.slice(0, -1),
|
|
@@ -3371,49 +6084,6 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3371
6084
|
}
|
|
3372
6085
|
}
|
|
3373
6086
|
}
|
|
3374
|
-
else if (data.type === 'ACTION') {
|
|
3375
|
-
const action = data;
|
|
3376
|
-
const actionEvent = new CustomEvent('action', {
|
|
3377
|
-
detail: {
|
|
3378
|
-
action: action,
|
|
3379
|
-
},
|
|
3380
|
-
bubbles: true,
|
|
3381
|
-
composed: true,
|
|
3382
|
-
cancelable: true,
|
|
3383
|
-
});
|
|
3384
|
-
this.dispatchEvent(actionEvent);
|
|
3385
|
-
if (!actionEvent.defaultPrevented) {
|
|
3386
|
-
if (action.action === 'RELOAD') {
|
|
3387
|
-
location.reload();
|
|
3388
|
-
}
|
|
3389
|
-
else if (action.action === 'NAVIGATE') {
|
|
3390
|
-
if (action.data && action.data.url) {
|
|
3391
|
-
window.location.href = action.data.url;
|
|
3392
|
-
}
|
|
3393
|
-
}
|
|
3394
|
-
else if (action.action === 'OPEN_TAB') {
|
|
3395
|
-
if (action.data && action.data.url) {
|
|
3396
|
-
window.open(action.data.url, '_blank');
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
else if (action.action === 'UPDATE_HTML') {
|
|
3400
|
-
if (action.data && action.data.selector && action.data.html) {
|
|
3401
|
-
const el = document.querySelector(action.data.selector);
|
|
3402
|
-
if (el) {
|
|
3403
|
-
el.innerHTML = action.data.html;
|
|
3404
|
-
}
|
|
3405
|
-
}
|
|
3406
|
-
}
|
|
3407
|
-
else if (action.action === 'SCROLL_TO') {
|
|
3408
|
-
if (action.data && action.data.selector) {
|
|
3409
|
-
const el = document.querySelector(action.data.selector);
|
|
3410
|
-
if (el) {
|
|
3411
|
-
el.scrollIntoView({ behavior: 'smooth' });
|
|
3412
|
-
}
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
}
|
|
3416
|
-
}
|
|
3417
6087
|
else if (data.type === 'ERROR') {
|
|
3418
6088
|
this._handleStreamError(String(data.message || 'Unknown error'));
|
|
3419
6089
|
}
|
|
@@ -3447,157 +6117,192 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3447
6117
|
}
|
|
3448
6118
|
}
|
|
3449
6119
|
}
|
|
3450
|
-
/**
|
|
3451
|
-
* Lightweight text formatting for assistant messages.
|
|
3452
|
-
* Handles code blocks, inline code, bold, and line breaks.
|
|
3453
|
-
* Escapes HTML entities first to prevent XSS.
|
|
3454
|
-
*/
|
|
3455
|
-
_formatAssistantContent(text) {
|
|
3456
|
-
// Escape HTML entities
|
|
3457
|
-
let escaped = text
|
|
3458
|
-
.replace(/&/g, '&')
|
|
3459
|
-
.replace(/</g, '<')
|
|
3460
|
-
.replace(/>/g, '>')
|
|
3461
|
-
.replace(/"/g, '"')
|
|
3462
|
-
.replace(/'/g, ''');
|
|
3463
|
-
// Code blocks: ```...```
|
|
3464
|
-
escaped = escaped.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre><code>$2</code></pre>');
|
|
3465
|
-
// Inline code: `...`
|
|
3466
|
-
escaped = escaped.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
3467
|
-
// Bold: **...**
|
|
3468
|
-
escaped = escaped.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
3469
|
-
// Split on code blocks to only convert newlines outside of pre tags
|
|
3470
|
-
const parts = escaped.split(/(<pre><code>[\s\S]*?<\/code><\/pre>)/g);
|
|
3471
|
-
for (let i = 0; i < parts.length; i++) {
|
|
3472
|
-
// Skip code blocks (odd indices from the split)
|
|
3473
|
-
if (i % 2 === 0) {
|
|
3474
|
-
// Convert double newlines to paragraph breaks
|
|
3475
|
-
parts[i] = parts[i].replace(/\n\n/g, '</p><p>');
|
|
3476
|
-
// Convert single newlines to line breaks
|
|
3477
|
-
parts[i] = parts[i].replace(/\n/g, '<br>');
|
|
3478
|
-
}
|
|
3479
|
-
}
|
|
3480
|
-
escaped = parts.join('');
|
|
3481
|
-
// Wrap in paragraph if we inserted paragraph breaks
|
|
3482
|
-
if (escaped.includes('</p><p>')) {
|
|
3483
|
-
escaped = '<p>' + escaped + '</p>';
|
|
3484
|
-
}
|
|
3485
|
-
return escaped;
|
|
3486
|
-
}
|
|
3487
6120
|
// --- Render ---
|
|
3488
6121
|
render() {
|
|
3489
6122
|
return b `
|
|
3490
6123
|
<button
|
|
3491
6124
|
class=${e({
|
|
3492
|
-
'
|
|
3493
|
-
'
|
|
6125
|
+
'toggle': true,
|
|
6126
|
+
'toggle--hidden': this.opened,
|
|
3494
6127
|
})}
|
|
3495
6128
|
@click=${this._handleToggle}
|
|
3496
6129
|
title="Open chat"
|
|
3497
6130
|
>
|
|
3498
|
-
<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
|
+
>
|
|
3499
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"/>
|
|
3500
6140
|
<path d="M8 11h.01M12 11h.01M16 11h.01" stroke-width="2.5"/>
|
|
3501
6141
|
</svg>
|
|
3502
6142
|
</button>
|
|
3503
6143
|
|
|
3504
6144
|
<div class=${e({
|
|
3505
|
-
'
|
|
3506
|
-
'
|
|
6145
|
+
'panel': true,
|
|
6146
|
+
'panel--opened': this.opened,
|
|
3507
6147
|
})}>
|
|
3508
|
-
<div
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
<div
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
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>
|
|
3525
6192
|
${this.subtitle ? b `
|
|
3526
|
-
<span class="
|
|
6193
|
+
<span class="header-subtitle">${this.subtitle}</span>
|
|
3527
6194
|
` : A}
|
|
3528
6195
|
</div>
|
|
3529
6196
|
</div>
|
|
3530
|
-
<div class="
|
|
6197
|
+
<div class="header-actions">
|
|
3531
6198
|
${this.messages.length > 0 ? b `
|
|
3532
|
-
<button
|
|
3533
|
-
|
|
3534
|
-
|
|
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
|
+
/>
|
|
3535
6217
|
</svg>
|
|
3536
6218
|
</button>
|
|
3537
6219
|
` : A}
|
|
3538
|
-
<button
|
|
3539
|
-
|
|
3540
|
-
|
|
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
|
+
/>
|
|
3541
6238
|
</svg>
|
|
3542
6239
|
</button>
|
|
3543
6240
|
</div>
|
|
3544
6241
|
</div>
|
|
3545
6242
|
|
|
3546
|
-
<div class="
|
|
6243
|
+
<div class="messages" @scroll=${this._handleMessagesScroll}>
|
|
3547
6244
|
${this.messages.length === 0 ? b `
|
|
3548
|
-
<div class="
|
|
3549
|
-
<
|
|
3550
|
-
<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" />
|
|
3551
|
-
</svg>
|
|
3552
|
-
<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>
|
|
3553
6247
|
</div>
|
|
3554
6248
|
` : A}
|
|
3555
6249
|
${this.messages.map((msg) => b `
|
|
3556
6250
|
<div class=${e({
|
|
3557
|
-
'
|
|
3558
|
-
'
|
|
3559
|
-
'
|
|
6251
|
+
'message': true,
|
|
6252
|
+
'message--user': msg.role === 'user',
|
|
6253
|
+
'message--assistant': msg.role === 'assistant',
|
|
3560
6254
|
})}>
|
|
3561
6255
|
${msg.reasoning ? b `
|
|
3562
|
-
<details class="
|
|
6256
|
+
<details class="reasoning">
|
|
3563
6257
|
<summary>Thinking</summary>
|
|
3564
|
-
<div class="
|
|
6258
|
+
<div class="reasoning-content">${msg.reasoning}</div>
|
|
3565
6259
|
</details>
|
|
3566
6260
|
` : A}
|
|
3567
|
-
|
|
3568
|
-
|
|
6261
|
+
${msg.content ? b `
|
|
6262
|
+
<div class="message-content">
|
|
6263
|
+
${msg.role === 'user'
|
|
3569
6264
|
? msg.content
|
|
3570
|
-
: o(
|
|
3571
|
-
|
|
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}
|
|
3572
6275
|
</div>
|
|
3573
6276
|
`)}
|
|
3574
|
-
${this._statusText ? b `
|
|
3575
|
-
<div class="chatbot__message chatbot__message--assistant">
|
|
3576
|
-
<div class="chatbot__typing">
|
|
3577
|
-
<span></span>
|
|
3578
|
-
<span></span>
|
|
3579
|
-
<span></span>
|
|
3580
|
-
</div>
|
|
3581
|
-
</div>
|
|
3582
|
-
` : A}
|
|
3583
6277
|
</div>
|
|
3584
6278
|
|
|
3585
6279
|
${this._error ? b `
|
|
3586
|
-
<div class="
|
|
6280
|
+
<div class="error">
|
|
3587
6281
|
<span>${this._error}</span>
|
|
3588
|
-
<button class="
|
|
3589
|
-
<svg
|
|
3590
|
-
|
|
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
|
+
/>
|
|
3591
6296
|
</svg>
|
|
3592
6297
|
</button>
|
|
3593
6298
|
</div>
|
|
3594
6299
|
` : A}
|
|
3595
6300
|
|
|
3596
|
-
<div class="
|
|
3597
|
-
<div class="
|
|
3598
|
-
<button class="
|
|
6301
|
+
<div class="footer">
|
|
6302
|
+
<div class="input-wrapper">
|
|
6303
|
+
<button class="input-plus" title="Attach">+</button>
|
|
3599
6304
|
<textarea
|
|
3600
|
-
class="
|
|
6305
|
+
class="input"
|
|
3601
6306
|
.value=${this._inputValue}
|
|
3602
6307
|
placeholder=${this.placeholder}
|
|
3603
6308
|
rows="1"
|
|
@@ -3605,21 +6310,45 @@ let KRChatbot = class KRChatbot extends i$1 {
|
|
|
3605
6310
|
@keydown=${this._handleKeyDown}
|
|
3606
6311
|
></textarea>
|
|
3607
6312
|
${this._isStreaming ? b `
|
|
3608
|
-
<button
|
|
3609
|
-
|
|
3610
|
-
|
|
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
|
+
/>
|
|
3611
6331
|
</svg>
|
|
3612
6332
|
</button>
|
|
3613
6333
|
` : b `
|
|
3614
6334
|
<button
|
|
3615
6335
|
class=${e({
|
|
3616
|
-
'
|
|
3617
|
-
'
|
|
6336
|
+
'send': true,
|
|
6337
|
+
'send--disabled': !this._inputValue.trim(),
|
|
3618
6338
|
})}
|
|
3619
6339
|
@click=${this._handleSubmit}
|
|
3620
6340
|
title="Send message"
|
|
3621
6341
|
>
|
|
3622
|
-
<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
|
+
>
|
|
3623
6352
|
<path d="M12 19V5M5 12l7-7 7 7"/>
|
|
3624
6353
|
</svg>
|
|
3625
6354
|
</button>
|
|
@@ -3650,7 +6379,6 @@ KRChatbot.styles = i$4 `
|
|
|
3650
6379
|
--kr-chatbot-text: #1a1a2e;
|
|
3651
6380
|
--kr-chatbot-text-secondary: #64668b;
|
|
3652
6381
|
--kr-chatbot-user-bg: #e9e9e980;
|
|
3653
|
-
--kr-chatbot-user-text: #1a1a2e;
|
|
3654
6382
|
--kr-chatbot-error-bg: #fef2f2;
|
|
3655
6383
|
--kr-chatbot-error-text: #dc2626;
|
|
3656
6384
|
--kr-chatbot-success: #00b894;
|
|
@@ -3667,7 +6395,7 @@ KRChatbot.styles = i$4 `
|
|
|
3667
6395
|
}
|
|
3668
6396
|
|
|
3669
6397
|
/* Toggle button */
|
|
3670
|
-
.
|
|
6398
|
+
.toggle {
|
|
3671
6399
|
width: var(--kr-chatbot-toggle-size);
|
|
3672
6400
|
height: var(--kr-chatbot-toggle-size);
|
|
3673
6401
|
border-radius: 18px;
|
|
@@ -3682,24 +6410,24 @@ KRChatbot.styles = i$4 `
|
|
|
3682
6410
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
3683
6411
|
}
|
|
3684
6412
|
|
|
3685
|
-
.
|
|
6413
|
+
.toggle:hover {
|
|
3686
6414
|
transform: scale(1.05);
|
|
3687
6415
|
box-shadow: 0 6px 32px rgba(22, 48, 82, 0.5);
|
|
3688
6416
|
}
|
|
3689
6417
|
|
|
3690
|
-
.
|
|
6418
|
+
.toggle--hidden {
|
|
3691
6419
|
transform: scale(0);
|
|
3692
6420
|
opacity: 0;
|
|
3693
6421
|
pointer-events: none;
|
|
3694
6422
|
}
|
|
3695
6423
|
|
|
3696
|
-
.
|
|
6424
|
+
.toggle-icon {
|
|
3697
6425
|
width: 26px;
|
|
3698
6426
|
height: 26px;
|
|
3699
6427
|
}
|
|
3700
6428
|
|
|
3701
6429
|
/* Panel */
|
|
3702
|
-
.
|
|
6430
|
+
.panel {
|
|
3703
6431
|
display: none;
|
|
3704
6432
|
flex-direction: column;
|
|
3705
6433
|
background: var(--kr-chatbot-bg);
|
|
@@ -3717,7 +6445,7 @@ KRChatbot.styles = i$4 `
|
|
|
3717
6445
|
transform-origin: bottom right;
|
|
3718
6446
|
}
|
|
3719
6447
|
|
|
3720
|
-
.
|
|
6448
|
+
.panel--opened {
|
|
3721
6449
|
display: flex;
|
|
3722
6450
|
}
|
|
3723
6451
|
|
|
@@ -3733,49 +6461,35 @@ KRChatbot.styles = i$4 `
|
|
|
3733
6461
|
}
|
|
3734
6462
|
|
|
3735
6463
|
/* Header */
|
|
3736
|
-
.
|
|
3737
|
-
padding:
|
|
3738
|
-
|
|
3739
|
-
|
|
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);
|
|
3740
6470
|
display: flex;
|
|
3741
6471
|
align-items: center;
|
|
3742
6472
|
justify-content: space-between;
|
|
3743
6473
|
flex-shrink: 0;
|
|
3744
6474
|
}
|
|
3745
6475
|
|
|
3746
|
-
.
|
|
6476
|
+
.header-left {
|
|
3747
6477
|
display: flex;
|
|
3748
6478
|
align-items: center;
|
|
3749
6479
|
gap: 10px;
|
|
3750
6480
|
}
|
|
3751
6481
|
|
|
3752
|
-
|
|
3753
|
-
display: flex;
|
|
3754
|
-
flex-direction: column;
|
|
3755
|
-
gap: 2px;
|
|
3756
|
-
opacity: 0.35;
|
|
3757
|
-
}
|
|
3758
|
-
|
|
3759
|
-
.chatbot__header-drag-hint span {
|
|
3760
|
-
display: block;
|
|
3761
|
-
width: 14px;
|
|
3762
|
-
height: 2px;
|
|
3763
|
-
background: white;
|
|
3764
|
-
border-radius: 1px;
|
|
3765
|
-
}
|
|
3766
|
-
|
|
3767
|
-
.chatbot__header-info {
|
|
6482
|
+
.header-info {
|
|
3768
6483
|
display: flex;
|
|
3769
6484
|
flex-direction: column;
|
|
3770
6485
|
}
|
|
3771
6486
|
|
|
3772
|
-
.
|
|
3773
|
-
font-size:
|
|
6487
|
+
.header-title {
|
|
6488
|
+
font-size: 16px;
|
|
3774
6489
|
font-weight: 600;
|
|
3775
|
-
letter-spacing: -0.2px;
|
|
3776
6490
|
}
|
|
3777
6491
|
|
|
3778
|
-
.
|
|
6492
|
+
.header-subtitle {
|
|
3779
6493
|
color: rgba(255, 255, 255, 0.5);
|
|
3780
6494
|
font-size: 11px;
|
|
3781
6495
|
display: flex;
|
|
@@ -3783,7 +6497,7 @@ KRChatbot.styles = i$4 `
|
|
|
3783
6497
|
gap: 4px;
|
|
3784
6498
|
}
|
|
3785
6499
|
|
|
3786
|
-
.
|
|
6500
|
+
.header-subtitle::before {
|
|
3787
6501
|
content: '';
|
|
3788
6502
|
width: 5px;
|
|
3789
6503
|
height: 5px;
|
|
@@ -3791,18 +6505,18 @@ KRChatbot.styles = i$4 `
|
|
|
3791
6505
|
border-radius: 50%;
|
|
3792
6506
|
}
|
|
3793
6507
|
|
|
3794
|
-
.
|
|
6508
|
+
.header-actions {
|
|
3795
6509
|
display: flex;
|
|
3796
6510
|
align-items: center;
|
|
3797
6511
|
gap: 4px;
|
|
3798
6512
|
}
|
|
3799
6513
|
|
|
3800
|
-
.
|
|
3801
|
-
width:
|
|
3802
|
-
height:
|
|
6514
|
+
.header-action {
|
|
6515
|
+
width: 32px;
|
|
6516
|
+
height: 32px;
|
|
3803
6517
|
background: transparent;
|
|
3804
6518
|
border: none;
|
|
3805
|
-
color:
|
|
6519
|
+
color: rgb(0 0 0 / 70%);
|
|
3806
6520
|
border-radius: 8px;
|
|
3807
6521
|
cursor: pointer;
|
|
3808
6522
|
display: flex;
|
|
@@ -3811,18 +6525,18 @@ KRChatbot.styles = i$4 `
|
|
|
3811
6525
|
transition: all 0.15s;
|
|
3812
6526
|
}
|
|
3813
6527
|
|
|
3814
|
-
.
|
|
3815
|
-
background: rgba(
|
|
3816
|
-
color:
|
|
6528
|
+
.header-action:hover {
|
|
6529
|
+
background: rgba(0, 0, 0, 0.05);
|
|
6530
|
+
color: #000000;
|
|
3817
6531
|
}
|
|
3818
6532
|
|
|
3819
|
-
.
|
|
3820
|
-
width:
|
|
3821
|
-
height:
|
|
6533
|
+
.header-action-icon {
|
|
6534
|
+
width: 20px;
|
|
6535
|
+
height: 20px;
|
|
3822
6536
|
}
|
|
3823
6537
|
|
|
3824
6538
|
/* Messages */
|
|
3825
|
-
.
|
|
6539
|
+
.messages {
|
|
3826
6540
|
flex: 1;
|
|
3827
6541
|
overflow-y: auto;
|
|
3828
6542
|
padding: 32px;
|
|
@@ -3833,20 +6547,20 @@ KRChatbot.styles = i$4 `
|
|
|
3833
6547
|
background: white;
|
|
3834
6548
|
}
|
|
3835
6549
|
|
|
3836
|
-
.
|
|
6550
|
+
.messages::-webkit-scrollbar {
|
|
3837
6551
|
width: 4px;
|
|
3838
6552
|
}
|
|
3839
6553
|
|
|
3840
|
-
.
|
|
6554
|
+
.messages::-webkit-scrollbar-track {
|
|
3841
6555
|
background: transparent;
|
|
3842
6556
|
}
|
|
3843
6557
|
|
|
3844
|
-
.
|
|
6558
|
+
.messages::-webkit-scrollbar-thumb {
|
|
3845
6559
|
background: rgba(0, 0, 0, 0.08);
|
|
3846
6560
|
border-radius: 2px;
|
|
3847
6561
|
}
|
|
3848
6562
|
|
|
3849
|
-
.
|
|
6563
|
+
.empty {
|
|
3850
6564
|
flex: 1;
|
|
3851
6565
|
display: flex;
|
|
3852
6566
|
flex-direction: column;
|
|
@@ -3856,17 +6570,12 @@ KRChatbot.styles = i$4 `
|
|
|
3856
6570
|
gap: 8px;
|
|
3857
6571
|
}
|
|
3858
6572
|
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
opacity: 0.4;
|
|
3863
|
-
}
|
|
3864
|
-
|
|
3865
|
-
.chatbot__empty-text {
|
|
3866
|
-
font-size: 13px;
|
|
6573
|
+
.empty-text {
|
|
6574
|
+
font-size: 14px;
|
|
6575
|
+
color: rgb(0 0 0 / 80%);
|
|
3867
6576
|
}
|
|
3868
6577
|
|
|
3869
|
-
.
|
|
6578
|
+
.message {
|
|
3870
6579
|
display: flex;
|
|
3871
6580
|
flex-direction: column;
|
|
3872
6581
|
max-width: 100%;
|
|
@@ -3884,40 +6593,41 @@ KRChatbot.styles = i$4 `
|
|
|
3884
6593
|
}
|
|
3885
6594
|
}
|
|
3886
6595
|
|
|
3887
|
-
.
|
|
6596
|
+
.message--user {
|
|
3888
6597
|
align-self: flex-end;
|
|
3889
6598
|
align-items: flex-end;
|
|
3890
6599
|
max-width: 85%;
|
|
3891
6600
|
}
|
|
3892
6601
|
|
|
3893
|
-
.
|
|
6602
|
+
.message--assistant {
|
|
3894
6603
|
align-self: flex-start;
|
|
6604
|
+
gap: 24px;
|
|
3895
6605
|
}
|
|
3896
6606
|
|
|
3897
|
-
.
|
|
6607
|
+
.message-content {
|
|
3898
6608
|
line-height: 1.7;
|
|
3899
6609
|
word-wrap: break-word;
|
|
3900
6610
|
overflow-wrap: break-word;
|
|
3901
6611
|
}
|
|
3902
6612
|
|
|
3903
|
-
.
|
|
6613
|
+
.message--user .message-content {
|
|
3904
6614
|
display: inline-block;
|
|
3905
6615
|
background: var(--kr-chatbot-user-bg);
|
|
3906
|
-
color:
|
|
6616
|
+
color: #000000;
|
|
3907
6617
|
padding: 10px 16px;
|
|
3908
6618
|
border-radius: 20px;
|
|
3909
6619
|
border-bottom-right-radius: 6px;
|
|
3910
6620
|
font-size: 14px;
|
|
3911
6621
|
}
|
|
3912
6622
|
|
|
3913
|
-
.
|
|
6623
|
+
.message--assistant .message-content {
|
|
3914
6624
|
background: transparent;
|
|
3915
|
-
color:
|
|
6625
|
+
color: #000000;
|
|
3916
6626
|
padding: 0;
|
|
3917
6627
|
font-size: 14px;
|
|
3918
6628
|
}
|
|
3919
6629
|
|
|
3920
|
-
.
|
|
6630
|
+
.message--assistant .message-content pre {
|
|
3921
6631
|
background: #1e1e1e;
|
|
3922
6632
|
color: #d4d4d4;
|
|
3923
6633
|
padding: 12px;
|
|
@@ -3928,67 +6638,57 @@ KRChatbot.styles = i$4 `
|
|
|
3928
6638
|
line-height: 1.4;
|
|
3929
6639
|
}
|
|
3930
6640
|
|
|
3931
|
-
.
|
|
6641
|
+
.message--assistant .message-content code {
|
|
3932
6642
|
font-family: 'SF Mono', 'Fira Code', Monaco, monospace;
|
|
3933
6643
|
font-size: 13px;
|
|
3934
6644
|
}
|
|
3935
6645
|
|
|
3936
|
-
.
|
|
6646
|
+
.message--assistant .message-content :not(pre) > code {
|
|
3937
6647
|
background: rgba(0, 0, 0, 0.06);
|
|
3938
6648
|
padding: 2px 5px;
|
|
3939
6649
|
border-radius: 3px;
|
|
3940
6650
|
}
|
|
3941
6651
|
|
|
3942
|
-
.
|
|
6652
|
+
.message--assistant .message-content strong {
|
|
3943
6653
|
font-weight: 600;
|
|
3944
6654
|
}
|
|
3945
6655
|
|
|
3946
|
-
.
|
|
6656
|
+
.message--assistant .message-content p {
|
|
3947
6657
|
margin: 0 0 8px 0;
|
|
3948
6658
|
}
|
|
3949
6659
|
|
|
3950
|
-
.
|
|
6660
|
+
.message--assistant .message-content p:last-child {
|
|
3951
6661
|
margin-bottom: 0;
|
|
3952
6662
|
}
|
|
3953
6663
|
|
|
3954
6664
|
/* Reasoning */
|
|
3955
|
-
.
|
|
3956
|
-
margin-bottom: 8px;
|
|
6665
|
+
.reasoning {
|
|
3957
6666
|
border-radius: 6px;
|
|
3958
|
-
background:
|
|
6667
|
+
background: rgb(244 244 244 / 80%);
|
|
3959
6668
|
font-size: 12px;
|
|
3960
6669
|
}
|
|
3961
6670
|
|
|
3962
|
-
.
|
|
6671
|
+
.reasoning summary {
|
|
3963
6672
|
cursor: pointer;
|
|
3964
|
-
padding: 6px 10px;
|
|
3965
|
-
color:
|
|
3966
|
-
font-style: italic;
|
|
6673
|
+
padding: 6px 10px 6px 10px;
|
|
6674
|
+
color: black;
|
|
3967
6675
|
user-select: none;
|
|
3968
6676
|
}
|
|
3969
6677
|
|
|
3970
|
-
.
|
|
6678
|
+
.reasoning-content {
|
|
3971
6679
|
padding: 6px 10px 10px;
|
|
3972
|
-
color:
|
|
3973
|
-
line-height: 1.5;
|
|
6680
|
+
color: black;
|
|
3974
6681
|
white-space: pre-wrap;
|
|
3975
6682
|
word-wrap: break-word;
|
|
3976
6683
|
}
|
|
3977
6684
|
|
|
3978
|
-
|
|
3979
|
-
.chatbot__status {
|
|
3980
|
-
font-size: 13px;
|
|
3981
|
-
color: var(--kr-chatbot-text-secondary);
|
|
3982
|
-
font-style: italic;
|
|
3983
|
-
}
|
|
3984
|
-
|
|
3985
|
-
.chatbot__typing {
|
|
6685
|
+
.typing {
|
|
3986
6686
|
display: flex;
|
|
3987
6687
|
gap: 4px;
|
|
3988
6688
|
padding: 4px 0;
|
|
3989
6689
|
}
|
|
3990
6690
|
|
|
3991
|
-
.
|
|
6691
|
+
.typing span {
|
|
3992
6692
|
width: 6px;
|
|
3993
6693
|
height: 6px;
|
|
3994
6694
|
background: var(--kr-chatbot-text-secondary);
|
|
@@ -3997,11 +6697,11 @@ KRChatbot.styles = i$4 `
|
|
|
3997
6697
|
opacity: 0.4;
|
|
3998
6698
|
}
|
|
3999
6699
|
|
|
4000
|
-
.
|
|
6700
|
+
.typing span:nth-child(2) {
|
|
4001
6701
|
animation-delay: 0.2s;
|
|
4002
6702
|
}
|
|
4003
6703
|
|
|
4004
|
-
.
|
|
6704
|
+
.typing span:nth-child(3) {
|
|
4005
6705
|
animation-delay: 0.4s;
|
|
4006
6706
|
}
|
|
4007
6707
|
|
|
@@ -4017,7 +6717,7 @@ KRChatbot.styles = i$4 `
|
|
|
4017
6717
|
}
|
|
4018
6718
|
|
|
4019
6719
|
/* Error */
|
|
4020
|
-
.
|
|
6720
|
+
.error {
|
|
4021
6721
|
padding: 8px 16px;
|
|
4022
6722
|
background: var(--kr-chatbot-error-bg);
|
|
4023
6723
|
color: var(--kr-chatbot-error-text);
|
|
@@ -4029,7 +6729,7 @@ KRChatbot.styles = i$4 `
|
|
|
4029
6729
|
flex-shrink: 0;
|
|
4030
6730
|
}
|
|
4031
6731
|
|
|
4032
|
-
.
|
|
6732
|
+
.error-dismiss {
|
|
4033
6733
|
background: none;
|
|
4034
6734
|
border: none;
|
|
4035
6735
|
color: var(--kr-chatbot-error-text);
|
|
@@ -4040,19 +6740,19 @@ KRChatbot.styles = i$4 `
|
|
|
4040
6740
|
flex-shrink: 0;
|
|
4041
6741
|
}
|
|
4042
6742
|
|
|
4043
|
-
.
|
|
6743
|
+
.error-dismiss-icon {
|
|
4044
6744
|
width: 14px;
|
|
4045
6745
|
height: 14px;
|
|
4046
6746
|
}
|
|
4047
6747
|
|
|
4048
6748
|
/* Footer / Input */
|
|
4049
|
-
.
|
|
4050
|
-
padding:
|
|
6749
|
+
.footer {
|
|
6750
|
+
padding: 16px 16px 16px;
|
|
4051
6751
|
flex-shrink: 0;
|
|
4052
6752
|
background: white;
|
|
4053
6753
|
}
|
|
4054
6754
|
|
|
4055
|
-
.
|
|
6755
|
+
.input-wrapper {
|
|
4056
6756
|
display: flex;
|
|
4057
6757
|
align-items: center;
|
|
4058
6758
|
gap: 4px;
|
|
@@ -4063,12 +6763,12 @@ KRChatbot.styles = i$4 `
|
|
|
4063
6763
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
4064
6764
|
}
|
|
4065
6765
|
|
|
4066
|
-
.
|
|
6766
|
+
.input-wrapper:focus-within {
|
|
4067
6767
|
border-color: #b0b0b0;
|
|
4068
6768
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04);
|
|
4069
6769
|
}
|
|
4070
6770
|
|
|
4071
|
-
.
|
|
6771
|
+
.input-plus {
|
|
4072
6772
|
width: 34px;
|
|
4073
6773
|
height: 34px;
|
|
4074
6774
|
border: none;
|
|
@@ -4085,11 +6785,11 @@ KRChatbot.styles = i$4 `
|
|
|
4085
6785
|
transition: background 0.15s;
|
|
4086
6786
|
}
|
|
4087
6787
|
|
|
4088
|
-
.
|
|
6788
|
+
.input-plus:hover {
|
|
4089
6789
|
background: #f8f9fc;
|
|
4090
6790
|
}
|
|
4091
6791
|
|
|
4092
|
-
.
|
|
6792
|
+
.input {
|
|
4093
6793
|
flex: 1;
|
|
4094
6794
|
border: none;
|
|
4095
6795
|
outline: none;
|
|
@@ -4101,14 +6801,14 @@ KRChatbot.styles = i$4 `
|
|
|
4101
6801
|
min-height: 26px;
|
|
4102
6802
|
max-height: 120px;
|
|
4103
6803
|
background: transparent;
|
|
4104
|
-
color:
|
|
6804
|
+
color: black;
|
|
4105
6805
|
}
|
|
4106
6806
|
|
|
4107
|
-
.
|
|
6807
|
+
.input::placeholder {
|
|
4108
6808
|
color: #b0b0b0;
|
|
4109
6809
|
}
|
|
4110
6810
|
|
|
4111
|
-
.
|
|
6811
|
+
.send {
|
|
4112
6812
|
width: 34px;
|
|
4113
6813
|
height: 34px;
|
|
4114
6814
|
border-radius: 50%;
|
|
@@ -4123,25 +6823,25 @@ KRChatbot.styles = i$4 `
|
|
|
4123
6823
|
transition: all 0.15s;
|
|
4124
6824
|
}
|
|
4125
6825
|
|
|
4126
|
-
.
|
|
6826
|
+
.send:hover {
|
|
4127
6827
|
background: var(--kr-chatbot-primary-hover);
|
|
4128
6828
|
}
|
|
4129
6829
|
|
|
4130
|
-
.
|
|
6830
|
+
.send--disabled {
|
|
4131
6831
|
opacity: 0.4;
|
|
4132
6832
|
cursor: default;
|
|
4133
6833
|
}
|
|
4134
6834
|
|
|
4135
|
-
.
|
|
6835
|
+
.send--disabled:hover {
|
|
4136
6836
|
background: var(--kr-chatbot-primary);
|
|
4137
6837
|
}
|
|
4138
6838
|
|
|
4139
|
-
.
|
|
6839
|
+
.send-icon {
|
|
4140
6840
|
width: 16px;
|
|
4141
6841
|
height: 16px;
|
|
4142
6842
|
}
|
|
4143
6843
|
|
|
4144
|
-
.
|
|
6844
|
+
.stop {
|
|
4145
6845
|
width: 34px;
|
|
4146
6846
|
height: 34px;
|
|
4147
6847
|
border-radius: 50%;
|
|
@@ -4156,62 +6856,51 @@ KRChatbot.styles = i$4 `
|
|
|
4156
6856
|
transition: all 0.15s;
|
|
4157
6857
|
}
|
|
4158
6858
|
|
|
4159
|
-
.
|
|
6859
|
+
.stop:hover {
|
|
4160
6860
|
background: #b91c1c;
|
|
4161
6861
|
}
|
|
4162
6862
|
|
|
4163
|
-
.
|
|
6863
|
+
.stop-icon {
|
|
4164
6864
|
width: 14px;
|
|
4165
6865
|
height: 14px;
|
|
4166
6866
|
}
|
|
4167
6867
|
|
|
4168
6868
|
/* Header drag cursor */
|
|
4169
|
-
.
|
|
6869
|
+
.header {
|
|
4170
6870
|
cursor: grab;
|
|
4171
6871
|
user-select: none;
|
|
4172
6872
|
}
|
|
4173
6873
|
|
|
4174
|
-
.
|
|
6874
|
+
.header:active {
|
|
4175
6875
|
cursor: grabbing;
|
|
4176
6876
|
}
|
|
4177
6877
|
|
|
4178
6878
|
/* Drag / Resize states */
|
|
4179
|
-
.
|
|
4180
|
-
.
|
|
6879
|
+
.panel--dragging,
|
|
6880
|
+
.panel--resizing {
|
|
4181
6881
|
transition: none;
|
|
4182
6882
|
user-select: none;
|
|
4183
6883
|
}
|
|
4184
6884
|
|
|
4185
|
-
.
|
|
6885
|
+
.panel--dragging {
|
|
4186
6886
|
box-shadow: 0 32px 96px rgba(0, 0, 0, 0.18), 0 12px 40px rgba(0, 0, 0, 0.1);
|
|
4187
6887
|
}
|
|
4188
6888
|
|
|
4189
6889
|
/* Resize handles */
|
|
4190
|
-
.
|
|
6890
|
+
.resize {
|
|
4191
6891
|
position: absolute;
|
|
4192
6892
|
z-index: 10;
|
|
4193
6893
|
}
|
|
4194
6894
|
|
|
4195
|
-
.
|
|
4196
|
-
.
|
|
4197
|
-
.
|
|
4198
|
-
.
|
|
4199
|
-
.
|
|
4200
|
-
.
|
|
4201
|
-
.
|
|
4202
|
-
.
|
|
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; }
|
|
4203
6903
|
|
|
4204
|
-
.chatbot__resize--se::after {
|
|
4205
|
-
content: '';
|
|
4206
|
-
position: absolute;
|
|
4207
|
-
bottom: 7px;
|
|
4208
|
-
right: 7px;
|
|
4209
|
-
width: 10px;
|
|
4210
|
-
height: 10px;
|
|
4211
|
-
border-right: 2px solid rgba(0, 0, 0, 0.12);
|
|
4212
|
-
border-bottom: 2px solid rgba(0, 0, 0, 0.12);
|
|
4213
|
-
border-radius: 0 0 3px 0;
|
|
4214
|
-
}
|
|
4215
6904
|
`;
|
|
4216
6905
|
__decorate([
|
|
4217
6906
|
n({ attribute: false })
|
|
@@ -4219,6 +6908,9 @@ __decorate([
|
|
|
4219
6908
|
__decorate([
|
|
4220
6909
|
n({ attribute: false })
|
|
4221
6910
|
], KRChatbot.prototype, "clear", void 0);
|
|
6911
|
+
__decorate([
|
|
6912
|
+
n({ attribute: false })
|
|
6913
|
+
], KRChatbot.prototype, "load", void 0);
|
|
4222
6914
|
__decorate([
|
|
4223
6915
|
n({ attribute: false })
|
|
4224
6916
|
], KRChatbot.prototype, "messages", void 0);
|
|
@@ -4232,7 +6924,10 @@ __decorate([
|
|
|
4232
6924
|
n({ type: String })
|
|
4233
6925
|
], KRChatbot.prototype, "placeholder", void 0);
|
|
4234
6926
|
__decorate([
|
|
4235
|
-
n({
|
|
6927
|
+
n({
|
|
6928
|
+
type: Boolean,
|
|
6929
|
+
reflect: true
|
|
6930
|
+
})
|
|
4236
6931
|
], KRChatbot.prototype, "opened", void 0);
|
|
4237
6932
|
__decorate([
|
|
4238
6933
|
r()
|
|
@@ -4247,13 +6942,13 @@ __decorate([
|
|
|
4247
6942
|
r()
|
|
4248
6943
|
], KRChatbot.prototype, "_error", void 0);
|
|
4249
6944
|
__decorate([
|
|
4250
|
-
e$3('.
|
|
6945
|
+
e$3('.panel')
|
|
4251
6946
|
], KRChatbot.prototype, "_panelEl", void 0);
|
|
4252
6947
|
__decorate([
|
|
4253
|
-
e$3('.
|
|
6948
|
+
e$3('.messages')
|
|
4254
6949
|
], KRChatbot.prototype, "_messagesEl", void 0);
|
|
4255
6950
|
__decorate([
|
|
4256
|
-
e$3('.
|
|
6951
|
+
e$3('.input')
|
|
4257
6952
|
], KRChatbot.prototype, "_inputEl", void 0);
|
|
4258
6953
|
KRChatbot = __decorate([
|
|
4259
6954
|
t$1('kr-chatbot')
|