@kodaris/krubble-app-components 1.0.67 → 1.0.69

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