@twobirds/microcomponents 0.0.80 → 0.0.81

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.
@@ -0,0 +1,249 @@
1
+ 'use strict';
2
+ import { debounce, deepEqual, flattenObject, copyGettersSetters, } from './helpers.js';
3
+ import { DC } 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
10
+ .getAttributeNames()
11
+ .filter((attr) => target.getAttribute(attr)?.match(regEx))
12
+ .forEach((attr) => {
13
+ let phs = new Set(target.getAttribute(attr)?.match(regEx));
14
+ phs.forEach((placeholder) => placeholders.add(placeholder.replace(/[\{\}]/g, '')));
15
+ });
16
+ [...target.childNodes]
17
+ .filter((childNode) => {
18
+ return (childNode.nodeType === 3 &&
19
+ (childNode.nodeValue || '').match(regEx));
20
+ })
21
+ .forEach((childNode) => {
22
+ (childNode.nodeValue || '')
23
+ .match(regEx)
24
+ .forEach((placeholder) => {
25
+ placeholders.add(placeholder.replace(/[\{\}]/g, ''));
26
+ });
27
+ });
28
+ return [...placeholders].map((placeholder) => placeholder.replace(/[\{\}]/g, ''));
29
+ }
30
+ const inputs = [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement];
31
+ class Placeholders extends DC {
32
+ data = {};
33
+ oldDisplay = '';
34
+ constructor(target) {
35
+ super(target);
36
+ let that = this;
37
+ getPlaceholders(target).forEach((property) => (that.data[property] = ''));
38
+ observe(that);
39
+ that.#attachCallbacks();
40
+ delete that._mc;
41
+ }
42
+ #attachCallbacks() {
43
+ let that = this, target = that.target, hide = false;
44
+ target
45
+ .getAttributeNames()
46
+ .filter((attr) => target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g))
47
+ .forEach((attr) => {
48
+ let phs = new Set(target.getAttribute(attr)?.match(/\{[^\{\}]*\}/g));
49
+ that.data.observe(((template) => (data) => {
50
+ let result = template;
51
+ phs.forEach((placeholder) => {
52
+ result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
53
+ });
54
+ target.setAttribute(attr, result);
55
+ })(target.getAttribute(attr)));
56
+ });
57
+ [...target.childNodes]
58
+ .filter((childNode) => {
59
+ return (childNode.nodeType === 3 &&
60
+ (childNode.nodeValue || '').match(/\{[^\{\}]*\}/g));
61
+ })
62
+ .forEach((childNode) => {
63
+ hide = true;
64
+ let phs = new Set(childNode.nodeValue.match(/\{[^\{\}]*\}/g));
65
+ that.data.observe(((template) => (data) => {
66
+ let result = template;
67
+ phs.forEach((placeholder) => {
68
+ result = result.replace(placeholder, data[placeholder.replace(/[\{\}]/g, '')]);
69
+ });
70
+ if (Object.keys(data).some((key) => {
71
+ return !!data[key];
72
+ })) {
73
+ if (!!that.oldDisplay) {
74
+ target.style = that.oldDisplay;
75
+ }
76
+ else {
77
+ target.removeAttribute('style');
78
+ }
79
+ delete that.oldDisplay;
80
+ }
81
+ childNode.nodeValue = result;
82
+ })(childNode.nodeValue));
83
+ that.oldDisplay = target.getAttribute('style)') || '';
84
+ if (hide &&
85
+ !inputs.includes(target.constructor) &&
86
+ target.tagName !== 'FIELDSET') {
87
+ target.style.display = 'none';
88
+ }
89
+ });
90
+ }
91
+ onData(ev) {
92
+ let that = this, data = {};
93
+ Object.keys(ev.data).forEach((key) => {
94
+ if (that.data.hasOwnProperty(key))
95
+ data[key] = ev.data[key];
96
+ });
97
+ if (JSON.stringify(data) !== JSON.stringify(that.data))
98
+ Object.assign(that.data, data);
99
+ }
100
+ }
101
+ function getPlaceholderElements(target) {
102
+ let elements = (target instanceof HTMLElement ? [target] : [])
103
+ .concat([...target.querySelectorAll('*')])
104
+ .filter((e) => !!getPlaceholders(e).length)
105
+ .filter((e) => e.tagName !== 'STYLE');
106
+ return elements;
107
+ }
108
+ function makePlaceholders(element) {
109
+ getPlaceholderElements(element).forEach((e) => {
110
+ if (e?._mc?._placeholders)
111
+ return;
112
+ DC.add(e, '_placeholders', new Placeholders(e));
113
+ });
114
+ }
115
+ const classRepo = {};
116
+ function makeObservable(val) {
117
+ const Constructor = val.constructor, ConstructorName = Constructor.name;
118
+ let ObservableClass = class extends Constructor {
119
+ #notify = true;
120
+ #callbacks = [];
121
+ constructor(val) {
122
+ super(val);
123
+ this.constructor.callbacks = [];
124
+ if (isObservableObject(val)) {
125
+ Object.getOwnPropertyNames(val).forEach((key) => {
126
+ this[key] = val[key];
127
+ });
128
+ }
129
+ }
130
+ get callbacks() {
131
+ return this.#callbacks;
132
+ }
133
+ set callbacks(callbacks) {
134
+ this.#callbacks = callbacks;
135
+ }
136
+ observe(f) {
137
+ this.#callbacks.push(f);
138
+ return this;
139
+ }
140
+ bind(target) {
141
+ const that = this, iso = isObservableObject(that.valueOf());
142
+ if (iso) {
143
+ makePlaceholders(target);
144
+ const placeholders = [
145
+ ...target.querySelectorAll('[_mc]'),
146
+ ].filter((e) => !!e?._mc?._placeholders);
147
+ const func = function callback(data) {
148
+ let d = flattenObject(data);
149
+ placeholders.forEach((e) => {
150
+ if (!e)
151
+ return;
152
+ e._mc.trigger('data', d);
153
+ });
154
+ };
155
+ that.#callbacks.push(func);
156
+ that.notify();
157
+ }
158
+ else {
159
+ console.warn('IGNORED - cannot bind a non-Object to the dom, IS:', typeof that.valueOf(), that);
160
+ }
161
+ return this;
162
+ }
163
+ notify(notify) {
164
+ let that = this, data = isObservableObject(that.valueOf()) &&
165
+ that.valueOf() instanceof Array === false
166
+ ? structuredClone(Object.assign({}, that))
167
+ : that.valueOf();
168
+ if (notify !== undefined) {
169
+ that.#notify = notify;
170
+ }
171
+ that.#callbacks.forEach((f) => {
172
+ f(data);
173
+ });
174
+ return that;
175
+ }
176
+ };
177
+ classRepo[ConstructorName] = ObservableClass;
178
+ return ObservableClass;
179
+ }
180
+ function getConstructor(val) {
181
+ let key = val.constructor.name;
182
+ return classRepo[key] || makeObservable(val);
183
+ }
184
+ export const observe = (target, propertyName) => {
185
+ let keys = !propertyName
186
+ ? [...Object.getOwnPropertyNames(target)]
187
+ : [propertyName];
188
+ keys.forEach((key) => {
189
+ if (target.hasOwnProperty(key)
190
+ && typeof target[key] !== 'function'
191
+ && !target?.[key]?.constructor?.prototype?.observe) {
192
+ if (key[0] === '_' || target?.[key] === undefined)
193
+ return target;
194
+ let val = target[key];
195
+ let o = new (getConstructor(val))(val);
196
+ Object.defineProperty(target, key, {
197
+ enumerable: true,
198
+ get() {
199
+ if (isObservableObject(o.valueOf())) {
200
+ let check = structuredClone(Object.assign({}, o));
201
+ setTimeout(debounce(function checkChanges() {
202
+ let state = structuredClone(Object.assign({}, o));
203
+ if (!deepEqual(state, check)) {
204
+ o.notify();
205
+ }
206
+ }, 0), 0);
207
+ }
208
+ return o;
209
+ },
210
+ set(val) {
211
+ if (typeof val === typeof o.valueOf()) {
212
+ let iso = isObservableObject(o.valueOf()) &&
213
+ o.valueOf() instanceof Array === false;
214
+ if (iso) {
215
+ let old = structuredClone(Object.assign({}, o));
216
+ if (o?.constructor?.prototype?.observe === undefined) {
217
+ o = new (getConstructor(val))(structuredClone(Object.assign({}, val)));
218
+ copyGettersSetters(val, o);
219
+ o.seal();
220
+ }
221
+ Object.assign(o, val);
222
+ setTimeout(debounce(function checkChanges() {
223
+ let state = structuredClone(Object.assign({}, o));
224
+ if (!deepEqual(state, old)) {
225
+ o.notify();
226
+ }
227
+ }, 0), 0);
228
+ }
229
+ else {
230
+ let old = o.valueOf(), callbacks = o.callbacks;
231
+ if (val !== old) {
232
+ o = new (getConstructor(val))(val);
233
+ o.callbacks = callbacks;
234
+ o.notify();
235
+ }
236
+ }
237
+ }
238
+ else {
239
+ console.warn('IGNORED - cannot change observable types, IS:', typeof o.valueOf(), o, '- CANNOT BECOME:', typeof val);
240
+ }
241
+ },
242
+ });
243
+ target[key] = val;
244
+ }
245
+ ;
246
+ });
247
+ return target;
248
+ };
249
+ //# sourceMappingURL=observables.js.map