@webtides/element-js 1.0.0-alpha.2 → 1.0.0-alpha.3

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/dist/index.js CHANGED
@@ -86,6 +86,19 @@ function getShadowParentOrBody(element) {
86
86
  }
87
87
  return document.body;
88
88
  }
89
+ function getAllElementChildren(domNode, instanceOfFilter = HTMLElement) {
90
+ const nodeIterator = document.createNodeIterator(
91
+ domNode,
92
+ NodeFilter.SHOW_ELEMENT,
93
+ (node) => node.nodeName.includes("-") && node instanceof instanceOfFilter ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
94
+ );
95
+ const customElements2 = [];
96
+ let currentNode;
97
+ while (currentNode = nodeIterator.nextNode()) {
98
+ customElements2.push(currentNode);
99
+ }
100
+ return customElements2;
101
+ }
89
102
  var supportsAdoptingStyleSheets = () => {
90
103
  return "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype;
91
104
  };
@@ -96,16 +109,101 @@ var convertStringToTemplate = (string) => {
96
109
  return template.content;
97
110
  };
98
111
 
112
+ // src/util/SerializeStateHelper.js
113
+ var serializableObjectsCache = /* @__PURE__ */ new Map();
114
+ var globalElementJsState;
115
+ function initGlobalStateObject() {
116
+ if (!globalElementJsState) {
117
+ globalElementJsState = Array.from(globalThis.document.scripts).find((script) => script.type === "ejs/json");
118
+ if (!globalElementJsState) {
119
+ const script = document.createElement("script");
120
+ script.setAttribute("type", "ejs/json");
121
+ script.textContent = "{}";
122
+ document.body.appendChild(script);
123
+ globalElementJsState = script;
124
+ }
125
+ }
126
+ }
127
+ function serializeState(serializableObject) {
128
+ var _a;
129
+ if (!((_a = globalThis.elementJsConfig) == null ? void 0 : _a.serializeState))
130
+ return;
131
+ if (!serializableObject._serializationKey && !serializableObject.serializeState) {
132
+ throw new Error("serializableObject does not implement the Serializable interface");
133
+ }
134
+ initGlobalStateObject();
135
+ const currentState = JSON.parse(globalElementJsState.textContent);
136
+ currentState[serializableObject._serializationKey] = serializableObject.serializeState();
137
+ globalElementJsState.textContent = JSON.stringify(currentState, (key, value) => {
138
+ if (value instanceof Store) {
139
+ return "Store/" + value._serializationKey;
140
+ } else {
141
+ return value;
142
+ }
143
+ });
144
+ }
145
+ function deserializeState(serializableObject, serializedState) {
146
+ var _a;
147
+ if (!((_a = globalThis.elementJsConfig) == null ? void 0 : _a.serializeState))
148
+ return;
149
+ if (!serializableObject._serializationKey && !serializableObject.restoreState) {
150
+ throw new Error("serializableObject does not implement the Serializable interface");
151
+ }
152
+ if (serializedState) {
153
+ serializableObject.restoreState(serializedState);
154
+ return;
155
+ }
156
+ initGlobalStateObject();
157
+ const unresolvedState = JSON.parse(globalElementJsState.textContent);
158
+ const currentState = JSON.parse(globalElementJsState.textContent, (key, value) => {
159
+ if (typeof value === "string" && value.startsWith("Store/")) {
160
+ const [_, storeUuid] = value.split("/");
161
+ const serializedState2 = unresolvedState[storeUuid];
162
+ return new Store(serializedState2, { key: storeUuid, serializedState: serializedState2 });
163
+ } else {
164
+ return value;
165
+ }
166
+ });
167
+ serializableObject.restoreState(currentState[serializableObject._serializationKey]);
168
+ }
169
+ function hasSerializedState(key) {
170
+ var _a;
171
+ if (!((_a = globalThis.elementJsConfig) == null ? void 0 : _a.serializeState))
172
+ return false;
173
+ initGlobalStateObject();
174
+ const serializedState = JSON.parse(globalElementJsState.textContent);
175
+ return serializedState.hasOwnProperty(key);
176
+ }
177
+
99
178
  // src/util/Store.js
100
179
  var Store = class {
101
- constructor(value) {
102
- __publicField(this, "_observer", /* @__PURE__ */ new Set());
180
+ constructor(value, options) {
181
+ __publicField(this, "_serializationKey");
182
+ __publicField(this, "_observer", /* @__PURE__ */ new Set([]));
103
183
  __publicField(this, "_singlePropertyMode", false);
104
184
  __publicField(this, "_state", {});
185
+ if ((options == null ? void 0 : options.key) && serializableObjectsCache.has(options == null ? void 0 : options.key)) {
186
+ return serializableObjectsCache.get(options == null ? void 0 : options.key);
187
+ }
105
188
  this._singlePropertyMode = arguments.length > 0 && !isObjectLike(value);
189
+ if (options == null ? void 0 : options.key) {
190
+ this._serializationKey = options == null ? void 0 : options.key;
191
+ } else {
192
+ this._serializationKey = globalThis.crypto.randomUUID();
193
+ }
194
+ if (options == null ? void 0 : options.serializedState) {
195
+ deserializeState(this, options.serializedState);
196
+ } else if (hasSerializedState(this._serializationKey)) {
197
+ deserializeState(this);
198
+ }
106
199
  const specificValues = this._singlePropertyMode ? { value } : value;
107
- this._state = { ...!this._singlePropertyMode && this.properties(), ...specificValues };
108
- Object.entries(this._state).map(([key, value2]) => {
200
+ const properties = { ...!this._singlePropertyMode && this.properties(), ...specificValues };
201
+ const serializationKeys = Object.keys(this.serializeState());
202
+ Object.entries(properties).map(([key, value2]) => {
203
+ this._state[key] = hasSerializedState(this._serializationKey) && serializationKeys.includes(key) ? this[key] : value2;
204
+ if (value2 instanceof Store) {
205
+ value2.subscribe(this);
206
+ }
109
207
  Object.defineProperty(this, key, {
110
208
  get: () => {
111
209
  return this._state[key];
@@ -113,6 +211,10 @@ var Store = class {
113
211
  set: (newValue) => {
114
212
  const oldValue = this._state[key];
115
213
  this._state[key] = newValue;
214
+ if (value2 instanceof Store) {
215
+ value2.subscribe(this);
216
+ }
217
+ serializeState(this);
116
218
  if (!deepEquals(newValue, oldValue)) {
117
219
  const watch = this.watch();
118
220
  if (watch.hasOwnProperty(key) && typeof watch[key] === "function") {
@@ -123,6 +225,7 @@ var Store = class {
123
225
  }
124
226
  });
125
227
  });
228
+ serializableObjectsCache.set(this._serializationKey, this);
126
229
  }
127
230
  properties() {
128
231
  return {};
@@ -144,15 +247,21 @@ var Store = class {
144
247
  }
145
248
  requestUpdate() {
146
249
  this._observer.forEach(async (observer) => {
147
- var _a, _b;
148
- if (observer instanceof BaseElement) {
149
- await observer.requestUpdate();
150
- if (Object.keys((_a = observer.watch()) != null ? _a : {}).length > 0) {
151
- const properties = observer.properties();
152
- Object.keys((_b = observer.watch()) != null ? _b : {}).forEach((key) => {
250
+ var _a, _b, _c;
251
+ if (observer instanceof BaseElement || observer instanceof Store) {
252
+ if (((_a = observer == null ? void 0 : observer._options) == null ? void 0 : _a.autoUpdate) !== false) {
253
+ await observer.requestUpdate();
254
+ }
255
+ if (Object.keys((_b = observer.watch()) != null ? _b : {}).length > 0) {
256
+ Object.keys((_c = observer.watch()) != null ? _c : {}).forEach((key) => {
257
+ var _a2;
153
258
  if (observer._state[key] === this) {
154
- observer.callPropertyWatcher(key, this, this);
155
- observer.notifyPropertyChange(key, this);
259
+ if (observer instanceof Store) {
260
+ (_a2 = observer.watch) == null ? void 0 : _a2.call(observer)[key](this, this);
261
+ } else {
262
+ observer.callPropertyWatcher(key, this, this);
263
+ observer.notifyPropertyChange(key, this);
264
+ }
156
265
  }
157
266
  });
158
267
  }
@@ -163,6 +272,13 @@ var Store = class {
163
272
  }
164
273
  });
165
274
  }
275
+ serializeState() {
276
+ const keys = Object.keys(this.properties());
277
+ return Object.fromEntries(keys.map((key) => [key, this[key]]));
278
+ }
279
+ restoreState(serializedState) {
280
+ Object.assign(this, serializedState);
281
+ }
166
282
  };
167
283
 
168
284
  // src/util/defineElement.js
@@ -186,6 +302,7 @@ function toString(value) {
186
302
  var BaseElement = class extends HTMLElement {
187
303
  constructor(options = {}) {
188
304
  super();
305
+ __publicField(this, "_serializationKey");
189
306
  this.$refs = {};
190
307
  this._state = {};
191
308
  this._mutationObserver = null;
@@ -195,6 +312,7 @@ var BaseElement = class extends HTMLElement {
195
312
  this._options = {
196
313
  autoUpdate: true,
197
314
  deferUpdate: true,
315
+ deferConnected: false,
198
316
  mutationObserverOptions: {
199
317
  attributes: true,
200
318
  childList: true,
@@ -204,8 +322,28 @@ var BaseElement = class extends HTMLElement {
204
322
  propertyOptions: {},
205
323
  ...options
206
324
  };
325
+ if (this.hasAttribute("defer-update")) {
326
+ this._options.deferUpdate = true;
327
+ }
328
+ if (this.hasAttribute("defer-connected")) {
329
+ this._options.deferConnected = true;
330
+ }
207
331
  }
208
332
  connectedCallback() {
333
+ var _a;
334
+ if (this._options.deferConnected) {
335
+ this._options.deferConnected = false;
336
+ return;
337
+ }
338
+ if (this.hasAttribute("ejs:key")) {
339
+ this._serializationKey = this.getAttribute("ejs:key");
340
+ deserializeState(this);
341
+ } else {
342
+ this._serializationKey = globalThis.crypto.randomUUID();
343
+ if ((_a = globalThis.elementJsConfig) == null ? void 0 : _a.serializeState) {
344
+ this.setAttribute("ejs:key", this._serializationKey);
345
+ }
346
+ }
209
347
  this.defineAttributesAsProperties();
210
348
  this.defineProperties();
211
349
  this.definePropertyInjection();
@@ -309,10 +447,7 @@ var BaseElement = class extends HTMLElement {
309
447
  });
310
448
  }
311
449
  defineProperty(property, value, reflectAttribute = false) {
312
- var _a, _b;
313
- if (value instanceof Store) {
314
- value.subscribe(this);
315
- }
450
+ var _a, _b, _c;
316
451
  if (this._state.hasOwnProperty(property)) {
317
452
  return;
318
453
  }
@@ -322,7 +457,13 @@ var BaseElement = class extends HTMLElement {
322
457
  if (((_b = this._options.propertyOptions[property]) == null ? void 0 : _b.reflect) === false) {
323
458
  this.removeAttribute(camelToDash(property));
324
459
  }
460
+ if (hasSerializedState(this._serializationKey) && ((_c = Object.keys(this.serializeState())) == null ? void 0 : _c.includes(property))) {
461
+ value = this[property];
462
+ }
325
463
  this._state[property] = value;
464
+ if (this._state[property] instanceof Store) {
465
+ this._state[property].subscribe(this);
466
+ }
326
467
  Object.defineProperty(this, property, {
327
468
  get: () => {
328
469
  return this._state[property];
@@ -333,6 +474,7 @@ var BaseElement = class extends HTMLElement {
333
474
  const newValueString = JSON.stringify(newValue);
334
475
  if (JSON.stringify(oldValue) !== newValueString) {
335
476
  this._state[property] = newValue;
477
+ serializeState(this);
336
478
  if (newValue instanceof Store) {
337
479
  newValue.subscribe(this);
338
480
  }
@@ -394,16 +536,25 @@ var BaseElement = class extends HTMLElement {
394
536
  Object.entries(this.injectProperties()).forEach(([key, value]) => {
395
537
  this.requestContext(key, value);
396
538
  });
397
- if (Object.keys(this.provideProperties()).length > 0) {
539
+ const providedKeys = Object.keys(this.provideProperties());
540
+ if (providedKeys.length > 0) {
398
541
  this.addEventListener("request-context", this.onRequestContext);
542
+ getAllElementChildren(this.getRoot(), BaseElement).forEach((customChild) => {
543
+ var _a, _b;
544
+ const requestedProperties = (_b = (_a = customChild.injectProperties) == null ? void 0 : _a.call(customChild)) != null ? _b : {};
545
+ Object.entries(requestedProperties).forEach(([key, value]) => {
546
+ if (providedKeys.includes(key)) {
547
+ customChild.requestContext(key, value);
548
+ }
549
+ });
550
+ });
399
551
  }
400
552
  }
401
553
  requestContext(propertyName, valueOrCallback) {
402
- this.dispatch("request-context", { [propertyName]: valueOrCallback }, true);
554
+ this.dispatch("request-context", { [propertyName]: valueOrCallback }, true, true, true);
403
555
  }
404
556
  onRequestContext(event) {
405
557
  var _a;
406
- const properties = this.properties();
407
558
  const provideProperties = this.provideProperties();
408
559
  Object.entries((_a = event.detail) != null ? _a : {}).forEach(([key, valueOrCallback]) => {
409
560
  if (key in provideProperties) {
@@ -412,7 +563,9 @@ var BaseElement = class extends HTMLElement {
412
563
  if (typeof valueOrCallback === "function") {
413
564
  valueOrCallback(providedValue);
414
565
  } else {
415
- event.target[key] = providedValue;
566
+ const eventPath = event.composedPath();
567
+ const target = eventPath[0] || event.target;
568
+ target[key] = providedValue;
416
569
  }
417
570
  }
418
571
  });
@@ -493,45 +646,99 @@ var BaseElement = class extends HTMLElement {
493
646
  });
494
647
  this.$refs = refsMap;
495
648
  }
496
- dispatch(name, data, bubble = false, cancelable = false, composed = false) {
497
- const event = new CustomEvent(name, {
498
- bubbles: bubble,
499
- cancelable,
500
- composed,
501
- detail: data
502
- });
649
+ dispatch(name, data, options, cancelable = false, composed = false) {
650
+ let eventInit = {};
651
+ if (options !== void 0 && typeof options === "boolean") {
652
+ eventInit["bubbles"] = options;
653
+ eventInit["cancelable"] = cancelable;
654
+ eventInit["composed"] = composed;
655
+ eventInit["detail"] = data;
656
+ console.warn(
657
+ `[${this.localName}] Using the old parameter options for the event is deprecated and will be removed in v2.0! Please use the new options object that is in line with the "CustomEventInit" options`
658
+ );
659
+ } else {
660
+ eventInit = {
661
+ bubbles: true,
662
+ cancelable: true,
663
+ composed: true,
664
+ detail: data,
665
+ ...options
666
+ };
667
+ }
668
+ const event = new CustomEvent(name, eventInit);
503
669
  this.dispatchEvent(event);
504
670
  }
505
671
  getRoot() {
506
672
  return this;
507
673
  }
674
+ serializeState() {
675
+ const keys = Object.keys(this.properties());
676
+ return Object.fromEntries(keys.map((key) => [key, this[key]]));
677
+ }
678
+ restoreState(serializedState) {
679
+ Object.assign(this, serializedState);
680
+ }
508
681
  };
509
682
 
510
- // src/util/i18n.js
511
- function i18n(key, fallback) {
512
- try {
513
- const translations = window.elementjs.i18n();
514
- if (translations[key] === void 0) {
515
- throw "Translation Missing";
683
+ // src/util/GlobalStylesStore.js
684
+ var GlobalStylesStore = class extends Store {
685
+ constructor() {
686
+ var _a;
687
+ super();
688
+ __publicField(this, "globalStyleSheetsCache", /* @__PURE__ */ new WeakMap());
689
+ if ((_a = globalThis.elementJsConfig) == null ? void 0 : _a.observeGlobalStyles) {
690
+ const mutationObserver = new MutationObserver((mutationRecord) => {
691
+ if (!mutationRecord[0])
692
+ return;
693
+ const filteredNodes = Array.from(mutationRecord[0].addedNodes).filter(
694
+ (node) => node.tagName === "STYLE" || node.tagName === "LINK"
695
+ );
696
+ if (filteredNodes && filteredNodes[0] && filteredNodes[0].tagName === "LINK") {
697
+ filteredNodes[0].onload = () => {
698
+ this.requestUpdate();
699
+ };
700
+ } else if (filteredNodes && filteredNodes[0] && filteredNodes[0].tagName === "STYLE") {
701
+ this.requestUpdate();
702
+ }
703
+ });
704
+ mutationObserver.observe(globalThis.document, { subtree: true, childList: true });
516
705
  }
517
- return translations[key];
518
- } catch (err) {
519
- if (fallback)
520
- return fallback;
521
- else
522
- return key;
523
706
  }
524
- }
525
-
526
- // src/StyledElement.js
527
- var _StyledElement = class extends BaseElement {
528
- static updateGlobalStyles() {
529
- var _a;
530
- _StyledElement.globalStyles = (_a = globalThis.document) == null ? void 0 : _a.getElementById("globalStyles");
531
- if (_StyledElement.globalStyles && _StyledElement["globalStyleSheet"]) {
532
- _StyledElement["globalStyleSheet"].replaceSync(_StyledElement.globalStyles.textContent);
707
+ getGlobalStyleSheets(selector) {
708
+ var _a, _b;
709
+ const cssStyleSheets = [];
710
+ if (selector === false)
711
+ return cssStyleSheets;
712
+ if (typeof selector === "string") {
713
+ selector = [selector];
714
+ }
715
+ if (selector === true || selector.includes("document")) {
716
+ cssStyleSheets.push(...(_a = globalThis.document) == null ? void 0 : _a.adoptedStyleSheets);
533
717
  }
718
+ Array.from((_b = globalThis.document) == null ? void 0 : _b.styleSheets).map((styleSheet) => {
719
+ if (Array.isArray(selector) && !selector.some((cssSelector) => styleSheet.ownerNode.matches(cssSelector))) {
720
+ return;
721
+ }
722
+ let cssStyleSheet = this.globalStyleSheetsCache.get(styleSheet.ownerNode);
723
+ if (!cssStyleSheet) {
724
+ cssStyleSheet = new CSSStyleSheet();
725
+ let cssText = "";
726
+ if (styleSheet.ownerNode.tagName === "STYLE") {
727
+ cssText = styleSheet.ownerNode.textContent;
728
+ } else if (styleSheet.ownerNode.tagName === "LINK") {
729
+ cssText = Array.from(styleSheet.cssRules).map((rule) => rule.cssText).join("");
730
+ }
731
+ cssStyleSheet.replaceSync(cssText);
732
+ }
733
+ cssStyleSheets.push(cssStyleSheet);
734
+ });
735
+ return cssStyleSheets;
534
736
  }
737
+ };
738
+ var globalStylesStore = new GlobalStylesStore();
739
+
740
+ // src/StyledElement.js
741
+ var StyledElement = class extends BaseElement {
535
742
  constructor(options) {
536
743
  super({
537
744
  deferUpdate: false,
@@ -544,61 +751,58 @@ var _StyledElement = class extends BaseElement {
544
751
  }
545
752
  connectedCallback() {
546
753
  super.connectedCallback();
754
+ if (!this.constructor["elementStyleSheets"]) {
755
+ this.constructor["elementStyleSheets"] = this._styles.map((style) => {
756
+ const cssStyleSheet = new CSSStyleSheet();
757
+ cssStyleSheet.replaceSync(style);
758
+ return cssStyleSheet;
759
+ });
760
+ }
547
761
  if (supportsAdoptingStyleSheets() && this._options.shadowRender) {
548
762
  this.adoptStyleSheets();
763
+ if (this._options.adoptGlobalStyles !== false) {
764
+ globalStylesStore.subscribe(() => {
765
+ this.adoptStyleSheets();
766
+ });
767
+ }
549
768
  }
550
769
  }
551
770
  styles() {
552
771
  return [];
553
772
  }
554
773
  update(options) {
555
- var _a, _b;
556
774
  if (!supportsAdoptingStyleSheets() || this._options.shadowRender === false) {
557
- const appendableStyles = [...this._styles];
558
- if (this._options.shadowRender && this._options.adoptGlobalStyles) {
559
- appendableStyles.unshift((_b = (_a = _StyledElement.globalStyles) == null ? void 0 : _a.textContent) != null ? _b : "");
560
- }
561
- this.appendStyleSheets(appendableStyles);
775
+ this.appendStyleSheets();
562
776
  }
563
777
  super.update(options);
564
778
  }
565
779
  adoptStyleSheets() {
566
- if (!this.constructor["cssStyleSheets"]) {
567
- this.constructor["cssStyleSheets"] = this._styles.map((style) => {
568
- const sheet = new CSSStyleSheet();
569
- if (sheet && sheet.cssRules.length === 0) {
570
- sheet.replaceSync(style);
571
- }
572
- return sheet;
573
- });
574
- }
575
- if (_StyledElement.globalStyles && !_StyledElement["globalStyleSheet"]) {
576
- _StyledElement["globalStyleSheet"] = new CSSStyleSheet();
577
- _StyledElement["globalStyleSheet"].replaceSync(_StyledElement.globalStyles.textContent);
578
- }
780
+ const adoptGlobalStyleSheets = this._options.shadowRender && this._options.adoptGlobalStyles !== false;
579
781
  this.getRoot().adoptedStyleSheets = [
580
- ...this._options.shadowRender && this._options.adoptGlobalStyles && _StyledElement["globalStyleSheet"] ? [_StyledElement["globalStyleSheet"]] : [],
581
- ...this.constructor["cssStyleSheets"]
782
+ ...adoptGlobalStyleSheets ? globalStylesStore.getGlobalStyleSheets(this._options.adoptGlobalStyles) : [],
783
+ ...this.constructor["elementStyleSheets"]
582
784
  ];
583
785
  }
584
- appendStyleSheets(styles) {
786
+ appendStyleSheets() {
585
787
  const parentDocument = getShadowParentOrBody(this.getRoot());
586
- styles.forEach((style, index) => {
788
+ const adoptGlobalStyleSheets = this._options.shadowRender && this._options.adoptGlobalStyles !== false && parentDocument !== document.body;
789
+ const appendableStyles = [
790
+ ...adoptGlobalStyleSheets ? globalStylesStore.getGlobalStyleSheets(this._options.adoptGlobalStyles) : [],
791
+ ...this.constructor["elementStyleSheets"]
792
+ ];
793
+ appendableStyles.forEach((styleSheet, index) => {
587
794
  var _a;
588
795
  const identifier = this.tagName + index;
589
796
  if (!parentDocument.querySelector(`#${identifier}`)) {
590
797
  const styleElement = (_a = globalThis.document) == null ? void 0 : _a.createElement("style");
591
798
  styleElement.id = identifier;
592
799
  styleElement.style.display = "none";
593
- styleElement.textContent = style;
800
+ styleElement.textContent = Array.from(styleSheet.cssRules).map((rule) => rule.cssText).join("");
594
801
  parentDocument.appendChild(styleElement);
595
802
  }
596
803
  });
597
804
  }
598
805
  };
599
- var StyledElement = _StyledElement;
600
- __publicField(StyledElement, "globalStyles", null);
601
- StyledElement.updateGlobalStyles();
602
806
 
603
807
  // src/dom-parts/Part.js
604
808
  var Part = class {
@@ -1343,7 +1547,6 @@ export {
1343
1547
  TemplateElement,
1344
1548
  defineElement,
1345
1549
  html,
1346
- i18n,
1347
1550
  toString
1348
1551
  };
1349
1552
  //# sourceMappingURL=index.js.map