@kodaris/krubble-app-components 1.0.66 → 1.0.68

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