estreui 1.2.2 → 1.2.4

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/scripts/doctre.js CHANGED
@@ -30,7 +30,7 @@ SOFTWARE.
30
30
  //
31
31
  // Cold(array object) assigning of HTML Tree for make to JSON string.
32
32
  //
33
- // v1.1.1 / release 2026.02.20
33
+ // v1.1.2 / release 2026.04.18
34
34
  //
35
35
  // cold = [] - Cold HTML child node list
36
36
  // cold[0] - Tag name, classes, id, name, type = "tag.class1.class2#id@name$type" : string
@@ -45,8 +45,63 @@ SOFTWARE.
45
45
  // Match replace
46
46
  // ex) Doctre.parse([["|tag|.|classes|#|id|", "empty content"], "|divider|"], { tag: () => isInline ? "span" | "div", classes: "test fixed", id: getId(), divider: it => '<hr class="' + it + '" />' })
47
47
 
48
+ // ──────────────────────────────────────────────
49
+ // @typedef — reusable type shapes
50
+ // ──────────────────────────────────────────────
51
+
52
+ /**
53
+ * Extracted solidId components.
54
+ * @typedef {Object} DoctreSolidId
55
+ * @property {string} tagName - HTML tag name.
56
+ * @property {string} [class] - Space-separated CSS class names.
57
+ * @property {string} [id] - Element id.
58
+ * @property {string} [name] - Element name attribute.
59
+ * @property {string} [type] - Element type attribute.
60
+ */
61
+
62
+ /**
63
+ * A single cold element entry — serialized DOM node in array form.
64
+ *
65
+ * `[solidId, contentData, style, attrs, datas]`
66
+ * @typedef {Array} DoctreColdElement
67
+ * @property {string|DoctreSolidId} 0 - solidId string or extracted object.
68
+ * @property {DoctreColdElement[]|string|null} [1] - Child content (cold array, text, or null).
69
+ * @property {string|Object} [2] - Inline style string or style object.
70
+ * @property {Object<string, string>} [3] - Regular HTML attributes (excluding id/name/type/class/style/data-*).
71
+ * @property {Object<string, string>} [4] - data-* attributes.
72
+ */
73
+
74
+ /**
75
+ * Token replacement map used by Doctre.matchReplace.
76
+ * Keys are token names (matched as `|key|`); values are replacement strings, functions, or objects.
77
+ * @typedef {Object<string, string|Function|Object>} DoctreMatchReplacer
78
+ * @property {string} [dataPlaceholder] - Default replacement for unmatched tokens.
79
+ * @property {boolean} [coverReplaceable] - If true, replaces all unmatched tokens with dataPlaceholder.
80
+ */
81
+
82
+ /**
83
+ * Document Object Cold Taste Refrigeration Effortlessness — DOM serialization/deserialization engine.
84
+ * Preserves and restores HTML trees using cold (array object) and frost (JSON string) formats.
85
+ *
86
+ * **cold format**: `[solidId, contentData, style, attrs, datas]`
87
+ * - `solidId`: `"tag.class1.class2#id@name$type"` string or extracted object
88
+ * - `contentData`: cold array / text string / NodeList / Element / Node
89
+ * - `style`: style string or object
90
+ * - `attrs`: regular attribute object
91
+ * - `datas`: data-* attribute object
92
+ *
93
+ * **frost format**: JSON.stringify'd cold string
94
+ *
95
+ * **matchReplace**: replaces `|key|` tokens with values from the matchReplacer object
96
+ * @class
97
+ */
48
98
  class Doctre {
49
99
 
100
+ /**
101
+ * Splits a solidId string into the tag name and remaining major attribute parts.
102
+ * @param {string|Object} solidId - solidId string or `{ tagName, ... }` object.
103
+ * @returns {[string, string|Object]} `[tagName, majorAttrs]` tuple.
104
+ */
50
105
  static extractTagName(solidId) {
51
106
  let tagName, majorAttrs;
52
107
  if (typeof solidId == "string") {
@@ -61,6 +116,12 @@ class Doctre {
61
116
  return [tagName, majorAttrs];
62
117
  }
63
118
 
119
+ /**
120
+ * Parses the major attribute part (`.class#id@name$type`) of a solidId into an object.
121
+ * @param {string} majorAttrs - Major attribute string.
122
+ * @param {Object} [to={}] - Object to store results into.
123
+ * @returns {Object} `{ class?, id?, name?, type? }` attribute object.
124
+ */
64
125
  static extractMajorAttrs(majorAttrs, to = {}) {
65
126
  const process = (string, divider, attrName) => {
66
127
  const filter = new RegExp(divider + "[\\w.-]*");
@@ -77,12 +138,28 @@ class Doctre {
77
138
  return to;
78
139
  }
79
140
 
141
+ /**
142
+ * Extracts both the tag name and major attributes from a solidId.
143
+ * @param {string} solidId - solidId string.
144
+ * @returns {Object} `{ tagName, class?, id?, name?, type? }`.
145
+ */
80
146
  static extractTagAndMajorAttrs(solidId) {
81
147
  const [tagName, majorAttrs] = this.extractTagName(solidId);
82
148
  return this.extractMajorAttrs(majorAttrs, { tagName });
83
149
  }
84
150
 
85
151
 
152
+ /**
153
+ * Creates a DOM element from cold parameters.
154
+ * @param {string|Array} [tagName="template"] - Tag name or cold array.
155
+ * @param {string|Object} [majorAttrs] - Major attributes string/object.
156
+ * @param {string|Array|NodeList|Node|Doctre|null} [contentData] - Child content.
157
+ * @param {string|Object} [style={}] - Style.
158
+ * @param {Object} [attrs={}] - Regular attributes.
159
+ * @param {Object} [datas={}] - data-* attributes.
160
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - `|key|` token replacement map.
161
+ * @returns {Element} The created DOM element.
162
+ */
86
163
  static createElement(tagName = "template", majorAttrs, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
87
164
  if (tagName instanceof Array) return this.createElement(...tagName);
88
165
 
@@ -132,10 +209,32 @@ class Doctre {
132
209
  return element;
133
210
  }
134
211
 
212
+ /**
213
+ * createElement variant that takes matchReplacer as the first argument.
214
+ * @param {DoctreMatchReplacer} matchReplacer - Token replacement map.
215
+ * @param {string} tagName - Tag name.
216
+ * @param {string|Object} [majorAttrs] - Major attributes.
217
+ * @param {*} [contentData] - Child content.
218
+ * @param {string|Object} [style={}] - Style.
219
+ * @param {Object} [attrs={}] - Regular attributes.
220
+ * @param {Object} [datas={}] - data-* attributes.
221
+ * @param {DoctreMatchReplacer} [matchReplacerOrigin={}] - Fallback when matchReplacer is null.
222
+ * @returns {Element}
223
+ */
135
224
  static createElementReplaced(matchReplacer, tagName, majorAttrs, contentData, style = {}, attrs = {}, datas = {}, matchReplacerOrigin = {}) {
136
225
  return this.createElement(tagName, majorAttrs, contentData, style, attrs, datas, matchReplacer ?? matchReplacerOrigin);
137
226
  }
138
227
 
228
+ /**
229
+ * Creates an element from a solidId string. Automatically extracts tagName and majorAttrs from solidId.
230
+ * @param {string|Array} solidId - solidId string or array.
231
+ * @param {*} [contentData] - Child content.
232
+ * @param {string|Object} [style={}] - Style.
233
+ * @param {Object} [attrs={}] - Regular attributes.
234
+ * @param {Object} [datas={}] - data-* attributes.
235
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
236
+ * @returns {Element}
237
+ */
139
238
  static createElementBy(solidId, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
140
239
  if (solidId instanceof Array) return this.createElementBy(...solidId);
141
240
 
@@ -143,10 +242,27 @@ class Doctre {
143
242
  return this.createElement(tagName, majorAttrs, contentData, style, attrs, datas, matchReplacer);
144
243
  }
145
244
 
245
+ /**
246
+ * createElementBy variant that takes matchReplacer as the first argument.
247
+ * @param {DoctreMatchReplacer} matchReplacer - Token replacement map.
248
+ * @param {string} solidId - solidId string.
249
+ * @param {*} [contentData] - Child content.
250
+ * @param {string|Object} [style={}] - Style.
251
+ * @param {Object} [attrs={}] - Regular attributes.
252
+ * @param {Object} [datas={}] - data-* attributes.
253
+ * @param {DoctreMatchReplacer} [matchReplacerOrigin={}] - Fallback replacement map.
254
+ * @returns {Element}
255
+ */
146
256
  static createElementReplacedBy(matchReplacer, solidId, contentData, style = {}, attrs = {}, datas = {}, matchReplacerOrigin = {}) {
147
257
  return this.createElementBy(solidId, contentData, style, attrs, datas, matchReplacer ?? matchReplacerOrigin);
148
258
  }
149
259
 
260
+ /**
261
+ * Creates a DocumentFragment from a cold (HCNL) array.
262
+ * @param {Array} hcnlArray - HTML Cold Node List array.
263
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
264
+ * @returns {DocumentFragment}
265
+ */
150
266
  static createFragment(hcnlArray, matchReplacer = {}) {
151
267
  const df = document.createDocumentFragment();
152
268
  for (const val of hcnlArray) switch (typeof val) {
@@ -168,22 +284,42 @@ class Doctre {
168
284
  return df;
169
285
  }
170
286
 
287
+ /** @type {string} Current User-Agent string. */
171
288
  static get userAgent() { return navigator?.userAgent ?? ""; }
289
+ /** @type {boolean} Whether newline/tab escaping is needed for Safari/iOS. */
172
290
  static get isRequiredEscape() {
173
291
  const userAgent = this.userAgent;
174
292
  return userAgent != "" && (userAgent.includes("iPad") || userAgent.includes("iPhone") || userAgent.includes("iPod") || (userAgent.includes("Macintosh") && !userAgent.includes("Chrome") && !userAgent.includes("Firefox") && !userAgent.includes("Edge") && !userAgent.includes("Opera")));
175
293
  }
294
+ /**
295
+ * Escapes newlines and tabs in JSON strings for Safari compatibility.
296
+ * @param {string} jsonContent - JSON string.
297
+ * @returns {string} Escaped string (returned as-is on non-Safari).
298
+ */
176
299
  static crashBroker(jsonContent) {
177
300
  if (this.isRequiredEscape) jsonContent = jsonContent.replace(/\r\n/gm, "\\r\\n").replace(/\n\r/gm, "\\n\\r").replace(/\r/gm, "\\r").replace(/\n/gm, "\\n").replace(/\t/g, "\\t");
178
301
  return jsonContent;
179
302
  }
180
303
 
304
+ /**
305
+ * Copies only primitive-type values from an object. Used to avoid circular references.
306
+ * @param {Object} obj - Source object.
307
+ * @returns {Object} A new object containing only primitive values.
308
+ */
181
309
  static copyPrimitives(obj) {
182
310
  return Object.fromEntries(
183
311
  Object.entries(obj).filter(([, v]) => v !== Object(v))
184
312
  );
185
313
  }
186
314
 
315
+ /**
316
+ * Replaces `|key|` tokens in a string with values from the matchReplacer. Delegates to matchReplaceObject for objects.
317
+ * @param {string|Object} frostOrString - String or object to apply replacements to.
318
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - `{ key: value }` replacement map. Values can be string/function/object.
319
+ * - `dataPlaceholder`: default replacement for unmatched tokens.
320
+ * - `coverReplaceable`: if true, replaces all unmatched tokens with dataPlaceholder.
321
+ * @returns {string|Object} The replaced result.
322
+ */
187
323
  static matchReplace(frostOrString, matchReplacer = {}) {
188
324
  if (typeof frostOrString != "string") return this.matchReplaceObject(frostOrString, matchReplacer);
189
325
 
@@ -249,12 +385,24 @@ class Doctre {
249
385
  return frostOrString;
250
386
  }
251
387
 
388
+ /**
389
+ * Recursively applies matchReplace to both keys and values of an object.
390
+ * @param {Object} object - Object to apply replacements to.
391
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Replacement map.
392
+ * @returns {Object} A new object with replacements applied.
393
+ */
252
394
  static matchReplaceObject(object, matchReplacer = {}) {
253
395
  const replaced = object.constructor();
254
396
  for (const key in object) replaced[this.matchReplace(key, matchReplacer)] = this.matchReplace(object[key], matchReplacer);
255
397
  return replaced;
256
398
  }
257
399
 
400
+ /**
401
+ * Parses a frost (JSON string) and restores it as a DocumentFragment.
402
+ * @param {string} frost - Frost format JSON string.
403
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
404
+ * @returns {DocumentFragment}
405
+ */
258
406
  static parse(frost, matchReplacer = {}) {
259
407
  frost = this.crashBroker(frost);
260
408
  const trimmedFrost = frost.trim();
@@ -273,11 +421,23 @@ class Doctre {
273
421
  return this.createFragment(parsed);
274
422
  }
275
423
 
424
+ /**
425
+ * Restores frost (string) or cold (array) to a live DOM (DocumentFragment).
426
+ * @param {string|Array} frostOrCold - Frost string or cold array.
427
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
428
+ * @returns {DocumentFragment}
429
+ */
276
430
  static live(frostOrCold, matchReplacer = {}) {
277
431
  if (typeof frostOrCold == "string") return this.parse(frostOrCold, matchReplacer);
278
432
  else return this.createFragment(frostOrCold);
279
433
  }
280
434
 
435
+ /**
436
+ * Wraps frost/cold in a template element and returns it.
437
+ * @param {string|Array} frostOrCold - Frost or cold data.
438
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
439
+ * @returns {Element} Template element containing the content.
440
+ */
281
441
  static takeOut(frostOrCold, matchReplacer = {}) {
282
442
  const element = this.createElement();
283
443
  element.append(this.live(frostOrCold, matchReplacer));
@@ -285,6 +445,15 @@ class Doctre {
285
445
  }
286
446
 
287
447
 
448
+ /**
449
+ * Assembles a solidId string from tag name and major attributes.
450
+ * @param {string} tagName - Tag name.
451
+ * @param {string} [className] - CSS classes (space-separated).
452
+ * @param {string} [id] - ID.
453
+ * @param {string} [name] - name attribute.
454
+ * @param {string} [type] - type attribute.
455
+ * @returns {string} solidId string (e.g. `"div.box.float#app@root$text"`).
456
+ */
288
457
  static getSolidId(tagName, className, id, name, type) {
289
458
  let solidId = tagName;
290
459
  if (className != null) solidId += "." + className.replace(/ /g, ".");
@@ -294,6 +463,12 @@ class Doctre {
294
463
  return solidId;
295
464
  }
296
465
 
466
+ /**
467
+ * Extracts the tag name and major attributes (class, id, name, type) from a DOM element.
468
+ * @param {Element} element - Target element.
469
+ * @param {boolean} [asSolidId=false] - If true returns solidId string, if false returns object.
470
+ * @returns {string|Object} solidId string or `{ tagName, class?, id?, name?, type? }`.
471
+ */
297
472
  static packTagAndMajorAttrs(element, asSolidId = false) {
298
473
  const tagName = element.tagName.toLowerCase();
299
474
  const className = element.getAttribute("class");
@@ -312,6 +487,11 @@ class Doctre {
312
487
  }
313
488
  }
314
489
 
490
+ /**
491
+ * Parses a CSS style string into a `{ property: value }` object.
492
+ * @param {string} style - Inline style string.
493
+ * @returns {Object<string, string>}
494
+ */
315
495
  static getStyleObject(style) {
316
496
  const styles = {};
317
497
  const divided = style.split(";");
@@ -325,6 +505,11 @@ class Doctre {
325
505
  return styles;
326
506
  }
327
507
 
508
+ /**
509
+ * Extracts attributes from a NamedNodeMap, excluding id/name/type/class/style/data-*.
510
+ * @param {NamedNodeMap} attrs - Element's attributes.
511
+ * @returns {Object<string, string>}
512
+ */
328
513
  static packAttributes(attrs) {
329
514
  const pack = {};
330
515
  for (const attr of attrs) {
@@ -345,6 +530,11 @@ class Doctre {
345
530
  return pack;
346
531
  }
347
532
 
533
+ /**
534
+ * Copies a DOMStringMap (dataset) to a plain object.
535
+ * @param {DOMStringMap} dataset - Element's dataset.
536
+ * @returns {Object<string, string>}
537
+ */
348
538
  static getDataObject(dataset) {
349
539
  const datas = {};
350
540
  for (const key in dataset) datas[key] = dataset[key];
@@ -352,6 +542,11 @@ class Doctre {
352
542
  }
353
543
 
354
544
 
545
+ /**
546
+ * Removes trailing empty entries (null, empty string, empty array, empty object) from an HECP (cold element array).
547
+ * @param {Array} hecp - Cold element array `[solidId, content, style, attrs, datas]`.
548
+ * @returns {Array} The trimmed array (mutates the original).
549
+ */
355
550
  static trimHecp(hecp) {
356
551
  for (var i = hecp.length - 1; i > 0; i--) {
357
552
  if (hecp[i] == null) delete hecp[i];
@@ -367,6 +562,16 @@ class Doctre {
367
562
  return hecp;
368
563
  }
369
564
 
565
+ /**
566
+ * Serializes a DOM element into a cold array.
567
+ * @param {Element} element - Target element.
568
+ * @param {boolean} [trimBobbleNode=false] - Remove whitespace-only text nodes.
569
+ * @param {boolean} [trimHecp=false] - Trim trailing empty entries.
570
+ * @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
571
+ * @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
572
+ * @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre instances.
573
+ * @returns {Array} Cold array.
574
+ */
370
575
  static frostElement(element, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
371
576
  const frozen = [];
372
577
  frozen.push(this.packTagAndMajorAttrs(element, !elementAsDoctre));
@@ -379,6 +584,12 @@ class Doctre {
379
584
  return trimHecp ? this.trimHecp(frozen) : frozen;
380
585
  }
381
586
 
587
+ /**
588
+ * Trims leading/trailing whitespace from each line of text.
589
+ * @param {string} text - Source text.
590
+ * @param {boolean} [trimIndent=false] - If true, fully removes indentation; if false, collapses to single space.
591
+ * @returns {string}
592
+ */
382
593
  static trimTextIndent(text, trimIndent = false) {
383
594
  return text.split("\n").map(line => {
384
595
  let std = line.trimStart();
@@ -389,6 +600,16 @@ class Doctre {
389
600
  }).join("\n");
390
601
  }
391
602
 
603
+ /**
604
+ * Serializes a single node to cold format. Branches by node type.
605
+ * @param {Node|Doctre|Array} node - Target node.
606
+ * @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
607
+ * @param {boolean} [trimHecp=false] - Trim trailing empty entries.
608
+ * @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
609
+ * @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
610
+ * @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre.
611
+ * @returns {Array|Doctre|string} Cold array, Doctre instance, or text string.
612
+ */
392
613
  static frostNode(node, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
393
614
  if (node instanceof Doctre) return elementAsDoctre ? node : node.frost(trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
394
615
  else if (node instanceof DocumentFragment) return this.coldify(node.childNodes, trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
@@ -400,6 +621,16 @@ class Doctre {
400
621
  }
401
622
  }
402
623
 
624
+ /**
625
+ * Serializes a node or node list into a cold array.
626
+ * @param {Node|NodeList|Doctre|string} nodeOrList - Target node/list.
627
+ * @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
628
+ * @param {boolean} [trimHecp=false] - Trim trailing empty entries.
629
+ * @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
630
+ * @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
631
+ * @param {boolean} [elementAsDoctre=!trimHecp] - Preserve child elements as Doctre.
632
+ * @returns {Array} Cold array.
633
+ */
403
634
  static coldify(nodeOrList, trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
404
635
  if (typeof nodeOrList == "string") return this.coldify([nodeOrList], trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
405
636
 
@@ -413,6 +644,16 @@ class Doctre {
413
644
  return cold;
414
645
  }
415
646
 
647
+ /**
648
+ * Serializes node/list/cold to frost (JSON string).
649
+ * @param {Node|NodeList|Array} nodeOrListOrCold - Target.
650
+ * @param {boolean|number} [prettyJson=false] - If true or a number (indent), produces pretty-printed JSON.
651
+ * @param {boolean} [trimBobbleNode=false] - Remove whitespace text nodes.
652
+ * @param {boolean} [trimHecp=true] - Trim trailing empty entries.
653
+ * @param {boolean} [styleToObject=!trimHecp] - Convert style to object.
654
+ * @param {boolean} [trimIndent=trimHecp] - Trim text indentation.
655
+ * @returns {string} Frost JSON string.
656
+ */
416
657
  static stringify(nodeOrListOrCold, prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
417
658
  const cold = this.coldify(nodeOrListOrCold, trimBobbleNode, trimHecp, styleToObject, trimIndent, false);
418
659
 
@@ -421,6 +662,17 @@ class Doctre {
421
662
  }
422
663
 
423
664
 
665
+ /**
666
+ * Injects Doctre convenience methods into Node, NodeList, Element, and jQuery prototypes.
667
+ *
668
+ * **NodeList/Node**: `coldify`, `coldified`, `stringify`, `stringified`
669
+ * **Element**: `cold`, `takeCold`, `frozen`, `takeFrozen`,
670
+ * `alive`(append), `alone`(replace+append),
671
+ * `freeze`(→data-frozen), `solid`(freeze+clear),
672
+ * `hot`(data-frozen→fragment), `worm`(hot+append), `melt`(clear+worm),
673
+ * `burn`(hot+delete data), `wormOut`(worm+delete), `meltOut`(clear+wormOut)
674
+ * **jQuery**: `coldify`, `coldified`, `stringify`, `stringified` (only when jQuery is available)
675
+ */
424
676
  static patch() {
425
677
  const attach = (cls, name, value) => Object.defineProperty(cls.prototype, name, { value, writable: true, configurable: true, enumerable: false });
426
678
  const attachGS = (cls, name, getter, setter) => Object.defineProperty(cls.prototype, name, { getter, setter, configurable: true, enumerable: false });
@@ -464,22 +716,35 @@ class Doctre {
464
716
  }
465
717
 
466
718
 
719
+ /** @type {string} Tag name. */
467
720
  tagName;
468
-
721
+ /** @type {string[]} CSS class array. */
469
722
  classes;
470
-
723
+ /** @type {string|undefined} ID. */
471
724
  id;
725
+ /** @type {string|undefined} name attribute. */
472
726
  name;
727
+ /** @type {string|undefined} type attribute. */
473
728
  type;
474
-
729
+ /** @type {Array} Child cold array (Doctre instances or strings). */
475
730
  childDoctres;
476
-
731
+ /** @type {string|Object} Style. */
477
732
  style;
733
+ /** @type {Object} Regular attributes. */
478
734
  attrs;
735
+ /** @type {Object} data-* attributes. */
479
736
  datas;
480
-
737
+ /** @type {DoctreMatchReplacer} Default token replacement map. */
481
738
  matchReplacer;
482
739
 
740
+ /**
741
+ * @param {string|Object|Array} [solidIdOrExtracted] - solidId string, extracted object, or cold array.
742
+ * @param {*} [contentData] - Child content.
743
+ * @param {string|Object} [style={}] - Style.
744
+ * @param {Object} [attrs={}] - Regular attributes.
745
+ * @param {Object} [datas={}] - data-* attributes.
746
+ * @param {DoctreMatchReplacer} [matchReplacer={}] - Token replacement map.
747
+ */
483
748
  constructor(solidIdOrExtracted, contentData, style = {}, attrs = {}, datas = {}, matchReplacer = {}) {
484
749
  if (solidIdOrExtracted instanceof Array) {
485
750
  solidIdOrExtracted = solidIdOrExtracted[0];
@@ -511,9 +776,11 @@ class Doctre {
511
776
  this.matchReplacer = matchReplacer ?? {};
512
777
  }
513
778
 
779
+ /** @type {string} Space-separated class string. */
514
780
  get className() { return this.classes.join(" "); }
515
781
  set className(value) { this.classes = value.split(" "); }
516
782
 
783
+ /** @type {Object} Major attributes object `{ class, id, name, type }`. */
517
784
  get majorAttrs() {
518
785
  return {
519
786
  class: this.className,
@@ -523,20 +790,46 @@ class Doctre {
523
790
  };
524
791
  }
525
792
 
793
+ /** @type {string} solidId string for this instance. */
526
794
  get solidId() { return Doctre.getSolidId(this.tagName, this.className, this.id, this.name, this.type); }
527
795
 
528
796
 
797
+ /** @type {Element} Creates a live DOM element from this Doctre (without default matchReplacer). */
529
798
  get live() { return Doctre.createElement(this.tagName, this.majorAttrs, this.childDoctres, this.style, this.attrs, this.datas); }
530
799
 
800
+ /**
801
+ * Creates a live DOM element with the applied matchReplacer.
802
+ * @param {DoctreMatchReplacer} [matchReplacer] - Token replacement map. Uses instance default if omitted.
803
+ * @returns {Element}
804
+ */
531
805
  fresh(matchReplacer) { return Doctre.createElement(this.tagName, this.majorAttrs, this.childDoctres, this.style, this.attrs, this.datas, matchReplacer ?? this.matchReplacer ?? {}); }
532
806
 
807
+ /**
808
+ * Serializes this Doctre to a cold array.
809
+ * @param {boolean} [trimBobbleNode=false]
810
+ * @param {boolean} [trimHecp=false]
811
+ * @param {boolean} [styleToObject=!trimHecp]
812
+ * @param {boolean} [trimIndent=trimHecp]
813
+ * @param {boolean} [elementAsDoctre=!trimHecp]
814
+ * @returns {Array} Cold array.
815
+ */
533
816
  frost(trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
534
817
  const hecp = [[this.solidId, this.cold(trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre), this.style, this.attrs, this.datas]];
535
818
  return trimHecp ? Doctre.trimHecp(hecp) : hecp;
536
819
  }
537
820
 
821
+ /** @type {Array} Compact (trimmed) frost — `frost(false, true, false, false)`. */
538
822
  get icy() { return this.frost(false, true, false, false); }
539
823
 
824
+ /**
825
+ * Serializes this Doctre to a frost JSON string.
826
+ * @param {boolean|number} [prettyJson=false]
827
+ * @param {boolean} [trimBobbleNode=false]
828
+ * @param {boolean} [trimHecp=true]
829
+ * @param {boolean} [styleToObject=!trimHecp]
830
+ * @param {boolean} [trimIndent=trimHecp]
831
+ * @returns {string} Frost JSON string.
832
+ */
540
833
  toString(prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
541
834
  const hecp = this.frost(trimBobbleNode, trimHecp, styleToObject, trimIndent, false);
542
835
  if (prettyJson == null || prettyJson === false) return JSON.stringify(hecp);
@@ -545,19 +838,50 @@ class Doctre {
545
838
 
546
839
 
547
840
 
841
+ /** @type {DocumentFragment} Restores child cold to a live DocumentFragment. */
548
842
  get chill() { return Doctre.createFragment(this.childDoctres); }
549
843
 
844
+ /**
845
+ * Serializes child content to a cold array.
846
+ * @param {boolean} [trimBobbleNode=false]
847
+ * @param {boolean} [trimHecp=false]
848
+ * @param {boolean} [styleToObject=!trimHecp]
849
+ * @param {boolean} [trimIndent=trimHecp]
850
+ * @param {boolean} [elementAsDoctre=!trimHecp]
851
+ * @returns {Array}
852
+ */
550
853
  cold(trimBobbleNode = false, trimHecp = false, styleToObject = !trimHecp, trimIndent = trimHecp, elementAsDoctre = !trimHecp) {
551
854
  return Doctre.coldify(this.childDoctres, trimBobbleNode, trimHecp, styleToObject, trimIndent, elementAsDoctre);
552
855
  }
553
856
 
857
+ /**
858
+ * Serializes child content to a frost JSON string.
859
+ * @param {boolean|number} [prettyJson=false]
860
+ * @param {boolean} [trimBobbleNode=false]
861
+ * @param {boolean} [trimHecp=true]
862
+ * @param {boolean} [styleToObject=!trimHecp]
863
+ * @param {boolean} [trimIndent=trimHecp]
864
+ * @returns {string}
865
+ */
554
866
  frozen(prettyJson = false, trimBobbleNode = false, trimHecp = true, styleToObject = !trimHecp, trimIndent = trimHecp) {
555
867
  return Doctre.stringify(this.childDoctres, prettyJson, trimBobbleNode, trimHecp, styleToObject, trimIndent);
556
868
  }
557
869
  }
558
870
 
871
+ /**
872
+ * Node array extending Array. Preserves nodes from DocumentFragment or NodeList as an array.
873
+ * Since a Fragment loses its children when appended to the DOM, use NodeArray to maintain references.
874
+ * @class
875
+ * @extends Array
876
+ */
559
877
  class NodeArray extends Array {
560
878
 
879
+ /**
880
+ * Copies nodes from a DocumentFragment or NodeList into a NodeArray.
881
+ * @param {DocumentFragment|NodeList} fragmentOrNodeList - Source.
882
+ * @param {NodeArray} [into=new NodeArray()] - Array to store results into.
883
+ * @returns {NodeArray}
884
+ */
561
885
  static box(fragmentOrNodeList, into = new NodeArray()) {
562
886
  const nodeList = fragmentOrNodeList instanceof DocumentFragment ? fragmentOrNodeList.childNodes : fragmentOrNodeList;
563
887
  for (const node of nodeList) into.push(node);