@codady/coax 0.0.2 → 0.0.3
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 +421 -257
- package/dist/coax.cjs.min.js +3 -3
- package/dist/coax.esm.js +415 -257
- package/dist/coax.esm.min.js +3 -3
- package/dist/coax.umd.js +435 -249
- package/dist/coax.umd.min.js +3 -3
- package/examples/.htaccess +0 -0
- package/examples/append-highlight.html +82 -0
- package/examples/color-selector.html +412 -0
- package/examples/deepseek-highlight.html +91 -0
- package/examples/js-highlight.html +1 -1
- package/examples/md-highlight.html +60 -0
- package/examples/nginx.htaccess +0 -0
- package/examples/replace-highlight.html +69 -0
- package/examples/stream-highlight.html +64 -0
- package/examples/theme-highlight.html +69 -0
- package/package.json +3 -3
- package/rollup.config.js +3 -3
- package/src/Coax.js +26 -414
- package/src/Coax.ts +29 -443
- package/src/components/CoaxElem.js +457 -0
- package/src/components/CoaxElem.ts +488 -0
- package/src/modules.js +12 -0
- package/src/modules.ts +23 -0
- package/src/rules/css.js +11 -0
- package/src/rules/css.ts +11 -0
- package/src/rules/html.js +13 -0
- package/src/rules/html.ts +13 -0
- package/src/rules/javascript.js +10 -0
- package/src/rules/javascript.ts +10 -0
- package/src/rules/markdown.js +29 -0
- package/src/rules/markdown.ts +41 -0
- package/src/rules/ruleCss - /345/211/257/346/234/254.js" +10 -0
- package/src/rules/ruleHTML - /345/211/257/346/234/254.js" +12 -0
- package/src/rules/ruleJs - /345/211/257/346/234/254.js" +10 -0
- package/src/rules/ruleTs - /345/211/257/346/234/254.js" +12 -0
- package/src/rules/typescript.js +12 -0
- package/src/rules/typescript.ts +12 -0
- package/src/tools/copy.js +26 -0
- package/src/tools/copy.ts +29 -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-12 9:47:5
|
|
4
4
|
* @name Coax event management system.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.3
|
|
6
6
|
* @author AXUI development team <3217728223@qq.com>
|
|
7
7
|
* @description Coax is a custom web component that enables syntax highlighting for various programming languages inside your HTML documents.
|
|
8
8
|
* @see {@link https://coax.axui.cn|Official website}
|
|
@@ -14,10 +14,80 @@
|
|
|
14
14
|
* @license MIT license
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
(function (factory) {
|
|
17
|
+
(function (global, factory) {
|
|
18
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
18
19
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
19
|
-
factory();
|
|
20
|
-
})((function () { 'use strict';
|
|
20
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.coax = factory());
|
|
21
|
+
})(this, (function () { 'use strict';
|
|
22
|
+
|
|
23
|
+
const NAMESPACE = 'ax';
|
|
24
|
+
|
|
25
|
+
const typeWriter = (text, options) => {
|
|
26
|
+
const speed = options.speed || 100; // Set typing speed (default to 100ms per character)
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
// Callback before typing starts
|
|
29
|
+
options?.onBeforeType?.(text);
|
|
30
|
+
let index = 0;
|
|
31
|
+
// Timer to type the text character by character at the given speed
|
|
32
|
+
const timer = setInterval(() => {
|
|
33
|
+
if (index < text.length) {
|
|
34
|
+
const char = text.charAt(index); // Get the character at the current index
|
|
35
|
+
const typedText = text.substring(0, index + 1); // The text typed so far
|
|
36
|
+
// Callback during typing each character
|
|
37
|
+
options?.onDuringType?.(char, typedText);
|
|
38
|
+
index++;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Clear the timer once typing is complete
|
|
42
|
+
clearInterval(timer);
|
|
43
|
+
// Resolve the Promise when typing is complete
|
|
44
|
+
resolve(text);
|
|
45
|
+
// Callback after typing is finished
|
|
46
|
+
options?.onAfterType?.(text);
|
|
47
|
+
}
|
|
48
|
+
}, speed);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const COMMA$1 = ',';
|
|
53
|
+
|
|
54
|
+
const SPACE$1 = ' ';
|
|
55
|
+
|
|
56
|
+
const trim$1 = (str, placement = 'compress') => {
|
|
57
|
+
if (typeof str !== 'string') {
|
|
58
|
+
console.warn('Expected a string input');
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
switch (placement) {
|
|
62
|
+
case 'start':
|
|
63
|
+
return str.trimStart();
|
|
64
|
+
case 'end':
|
|
65
|
+
return str.trimEnd();
|
|
66
|
+
case 'both':
|
|
67
|
+
return str.trim();
|
|
68
|
+
case 'global':
|
|
69
|
+
return str.replace(/[\s\r\n]+/g, '');
|
|
70
|
+
default:
|
|
71
|
+
return str.trim().replace(/[\s\r\n]+/g, ' '); // Default behavior, trims both ends and replaces inner spaces
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const parseClasses$1 = (data) => {
|
|
76
|
+
let separator, result = [];
|
|
77
|
+
if (Array.isArray(data)) {
|
|
78
|
+
// If data is already an array, filter out invalid values
|
|
79
|
+
result = data.filter((k) => k && typeof k === 'string');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Trim the input string and handle multiple spaces
|
|
83
|
+
data = trim$1(data);
|
|
84
|
+
// Use comma as the separator if present, otherwise use space
|
|
85
|
+
separator = data.includes(COMMA$1) ? COMMA$1 : SPACE$1;
|
|
86
|
+
result = data.split(separator);
|
|
87
|
+
}
|
|
88
|
+
// Trim each item globally and filter out any empty strings
|
|
89
|
+
return result.map((k) => trim$1(k, 'global')).filter(Boolean);
|
|
90
|
+
};
|
|
21
91
|
|
|
22
92
|
const getDataType = (obj) => {
|
|
23
93
|
let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
|
|
@@ -161,48 +231,6 @@
|
|
|
161
231
|
|
|
162
232
|
const ALIAS = 'rep';
|
|
163
233
|
|
|
164
|
-
const NAMESPACE = 'ax';
|
|
165
|
-
|
|
166
|
-
const COMMA$1 = ',';
|
|
167
|
-
|
|
168
|
-
const SPACE$1 = ' ';
|
|
169
|
-
|
|
170
|
-
const trim$1 = (str, placement = '') => {
|
|
171
|
-
if (typeof str !== 'string') {
|
|
172
|
-
console.warn('Expected a string input');
|
|
173
|
-
return '';
|
|
174
|
-
}
|
|
175
|
-
switch (placement) {
|
|
176
|
-
case 'start':
|
|
177
|
-
return str.trimStart();
|
|
178
|
-
case 'end':
|
|
179
|
-
return str.trimEnd();
|
|
180
|
-
case 'both':
|
|
181
|
-
return str.trim();
|
|
182
|
-
case 'global':
|
|
183
|
-
return str.replace(/[\s\r\n]+/g, '');
|
|
184
|
-
default:
|
|
185
|
-
return str.trim().replace(/[\s\r\n]+/g, ' '); // Default behavior, trims both ends and replaces inner spaces
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const parseClasses$1 = (data) => {
|
|
190
|
-
let separator, result = [];
|
|
191
|
-
if (Array.isArray(data)) {
|
|
192
|
-
// If data is already an array, filter out invalid values
|
|
193
|
-
result = data.filter((k) => k && typeof k === 'string');
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
// Trim the input string and handle multiple spaces
|
|
197
|
-
data = trim$1(data);
|
|
198
|
-
// Use comma as the separator if present, otherwise use space
|
|
199
|
-
separator = data.includes(COMMA$1) ? COMMA$1 : SPACE$1;
|
|
200
|
-
result = data.split(separator);
|
|
201
|
-
}
|
|
202
|
-
// Trim each item globally and filter out any empty strings
|
|
203
|
-
return result.map((k) => trim$1(k, 'global')).filter(Boolean);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
234
|
const addClasses = (target, classes, intercept) => {
|
|
207
235
|
const el = getEl(target), arr = parseClasses$1(classes);
|
|
208
236
|
if (!el || arr.length === 0) {
|
|
@@ -244,72 +272,7 @@
|
|
|
244
272
|
return toolsEl;
|
|
245
273
|
};
|
|
246
274
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const SPACE = ' ';
|
|
250
|
-
|
|
251
|
-
const trim = (str, placement = '') => {
|
|
252
|
-
if (typeof str !== 'string') {
|
|
253
|
-
console.warn('Expected a string input');
|
|
254
|
-
return '';
|
|
255
|
-
}
|
|
256
|
-
switch (placement) {
|
|
257
|
-
case 'start':
|
|
258
|
-
return str.trimStart();
|
|
259
|
-
case 'end':
|
|
260
|
-
return str.trimEnd();
|
|
261
|
-
case 'both':
|
|
262
|
-
return str.trim();
|
|
263
|
-
case 'global':
|
|
264
|
-
return str.replace(/[\s\r\n]+/g, '');
|
|
265
|
-
default:
|
|
266
|
-
return str.trim().replace(/[\s\r\n]+/g, ' '); // Default behavior, trims both ends and replaces inner spaces
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const parseClasses = (data) => {
|
|
271
|
-
let separator, result = [];
|
|
272
|
-
if (Array.isArray(data)) {
|
|
273
|
-
// If data is already an array, filter out invalid values
|
|
274
|
-
result = data.filter((k) => k && typeof k === 'string');
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
// Trim the input string and handle multiple spaces
|
|
278
|
-
data = trim(data);
|
|
279
|
-
// Use comma as the separator if present, otherwise use space
|
|
280
|
-
separator = data.includes(COMMA) ? COMMA : SPACE;
|
|
281
|
-
result = data.split(separator);
|
|
282
|
-
}
|
|
283
|
-
// Trim each item globally and filter out any empty strings
|
|
284
|
-
return result.map((k) => trim(k, 'global')).filter(Boolean);
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
const rtlStyle = (name = '') => `
|
|
288
|
-
<style>
|
|
289
|
-
:where([dir="rtl"]) .icax-${name},
|
|
290
|
-
:where(:dir(rtl)) .icax-${name} {
|
|
291
|
-
transform: scaleX(-1);
|
|
292
|
-
transform-origin: center;
|
|
293
|
-
}
|
|
294
|
-
</style>
|
|
295
|
-
`;
|
|
296
|
-
|
|
297
|
-
const wrap = (content, fun, isRtl = false, options) => {
|
|
298
|
-
const size = options?.size || '1em', color = options?.color || 'currentColor', thickness = options?.thickness || 2, classes = options?.classes ? parseClasses(options.classes).join(' ') : '',
|
|
299
|
-
// 得到 "icax-left"
|
|
300
|
-
origName = fun.name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
301
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${color}"
|
|
302
|
-
stroke-width="${thickness}" stroke-linecap="round" stroke-linejoin="round" class="${origName} ${classes}">
|
|
303
|
-
${isRtl ? rtlStyle(origName.split('-')[1]) : ''}
|
|
304
|
-
${content}
|
|
305
|
-
</svg>`;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
const icaxCopy = (options) => 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, false, options);
|
|
309
|
-
|
|
310
|
-
const icaxCheck = (options) => wrap(`<polyline points="20 6 9 17 4 12"></polyline>`, icaxCheck, false, options);
|
|
311
|
-
|
|
312
|
-
class Coax extends HTMLElement {
|
|
275
|
+
class CoaxElem extends HTMLElement {
|
|
313
276
|
// A static Map to hold the configuration for different languages
|
|
314
277
|
static languages = new Map();
|
|
315
278
|
static tools = [];
|
|
@@ -320,9 +283,13 @@
|
|
|
320
283
|
dynamicStylesEl;
|
|
321
284
|
highlightedCodeEl;
|
|
322
285
|
headerEl;
|
|
323
|
-
|
|
324
|
-
|
|
286
|
+
codeNameEl;
|
|
287
|
+
codeToolsEl;
|
|
288
|
+
codeBodyEl;
|
|
325
289
|
alias;
|
|
290
|
+
lineString;
|
|
291
|
+
speed;
|
|
292
|
+
autoScroll;
|
|
326
293
|
constructor() {
|
|
327
294
|
super();
|
|
328
295
|
// Attach a Shadow DOM to the custom element
|
|
@@ -331,6 +298,9 @@
|
|
|
331
298
|
this.source = this.textContent?.replace(/^\s*\n|\n\s*$/g, '') || '';
|
|
332
299
|
this.lang = 'plain';
|
|
333
300
|
this.alias = 'Plain Text';
|
|
301
|
+
this.lineString = '';
|
|
302
|
+
this.speed = 5;
|
|
303
|
+
this.autoScroll = true;
|
|
334
304
|
// 1. 初始化基础骨架
|
|
335
305
|
this.shadowRoot.innerHTML = `
|
|
336
306
|
<style id="base-styles">
|
|
@@ -348,16 +318,16 @@
|
|
|
348
318
|
--border-color:rgb(224, 224, 224);
|
|
349
319
|
--color-code:rgb(51, 51, 51);
|
|
350
320
|
--color-index:rgb(153, 153, 153);
|
|
351
|
-
--color-stripe:
|
|
352
|
-
--color-hover:
|
|
321
|
+
--color-stripe:rgba(0,0,0,0.04);
|
|
322
|
+
--color-hover:rgba(0,0,0,0.06);
|
|
353
323
|
}
|
|
354
324
|
:host([scheme="dark"]){
|
|
355
325
|
--background: #282c34;
|
|
356
326
|
--border-color: transparent;
|
|
357
327
|
--color-code: #abb2bf;
|
|
358
328
|
--color-index:rgb(153, 153, 153);
|
|
359
|
-
--color-stripe:
|
|
360
|
-
--color-hover:
|
|
329
|
+
--color-stripe:rgba(255,255,255,0.04);
|
|
330
|
+
--color-hover:rgba(255,255,255,0.06);
|
|
361
331
|
}
|
|
362
332
|
@media (prefers-color-scheme: dark) {
|
|
363
333
|
:host{
|
|
@@ -365,8 +335,8 @@
|
|
|
365
335
|
--border-color: transparent;
|
|
366
336
|
--color-code: #abb2bf;
|
|
367
337
|
--color-index:rgb(153, 153, 153);
|
|
368
|
-
--color-stripe:
|
|
369
|
-
--color-hover:
|
|
338
|
+
--color-stripe:rgba(255,255,255,0.04);
|
|
339
|
+
--color-hover:rgba(255,255,255,0.06);
|
|
370
340
|
}
|
|
371
341
|
}
|
|
372
342
|
:host {
|
|
@@ -376,7 +346,6 @@
|
|
|
376
346
|
background:var(--${NAMESPACE}-code-background-color,var(--background));
|
|
377
347
|
color:var(--${NAMESPACE}-code-color,var(--color-code));
|
|
378
348
|
border:var(--${NAMESPACE}-code-border-width,var(--border-width)) var(--${NAMESPACE}-code-border-style,var(--border-style)) var(--${NAMESPACE}-code-border-color,var(--border-color));
|
|
379
|
-
overflow:auto;
|
|
380
349
|
transition: border-color 0.3s ease,color 0.3s ease;
|
|
381
350
|
border-radius: var(--${NAMESPACE}-code-radius,var(--radius));
|
|
382
351
|
}
|
|
@@ -393,6 +362,7 @@
|
|
|
393
362
|
padding: var(--${NAMESPACE}-code-padding,var(--padding)) 0;
|
|
394
363
|
height:var(--${NAMESPACE}-code-height,var(--height));
|
|
395
364
|
max-height:var(--${NAMESPACE}-code-max-height,var(--max-height));
|
|
365
|
+
overflow:auto;
|
|
396
366
|
}
|
|
397
367
|
pre,code{
|
|
398
368
|
font-family:"Consolas", "Monaco", "Andale Mono", "Ubuntu Mono", "monospace";
|
|
@@ -408,6 +378,9 @@
|
|
|
408
378
|
flex:auto;
|
|
409
379
|
}
|
|
410
380
|
}
|
|
381
|
+
code>div>div:empty:before{
|
|
382
|
+
content:' ';
|
|
383
|
+
}
|
|
411
384
|
:host([indexed]) code>div:before{
|
|
412
385
|
display:inline-flex;
|
|
413
386
|
color:var(--color-index);
|
|
@@ -415,13 +388,13 @@
|
|
|
415
388
|
min-width:var(--${NAMESPACE}-code-index-width,2em);
|
|
416
389
|
margin-inline-end:var(--${NAMESPACE}-code-padding,8px);
|
|
417
390
|
}
|
|
418
|
-
:host([hoverable]) code>div:hover{
|
|
419
|
-
background-color:var(--color-hover);
|
|
420
|
-
}
|
|
421
391
|
:host([striped]) code>div:nth-child(odd){
|
|
422
392
|
background-color:var(--color-stripe);
|
|
423
393
|
}
|
|
424
|
-
:host([
|
|
394
|
+
:host([hoverable]) code>div:hover{
|
|
395
|
+
background-color:var(--color-hover);
|
|
396
|
+
}
|
|
397
|
+
:host([wrapped]) code>div>div{
|
|
425
398
|
white-space: pre-wrap;
|
|
426
399
|
}
|
|
427
400
|
:host([unnamed]) #code-name{
|
|
@@ -466,9 +439,15 @@
|
|
|
466
439
|
this.themeStylesEl = getEl('#theme-styles', this.shadowRoot);
|
|
467
440
|
this.dynamicStylesEl = getEl('#dynamic-styles', this.shadowRoot);
|
|
468
441
|
this.headerEl = getEl('#code-header', this.shadowRoot);
|
|
469
|
-
this.
|
|
470
|
-
this.
|
|
442
|
+
this.codeNameEl = getEl('#code-name', this.shadowRoot);
|
|
443
|
+
this.codeToolsEl = getEl('#code-tools', this.shadowRoot);
|
|
444
|
+
this.codeBodyEl = getEl('#code-body', this.shadowRoot);
|
|
471
445
|
this.highlightedCodeEl = getEl('#highlight-code', this.shadowRoot);
|
|
446
|
+
this.codeBodyEl.addEventListener('scroll', () => {
|
|
447
|
+
let flag = this.codeBodyEl.scrollTop + this.codeBodyEl.clientHeight < this.codeBodyEl.scrollHeight;
|
|
448
|
+
// 检测是否是用户手动滚动
|
|
449
|
+
this.autoScroll = !flag;
|
|
450
|
+
});
|
|
472
451
|
}
|
|
473
452
|
|
|
474
453
|
static register(name, config) {
|
|
@@ -477,17 +456,17 @@
|
|
|
477
456
|
}
|
|
478
457
|
//注册工具箱
|
|
479
458
|
static addTools(items) {
|
|
480
|
-
|
|
459
|
+
CoaxElem.tools = items;
|
|
481
460
|
}
|
|
482
461
|
//加入工具箱
|
|
483
462
|
mountTools(toolItems) {
|
|
484
463
|
requestAnimationFrame(() => {
|
|
485
|
-
this.
|
|
464
|
+
this.codeToolsEl.innerHTML = '';
|
|
486
465
|
let items = toolItems.map(k => {
|
|
487
466
|
k.action = k.action.bind(this);
|
|
488
467
|
return k;
|
|
489
468
|
});
|
|
490
|
-
this.
|
|
469
|
+
this.codeToolsEl.appendChild(createTools(items));
|
|
491
470
|
});
|
|
492
471
|
}
|
|
493
472
|
// Called when the element is connected to the DOM
|
|
@@ -495,7 +474,7 @@
|
|
|
495
474
|
this.render();
|
|
496
475
|
}
|
|
497
476
|
// Observed attributes for changes
|
|
498
|
-
static get observedAttributes() { return ['lang', 'height', 'max-height', 'tools']; }
|
|
477
|
+
static get observedAttributes() { return ['lang', 'height', 'max-height', 'tools', 'speed']; }
|
|
499
478
|
|
|
500
479
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
501
480
|
if (oldVal === newVal)
|
|
@@ -503,19 +482,18 @@
|
|
|
503
482
|
if (name === 'height' || name === 'max-height') {
|
|
504
483
|
this.updateStyleByRegExp(name, newVal);
|
|
505
484
|
}
|
|
506
|
-
|
|
485
|
+
if (name === 'speed') {
|
|
486
|
+
this.speed = ~~(!!newVal);
|
|
487
|
+
}
|
|
488
|
+
if (name === 'lang') {
|
|
507
489
|
//更新当前语言
|
|
508
490
|
this.lang = newVal;
|
|
509
491
|
this.render();
|
|
510
492
|
}
|
|
511
|
-
|
|
512
|
-
this.nameEl.innerHTML = newVal === null ? (this.alias || this.lang) : '';
|
|
513
|
-
this.nameEl.innerHTML = '';
|
|
514
|
-
}
|
|
515
|
-
else if (name === 'tools') {
|
|
493
|
+
if (name === 'tools') {
|
|
516
494
|
if (!newVal)
|
|
517
|
-
this.
|
|
518
|
-
const tools = parseClasses$1(newVal), toolItems =
|
|
495
|
+
this.codeToolsEl.innerHTML = '';
|
|
496
|
+
const tools = parseClasses$1(newVal), toolItems = CoaxElem.tools.filter(k => tools.includes(k.name));
|
|
519
497
|
if (!toolItems.length)
|
|
520
498
|
return;
|
|
521
499
|
this.mountTools(toolItems);
|
|
@@ -532,36 +510,84 @@
|
|
|
532
510
|
getCssPrefix(config) {
|
|
533
511
|
return (config?.cssPrefix || this.lang).replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
534
512
|
}
|
|
513
|
+
getHighLightString(string, config) {
|
|
514
|
+
config = config || CoaxElem.languages.get(this.lang);
|
|
515
|
+
if (!config)
|
|
516
|
+
return string;
|
|
517
|
+
// 如果找到了配置,则进行高亮处理
|
|
518
|
+
const cssPrefix = this.getCssPrefix(config),
|
|
519
|
+
// 获取用于语法高亮的正则表达式
|
|
520
|
+
combinedRegex = new RegExp(config.rules.map((r) => `(${r.pattern.source})`).join('|'), 'g');
|
|
521
|
+
return string.replace(combinedRegex, (match, ...args) => {
|
|
522
|
+
const i = args.findIndex(val => val !== undefined);
|
|
523
|
+
return i !== -1 && config.rules[i] ? `<span class="${NAMESPACE}-${cssPrefix}-${config.rules[i].token}">${match}</span>` : match;
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
createLineWrap(index, startIndex) {
|
|
527
|
+
let dataIndex = 0;
|
|
528
|
+
if (index == null && startIndex == null) {
|
|
529
|
+
dataIndex = this.highlightedCodeEl.children.length;
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
const start = startIndex || this.highlightedCodeEl.children.length;
|
|
533
|
+
dataIndex = start + index;
|
|
534
|
+
}
|
|
535
|
+
return createEl('div', { 'data-index': dataIndex }, '<div></div>');
|
|
536
|
+
}
|
|
537
|
+
getLineToFill(codeWrap, line, config) {
|
|
538
|
+
config = config || CoaxElem.languages.get(this.lang);
|
|
539
|
+
let highlightedLine = this.getHighLightString(line, config);
|
|
540
|
+
// 将高亮后的内容填充到 div 中
|
|
541
|
+
codeWrap.innerHTML = highlightedLine;
|
|
542
|
+
}
|
|
543
|
+
;
|
|
535
544
|
|
|
536
|
-
highlight(newCode) {
|
|
537
|
-
const config =
|
|
545
|
+
async highlight(newCode) {
|
|
546
|
+
const config = CoaxElem.languages.get(this.lang), startIndex = this.highlightedCodeEl.children.length,
|
|
538
547
|
// 将新源码按行分割
|
|
539
|
-
newCodeLines = newCode.split('\n')
|
|
548
|
+
newCodeLines = newCode ? newCode.split('\n') : [];
|
|
549
|
+
//更新别名
|
|
550
|
+
this.updateName(config);
|
|
551
|
+
if (!newCodeLines.length)
|
|
552
|
+
return true;
|
|
540
553
|
// 如果没有找到配置,则输出原始代码,并不进行高亮处理
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
554
|
+
for (let [index, lineString] of newCodeLines.entries()) {
|
|
555
|
+
//如果是空行则跳过
|
|
556
|
+
if (!lineString.trim() && this.hasAttribute('sanitized'))
|
|
557
|
+
continue;
|
|
558
|
+
// 创建一个 div 包裹每一行
|
|
559
|
+
const lineWrap = this.createLineWrap(index, startIndex), codeWrap = lineWrap.lastElementChild;
|
|
560
|
+
//标记完成
|
|
561
|
+
this.closeLine(lineWrap);
|
|
562
|
+
if (this.hasAttribute('speed')) {
|
|
563
|
+
this.highlightedCodeEl.appendChild(lineWrap);
|
|
564
|
+
//流式打字
|
|
565
|
+
await typeWriter(lineString, {
|
|
566
|
+
speed: this.speed,
|
|
567
|
+
onDuringType: (char, fullText) => {
|
|
568
|
+
codeWrap.innerHTML = fullText;
|
|
569
|
+
}
|
|
552
570
|
});
|
|
571
|
+
this.getLineToFill(codeWrap, lineString, config);
|
|
553
572
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
573
|
+
else {
|
|
574
|
+
//直接打出
|
|
575
|
+
this.getLineToFill(codeWrap, lineString, config);
|
|
576
|
+
//
|
|
577
|
+
this.highlightedCodeEl.appendChild(lineWrap);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
//滚动到最底部
|
|
581
|
+
this.autoScrollCode();
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
autoScrollCode() {
|
|
585
|
+
if (this.autoScroll) {
|
|
586
|
+
this.codeBodyEl.scrollTop = this.codeBodyEl.scrollHeight;
|
|
587
|
+
}
|
|
562
588
|
}
|
|
563
589
|
injectThemeStyles() {
|
|
564
|
-
const config =
|
|
590
|
+
const config = CoaxElem.languages.get(this.lang);
|
|
565
591
|
if (!config)
|
|
566
592
|
return;
|
|
567
593
|
// Get language name, fallback to 'js' if not provided
|
|
@@ -569,17 +595,17 @@
|
|
|
569
595
|
//Generate dynamic CSS classes for each syntax rule
|
|
570
596
|
// 为 rules 中的每一个 name 生成类似 .hl-name { color: var(--ax-code-name); }
|
|
571
597
|
lightStyles = config.rules.map((rule) => `
|
|
572
|
-
.${NAMESPACE}-${cssPrefix}-${rule.token} { color: var(--${NAMESPACE}-${cssPrefix}-${rule.token}${rule.
|
|
598
|
+
.${NAMESPACE}-${cssPrefix}-${rule.token} { color: var(--${NAMESPACE}-${cssPrefix}-${rule.token}${rule.light ? ',' + rule.light : ''});}`).join('\n'), darkStyles = '', schemeStyles = '';
|
|
573
599
|
darkStyles += `:host([scheme="dark"]){`;
|
|
574
600
|
darkStyles += config.rules.map((rule) => `
|
|
575
|
-
${rule.
|
|
601
|
+
${rule.light ? `
|
|
576
602
|
.${NAMESPACE}-${cssPrefix}-${rule.token} {color: var(--${NAMESPACE}-${cssPrefix}-${rule.token},${rule.dark});}` : ``}`).join('\n');
|
|
577
603
|
darkStyles += `}`;
|
|
578
604
|
schemeStyles = `@media (prefers-color-scheme: dark){
|
|
579
605
|
:host{
|
|
580
606
|
`;
|
|
581
607
|
schemeStyles += config.rules.map((rule) => `
|
|
582
|
-
${rule.
|
|
608
|
+
${rule.light ? `
|
|
583
609
|
.${NAMESPACE}-${cssPrefix}-${rule.token} { color: var(--${NAMESPACE}-${cssPrefix}-${rule.token},${rule.dark}); }` : ``} `).join('\n');
|
|
584
610
|
schemeStyles += `}`;
|
|
585
611
|
// Set the inner HTML of the shadow root, including styles and highlighted code
|
|
@@ -589,123 +615,283 @@
|
|
|
589
615
|
if (config?.themeStyles) {
|
|
590
616
|
this.themeStylesEl.textContent = config.themeStyles;
|
|
591
617
|
}
|
|
592
|
-
//更新别名
|
|
593
|
-
this.updateName(config);
|
|
594
618
|
}
|
|
595
619
|
updateName(config) {
|
|
596
620
|
if (this.hasAttribute('unnamed'))
|
|
597
621
|
return;
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
622
|
+
if (!config) {
|
|
623
|
+
this.codeNameEl.innerHTML = 'Plain Text';
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
//更新别名
|
|
627
|
+
this.alias = config.alias || this.lang;
|
|
628
|
+
this.codeNameEl.innerHTML = this.alias;
|
|
629
|
+
}
|
|
601
630
|
}
|
|
602
631
|
|
|
603
|
-
render() {
|
|
632
|
+
render(code = this.source) {
|
|
604
633
|
//同时多次改变属性,只执行一次
|
|
605
634
|
// 如果已经在队列中,则直接返回
|
|
606
635
|
if (this._renderQueued)
|
|
607
636
|
return;
|
|
608
637
|
this._renderQueued = true;
|
|
609
638
|
// 使用 requestAnimationFrame 将渲染推迟到下一帧
|
|
610
|
-
requestAnimationFrame(() => {
|
|
611
|
-
this.
|
|
612
|
-
//一次性渲染
|
|
613
|
-
this.highlight(this.source);
|
|
639
|
+
requestAnimationFrame(async () => {
|
|
640
|
+
this.clear();
|
|
614
641
|
this.injectThemeStyles();
|
|
642
|
+
//一次性渲染
|
|
643
|
+
await this.highlight(code);
|
|
615
644
|
this._renderQueued = false;
|
|
616
645
|
});
|
|
617
646
|
}
|
|
647
|
+
clear() {
|
|
648
|
+
this.highlightedCodeEl.innerHTML = this.source = this.lineString = '';
|
|
649
|
+
}
|
|
618
650
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
this.
|
|
622
|
-
//清空
|
|
623
|
-
this.highlightedCodeEl.innerHTML = '';
|
|
624
|
-
this.highlight(newCode);
|
|
651
|
+
async replace(newCode) {
|
|
652
|
+
this.clear();
|
|
653
|
+
await this.highlight(newCode);
|
|
625
654
|
}
|
|
626
655
|
|
|
627
|
-
|
|
656
|
+
async append(newCode) {
|
|
628
657
|
// 将新的代码追加到现有代码末尾
|
|
629
658
|
this.source += `\n${newCode}`;
|
|
630
659
|
// 高亮新的部分
|
|
631
|
-
this.highlight(newCode);
|
|
660
|
+
await this.highlight(newCode);
|
|
661
|
+
}
|
|
662
|
+
getActiveCodeWrap() {
|
|
663
|
+
const lastChild = this.highlightedCodeEl.lastElementChild, lastLine = !lastChild || this.highlightedCodeEl.lastElementChild?.completed ?
|
|
664
|
+
this.createLineWrap() : lastChild;
|
|
665
|
+
return {
|
|
666
|
+
lineWrap: lastLine,
|
|
667
|
+
codeWrap: lastLine.lastElementChild
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
closeLine(lineWrap) {
|
|
671
|
+
lineWrap = lineWrap || this.highlightedCodeEl.lastElementChild;
|
|
672
|
+
lineWrap && (lineWrap.completed = true);
|
|
673
|
+
}
|
|
674
|
+
openLine(lineWrap) {
|
|
675
|
+
lineWrap = lineWrap || this.highlightedCodeEl.lastElementChild;
|
|
676
|
+
lineWrap && (lineWrap.completed = false);
|
|
677
|
+
}
|
|
678
|
+
stream(str, forceEnd = false) {
|
|
679
|
+
const { lineWrap, codeWrap } = this.getActiveCodeWrap();
|
|
680
|
+
this.highlightedCodeEl.appendChild(lineWrap);
|
|
681
|
+
//汇集
|
|
682
|
+
this.source += str;
|
|
683
|
+
//如果没有遇到换行符号,也可以强制结束
|
|
684
|
+
forceEnd && this.closeLine(lineWrap);
|
|
685
|
+
if (str.startsWith('\n') || str.startsWith('\r')) {
|
|
686
|
+
//标记完成
|
|
687
|
+
this.closeLine(lineWrap);
|
|
688
|
+
//渲染
|
|
689
|
+
this.getLineToFill(codeWrap, this.lineString);
|
|
690
|
+
//一行结束,清空临时行文本
|
|
691
|
+
this.lineString = '';
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
//插入文本
|
|
695
|
+
codeWrap.innerHTML += str;
|
|
696
|
+
//临时保存行文本
|
|
697
|
+
this.lineString += str;
|
|
698
|
+
}
|
|
699
|
+
//滚动到最底部
|
|
700
|
+
this.autoScrollCode();
|
|
632
701
|
}
|
|
633
702
|
}
|
|
703
|
+
|
|
704
|
+
const html = [
|
|
705
|
+
{ token: 'comment', pattern: /<!--[\s\S]*?-->/, light: '#999999', dark: '#6e7681' },
|
|
706
|
+
{ token: 'doctype', pattern: /<!DOCTYPE[\s\S]*?>/i, light: '#6a737d', dark: '#8b949e' },
|
|
707
|
+
// 匹配标签名: <div, </div
|
|
708
|
+
{ token: 'tag', pattern: /<\/?[a-zA-Z0-9]+/, light: '#22863a', dark: '#7ee787' },
|
|
709
|
+
// 匹配属性名: class=
|
|
710
|
+
{ token: 'attr', pattern: /[a-zA-Z-]+(?=\s*=\s*)/, light: '#6f42c1', dark: '#d2a8ff' },
|
|
711
|
+
// 匹配属性值: "value"
|
|
712
|
+
{ token: 'string', pattern: /(['"])(?:\\.|[^\\])*?\1/, light: '#032f62', dark: '#a5d6ff' },
|
|
713
|
+
// 匹配标签闭合: >, />
|
|
714
|
+
{ token: 'bracket', pattern: /\/?>/, light: '#24292e', dark: '#c9d1d9' }
|
|
715
|
+
];
|
|
716
|
+
|
|
717
|
+
const javascript = [
|
|
718
|
+
{ token: 'comment', pattern: /\/\/[^\n]*|\/\*[\s\S]*?\*\//, light: '#6a737d', dark: '#8b949e' },
|
|
719
|
+
{ token: 'string', pattern: /(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/, light: '#032f62', dark: '#98c379' },
|
|
720
|
+
{ 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' },
|
|
721
|
+
{ token: 'builtin', pattern: /\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise|Number|String|Boolean)\b/, light: '#e36209', dark: '#ffa657' },
|
|
722
|
+
{ token: 'number', pattern: /\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/, light: '#005cc5', dark: '#79c0ff' },
|
|
723
|
+
{ token: 'func', pattern: /\b[a-zA-Z_]\w*(?=\s*\()/, light: '#6f42c1', dark: '#d2a8ff' },
|
|
724
|
+
{ token: 'op', pattern: /[+\-*/%=<>!&|^~]+/, light: '#069598', dark: '#56b6c2' }
|
|
725
|
+
];
|
|
726
|
+
|
|
727
|
+
const markdown = [
|
|
728
|
+
// 注释: 这是 Markdown 中的行内注释
|
|
729
|
+
{ token: 'comment', pattern: /<!--[\s\S]*?-->/, light: '#6a737d', dark: '#8b949e' },
|
|
730
|
+
// 标题: 通过 `#` 来定义标题
|
|
731
|
+
{ token: 'heading', pattern: /(^|\n)(#{1,6})\s*(.+)/, light: '#e36209', dark: '#ffa657' },
|
|
732
|
+
// 粗体: **text** 或 __text__
|
|
733
|
+
{ token: 'bold', pattern: /\*\*([^*]+)\*\*|__([^_]+)__/g, light: '#d73a49', dark: '#ff7b72' },
|
|
734
|
+
// 斜体: *text* 或 _text_
|
|
735
|
+
{ token: 'italic', pattern: /\*([^*]+)\*|_([^_]+)_/g, light: '#032f62', dark: '#a5d6ff' },
|
|
736
|
+
// 链接: [text](url)
|
|
737
|
+
{ token: 'link', pattern: /\[([^\]]+)\]\(([^)]+)\)/g, light: '#0288d1', dark: '#80c0ff' },
|
|
738
|
+
// 行内代码: `code`
|
|
739
|
+
{ token: 'inline-code', pattern: /`([^`]+)`/g, light: '#032f62', dark: '#98c379' },
|
|
740
|
+
// 代码块: ```code```
|
|
741
|
+
{ token: 'code-block', pattern: /```([^\n]+)\n([\s\S]*?)```/g, light: '#24292e', dark: '#c9d1d9' },
|
|
742
|
+
// 列表项: - item 或 * item
|
|
743
|
+
{ token: 'list-item', pattern: /(^|\n)([-*])\s+(.+)/g, light: '#5c6e7c', dark: '#8b949e' },
|
|
744
|
+
// 引用: > text
|
|
745
|
+
{ token: 'quote', pattern: /(^|\n)>[ \t]*(.+)/g, light: '#6f42c1', dark: '#d2a8ff' },
|
|
746
|
+
// 图片: 
|
|
747
|
+
{ token: 'image', pattern: /!\[([^\]]+)\]\(([^)]+)\)/g, light: '#d73a49', dark: '#ff7b72' },
|
|
748
|
+
// 分割线: ---
|
|
749
|
+
{ token: 'hr', pattern: /^(---|___|\*\*\*)\s*$/gm, light: '#24292e', dark: '#c9d1d9' },
|
|
750
|
+
// 强调和删除: ~~text~~
|
|
751
|
+
{ token: 'strikethrough', pattern: /~~([^~]+)~~/g, light: '#e36209', dark: '#ffa657' },
|
|
752
|
+
// 表格: | header1 | header2 |
|
|
753
|
+
{ token: 'table', pattern: /\|([^\|]+)\|([^\|]+)\|/g, light: '#5c6e7c', dark: '#8b949e' }
|
|
754
|
+
];
|
|
755
|
+
|
|
756
|
+
const typescript = [
|
|
757
|
+
{ token: 'comment', pattern: /\/\/[^\n]*|\/\*[\s\S]*?\*\//, light: '#6a737d', dark: '#8b949e' },
|
|
758
|
+
{ token: 'string', pattern: /(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/, light: '#032f62', dark: '#98c379' },
|
|
759
|
+
{ token: 'decorator', pattern: /@[a-zA-Z_]\w*/, light: '#953800', dark: '#ffa657' },
|
|
760
|
+
{ 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' },
|
|
761
|
+
{ token: 'builtin', pattern: /\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|true|false|console|window|document)\b/, light: '#e36209', dark: '#ffa657' },
|
|
762
|
+
{ token: 'type', pattern: /\b[A-Z]\w*\b/, light: '#005cc5', dark: '#79c0ff' },
|
|
763
|
+
{ token: 'number', pattern: /\b(0x[\da-fA-F]+|0b[01]+|\d+(\.\d+)?)\b/, light: '#005cc5', dark: '#79c0ff' },
|
|
764
|
+
{ token: 'func', pattern: /\b[a-zA-Z_]\w*(?=\s*\()/, light: '#6f42c1', dark: '#d2a8ff' },
|
|
765
|
+
{ token: 'op', pattern: /(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/, light: '#089ba6', dark: '#79c0ff' }
|
|
766
|
+
];
|
|
767
|
+
|
|
768
|
+
const COMMA = ',';
|
|
769
|
+
|
|
770
|
+
const SPACE = ' ';
|
|
771
|
+
|
|
772
|
+
const trim = (str, placement = '') => {
|
|
773
|
+
if (typeof str !== 'string') {
|
|
774
|
+
console.warn('Expected a string input');
|
|
775
|
+
return '';
|
|
776
|
+
}
|
|
777
|
+
switch (placement) {
|
|
778
|
+
case 'start':
|
|
779
|
+
return str.trimStart();
|
|
780
|
+
case 'end':
|
|
781
|
+
return str.trimEnd();
|
|
782
|
+
case 'both':
|
|
783
|
+
return str.trim();
|
|
784
|
+
case 'global':
|
|
785
|
+
return str.replace(/[\s\r\n]+/g, '');
|
|
786
|
+
default:
|
|
787
|
+
return str.trim().replace(/[\s\r\n]+/g, ' '); // Default behavior, trims both ends and replaces inner spaces
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const parseClasses = (data) => {
|
|
792
|
+
let separator, result = [];
|
|
793
|
+
if (Array.isArray(data)) {
|
|
794
|
+
// If data is already an array, filter out invalid values
|
|
795
|
+
result = data.filter((k) => k && typeof k === 'string');
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
// Trim the input string and handle multiple spaces
|
|
799
|
+
data = trim(data);
|
|
800
|
+
// Use comma as the separator if present, otherwise use space
|
|
801
|
+
separator = data.includes(COMMA) ? COMMA : SPACE;
|
|
802
|
+
result = data.split(separator);
|
|
803
|
+
}
|
|
804
|
+
// Trim each item globally and filter out any empty strings
|
|
805
|
+
return result.map((k) => trim(k, 'global')).filter(Boolean);
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
const rtlStyle = (name = '') => `
|
|
809
|
+
<style>
|
|
810
|
+
:where([dir="rtl"]) .icax-${name},
|
|
811
|
+
:where(:dir(rtl)) .icax-${name} {
|
|
812
|
+
transform: scaleX(-1);
|
|
813
|
+
transform-origin: center;
|
|
814
|
+
}
|
|
815
|
+
</style>
|
|
816
|
+
`;
|
|
817
|
+
|
|
818
|
+
const wrap = (content, fun, isRtl = false, options) => {
|
|
819
|
+
const size = options?.size || '1em', color = options?.color || 'currentColor', thickness = options?.thickness || 2, classes = options?.classes ? parseClasses(options.classes).join(' ') : '',
|
|
820
|
+
// 得到 "icax-left"
|
|
821
|
+
origName = fun.name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
822
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${color}"
|
|
823
|
+
stroke-width="${thickness}" stroke-linecap="round" stroke-linejoin="round" class="${origName} ${classes}">
|
|
824
|
+
${isRtl ? rtlStyle(origName.split('-')[1]) : ''}
|
|
825
|
+
${content}
|
|
826
|
+
</svg>`;
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
const icaxCheck = (options) => wrap(`<polyline points="20 6 9 17 4 12"></polyline>`, icaxCheck, false, options);
|
|
830
|
+
|
|
831
|
+
const icaxCopy = (options) => 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, false, options);
|
|
832
|
+
|
|
833
|
+
const copy = {
|
|
834
|
+
name: 'copy',
|
|
835
|
+
icon: icaxCopy(),
|
|
836
|
+
action: function (arg) {
|
|
837
|
+
arg.wrapEl.onclick = () => {
|
|
838
|
+
//this只是组件实例
|
|
839
|
+
navigator.clipboard.writeText(this.source)
|
|
840
|
+
.then(() => {
|
|
841
|
+
console.log('Text successfully copied to clipboard');
|
|
842
|
+
arg.iconEl.innerHTML = icaxCheck();
|
|
843
|
+
arg.iconEl.toggleAttribute('disabled', true);
|
|
844
|
+
setTimeout(() => {
|
|
845
|
+
//恢复
|
|
846
|
+
arg.iconEl.removeAttribute('disabled');
|
|
847
|
+
arg.iconEl.innerHTML = icaxCopy();
|
|
848
|
+
}, 2000);
|
|
849
|
+
})
|
|
850
|
+
.catch(err => {
|
|
851
|
+
console.error('Error copying text to clipboard: ', err);
|
|
852
|
+
});
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
const css = [
|
|
858
|
+
{ token: 'comment', pattern: /\/\*[\s\S]*?\*\//, light: '#6a737d', dark: '#8b949e' },
|
|
859
|
+
{ token: 'value', pattern: /(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/, light: '#032f62', dark: '#a5d6ff' },
|
|
860
|
+
{ token: 'func', pattern: /[a-z-]+\(?=/, light: '#e36209', dark: '#ffa657' },
|
|
861
|
+
{ token: 'property', pattern: /[a-z-]+(?=\s*:)/, light: '#005cc5', dark: '#79c0ff' },
|
|
862
|
+
{ token: 'selector', pattern: /[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i, light: '#22863a', dark: '#7ee787' },
|
|
863
|
+
{ token: 'unit', pattern: /(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/, light: '#d73a49', dark: '#ff7b72' },
|
|
864
|
+
{ token: 'number', pattern: /\b\d+(\.\d+)?\b/, light: '#005cc5', dark: '#79c0ff' },
|
|
865
|
+
{ token: 'punct', pattern: /[{}();:]/, light: '#24292e', dark: '#c9d1d9' }
|
|
866
|
+
];
|
|
867
|
+
|
|
868
|
+
const Coax = CoaxElem;
|
|
869
|
+
//注册语言类型
|
|
634
870
|
Coax.register('css', {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
{ token: 'value', pattern: /(?:'|")(?:\\.|[^\\'"\b])*?(?:'|")/, color: '#61afef', dark: '#a5d6ff' },
|
|
638
|
-
{ token: 'func', pattern: /[a-z-]+\(?=/, color: '#e36209', dark: '#ffa657' },
|
|
639
|
-
{ token: 'property', pattern: /[a-z-]+(?=\s*:)/, color: '#005cc5', dark: '#79c0ff' },
|
|
640
|
-
{ token: 'selector', pattern: /[.#a-z0-9, \n\t>:+()_-]+(?=\s*\{)/i, color: '#6f42c1', dark: '#d2a8ff' },
|
|
641
|
-
{ token: 'unit', pattern: /(?<=\d)(px|em|rem|%|vh|vw|ms|s|deg)/, color: '#d73a49', dark: '#ff7b72' },
|
|
642
|
-
{ token: 'number', pattern: /\b\d+(\.\d+)?\b/, color: '#005cc5', dark: '#79c0ff' },
|
|
643
|
-
{ token: 'punct', pattern: /[{}();:]/, color: '#24292e', dark: '#c9d1d9' }
|
|
644
|
-
],
|
|
871
|
+
alias: 'CSS',
|
|
872
|
+
rules: css,
|
|
645
873
|
|
|
646
874
|
});
|
|
647
875
|
Coax.register('html', {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
{ token: 'doctype', pattern: /<!DOCTYPE[\s\S]*?>/i, color: '#005cc5', dark: '#56b6c2' },
|
|
651
|
-
// 匹配标签名: <div, </div
|
|
652
|
-
{ token: 'tag', pattern: /<\/?[a-zA-Z0-9]+/, color: '#22863a', dark: '#abb2bf' },
|
|
653
|
-
// 匹配属性名: class=
|
|
654
|
-
{ token: 'attr', pattern: /[a-zA-Z-]+(?=\s*=\s*)/, color: '#6f42c1', dark: '#e06c75' },
|
|
655
|
-
// 匹配属性值: "value"
|
|
656
|
-
{ token: 'string', pattern: /(['"])(?:\\.|[^\\])*?\1/, color: '#032f62', dark: '#f39c12' },
|
|
657
|
-
// 匹配标签闭合: >, />
|
|
658
|
-
{ token: 'bracket', pattern: /\/?>/, color: '#24292e', dark: '#f1f1f1' }
|
|
659
|
-
],
|
|
876
|
+
alias: 'HTML',
|
|
877
|
+
rules: html,
|
|
660
878
|
});
|
|
661
879
|
Coax.register('js', {
|
|
662
880
|
alias: 'Javascript',
|
|
663
|
-
rules:
|
|
664
|
-
{ token: 'comment', pattern: /\/\/[^\n]*|\/\*[\s\S]*?\*\//, color: '#6a737d', dark: '#8b949e' },
|
|
665
|
-
{ token: 'string', pattern: /(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/, color: '#032f62', dark: '#61afef' },
|
|
666
|
-
{ 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/, color: '#e06c75', dark: '#d73a49' },
|
|
667
|
-
{ token: 'builtin', pattern: /\b(console|window|document|Math|JSON|true|false|null|undefined|Object|Array|Promise)\b/, color: '#56b6c2', dark: '#61afef' },
|
|
668
|
-
{ token: 'number', pattern: /\b\d+\b/, color: '#61afef', dark: '#d19a66' },
|
|
669
|
-
{ token: 'func', pattern: /\b[a-zA-Z_]\w*(?=\s*\()/, color: '#e5c07b', dark: '#98c379' },
|
|
670
|
-
{ token: 'op', pattern: /[+\-*/%=<>!&|^~]+/, color: '#d73a49', dark: '#e06c75' }
|
|
671
|
-
],
|
|
881
|
+
rules: javascript,
|
|
672
882
|
});
|
|
673
883
|
Coax.register('ts', {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
{ token: 'string', pattern: /(?:'|"|`)(?:\\.|[^\\'"\b])*?(?:'|"|`)/, color: '#032f62', dark: '#61afef' },
|
|
677
|
-
{ token: 'decorator', pattern: /@[a-zA-Z_]\w*/, color: '#d19a66', dark: '#e5c07b' },
|
|
678
|
-
{ 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/, color: '#e06c75', dark: '#d73a49' },
|
|
679
|
-
{ token: 'builtin', pattern: /\b(any|boolean|never|number|string|symbol|unknown|void|undefined|null|boolean|true|false|console|window|document)\b/, color: '#56b6c2', dark: '#61afef' },
|
|
680
|
-
{ token: 'type', pattern: /\b[A-Z]\w*\b/, color: '#22863a', dark: '#8b949e' },
|
|
681
|
-
{ token: 'number', pattern: /\b\d+\b/, color: '#61afef', dark: '#d19a66' },
|
|
682
|
-
{ token: 'func', pattern: /\b[a-zA-Z_]\w*(?=\s*\()/, color: '#e5c07b', dark: '#98c379' },
|
|
683
|
-
{ token: 'op', pattern: /(\?\.|![:\.]|[+\-*/%=<>!&|^~]+)/, color: '#d73a49', dark: '#e06c75' }
|
|
684
|
-
],
|
|
884
|
+
alias: 'Typescript',
|
|
885
|
+
rules: typescript,
|
|
685
886
|
});
|
|
686
|
-
Coax.
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
navigator.clipboard.writeText(this.source)
|
|
693
|
-
.then(() => {
|
|
694
|
-
console.log('Text successfully copied to clipboard');
|
|
695
|
-
arg.iconEl.innerHTML = icaxCheck();
|
|
696
|
-
arg.iconEl.toggleAttribute('disabled', true);
|
|
697
|
-
setTimeout(() => {
|
|
698
|
-
//恢复
|
|
699
|
-
arg.iconEl.removeAttribute('disabled');
|
|
700
|
-
arg.iconEl.innerHTML = icaxCopy();
|
|
701
|
-
}, 2000);
|
|
702
|
-
})
|
|
703
|
-
.catch(err => {
|
|
704
|
-
console.error('Error copying text to clipboard: ', err);
|
|
705
|
-
});
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
}]);
|
|
887
|
+
Coax.register('md', {
|
|
888
|
+
alias: 'Markdown',
|
|
889
|
+
rules: markdown
|
|
890
|
+
});
|
|
891
|
+
//注册工具箱
|
|
892
|
+
Coax.addTools([copy]);
|
|
709
893
|
customElements.define(`${NAMESPACE}-code`, Coax);
|
|
710
894
|
|
|
895
|
+
return Coax;
|
|
896
|
+
|
|
711
897
|
}));
|