@twobirds/microcomponents 0.10.3 → 0.12.1
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/README.md +13 -3
- package/dist/MC.min.js +1 -1
- package/dist/autoload.min.js +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/dev.d.ts +3 -1
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dispatch.d.ts +2 -0
- package/dist/cli/dispatch.d.ts.map +1 -1
- package/dist/cli/index.js +110 -18
- package/dist/cli/preview.d.ts +3 -1
- package/dist/cli/preview.d.ts.map +1 -1
- package/dist/core/MC.d.ts +1 -1
- package/dist/core/MC.d.ts.map +1 -1
- package/dist/core/elements.d.ts.map +1 -1
- package/dist/core/elements.js +12 -5
- package/dist/core/mcGuards.js +6 -1
- package/dist/docs/cli.d.ts +1 -1
- package/dist/elements.min.js +1 -1
- package/dist/formValues.min.js +1 -1
- package/dist/helpers.min.js +1 -0
- package/dist/mcGuards.min.js +1 -1
- package/dist/mcp/api.json +30 -4
- package/dist/mcp/concepts/mc-types.md +15 -8
- package/dist/mcp/docs.d.ts +55 -0
- package/dist/mcp/docs.d.ts.map +1 -0
- package/dist/mcp/index.js +320 -203
- package/dist/mcp/server.d.ts +43 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/microcomponents.d.ts +1 -0
- package/dist/microcomponents.d.ts.map +1 -1
- package/dist/microcomponents.js +84 -39
- package/dist/microcomponents.min.js +1 -1
- package/dist/observables.min.js +1 -1
- package/dist/placeholders.min.js +1 -0
- package/dist/state/formValues.d.ts.map +1 -1
- package/dist/state/formValues.js +59 -31
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/observables.d.ts.map +1 -1
- package/dist/state/observables.js +55 -28
- package/dist/state/placeholders.d.ts +0 -1
- package/dist/state/placeholders.d.ts.map +1 -1
- package/dist/state/placeholders.js +1980 -0
- package/dist/utils/autoload.d.ts.map +1 -1
- package/dist/utils/autoload.js +1451 -0
- package/dist/utils/events.d.ts +1 -1
- package/dist/utils/events.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +3 -0
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/utils/helpers.js +693 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +23 -5
package/dist/state/formValues.js
CHANGED
|
@@ -619,7 +619,12 @@ function bindTemplateEvents(rootElement, instance) {
|
|
|
619
619
|
//#endregion
|
|
620
620
|
//#region src/core/mcGuards.ts
|
|
621
621
|
function isMcHost(element, key) {
|
|
622
|
-
|
|
622
|
+
if (typeof HTMLElement === "undefined" || !(element instanceof HTMLElement)) return false;
|
|
623
|
+
if (!("_mc" in element)) return false;
|
|
624
|
+
if (key === void 0) return true;
|
|
625
|
+
const mc = element._mc;
|
|
626
|
+
if (typeof mc !== "object" || mc === null) return false;
|
|
627
|
+
return key in mc;
|
|
623
628
|
}
|
|
624
629
|
//#endregion
|
|
625
630
|
//#region src/core/MC.ts
|
|
@@ -627,7 +632,7 @@ function add(targetHTMLElement, key, element = {}) {
|
|
|
627
632
|
const node = targetHTMLElement;
|
|
628
633
|
if (!("_mc" in targetHTMLElement)) node._mc = new DC(targetHTMLElement);
|
|
629
634
|
const _mc = node._mc;
|
|
630
|
-
if (key.length
|
|
635
|
+
if (key.length) {
|
|
631
636
|
_mc[key] = element;
|
|
632
637
|
if (targetHTMLElement instanceof HTMLElement && !targetHTMLElement.getAttribute("data-mc")) targetHTMLElement.setAttribute("data-mc", "");
|
|
633
638
|
}
|
|
@@ -793,7 +798,7 @@ runs once after the constructor.
|
|
|
793
798
|
@group Micro Components
|
|
794
799
|
*/
|
|
795
800
|
var McBase = class {
|
|
796
|
-
|
|
801
|
+
#target;
|
|
797
802
|
/**
|
|
798
803
|
* Loaded asset cache, keyed by camelCase descriptor (`'targetHtml'` → `.target.html`).
|
|
799
804
|
* Inlined by the bundler in a bundled build, filled by `loadAssets()` in dev/autoload.
|
|
@@ -822,7 +827,7 @@ var McBase = class {
|
|
|
822
827
|
@param target - The object or element this microcomponent represents.
|
|
823
828
|
*/
|
|
824
829
|
constructor(target) {
|
|
825
|
-
this
|
|
830
|
+
this.#target = new WeakRef(target || {});
|
|
826
831
|
const ctor = this.constructor;
|
|
827
832
|
if (this instanceof DC && this.constructor !== DC) autoAttachListeners(this);
|
|
828
833
|
const remaining = (ctor.assets ?? []).filter((key) => !ctor._assets[key]);
|
|
@@ -849,7 +854,7 @@ var McBase = class {
|
|
|
849
854
|
@returns The target object.
|
|
850
855
|
*/
|
|
851
856
|
get target() {
|
|
852
|
-
return this.
|
|
857
|
+
return this.#target.deref();
|
|
853
858
|
}
|
|
854
859
|
/**
|
|
855
860
|
The loaded assets for this component instance.
|
|
@@ -1458,7 +1463,8 @@ data object and updates the corresponding DOM locations when notified of changes
|
|
|
1458
1463
|
*/
|
|
1459
1464
|
var Placeholders = class extends DC {
|
|
1460
1465
|
data = {};
|
|
1461
|
-
oldDisplay = "";
|
|
1466
|
+
#oldDisplay = "";
|
|
1467
|
+
#restored = false;
|
|
1462
1468
|
/**
|
|
1463
1469
|
Creates a new `Placeholders` instance for the given HTML element.
|
|
1464
1470
|
|
|
@@ -1474,9 +1480,22 @@ var Placeholders = class extends DC {
|
|
|
1474
1480
|
observe(this);
|
|
1475
1481
|
this.#attachCallbacks();
|
|
1476
1482
|
}
|
|
1483
|
+
/**
|
|
1484
|
+
Replaces every occurrence of one placeholder in a template.
|
|
1485
|
+
The placeholder is escaped into a global regex, so a repeated `{x}` is fully
|
|
1486
|
+
substituted — `String.replace` with a string pattern replaces one occurrence only.
|
|
1487
|
+
@param template - The template holding the placeholder.
|
|
1488
|
+
@param placeholder - The `{key}` token to substitute.
|
|
1489
|
+
@param value - The replacement value.
|
|
1490
|
+
@returns The template with every occurrence replaced.
|
|
1491
|
+
*/
|
|
1492
|
+
#substitute(template, placeholder, value) {
|
|
1493
|
+
placeholder.replace(/[\{\}]/g, "");
|
|
1494
|
+
const escaped = placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1495
|
+
return template.replace(new RegExp(escaped, "g"), value);
|
|
1496
|
+
}
|
|
1477
1497
|
#attachCallbacks() {
|
|
1478
1498
|
const target = this.target;
|
|
1479
|
-
let hide = false;
|
|
1480
1499
|
(target.getAttributeNames ? target.getAttributeNames() : []).filter((attr) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g)).forEach((attr) => {
|
|
1481
1500
|
const placeholders = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
|
|
1482
1501
|
/* v8 ignore next -- attr passed the filter above, so its value is a non-null string */
|
|
@@ -1484,32 +1503,36 @@ var Placeholders = class extends DC {
|
|
|
1484
1503
|
this.data.subscribe(((template) => (data) => {
|
|
1485
1504
|
let result = template;
|
|
1486
1505
|
placeholders.forEach((placeholder) => {
|
|
1487
|
-
result = result
|
|
1506
|
+
result = this.#substitute(result, placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1488
1507
|
});
|
|
1489
1508
|
target.setAttribute(attr, result);
|
|
1490
1509
|
})(attrTemplate));
|
|
1491
1510
|
});
|
|
1492
|
-
[...target.childNodes].filter((childNode) => {
|
|
1511
|
+
const textNodes = [...target.childNodes].filter((childNode) => {
|
|
1493
1512
|
return childNode.nodeType === 3 && (childNode.nodeValue || "").match(/\{[^\{\}]*\}/g);
|
|
1494
|
-
}).forEach((childNode) => {
|
|
1495
|
-
hide = true;
|
|
1496
|
-
/* v8 ignore next -- the filter above only admits text nodes with a non-empty
|
|
1497
|
-
nodeValue, so the ?? fallback is unreachable */
|
|
1498
|
-
const textTemplate = childNode.nodeValue ?? "";
|
|
1499
|
-
const placeholders = new Set(textTemplate.match(/\{[^\{\}]*\}/g));
|
|
1500
|
-
this.data.subscribe(((template) => (data) => {
|
|
1501
|
-
let result = template;
|
|
1502
|
-
placeholders.forEach((placeholder) => {
|
|
1503
|
-
result = result.replace(placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1504
|
-
});
|
|
1505
|
-
if (this.oldDisplay) target.style = this.oldDisplay;
|
|
1506
|
-
else target.removeAttribute("style");
|
|
1507
|
-
delete this.oldDisplay;
|
|
1508
|
-
childNode.nodeValue = result;
|
|
1509
|
-
})(textTemplate));
|
|
1510
|
-
this.oldDisplay = target.getAttribute("style") || "";
|
|
1511
|
-
if (hide && !inputTags.includes(target.tagName) && target.tagName !== "FIELDSET") target.style.display = "none";
|
|
1512
1513
|
});
|
|
1514
|
+
if (textNodes.length) {
|
|
1515
|
+
this.#oldDisplay = target.getAttribute("style") || "";
|
|
1516
|
+
textNodes.forEach((childNode) => {
|
|
1517
|
+
/* v8 ignore next -- the filter above only admits text nodes with a non-empty
|
|
1518
|
+
nodeValue, so the ?? fallback is unreachable */
|
|
1519
|
+
const textTemplate = childNode.nodeValue ?? "";
|
|
1520
|
+
const placeholders = new Set(textTemplate.match(/\{[^\{\}]*\}/g));
|
|
1521
|
+
this.data.subscribe(((template) => (data) => {
|
|
1522
|
+
let result = template;
|
|
1523
|
+
placeholders.forEach((placeholder) => {
|
|
1524
|
+
result = this.#substitute(result, placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1525
|
+
});
|
|
1526
|
+
if (!this.#restored) {
|
|
1527
|
+
this.#restored = true;
|
|
1528
|
+
if (this.#oldDisplay) target.style = this.#oldDisplay;
|
|
1529
|
+
else target.removeAttribute("style");
|
|
1530
|
+
}
|
|
1531
|
+
childNode.nodeValue = result;
|
|
1532
|
+
})(textTemplate));
|
|
1533
|
+
if (!inputTags.includes(target.tagName) && target.tagName !== "FIELDSET") target.style.display = "none";
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1513
1536
|
}
|
|
1514
1537
|
/**
|
|
1515
1538
|
Handles a `data` custom event to update the internal placeholder data.
|
|
@@ -1757,7 +1780,7 @@ function makeObservable(val) {
|
|
|
1757
1780
|
`{count}` placeholders update on every change.
|
|
1758
1781
|
*/
|
|
1759
1782
|
bind(target) {
|
|
1760
|
-
if (!isBrowser()) return;
|
|
1783
|
+
if (!isBrowser()) return this;
|
|
1761
1784
|
if (isObservableObject(this.valueOf())) {
|
|
1762
1785
|
makePlaceholders(target);
|
|
1763
1786
|
const placeholders = [target, ...target.querySelectorAll("[data-mc]")].filter((e) => {
|
|
@@ -1906,8 +1929,12 @@ function observe(target, propertyName) {
|
|
|
1906
1929
|
if (key[0] === "_" || current === void 0) return;
|
|
1907
1930
|
const wrappedVal = current;
|
|
1908
1931
|
let o = new (getConstructor(wrappedVal))(wrappedVal);
|
|
1932
|
+
let notifyPending = false;
|
|
1909
1933
|
const debouncedNotify = function() {
|
|
1934
|
+
if (notifyPending) return;
|
|
1935
|
+
notifyPending = true;
|
|
1910
1936
|
queueMicrotask(function() {
|
|
1937
|
+
notifyPending = false;
|
|
1911
1938
|
o.notify();
|
|
1912
1939
|
});
|
|
1913
1940
|
};
|
|
@@ -2130,12 +2157,13 @@ var RadioHandler = class extends InputBase {
|
|
|
2130
2157
|
/**
|
|
2131
2158
|
Sets the selected radio button by value.
|
|
2132
2159
|
Finds and checks the first radio input matching the specified value within the same group.
|
|
2160
|
+
An unknown value has no matching radio in the group, so the group is left untouched —
|
|
2161
|
+
the setter never throws.
|
|
2133
2162
|
@param value - The value to match against radio inputs in this group.
|
|
2134
2163
|
*/
|
|
2135
2164
|
set val(value) {
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
arr.filter((e) => e.getAttribute("value") === value).shift().checked = true;
|
|
2165
|
+
const match = [...this.#e.form?.querySelectorAll(`input[type="radio"][name="${this.#e.name}"]`) ?? []].filter((e) => e.getAttribute("value") === value).shift();
|
|
2166
|
+
if (match) match.checked = true;
|
|
2139
2167
|
}
|
|
2140
2168
|
};
|
|
2141
2169
|
/**
|
package/dist/state/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { observe, observePlugin, isAlreadyObserved } from './observables.js';
|
|
|
7
7
|
export type { Observable, Callback, Observed, ObservedKey, Unobserved } from './observables.js';
|
|
8
8
|
/** @group State */
|
|
9
9
|
export { formValues, formValuePlugin } from './formValues.js';
|
|
10
|
+
/** @group State */
|
|
11
|
+
export { makePlaceholders } from './placeholders.js';
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA;;EAEE;AACF,mBAAmB;AACnB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,mBAAmB;AACnB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChG,mBAAmB;AACnB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA;;EAEE;AACF,mBAAmB;AACnB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,mBAAmB;AACnB,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChG,mBAAmB;AACnB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC9D,mBAAmB;AACnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observables.d.ts","sourceRoot":"","sources":["../../src/state/observables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyEE;AAkBF;;;;;;;;;EASE;AACF,MAAM,MAAM,QAAQ,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAEvD;;;;;;;;;;;;;;;EAeE;AACF,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG;IACzC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChD,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,gBAAgB,GAAG,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACzE,cAAc;IACd,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;CAC3B,CAAC;
|
|
1
|
+
{"version":3,"file":"observables.d.ts","sourceRoot":"","sources":["../../src/state/observables.ts"],"names":[],"mappings":"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"}
|
|
@@ -619,7 +619,12 @@ function bindTemplateEvents(rootElement, instance) {
|
|
|
619
619
|
//#endregion
|
|
620
620
|
//#region src/core/mcGuards.ts
|
|
621
621
|
function isMcHost(element, key) {
|
|
622
|
-
|
|
622
|
+
if (typeof HTMLElement === "undefined" || !(element instanceof HTMLElement)) return false;
|
|
623
|
+
if (!("_mc" in element)) return false;
|
|
624
|
+
if (key === void 0) return true;
|
|
625
|
+
const mc = element._mc;
|
|
626
|
+
if (typeof mc !== "object" || mc === null) return false;
|
|
627
|
+
return key in mc;
|
|
623
628
|
}
|
|
624
629
|
//#endregion
|
|
625
630
|
//#region src/core/MC.ts
|
|
@@ -627,7 +632,7 @@ function add(targetHTMLElement, key, element = {}) {
|
|
|
627
632
|
const node = targetHTMLElement;
|
|
628
633
|
if (!("_mc" in targetHTMLElement)) node._mc = new DC(targetHTMLElement);
|
|
629
634
|
const _mc = node._mc;
|
|
630
|
-
if (key.length
|
|
635
|
+
if (key.length) {
|
|
631
636
|
_mc[key] = element;
|
|
632
637
|
if (targetHTMLElement instanceof HTMLElement && !targetHTMLElement.getAttribute("data-mc")) targetHTMLElement.setAttribute("data-mc", "");
|
|
633
638
|
}
|
|
@@ -793,7 +798,7 @@ runs once after the constructor.
|
|
|
793
798
|
@group Micro Components
|
|
794
799
|
*/
|
|
795
800
|
var McBase = class {
|
|
796
|
-
|
|
801
|
+
#target;
|
|
797
802
|
/**
|
|
798
803
|
* Loaded asset cache, keyed by camelCase descriptor (`'targetHtml'` → `.target.html`).
|
|
799
804
|
* Inlined by the bundler in a bundled build, filled by `loadAssets()` in dev/autoload.
|
|
@@ -822,7 +827,7 @@ var McBase = class {
|
|
|
822
827
|
@param target - The object or element this microcomponent represents.
|
|
823
828
|
*/
|
|
824
829
|
constructor(target) {
|
|
825
|
-
this
|
|
830
|
+
this.#target = new WeakRef(target || {});
|
|
826
831
|
const ctor = this.constructor;
|
|
827
832
|
if (this instanceof DC && this.constructor !== DC) autoAttachListeners(this);
|
|
828
833
|
const remaining = (ctor.assets ?? []).filter((key) => !ctor._assets[key]);
|
|
@@ -849,7 +854,7 @@ var McBase = class {
|
|
|
849
854
|
@returns The target object.
|
|
850
855
|
*/
|
|
851
856
|
get target() {
|
|
852
|
-
return this.
|
|
857
|
+
return this.#target.deref();
|
|
853
858
|
}
|
|
854
859
|
/**
|
|
855
860
|
The loaded assets for this component instance.
|
|
@@ -1458,7 +1463,8 @@ data object and updates the corresponding DOM locations when notified of changes
|
|
|
1458
1463
|
*/
|
|
1459
1464
|
var Placeholders = class extends DC {
|
|
1460
1465
|
data = {};
|
|
1461
|
-
oldDisplay = "";
|
|
1466
|
+
#oldDisplay = "";
|
|
1467
|
+
#restored = false;
|
|
1462
1468
|
/**
|
|
1463
1469
|
Creates a new `Placeholders` instance for the given HTML element.
|
|
1464
1470
|
|
|
@@ -1474,9 +1480,22 @@ var Placeholders = class extends DC {
|
|
|
1474
1480
|
observe(this);
|
|
1475
1481
|
this.#attachCallbacks();
|
|
1476
1482
|
}
|
|
1483
|
+
/**
|
|
1484
|
+
Replaces every occurrence of one placeholder in a template.
|
|
1485
|
+
The placeholder is escaped into a global regex, so a repeated `{x}` is fully
|
|
1486
|
+
substituted — `String.replace` with a string pattern replaces one occurrence only.
|
|
1487
|
+
@param template - The template holding the placeholder.
|
|
1488
|
+
@param placeholder - The `{key}` token to substitute.
|
|
1489
|
+
@param value - The replacement value.
|
|
1490
|
+
@returns The template with every occurrence replaced.
|
|
1491
|
+
*/
|
|
1492
|
+
#substitute(template, placeholder, value) {
|
|
1493
|
+
placeholder.replace(/[\{\}]/g, "");
|
|
1494
|
+
const escaped = placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1495
|
+
return template.replace(new RegExp(escaped, "g"), value);
|
|
1496
|
+
}
|
|
1477
1497
|
#attachCallbacks() {
|
|
1478
1498
|
const target = this.target;
|
|
1479
|
-
let hide = false;
|
|
1480
1499
|
(target.getAttributeNames ? target.getAttributeNames() : []).filter((attr) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g)).forEach((attr) => {
|
|
1481
1500
|
const placeholders = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
|
|
1482
1501
|
/* v8 ignore next -- attr passed the filter above, so its value is a non-null string */
|
|
@@ -1484,32 +1503,36 @@ var Placeholders = class extends DC {
|
|
|
1484
1503
|
this.data.subscribe(((template) => (data) => {
|
|
1485
1504
|
let result = template;
|
|
1486
1505
|
placeholders.forEach((placeholder) => {
|
|
1487
|
-
result = result
|
|
1506
|
+
result = this.#substitute(result, placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1488
1507
|
});
|
|
1489
1508
|
target.setAttribute(attr, result);
|
|
1490
1509
|
})(attrTemplate));
|
|
1491
1510
|
});
|
|
1492
|
-
[...target.childNodes].filter((childNode) => {
|
|
1511
|
+
const textNodes = [...target.childNodes].filter((childNode) => {
|
|
1493
1512
|
return childNode.nodeType === 3 && (childNode.nodeValue || "").match(/\{[^\{\}]*\}/g);
|
|
1494
|
-
}).forEach((childNode) => {
|
|
1495
|
-
hide = true;
|
|
1496
|
-
/* v8 ignore next -- the filter above only admits text nodes with a non-empty
|
|
1497
|
-
nodeValue, so the ?? fallback is unreachable */
|
|
1498
|
-
const textTemplate = childNode.nodeValue ?? "";
|
|
1499
|
-
const placeholders = new Set(textTemplate.match(/\{[^\{\}]*\}/g));
|
|
1500
|
-
this.data.subscribe(((template) => (data) => {
|
|
1501
|
-
let result = template;
|
|
1502
|
-
placeholders.forEach((placeholder) => {
|
|
1503
|
-
result = result.replace(placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1504
|
-
});
|
|
1505
|
-
if (this.oldDisplay) target.style = this.oldDisplay;
|
|
1506
|
-
else target.removeAttribute("style");
|
|
1507
|
-
delete this.oldDisplay;
|
|
1508
|
-
childNode.nodeValue = result;
|
|
1509
|
-
})(textTemplate));
|
|
1510
|
-
this.oldDisplay = target.getAttribute("style") || "";
|
|
1511
|
-
if (hide && !inputTags.includes(target.tagName) && target.tagName !== "FIELDSET") target.style.display = "none";
|
|
1512
1513
|
});
|
|
1514
|
+
if (textNodes.length) {
|
|
1515
|
+
this.#oldDisplay = target.getAttribute("style") || "";
|
|
1516
|
+
textNodes.forEach((childNode) => {
|
|
1517
|
+
/* v8 ignore next -- the filter above only admits text nodes with a non-empty
|
|
1518
|
+
nodeValue, so the ?? fallback is unreachable */
|
|
1519
|
+
const textTemplate = childNode.nodeValue ?? "";
|
|
1520
|
+
const placeholders = new Set(textTemplate.match(/\{[^\{\}]*\}/g));
|
|
1521
|
+
this.data.subscribe(((template) => (data) => {
|
|
1522
|
+
let result = template;
|
|
1523
|
+
placeholders.forEach((placeholder) => {
|
|
1524
|
+
result = this.#substitute(result, placeholder, String(data[placeholder.replace(/[\{\}]/g, "")]));
|
|
1525
|
+
});
|
|
1526
|
+
if (!this.#restored) {
|
|
1527
|
+
this.#restored = true;
|
|
1528
|
+
if (this.#oldDisplay) target.style = this.#oldDisplay;
|
|
1529
|
+
else target.removeAttribute("style");
|
|
1530
|
+
}
|
|
1531
|
+
childNode.nodeValue = result;
|
|
1532
|
+
})(textTemplate));
|
|
1533
|
+
if (!inputTags.includes(target.tagName) && target.tagName !== "FIELDSET") target.style.display = "none";
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1513
1536
|
}
|
|
1514
1537
|
/**
|
|
1515
1538
|
Handles a `data` custom event to update the internal placeholder data.
|
|
@@ -1757,7 +1780,7 @@ function makeObservable(val) {
|
|
|
1757
1780
|
`{count}` placeholders update on every change.
|
|
1758
1781
|
*/
|
|
1759
1782
|
bind(target) {
|
|
1760
|
-
if (!isBrowser()) return;
|
|
1783
|
+
if (!isBrowser()) return this;
|
|
1761
1784
|
if (isObservableObject(this.valueOf())) {
|
|
1762
1785
|
makePlaceholders(target);
|
|
1763
1786
|
const placeholders = [target, ...target.querySelectorAll("[data-mc]")].filter((e) => {
|
|
@@ -1906,8 +1929,12 @@ function observe(target, propertyName) {
|
|
|
1906
1929
|
if (key[0] === "_" || current === void 0) return;
|
|
1907
1930
|
const wrappedVal = current;
|
|
1908
1931
|
let o = new (getConstructor(wrappedVal))(wrappedVal);
|
|
1932
|
+
let notifyPending = false;
|
|
1909
1933
|
const debouncedNotify = function() {
|
|
1934
|
+
if (notifyPending) return;
|
|
1935
|
+
notifyPending = true;
|
|
1910
1936
|
queueMicrotask(function() {
|
|
1937
|
+
notifyPending = false;
|
|
1911
1938
|
o.notify();
|
|
1912
1939
|
});
|
|
1913
1940
|
};
|
|
@@ -21,7 +21,6 @@ data object and updates the corresponding DOM locations when notified of changes
|
|
|
21
21
|
declare class Placeholders extends DC {
|
|
22
22
|
#private;
|
|
23
23
|
data: Observable<Record<string, unknown>>;
|
|
24
|
-
oldDisplay?: string;
|
|
25
24
|
/**
|
|
26
25
|
Creates a new `Placeholders` instance for the given HTML element.
|
|
27
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../../src/state/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE;AAEF,OAAO,EAAE,EAAE,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAoD5D;;;;;;EAME;AACF,cAAM,YAAa,SAAQ,EAAE;;IAE5B,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAwD;
|
|
1
|
+
{"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../../src/state/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE;AAEF,OAAO,EAAE,EAAE,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAoD5D;;;;;;EAME;AACF,cAAM,YAAa,SAAQ,EAAE;;IAE5B,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAwD;IAQjG;;;;;;;;MAQE;gBACU,MAAM,EAAE,WAAW;IA+G/B;;;;;;;MAOE;IACF,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAOzD;AAmBD;;;;;;;EAOE;AACF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,gBAAgB,GAAG,UAAU,GAAG,IAAI,CAK3F;AAED;;;;EAIE;AACF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE;IAAE,aAAa,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC"}
|