@codady/coax 0.0.3 → 0.0.5
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/LICENSE +1 -1
- package/README.md +331 -166
- package/dist/coax.cjs.js +88 -75
- package/dist/coax.cjs.min.js +4 -4
- package/dist/coax.esm.js +88 -75
- package/dist/coax.esm.min.js +4 -4
- package/dist/coax.umd.js +259 -247
- package/dist/coax.umd.min.js +4 -4
- package/examples/color-selector.html +3 -4
- package/examples/deepseek-highlight.html +19 -10
- package/examples/js-highlight.html +3 -9
- package/package.json +2 -2
- package/script-note.js +2 -2
- package/src/Coax.js +2 -3
- package/src/Coax.ts +2 -3
- package/src/components/{CoaxElem.js → Coax.js} +159 -90
- package/src/components/{CoaxElem.ts → Coax.ts} +169 -103
- package/src/modules.js +3 -3
- package/src/modules.ts +3 -3
- package/examples/.htaccess +0 -0
- package/examples/nginx.htaccess +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Last modified: 2026/01/12
|
|
2
|
+
* Last modified: 2026/01/12 15:11:21
|
|
3
|
+
* Coax - A custom web component for syntax highlighting, code display, and interactive features
|
|
4
|
+
*
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
import icaxCopy from "@codady/icax/src/icaxCopy";
|
|
7
|
-
import icaxCheck from "@codady/icax/src/icaxCheck";
|
|
8
7
|
import typeWriter from "@codady/utils/typeWriter";
|
|
9
8
|
import parseClasses from "@codady/utils/parseClasses";
|
|
10
9
|
import NAMESPACE from "@codady/utils/namespace";
|
|
@@ -15,37 +14,44 @@ import createEl from "@codady/utils/createEl";
|
|
|
15
14
|
|
|
16
15
|
// Define the structure for the language configuration
|
|
17
16
|
export interface LanguageRule {
|
|
18
|
-
token: string;
|
|
19
|
-
pattern: RegExp;
|
|
20
|
-
light?: string;
|
|
21
|
-
dark?: string;
|
|
17
|
+
token: string; // Token representing a specific syntax element (e.g., keyword, string, comment)
|
|
18
|
+
pattern: RegExp; // Regular expression used to match the syntax element
|
|
19
|
+
light?: string; // Optional CSS color for light mode
|
|
20
|
+
dark?: string; // Optional CSS color for dark mode
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
export interface LanguageConfig {
|
|
25
24
|
rules: LanguageRule[]; // Array of syntax highlighting rules
|
|
26
|
-
alias?: string; // Alias name
|
|
25
|
+
alias?: string; // Alias name for the language (e.g., 'JavaScript', 'JS', etc.)
|
|
27
26
|
themeStyles?: string; // Optional internal CSS for language-specific styles
|
|
28
|
-
cssPrefix?: string; // Optional CSS prefix for class names
|
|
27
|
+
cssPrefix?: string; // Optional CSS prefix for class names used in syntax highlighting
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
class
|
|
30
|
+
class Coax extends HTMLElement {
|
|
32
31
|
// A static Map to hold the configuration for different languages
|
|
33
32
|
static languages = new Map<string, LanguageConfig>();
|
|
33
|
+
|
|
34
|
+
// A static array to hold the tools registered with the component
|
|
34
35
|
static tools: any[] = [];
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
private
|
|
38
|
-
private
|
|
39
|
-
private
|
|
40
|
-
private
|
|
41
|
-
private
|
|
42
|
-
private
|
|
43
|
-
private
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
public
|
|
48
|
-
public
|
|
36
|
+
|
|
37
|
+
private source: string; // Source code content to be highlighted
|
|
38
|
+
private _renderQueued = false; // Flag to prevent multiple render requests
|
|
39
|
+
private baseStylesEl!: HTMLStyleElement; // Element for base styles
|
|
40
|
+
private themeStylesEl!: HTMLStyleElement; // Element for theme styles
|
|
41
|
+
private dynamicStylesEl!: HTMLStyleElement; // Element for dynamic styles
|
|
42
|
+
private highlightEl!: HTMLElement; // Element that holds the highlighted code
|
|
43
|
+
private headerEl!: HTMLElement; // Header element (for code name, tools, etc.)
|
|
44
|
+
private codeNameEl!: HTMLElement; // Code name element (shows language or alias)
|
|
45
|
+
private codeToolsEl!: HTMLElement; // Code tools element (for interactive tools like copy)
|
|
46
|
+
private codeBodyEl!: HTMLElement; // Code body element (the container for the code)
|
|
47
|
+
|
|
48
|
+
public lang: string = 'plain'; // Language of the code (default is plain text)
|
|
49
|
+
public alias: string = 'Plain Text'; // Alias name for the language (default is 'Plain Text')
|
|
50
|
+
public lineString: string = ''; // The current line's string being typed
|
|
51
|
+
public lastLineString: string = ''; // The last line's string
|
|
52
|
+
public speed: number = 5; // Speed of the typing effect (higher is slower)
|
|
53
|
+
public autoScroll: boolean = true; // Flag to enable/disable auto-scrolling
|
|
54
|
+
public canListen: boolean = true; // Flag to enable/disable auto-scrolling
|
|
49
55
|
|
|
50
56
|
constructor() {
|
|
51
57
|
super();
|
|
@@ -53,12 +59,7 @@ class CoaxElem extends HTMLElement {
|
|
|
53
59
|
this.attachShadow({ mode: 'open' });
|
|
54
60
|
// Remove leading/trailing whitespace from the raw code content
|
|
55
61
|
this.source = this.textContent?.replace(/^\s*\n|\n\s*$/g, '') || '';
|
|
56
|
-
|
|
57
|
-
this.alias = 'Plain Text';
|
|
58
|
-
this.lineString = '';
|
|
59
|
-
this.speed = 5;
|
|
60
|
-
this.autoScroll = true;
|
|
61
|
-
// 1. 初始化基础骨架
|
|
62
|
+
// Initialize the basic structure of the component
|
|
62
63
|
(this.shadowRoot as any).innerHTML = `
|
|
63
64
|
<style id="base-styles">
|
|
64
65
|
:host {
|
|
@@ -188,11 +189,11 @@ class CoaxElem extends HTMLElement {
|
|
|
188
189
|
<style id="theme-styles"></style>
|
|
189
190
|
<div id="code-header"><span id="code-name">${this.alias}</span><div id="code-tools"></div></div>
|
|
190
191
|
<div id="code-body">
|
|
191
|
-
<pre><code id="highlight
|
|
192
|
+
<pre><code id="highlight"></code></pre>
|
|
192
193
|
</div>
|
|
193
194
|
`;
|
|
194
195
|
|
|
195
|
-
//
|
|
196
|
+
// Cache references to various elements
|
|
196
197
|
this.baseStylesEl = getEl('#base-styles', this.shadowRoot) as HTMLStyleElement;
|
|
197
198
|
this.themeStylesEl = getEl('#theme-styles', this.shadowRoot) as HTMLStyleElement;
|
|
198
199
|
this.dynamicStylesEl = getEl('#dynamic-styles', this.shadowRoot) as HTMLStyleElement;
|
|
@@ -200,28 +201,34 @@ class CoaxElem extends HTMLElement {
|
|
|
200
201
|
this.codeNameEl = getEl('#code-name', this.shadowRoot) as HTMLElement;
|
|
201
202
|
this.codeToolsEl = getEl('#code-tools', this.shadowRoot) as HTMLElement;
|
|
202
203
|
this.codeBodyEl = getEl('#code-body', this.shadowRoot) as HTMLElement;
|
|
203
|
-
this.
|
|
204
|
+
this.highlightEl = getEl('#highlight', this.shadowRoot) as HTMLElement;
|
|
204
205
|
|
|
205
206
|
this.codeBodyEl.addEventListener('scroll', () => {
|
|
206
207
|
let flag = this.codeBodyEl.scrollTop + this.codeBodyEl.clientHeight < this.codeBodyEl.scrollHeight;
|
|
207
|
-
//
|
|
208
|
+
// Check if the user manually scrolled
|
|
208
209
|
this.autoScroll = !flag;
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
212
|
/**
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
* Registers a new language with a set of syntax highlighting rules.
|
|
214
|
+
* @param name - The name of the programming language (e.g., 'javascript', 'html', etc.)
|
|
215
|
+
* @param config - Configuration for the language, including rules, theme, and optional CSS.
|
|
216
|
+
*/
|
|
216
217
|
static register(name: string, config: LanguageConfig): void {
|
|
217
218
|
// Store the language configuration in the static map
|
|
218
219
|
this.languages.set(name, { ...config });
|
|
219
220
|
}
|
|
220
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Registers tools that can be used with the code editor (e.g., copy, download, etc.).
|
|
223
|
+
* @param items - An array of tool items to register.
|
|
224
|
+
*/
|
|
221
225
|
static addTools(items: toolsItem[]): void {
|
|
222
|
-
|
|
226
|
+
Coax.tools = items;
|
|
223
227
|
}
|
|
224
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Mounts the tools to the code tools container.
|
|
230
|
+
* @param toolItems - An array of tool items to be added to the tools container.
|
|
231
|
+
*/
|
|
225
232
|
mountTools(toolItems: any[]) {
|
|
226
233
|
requestAnimationFrame(() => {
|
|
227
234
|
this.codeToolsEl.innerHTML = '';
|
|
@@ -232,29 +239,37 @@ class CoaxElem extends HTMLElement {
|
|
|
232
239
|
this.codeToolsEl.appendChild(createTools(items));
|
|
233
240
|
});
|
|
234
241
|
}
|
|
235
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Called when the element is connected to the DOM.
|
|
244
|
+
*/
|
|
236
245
|
connectedCallback() {
|
|
237
246
|
this.render();
|
|
238
247
|
}
|
|
239
248
|
|
|
240
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Observed attributes for changes. These include the language, height, tools, and speed.
|
|
251
|
+
*/
|
|
241
252
|
static get observedAttributes() { return ['lang', 'height', 'max-height', 'tools', 'speed']; }
|
|
242
253
|
|
|
243
254
|
/**
|
|
244
|
-
|
|
245
|
-
|
|
255
|
+
* Called when any of the observed attributes change.
|
|
256
|
+
* @param name - The name of the changed attribute.
|
|
257
|
+
* @param oldVal - The old value of the attribute.
|
|
258
|
+
* @param newVal - The new value of the attribute.
|
|
259
|
+
*/
|
|
246
260
|
attributeChangedCallback(name: string, oldVal: string, newVal: string) {
|
|
247
|
-
if (oldVal === newVal) return;
|
|
261
|
+
if (oldVal === newVal || !this.canListen) return;
|
|
248
262
|
if (name === 'height' || name === 'max-height') {
|
|
249
263
|
this.updateStyleByRegExp(name, newVal);
|
|
250
264
|
}
|
|
251
265
|
|
|
252
266
|
if (name === 'speed') {
|
|
267
|
+
// Convert to integer (0 or 1)
|
|
253
268
|
this.speed = ~~(!!newVal);
|
|
254
269
|
}
|
|
255
270
|
|
|
256
271
|
if (name === 'lang') {
|
|
257
|
-
|
|
272
|
+
// Update the language and re-render
|
|
258
273
|
this.lang = newVal;
|
|
259
274
|
this.render();
|
|
260
275
|
}
|
|
@@ -262,14 +277,16 @@ class CoaxElem extends HTMLElement {
|
|
|
262
277
|
if (name === 'tools') {
|
|
263
278
|
if (!newVal) this.codeToolsEl.innerHTML = '';
|
|
264
279
|
const tools = parseClasses(newVal),
|
|
265
|
-
toolItems =
|
|
280
|
+
toolItems = Coax.tools.filter(k => tools.includes(k.name));
|
|
266
281
|
if (!toolItems.length) return;
|
|
267
282
|
this.mountTools(toolItems);
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
/**
|
|
271
|
-
|
|
272
|
-
|
|
286
|
+
* Updates the base style by replacing specific CSS properties using a regular expression.
|
|
287
|
+
* @param prop - The CSS property name to update (e.g., 'height', 'max-height').
|
|
288
|
+
* @param value - The new value for the property.
|
|
289
|
+
*/
|
|
273
290
|
private updateStyleByRegExp(prop: string, value: string) {
|
|
274
291
|
// 构建正则:匹配属性名后面跟着冒号,直到分号或换行
|
|
275
292
|
// 例如:height:\s*[^;]+;
|
|
@@ -277,11 +294,22 @@ class CoaxElem extends HTMLElement {
|
|
|
277
294
|
// 替换为新的属性值
|
|
278
295
|
this.baseStylesEl.textContent = this.baseStylesEl.textContent.replace(regex, `;\n${prop}: ${value};`);
|
|
279
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Retrieves the CSS prefix for the language configuration.
|
|
299
|
+
* @param config - The language configuration object.
|
|
300
|
+
* @returns The CSS prefix.
|
|
301
|
+
*/
|
|
280
302
|
getCssPrefix(config: LanguageConfig) {
|
|
281
303
|
return (config?.cssPrefix || this.lang).replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
282
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Highlights a given string according to the language configuration.
|
|
307
|
+
* @param string - The string to highlight.
|
|
308
|
+
* @param config - The language configuration object.
|
|
309
|
+
* @returns The highlighted string with HTML spans.
|
|
310
|
+
*/
|
|
283
311
|
getHighLightString(string: string, config?: LanguageConfig) {
|
|
284
|
-
config = config ||
|
|
312
|
+
config = config || Coax.languages.get(this.lang);
|
|
285
313
|
if (!config) return string;
|
|
286
314
|
// 如果找到了配置,则进行高亮处理
|
|
287
315
|
const cssPrefix = this.getCssPrefix(config),
|
|
@@ -292,29 +320,41 @@ class CoaxElem extends HTMLElement {
|
|
|
292
320
|
return i !== -1 && config.rules[i] ? `<span class="${NAMESPACE}-${cssPrefix}-${config.rules[i].token}">${match}</span>` : match;
|
|
293
321
|
});
|
|
294
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Creates a wrapper element for a line of code.
|
|
325
|
+
* @param index - The line index to assign.
|
|
326
|
+
* @param startIndex - The starting index for the line.
|
|
327
|
+
* @returns A div element wrapping the line of code.
|
|
328
|
+
*/
|
|
295
329
|
createLineWrap(index?: number, startIndex?: number) {
|
|
296
330
|
let dataIndex = 0;
|
|
297
331
|
if (index == null && startIndex == null) {
|
|
298
|
-
dataIndex = this.
|
|
332
|
+
dataIndex = this.highlightEl.children.length;
|
|
299
333
|
} else {
|
|
300
|
-
const start = startIndex || this.
|
|
334
|
+
const start = startIndex || this.highlightEl.children.length;
|
|
301
335
|
dataIndex = start + (index as number);
|
|
302
336
|
}
|
|
303
337
|
return createEl('div', { 'data-index': dataIndex }, '<div></div>');
|
|
304
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Fills a line of code with highlighted content.
|
|
341
|
+
* @param codeWrap - The element that will contain the highlighted line of code.
|
|
342
|
+
* @param line - The line of code to highlight.
|
|
343
|
+
* @param config - The language configuration object.
|
|
344
|
+
*/
|
|
305
345
|
getLineToFill(codeWrap: Element, line: string, config?: LanguageConfig) {
|
|
306
|
-
config = config ||
|
|
346
|
+
config = config || Coax.languages.get(this.lang);
|
|
307
347
|
let highlightedLine = this.getHighLightString(line, config);
|
|
308
348
|
// 将高亮后的内容填充到 div 中
|
|
309
349
|
codeWrap.innerHTML = highlightedLine;
|
|
310
350
|
};
|
|
311
351
|
/**
|
|
312
|
-
*
|
|
313
|
-
* @param newCode -
|
|
352
|
+
* Highlights new source code and appends it to the code body.
|
|
353
|
+
* @param newCode - The new source code to highlight and append.
|
|
314
354
|
*/
|
|
315
355
|
async highlight(newCode: string) {
|
|
316
|
-
const config =
|
|
317
|
-
startIndex = this.
|
|
356
|
+
const config = Coax.languages.get(this.lang),
|
|
357
|
+
startIndex = this.highlightEl.children.length,
|
|
318
358
|
// 将新源码按行分割
|
|
319
359
|
newCodeLines = newCode ? newCode.split('\n') : [];
|
|
320
360
|
//更新别名
|
|
@@ -328,10 +368,10 @@ class CoaxElem extends HTMLElement {
|
|
|
328
368
|
const lineWrap = this.createLineWrap(index, startIndex),
|
|
329
369
|
codeWrap = lineWrap.lastElementChild as Element;
|
|
330
370
|
//标记完成
|
|
331
|
-
|
|
371
|
+
(lineWrap as any).completed = true;
|
|
332
372
|
|
|
333
373
|
if (this.hasAttribute('speed')) {
|
|
334
|
-
this.
|
|
374
|
+
this.highlightEl.appendChild(lineWrap);
|
|
335
375
|
//流式打字
|
|
336
376
|
await typeWriter(lineString, {
|
|
337
377
|
speed: this.speed,
|
|
@@ -344,20 +384,27 @@ class CoaxElem extends HTMLElement {
|
|
|
344
384
|
//直接打出
|
|
345
385
|
this.getLineToFill(codeWrap, lineString, config);
|
|
346
386
|
//
|
|
347
|
-
this.
|
|
387
|
+
this.highlightEl.appendChild(lineWrap);
|
|
348
388
|
}
|
|
349
389
|
}
|
|
350
390
|
//滚动到最底部
|
|
351
391
|
this.autoScrollCode();
|
|
352
392
|
return true;
|
|
353
393
|
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Automatically scrolls the code body to the bottom.
|
|
397
|
+
*/
|
|
354
398
|
autoScrollCode() {
|
|
355
399
|
if (this.autoScroll) {
|
|
356
400
|
this.codeBodyEl.scrollTop = this.codeBodyEl.scrollHeight;
|
|
357
401
|
}
|
|
358
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Injects the theme styles for syntax highlighting (light/dark modes).
|
|
405
|
+
*/
|
|
359
406
|
injectThemeStyles() {
|
|
360
|
-
const config =
|
|
407
|
+
const config = Coax.languages.get(this.lang);
|
|
361
408
|
if (!config) return;
|
|
362
409
|
|
|
363
410
|
// Get language name, fallback to 'js' if not provided
|
|
@@ -382,7 +429,6 @@ class CoaxElem extends HTMLElement {
|
|
|
382
429
|
.${NAMESPACE}-${cssPrefix}-${rule.token} { color: var(--${NAMESPACE}-${cssPrefix}-${rule.token},${rule.dark}); }` : ``} `).join('\n');
|
|
383
430
|
schemeStyles += `}`;
|
|
384
431
|
// Set the inner HTML of the shadow root, including styles and highlighted code
|
|
385
|
-
// 2. 精确更新 DOM 节点而非重写 ShadowRoot
|
|
386
432
|
this.dynamicStylesEl.textContent = lightStyles + darkStyles + schemeStyles;
|
|
387
433
|
|
|
388
434
|
//附加主题样式
|
|
@@ -392,6 +438,10 @@ class CoaxElem extends HTMLElement {
|
|
|
392
438
|
|
|
393
439
|
|
|
394
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Updates the alias name for the language based on the configuration.
|
|
443
|
+
* @param config - The language configuration object.
|
|
444
|
+
*/
|
|
395
445
|
updateName(config: any) {
|
|
396
446
|
if (this.hasAttribute('unnamed')) return;
|
|
397
447
|
if (!config) {
|
|
@@ -403,36 +453,35 @@ class CoaxElem extends HTMLElement {
|
|
|
403
453
|
}
|
|
404
454
|
}
|
|
405
455
|
/**
|
|
406
|
-
|
|
407
|
-
|
|
456
|
+
* Renders the highlighted code within the shadow DOM.
|
|
457
|
+
*/
|
|
408
458
|
render(code = this.source) {
|
|
409
459
|
//同时多次改变属性,只执行一次
|
|
410
|
-
// 如果已经在队列中,则直接返回
|
|
411
460
|
if (this._renderQueued) return;
|
|
412
461
|
this._renderQueued = true;
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
await this.highlight(code);
|
|
419
|
-
this._renderQueued = false;
|
|
420
|
-
});
|
|
462
|
+
this.clear();
|
|
463
|
+
this.injectThemeStyles();
|
|
464
|
+
//一次性渲染
|
|
465
|
+
this.highlight(code);
|
|
466
|
+
this._renderQueued = false;
|
|
421
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Clears the current content and resets the state.
|
|
470
|
+
*/
|
|
422
471
|
clear() {
|
|
423
|
-
this.
|
|
472
|
+
this.highlightEl.innerHTML = this.source = this.lineString = '';
|
|
424
473
|
}
|
|
425
474
|
/**
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
475
|
+
* Replaces the existing code with new source code and re-renders.
|
|
476
|
+
* @param newCode - The new source code to replace the existing code.
|
|
477
|
+
*/
|
|
429
478
|
async replace(newCode: string) {
|
|
430
479
|
this.clear();
|
|
431
480
|
await this.highlight(newCode);
|
|
432
481
|
}
|
|
433
482
|
/**
|
|
434
|
-
*
|
|
435
|
-
* @param newCode -
|
|
483
|
+
* Appends new source code to the current content and highlights only the new portion.
|
|
484
|
+
* @param newCode - The new source code to append and highlight.
|
|
436
485
|
*/
|
|
437
486
|
async append(newCode: string) {
|
|
438
487
|
// 将新的代码追加到现有代码末尾
|
|
@@ -440,49 +489,66 @@ class CoaxElem extends HTMLElement {
|
|
|
440
489
|
// 高亮新的部分
|
|
441
490
|
await this.highlight(newCode);
|
|
442
491
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Retrieves the last line of code that was rendered.
|
|
494
|
+
* @returns An object containing the line wrapper and code wrapper for the last line.
|
|
495
|
+
*/
|
|
496
|
+
getLastLine() {
|
|
497
|
+
const lastChild = this.highlightEl.lastElementChild,
|
|
498
|
+
lastLine = !lastChild || (this.highlightEl.lastElementChild as any)?.completed ?
|
|
446
499
|
this.createLineWrap() : lastChild;
|
|
447
500
|
return {
|
|
448
501
|
lineWrap: lastLine,
|
|
449
502
|
codeWrap: lastLine.lastElementChild as Element
|
|
450
503
|
}
|
|
451
504
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
505
|
+
/**
|
|
506
|
+
* Marks the current line as completed and updates the displayed code.
|
|
507
|
+
*/
|
|
508
|
+
close() {
|
|
509
|
+
const lineWrap = this.highlightEl.lastElementChild;
|
|
510
|
+
if (!lineWrap) return;
|
|
511
|
+
(lineWrap as any).completed = true;
|
|
512
|
+
//行结束前保存
|
|
513
|
+
this.lastLineString = this.lineString;
|
|
514
|
+
this.getLineToFill(lineWrap?.lastElementChild as Element, this.lineString);
|
|
515
|
+
//一行结束,清空临时行文本
|
|
516
|
+
this.lineString = '';
|
|
455
517
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
518
|
+
/**
|
|
519
|
+
* Reopens the last closed line and restores its original content.
|
|
520
|
+
*/
|
|
521
|
+
open() {
|
|
522
|
+
const lineWrap = this.highlightEl.lastElementChild;
|
|
523
|
+
if (!lineWrap) return;
|
|
524
|
+
(lineWrap as any).completed = false;
|
|
525
|
+
//恢复最后一行字符串
|
|
526
|
+
(lineWrap?.lastElementChild as any).textContent = this.lineString = this.lastLineString;
|
|
459
527
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Streams a string of code into the component, either appending or closing the current line.
|
|
530
|
+
* @param str - The code string to stream into the component.
|
|
531
|
+
* @param forceClose - Forcefully close the line if set to `true`.
|
|
532
|
+
*/
|
|
533
|
+
stream(str: string, forceClose: boolean = false) {
|
|
534
|
+
const { lineWrap, codeWrap } = this.getLastLine();
|
|
535
|
+
this.highlightEl.appendChild(lineWrap);
|
|
463
536
|
//汇集
|
|
464
537
|
this.source += str;
|
|
465
538
|
|
|
466
539
|
//如果没有遇到换行符号,也可以强制结束
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (str.startsWith('\n') || str.startsWith('\r')) {
|
|
540
|
+
if (forceClose || (str.startsWith('\n') || str.endsWith('\n'))) {
|
|
470
541
|
//标记完成
|
|
471
|
-
this.
|
|
472
|
-
//渲染
|
|
473
|
-
this.getLineToFill(codeWrap, this.lineString);
|
|
474
|
-
//一行结束,清空临时行文本
|
|
475
|
-
this.lineString = '';
|
|
542
|
+
this.close();
|
|
476
543
|
} else {
|
|
477
544
|
//插入文本
|
|
478
545
|
codeWrap.innerHTML += str;
|
|
479
546
|
//临时保存行文本
|
|
480
547
|
this.lineString += str;
|
|
481
|
-
|
|
482
548
|
}
|
|
483
549
|
//滚动到最底部
|
|
484
550
|
this.autoScrollCode();
|
|
485
551
|
}
|
|
486
552
|
}
|
|
487
553
|
|
|
488
|
-
export default
|
|
554
|
+
export default Coax;
|
package/src/modules.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since Last modified: 2026/01/12
|
|
2
|
+
* @since Last modified: 2026/01/12 14:10:29
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
|
-
import
|
|
5
|
+
import Coax from './components/Coax.js';
|
|
6
6
|
import css from './rules/css.js';
|
|
7
7
|
import html from './rules/html.js';
|
|
8
8
|
import javascript from './rules/javascript.js';
|
|
9
9
|
import markdown from './rules/markdown.js';
|
|
10
10
|
import typescript from './rules/typescript.js';
|
|
11
11
|
import copy from './tools/copy.js';
|
|
12
|
-
export {
|
|
12
|
+
export { Coax, copy, css, html, javascript, typescript, markdown, };
|
package/src/modules.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since Last modified: 2026/01/12
|
|
2
|
+
* @since Last modified: 2026/01/12 14:10:29
|
|
3
3
|
*/
|
|
4
4
|
'use strict'
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import Coax from './components/Coax.js';
|
|
7
7
|
import css from './rules/css.js';
|
|
8
8
|
import html from './rules/html.js';
|
|
9
9
|
import javascript from './rules/javascript.js';
|
|
@@ -12,7 +12,7 @@ import typescript from './rules/typescript.js';
|
|
|
12
12
|
import copy from './tools/copy.js';
|
|
13
13
|
|
|
14
14
|
export {
|
|
15
|
-
|
|
15
|
+
Coax,
|
|
16
16
|
copy,
|
|
17
17
|
css,
|
|
18
18
|
html,
|
package/examples/.htaccess
DELETED
|
File without changes
|
package/examples/nginx.htaccess
DELETED
|
File without changes
|