@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.cjs.js +72 -35
- package/dist/coax.cjs.min.js +3 -3
- package/dist/coax.esm.js +72 -35
- package/dist/coax.esm.min.js +3 -3
- package/dist/coax.umd.js +72 -35
- package/dist/coax.umd.min.js +3 -3
- package/examples/{append-highlight.html → append.html} +1 -5
- package/examples/{css-highlight.html → css.html} +1 -5
- package/examples/{deepseek-highlight.html → deepseek.html} +1 -1
- package/examples/{html-highlight.html → html.html} +2 -13
- package/examples/index.html +214 -0
- package/examples/js.html +41 -0
- package/examples/{md-highlight.html → md.html} +1 -12
- package/examples/{theme-highlight.html → module.html} +1 -5
- package/examples/{plain-highlight.html → plain.html} +1 -5
- package/examples/{replace-highlight.html → replace.html} +1 -6
- package/examples/{stream-highlight.html → steam.html} +10 -16
- package/examples/{color-selector.html → theme.html} +3 -6
- package/examples/{js-highlight.html → tools.html} +2 -10
- package/examples/{ts-highlight.html → ts.html} +1 -20
- package/examples/typewriter.html +41 -0
- package/package.json +2 -2
- package/src/Coax.js +1 -1
- package/src/Coax.ts +1 -1
- package/src/components/Coax.js +54 -34
- package/src/components/Coax.ts +63 -36
- package/src/modules.js +1 -1
- package/src/modules.ts +1 -1
- package/examples/.htaccess +0 -0
- package/examples/nginx.htaccess +0 -0
package/dist/coax.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2026-1-
|
|
3
|
+
* @since Last modified: 2026-1-15 19:21:59
|
|
4
4
|
* @name Coax event management system.
|
|
5
|
-
* @version 0.0.
|
|
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, '&') // Replace '&' with '&'
|
|
452
|
+
.replace(/</g, '<') // Replace '<' with '<'
|
|
453
|
+
.replace(/>/g, '>') // Replace '>' with '>'
|
|
454
|
+
.replace(/"/g, '"') // Replace '"' with '"'
|
|
455
|
+
.replace(/'/g, '''); // Replace "'" with '''
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
715
|
+
dataIndex = this.highlightEl.children.length;
|
|
696
716
|
}
|
|
697
717
|
else {
|
|
698
|
-
const start = startIndex || this.
|
|
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
|
-
|
|
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.
|
|
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() &&
|
|
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 (
|
|
730
|
-
this.
|
|
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.
|
|
758
|
+
this.getLineToFillHighLight(codeWrap, lineString, config);
|
|
739
759
|
}
|
|
740
760
|
else {
|
|
741
761
|
//直接打出
|
|
742
|
-
this.
|
|
762
|
+
this.getLineToFillHighLight(codeWrap, lineString, config);
|
|
743
763
|
//
|
|
744
|
-
this.
|
|
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(
|
|
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.
|
|
838
|
+
this.highlightEl.innerHTML = '';
|
|
809
839
|
this.injectThemeStyles();
|
|
810
840
|
//一次性渲染
|
|
811
|
-
await this.highlight(
|
|
841
|
+
await this.highlight();
|
|
812
842
|
this._renderQueued = false;
|
|
813
843
|
});
|
|
814
844
|
}
|
|
815
845
|
|
|
816
846
|
clear() {
|
|
817
|
-
this.
|
|
847
|
+
this.highlightEl.innerHTML = this.source = this.lineString = '';
|
|
818
848
|
}
|
|
819
849
|
|
|
820
850
|
async replace(newCode) {
|
|
821
|
-
|
|
822
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
884
|
+
this.getLineToFillHighLight(lineWrap?.lastElementChild, this.lineString);
|
|
849
885
|
//一行结束,清空临时行文本
|
|
850
886
|
this.lineString = '';
|
|
851
887
|
}
|
|
852
888
|
|
|
853
889
|
open() {
|
|
854
|
-
const lineWrap = this.
|
|
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
|
-
|
|
864
|
-
this.
|
|
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 ||
|
|
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();
|
package/dist/coax.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2026-1-
|
|
2
|
+
* @since Last modified: 2026-1-15 19:21:59
|
|
3
3
|
* @name Coax event management system.
|
|
4
|
-
* @version 0.0.
|
|
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:/<!--[\s\S]*?-->/,light:"#999999",dark:"#6e7681"},{token:"doctype",pattern:/<!DOCTYPE[\s\S]*?>/i,light:"#6a737d",dark:"#8b949e"},{token:"tag",pattern:/<\/?[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:/\/?>/,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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"):"";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:/<!--[\s\S]*?-->/,light:"#999999",dark:"#6e7681"},{token:"doctype",pattern:/<!DOCTYPE[\s\S]*?>/i,light:"#6a737d",dark:"#8b949e"},{token:"tag",pattern:/<\/?[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:/\/?>/,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,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
|
|
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
|
<!---->
|
|
26
15
|
<!DOCTYPE html>
|