@kodaris/krubble-app-components 1.0.67 → 1.0.68

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