@schukai/monster 4.85.0 → 4.85.2

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,22 @@
2
2
 
3
3
 
4
4
 
5
+ ## [4.85.2] - 2026-01-08
6
+
7
+ ### Bug Fixes
8
+
9
+ - Rename issue [#368](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/368) to closed and add issue [#369](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/369)
10
+
11
+
12
+
13
+ ## [4.85.1] - 2026-01-08
14
+
15
+ ### Bug Fixes
16
+
17
+ - Add new issue page and enhanced message state button functionality
18
+
19
+
20
+
5
21
  ## [4.85.0] - 2026-01-08
6
22
 
7
23
  ### Add Features
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.85.0"}
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.85.2"}
@@ -166,7 +166,8 @@ function initControlReferences() {
166
166
  this[errorElementSymbol] = this.shadowRoot.querySelector(
167
167
  "monster-context-error",
168
168
  );
169
- this[spinnerElementSymbol] = this.shadowRoot.querySelector(".monster-spinner");
169
+ this[spinnerElementSymbol] =
170
+ this.shadowRoot.querySelector(".monster-spinner");
170
171
  }
171
172
 
172
173
  /**
@@ -68,7 +68,16 @@ function doDiff(a, b, path, diff) {
68
68
  const currDiff = diff || [];
69
69
 
70
70
  if (typeA === typeB && (typeA === "object" || typeA === "array")) {
71
- getKeys(a, b, typeA).forEach((v) => {
71
+ const keys = getKeys(a, b, typeA);
72
+ if (keys.size === 0) {
73
+ const o = getOperator(a, b, typeA, typeB);
74
+ if (o !== undefined) {
75
+ currDiff.push(buildResult(a, b, o, currPath));
76
+ }
77
+ return currDiff;
78
+ }
79
+
80
+ keys.forEach((v) => {
72
81
  if (!Object.prototype.hasOwnProperty.call(a, v)) {
73
82
  currDiff.push(buildResult(a[v], b[v], "add", currPath.concat(v)));
74
83
  } else if (!Object.prototype.hasOwnProperty.call(b, v)) {
@@ -147,8 +147,7 @@ class ControlFlow {
147
147
  */
148
148
  static onState(events, run) {
149
149
  return {
150
- on: (ctx) =>
151
- ctx.source === "state" && matchEvent(ctx.event, events),
150
+ on: (ctx) => ctx.source === "state" && matchEvent(ctx.event, events),
152
151
  run,
153
152
  };
154
153
  }
@@ -22,6 +22,7 @@ import { parseDataURL } from "../types/dataurl.mjs";
22
22
  import { getGlobalObject } from "../types/global.mjs";
23
23
  import {
24
24
  isArray,
25
+ isElement,
25
26
  isFunction,
26
27
  isIterable,
27
28
  isObject,
@@ -1080,6 +1081,16 @@ function syncUpdaterSubject(target, source) {
1080
1081
  }
1081
1082
 
1082
1083
  for (const [key, value] of Object.entries(source)) {
1084
+ if (
1085
+ isElement(value) ||
1086
+ (typeof Document !== "undefined" && value instanceof Document) ||
1087
+ (typeof DocumentFragment !== "undefined" &&
1088
+ value instanceof DocumentFragment)
1089
+ ) {
1090
+ target[key] = value;
1091
+ continue;
1092
+ }
1093
+
1083
1094
  if (isArray(value)) {
1084
1095
  if (!isArray(target?.[key])) {
1085
1096
  target[key] = [];
@@ -1090,6 +1101,11 @@ function syncUpdaterSubject(target, source) {
1090
1101
  }
1091
1102
 
1092
1103
  if (isObject(value)) {
1104
+ const proto = Object.getPrototypeOf(value);
1105
+ if (proto && proto !== Object.prototype) {
1106
+ target[key] = value;
1107
+ continue;
1108
+ }
1093
1109
  if (!isObject(target?.[key]) || isArray(target?.[key])) {
1094
1110
  target[key] = {};
1095
1111
  }
@@ -13,7 +13,7 @@
13
13
  */
14
14
 
15
15
  import { Base } from "./base.mjs";
16
- import { isArray, isObject, isPrimitive } from "./is.mjs";
16
+ import { isArray, isElement, isObject, isPrimitive } from "./is.mjs";
17
17
  import { Observer } from "./observer.mjs";
18
18
  import { ObserverList } from "./observerlist.mjs";
19
19
  import { validateObject } from "./validate.mjs";
@@ -165,6 +165,14 @@ function getHandler() {
165
165
  return value;
166
166
  }
167
167
 
168
+ if (isElement(value)) {
169
+ return value;
170
+ }
171
+
172
+ if (typeof Node !== "undefined" && value instanceof Node) {
173
+ return value;
174
+ }
175
+
168
176
  // set value as proxy if object or array
169
177
  if (isArray(value) || isObject(value)) {
170
178
  if (proxy.objectMap.has(value)) {
@@ -80,6 +80,29 @@ function clone(obj) {
80
80
  return new URL(obj.toString());
81
81
  }
82
82
 
83
+ // Handle RegExp
84
+ if (obj instanceof RegExp) {
85
+ return new RegExp(obj.source, obj.flags);
86
+ }
87
+
88
+ // Handle Map
89
+ if (obj instanceof Map) {
90
+ const copy = new Map();
91
+ for (const [key, value] of obj.entries()) {
92
+ copy.set(clone(key), clone(value));
93
+ }
94
+ return copy;
95
+ }
96
+
97
+ // Handle Set
98
+ if (obj instanceof Set) {
99
+ const copy = new Set();
100
+ for (const value of obj.values()) {
101
+ copy.add(clone(value));
102
+ }
103
+ return copy;
104
+ }
105
+
83
106
  /** Do not clone DOM nodes */
84
107
  if (typeof Element !== "undefined" && obj instanceof Element) return obj;
85
108
  if (typeof Document !== "undefined" && obj instanceof Document) return obj;
@@ -65,7 +65,7 @@ describe('Diff', function () {
65
65
 
66
66
  it('Diff value with null ', function () {
67
67
  let d = diff(obj1, obj2);
68
- expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["count"],"first":{"value":1,"type":"number"},"second":{"value":2,"type":"number"}},{"operator":"delete","path":["info"],"first":{"value":"test","type":"string"}}]');
68
+ expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["count"],"first":{"value":1,"type":"number"},"second":{"value":2,"type":"number"}},{"operator":"delete","path":["info"],"first":{"value":"test","type":"string"}},{"operator":"update","path":["exchange"],"first":{"value":[],"type":"object"},"second":{"value":[],"type":"object"}}]');
69
69
  });
70
70
 
71
71
  it('Diff identical value with null ', function () {
@@ -86,6 +86,21 @@ describe('Diff', function () {
86
86
  const date5 = new Date(Date.parse('04 Dec 1995 00:12:01 GMT')); // Date
87
87
  const date6 = new Date(Date.parse('04 Dec 1995 00:12:02 GMT')); // Date
88
88
 
89
+ const hiddenKey = Symbol("hidden");
90
+ class HiddenState {
91
+ constructor(value) {
92
+ this[hiddenKey] = value;
93
+ }
94
+
95
+ get value() {
96
+ return this[hiddenKey];
97
+ }
98
+
99
+ getClone() {
100
+ return new HiddenState(this.value);
101
+ }
102
+ }
103
+
89
104
  [
90
105
 
91
106
  [
@@ -146,6 +161,15 @@ describe('Diff', function () {
146
161
  },
147
162
  '[]'
148
163
  ],
164
+ [
165
+ {
166
+ a: new HiddenState("a")
167
+ },
168
+ {
169
+ a: new HiddenState("b")
170
+ },
171
+ '[{"operator":"update","path":["a"],"first":{"value":{},"type":"object","instance":"HiddenState"},"second":{"value":{},"type":"object","instance":"HiddenState"}}]'
172
+ ],
149
173
  [
150
174
  {},
151
175
  {
@@ -238,4 +262,4 @@ describe('Diff', function () {
238
262
 
239
263
  });
240
264
 
241
- })
265
+ })
@@ -27,7 +27,7 @@ const updaterSymbolSymbol = Symbol.for(updaterSymbolKey);
27
27
 
28
28
  describe('DOM', function () {
29
29
 
30
- let CustomElement, registerCustomElement, TestComponent, document, TestComponent2, assignUpdaterToElement,
30
+ let CustomElement, registerCustomElement, TestComponent, document, TestComponent2, TestStateComponent, HiddenStateClass, assignUpdaterToElement,
31
31
  addObjectWithUpdaterToElement;
32
32
 
33
33
  describe("assignUpdaterToElement", function () {
@@ -184,6 +184,40 @@ describe('DOM', function () {
184
184
 
185
185
  registerCustomElement(TestComponent2)
186
186
 
187
+ const hiddenKey = Symbol("hidden");
188
+ class HiddenState {
189
+ constructor(presentation) {
190
+ this[hiddenKey] = presentation;
191
+ }
192
+
193
+ get presentation() {
194
+ return this[hiddenKey];
195
+ }
196
+
197
+ getClone() {
198
+ return new HiddenState(this.presentation);
199
+ }
200
+ }
201
+
202
+ HiddenStateClass = HiddenState;
203
+
204
+ TestStateComponent = class extends CustomElement {
205
+ static getTag() {
206
+ return "monster-testclass-state"
207
+ }
208
+
209
+ get defaults() {
210
+ return Object.assign({}, super.defaults, {
211
+ current: new HiddenStateClass(""),
212
+ templates: {
213
+ main: '<div id="state" data-monster-replace="path:current.presentation"></div>'
214
+ }
215
+ })
216
+ }
217
+ }
218
+
219
+ registerCustomElement(TestStateComponent)
220
+
187
221
  document = getDocument();
188
222
  done()
189
223
  } catch (e) {
@@ -292,6 +326,26 @@ describe('DOM', function () {
292
326
 
293
327
  })
294
328
 
329
+ describe('Updater sync for instance values', function () {
330
+ it('should keep class instances and update presentation', function (done) {
331
+ let d = document.createElement('monster-testclass-state');
332
+ document.getElementById('test1').appendChild(d);
333
+
334
+ setTimeout(function () {
335
+ d.setOption('current', new HiddenStateClass('OK'));
336
+
337
+ setTimeout(function () {
338
+ try {
339
+ expect(d.shadowRoot.querySelector('#state').textContent).to.equal('OK');
340
+ done();
341
+ } catch (e) {
342
+ done(e);
343
+ }
344
+ }, 20);
345
+ }, 10);
346
+ });
347
+ })
348
+
295
349
  describe('setOptions()', function () {
296
350
  [
297
351
  ['shadowMode', 'x1'],
@@ -119,6 +119,41 @@ describe('Clone', function () {
119
119
 
120
120
  })
121
121
 
122
+ describe('.clone(Map)', function () {
123
+ it('.clone(Map) should preserve entries', function () {
124
+ let a = new Map([
125
+ ['x', 1],
126
+ ['y', {z: 2}],
127
+ ]);
128
+ let b = clone(a);
129
+ expect(b).to.be.instanceOf(Map);
130
+ expect(b).not.equal(a);
131
+ expect(b.get('x')).to.equal(1);
132
+ expect(JSON.stringify(b.get('y'))).to.equal(JSON.stringify({z: 2}));
133
+ });
134
+ })
135
+
136
+ describe('.clone(Set)', function () {
137
+ it('.clone(Set) should preserve values', function () {
138
+ let a = new Set([1, 2, 3]);
139
+ let b = clone(a);
140
+ expect(b).to.be.instanceOf(Set);
141
+ expect(b).not.equal(a);
142
+ expect([...b]).to.deep.equal([1, 2, 3]);
143
+ });
144
+ })
145
+
146
+ describe('.clone(RegExp)', function () {
147
+ it('.clone(RegExp) should preserve pattern and flags', function () {
148
+ let a = /test/gi;
149
+ let b = clone(a);
150
+ expect(b).to.be.instanceOf(RegExp);
151
+ expect(b).not.equal(a);
152
+ expect(b.source).to.equal(a.source);
153
+ expect(b.flags).to.equal(a.flags);
154
+ });
155
+ })
156
+
122
157
  describe('.clone()', function () {
123
158
 
124
159
  [
@@ -152,4 +187,3 @@ describe('Clone', function () {
152
187
  });
153
188
 
154
189
  });
155
-