@xtia/jel 0.6.2 → 0.6.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.
@@ -2,7 +2,7 @@ import { attribsProxy, eventsProxy, styleProxy } from "./proxy";
2
2
  import { entityDataSymbol, isContent, isJelEntity } from "./util";
3
3
  const elementWrapCache = new WeakMap();
4
4
  const recursiveAppend = (parent, c) => {
5
- if (c === null)
5
+ if (c === null || c === undefined)
6
6
  return;
7
7
  if (Array.isArray(c)) {
8
8
  c.forEach(item => recursiveAppend(parent, item));
@@ -52,8 +52,9 @@ function createElement(tag, descriptor = {}) {
52
52
  domElement.setAttribute(k, v === true ? k : v);
53
53
  });
54
54
  }
55
- if (descriptor.content !== undefined)
56
- recursiveAppend(domElement, descriptor.content);
55
+ if ("content" in descriptor) {
56
+ ent.content = descriptor.content;
57
+ }
57
58
  if (descriptor.style) {
58
59
  ent.style(descriptor.style);
59
60
  }
@@ -103,17 +104,23 @@ function observeMutations() {
103
104
  if (mutationObserver !== null)
104
105
  return;
105
106
  mutationObserver = new MutationObserver((mutations) => {
107
+ const recursiveAdd = (node) => {
108
+ if (elementMutationMap.has(node)) {
109
+ elementMutationMap.get(node).add();
110
+ }
111
+ if (node.hasChildNodes())
112
+ node.childNodes.forEach(recursiveAdd);
113
+ };
114
+ const recursiveRemove = (node) => {
115
+ if (elementMutationMap.has(node)) {
116
+ elementMutationMap.get(node).remove();
117
+ }
118
+ if (node.hasChildNodes())
119
+ node.childNodes.forEach(recursiveRemove);
120
+ };
106
121
  mutations.forEach(mut => {
107
- mut.addedNodes.forEach(node => {
108
- if (elementMutationMap.has(node)) {
109
- elementMutationMap.get(node).add();
110
- }
111
- });
112
- mut.removedNodes.forEach(node => {
113
- if (elementMutationMap.has(node)) {
114
- elementMutationMap.get(node).remove();
115
- }
116
- });
122
+ mut.addedNodes.forEach(node => recursiveAdd(node));
123
+ mut.removedNodes.forEach(node => recursiveRemove(node));
117
124
  });
118
125
  });
119
126
  mutationObserver.observe(document.body, {
@@ -121,6 +128,9 @@ function observeMutations() {
121
128
  subtree: true
122
129
  });
123
130
  }
131
+ function isReactiveSource(value) {
132
+ return typeof value == "object" && value && ("listen" in value || "subscribe" in value);
133
+ }
124
134
  function getWrappedElement(element) {
125
135
  if (!elementWrapCache.has(element)) {
126
136
  const setCSSVariable = (k, v) => {
@@ -131,53 +141,69 @@ function getWrappedElement(element) {
131
141
  element.style.setProperty("--" + k, v);
132
142
  }
133
143
  };
134
- const styleListeners = {};
135
- function addStyleListener(prop, source) {
144
+ const listeners = {
145
+ style: {},
146
+ cssVariable: {},
147
+ content: {},
148
+ };
149
+ function addListener(type, prop, source) {
150
+ const set = {
151
+ style: (v) => element.style[prop] = v,
152
+ cssVariable: (v) => setCSSVariable(prop, v),
153
+ content: (v) => {
154
+ element.innerHTML = "";
155
+ recursiveAppend(element, v);
156
+ }
157
+ }[type];
136
158
  const subscribe = "subscribe" in source
137
- ? () => source.subscribe(v => element.style[prop] = v)
138
- : () => source.listen(v => element.style[prop] = v);
139
- styleListeners[prop] = {
159
+ ? () => source.subscribe(set)
160
+ : () => source.listen(set);
161
+ listeners[type][prop] = {
140
162
  subscribe,
141
163
  unsubscribe: element.isConnected ? subscribe() : null,
142
164
  };
143
165
  if (!elementMutationMap.has(element)) {
144
166
  elementMutationMap.set(element, {
145
167
  add: () => {
146
- Object.values(styleListeners).forEach(l => { var _a; return l.unsubscribe = (_a = l.subscribe) === null || _a === void 0 ? void 0 : _a.call(l); });
168
+ Object.values(listeners).forEach(group => {
169
+ Object.values(group).forEach(l => { var _a; return l.unsubscribe = (_a = l.subscribe) === null || _a === void 0 ? void 0 : _a.call(l); });
170
+ });
147
171
  },
148
172
  remove: () => {
149
- Object.values(styleListeners).forEach(l => {
150
- var _a;
151
- (_a = l.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(l);
152
- l.unsubscribe = null;
173
+ Object.values(listeners).forEach(group => {
174
+ Object.values(group).forEach(l => {
175
+ var _a;
176
+ (_a = l.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(l);
177
+ l.unsubscribe = null;
178
+ });
153
179
  });
154
180
  }
155
181
  });
156
182
  }
157
183
  observeMutations();
158
184
  }
159
- function removeStyleListener(prop) {
160
- if (styleListeners[prop].unsubscribe) {
161
- styleListeners[prop].unsubscribe();
185
+ function removeListener(type, prop) {
186
+ if (listeners[type][prop].unsubscribe) {
187
+ listeners[type][prop].unsubscribe();
162
188
  }
163
- delete styleListeners[prop];
164
- if (Object.keys(styleListeners).length == 0) {
189
+ delete listeners[type][prop];
190
+ if (!Object.keys(listeners).some(group => Object.keys(group).length == 0)) {
165
191
  elementMutationMap.delete(element);
166
192
  }
167
193
  }
168
194
  function setStyle(prop, value) {
169
- if (styleListeners[prop])
170
- removeStyleListener(prop);
195
+ if (listeners.style[prop])
196
+ removeListener("style", prop);
171
197
  if (typeof value == "object" && value) {
172
198
  if ("listen" in value || "subscribe" in value) {
173
- addStyleListener(prop, value);
199
+ addListener("style", prop, value);
174
200
  return;
175
201
  }
176
202
  value = value.toString();
177
203
  }
178
204
  if (value === undefined) {
179
- return prop in styleListeners
180
- ? styleListeners[prop].subscribe
205
+ return prop in listeners
206
+ ? listeners.style[prop].subscribe
181
207
  : element.style[prop];
182
208
  }
183
209
  element.style[prop] = value;
@@ -193,12 +219,27 @@ function getWrappedElement(element) {
193
219
  });
194
220
  },
195
221
  append(...content) {
222
+ var _a;
223
+ if ((_a = listeners.content) === null || _a === void 0 ? void 0 : _a[""])
224
+ removeListener("content", "");
196
225
  recursiveAppend(element, content);
197
226
  },
198
227
  remove: () => element.remove(),
199
228
  setCSSVariable(variableNameOrTable, value) {
200
229
  if (typeof variableNameOrTable == "object") {
201
- Object.entries(variableNameOrTable).forEach(([k, v]) => setCSSVariable(k, v));
230
+ Object.entries(variableNameOrTable).forEach(([k, v]) => {
231
+ if (isReactiveSource(v)) {
232
+ addListener("cssVariable", k, v);
233
+ return;
234
+ }
235
+ setCSSVariable(k, v);
236
+ });
237
+ return;
238
+ }
239
+ if (listeners.cssVariable[variableNameOrTable])
240
+ removeListener("cssVariable", variableNameOrTable);
241
+ if (isReactiveSource(value)) {
242
+ addListener("cssVariable", variableNameOrTable, value);
202
243
  return;
203
244
  }
204
245
  setCSSVariable(variableNameOrTable, value);
@@ -225,6 +266,13 @@ function getWrappedElement(element) {
225
266
  });
226
267
  },
227
268
  set content(v) {
269
+ var _a;
270
+ if ((_a = listeners.content) === null || _a === void 0 ? void 0 : _a[""])
271
+ removeListener("content", "");
272
+ if (isReactiveSource(v)) {
273
+ addListener("content", "", v);
274
+ return;
275
+ }
228
276
  element.innerHTML = "";
229
277
  recursiveAppend(element, v);
230
278
  },
@@ -38,7 +38,7 @@ export type ElementDescriptor<Tag extends string> = {
38
38
  [E in keyof HTMLElementEventMap]+?: (event: HTMLElementEventMap[E]) => void;
39
39
  };
40
40
  style?: StylesDescriptor;
41
- cssVariables?: Record<string, CSSValue>;
41
+ cssVariables?: Record<string, CSSValue | ReactiveSource<CSSValue>>;
42
42
  } & (Tag extends TagWithValue ? {
43
43
  value?: string | number;
44
44
  } : {}) & (Tag extends ContentlessTag ? {} : {
@@ -63,8 +63,8 @@ type ElementAPI<T extends HTMLElement> = {
63
63
  };
64
64
  readonly events: EventsAccessor;
65
65
  readonly style: StyleAccessor;
66
- setCSSVariable(variableName: string, value: CSSValue): void;
67
- setCSSVariable(table: Record<string, CSSValue>): void;
66
+ setCSSVariable(variableName: string, value: CSSValue | ReactiveSource<CSSValue>): void;
67
+ setCSSVariable(table: Record<string, CSSValue | ReactiveSource<CSSValue>>): void;
68
68
  qsa(selector: string): (Element | DomEntity<HTMLElement>)[];
69
69
  remove(): void;
70
70
  getRect(): DOMRect;
@@ -74,7 +74,7 @@ type ElementAPI<T extends HTMLElement> = {
74
74
  } & (T extends ContentlessElement ? {} : {
75
75
  append(...content: DOMContent[]): void;
76
76
  innerHTML: string;
77
- content: DOMContent;
77
+ content: DOMContent | ReactiveSource<DOMContent>;
78
78
  }) & (T extends HTMLElementTagNameMap[TagWithValue] ? {
79
79
  value: string;
80
80
  select(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtia/jel",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "repository": {
5
5
  "url": "https://github.com/tiadrop/jel-ts",
6
6
  "type": "github"