@codady/coax 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/coax.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2026-1-12 14:46:3
3
+ * @since Last modified: 2026-1-15 19:21:59
4
4
  * @name Coax event management system.
5
- * @version 0.0.4
5
+ * @version 0.0.6
6
6
  * @author AXUI development team <3217728223@qq.com>
7
7
  * @description Coax is a lightweight web component for elegant code display with syntax highlighting, typewriter effects, and theme switching. Supports JavaScript, HTML, CSS, TypeScript, and Markdown with copy tools and customization.
8
8
  * @see {@link https://coax.axui.cn|Official website}
@@ -436,6 +436,25 @@
436
436
  return toolsEl;
437
437
  };
438
438
 
439
+ const trimEmptyLines = (str) => {
440
+ if (str == null)
441
+ return '';
442
+ return str.replace(/^\s*\n|\n\s*$/g, '') || '';
443
+ };
444
+
445
+ const escapeHtmlChars = (text) => {
446
+ // Check if the input text is empty or undefined
447
+ if (!text)
448
+ return '';
449
+ // Replace the special characters with their corresponding HTML entities
450
+ return text
451
+ .replace(/&/g, '&amp;') // Replace '&' with '&amp;'
452
+ .replace(/</g, '&lt;') // Replace '<' with '&lt;'
453
+ .replace(/>/g, '&gt;') // Replace '>' with '&gt;'
454
+ .replace(/"/g, '&quot;') // Replace '"' with '&quot;'
455
+ .replace(/'/g, '&#39;'); // Replace "'" with '&#39;'
456
+ };
457
+
439
458
  class Coax extends HTMLElement {
440
459
  // A static Map to hold the configuration for different languages
441
460
  static languages = new Map();
@@ -446,7 +465,7 @@
446
465
  baseStylesEl; // Element for base styles
447
466
  themeStylesEl; // Element for theme styles
448
467
  dynamicStylesEl; // Element for dynamic styles
449
- highlightedCodeEl; // Element that holds the highlighted code
468
+ highlightEl; // Element that holds the highlighted code
450
469
  headerEl; // Header element (for code name, tools, etc.)
451
470
  codeNameEl; // Code name element (shows language or alias)
452
471
  codeToolsEl; // Code tools element (for interactive tools like copy)
@@ -457,12 +476,13 @@
457
476
  lastLineString = ''; // The last line's string
458
477
  speed = 5; // Speed of the typing effect (higher is slower)
459
478
  autoScroll = true; // Flag to enable/disable auto-scrolling
479
+ canListen = true; // Flag to enable/disable auto-scrolling
460
480
  constructor() {
461
481
  super();
462
482
  // Attach a Shadow DOM to the custom element
463
483
  this.attachShadow({ mode: 'open' });
464
484
  // Remove leading/trailing whitespace from the raw code content
465
- this.source = this.textContent?.replace(/^\s*\n|\n\s*$/g, '') || '';
485
+ this.source = escapeHtmlChars(trimEmptyLines(this.textContent));
466
486
  // Initialize the basic structure of the component
467
487
  this.shadowRoot.innerHTML = `
468
488
  <style id="base-styles">
@@ -593,7 +613,7 @@
593
613
  <style id="theme-styles"></style>
594
614
  <div id="code-header"><span id="code-name">${this.alias}</span><div id="code-tools"></div></div>
595
615
  <div id="code-body">
596
- <pre><code id="highlight-code"></code></pre>
616
+ <pre><code id="highlight"></code></pre>
597
617
  </div>
598
618
  `;
599
619
  // Cache references to various elements
@@ -604,7 +624,7 @@
604
624
  this.codeNameEl = getEl('#code-name', this.shadowRoot);
605
625
  this.codeToolsEl = getEl('#code-tools', this.shadowRoot);
606
626
  this.codeBodyEl = getEl('#code-body', this.shadowRoot);
607
- this.highlightedCodeEl = getEl('#highlight-code', this.shadowRoot);
627
+ this.highlightEl = getEl('#highlight', this.shadowRoot);
608
628
  this.codeBodyEl.addEventListener('scroll', () => {
609
629
  let flag = this.codeBodyEl.scrollTop + this.codeBodyEl.clientHeight < this.codeBodyEl.scrollHeight;
610
630
  // Check if the user manually scrolled
@@ -639,7 +659,7 @@
639
659
  static get observedAttributes() { return ['lang', 'height', 'max-height', 'tools', 'speed']; }
640
660
 
641
661
  attributeChangedCallback(name, oldVal, newVal) {
642
- if (oldVal === newVal)
662
+ if (oldVal === newVal || !this.canListen)
643
663
  return;
644
664
  if (name === 'height' || name === 'max-height') {
645
665
  this.updateStyleByRegExp(name, newVal);
@@ -692,16 +712,16 @@
692
712
  createLineWrap(index, startIndex) {
693
713
  let dataIndex = 0;
694
714
  if (index == null && startIndex == null) {
695
- dataIndex = this.highlightedCodeEl.children.length;
715
+ dataIndex = this.highlightEl.children.length;
696
716
  }
697
717
  else {
698
- const start = startIndex || this.highlightedCodeEl.children.length;
718
+ const start = startIndex || this.highlightEl.children.length;
699
719
  dataIndex = start + index;
700
720
  }
701
721
  return createEl('div', { 'data-index': dataIndex }, '<div></div>');
702
722
  }
703
723
 
704
- getLineToFill(codeWrap, line, config) {
724
+ getLineToFillHighLight(codeWrap, line, config) {
705
725
  config = config || Coax.languages.get(this.lang);
706
726
  let highlightedLine = this.getHighLightString(line, config);
707
727
  // 将高亮后的内容填充到 div 中
@@ -709,10 +729,10 @@
709
729
  }
710
730
  ;
711
731
 
712
- async highlight(newCode) {
713
- const config = Coax.languages.get(this.lang), startIndex = this.highlightedCodeEl.children.length,
732
+ async highlight(newCode = this.source) {
733
+ const config = Coax.languages.get(this.lang), startIndex = this.highlightEl.children.length,
714
734
  // 将新源码按行分割
715
- newCodeLines = newCode ? newCode.split('\n') : [];
735
+ newCodeLines = newCode ? newCode.split('\n') : [], hasSpeedAttr = this.hasAttribute('speed'), hasSanitizedAttr = this.hasAttribute('sanitized');
716
736
  //更新别名
717
737
  this.updateName(config);
718
738
  if (!newCodeLines.length)
@@ -720,14 +740,14 @@
720
740
  // 如果没有找到配置,则输出原始代码,并不进行高亮处理
721
741
  for (let [index, lineString] of newCodeLines.entries()) {
722
742
  //如果是空行则跳过
723
- if (!lineString.trim() && this.hasAttribute('sanitized'))
743
+ if (!lineString.trim() && hasSanitizedAttr)
724
744
  continue;
725
745
  // 创建一个 div 包裹每一行
726
746
  const lineWrap = this.createLineWrap(index, startIndex), codeWrap = lineWrap.lastElementChild;
727
747
  //标记完成
728
748
  lineWrap.completed = true;
729
- if (this.hasAttribute('speed')) {
730
- this.highlightedCodeEl.appendChild(lineWrap);
749
+ if (hasSpeedAttr) {
750
+ this.highlightEl.appendChild(lineWrap);
731
751
  //流式打字
732
752
  await typeWriter(lineString, {
733
753
  speed: this.speed,
@@ -735,13 +755,13 @@
735
755
  codeWrap.innerHTML = fullText;
736
756
  }
737
757
  });
738
- this.getLineToFill(codeWrap, lineString, config);
758
+ this.getLineToFillHighLight(codeWrap, lineString, config);
739
759
  }
740
760
  else {
741
761
  //直接打出
742
- this.getLineToFill(codeWrap, lineString, config);
762
+ this.getLineToFillHighLight(codeWrap, lineString, config);
743
763
  //
744
- this.highlightedCodeEl.appendChild(lineWrap);
764
+ this.highlightEl.appendChild(lineWrap);
745
765
  }
746
766
  }
747
767
  //滚动到最底部
@@ -797,32 +817,48 @@
797
817
  this.codeNameEl.innerHTML = this.alias;
798
818
  }
799
819
  }
820
+ trimLineString(str) {
821
+ // 删除开头的第一个换行符
822
+ if (str.startsWith('\n')) {
823
+ str = str.substring(1);
824
+ }
825
+ // 删除结尾的第一个换行符
826
+ if (str.endsWith('\n')) {
827
+ str = str.slice(0, -1);
828
+ }
829
+ return str;
830
+ }
800
831
 
801
- render(code = this.source) {
832
+ render() {
802
833
  //同时多次改变属性,只执行一次
803
834
  if (this._renderQueued)
804
835
  return;
805
836
  this._renderQueued = true;
806
- // 使用 requestAnimationFrame 将渲染推迟到下一帧
807
837
  requestAnimationFrame(async () => {
808
- this.clear();
838
+ this.highlightEl.innerHTML = '';
809
839
  this.injectThemeStyles();
810
840
  //一次性渲染
811
- await this.highlight(code);
841
+ await this.highlight();
812
842
  this._renderQueued = false;
813
843
  });
814
844
  }
815
845
 
816
846
  clear() {
817
- this.highlightedCodeEl.innerHTML = this.source = this.lineString = '';
847
+ this.highlightEl.innerHTML = this.source = this.lineString = '';
818
848
  }
819
849
 
820
850
  async replace(newCode) {
821
- this.clear();
822
- await this.highlight(newCode);
851
+ newCode = escapeHtmlChars(newCode);
852
+ this.source = trimEmptyLines(newCode);
853
+ if (this._renderQueued)
854
+ return;
855
+ this.highlightEl.innerHTML = '';
856
+ //一次性渲染
857
+ await this.highlight();
823
858
  }
824
859
 
825
860
  async append(newCode) {
861
+ newCode = escapeHtmlChars(newCode);
826
862
  // 将新的代码追加到现有代码末尾
827
863
  this.source += `\n${newCode}`;
828
864
  // 高亮新的部分
@@ -830,7 +866,7 @@
830
866
  }
831
867
 
832
868
  getLastLine() {
833
- const lastChild = this.highlightedCodeEl.lastElementChild, lastLine = !lastChild || this.highlightedCodeEl.lastElementChild?.completed ?
869
+ const lastChild = this.highlightEl.lastElementChild, lastLine = !lastChild || this.highlightEl.lastElementChild?.completed ?
834
870
  this.createLineWrap() : lastChild;
835
871
  return {
836
872
  lineWrap: lastLine,
@@ -839,19 +875,19 @@
839
875
  }
840
876
 
841
877
  close() {
842
- const lineWrap = this.highlightedCodeEl.lastElementChild;
878
+ const lineWrap = this.highlightEl.lastElementChild;
843
879
  if (!lineWrap)
844
880
  return;
845
881
  lineWrap.completed = true;
846
882
  //行结束前保存
847
883
  this.lastLineString = this.lineString;
848
- this.getLineToFill(lineWrap?.lastElementChild, this.lineString);
884
+ this.getLineToFillHighLight(lineWrap?.lastElementChild, this.lineString);
849
885
  //一行结束,清空临时行文本
850
886
  this.lineString = '';
851
887
  }
852
888
 
853
889
  open() {
854
- const lineWrap = this.highlightedCodeEl.lastElementChild;
890
+ const lineWrap = this.highlightEl.lastElementChild;
855
891
  if (!lineWrap)
856
892
  return;
857
893
  lineWrap.completed = false;
@@ -860,20 +896,21 @@
860
896
  }
861
897
 
862
898
  stream(str, forceClose = false) {
863
- const { lineWrap, codeWrap } = this.getLastLine();
864
- this.highlightedCodeEl.appendChild(lineWrap);
899
+ str = escapeHtmlChars(str);
900
+ const { lineWrap, codeWrap } = this.getLastLine(), isLine = str.startsWith('\n') || str.endsWith('\n');
901
+ this.highlightEl.appendChild(lineWrap);
865
902
  //汇集
866
903
  this.source += str;
904
+ //临时保存行文本
905
+ this.lineString += isLine ? this.trimLineString(str) : str;
867
906
  //如果没有遇到换行符号,也可以强制结束
868
- if (forceClose || (str.startsWith('\n') || str.endsWith('\n'))) {
907
+ if (forceClose || isLine) {
869
908
  //标记完成
870
909
  this.close();
871
910
  }
872
911
  else {
873
912
  //插入文本
874
913
  codeWrap.innerHTML += str;
875
- //临时保存行文本
876
- this.lineString += str;
877
914
  }
878
915
  //滚动到最底部
879
916
  this.autoScrollCode();
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2026-1-12 14:46:3
2
+ * @since Last modified: 2026-1-15 19:21:59
3
3
  * @name Coax event management system.
4
- * @version 0.0.4
4
+ * @version 0.0.6
5
5
  * @author AXUI development team <3217728223@qq.com>
6
6
  * @description Coax is a lightweight web component for elegant code display with syntax highlighting, typewriter effects, and theme switching. Supports JavaScript, HTML, CSS, TypeScript, and Markdown with copy tools and customization.
7
7
  * @see {@link https://coax.axui.cn|Official website}
@@ -12,4 +12,4 @@
12
12
  * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'coax', 'Coax' and 'COAX' within the software.
13
13
  * @license MIT license
14
14
  */
15
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).coax=t()}(this,function(){"use strict";const e="ax",trim$1=(e,t="")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},wrap=(e,t,n=!1,i)=>{const r=i?.size||"1em",o=i?.color||"currentColor",a=i?.thickness||2,l=i?.classes?(e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim$1(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim$1(e,"global")).filter(Boolean)})(i.classes).join(" "):"",s=t.name.replace(/([A-Z])/g,"-$1").toLowerCase();return`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}" viewBox="0 0 24 24" fill="none" stroke="${o}"\n stroke-width="${a}" stroke-linecap="round" stroke-linejoin="round" class="${s} ${l}">\n ${n?((e="")=>`\n <style>\n :where([dir="rtl"]) .icax-${e},\n :where(:dir(rtl)) .icax-${e} {\n transform: scaleX(-1);\n transform-origin: center;\n }\n </style>\n`)(s.split("-")[1]):""}\n ${e}\n </svg>`},icaxCheck=e=>wrap('<polyline points="20 6 9 17 4 12"></polyline>',icaxCheck,!1,e),icaxCopy=e=>wrap('<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>',icaxCopy,!1,e),t={name:"copy",icon:icaxCopy(),action:function(e){e.wrapEl.onclick=()=>{navigator.clipboard.writeText(this.source).then(()=>{e.iconEl.innerHTML=icaxCheck(),e.iconEl.toggleAttribute("disabled",!0),setTimeout(()=>{e.iconEl.removeAttribute("disabled"),e.iconEl.innerHTML=icaxCopy()},2e3)}).catch(e=>{})}}},typeWriter=(e,t)=>{const n=t.speed||100;return new Promise(i=>{t?.onBeforeType?.(e);let r=0;const o=setInterval(()=>{if(r<e.length){const n=e.charAt(r),i=e.substring(0,r+1);t?.onDuringType?.(n,i),r++}else clearInterval(o),i(e),t?.onAfterType?.(e)},n)})},trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim(e,"global")).filter(Boolean)},getDataType=e=>{let t,n=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===n&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===n&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":n,t},getEl=(e,t=document.body)=>{let n=getDataType(e),i=getDataType(t),r=i.includes("HTML")||"ShadowRoot"===i?t:document.querySelector(t),o=r&&r instanceof HTMLTemplateElement?r.content:r,a=null;if(e)if(n.includes("HTML"))a=e;else if("String"===n)try{a=(o||document).querySelector(e.trim())}catch{a=null}return a},createEl=(e,t,n)=>{let i=(e=e||"div").toUpperCase().trim(),r=document.createElement(i),o=getDataType(t);if(t&&"Object"===o)for(let e in t)t.hasOwnProperty(e)&&r.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let n=getDataType(t);if("TEMPLATE"===i)e.innerHTML=t.toString();else if("Array"===n&&t.length>0)for(let n of t){if(getDataType(n).includes("HTML"))e.appendChild(n);else{let t=createEl(n.name,n.attrs,n.content);t&&e.appendChild(t)}}else if(n.includes("HTML"))e.appendChild(t);else if("String"===n&&t.trim().startsWith("#")&&t.trim().length>1){let n=getEl(t);if(!n)return;"TEMPLATE"===n.nodeName?e.appendChild(n.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",n.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(r,n),r},isEmpty=e=>{let t,n=getDataType(e);return t=!e||("Object"===n?0===Object.keys(e).length:"Array"===n?""===e.join(""):"Function"===n?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===n?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===n||"Map"===n?0===e.size:"Date"===n?isNaN(e.getTime()):"RegExp"===n?""===e.source:"ArrayBuffer"===n?0===e.byteLength:"NodeList"===n||"HTMLCollection"===n||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===n||e instanceof Error?""===e.message:!(!n.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(n))&&0===e.length),t},n="rep",createTools=t=>{const i=createEl("span",{class:`${e}-box-tools`}),renderFn=e=>{const t={},i=e.extendable?`<i ${n}="arrow"></i>`:"",r=(e.icon?`<i ${n}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${n}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${n}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${n}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${n}="label">${e.label}</i>`:"")+i;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),r),e.iconEl=e.wrapEl.querySelector(`[${n}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${n}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${n}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${n}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${n}="label"]`),!isEmpty(e.classes)&&((e,t)=>{const n=getEl(e),i=parseClasses(t);n&&0!==i.length&&i.forEach(e=>{n.classList.add(e)})})(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let e of t)renderFn(e),i.appendChild(e.wrapEl),e?.action?.(e);return i};class Coax extends HTMLElement{static languages=new Map;static tools=[];source;_renderQueued=!1;baseStylesEl;themeStylesEl;dynamicStylesEl;highlightedCodeEl;headerEl;codeNameEl;codeToolsEl;codeBodyEl;lang="plain";alias="Plain Text";lineString="";lastLineString="";speed=5;autoScroll=!0;constructor(){super(),this.attachShadow({mode:"open"}),this.source=this.textContent?.replace(/^\s*\n|\n\s*$/g,"")||"",this.shadowRoot.innerHTML=`\n <style id="base-styles">\n :host { \n --border-width:1px;\n --border-style:solid;\n --radius:9px;\n --height:auto;\n --max-height:500px;\n --radius:9px;\n --padding:1em;\n --font-size:16px;\n --line-height:1.8;\n --background:rgb(247, 247, 247);\n --border-color:rgb(224, 224, 224);\n --color-code:rgb(51, 51, 51);\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(0,0,0,0.04);\n --color-hover:rgba(0,0,0,0.06);\n } \n :host([scheme="dark"]){\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n @media (prefers-color-scheme: dark) {\n :host{\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n }\n :host {\n font-size: var(--${e}-code-font-size,var(--font-size));\n display: block; \n box-sizing:border-box;\n background:var(--${e}-code-background-color,var(--background));\n color:var(--${e}-code-color,var(--color-code));\n border:var(--${e}-code-border-width,var(--border-width)) var(--${e}-code-border-style,var(--border-style)) var(--${e}-code-border-color,var(--border-color));\n transition: border-color 0.3s ease,color 0.3s ease; \n border-radius: var(--${e}-code-radius,var(--radius));\n }\n #code-header{\n line-height:calc(var(--${e}-code-line-height,var(--line-height))*1.5);\n padding-inline-start:var(--${e}-code-padding,var(--padding));\n display:flex;\n \n >:first-child{\n flex:auto;\n }\n }\n #code-body{\n padding: var(--${e}-code-padding,var(--padding)) 0;\n height:var(--${e}-code-height,var(--height));\n max-height:var(--${e}-code-max-height,var(--max-height));\n overflow:auto;\n }\n pre,code{\n font-family:"Consolas", "Monaco", "Andale Mono", "Ubuntu Mono", "monospace";\n margin:0; padding:0;\n }\n code>div{\n display:flex;\n padding:0 var(--${e}-code-padding,var(--padding));\n line-height: var(--${e}-code-line-height,var(--line-height));\n box-sizing:border-box;\n \n >div{\n flex:auto;\n }\n }\n code>div>div:empty:before{\n content:' ';\n }\n :host([indexed]) code>div:before{\n display:inline-flex;\n color:var(--color-index);\n content: attr(data-index);\n min-width:var(--${e}-code-index-width,2em);\n margin-inline-end:var(--${e}-code-padding,8px);\n }\n :host([striped]) code>div:nth-child(odd){\n background-color:var(--color-stripe);\n }\n :host([hoverable]) code>div:hover{\n background-color:var(--color-hover);\n }\n :host([wrapped]) code>div>div{\n white-space: pre-wrap;\n }\n :host([unnamed]) #code-name{\n display:none;\n }\n .${e}-box-tools{\n >*{\n font-size:14px;\n display:inline-flex;\n align-items:center;\n justify-content:center;\n height:2em;\n line-height:2em;\n aspect-ratio:1/1;\n margin-inline-end:8px;\n transition:all 200ms ease;\n border-radius:6px;\n &:hover{\n cursor:pointer;\n background-color:rgba(0,0,0,.04);\n }\n }\n [rep=icon]{\n display:inline-flex;\n align-items:center;\n justify-content:center;\n }\n }\n [disabled]{\n pointer-event:none;\n }\n </style>\n <style id="dynamic-styles"></style>\n <style id="theme-styles"></style>\n <div id="code-header"><span id="code-name">${this.alias}</span><div id="code-tools"></div></div>\n <div id="code-body">\n <pre><code id="highlight-code"></code></pre>\n </div>\n `,this.baseStylesEl=getEl("#base-styles",this.shadowRoot),this.themeStylesEl=getEl("#theme-styles",this.shadowRoot),this.dynamicStylesEl=getEl("#dynamic-styles",this.shadowRoot),this.headerEl=getEl("#code-header",this.shadowRoot),this.codeNameEl=getEl("#code-name",this.shadowRoot),this.codeToolsEl=getEl("#code-tools",this.shadowRoot),this.codeBodyEl=getEl("#code-body",this.shadowRoot),this.highlightedCodeEl=getEl("#highlight-code",this.shadowRoot),this.codeBodyEl.addEventListener("scroll",()=>{let e=this.codeBodyEl.scrollTop+this.codeBodyEl.clientHeight<this.codeBodyEl.scrollHeight;this.autoScroll=!e})}static register(e,t){this.languages.set(e,{...t})}static addTools(e){Coax.tools=e}mountTools(e){requestAnimationFrame(()=>{this.codeToolsEl.innerHTML="";let t=e.map(e=>(e.action=e.action.bind(this),e));this.codeToolsEl.appendChild(createTools(t))})}connectedCallback(){this.render()}static get observedAttributes(){return["lang","height","max-height","tools","speed"]}attributeChangedCallback(e,t,n){if(t!==n&&("height"!==e&&"max-height"!==e||this.updateStyleByRegExp(e,n),"speed"===e&&(this.speed=~~!!n),"lang"===e&&(this.lang=n,this.render()),"tools"===e)){n||(this.codeToolsEl.innerHTML="");const e=parseClasses(n),t=Coax.tools.filter(t=>e.includes(t.name));if(!t.length)return;this.mountTools(t)}}updateStyleByRegExp(e,t){const n=new RegExp(`;\\n\\s*${e}:\\s*[^;]+;`,"g");this.baseStylesEl.textContent=this.baseStylesEl.textContent.replace(n,`;\n${e}: ${t};`)}getCssPrefix(e){return(e?.cssPrefix||this.lang).replace(/[^a-zA-Z0-9_-]/g,"\\$&")}getHighLightString(t,n){if(!(n=n||Coax.languages.get(this.lang)))return t;const i=this.getCssPrefix(n),r=new RegExp(n.rules.map(e=>`(${e.pattern.source})`).join("|"),"g");return t.replace(r,(t,...r)=>{const o=r.findIndex(e=>void 0!==e);return-1!==o&&n.rules[o]?`<span class="${e}-${i}-${n.rules[o].token}">${t}</span>`:t})}createLineWrap(e,t){let n=0;if(null==e&&null==t)n=this.highlightedCodeEl.children.length;else{n=(t||this.highlightedCodeEl.children.length)+e}return createEl("div",{"data-index":n},"<div></div>")}getLineToFill(e,t,n){n=n||Coax.languages.get(this.lang);let i=this.getHighLightString(t,n);e.innerHTML=i}async highlight(e){const t=Coax.languages.get(this.lang),n=this.highlightedCodeEl.children.length,i=e?e.split("\n"):[];if(this.updateName(t),!i.length)return!0;for(let[e,r]of i.entries()){if(!r.trim()&&this.hasAttribute("sanitized"))continue;const i=this.createLineWrap(e,n),o=i.lastElementChild;i.completed=!0,this.hasAttribute("speed")?(this.highlightedCodeEl.appendChild(i),await typeWriter(r,{speed:this.speed,onDuringType:(e,t)=>{o.innerHTML=t}}),this.getLineToFill(o,r,t)):(this.getLineToFill(o,r,t),this.highlightedCodeEl.appendChild(i))}return this.autoScrollCode(),!0}autoScrollCode(){this.autoScroll&&(this.codeBodyEl.scrollTop=this.codeBodyEl.scrollHeight)}injectThemeStyles(){const t=Coax.languages.get(this.lang);if(!t)return;let n=this.getCssPrefix(t),i=t.rules.map(t=>`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token}${t.light?","+t.light:""});}`).join("\n"),r="",o="";r+=':host([scheme="dark"]){',r+=t.rules.map(t=>"\n "+(t.light?`\n .${e}-${n}-${t.token} {color: var(--${e}-${n}-${t.token},${t.dark});}`:"")).join("\n"),r+="}",o="@media (prefers-color-scheme: dark){\n :host{\n ",o+=t.rules.map(t=>`\n ${t.light?`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token},${t.dark}); }`:""} `).join("\n"),o+="}",this.dynamicStylesEl.textContent=i+r+o,t?.themeStyles&&(this.themeStylesEl.textContent=t.themeStyles)}updateName(e){this.hasAttribute("unnamed")||(e?(this.alias=e.alias||this.lang,this.codeNameEl.innerHTML=this.alias):this.codeNameEl.innerHTML="Plain Text")}render(e=this.source){this._renderQueued||(this._renderQueued=!0,requestAnimationFrame(async()=>{this.clear(),this.injectThemeStyles(),await this.highlight(e),this._renderQueued=!1}))}clear(){this.highlightedCodeEl.innerHTML=this.source=this.lineString=""}async replace(e){this.clear(),await this.highlight(e)}async append(e){this.source+=`\n${e}`,await this.highlight(e)}getLastLine(){const e=this.highlightedCodeEl.lastElementChild,t=!e||this.highlightedCodeEl.lastElementChild?.completed?this.createLineWrap():e;return{lineWrap:t,codeWrap:t.lastElementChild}}close(){const e=this.highlightedCodeEl.lastElementChild;e&&(e.completed=!0,this.lastLineString=this.lineString,this.getLineToFill(e?.lastElementChild,this.lineString),this.lineString="")}open(){const e=this.highlightedCodeEl.lastElementChild;e&&(e.completed=!1,(e?.lastElementChild).textContent=this.lineString=this.lastLineString)}stream(e,t=!1){const{lineWrap:n,codeWrap:i}=this.getLastLine();this.highlightedCodeEl.appendChild(n),this.source+=e,t||e.startsWith("\n")||e.endsWith("\n")?this.close():(i.innerHTML+=e,this.lineString+=e),this.autoScrollCode()}}return Coax.register("css",{alias:"CSS",rules:[{token:"comment",pattern:/\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"value",pattern:/(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/,light:"#032f62",dark:"#a5d6ff"},{token:"func",pattern:/[a-z-]+\(?=/,light:"#e36209",dark:"#ffa657"},{token:"property",pattern:/[a-z-]+(?=\s*:)/,light:"#005cc5",dark:"#79c0ff"},{token:"selector",pattern:/[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i,light:"#22863a",dark:"#7ee787"},{token:"unit",pattern:/(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/,light:"#d73a49",dark:"#ff7b72"},{token:"number",pattern:/\b\d+(\.\d+)?\b/,light:"#005cc5",dark:"#79c0ff"},{token:"punct",pattern:/[{}();:]/,light:"#24292e",dark:"#c9d1d9"}]}),Coax.register("html",{alias:"HTML",rules:[{token:"comment",pattern:/&lt;!--[\s\S]*?--&gt;/,light:"#999999",dark:"#6e7681"},{token:"doctype",pattern:/&lt;!DOCTYPE[\s\S]*?&gt;/i,light:"#6a737d",dark:"#8b949e"},{token:"tag",pattern:/&lt;\/?[a-zA-Z0-9]+/,light:"#22863a",dark:"#7ee787"},{token:"attr",pattern:/[a-zA-Z-]+(?=\s*=\s*)/,light:"#6f42c1",dark:"#d2a8ff"},{token:"string",pattern:/(['"])(?:\\.|[^\\])*?\1/,light:"#032f62",dark:"#a5d6ff"},{token:"bracket",pattern:/\/?&gt;/,light:"#24292e",dark:"#c9d1d9"}]}),Coax.register("js",{alias:"Javascript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"keyword",pattern:/\b(async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|new|return|super|switch|this|throw|try|typeof|var|while|with|yield|let|static)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise|Number|String|Boolean)\b/,light:"#e36209",dark:"#ffa657"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/[+\-*/%=<>!&|^~]+/,light:"#069598",dark:"#56b6c2"}]}),Coax.register("ts",{alias:"Typescript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"decorator",pattern:/@[a-zA-Z_]\w*/,light:"#953800",dark:"#ffa657"},{token:"keyword",pattern:/\b(abstract|as|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|package|private|protected|public|readonly|return|set|static|super|switch|this|throw|try|type|typeof|var|while|with|yield)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|true|false|console|window|document)\b/,light:"#e36209",dark:"#ffa657"},{token:"type",pattern:/\b[A-Z]\w*\b/,light:"#005cc5",dark:"#79c0ff"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/,light:"#089ba6",dark:"#79c0ff"}]}),Coax.register("md",{alias:"Markdown",rules:[{token:"comment",pattern:/<!--[\s\S]*?-->/,light:"#6a737d",dark:"#8b949e"},{token:"heading",pattern:/(^|\n)(#{1,6})\s*(.+)/,light:"#e36209",dark:"#ffa657"},{token:"bold",pattern:/\*\*([^*]+)\*\*|__([^_]+)__/g,light:"#d73a49",dark:"#ff7b72"},{token:"italic",pattern:/\*([^*]+)\*|_([^_]+)_/g,light:"#032f62",dark:"#a5d6ff"},{token:"link",pattern:/\[([^\]]+)\]\(([^)]+)\)/g,light:"#0288d1",dark:"#80c0ff"},{token:"inline-code",pattern:/`([^`]+)`/g,light:"#032f62",dark:"#98c379"},{token:"code-block",pattern:/```([^\n]+)\n([\s\S]*?)```/g,light:"#24292e",dark:"#c9d1d9"},{token:"list-item",pattern:/(^|\n)([-*])\s+(.+)/g,light:"#5c6e7c",dark:"#8b949e"},{token:"quote",pattern:/(^|\n)>[ \t]*(.+)/g,light:"#6f42c1",dark:"#d2a8ff"},{token:"image",pattern:/!\[([^\]]+)\]\(([^)]+)\)/g,light:"#d73a49",dark:"#ff7b72"},{token:"hr",pattern:/^(---|___|\*\*\*)\s*$/gm,light:"#24292e",dark:"#c9d1d9"},{token:"strikethrough",pattern:/~~([^~]+)~~/g,light:"#e36209",dark:"#ffa657"},{token:"table",pattern:/\|([^\|]+)\|([^\|]+)\|/g,light:"#5c6e7c",dark:"#8b949e"}]}),Coax.addTools([t]),customElements.define(`${e}-code`,Coax),Coax});
15
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).coax=t()}(this,function(){"use strict";const e="ax",trim$1=(e,t="")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},wrap=(e,t,n=!1,i)=>{const r=i?.size||"1em",a=i?.color||"currentColor",o=i?.thickness||2,l=i?.classes?(e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim$1(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim$1(e,"global")).filter(Boolean)})(i.classes).join(" "):"",s=t.name.replace(/([A-Z])/g,"-$1").toLowerCase();return`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}" viewBox="0 0 24 24" fill="none" stroke="${a}"\n stroke-width="${o}" stroke-linecap="round" stroke-linejoin="round" class="${s} ${l}">\n ${n?((e="")=>`\n <style>\n :where([dir="rtl"]) .icax-${e},\n :where(:dir(rtl)) .icax-${e} {\n transform: scaleX(-1);\n transform-origin: center;\n }\n </style>\n`)(s.split("-")[1]):""}\n ${e}\n </svg>`},icaxCheck=e=>wrap('<polyline points="20 6 9 17 4 12"></polyline>',icaxCheck,!1,e),icaxCopy=e=>wrap('<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>',icaxCopy,!1,e),t={name:"copy",icon:icaxCopy(),action:function(e){e.wrapEl.onclick=()=>{navigator.clipboard.writeText(this.source).then(()=>{e.iconEl.innerHTML=icaxCheck(),e.iconEl.toggleAttribute("disabled",!0),setTimeout(()=>{e.iconEl.removeAttribute("disabled"),e.iconEl.innerHTML=icaxCopy()},2e3)}).catch(e=>{})}}},typeWriter=(e,t)=>{const n=t.speed||100;return new Promise(i=>{t?.onBeforeType?.(e);let r=0;const a=setInterval(()=>{if(r<e.length){const n=e.charAt(r),i=e.substring(0,r+1);t?.onDuringType?.(n,i),r++}else clearInterval(a),i(e),t?.onAfterType?.(e)},n)})},trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,n=[];return Array.isArray(e)?n=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",n=e.split(t)),n.map(e=>trim(e,"global")).filter(Boolean)},getDataType=e=>{let t,n=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===n&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===n&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":n,t},getEl=(e,t=document.body)=>{let n=getDataType(e),i=getDataType(t),r=i.includes("HTML")||"ShadowRoot"===i?t:document.querySelector(t),a=r&&r instanceof HTMLTemplateElement?r.content:r,o=null;if(e)if(n.includes("HTML"))o=e;else if("String"===n)try{o=(a||document).querySelector(e.trim())}catch{o=null}return o},createEl=(e,t,n)=>{let i=(e=e||"div").toUpperCase().trim(),r=document.createElement(i),a=getDataType(t);if(t&&"Object"===a)for(let e in t)t.hasOwnProperty(e)&&r.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let n=getDataType(t);if("TEMPLATE"===i)e.innerHTML=t.toString();else if("Array"===n&&t.length>0)for(let n of t){if(getDataType(n).includes("HTML"))e.appendChild(n);else{let t=createEl(n.name,n.attrs,n.content);t&&e.appendChild(t)}}else if(n.includes("HTML"))e.appendChild(t);else if("String"===n&&t.trim().startsWith("#")&&t.trim().length>1){let n=getEl(t);if(!n)return;"TEMPLATE"===n.nodeName?e.appendChild(n.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",n.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(r,n),r},isEmpty=e=>{let t,n=getDataType(e);return t=!e||("Object"===n?0===Object.keys(e).length:"Array"===n?""===e.join(""):"Function"===n?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===n?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===n||"Map"===n?0===e.size:"Date"===n?isNaN(e.getTime()):"RegExp"===n?""===e.source:"ArrayBuffer"===n?0===e.byteLength:"NodeList"===n||"HTMLCollection"===n||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===n||e instanceof Error?""===e.message:!(!n.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(n))&&0===e.length),t},n="rep",createTools=t=>{const i=createEl("span",{class:`${e}-box-tools`}),renderFn=e=>{const t={},i=e.extendable?`<i ${n}="arrow"></i>`:"",r=(e.icon?`<i ${n}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${n}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${n}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${n}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${n}="label">${e.label}</i>`:"")+i;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),r),e.iconEl=e.wrapEl.querySelector(`[${n}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${n}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${n}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${n}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${n}="label"]`),!isEmpty(e.classes)&&((e,t)=>{const n=getEl(e),i=parseClasses(t);n&&0!==i.length&&i.forEach(e=>{n.classList.add(e)})})(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let e of t)renderFn(e),i.appendChild(e.wrapEl),e?.action?.(e);return i},trimEmptyLines=e=>null==e?"":e.replace(/^\s*\n|\n\s*$/g,"")||"",escapeHtmlChars=e=>e?e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"):"";class Coax extends HTMLElement{static languages=new Map;static tools=[];source;_renderQueued=!1;baseStylesEl;themeStylesEl;dynamicStylesEl;highlightEl;headerEl;codeNameEl;codeToolsEl;codeBodyEl;lang="plain";alias="Plain Text";lineString="";lastLineString="";speed=5;autoScroll=!0;canListen=!0;constructor(){super(),this.attachShadow({mode:"open"}),this.source=escapeHtmlChars(trimEmptyLines(this.textContent)),this.shadowRoot.innerHTML=`\n <style id="base-styles">\n :host { \n --border-width:1px;\n --border-style:solid;\n --radius:9px;\n --height:auto;\n --max-height:500px;\n --radius:9px;\n --padding:1em;\n --font-size:16px;\n --line-height:1.8;\n --background:rgb(247, 247, 247);\n --border-color:rgb(224, 224, 224);\n --color-code:rgb(51, 51, 51);\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(0,0,0,0.04);\n --color-hover:rgba(0,0,0,0.06);\n } \n :host([scheme="dark"]){\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n @media (prefers-color-scheme: dark) {\n :host{\n --background: #282c34;\n --border-color: transparent;\n --color-code: #abb2bf;\n --color-index:rgb(153, 153, 153);\n --color-stripe:rgba(255,255,255,0.04);\n --color-hover:rgba(255,255,255,0.06);\n }\n }\n :host {\n font-size: var(--${e}-code-font-size,var(--font-size));\n display: block; \n box-sizing:border-box;\n background:var(--${e}-code-background-color,var(--background));\n color:var(--${e}-code-color,var(--color-code));\n border:var(--${e}-code-border-width,var(--border-width)) var(--${e}-code-border-style,var(--border-style)) var(--${e}-code-border-color,var(--border-color));\n transition: border-color 0.3s ease,color 0.3s ease; \n border-radius: var(--${e}-code-radius,var(--radius));\n }\n #code-header{\n line-height:calc(var(--${e}-code-line-height,var(--line-height))*1.5);\n padding-inline-start:var(--${e}-code-padding,var(--padding));\n display:flex;\n \n >:first-child{\n flex:auto;\n }\n }\n #code-body{\n padding: var(--${e}-code-padding,var(--padding)) 0;\n height:var(--${e}-code-height,var(--height));\n max-height:var(--${e}-code-max-height,var(--max-height));\n overflow:auto;\n }\n pre,code{\n font-family:"Consolas", "Monaco", "Andale Mono", "Ubuntu Mono", "monospace";\n margin:0; padding:0;\n }\n code>div{\n display:flex;\n padding:0 var(--${e}-code-padding,var(--padding));\n line-height: var(--${e}-code-line-height,var(--line-height));\n box-sizing:border-box;\n \n >div{\n flex:auto;\n }\n }\n code>div>div:empty:before{\n content:' ';\n }\n :host([indexed]) code>div:before{\n display:inline-flex;\n color:var(--color-index);\n content: attr(data-index);\n min-width:var(--${e}-code-index-width,2em);\n margin-inline-end:var(--${e}-code-padding,8px);\n }\n :host([striped]) code>div:nth-child(odd){\n background-color:var(--color-stripe);\n }\n :host([hoverable]) code>div:hover{\n background-color:var(--color-hover);\n }\n :host([wrapped]) code>div>div{\n white-space: pre-wrap;\n }\n :host([unnamed]) #code-name{\n display:none;\n }\n .${e}-box-tools{\n >*{\n font-size:14px;\n display:inline-flex;\n align-items:center;\n justify-content:center;\n height:2em;\n line-height:2em;\n aspect-ratio:1/1;\n margin-inline-end:8px;\n transition:all 200ms ease;\n border-radius:6px;\n &:hover{\n cursor:pointer;\n background-color:rgba(0,0,0,.04);\n }\n }\n [rep=icon]{\n display:inline-flex;\n align-items:center;\n justify-content:center;\n }\n }\n [disabled]{\n pointer-event:none;\n }\n </style>\n <style id="dynamic-styles"></style>\n <style id="theme-styles"></style>\n <div id="code-header"><span id="code-name">${this.alias}</span><div id="code-tools"></div></div>\n <div id="code-body">\n <pre><code id="highlight"></code></pre>\n </div>\n `,this.baseStylesEl=getEl("#base-styles",this.shadowRoot),this.themeStylesEl=getEl("#theme-styles",this.shadowRoot),this.dynamicStylesEl=getEl("#dynamic-styles",this.shadowRoot),this.headerEl=getEl("#code-header",this.shadowRoot),this.codeNameEl=getEl("#code-name",this.shadowRoot),this.codeToolsEl=getEl("#code-tools",this.shadowRoot),this.codeBodyEl=getEl("#code-body",this.shadowRoot),this.highlightEl=getEl("#highlight",this.shadowRoot),this.codeBodyEl.addEventListener("scroll",()=>{let e=this.codeBodyEl.scrollTop+this.codeBodyEl.clientHeight<this.codeBodyEl.scrollHeight;this.autoScroll=!e})}static register(e,t){this.languages.set(e,{...t})}static addTools(e){Coax.tools=e}mountTools(e){requestAnimationFrame(()=>{this.codeToolsEl.innerHTML="";let t=e.map(e=>(e.action=e.action.bind(this),e));this.codeToolsEl.appendChild(createTools(t))})}connectedCallback(){this.render()}static get observedAttributes(){return["lang","height","max-height","tools","speed"]}attributeChangedCallback(e,t,n){if(t!==n&&this.canListen&&("height"!==e&&"max-height"!==e||this.updateStyleByRegExp(e,n),"speed"===e&&(this.speed=~~!!n),"lang"===e&&(this.lang=n,this.render()),"tools"===e)){n||(this.codeToolsEl.innerHTML="");const e=parseClasses(n),t=Coax.tools.filter(t=>e.includes(t.name));if(!t.length)return;this.mountTools(t)}}updateStyleByRegExp(e,t){const n=new RegExp(`;\\n\\s*${e}:\\s*[^;]+;`,"g");this.baseStylesEl.textContent=this.baseStylesEl.textContent.replace(n,`;\n${e}: ${t};`)}getCssPrefix(e){return(e?.cssPrefix||this.lang).replace(/[^a-zA-Z0-9_-]/g,"\\$&")}getHighLightString(t,n){if(!(n=n||Coax.languages.get(this.lang)))return t;const i=this.getCssPrefix(n),r=new RegExp(n.rules.map(e=>`(${e.pattern.source})`).join("|"),"g");return t.replace(r,(t,...r)=>{const a=r.findIndex(e=>void 0!==e);return-1!==a&&n.rules[a]?`<span class="${e}-${i}-${n.rules[a].token}">${t}</span>`:t})}createLineWrap(e,t){let n=0;if(null==e&&null==t)n=this.highlightEl.children.length;else{n=(t||this.highlightEl.children.length)+e}return createEl("div",{"data-index":n},"<div></div>")}getLineToFillHighLight(e,t,n){n=n||Coax.languages.get(this.lang);let i=this.getHighLightString(t,n);e.innerHTML=i}async highlight(e=this.source){const t=Coax.languages.get(this.lang),n=this.highlightEl.children.length,i=e?e.split("\n"):[],r=this.hasAttribute("speed"),a=this.hasAttribute("sanitized");if(this.updateName(t),!i.length)return!0;for(let[e,o]of i.entries()){if(!o.trim()&&a)continue;const i=this.createLineWrap(e,n),l=i.lastElementChild;i.completed=!0,r?(this.highlightEl.appendChild(i),await typeWriter(o,{speed:this.speed,onDuringType:(e,t)=>{l.innerHTML=t}}),this.getLineToFillHighLight(l,o,t)):(this.getLineToFillHighLight(l,o,t),this.highlightEl.appendChild(i))}return this.autoScrollCode(),!0}autoScrollCode(){this.autoScroll&&(this.codeBodyEl.scrollTop=this.codeBodyEl.scrollHeight)}injectThemeStyles(){const t=Coax.languages.get(this.lang);if(!t)return;let n=this.getCssPrefix(t),i=t.rules.map(t=>`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token}${t.light?","+t.light:""});}`).join("\n"),r="",a="";r+=':host([scheme="dark"]){',r+=t.rules.map(t=>"\n "+(t.light?`\n .${e}-${n}-${t.token} {color: var(--${e}-${n}-${t.token},${t.dark});}`:"")).join("\n"),r+="}",a="@media (prefers-color-scheme: dark){\n :host{\n ",a+=t.rules.map(t=>`\n ${t.light?`\n .${e}-${n}-${t.token} { color: var(--${e}-${n}-${t.token},${t.dark}); }`:""} `).join("\n"),a+="}",this.dynamicStylesEl.textContent=i+r+a,t?.themeStyles&&(this.themeStylesEl.textContent=t.themeStyles)}updateName(e){this.hasAttribute("unnamed")||(e?(this.alias=e.alias||this.lang,this.codeNameEl.innerHTML=this.alias):this.codeNameEl.innerHTML="Plain Text")}trimLineString(e){return e.startsWith("\n")&&(e=e.substring(1)),e.endsWith("\n")&&(e=e.slice(0,-1)),e}render(){this._renderQueued||(this._renderQueued=!0,requestAnimationFrame(async()=>{this.highlightEl.innerHTML="",this.injectThemeStyles(),await this.highlight(),this._renderQueued=!1}))}clear(){this.highlightEl.innerHTML=this.source=this.lineString=""}async replace(e){e=escapeHtmlChars(e),this.source=trimEmptyLines(e),this._renderQueued||(this.highlightEl.innerHTML="",await this.highlight())}async append(e){e=escapeHtmlChars(e),this.source+=`\n${e}`,await this.highlight(e)}getLastLine(){const e=this.highlightEl.lastElementChild,t=!e||this.highlightEl.lastElementChild?.completed?this.createLineWrap():e;return{lineWrap:t,codeWrap:t.lastElementChild}}close(){const e=this.highlightEl.lastElementChild;e&&(e.completed=!0,this.lastLineString=this.lineString,this.getLineToFillHighLight(e?.lastElementChild,this.lineString),this.lineString="")}open(){const e=this.highlightEl.lastElementChild;e&&(e.completed=!1,(e?.lastElementChild).textContent=this.lineString=this.lastLineString)}stream(e,t=!1){e=escapeHtmlChars(e);const{lineWrap:n,codeWrap:i}=this.getLastLine(),r=e.startsWith("\n")||e.endsWith("\n");this.highlightEl.appendChild(n),this.source+=e,this.lineString+=r?this.trimLineString(e):e,t||r?this.close():i.innerHTML+=e,this.autoScrollCode()}}return Coax.register("css",{alias:"CSS",rules:[{token:"comment",pattern:/\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"value",pattern:/(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/,light:"#032f62",dark:"#a5d6ff"},{token:"func",pattern:/[a-z-]+\(?=/,light:"#e36209",dark:"#ffa657"},{token:"property",pattern:/[a-z-]+(?=\s*:)/,light:"#005cc5",dark:"#79c0ff"},{token:"selector",pattern:/[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i,light:"#22863a",dark:"#7ee787"},{token:"unit",pattern:/(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/,light:"#d73a49",dark:"#ff7b72"},{token:"number",pattern:/\b\d+(\.\d+)?\b/,light:"#005cc5",dark:"#79c0ff"},{token:"punct",pattern:/[{}();:]/,light:"#24292e",dark:"#c9d1d9"}]}),Coax.register("html",{alias:"HTML",rules:[{token:"comment",pattern:/&lt;!--[\s\S]*?--&gt;/,light:"#999999",dark:"#6e7681"},{token:"doctype",pattern:/&lt;!DOCTYPE[\s\S]*?&gt;/i,light:"#6a737d",dark:"#8b949e"},{token:"tag",pattern:/&lt;\/?[a-zA-Z0-9]+/,light:"#22863a",dark:"#7ee787"},{token:"attr",pattern:/[a-zA-Z-]+(?=\s*=\s*)/,light:"#6f42c1",dark:"#d2a8ff"},{token:"string",pattern:/(['"])(?:\\.|[^\\])*?\1/,light:"#032f62",dark:"#a5d6ff"},{token:"bracket",pattern:/\/?&gt;/,light:"#24292e",dark:"#c9d1d9"}]}),Coax.register("js",{alias:"Javascript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"keyword",pattern:/\b(async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|new|return|super|switch|this|throw|try|typeof|var|while|with|yield|let|static)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise|Number|String|Boolean)\b/,light:"#e36209",dark:"#ffa657"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/[+\-*/%=<>!&|^~]+/,light:"#069598",dark:"#56b6c2"}]}),Coax.register("ts",{alias:"Typescript",rules:[{token:"comment",pattern:/\/\/[^\n]*|\/\*[\s\S]*?\*\//,light:"#6a737d",dark:"#8b949e"},{token:"string",pattern:/(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/,light:"#032f62",dark:"#98c379"},{token:"decorator",pattern:/@[a-zA-Z_]\w*/,light:"#953800",dark:"#ffa657"},{token:"keyword",pattern:/\b(abstract|as|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|package|private|protected|public|readonly|return|set|static|super|switch|this|throw|try|type|typeof|var|while|with|yield)\b/,light:"#d73a49",dark:"#ff7b72"},{token:"builtin",pattern:/\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|true|false|console|window|document)\b/,light:"#e36209",dark:"#ffa657"},{token:"type",pattern:/\b[A-Z]\w*\b/,light:"#005cc5",dark:"#79c0ff"},{token:"number",pattern:/\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/,light:"#005cc5",dark:"#79c0ff"},{token:"func",pattern:/\b[a-zA-Z_]\w*(?=\s*\()/,light:"#6f42c1",dark:"#d2a8ff"},{token:"op",pattern:/(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/,light:"#089ba6",dark:"#79c0ff"}]}),Coax.register("md",{alias:"Markdown",rules:[{token:"comment",pattern:/<!--[\s\S]*?-->/,light:"#6a737d",dark:"#8b949e"},{token:"heading",pattern:/(^|\n)(#{1,6})\s*(.+)/,light:"#e36209",dark:"#ffa657"},{token:"bold",pattern:/\*\*([^*]+)\*\*|__([^_]+)__/g,light:"#d73a49",dark:"#ff7b72"},{token:"italic",pattern:/\*([^*]+)\*|_([^_]+)_/g,light:"#032f62",dark:"#a5d6ff"},{token:"link",pattern:/\[([^\]]+)\]\(([^)]+)\)/g,light:"#0288d1",dark:"#80c0ff"},{token:"inline-code",pattern:/`([^`]+)`/g,light:"#032f62",dark:"#98c379"},{token:"code-block",pattern:/```([^\n]+)\n([\s\S]*?)```/g,light:"#24292e",dark:"#c9d1d9"},{token:"list-item",pattern:/(^|\n)([-*])\s+(.+)/g,light:"#5c6e7c",dark:"#8b949e"},{token:"quote",pattern:/(^|\n)>[ \t]*(.+)/g,light:"#6f42c1",dark:"#d2a8ff"},{token:"image",pattern:/!\[([^\]]+)\]\(([^)]+)\)/g,light:"#d73a49",dark:"#ff7b72"},{token:"hr",pattern:/^(---|___|\*\*\*)\s*$/gm,light:"#24292e",dark:"#c9d1d9"},{token:"strikethrough",pattern:/~~([^~]+)~~/g,light:"#e36209",dark:"#ffa657"},{token:"table",pattern:/\|([^\|]+)\|([^\|]+)\|/g,light:"#5c6e7c",dark:"#8b949e"}]}),Coax.addTools([t]),customElements.define(`${e}-code`,Coax),Coax});
@@ -4,11 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Coax 代码高亮插件</title>
8
- <style>
9
- /* 白天模式变量 */
10
- :root {}
11
- </style>
7
+ <title>Coax - 使用append方法在末尾追加新代码高亮渲染</title>
12
8
 
13
9
  </head>
14
10
 
@@ -4,11 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Coax 代码高亮插件</title>
8
- <style>
9
- /* 白天模式变量 */
10
- :root {}
11
- </style>
7
+ <title>Coax - 渲染css代码</title>
12
8
 
13
9
  </head>
14
10
 
@@ -4,7 +4,7 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>DeepSeek Stream Demo</title>
7
+ <title>Coax - deepseek 真实流式输出代码</title>
8
8
  <style>
9
9
  #output {
10
10
  font-family: monospace;
@@ -4,23 +4,12 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Coax 代码高亮插件</title>
8
- <style>
9
- /* 白天模式变量 */
10
- :root {
11
- --ax-html-comment: #6a737d;
12
- --ax-html-doctype: #005cc5;
13
- --ax-html-tag: #22863a;
14
- --ax-html-attr: #6f42c1;
15
- --ax-html-string: #032f62;
16
- --ax-html-bracket: #24292e;
17
- }
18
- </style>
7
+ <title>Coax - 渲染html代码</title>
19
8
 
20
9
  </head>
21
10
 
22
11
  <body>
23
- <ax-code lang="html">
12
+ <ax-code lang="html" indexed>
24
13
  <code>
25
14
  &lt;!---->
26
15
  &lt;!DOCTYPE html>