@twobirds/microcomponents 0.0.51 → 0.0.52

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 (73) hide show
  1. package/dist/formValues.d.ts.map +1 -1
  2. package/dist/formValues.ts +17 -44
  3. package/dist/formvValues.min.js +1 -1
  4. package/dist/microcomponents.min.js +1 -1
  5. package/package.json +1 -1
  6. package/public/3d.html +42 -0
  7. package/public/Grandparent.css +13 -0
  8. package/public/MC.js +314 -0
  9. package/public/MC.js.map +1 -0
  10. package/public/MC.min.js +451 -0
  11. package/public/McEvent.js +71 -0
  12. package/public/McEvent.js.map +1 -0
  13. package/public/MicroComponents.svg +15 -0
  14. package/public/autoloader.js +53 -0
  15. package/public/autoloader.js.map +1 -0
  16. package/public/documentation/MC.md +470 -0
  17. package/public/documentation/ajaxian-1.png +0 -0
  18. package/public/documentation/ajaxian-2.png +0 -0
  19. package/public/documentation/ajaxian-3.png +0 -0
  20. package/public/documentation/comparision.md +0 -0
  21. package/public/documentation/elements.md +276 -0
  22. package/public/documentation/functional_requirements.md +8 -0
  23. package/public/documentation/history.md +436 -0
  24. package/public/documentation/how_tos.md +0 -0
  25. package/public/documentation/introduction.md +0 -0
  26. package/public/documentation/magic.md +29 -0
  27. package/public/documentation/proposal_draft.md +37 -0
  28. package/public/documentation/rnd0023-1.jpg +0 -0
  29. package/public/documentation/rnd0023-2.jpg +0 -0
  30. package/public/documentation/rnd0023-3.jpg +0 -0
  31. package/public/documentation/tB_react.md +207 -0
  32. package/public/documentation/usage.md +142 -0
  33. package/public/documentation/why.md +25 -0
  34. package/public/elements.js +48 -0
  35. package/public/elements.js.map +1 -0
  36. package/public/elements.min.js +1 -0
  37. package/public/fiddle/MicroComponents.svg +15 -0
  38. package/public/fiddle/fiddle.css +0 -0
  39. package/public/fiddle/fiddle.js +0 -0
  40. package/public/fiddle/index.html +0 -0
  41. package/public/formValues.js +179 -0
  42. package/public/formValues.js.map +1 -0
  43. package/public/formvValues.min.js +1 -0
  44. package/public/helpers.js +113 -0
  45. package/public/helpers.js.map +1 -0
  46. package/public/microcomponents.es3.js +303 -0
  47. package/public/microcomponents.es3.js.map +1 -0
  48. package/public/microcomponents.js +9 -0
  49. package/public/microcomponents.js.map +1 -0
  50. package/public/microcomponents.min.js +1 -0
  51. package/public/my-tag.css +19 -0
  52. package/public/observables.js +251 -0
  53. package/public/observables.js.map +1 -0
  54. package/public/observables.min.js +1 -0
  55. package/public/selectors.js +971 -0
  56. package/public/selectors.js.map +1 -0
  57. package/public/selectors.min.js +1 -0
  58. package/public/src/MC.ts +478 -0
  59. package/public/src/McEvent.ts +96 -0
  60. package/public/src/autoloader.ts +98 -0
  61. package/public/src/elements.ts +76 -0
  62. package/public/src/formValues.ts +250 -0
  63. package/public/src/helpers.ts +149 -0
  64. package/public/src/microcomponents.ts +8 -0
  65. package/public/src/observables.ts +405 -0
  66. package/public/src/selectors.ts +1634 -0
  67. package/public/src/test.ts +177 -0
  68. package/public/test/Grandparent.js +1 -0
  69. package/public/test/Testform.js +1 -0
  70. package/public/test.html +27 -0
  71. package/public/test.js +78 -0
  72. package/public/test.js.map +1 -0
  73. package/src/formValues.ts +17 -44
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ import { getCE } from './elements.js'
4
+
5
+ // set of currently loading scripts
6
+ const loadingScripts: Set<string> = new Set();
7
+
8
+ const _makeLoadData = ( e: HTMLElement ): Array<any> | false => {
9
+
10
+ let
11
+ tagName = e?.localName ?? '',
12
+ isAttribute = e.getAttribute?.('is') || '',
13
+ isUBE = isAttribute ? true : false,
14
+ isCE = tagName.indexOf('-') !== -1 ? true : false,
15
+ ubeSelector = isUBE ? `${tagName}[is=\"${isAttribute}\"]:defined` : '',
16
+ ceSelector = isCE ? tagName + ':defined' : '',
17
+ fileBaseName = isUBE
18
+ ? isAttribute
19
+ : isCE
20
+ ? tagName
21
+ : '',
22
+ fileName = fileBaseName.length ? '/' + fileBaseName.split('-').join('/') + '.js' : '',
23
+ selector = isUBE
24
+ ? ubeSelector
25
+ : isCE
26
+ ? ceSelector
27
+ : ''
28
+ ;
29
+
30
+ //console.log( 'makeLoadData()', tagName, isUBE, isCE, ubeSelector, ceSelector, fileBaseName, ' => ', (isUBE || isCE) ? [ e, selector, fileName ] : false );
31
+ return (isUBE || isCE) ? [ e, selector, fileName, fileBaseName ] : false;
32
+ }
33
+
34
+ const _loadRequirements = ( node: HTMLTemplateElement | HTMLElement ): Promise<any> => {
35
+
36
+ let
37
+ undefinedSet: Set<any> = new Set(),
38
+ element: any = node instanceof HTMLTemplateElement ? (node as HTMLTemplateElement).content : node,
39
+ head = document.head,
40
+ allPromises: Array<any> = [],
41
+ e: HTMLElement;
42
+ ;
43
+
44
+ if ( element instanceof HTMLTemplateElement === false ){
45
+ // if node itself is undefined
46
+ let data: any = _makeLoadData(element);
47
+
48
+ if ( data && !data[0].matches( data[1] ) ){
49
+ undefinedSet.add( data );
50
+ }
51
+ }
52
+
53
+ // if some of the childNodes are undefined
54
+ Array.from( element.childNodes ).forEach(( node )=>{
55
+ let data: any = _makeLoadData(node as HTMLElement);
56
+
57
+ if ( data && !data[0].matches( data[1] ) ){
58
+ undefinedSet.add( data );
59
+ }
60
+ });
61
+
62
+ if ( !!undefinedSet.size ){ // there are requirements
63
+
64
+ undefinedSet.forEach( (data) => {
65
+ if ( !getCE( data[3] ) && !loadingScripts.has( data[2]) ){
66
+
67
+ loadingScripts.add( data[2] );
68
+
69
+ const se: HTMLScriptElement = document.createElement('script');
70
+
71
+ se.setAttribute( 'src', data[2] );
72
+ se.setAttribute( 'blocking', 'render' );
73
+ se.setAttribute( 'type', 'module' );
74
+ let s = (data as any)[2];
75
+ se.onload = () => {
76
+ // console.info('loaded', s);
77
+ loadingScripts.delete( s );
78
+ };
79
+
80
+ head.append( se );
81
+
82
+ let e = (data as Array<any>)[0];
83
+ } else {
84
+ return ;
85
+ }
86
+ });
87
+
88
+ }
89
+
90
+ return Promise.all( allPromises );
91
+ }
92
+
93
+ /*
94
+ TBD
95
+ if ( template.content.childNodes.length ){
96
+ _loadRequirements(template);
97
+ }
98
+ */
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ import { DC } from './MC.js';
4
+ import { kebabToPascal } from './helpers.js';
5
+
6
+ class CeBaseClass extends HTMLElement {
7
+ constructor() {
8
+ super();
9
+ }
10
+
11
+ connectedCallback() {
12
+ (DC as any).trigger(this, 'Connected');
13
+ }
14
+
15
+ disconnectedCallback() {
16
+ (DC as any).trigger(this, 'Disconnected');
17
+ }
18
+
19
+ adoptedCallback() {
20
+ (DC as any).trigger(this, 'Adopted');
21
+ }
22
+
23
+ attributeChangedCallback(name: string, oldValue: any, newValue: any) {
24
+ (DC as any).trigger(this, 'AttributeChanged', { name, oldValue, newValue });
25
+ }
26
+ }
27
+
28
+ function createNamedClass(
29
+ name: string,
30
+ ClassBody: { new (...args: any[]): any }
31
+ ) {
32
+ return Object.defineProperty(ClassBody, 'name', { value: name });
33
+ }
34
+
35
+ export function defineCE(
36
+ tagName: string,
37
+ DefinitionClass: { new (...args: any[]): any },
38
+ observedAttributes: string[] = []
39
+ ) {
40
+ if (customElements.get(tagName)) {
41
+ console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
42
+ return;
43
+ }
44
+
45
+ if (!tagName.includes('-')) {
46
+ throw new Error(
47
+ 'createCustomElement: tagName must contain at least one hyphen ("-").'
48
+ );
49
+ }
50
+
51
+ let name = kebabToPascal(tagName);
52
+
53
+ customElements.define(
54
+ tagName,
55
+ createNamedClass(
56
+ name,
57
+ class extends CeBaseClass {
58
+ instance: any;
59
+
60
+ constructor(data?: any) {
61
+ super();
62
+ let instance = new DefinitionClass(this, data);
63
+ DC.add(this, name, instance);
64
+ }
65
+
66
+ static get observedAttributes() {
67
+ return observedAttributes;
68
+ }
69
+ }
70
+ )
71
+ );
72
+ }
73
+
74
+ export function getCE(tagName: string): CustomElementConstructor | undefined {
75
+ return customElements.get(tagName);
76
+ }
@@ -0,0 +1,250 @@
1
+ 'use strict';
2
+
3
+ import { LooseObject, copyGettersSetters } from './helpers.js';
4
+ import { DC, addListener } from './MC.js';
5
+ import { observe } from './observables.js';
6
+
7
+ type inputTypes = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
8
+
9
+ const getInputName = (
10
+ e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
11
+ ): string => {
12
+ return e.tagName.toLowerCase();
13
+ };
14
+
15
+ abstract class InputBase {
16
+ constructor(e: inputTypes) {}
17
+
18
+ abstract get val(): any;
19
+
20
+ abstract set val(value: any);
21
+ }
22
+
23
+ class RadioHandler extends InputBase {
24
+ #e: HTMLInputElement;
25
+ #form: HTMLFormElement;
26
+
27
+ constructor(e: HTMLInputElement, form: HTMLFormElement) {
28
+ super(e);
29
+ this.#e = e;
30
+ this.#form = form;
31
+ }
32
+
33
+ get val(): string {
34
+ let ret = new FormData(this.#form).get(this.#e.name);
35
+
36
+ //console.log('radio[', this.#e.name, '] = "' + ret + '"');
37
+ return ret as string;
38
+ }
39
+
40
+ set val(value: string) {
41
+ let arr = [
42
+ ...this.#form.querySelectorAll(
43
+ `input[type="radio][name="${this.#e.name}"]`
44
+ ),
45
+ ] as HTMLInputElement[];
46
+
47
+ (
48
+ arr
49
+ .filter((e) => e.getAttribute('value') === value)
50
+ .shift() as HTMLInputElement
51
+ ).checked = true;
52
+ }
53
+ }
54
+
55
+ class CheckboxHandler extends InputBase {
56
+ #e: HTMLInputElement;
57
+
58
+ constructor(e: HTMLInputElement) {
59
+ super(e);
60
+ this.#e = e;
61
+ }
62
+
63
+ get val(): boolean {
64
+ return this.#e.checked;
65
+ }
66
+
67
+ set val(value: boolean) {
68
+ this.#e.checked = value;
69
+ }
70
+ }
71
+
72
+ class InputHandler extends InputBase {
73
+ #e: HTMLInputElement;
74
+
75
+ constructor(e: HTMLInputElement) {
76
+ super(e);
77
+ this.#e = e;
78
+ }
79
+
80
+ get val(): string {
81
+ return this.#e.value;
82
+ }
83
+
84
+ set val(value: string) {
85
+ this.#e.value = value;
86
+ }
87
+ }
88
+
89
+ class SelectHandler extends InputBase {
90
+ #e: HTMLSelectElement;
91
+ #multi: boolean = false;
92
+
93
+ constructor(e: HTMLSelectElement) {
94
+ super(e);
95
+ this.#e = e;
96
+ this.#multi = e.multiple;
97
+ }
98
+
99
+ get val(): string[] | string {
100
+ const that = this,
101
+ ret: string[] = [];
102
+
103
+ // get all options
104
+ const options = [...that.#e.querySelectorAll('option')]
105
+ .filter((o) => o.selected)
106
+ .forEach((o) => {
107
+ if (o.selected) ret.push(o.value);
108
+ });
109
+
110
+ if (this.#multi) return ret;
111
+ return ret.length ? ret[0] : '';
112
+ }
113
+
114
+ set val(value: string[] | string) {
115
+ const that = this;
116
+
117
+ value = typeof value === 'string' ? [value] : value;
118
+
119
+ // set all options
120
+ const options = [...that.#e.querySelectorAll('option')].forEach((o) => {
121
+ if (value.indexOf(o.value) > -1) {
122
+ o.setAttribute('selected', 'selected');
123
+ o.selected = true;
124
+ } else {
125
+ o.removeAttribute('selected');
126
+ o.selected = false;
127
+ }
128
+ });
129
+
130
+ return;
131
+ }
132
+ }
133
+
134
+ class TextAreaHandler extends InputBase {
135
+ #e: HTMLTextAreaElement;
136
+ constructor(e: HTMLTextAreaElement) {
137
+ super(e);
138
+ this.#e = e;
139
+ }
140
+
141
+ get val(): string {
142
+ return this.#e.value || '';
143
+ }
144
+
145
+ set val(value: string) {
146
+ this.#e.value = value;
147
+ return;
148
+ }
149
+ }
150
+
151
+ const getInputHandlers = (e: HTMLElement | ShadowRoot): LooseObject => {
152
+ let inputList = [
153
+ ...(e || document).querySelectorAll('input,select,textarea'),
154
+ ],
155
+ handlers: LooseObject = {};
156
+
157
+ inputList.forEach((i) => {
158
+ const name: string = (i as inputTypes).getAttribute('name') || 'undefined';
159
+ // console.log(name);
160
+ if (name) {
161
+ let h: InputBase,
162
+ type = (i as HTMLInputElement).type,
163
+ handler: any = false;
164
+ switch (getInputName(i as inputTypes)) {
165
+ case 'input':
166
+ switch (type) {
167
+ case 'radio':
168
+ handler = new RadioHandler(
169
+ i as HTMLInputElement,
170
+ (e.constructor === HTMLFormElement
171
+ ? e
172
+ : e.querySelector('form')) as HTMLFormElement
173
+ );
174
+ break;
175
+ case 'checkbox':
176
+ handler = new CheckboxHandler(i as HTMLInputElement);
177
+ break;
178
+ default:
179
+ handler = new InputHandler(i as HTMLInputElement);
180
+ }
181
+ break;
182
+ case 'select':
183
+ handler = new SelectHandler(i as HTMLSelectElement);
184
+ break;
185
+ case 'textarea':
186
+ handler = new TextAreaHandler(i as HTMLTextAreaElement);
187
+ break;
188
+ default:
189
+ console.warn(
190
+ 'handler missing:',
191
+ name,
192
+ 'for',
193
+ i.tagName.toLowerCase(),
194
+ i
195
+ );
196
+ break;
197
+ }
198
+
199
+ if (handler) {
200
+ DC.add(i, name, handler);
201
+ Object.defineProperty(handlers, name, {
202
+ enumerable: true,
203
+ configurable: true,
204
+ get: (): any => {
205
+ return handler.val;
206
+ },
207
+ set: (value: any) => {
208
+ if (handler.val !== value) {
209
+ handler.val = value;
210
+ }
211
+ },
212
+ });
213
+ }
214
+ }
215
+ });
216
+
217
+ return handlers;
218
+ };
219
+
220
+ export class FormValues {
221
+ constructor(
222
+ targetObject: LooseObject,
223
+ propertyName: string,
224
+ dom: HTMLElement | ShadowRoot
225
+ ) {
226
+ let that = this,
227
+ handlers = getInputHandlers(dom);
228
+
229
+ targetObject[propertyName] = Object.assign({}, handlers);
230
+
231
+ observe(targetObject, propertyName);
232
+
233
+ copyGettersSetters(handlers, targetObject[propertyName]);
234
+
235
+ [...dom.querySelectorAll('input, textarea, select')].forEach((input) => {
236
+ addListener(input as inputTypes, 'keyup', (ev: Event) => {
237
+ //console.log('keyup', ev);
238
+ targetObject[propertyName].notify();
239
+ });
240
+ addListener(input as HTMLElement, 'change', (ev: Event) => {
241
+ //console.log('change', ev);
242
+ targetObject[propertyName].notify();
243
+ });
244
+ addListener(input as inputTypes, 'select', (ev: Event) => {
245
+ //console.log('select', ev);
246
+ targetObject[propertyName].notify();
247
+ });
248
+ });
249
+ }
250
+ }
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ export interface LooseObject {
4
+ [key: string | symbol]: any;
5
+ }
6
+
7
+ export function isNativeObject(value: any): boolean {
8
+ return value && value['constructor'] && value.constructor === Object;
9
+ }
10
+
11
+ export function sortObject(o: LooseObject): LooseObject {
12
+ let result: LooseObject = {},
13
+ keys = [...Object.keys(o)].sort();
14
+
15
+ keys.forEach((key) => {
16
+ if (isNativeObject(o[key])) {
17
+ result[key] = sortObject(o[key]);
18
+ } else {
19
+ result[key] = o[key];
20
+ }
21
+ });
22
+
23
+ return result;
24
+ }
25
+
26
+ export function flattenObject(
27
+ o: LooseObject,
28
+ doSort: boolean = true
29
+ ): LooseObject {
30
+ let result: LooseObject = {};
31
+
32
+ [...Object.getOwnPropertyNames(o)].forEach((propName) => {
33
+ if (
34
+ o[propName] &&
35
+ o[propName]['constructor'] &&
36
+ o[propName].constructor === Object
37
+ ) {
38
+ const temp = flattenObject(o[propName], false);
39
+ for (const j in temp) {
40
+ result[propName + '.' + j] = temp[j];
41
+ }
42
+ } else {
43
+ result[propName] = o[propName];
44
+ }
45
+ });
46
+
47
+ return doSort ? sortObject(result) : result;
48
+ }
49
+
50
+ export function deepEqual(o1: LooseObject, o2: LooseObject): boolean {
51
+ return (
52
+ JSON.stringify(flattenObject(o1)) === JSON.stringify(flattenObject(o2))
53
+ );
54
+ }
55
+
56
+ export function nameSpace(ns: string | string[], obj: LooseObject = {}): any {
57
+ let nsa = ns.constructor === String ? ns.split('.') : ns;
58
+
59
+ if (!obj || !nsa[0] || !obj[nsa[0]]) {
60
+ console.warn('ns', nsa[0], 'not in', obj);
61
+ return;
62
+ }
63
+ if (obj[nsa[0]].constructor === Object && nsa.length > 1) {
64
+ return nameSpace((nsa as string[]).splice(1), obj[nsa[0]]);
65
+ }
66
+ return obj[nsa[0]];
67
+ }
68
+
69
+ export function parse(what: string | Object | any[], parseThis: Object) {
70
+ var args = Array.from(arguments);
71
+
72
+ if (args.length > 2) {
73
+ while (args.length > 1) {
74
+ args[0] = parse(args[0], args[1]);
75
+ args.splice(1, 1);
76
+ }
77
+ return args[0];
78
+ }
79
+
80
+ if (typeof what === 'string') {
81
+ what.match(/\{[^\{\}]*\}/g)?.forEach(function (pPropname) {
82
+ var propname = pPropname.substring(1, pPropname.length - 1),
83
+ value = nameSpace(propname, parseThis);
84
+ //console.log(propname, value);
85
+ if (typeof value !== 'undefined') {
86
+ what = (what as string).replace(pPropname, value);
87
+ }
88
+ });
89
+ } else if (isNativeObject(what)) {
90
+ switch (what.constructor) {
91
+ case Object:
92
+ Object.keys(what).forEach(function (pKey) {
93
+ if (what.hasOwnProperty(pKey)) {
94
+ (what as LooseObject)[pKey] = parse(
95
+ (what as LooseObject)[pKey],
96
+ parseThis
97
+ );
98
+ }
99
+ });
100
+ break;
101
+ case Array:
102
+ (what as Array<any>).forEach(function (pValue, pKey, original) {
103
+ original[pKey] = parse((what as any)[pKey], parseThis);
104
+ });
105
+ break;
106
+ }
107
+ }
108
+
109
+ return what;
110
+ }
111
+
112
+ export function kebabToPascal(str: string) {
113
+ return str
114
+ .split('-') // Split by hyphens
115
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) // Capitalize each part
116
+ .join(''); // Join without spaces
117
+ }
118
+
119
+ export function debounce(func: Function, milliseconds: number): Function {
120
+ let timeout: any;
121
+ return () => {
122
+ clearTimeout(timeout);
123
+
124
+ timeout = setTimeout(function () {
125
+ func(...arguments);
126
+ }, milliseconds);
127
+ };
128
+ }
129
+
130
+ export function htmlToElements(html: string): HTMLElement[] {
131
+ let template = document.createElement('template');
132
+
133
+ html = html.replace(/<([A-Za-z0-9\-]*)([^>\/]*)(\/>)/gi, '<$1$2></$1>'); // replace XHTML closing tags by full closing tags
134
+
135
+ template.innerHTML = html;
136
+
137
+ template.content.normalize();
138
+
139
+ return Array.from(template.content.childNodes) as HTMLElement[];
140
+ }
141
+
142
+ export function copyGettersSetters(source: LooseObject, target: LooseObject) {
143
+ const descriptors = Object.getOwnPropertyDescriptors(source);
144
+ for (const [key, descriptor] of Object.entries(descriptors)) {
145
+ if ('get' in descriptor || 'set' in descriptor) {
146
+ Object.defineProperty(target, key, descriptor);
147
+ }
148
+ }
149
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ export * from './helpers.js';
3
+ export * from './MC.js';
4
+ export * from './McEvent.js';
5
+ export * from './elements.js';
6
+ export * from './observables.js';
7
+ export * from './selectors.js';
8
+ export * from './formValues.js';