@schukai/monster 4.69.1 → 4.70.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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
 
4
4
 
5
+ ## [4.70.1] - 2026-01-03
6
+
7
+ ### Bug Fixes
8
+
9
+ - timing issues [#359](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/359)
10
+
11
+
12
+
13
+ ## [4.70.0] - 2026-01-03
14
+
15
+ ### Add Features
16
+
17
+ - Add Playwright support through Nix configuration and scripts
18
+ ### Bug Fixes
19
+
20
+ - Enhance value handling for CustomElements in input control updates [#359](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/359)
21
+
22
+
23
+
5
24
  ## [4.69.1] - 2026-01-03
6
25
 
7
26
  ### Bug Fixes
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.69.1"}
1
+ {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.70.1"}
@@ -155,9 +155,8 @@ class DataSet extends CustomElement {
155
155
  refresh() {
156
156
  // makes sure that handleDataSourceChanges is called
157
157
  return new Promise((resolve) => {
158
- this.setOption("data", {});
159
158
  queueMicrotask(() => {
160
- handleDataSourceChanges.call(this);
159
+ handleDataSourceChanges.call(this, true);
161
160
  resolve();
162
161
  });
163
162
  });
@@ -61,6 +61,7 @@ const originValuesSymbol = Symbol("originValues");
61
61
  const badgeElementSymbol = Symbol("badgeElement");
62
62
  const saveInFlightSymbol = Symbol("saveInFlight");
63
63
  const pendingResetSymbol = Symbol("pendingReset");
64
+ const fetchInFlightSymbol = Symbol("fetchInFlight");
64
65
 
65
66
  /**
66
67
  * A save button component
@@ -186,8 +187,21 @@ class SaveButton extends CustomElement {
186
187
  self[pendingResetSymbol] = true;
187
188
  return;
188
189
  }
190
+ self[fetchInFlightSymbol] = true;
189
191
  self[originValuesSymbol] = null;
190
192
  });
193
+ element.addEventListener("monster-datasource-fetched", () => {
194
+ self[fetchInFlightSymbol] = false;
195
+ if (!self[originValuesSymbol]) {
196
+ self[originValuesSymbol] = clone(
197
+ self[datasourceLinkedElementSymbol].data,
198
+ );
199
+ updateChangesState.call(self);
200
+ }
201
+ });
202
+ element.addEventListener("monster-datasource-error", () => {
203
+ self[fetchInFlightSymbol] = false;
204
+ });
191
205
  }
192
206
 
193
207
  this[datasourceLinkedElementSymbol] = element;
@@ -199,92 +213,16 @@ class SaveButton extends CustomElement {
199
213
 
200
214
  element.datasource.attachObserver(
201
215
  new Observer(function () {
216
+ if (self[fetchInFlightSymbol] === true) {
217
+ return;
218
+ }
202
219
  if (!self[originValuesSymbol]) {
203
220
  self[originValuesSymbol] = clone(
204
221
  self[datasourceLinkedElementSymbol].data,
205
222
  );
206
223
  }
207
224
 
208
- const currentValues = this.getRealSubject();
209
- const ignoreChanges = self.getOption("ignoreChanges");
210
-
211
- const result = diff(self[originValuesSymbol], currentValues);
212
- if (
213
- self.getOption("logLevel") === "debug" ||
214
- location.search.includes("logLevel=debug")
215
- ) {
216
- console.groupCollapsed("SaveButton");
217
- console.log(
218
- "originValues",
219
- JSON.parse(JSON.stringify(currentValues)),
220
- );
221
- console.log("result of diff", result);
222
- console.log("ignoreChanges", ignoreChanges);
223
-
224
- if (isArray(result) && result.length > 0) {
225
- const formattedDiff = result.map((change) => ({
226
- Operator: change?.operator,
227
- Path: change?.path?.join("."),
228
- "First Value": change?.first?.value,
229
- "First Type": change?.first?.type,
230
- "Second Value": change?.second?.value,
231
- "Second Type": change?.second?.type,
232
- }));
233
-
234
- console.table(formattedDiff);
235
- } else {
236
- console.log("There are no changes to save");
237
- }
238
- console.groupEnd();
239
- }
240
-
241
- if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
242
- const itemsToRemove = [];
243
- for (const item of result) {
244
- for (const ignorePattern of ignoreChanges) {
245
- const p = new RegExp(ignorePattern);
246
-
247
- let matchPath = item.path;
248
- if (isArray(item.path)) {
249
- matchPath = item.path.join(".");
250
- }
251
-
252
- if (p.test(matchPath)) {
253
- itemsToRemove.push(item);
254
- break;
255
- }
256
- }
257
- }
258
-
259
- for (const itemToRemove of itemsToRemove) {
260
- const index = result.indexOf(itemToRemove);
261
- if (index > -1) {
262
- result.splice(index, 1);
263
- }
264
- }
265
- }
266
-
267
- if (isArray(result) && result.length > 0) {
268
- self[stateButtonElementSymbol].setState("changed");
269
- self[stateButtonElementSymbol].setOption("disabled", false);
270
- self.setOption("changes", result.length);
271
- self.setOption(
272
- "classes.badge",
273
- new TokenList(self.getOption("classes.badge"))
274
- .remove("hidden")
275
- .toString(),
276
- );
277
- } else {
278
- self[stateButtonElementSymbol].removeState();
279
- self[stateButtonElementSymbol].setOption("disabled", true);
280
- self.setOption("changes", 0);
281
- self.setOption(
282
- "classes.badge",
283
- new TokenList(self.getOption("classes.badge"))
284
- .add("hidden")
285
- .toString(),
286
- );
287
- }
225
+ updateChangesState.call(self);
288
226
  }),
289
227
  );
290
228
  }
@@ -440,6 +378,91 @@ function initEventHandler() {
440
378
  });
441
379
  }
442
380
 
381
+ /**
382
+ * @private
383
+ */
384
+ function updateChangesState() {
385
+ const currentValues = this[datasourceLinkedElementSymbol]?.datasource?.get();
386
+ const ignoreChanges = this.getOption("ignoreChanges");
387
+ let result = diff(this[originValuesSymbol], currentValues);
388
+
389
+ if (
390
+ this.getOption("logLevel") === "debug" ||
391
+ location.search.includes("logLevel=debug")
392
+ ) {
393
+ console.groupCollapsed("SaveButton");
394
+ console.log(
395
+ "originValues",
396
+ JSON.parse(JSON.stringify(this[originValuesSymbol])),
397
+ );
398
+ console.log("currentValues", JSON.parse(JSON.stringify(currentValues)));
399
+ console.log("result of diff", result);
400
+ console.log("ignoreChanges", ignoreChanges);
401
+
402
+ if (isArray(result) && result.length > 0) {
403
+ const formattedDiff = result.map((change) => ({
404
+ Operator: change?.operator,
405
+ Path: change?.path?.join("."),
406
+ "First Value": change?.first?.value,
407
+ "First Type": change?.first?.type,
408
+ "Second Value": change?.second?.value,
409
+ "Second Type": change?.second?.type,
410
+ }));
411
+
412
+ console.table(formattedDiff);
413
+ } else {
414
+ console.log("There are no changes to save");
415
+ }
416
+ console.groupEnd();
417
+ }
418
+
419
+ if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
420
+ const itemsToRemove = [];
421
+ for (const item of result) {
422
+ for (const ignorePattern of ignoreChanges) {
423
+ const p = new RegExp(ignorePattern);
424
+
425
+ let matchPath = item.path;
426
+ if (isArray(item.path)) {
427
+ matchPath = item.path.join(".");
428
+ }
429
+
430
+ if (p.test(matchPath)) {
431
+ itemsToRemove.push(item);
432
+ break;
433
+ }
434
+ }
435
+ }
436
+
437
+ for (const itemToRemove of itemsToRemove) {
438
+ const index = result.indexOf(itemToRemove);
439
+ if (index > -1) {
440
+ result.splice(index, 1);
441
+ }
442
+ }
443
+ }
444
+
445
+ if (isArray(result) && result.length > 0) {
446
+ this[stateButtonElementSymbol].setState("changed");
447
+ this[stateButtonElementSymbol].setOption("disabled", false);
448
+ this.setOption("changes", result.length);
449
+ this.setOption(
450
+ "classes.badge",
451
+ new TokenList(this.getOption("classes.badge"))
452
+ .remove("hidden")
453
+ .toString(),
454
+ );
455
+ } else {
456
+ this[stateButtonElementSymbol].removeState();
457
+ this[stateButtonElementSymbol].setOption("disabled", true);
458
+ this.setOption("changes", 0);
459
+ this.setOption(
460
+ "classes.badge",
461
+ new TokenList(this.getOption("classes.badge")).add("hidden").toString(),
462
+ );
463
+ }
464
+ }
465
+
443
466
  /**
444
467
  * @param {Object} options
445
468
  * @deprecated 2024-12-31
@@ -16,6 +16,7 @@ import { diff } from "../../data/diff.mjs";
16
16
  import { Pathfinder } from "../../data/pathfinder.mjs";
17
17
  import { isObject, isPrimitive } from "../../types/is.mjs";
18
18
  import { Observer } from "../../types/observer.mjs";
19
+ import { clone } from "../../util/clone.mjs";
19
20
 
20
21
  export { handleDataSourceChanges, datasourceLinkedElementSymbol };
21
22
 
@@ -29,7 +30,7 @@ const dataChangeVersionSymbol = Symbol("dataChangeVersion");
29
30
  /**
30
31
  * @private
31
32
  */
32
- function handleDataSourceChanges() {
33
+ function handleDataSourceChanges(force = false) {
33
34
  if (!this[datasourceLinkedElementSymbol]) {
34
35
  return;
35
36
  }
@@ -69,15 +70,20 @@ function handleDataSourceChanges() {
69
70
  data = [];
70
71
  }
71
72
 
72
- const result = diff(data, actualDataAsObj);
73
- if (result.length === 0) {
74
- return;
75
- }
76
-
77
73
  queueMicrotask(() => {
78
74
  if (this[dataChangeVersionSymbol] !== version) {
79
75
  return;
80
76
  }
77
+ if (force) {
78
+ this.setOption("data", clone(data));
79
+ return;
80
+ }
81
+
82
+ const result = diff(data, actualDataAsObj);
83
+ if (result.length === 0) {
84
+ return;
85
+ }
86
+
81
87
  this.setOption("data", data);
82
88
  });
83
89
  }
@@ -252,6 +252,11 @@ const runLookupOnceSymbol = Symbol("runLookupOnce");
252
252
  * @type {symbol}
253
253
  */
254
254
  const cleanupOptionsListSymbol = Symbol("cleanupOptionsList");
255
+ const optionsVersionSymbol = Symbol("optionsVersion");
256
+ const pendingSelectionSymbol = Symbol("pendingSelection");
257
+ const selectionSyncScheduledSymbol = Symbol("selectionSyncScheduled");
258
+ const optionsSnapshotSymbol = Symbol("optionsSnapshot");
259
+ const selectionVersionSymbol = Symbol("selectionVersion");
255
260
 
256
261
  /**
257
262
  * @private
@@ -950,6 +955,77 @@ function processAndApplyPaginationData(data) {
950
955
  }
951
956
  }
952
957
 
958
+ /**
959
+ * @private
960
+ * @returns {number}
961
+ */
962
+ function bumpOptionsVersion() {
963
+ if (!isInteger(this[optionsVersionSymbol])) {
964
+ this[optionsVersionSymbol] = 0;
965
+ }
966
+ this[optionsVersionSymbol] += 1;
967
+ return this[optionsVersionSymbol];
968
+ }
969
+
970
+ /**
971
+ * @private
972
+ * @returns {*}
973
+ */
974
+ function getSelectionSyncState() {
975
+ const attrValue = this.getAttribute("value");
976
+ const selection = this.getOption("selection");
977
+ const options = this.getOption("options");
978
+ const optionsLength = Array.isArray(options) ? options.length : 0;
979
+ return { attrValue, selection, optionsLength };
980
+ }
981
+
982
+ /**
983
+ * @private
984
+ * @param {number} version
985
+ */
986
+ function scheduleSelectionSync(version) {
987
+ const state = getSelectionSyncState.call(this);
988
+ const selectionIsEmpty =
989
+ Array.isArray(state.selection) && state.selection.length === 0;
990
+
991
+ if (state.attrValue === null && selectionIsEmpty) {
992
+ return;
993
+ }
994
+
995
+ const pending = {
996
+ version,
997
+ selectionVersion: this[selectionVersionSymbol] || 0,
998
+ value: state.attrValue !== null ? state.attrValue : state.selection,
999
+ };
1000
+ this[pendingSelectionSymbol] = pending;
1001
+
1002
+ if (this[selectionSyncScheduledSymbol] === true) {
1003
+ return;
1004
+ }
1005
+ this[selectionSyncScheduledSymbol] = true;
1006
+
1007
+ queueMicrotask(() => {
1008
+ this[selectionSyncScheduledSymbol] = false;
1009
+ const current = this[pendingSelectionSymbol];
1010
+ if (!current) {
1011
+ return;
1012
+ }
1013
+ if (current.version !== this[optionsVersionSymbol]) {
1014
+ return;
1015
+ }
1016
+ if (current.selectionVersion !== (this[selectionVersionSymbol] || 0)) {
1017
+ return;
1018
+ }
1019
+
1020
+ setSelection
1021
+ .call(this, current.value)
1022
+ .then(() => {})
1023
+ .catch((e) => {
1024
+ addErrorAttribute(this, e);
1025
+ });
1026
+ });
1027
+ }
1028
+
953
1029
  /**
954
1030
  * @private
955
1031
  * @param data
@@ -1011,8 +1087,9 @@ function importOptionsIntern(data) {
1011
1087
  const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
1012
1088
 
1013
1089
  let options = [];
1090
+ const currentOptions = this.getOption("options");
1014
1091
  if (this[cleanupOptionsListSymbol] !== true) {
1015
- options = this.getOption("options", []);
1092
+ options = currentOptions ?? [];
1016
1093
  }
1017
1094
 
1018
1095
  this[cleanupOptionsListSymbol] = false;
@@ -1092,14 +1169,10 @@ function importOptionsIntern(data) {
1092
1169
  options,
1093
1170
  });
1094
1171
 
1095
- setTimeout(() => {
1096
- setSelection
1097
- .call(this, this.getOption("selection"))
1098
- .then(() => {})
1099
- .catch((e) => {
1100
- addErrorAttribute(this, e);
1101
- });
1102
- }, 10);
1172
+ if (options === currentOptions) {
1173
+ const version = bumpOptionsVersion.call(this);
1174
+ scheduleSelectionSync.call(this, version);
1175
+ }
1103
1176
 
1104
1177
  return this;
1105
1178
  }
@@ -1672,24 +1745,13 @@ function fetchIt(url, controlOptions) {
1672
1745
 
1673
1746
  this[lastFetchedDataSymbol] = map;
1674
1747
 
1675
- let result;
1676
- const selection = this.getOption("selection");
1677
- let newValue = [];
1678
- if (selection) {
1679
- newValue = selection;
1680
- } else if (this.hasAttribute("value")) {
1681
- newValue = this.getAttribute("value");
1682
- }
1683
-
1684
- result = setSelection.call(this, newValue);
1685
-
1686
1748
  queueMicrotask(() => {
1687
1749
  checkOptionState.call(this);
1688
1750
  setTotalText.call(this);
1689
1751
  updatePopper.call(this);
1690
1752
  setStatusOrRemoveBadges.call(this, "closed");
1691
1753
 
1692
- resolve(result);
1754
+ resolve();
1693
1755
  });
1694
1756
 
1695
1757
  return;
@@ -1828,6 +1890,7 @@ function getSummaryTemplate() {
1828
1890
  */
1829
1891
  function parseSlotsToOptions() {
1830
1892
  let options = this.getOption("options");
1893
+ const currentOptions = options;
1831
1894
  if (!isIterable(options)) {
1832
1895
  options = [];
1833
1896
  }
@@ -1855,6 +1918,8 @@ function parseSlotsToOptions() {
1855
1918
  });
1856
1919
 
1857
1920
  this.setOption("options", options);
1921
+ const version = bumpOptionsVersion.call(this);
1922
+ scheduleSelectionSync.call(this, version);
1858
1923
  }
1859
1924
 
1860
1925
  /**
@@ -2041,6 +2106,13 @@ function initOptionObserver() {
2041
2106
 
2042
2107
  self.attachObserver(
2043
2108
  new Observer(function () {
2109
+ const options = self.getOption("options");
2110
+ if (options !== self[optionsSnapshotSymbol]) {
2111
+ self[optionsSnapshotSymbol] = options;
2112
+ const version = bumpOptionsVersion.call(self);
2113
+ scheduleSelectionSync.call(self, version);
2114
+ }
2115
+
2044
2116
  new Processing(() => {
2045
2117
  try {
2046
2118
  self.updateI18n();
@@ -2782,6 +2854,11 @@ function gatherState() {
2782
2854
  throw new Error("no shadow-root is defined");
2783
2855
  }
2784
2856
 
2857
+ const inputElements = this.shadowRoot.querySelectorAll(`input[type=${type}]`);
2858
+ if (inputElements.length === 0) {
2859
+ return this;
2860
+ }
2861
+
2785
2862
  let filteredSelection = [];
2786
2863
  if (type === "radio") {
2787
2864
  const selection = [];
@@ -2799,7 +2876,7 @@ function gatherState() {
2799
2876
  filteredSelection = selection;
2800
2877
  } else {
2801
2878
  const selection = [...this.getOption("selection", [])];
2802
- const allElements = this.shadowRoot.querySelectorAll(`input[type=${type}]`);
2879
+ const allElements = inputElements;
2803
2880
  const checkedElements = this.shadowRoot.querySelectorAll(
2804
2881
  `input[type=${type}]:checked`,
2805
2882
  );
@@ -3003,6 +3080,10 @@ function areOptionsAvailableAndInitInternal() {
3003
3080
 
3004
3081
  if (updated) {
3005
3082
  this.setOption("options", options);
3083
+ if (options === currentOptions) {
3084
+ const version = bumpOptionsVersion.call(this);
3085
+ scheduleSelectionSync.call(this, version);
3086
+ }
3006
3087
  }
3007
3088
 
3008
3089
  setStatusOrRemoveBadges.call(this);
@@ -3033,11 +3114,19 @@ function checkOptionState() {
3033
3114
  return a.value;
3034
3115
  });
3035
3116
 
3117
+ const CLASSNAME = "selected";
3036
3118
  for (const e of elements) {
3119
+ const parent = e.closest(`[${ATTRIBUTE_ROLE}=option]`);
3037
3120
  if (checkedValues.indexOf(e.value) !== -1) {
3038
3121
  if (e.checked !== true) e.checked = true;
3122
+ if (parent) {
3123
+ parent.classList.add(CLASSNAME);
3124
+ }
3039
3125
  } else {
3040
3126
  if (e.checked !== false) e.checked = false;
3127
+ if (parent) {
3128
+ parent.classList.remove(CLASSNAME);
3129
+ }
3041
3130
  }
3042
3131
  }
3043
3132
  }
@@ -3188,6 +3277,11 @@ function setSelection(selection) {
3188
3277
 
3189
3278
  selection = resultSelection;
3190
3279
 
3280
+ if (!isInteger(this[selectionVersionSymbol])) {
3281
+ this[selectionVersionSymbol] = 0;
3282
+ }
3283
+ this[selectionVersionSymbol] += 1;
3284
+
3191
3285
  this.setOption("selection", selection);
3192
3286
 
3193
3287
  checkOptionState.call(this);
@@ -916,14 +916,14 @@ function getTemplate() {
916
916
  // language=HTML
917
917
  return `
918
918
  <div data-monster-role="control" part="control">
919
- <div class="prev" data-monster-role="prev" part="prev">
919
+ <div class="prev hidden" data-monster-role="prev" part="prev">
920
920
  <slot name="prev"></slot>
921
921
  </div>
922
922
  <div data-monster-role="slider" part="slides">
923
923
  <slot></slot>
924
924
  </div>
925
- <div data-monster-role="thumbnails" part="thumbnails"></div>
926
- <div class="next" data-monster-role="next" part="next">
925
+ <div class="hidden" data-monster-role="thumbnails" part="thumbnails"></div>
926
+ <div class="next hidden" data-monster-role="next" part="next">
927
927
  <slot name="next"></slot>
928
928
  </div>
929
929
  </div>`;
@@ -98,6 +98,12 @@ const attributeObserverSymbol = Symbol.for(
98
98
  const attributeMutationObserverSymbol = Symbol(
99
99
  "@schukai/monster/dom/@@mutationObserver",
100
100
  );
101
+ const childMutationObserverSymbol = Symbol(
102
+ "@schukai/monster/dom/@@childMutationObserver",
103
+ );
104
+ const childMutationTimerSymbol = Symbol(
105
+ "@schukai/monster/dom/@@childMutationTimer",
106
+ );
101
107
 
102
108
  /**
103
109
  * @private
@@ -221,6 +227,9 @@ class CustomElement extends HTMLElement {
221
227
  this[initMethodSymbol]();
222
228
  initOptionObserver.call(this);
223
229
  this[scriptHostElementSymbol] = [];
230
+ // Catch attribute changes made before connectedCallback runs.
231
+ attachAttributeChangeMutationObserver.call(this);
232
+ attachChildMutationObserver.call(this);
224
233
  }
225
234
 
226
235
  /**
@@ -679,6 +688,14 @@ class CustomElement extends HTMLElement {
679
688
  connectedCallback() {
680
689
  // Check if the object has already been initialized
681
690
  if (!hasObjectLink(this, customElementUpdaterLinkSymbol)) {
691
+ try {
692
+ initOptionsFromAttributes(
693
+ this,
694
+ this[internalSymbol].getSubject()?.["options"],
695
+ );
696
+ } catch (e) {
697
+ addErrorAttribute(this, e);
698
+ }
682
699
  // If not, call the assembleMethod to initialize the object
683
700
  this[assembleMethodSymbol]();
684
701
  }
@@ -874,6 +891,65 @@ function attachAttributeChangeMutationObserver() {
874
891
  }
875
892
  }
876
893
 
894
+ /**
895
+ * @private
896
+ * @this CustomElement
897
+ */
898
+ function attachChildMutationObserver() {
899
+ const self = this;
900
+
901
+ if (self[childMutationObserverSymbol]) {
902
+ return;
903
+ }
904
+
905
+ if (self.getOption("features.mutationObserver") !== true) {
906
+ return;
907
+ }
908
+
909
+ self[childMutationObserverSymbol] = new MutationObserver((mutations) => {
910
+ let hasAdditions = false;
911
+ for (const mutation of mutations) {
912
+ if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
913
+ hasAdditions = true;
914
+ break;
915
+ }
916
+ }
917
+
918
+ if (!hasAdditions) {
919
+ return;
920
+ }
921
+
922
+ if (self[childMutationTimerSymbol]) {
923
+ return;
924
+ }
925
+
926
+ self[childMutationTimerSymbol] = setTimeout(() => {
927
+ self[childMutationTimerSymbol] = null;
928
+ if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
929
+ return;
930
+ }
931
+
932
+ const updaters = getLinkedObjects(self, customElementUpdaterLinkSymbol);
933
+ for (const list of updaters) {
934
+ for (const updater of list) {
935
+ updater.run().catch((e) => {
936
+ addErrorAttribute(self, e);
937
+ });
938
+ }
939
+ }
940
+ }, 50);
941
+ });
942
+
943
+ try {
944
+ self[childMutationObserverSymbol].observe(self, {
945
+ childList: true,
946
+ subtree: true,
947
+ });
948
+ } catch (e) {
949
+ addErrorAttribute(self, e);
950
+ }
951
+ }
952
+
877
953
  /**
878
954
  * @this CustomElement
879
955
  * @private
@@ -1075,6 +1075,10 @@ function handleInputControlAttributeUpdate(element, name, value) {
1075
1075
  if (name === "value") {
1076
1076
  element.value = value === undefined ? "" : value;
1077
1077
  }
1078
+ } else if (name === "value" && element instanceof CustomElement) {
1079
+ if ("value" in element) {
1080
+ element.value = value === undefined ? "" : value;
1081
+ }
1078
1082
  }
1079
1083
  }
1080
1084