@twobirds/microcomponents 0.0.46 → 0.0.50

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 (100) hide show
  1. package/assets/Grandparent.css +13 -0
  2. package/assets/documentation/MC.md +380 -166
  3. package/assets/test.html +5 -1
  4. package/dist/MC.d.ts +1 -0
  5. package/dist/MC.d.ts.map +1 -1
  6. package/dist/MC.min.js +44 -0
  7. package/dist/MC.ts +65 -0
  8. package/dist/elements.min.js +1 -1
  9. package/dist/elements.ts +10 -10
  10. package/dist/formValues.d.ts +3 -2
  11. package/dist/formValues.d.ts.map +1 -1
  12. package/dist/formValues.ts +206 -203
  13. package/dist/formvValues.min.js +1 -1
  14. package/dist/helpers.d.ts +1 -0
  15. package/dist/helpers.d.ts.map +1 -1
  16. package/dist/helpers.ts +9 -0
  17. package/dist/microcomponents.min.js +1 -1
  18. package/dist/observables.d.ts +1 -1
  19. package/dist/observables.d.ts.map +1 -1
  20. package/dist/observables.min.js +1 -1
  21. package/dist/observables.ts +72 -33
  22. package/dist/selectors.min.js +1 -1
  23. package/dist/test.ts +14 -14
  24. package/package.json +1 -1
  25. package/public/Grandparent.css +13 -0
  26. package/public/Grandparent.js +338 -0
  27. package/public/MC.js +43 -0
  28. package/public/MC.js.map +1 -1
  29. package/public/MC.min.js +44 -0
  30. package/public/TestForm.css +47 -0
  31. package/public/TestForm.html +56 -0
  32. package/public/TestForm.js +56 -0
  33. package/public/TestForm.json +27 -0
  34. package/public/Testform.js +149 -0
  35. package/public/classes/MC.DC.html +13 -13
  36. package/public/classes/MC.MC.html +7 -7
  37. package/public/classes/MC.McBase.html +4 -4
  38. package/public/classes/MC.McEvent.html +13 -13
  39. package/public/documentation/MC.md +380 -166
  40. package/public/documentation/observe.md +317 -0
  41. package/public/elements.js +9 -9
  42. package/public/elements.js.map +1 -1
  43. package/public/elements.min.js +1 -1
  44. package/public/formValues.js +142 -133
  45. package/public/formValues.js.map +1 -1
  46. package/public/formvValues.min.js +1 -1
  47. package/public/functions/MC.addListener.html +1 -1
  48. package/public/functions/MC.removeListener.html +1 -1
  49. package/public/functions/elements.defineCE.html +1 -1
  50. package/public/functions/elements.getCE.html +1 -1
  51. package/public/functions/formValues.formValues.html +1 -1
  52. package/public/functions/observables.observe.html +1 -1
  53. package/public/functions/selectors._d.html +1 -1
  54. package/public/functions/selectors._t.html +1 -1
  55. package/public/helpers.js +8 -0
  56. package/public/helpers.js.map +1 -1
  57. package/public/interfaces/MC.HTMLMcElement.html +2 -2
  58. package/public/interfaces/selectors.DSelector.html +55 -55
  59. package/public/interfaces/selectors.TSelector.html +37 -37
  60. package/public/microcomponents.min.js +1 -1
  61. package/public/modules/MC.html +1 -1
  62. package/public/modules/elements.html +1 -1
  63. package/public/modules/formValues.html +1 -1
  64. package/public/modules/observables.html +1 -1
  65. package/public/modules/selectors.html +1 -1
  66. package/public/observables.js +39 -21
  67. package/public/observables.js.map +1 -1
  68. package/public/observables.min.js +1 -1
  69. package/public/selectors.min.js +1 -1
  70. package/public/src/MC.ts +65 -0
  71. package/public/src/elements.ts +10 -10
  72. package/public/src/formValues.ts +206 -203
  73. package/public/src/helpers.ts +9 -0
  74. package/public/src/observables.ts +72 -33
  75. package/public/src/test.ts +14 -14
  76. package/public/test/Grandparent.js +1 -0
  77. package/public/test/Testform.js +1 -0
  78. package/public/test.html +5 -1
  79. package/public/test.js +9 -11
  80. package/public/test.js.map +1 -1
  81. package/public/types/observables.Observable.html +1 -1
  82. package/public/types/selectors.selection.html +1 -1
  83. package/public/types/selectors.singleSelector.html +1 -1
  84. package/src/MC.ts +65 -0
  85. package/src/elements.ts +10 -10
  86. package/src/formValues.ts +206 -203
  87. package/src/helpers.ts +9 -0
  88. package/src/observables.ts +72 -33
  89. package/src/test/Child.ts +21 -0
  90. package/src/test/Grandchild.ts +21 -0
  91. package/src/test/Grandparent.css +11 -0
  92. package/src/test/Grandparent.ts +21 -0
  93. package/src/test/Greatgrandchild.ts +42 -0
  94. package/src/test/Parent.ts +21 -0
  95. package/src/test/Testform.css +47 -0
  96. package/src/test/Testform.html +56 -0
  97. package/src/test/Testform.json +27 -0
  98. package/src/test/Testform.ts +159 -0
  99. package/src/test.ts +14 -14
  100. package/webpack.config.js +135 -61
package/src/formValues.ts CHANGED
@@ -1,275 +1,278 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
- import { LooseObject } from './helpers.js'
4
- import { MC, addListener } from './MC.js'
3
+ import { LooseObject, copyGettersSetters } from './helpers.js';
4
+ import { DC, HTMLMcElement, addListener } from './MC.js';
5
+ import { Observable, observe } from './observables.js';
5
6
 
6
7
  type inputTypes = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
7
8
 
8
- const getInputName = ( e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement ): string => {
9
+ const getInputName = (
10
+ e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
11
+ ): string => {
12
+ return e.tagName.toLowerCase();
13
+ };
9
14
 
10
- let ret = e instanceof HTMLInputElement
11
- ? 'input'
12
- : e instanceof HTMLSelectElement
13
- ? 'select'
14
- : e instanceof HTMLTextAreaElement
15
- ? 'textarea'
16
- : ''
17
- ;
18
-
19
- return ret;
20
- }
21
-
22
- abstract class InputBase{
23
- constructor( e: any ){
24
- }
15
+ abstract class InputBase {
16
+ constructor(e: inputTypes) {}
25
17
 
26
18
  abstract get val(): any;
27
19
 
28
- abstract set val( value: any );
29
-
20
+ abstract set val(value: any);
30
21
  }
31
22
 
32
- const getInputHandlers = ( e: HTMLElement | ShadowRoot ): LooseObject => {
33
-
34
- let
35
- //inputList = ( Array.from( e.querySelectorAll('*') ) as HTMLElement[] ).filter( i => isInputElement(i) ),
36
- inputList = [ ...( e || document).querySelectorAll('input,select,textarea') ],
37
- handlers: LooseObject = {};
38
-
39
- inputList.forEach( (i) => {
40
- const
41
- name: string = ( i as inputTypes ).getAttribute('name') || 'undefined';
42
-
43
- if ( name ){
44
- let h: InputBase;
45
- switch ( getInputName( i as inputTypes ) ){
46
- case 'input':
47
- //console.log( i, 'is HTMLInputElement');
48
- h = new InputHandler( i as HTMLInputElement, e ); // e = element to search radios in = radioBase
49
- Object.defineProperty( handlers, name, {
50
- enumerable: true,
51
- configurable: true,
52
- get: (): any => { return h.val },
53
- set: ( value: any ) => { h.val = value }
54
- });
55
- break;
56
- case 'select':
57
- //console.log( i, 'is HTMLSelectElement');
58
- h = new SelectHandler( i as HTMLSelectElement );
59
- Object.defineProperty( handlers, name, {
60
- enumerable: true,
61
- configurable: true,
62
- get: (): any => { return h.val },
63
- set: ( value: any ) => { h.val = value }
64
- });
65
- break;
66
- case 'textarea':
67
- //console.log( i, 'is HTMLTextAreaElement');
68
- h = new TextAreaHandler( i as HTMLTextAreaElement );
69
- Object.defineProperty( handlers, name, {
70
- enumerable: true,
71
- configurable: true,
72
- get: (): any => { return h.val },
73
- set: ( value: any ) => { h.val = value }
74
- });
75
- break;
76
- default:
77
- console.warn('handler missing:', name, 'for', i);
78
- break;
79
- }
80
- }
81
- });
82
-
83
- return handlers;
84
- }
85
-
86
- class InputHandler extends InputBase {
87
-
23
+ class RadioHandler extends InputBase {
88
24
  #e: HTMLInputElement;
89
- #type: string;
90
- #radioBase: any;
25
+ #form: HTMLFormElement;
91
26
 
92
- constructor( e: HTMLInputElement, radioBase?: HTMLElement | ShadowRoot ){
93
- super( e );
27
+ constructor(e: HTMLInputElement, form: HTMLFormElement) {
28
+ super(e);
94
29
  this.#e = e;
95
- this.#type = e.type;
96
- this.#radioBase = radioBase;
30
+ this.#form = form;
97
31
  }
98
32
 
99
- get val(): any{
100
- let that = this,
101
- type = that.#type,
102
- ret: any;
103
-
104
- switch (type){
105
- case 'radio':
106
- const check = [ ...(this.#radioBase || document).querySelectorAll( `input[type="radio"][name="${ this.#e.getAttribute('name') }"]` ) ]
107
- .filter( e => e.checked );
108
- if ( !check.length ) return '';
109
- ret = check?.[0];
110
- return ret.value;
111
- case 'checkbox':
112
- return that.#e.checked;
113
- default:
114
- return that.#e.value;
115
- break;
116
- }
33
+ get val(): string {
34
+ let ret = new FormData(this.#form).get(this.#e.name);
117
35
 
118
- return '';
36
+ //console.log('radio[', this.#e.name, '] = "' + ret + '"');
37
+ return ret as string;
119
38
  }
120
39
 
121
- set val( value: any ){
122
- let that = this,
123
- type = that.#type,
124
- ret: any;
125
-
126
- switch (type){
127
- case 'radio':
128
- const
129
- radios = [ ...(this.#radioBase || document).querySelectorAll( `input[type="radio"][name="${ this.#e.getAttribute('name') }"]` ) ];
130
-
131
- // console.log('set radios', selection, this.#radioBase, radios.array );
132
-
133
- if ( !radios.length ) return;
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
+ }
134
54
 
135
- if ( value === '' ){ // uncheck all
136
- radios.forEach( r => { if (r.checked) r.checked = false } );
137
- //console.log('unset all radios', radios.array );
138
- return;
139
- }
55
+ class CheckboxHandler extends InputBase {
56
+ #e: HTMLInputElement;
140
57
 
141
- const setRadioElement = radios.filter( r => r.getAttribute('value') === value );
58
+ constructor(e: HTMLInputElement) {
59
+ super(e);
60
+ this.#e = e;
61
+ }
142
62
 
143
- if ( !setRadioElement.length ) return;
63
+ get val(): boolean {
64
+ return this.#e.checked;
65
+ }
144
66
 
145
- // console.log('set this radio', setRadioElement.array );
67
+ set val(value: boolean) {
68
+ this.#e.checked = value;
69
+ }
70
+ }
146
71
 
147
- (setRadioElement?.[0] as HTMLInputElement).checked = true;
72
+ class InputHandler extends InputBase {
73
+ #e: HTMLInputElement;
148
74
 
149
- // console.log('done', setRadioElement.array );
150
- return;
151
- break;
152
- case 'checkbox':
153
- that.#e.checked = value;
154
- break;
155
- default:
156
- that.#e.value = value;
157
- break;
158
- }
75
+ constructor(e: HTMLInputElement) {
76
+ super(e);
77
+ this.#e = e;
78
+ }
159
79
 
160
- return;
80
+ get val(): string {
81
+ return this.#e.value;
161
82
  }
162
83
 
84
+ set val(value: string) {
85
+ this.#e.value = value;
86
+ }
163
87
  }
164
88
 
165
89
  class SelectHandler extends InputBase {
166
-
167
90
  #e: HTMLSelectElement;
168
91
  #multi: boolean = false;
169
92
 
170
- constructor( e: HTMLSelectElement ){
171
- super( e );
93
+ constructor(e: HTMLSelectElement) {
94
+ super(e);
172
95
  this.#e = e;
173
- this.#multi = e.type === 'select-multiple';
96
+ this.#multi = e.multiple;
174
97
  }
175
98
 
176
- get val(): string[] | string{
177
- const
178
- that = this,
99
+ get val(): string[] | string {
100
+ const that = this,
179
101
  ret: string[] = [];
180
102
 
181
103
  // get all options
182
- const options = [ ...that.#e.querySelectorAll('option') ]
183
- .filter( o => o.selected )
184
- .forEach( o => { if ( o.selected ) ret.push( o.value ) } );
104
+ const options = [...that.#e.querySelectorAll('option')]
105
+ .filter((o) => o.selected)
106
+ .forEach((o) => {
107
+ if (o.selected) ret.push(o.value);
108
+ });
185
109
 
186
- if ( this.#multi ) return ret;
110
+ if (this.#multi) return ret;
187
111
  return ret.length ? ret[0] : '';
188
112
  }
189
113
 
190
- set val( value: string[] | string ){
191
- const
192
- that = this;
193
-
194
- value = typeof value === 'string' ? [ value ] : value;
114
+ set val(value: string[] | string) {
115
+ const that = this;
195
116
 
196
- //console.log('set values', value );
117
+ value = typeof value === 'string' ? [value] : value;
197
118
 
198
119
  // set all options
199
- const options = [ ...that.#e.querySelectorAll('option') ]
200
- .forEach( o => {
201
- if ( value.indexOf( o.value ) > -1 ) {
202
- o.setAttribute( 'selected', 'selected' )
203
- o.selected = true;
204
- } else {
205
- o.removeAttribute( 'selected' )
206
- o.selected = false;
207
- }
208
- });
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
+ });
209
129
 
210
130
  return;
211
131
  }
212
-
213
132
  }
214
133
 
215
134
  class TextAreaHandler extends InputBase {
216
- #e: HTMLTextAreaElement
217
- constructor( e: HTMLTextAreaElement ){
135
+ #e: HTMLTextAreaElement;
136
+ constructor(e: HTMLTextAreaElement) {
218
137
  super(e);
219
138
  this.#e = e;
220
139
  }
221
140
 
222
- get val(): string{
223
- return this.#e.value;
141
+ get val(): string {
142
+ return this.#e.value || '';
224
143
  }
225
144
 
226
- set val( value: string ){
145
+ set val(value: string) {
227
146
  this.#e.value = value;
228
147
  return;
229
148
  }
230
-
231
149
  }
232
150
 
233
- export const formValues = ( target: HTMLElement | ShadowRoot, values: Object = {}, mc?: typeof MC, observable?: string ): LooseObject => {
234
-
235
- //console.log( 'values(', target, ',', values, ',', observable, ')' );
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,
164
+ setter: DC;
165
+ switch (getInputName(i as inputTypes)) {
166
+ case 'input':
167
+ switch (type) {
168
+ case 'radio':
169
+ handler = new RadioHandler(
170
+ i as HTMLInputElement,
171
+ (e.constructor === HTMLFormElement
172
+ ? e
173
+ : e.querySelector('form')) as HTMLFormElement
174
+ );
175
+ setter = DC.add(i, name, handler);
176
+ break;
177
+ case 'checkbox':
178
+ handler = new CheckboxHandler(i as HTMLInputElement);
179
+ setter = DC.add(i, name, handler);
180
+ break;
181
+ default:
182
+ handler = new InputHandler(i as HTMLInputElement);
183
+ setter = DC.add(i, name, handler);
184
+ }
185
+
186
+ Object.defineProperty(handlers, name, {
187
+ enumerable: true,
188
+ configurable: true,
189
+ get: (): any => {
190
+ return (setter as unknown as SelectHandler).val;
191
+ },
192
+ set: (value: any) => {
193
+ if ((setter as unknown as InputHandler).val !== value) {
194
+ (setter as unknown as InputHandler).val = value;
195
+ }
196
+ },
197
+ });
198
+
199
+ break;
200
+ case 'select':
201
+ handler = new SelectHandler(i as HTMLSelectElement);
202
+ setter = DC.add(i, name, handler);
203
+ Object.defineProperty(handlers, name, {
204
+ enumerable: true,
205
+ configurable: true,
206
+ get: (): any => {
207
+ return (setter as unknown as SelectHandler).val;
208
+ },
209
+ set: (value: any) => {
210
+ if ((setter as unknown as SelectHandler).val !== value) {
211
+ (setter as unknown as SelectHandler).val = value;
212
+ }
213
+ },
214
+ });
215
+ break;
216
+ case 'textarea':
217
+ handler = new TextAreaHandler(i as HTMLTextAreaElement);
218
+ setter = DC.add(i, name, handler);
219
+ Object.defineProperty(handlers, name, {
220
+ enumerable: true,
221
+ configurable: true,
222
+ get: (): any => {
223
+ return (setter as unknown as TextAreaHandler).val;
224
+ },
225
+ set: (value: any) => {
226
+ if ((setter as unknown as TextAreaHandler).val !== value) {
227
+ (setter as unknown as TextAreaHandler).val = value;
228
+ }
229
+ },
230
+ });
231
+ break;
232
+ default:
233
+ console.warn(
234
+ 'handler missing:',
235
+ name,
236
+ 'for',
237
+ i.tagName.toLowerCase(),
238
+ i
239
+ );
240
+ break;
241
+ }
242
+ }
243
+ });
236
244
 
237
- //console.log( 'values()', values );
238
- let handlers = getInputHandlers( target );
245
+ return handlers;
246
+ };
239
247
 
240
- function updateForm( values: Object ){
241
- Object
242
- .keys( values )
243
- .forEach( (key) => {
244
- if ( handlers.hasOwnProperty(key) && values.hasOwnProperty(key) ) {
245
- //console.log( 'set value', key, values[key] );
246
- handlers[key] = (values as LooseObject)[key];
247
- }
248
- });
249
- }
248
+ export class FormValues {
249
+ constructor(
250
+ targetObject: LooseObject,
251
+ propertyName: string,
252
+ dom: HTMLElement | ShadowRoot
253
+ ) {
254
+ let that = this,
255
+ handlers = getInputHandlers(dom);
250
256
 
251
- if ( Object.keys(values).length > 0 ){
252
- updateForm( values );
253
- }
257
+ targetObject[propertyName] = Object.assign({}, handlers);
254
258
 
255
- //console.log( 'set observable on form change', observable );
256
- if ( observable !== undefined ){
257
- let obs = ( mc as LooseObject )[observable];
258
- if ( !obs.constructor?.hasFormHandler ){
259
- obs.constructor.hasFormHandler = true;
260
- obs.observe( updateForm );
261
- }
259
+ observe(targetObject, propertyName);
262
260
 
263
- ( mc as any)[observable].observe( () => { } );
261
+ copyGettersSetters(handlers, targetObject[propertyName]);
264
262
 
265
- [ ...target.querySelectorAll('input, textarea, select') ].forEach( ( e ) => {
266
- addListener( (e as HTMLElement), 'keyup', () => { ( mc as any)[observable] = structuredClone( Object.assign( handlers ) ) } );
267
- addListener( (e as HTMLElement), 'change', () => { ( mc as any)[observable] = structuredClone( Object.assign( handlers ) ) } );
268
- if ( (e as HTMLElement) instanceof HTMLSelectElement ){
269
- addListener( (e as HTMLElement), 'select', () => { ( mc as any)[observable] = structuredClone( Object.assign( handlers ) ) } );
270
- };
263
+ [...dom.querySelectorAll('input, textarea, select')].forEach((input) => {
264
+ addListener(input as inputTypes, 'keyup', (ev: Event) => {
265
+ //console.log('keyup', ev);
266
+ targetObject[propertyName].notify();
267
+ });
268
+ addListener(input as HTMLElement, 'change', (ev: Event) => {
269
+ //console.log('change', ev);
270
+ targetObject[propertyName].notify();
271
+ });
272
+ addListener(input as inputTypes, 'select', (ev: Event) => {
273
+ //console.log('select', ev);
274
+ targetObject[propertyName].notify();
275
+ });
271
276
  });
272
277
  }
273
-
274
- return observable ? ( mc as any)[observable] : Object.assign( {}, handlers );
275
278
  }
package/src/helpers.ts CHANGED
@@ -138,3 +138,12 @@ export function htmlToElements(html: string): HTMLElement[] {
138
138
 
139
139
  return Array.from(template.content.childNodes) as HTMLElement[];
140
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
+ }