@twobirds/microcomponents 0.1.20 → 0.1.23

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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -102
  3. package/dist/MC.min.js +1 -342
  4. package/dist/autoload.min.js +1 -0
  5. package/dist/core/MC.d.ts +401 -0
  6. package/dist/core/MC.d.ts.map +1 -0
  7. package/dist/core/MC.js +471 -0
  8. package/dist/core/autoload.d.ts +54 -0
  9. package/dist/core/autoload.d.ts.map +1 -0
  10. package/dist/core/autoload.js +158 -0
  11. package/dist/core/elements.d.ts +232 -0
  12. package/dist/core/elements.d.ts.map +1 -0
  13. package/dist/core/elements.js +123 -0
  14. package/dist/core/events.d.ts +231 -0
  15. package/dist/core/events.d.ts.map +1 -0
  16. package/dist/core/events.js +228 -0
  17. package/dist/core/mcGuards.d.ts +49 -0
  18. package/dist/core/mcGuards.d.ts.map +1 -0
  19. package/dist/core/mcGuards.js +19 -0
  20. package/dist/elements.min.js +1 -1
  21. package/dist/events.min.js +1 -0
  22. package/dist/formValues.min.js +1 -1
  23. package/dist/mcGuards.min.js +1 -0
  24. package/dist/microcomponents.d.ts +8 -5
  25. package/dist/microcomponents.d.ts.map +1 -1
  26. package/dist/microcomponents.js +8 -5
  27. package/dist/microcomponents.min.js +1 -1
  28. package/dist/observables.min.js +1 -1
  29. package/dist/state/formValues.d.ts +70 -0
  30. package/dist/state/formValues.d.ts.map +1 -0
  31. package/dist/state/formValues.js +334 -0
  32. package/dist/state/observables.d.ts +276 -0
  33. package/dist/state/observables.d.ts.map +1 -0
  34. package/dist/state/observables.js +382 -0
  35. package/dist/state/placeholders.d.ts +62 -0
  36. package/dist/state/placeholders.d.ts.map +1 -0
  37. package/dist/state/placeholders.js +181 -0
  38. package/dist/types/mcTypes.d.ts +201 -0
  39. package/dist/types/mcTypes.d.ts.map +1 -0
  40. package/dist/types/mcTypes.js +9 -0
  41. package/dist/utils/helpers.d.ts +195 -0
  42. package/dist/utils/helpers.d.ts.map +1 -0
  43. package/dist/utils/helpers.js +340 -0
  44. package/package.json +95 -61
  45. package/dist/MC.d.ts +0 -39
  46. package/dist/MC.d.ts.map +0 -1
  47. package/dist/MC.js +0 -299
  48. package/dist/MC.ts +0 -457
  49. package/dist/MicroComponents.svg +0 -15
  50. package/dist/elements.d.ts +0 -5
  51. package/dist/elements.d.ts.map +0 -1
  52. package/dist/elements.js +0 -50
  53. package/dist/elements.ts +0 -94
  54. package/dist/formValues.d.ts +0 -3
  55. package/dist/formValues.d.ts.map +0 -1
  56. package/dist/formValues.js +0 -158
  57. package/dist/formValues.ts +0 -213
  58. package/dist/helpers.d.ts +0 -14
  59. package/dist/helpers.d.ts.map +0 -1
  60. package/dist/helpers.js +0 -111
  61. package/dist/helpers.ts +0 -138
  62. package/dist/microcomponents.ts +0 -6
  63. package/dist/observables.d.ts +0 -11
  64. package/dist/observables.d.ts.map +0 -1
  65. package/dist/observables.js +0 -228
  66. package/dist/observables.ts +0 -338
@@ -1,228 +0,0 @@
1
- 'use strict';
2
- import { debounce, deepEqual, flattenObject, copyGettersSetters } from './helpers.js';
3
- import { DC, trigger } from './MC.js';
4
- function isObservableObject(value) {
5
- return value != null && typeof value === 'object';
6
- }
7
- function getPlaceholders(target) {
8
- let placeholders = new Set(), regEx = /\{[^\{\}]*\}/g;
9
- (target.getAttributeNames ? target.getAttributeNames() : [])
10
- .filter((attr) => target.getAttribute(attr)?.match(regEx))
11
- .forEach((attr) => {
12
- let placeholders = new Set(target.getAttribute(attr)?.match(regEx));
13
- placeholders.forEach((placeholder) => placeholders.add(placeholder.replace(/[\{\}]/g, '')));
14
- });
15
- [...target.childNodes]
16
- .filter((childNode) => {
17
- return (childNode.nodeType === 3 && (childNode.nodeValue || '').match(regEx));
18
- })
19
- .forEach((childNode) => {
20
- (childNode.nodeValue || '').match(regEx).forEach((placeholder) => {
21
- placeholders.add(placeholder.replace(/[\{\}]/g, ''));
22
- });
23
- });
24
- return [...placeholders].map((placeholder) => placeholder.replace(/[\{\}]/g, ''));
25
- }
26
- const inputs = [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement];
27
- class Placeholders extends DC {
28
- data = {};
29
- oldDisplay = '';
30
- constructor(target) {
31
- super(target);
32
- getPlaceholders(target).forEach((property) => (this.data[property] = ''));
33
- observe(this);
34
- this.#attachCallbacks();
35
- }
36
- #attachCallbacks() {
37
- let target = this.target, hide = false;
38
- (target.getAttributeNames ? target.getAttributeNames() : [])
39
- .filter((attr) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g))
40
- .forEach((attr) => {
41
- let placeholders = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
42
- this.data.observe(((template) => (data) => {
43
- let result = template;
44
- placeholders.forEach((placeholder) => {
45
- result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
46
- });
47
- target.setAttribute(attr, result);
48
- })(target.getAttribute(attr)));
49
- });
50
- [...target.childNodes]
51
- .filter((childNode) => {
52
- return (childNode.nodeType === 3 && (childNode.nodeValue || '').match(/\{[^\{\}]*\}/g));
53
- })
54
- .forEach((childNode) => {
55
- hide = true;
56
- let placeholders = new Set(childNode.nodeValue.match(/\{[^\{\}]*\}/g));
57
- this.data.observe(((template) => (data) => {
58
- let result = template;
59
- placeholders.forEach((placeholder) => {
60
- result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
61
- });
62
- if (this.oldDisplay) {
63
- target.style = this.oldDisplay;
64
- }
65
- else {
66
- target.removeAttribute('style');
67
- }
68
- delete this.oldDisplay;
69
- childNode.nodeValue = result;
70
- })(childNode.nodeValue));
71
- this.oldDisplay = target.getAttribute('style') || '';
72
- if (hide &&
73
- !inputs.includes(target.constructor) &&
74
- target.tagName !== 'FIELDSET') {
75
- target.style.display = 'none';
76
- }
77
- });
78
- }
79
- onData(ev) {
80
- let data = {};
81
- Object.keys(ev.detail.data).forEach((key) => {
82
- if (this.data.hasOwnProperty(key))
83
- data[key] = ev.detail.data[key];
84
- });
85
- if (JSON.stringify(data) !== JSON.stringify(this.data))
86
- Object.assign(this.data, data);
87
- }
88
- }
89
- function getPlaceholderElements(target) {
90
- let elements = [target]
91
- .concat([...target.querySelectorAll('*')])
92
- .filter((e) => !!getPlaceholders(e).length)
93
- .filter((e) => e?.tagName !== 'STYLE')
94
- .reverse();
95
- return elements;
96
- }
97
- function makePlaceholders(element) {
98
- getPlaceholderElements(element).forEach((e) => {
99
- if (e?._mc?._placeholders)
100
- return;
101
- DC.add(e, '_placeholders', new Placeholders(e));
102
- });
103
- }
104
- const classRepo = {};
105
- function makeObservable(val) {
106
- const Constructor = val.constructor, ConstructorName = Constructor.name;
107
- let ObservableClass = class extends Constructor {
108
- #notify = true;
109
- #callbacks = [];
110
- constructor(val) {
111
- super(val);
112
- this.constructor.callbacks = [];
113
- if (isObservableObject(val)) {
114
- Object.getOwnPropertyNames(val).forEach((key) => {
115
- this[key] = val[key];
116
- });
117
- }
118
- }
119
- get callbacks() {
120
- return this.#callbacks;
121
- }
122
- set callbacks(callbacks) {
123
- this.#callbacks = callbacks;
124
- }
125
- observe(callback) {
126
- this.#callbacks.push(callback);
127
- return this;
128
- }
129
- bind(target) {
130
- const iso = isObservableObject(this.valueOf());
131
- if (iso) {
132
- makePlaceholders(target);
133
- const placeholders = [target, ...target.querySelectorAll('[data-mc]')].filter((e) => !!e?._mc?._placeholders);
134
- const func = function callback(data) {
135
- let flattenedData = flattenObject(data);
136
- placeholders.forEach((node) => {
137
- if (!node)
138
- return;
139
- trigger(node, 'data', flattenedData);
140
- });
141
- };
142
- this.#callbacks.push(func);
143
- this.notify();
144
- }
145
- else {
146
- console.warn('IGNORED - cannot bind a non-Object to the dom, IS:', typeof this.valueOf(), this);
147
- }
148
- return this;
149
- }
150
- notify(notify) {
151
- let data = isObservableObject(this.valueOf()) && this.valueOf() instanceof Array === false
152
- ? structuredClone(Object.assign({}, this))
153
- : this.valueOf();
154
- if (notify !== undefined) {
155
- this.#notify = notify;
156
- }
157
- if (this.#notify) {
158
- this.#callbacks.forEach((f) => {
159
- f(data);
160
- });
161
- }
162
- return this;
163
- }
164
- };
165
- classRepo[ConstructorName] = ObservableClass;
166
- return ObservableClass;
167
- }
168
- function getConstructor(val) {
169
- let key = val.constructor.name;
170
- return classRepo[key] || makeObservable(val);
171
- }
172
- export const observe = (target, propertyName) => {
173
- let keys = !propertyName ? [...Object.getOwnPropertyNames(target)] : [propertyName];
174
- keys.forEach((key) => {
175
- if (target.hasOwnProperty(key) &&
176
- typeof target[key] !== 'function' &&
177
- !target?.[key]?.constructor?.prototype?.observe) {
178
- if (key[0] === '_' || target?.[key] === undefined)
179
- return target;
180
- let val = target[key];
181
- let o = new (getConstructor(val))(val);
182
- let debouncedNotify = debounce(function debouncedNotify() {
183
- o.notify();
184
- }, 0);
185
- Object.defineProperty(target, key, {
186
- enumerable: true,
187
- get() {
188
- if (isObservableObject(o.valueOf())) {
189
- let check = structuredClone(Object.assign({}, o));
190
- setTimeout(function checkChanges() {
191
- let state = structuredClone(Object.assign({}, o));
192
- if (!deepEqual(state, check)) {
193
- debouncedNotify();
194
- }
195
- }, 0);
196
- }
197
- return o;
198
- },
199
- set(val) {
200
- if (typeof val === typeof o.valueOf()) {
201
- let iso = isObservableObject(o.valueOf()) && o.valueOf() instanceof Array === false;
202
- if (iso) {
203
- if (o?.constructor?.prototype?.observe === undefined) {
204
- o = new (getConstructor(val))(structuredClone(Object.assign({}, val)));
205
- copyGettersSetters(val, o);
206
- }
207
- Object.assign(o, val);
208
- o.notify();
209
- }
210
- else {
211
- let old = o.valueOf(), callbacks = o.callbacks;
212
- if (val !== old) {
213
- o = new (getConstructor(val))(val);
214
- o.callbacks = callbacks;
215
- debouncedNotify();
216
- }
217
- }
218
- }
219
- else {
220
- console.warn('IGNORED - cannot change observable types, IS:', typeof o.valueOf(), o, '- CANNOT BECOME:', typeof val);
221
- }
222
- },
223
- });
224
- target[key] = val;
225
- }
226
- });
227
- return target;
228
- };
@@ -1,338 +0,0 @@
1
- 'use strict';
2
-
3
- import { LooseObject, debounce, deepEqual, flattenObject, copyGettersSetters } from './helpers.js';
4
-
5
- import { DC, HTMLMcElement, trigger } from './MC.js';
6
-
7
- function isObservableObject(value: any): boolean {
8
- return value != null && typeof value === 'object';
9
- }
10
-
11
- type Callback = (value: any) => void;
12
-
13
- function getPlaceholders(target: HTMLElement): string[] {
14
- let placeholders: Set<string> = new Set(),
15
- regEx = /\{[^\{\}]*\}/g;
16
-
17
- // scan attributes
18
- (target.getAttributeNames ? target.getAttributeNames() : [])
19
- .filter((attr) => target.getAttribute(attr)?.match(regEx)) // extract placeholder(s)
20
- .forEach((attr) => {
21
- let placeholders: Set<string> = new Set(target.getAttribute(attr)?.match(regEx));
22
- placeholders.forEach((placeholder) => placeholders.add(placeholder.replace(/[\{\}]/g, '')));
23
- });
24
-
25
- // scan children text nodes
26
- [...target.childNodes]
27
- .filter((childNode) => {
28
- return (
29
- // is text node and has placeholders
30
- childNode.nodeType === 3 && ((childNode as any).nodeValue || '').match(regEx)
31
- );
32
- })
33
- .forEach((childNode) => {
34
- ((childNode as any).nodeValue || '').match(regEx).forEach((placeholder: string) => {
35
- placeholders.add(placeholder.replace(/[\{\}]/g, ''));
36
- });
37
- });
38
-
39
- // extract {} and return result
40
- return [...placeholders].map((placeholder) => placeholder.replace(/[\{\}]/g, ''));
41
- }
42
-
43
- const inputs = [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement];
44
-
45
- class Placeholders extends DC {
46
- data: LooseObject = {};
47
- oldDisplay?: string = '';
48
-
49
- constructor(target: HTMLElement) {
50
- super(target);
51
- getPlaceholders(target).forEach((property) => (this.data[property] = ''));
52
- observe(this);
53
- this.#attachCallbacks();
54
- }
55
-
56
- #attachCallbacks() {
57
- let target = this.target,
58
- hide: boolean = false;
59
-
60
- // scan attributes
61
- (target.getAttributeNames ? target.getAttributeNames() : [])
62
- .filter((attr: string) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g)) // extract placeholder(s)
63
- .forEach((attr: string) => {
64
- let placeholders: Set<string> = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
65
- // attach callback
66
- this.data.observe(
67
- ((template: string) => (data: LooseObject) => {
68
- let result: string = template;
69
- placeholders.forEach((placeholder) => {
70
- result = result.replace(
71
- placeholder,
72
- // JSON.stringify(data[placeholder.replace(/[\{\}]/g, '')])
73
- data[placeholder.replace(/[\{\}]/g, '')]
74
- );
75
- });
76
- target.setAttribute(attr, result);
77
- })(target.getAttribute(attr))
78
- );
79
- });
80
-
81
- // scan children text nodes
82
- [...target.childNodes]
83
- .filter((childNode) => {
84
- return (
85
- // is text node and has placeholders
86
- childNode.nodeType === 3 && ((childNode as Node).nodeValue || '').match(/\{[^\{\}]*\}/g)
87
- );
88
- })
89
- .forEach((childNode) => {
90
- hide = true;
91
- let placeholders: Set<string> = new Set(childNode.nodeValue.match(/\{[^\{\}]*\}/g));
92
-
93
- // attach callback
94
- this.data.observe(
95
- ((template: string) => (data: LooseObject) => {
96
- let result: string = template;
97
- placeholders.forEach((placeholder) => {
98
- result = result.replace(
99
- placeholder,
100
- // JSON.stringify(data[placeholder.replace(/[\{\}]/g, '')])
101
- data[placeholder.replace(/[\{\}]/g, '')]
102
- );
103
- });
104
-
105
- if (this.oldDisplay) {
106
- target.style = this.oldDisplay;
107
- } else {
108
- target.removeAttribute('style');
109
- }
110
- delete this.oldDisplay;
111
-
112
- childNode.nodeValue = result;
113
- })(childNode.nodeValue)
114
- );
115
-
116
- // hide for now
117
- this.oldDisplay = target.getAttribute('style') || ''; // TBD allow null to indicate there was no old style attribute
118
-
119
- if (
120
- hide &&
121
- !inputs.includes((target as any).constructor) &&
122
- target.tagName !== 'FIELDSET'
123
- ) {
124
- target.style.display = 'none';
125
- }
126
- });
127
- }
128
-
129
- onData(ev: CustomEvent) {
130
- let data: LooseObject = {};
131
- Object.keys(ev.detail.data).forEach((key) => {
132
- if (this.data.hasOwnProperty(key)) data[key] = ev.detail.data[key];
133
- });
134
- if (JSON.stringify(data) !== JSON.stringify(this.data)) Object.assign(this.data, data); // will trigger callbacks
135
- }
136
- }
137
-
138
- function getPlaceholderElements(
139
- target: HTMLElement | DocumentFragment | ShadowRoot
140
- ): HTMLElement[] {
141
- let elements: Array<Node> = [target]
142
- .concat([...(target.querySelectorAll('*') as unknown as HTMLElement[])])
143
- .filter((e) => !!getPlaceholders(e as HTMLElement).length)
144
- .filter((e) => (e as HTMLElement)?.tagName !== 'STYLE')
145
- .reverse(); // to start with inner elements
146
- return elements as HTMLElement[];
147
- }
148
-
149
- function makePlaceholders(element: HTMLElement | DocumentFragment | ShadowRoot): void {
150
- getPlaceholderElements(element).forEach((e: HTMLElement) => {
151
- if ((e as HTMLMcElement)?._mc?._placeholders) return;
152
- DC.add(e, '_placeholders', new Placeholders(e));
153
- });
154
- }
155
-
156
- export type Observable = {
157
- observe: (cb: Callback) => void;
158
- notify: () => void;
159
- bind: (target: HTMLElement | DocumentFragment | ShadowRoot) => void;
160
- callbacks: Array<Function>;
161
- };
162
-
163
- type Class<T> = new (...args: any[]) => T;
164
-
165
- // repository for observable class wrappers
166
- const classRepo: LooseObject = {};
167
-
168
- // creates a new observable class wrapper
169
- function makeObservable(val: any): Class<typeof val> {
170
- const Constructor = val.constructor,
171
- ConstructorName: string = Constructor.name;
172
-
173
- let ObservableClass = class extends Constructor {
174
- #notify: boolean = true;
175
- #callbacks: Array<Function> = [];
176
-
177
- constructor(val: any) {
178
- super(val);
179
- (this.constructor as LooseObject).callbacks = [];
180
- if (isObservableObject(val)) {
181
- // you cannot bind native values to the dom
182
- Object.getOwnPropertyNames(val).forEach((key) => {
183
- this[key] = val[key];
184
- });
185
- }
186
- }
187
-
188
- get callbacks(): Array<Function> {
189
- return this.#callbacks;
190
- }
191
-
192
- set callbacks(callbacks: Array<Function>) {
193
- this.#callbacks = callbacks;
194
- }
195
-
196
- observe(callback: Function) {
197
- this.#callbacks.push(callback);
198
- return this;
199
- }
200
-
201
- bind(target: HTMLElement | DocumentFragment | ShadowRoot) {
202
- const iso = isObservableObject(this.valueOf());
203
-
204
- if (iso) {
205
- makePlaceholders(target);
206
- const placeholders: unknown = [target, ...target.querySelectorAll('[data-mc]')].filter(
207
- (e) => !!(e as LooseObject)?._mc?._placeholders
208
- );
209
-
210
- const func = function callback(data: LooseObject) {
211
- // avoid bubbling for speed
212
- let flattenedData = flattenObject(data);
213
- (placeholders as Node[]).forEach((node) => {
214
- // console.log('trigger callback', e);
215
- if (!node) return;
216
- trigger(node as HTMLMcElement, 'data', flattenedData);
217
- });
218
- };
219
- (this as any).#callbacks.push(func);
220
- this.notify();
221
- } else {
222
- console.warn(
223
- 'IGNORED - cannot bind a non-Object to the dom, IS:',
224
- typeof this.valueOf(),
225
- this
226
- );
227
- }
228
-
229
- return this;
230
- }
231
-
232
- notify(notify?: boolean) {
233
- let data =
234
- isObservableObject(this.valueOf()) && this.valueOf() instanceof Array === false
235
- ? structuredClone(Object.assign({}, this))
236
- : this.valueOf();
237
-
238
- if (notify !== undefined) {
239
- this.#notify = notify;
240
- // return;
241
- }
242
-
243
- if (this.#notify) {
244
- (this as any).#callbacks.forEach((f: Function) => {
245
- f(data);
246
- });
247
- }
248
-
249
- return this;
250
- }
251
- };
252
-
253
- (classRepo as any)[ConstructorName] = ObservableClass;
254
-
255
- return ObservableClass;
256
- }
257
-
258
- function getConstructor(val: any): Class<typeof val> {
259
- let key: string = val.constructor.name;
260
- return classRepo[key] || makeObservable(val);
261
- }
262
-
263
- export const observe = (target: LooseObject, propertyName?: string): LooseObject => {
264
- let keys = !propertyName ? [...Object.getOwnPropertyNames(target)] : [propertyName];
265
-
266
- keys.forEach((key) => {
267
- if (
268
- target.hasOwnProperty(key) &&
269
- typeof target[key] !== 'function' &&
270
- !target?.[key]?.constructor?.prototype?.observe
271
- ) {
272
- if (key[0] === '_' || target?.[key] === undefined) return target;
273
- let val: any = target[key];
274
-
275
- let o = new (getConstructor(val) as Class<typeof val>)(val);
276
-
277
- let debouncedNotify: Function = debounce(function debouncedNotify() {
278
- o.notify();
279
- }, 0);
280
-
281
- Object.defineProperty(target, key, {
282
- enumerable: true,
283
- get() {
284
- if (isObservableObject(o.valueOf())) {
285
- let check = structuredClone(Object.assign({}, o));
286
- setTimeout(function checkChanges() {
287
- let state = structuredClone(Object.assign({}, o));
288
- if (!deepEqual(state, check)) {
289
- debouncedNotify();
290
- }
291
- }, 0);
292
- }
293
- return o;
294
- },
295
- set(val: any) {
296
- if (typeof val === typeof o.valueOf()) {
297
- let iso = isObservableObject(o.valueOf()) && o.valueOf() instanceof Array === false;
298
- if (iso) {
299
- // is observable object
300
- if (o?.constructor?.prototype?.observe === undefined) {
301
- // not observed yet
302
- o = new (getConstructor(val) as Class<typeof val>)(
303
- structuredClone(Object.assign({}, val))
304
- );
305
- copyGettersSetters(val, o);
306
- //o.seal();
307
- }
308
- Object.assign(o, val); // mixin set object into observable object
309
- o.notify(); // dont test, just assume "changed" status
310
- } else {
311
- // simple native var
312
- let old = o.valueOf(),
313
- callbacks = (o as Observable).callbacks;
314
-
315
- if (val !== old) {
316
- o = new (getConstructor(val) as Class<typeof val>)(val);
317
- (o as Observable).callbacks = callbacks;
318
- debouncedNotify();
319
- }
320
- }
321
- } else {
322
- // set type is not stored type
323
- console.warn(
324
- 'IGNORED - cannot change observable types, IS:',
325
- typeof o.valueOf(),
326
- o,
327
- '- CANNOT BECOME:',
328
- typeof val
329
- );
330
- }
331
- },
332
- });
333
- target[key] = val; // replace old property with proxy (observable)
334
- }
335
- });
336
-
337
- return target;
338
- };