@twobirds/microcomponents 0.1.16 → 0.1.19

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.
package/dist/elements.ts CHANGED
@@ -3,108 +3,92 @@
3
3
  import { DC, McBase } from './MC.js';
4
4
  import { kebabToPascal } from './helpers.js';
5
5
 
6
- class CeBaseClass extends HTMLElement {
7
- constructor() {
8
- super();
9
- }
10
-
11
- connectedCallback() {
12
- this.dispatchEvent(new CustomEvent('_mcConnected'));
13
- }
14
-
15
- connectedMoveCallback() {
16
- this.dispatchEvent(new CustomEvent('_mcConnectedMove'));
17
- }
18
-
19
- disconnectedCallback() {
20
- this.dispatchEvent(new CustomEvent('_mcDisconnected'));
21
- }
22
-
23
- adoptedCallback() {
24
- this.dispatchEvent(new CustomEvent('_mcAdopted'));
25
- }
26
-
27
- attributeChangedCallback(name: string, oldValue: any, newValue: any) {
28
- this.dispatchEvent(
29
- new CustomEvent('_mcAttributeChanged', { detail: { name, oldValue, newValue } })
30
- );
31
- }
32
-
33
- formResetCallback() {
34
- this.dispatchEvent(new CustomEvent('_mcFormReset'));
35
- }
36
- }
37
-
38
6
  function createNamedClass(name: string, ClassBody: { new (...args: any[]): any }) {
39
- return Object.defineProperty(ClassBody, 'name', { value: name });
40
- }
41
-
42
- function isClass(func: any) {
43
- return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func));
7
+ return Object.defineProperty(ClassBody, 'name', { value: name });
44
8
  }
45
9
 
46
10
  export function defineCE(
47
- tagName: string,
48
- DefinitionClass: { new (...args: any[]): any } | Function,
49
- observedAttributes: string[] = []
11
+ tagName: string,
12
+ DefinitionClass: { new (...args: any[]): any } | Function,
13
+ observedAttributes: string[] = []
50
14
  ) {
51
- if (customElements.get(tagName)) {
52
- console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
53
- return;
54
- }
55
-
56
- if (!tagName.includes('-')) {
57
- throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');
58
- }
59
-
60
- let name = kebabToPascal(tagName);
61
-
62
- // not a class, but a pure function
63
- if (!isClass(DefinitionClass.prototype.constructor)) {
64
- customElements.define(
65
- tagName,
66
- // @ts-ignore
67
- DefinitionClass
68
- );
69
- return;
70
- }
71
-
72
- // a class, but not a MC
73
- if (!(DefinitionClass.prototype instanceof McBase)) {
74
- customElements.define(
75
- tagName,
76
- // @ts-ignore
77
- DefinitionClass
78
- );
79
- return;
80
- }
81
-
82
- // a MC
83
- customElements.define(
84
- tagName,
85
- createNamedClass(
86
- name,
87
- class extends CeBaseClass {
88
- instance: any;
89
-
90
- constructor(data?: any) {
91
- super();
92
- // @ts-ignore
93
- const instance = isClass(DefinitionClass)
94
- ? // @ts-ignore
95
- new DefinitionClass(this, data)
96
- : DefinitionClass;
97
- DC.add(this, name, instance);
98
- }
99
-
100
- static get observedAttributes() {
101
- return observedAttributes;
102
- }
103
- }
104
- )
105
- );
15
+ //console.warn('defineCE args', arguments);
16
+
17
+ if (customElements.get(tagName)) {
18
+ console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
19
+ return;
20
+ }
21
+
22
+ if (!tagName.includes('-')) {
23
+ throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');
24
+ }
25
+
26
+ let name = kebabToPascal(tagName);
27
+
28
+ // a class, but not a MC
29
+ if (!(DefinitionClass.prototype instanceof McBase)) {
30
+ //console.warn('pure class', tagName, DefinitionClass);
31
+ customElements.define(
32
+ tagName,
33
+ // @ts-ignore
34
+ DefinitionClass
35
+ );
36
+ return;
37
+ }
38
+
39
+ //console.warn('MC class', tagName, DefinitionClass);
40
+ // a MC
41
+ customElements.define(
42
+ tagName,
43
+ createNamedClass(
44
+ name,
45
+ class extends HTMLElement {
46
+ constructor(data?: any) {
47
+ super();
48
+ // console.log('[named class constructor]', tagName, name, this, data);
49
+ // @ts-ignore
50
+ DC.add(this, name, new DefinitionClass(this, data));
51
+ }
52
+
53
+ connectedCallback() {
54
+ //console.warn('onConnected', this);
55
+ this.dispatchEvent(new CustomEvent('_mcConnected'));
56
+ }
57
+
58
+ connectedMoveCallback() {
59
+ //console.warn('onConnectedMove', this);
60
+ this.dispatchEvent(new CustomEvent('_mcConnectedMove'));
61
+ }
62
+
63
+ disconnectedCallback() {
64
+ //console.warn('onDisconnected', this);
65
+ this.dispatchEvent(new CustomEvent('_mcDisconnected'));
66
+ }
67
+
68
+ adoptedCallback() {
69
+ //console.warn('onAdopted', this);
70
+ this.dispatchEvent(new CustomEvent('_mcAdopted'));
71
+ }
72
+
73
+ attributeChangedCallback(name: string, oldValue: any, newValue: any) {
74
+ //console.warn('onAttributeChanged', this);
75
+ this.dispatchEvent(
76
+ new CustomEvent('_mcAttributeChanged', { detail: { name, oldValue, newValue } })
77
+ );
78
+ }
79
+
80
+ formResetCallback() {
81
+ this.dispatchEvent(new CustomEvent('_mcFormReset'));
82
+ }
83
+
84
+ static get observedAttributes() {
85
+ return observedAttributes;
86
+ }
87
+ }
88
+ )
89
+ );
106
90
  }
107
91
 
108
92
  export function getCE(tagName: string): CustomElementConstructor | undefined {
109
- return customElements.get(tagName);
93
+ return customElements.get(tagName);
110
94
  }
@@ -7,213 +7,207 @@ import { observe } from './observables.js';
7
7
  type inputTypes = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
8
8
 
9
9
  const getInputName = (e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): string => {
10
- return e.tagName.toLowerCase();
10
+ return e.tagName.toLowerCase();
11
11
  };
12
12
 
13
13
  abstract class InputBase {
14
- constructor(e: inputTypes) {}
14
+ constructor(e: inputTypes) {}
15
15
 
16
- abstract get val(): any;
16
+ abstract get val(): any;
17
17
 
18
- abstract set val(value: any);
18
+ abstract set val(value: any);
19
19
  }
20
20
 
21
21
  class RadioHandler extends InputBase {
22
- #e: HTMLInputElement;
23
-
24
- constructor(e: HTMLInputElement) {
25
- super(e);
26
- this.#e = e;
27
- }
28
-
29
- get val(): string {
30
- let ret = new FormData(this.#e.form as HTMLFormElement).get(this.#e.name);
31
-
32
- //console.log('radio[', this.#e.name, '] = "' + ret + '"');
33
- return ret as string;
34
- }
35
-
36
- set val(value: string) {
37
- let arr = [
38
- ...(this.#e.form as HTMLFormElement).querySelectorAll(
39
- `input[type="radio"][name="${this.#e.name}"]`
40
- ),
41
- ] as HTMLInputElement[];
42
-
43
- (arr.filter((e) => e.getAttribute('value') === value).shift() as HTMLInputElement).checked =
44
- true;
45
- }
22
+ #e: HTMLInputElement;
23
+
24
+ constructor(e: HTMLInputElement) {
25
+ super(e);
26
+ this.#e = e;
27
+ }
28
+
29
+ get val(): string {
30
+ let ret = new FormData(this.#e.form as HTMLFormElement).get(this.#e.name);
31
+
32
+ //console.log('radio[', this.#e.name, '] = "' + ret + '"');
33
+ return ret as string;
34
+ }
35
+
36
+ set val(value: string) {
37
+ let arr = [
38
+ ...(this.#e.form as HTMLFormElement).querySelectorAll(
39
+ `input[type="radio"][name="${this.#e.name}"]`
40
+ ),
41
+ ] as HTMLInputElement[];
42
+
43
+ (arr.filter((e) => e.getAttribute('value') === value).shift() as HTMLInputElement).checked =
44
+ true;
45
+ }
46
46
  }
47
47
 
48
48
  class CheckboxHandler extends InputBase {
49
- #e: HTMLInputElement;
49
+ #e: HTMLInputElement;
50
50
 
51
- constructor(e: HTMLInputElement) {
52
- super(e);
53
- this.#e = e;
54
- }
51
+ constructor(e: HTMLInputElement) {
52
+ super(e);
53
+ this.#e = e;
54
+ }
55
55
 
56
- get val(): boolean {
57
- return this.#e.checked;
58
- }
56
+ get val(): boolean {
57
+ return this.#e.checked;
58
+ }
59
59
 
60
- set val(value: boolean) {
61
- this.#e.checked = value;
62
- }
60
+ set val(value: boolean) {
61
+ this.#e.checked = value;
62
+ }
63
63
  }
64
64
 
65
65
  class InputHandler extends InputBase {
66
- #e: HTMLInputElement;
66
+ #e: HTMLInputElement;
67
67
 
68
- constructor(e: HTMLInputElement) {
69
- super(e);
70
- this.#e = e;
71
- }
68
+ constructor(e: HTMLInputElement) {
69
+ super(e);
70
+ this.#e = e;
71
+ }
72
72
 
73
- get val(): string {
74
- return this.#e.value;
75
- }
73
+ get val(): string {
74
+ return this.#e.value;
75
+ }
76
76
 
77
- set val(value: string) {
78
- this.#e.value = value;
79
- }
77
+ set val(value: string) {
78
+ this.#e.value = value;
79
+ }
80
80
  }
81
81
 
82
82
  class SelectHandler extends InputBase {
83
- #e: HTMLSelectElement;
84
- #multi: boolean = false;
85
-
86
- constructor(e: HTMLSelectElement) {
87
- super(e);
88
- this.#e = e;
89
- this.#multi = e.multiple;
90
- }
91
-
92
- get val(): string[] | string {
93
- const that = this,
94
- ret: string[] = [];
95
-
96
- // get all options
97
- [...that.#e.querySelectorAll('option')]
98
- .filter((o) => o.selected)
99
- .forEach((o) => {
100
- ret.push(o.value);
101
- });
102
-
103
- if (this.#multi) return ret;
104
- return ret.length ? ret[0] : '';
105
- }
106
-
107
- set val(value: string[] | string) {
108
- const that = this;
109
-
110
- value = typeof value === 'string' ? [value] : value;
111
-
112
- // set all options
113
- [...that.#e.querySelectorAll('option')].forEach((o) => {
114
- if (value.indexOf(o.value) > -1) {
115
- o.selected = true;
116
- } else {
117
- o.selected = false;
118
- }
119
- });
120
- }
83
+ #e: HTMLSelectElement;
84
+ #multi: boolean = false;
85
+
86
+ constructor(e: HTMLSelectElement) {
87
+ super(e);
88
+ this.#e = e;
89
+ this.#multi = e.multiple;
90
+ }
91
+
92
+ get val(): string[] | string {
93
+ const that = this,
94
+ ret: string[] = [];
95
+
96
+ // get all options
97
+ [...that.#e.querySelectorAll('option')]
98
+ .filter((o) => o.selected)
99
+ .forEach((o) => {
100
+ ret.push(o.value);
101
+ });
102
+
103
+ if (this.#multi) return ret;
104
+ return ret.length ? ret[0] : '';
105
+ }
106
+
107
+ set val(value: string[] | string) {
108
+ const that = this;
109
+
110
+ value = typeof value === 'string' ? [value] : value;
111
+
112
+ // set all options
113
+ [...that.#e.querySelectorAll('option')].forEach((o) => {
114
+ if (value.indexOf(o.value) > -1) {
115
+ o.selected = true;
116
+ } else {
117
+ o.selected = false;
118
+ }
119
+ });
120
+ }
121
121
  }
122
122
 
123
123
  class TextAreaHandler extends InputBase {
124
- #e: HTMLTextAreaElement;
125
- constructor(e: HTMLTextAreaElement) {
126
- super(e);
127
- this.#e = e;
128
- }
129
-
130
- get val(): string {
131
- return this.#e.value || '';
132
- }
133
-
134
- set val(value: string) {
135
- this.#e.value = value;
136
- }
124
+ #e: HTMLTextAreaElement;
125
+ constructor(e: HTMLTextAreaElement) {
126
+ super(e);
127
+ this.#e = e;
128
+ }
129
+
130
+ get val(): string {
131
+ return this.#e.value || '';
132
+ }
133
+
134
+ set val(value: string) {
135
+ this.#e.value = value;
136
+ }
137
137
  }
138
138
 
139
139
  const getInputHandlers = (e: HTMLElement | ShadowRoot): LooseObject => {
140
- let inputList = [...(e || document).querySelectorAll('input,select,textarea')],
141
- handlers: LooseObject = {};
142
-
143
- inputList.forEach((input) => {
144
- const name: string | null = (input as inputTypes).getAttribute('name');
145
- if (name) {
146
- let handler: any = false;
147
- switch (getInputName(input as inputTypes)) {
148
- case 'input':
149
- switch ((input as HTMLInputElement).type) {
150
- case 'radio':
151
- handler = new RadioHandler(input as HTMLInputElement);
152
- break;
153
- case 'checkbox':
154
- handler = new CheckboxHandler(input as HTMLInputElement);
155
- break;
156
- default:
157
- handler = new InputHandler(input as HTMLInputElement);
158
- }
159
- break;
160
- case 'select':
161
- handler = new SelectHandler(input as HTMLSelectElement);
162
- break;
163
- case 'textarea':
164
- handler = new TextAreaHandler(input as HTMLTextAreaElement);
165
- break;
166
- default:
167
- console.warn(
168
- 'handler missing:',
169
- name,
170
- 'for',
171
- input.tagName.toLowerCase(),
172
- input
173
- );
174
- break;
175
- }
176
-
177
- if (handler) {
178
- DC.add(input as HTMLElement, name, handler);
179
- Object.defineProperty(handlers, name, {
180
- enumerable: true,
181
- configurable: true,
182
- get: (): any => {
183
- return handler.val;
184
- },
185
- set: (value: any) => {
186
- if (handler.val !== value) {
187
- handler.val = value;
188
- }
189
- },
190
- });
191
- }
192
- }
193
- });
194
-
195
- return handlers;
140
+ let inputList = [...(e || document).querySelectorAll('input,select,textarea')],
141
+ handlers: LooseObject = {};
142
+
143
+ inputList.forEach((input) => {
144
+ const name: string | null = (input as inputTypes).getAttribute('name');
145
+ if (name) {
146
+ let handler: any = false;
147
+ switch (getInputName(input as inputTypes)) {
148
+ case 'input':
149
+ switch ((input as HTMLInputElement).type) {
150
+ case 'radio':
151
+ handler = new RadioHandler(input as HTMLInputElement);
152
+ break;
153
+ case 'checkbox':
154
+ handler = new CheckboxHandler(input as HTMLInputElement);
155
+ break;
156
+ default:
157
+ handler = new InputHandler(input as HTMLInputElement);
158
+ }
159
+ break;
160
+ case 'select':
161
+ handler = new SelectHandler(input as HTMLSelectElement);
162
+ break;
163
+ case 'textarea':
164
+ handler = new TextAreaHandler(input as HTMLTextAreaElement);
165
+ break;
166
+ default:
167
+ console.warn('handler missing:', name, 'for', input.tagName.toLowerCase(), input);
168
+ break;
169
+ }
170
+
171
+ if (handler) {
172
+ DC.add(input as HTMLElement, name, handler);
173
+ Object.defineProperty(handlers, name, {
174
+ enumerable: true,
175
+ configurable: true,
176
+ get: (): any => {
177
+ return handler.val;
178
+ },
179
+ set: (value: any) => {
180
+ if (handler.val !== value) {
181
+ handler.val = value;
182
+ }
183
+ },
184
+ });
185
+ }
186
+ }
187
+ });
188
+
189
+ return handlers;
196
190
  };
197
191
 
198
192
  export function formValues(
199
- targetObject: LooseObject,
200
- propertyName: string,
201
- dom: HTMLElement | ShadowRoot
193
+ targetObject: LooseObject,
194
+ propertyName: string,
195
+ dom: HTMLElement | ShadowRoot
202
196
  ) {
203
- let handlers = getInputHandlers(dom);
197
+ let handlers = getInputHandlers(dom);
204
198
 
205
- targetObject[propertyName] = Object.assign({}, handlers);
199
+ targetObject[propertyName] = Object.assign({}, handlers);
206
200
 
207
- observe(targetObject, propertyName);
201
+ observe(targetObject, propertyName);
208
202
 
209
- copyGettersSetters(handlers, targetObject[propertyName]);
203
+ copyGettersSetters(handlers, targetObject[propertyName]);
210
204
 
211
- Object.seal(targetObject[propertyName]); // object structure may not be changed from now on
205
+ //Object.seal(targetObject[propertyName]); // object structure may not be changed from now on
212
206
 
213
- [...dom.querySelectorAll('input, textarea, select')].forEach((input) => {
214
- input.addEventListener('input', (ev) => {
215
- //console.log('input event', input, ev);
216
- targetObject[propertyName].notify();
217
- });
218
- });
207
+ [...dom.querySelectorAll('input, textarea, select')].forEach((input) => {
208
+ input.addEventListener('input', (ev) => {
209
+ //console.log('input event', input, ev);
210
+ targetObject[propertyName].notify();
211
+ });
212
+ });
219
213
  }