@alexgyver/component 1.4.0 → 1.5.0
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/Component.js +192 -67
- package/Component.min.js +1 -1
- package/README.md +172 -28
- package/package.json +2 -2
- package/test/script.js +25 -1
package/Component.js
CHANGED
|
@@ -9,8 +9,19 @@ export class EL {
|
|
|
9
9
|
* @param {Boolean} svg SVG
|
|
10
10
|
*/
|
|
11
11
|
constructor(tag, data = {}, svg = false) {
|
|
12
|
-
EL.
|
|
13
|
-
|
|
12
|
+
this.$root = EL.makeIn(this, tag, data, svg);
|
|
13
|
+
}
|
|
14
|
+
make(tag, data = {}, svg = false) {
|
|
15
|
+
return EL.makeIn(this, tag, data, svg);
|
|
16
|
+
}
|
|
17
|
+
makeArray(arr, svg = false) {
|
|
18
|
+
return EL.makeArrayIn(this, arr, svg);
|
|
19
|
+
}
|
|
20
|
+
config(el, data, svg = false) {
|
|
21
|
+
return EL.configIn(this, el, data, svg);
|
|
22
|
+
}
|
|
23
|
+
makeShadow(host, data = {}, sheet = null) {
|
|
24
|
+
return EL.makeShadowIn(this, host, data, sheet);
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
/**
|
|
@@ -19,34 +30,14 @@ export class EL {
|
|
|
19
30
|
* @param {object} data параметры
|
|
20
31
|
* @param {Boolean} svg SVG
|
|
21
32
|
* @returns {Node}
|
|
22
|
-
* @params
|
|
23
|
-
* tag {string} - тег html элемента. Если 'svg' - включится режим SVG на детей
|
|
24
|
-
* context {object} - объект для параметра '$', прокидывается в детей
|
|
25
|
-
* parent - {Element} добавить созданный элемент к указанному элементу
|
|
26
|
-
* text {string} - добавить в textContent
|
|
27
|
-
* html {string} - добавить в innerHTML
|
|
28
|
-
* class {string | Array} - добавить в className
|
|
29
|
-
* style/style_r {string | object} - объект в виде { padding: '0px', ... } или строка css стилей. _r - заменить имеющиеся
|
|
30
|
-
* push {array} - добавить к указанному массиву
|
|
31
|
-
* $ {string} - создать переменную $имя в указанном объекте
|
|
32
|
-
* events {object} - добавить addEventListener'ы {event: e => {}}
|
|
33
|
-
* click, change, input, mousewheel - добавление события без events
|
|
34
|
-
* children/children_r - дети, массив {DOM, EL, object, html string}. _r - заменить имеющиеся. Без тега tag будет div
|
|
35
|
-
* child/child_r - ребенок {DOM, EL, object, html string}. _r - заменить имеющиеся. Без тега tag будет div
|
|
36
|
-
* attrs {object} - добавить аттрибуты (как setAttribute())
|
|
37
|
-
* props {object} - добавить свойства (как el[prop])
|
|
38
|
-
* also {function} - вызвать с текущим элементом: also(el) { console.log(el); }
|
|
39
|
-
* всё остальное будет добавлено как property
|
|
40
33
|
*/
|
|
41
34
|
static make(tag, data = {}, svg = false) {
|
|
42
|
-
if (!tag || typeof data !== 'object') return null;
|
|
43
35
|
if (data instanceof Node) return data;
|
|
44
36
|
if (tag == 'svg') svg = true;
|
|
45
|
-
return EL.config(svg ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag), data, svg);
|
|
37
|
+
return EL.config(svg ? document.createElementNS("http://www.w3.org/2000/svg", tag ?? 'svg') : document.createElement(tag ?? 'div'), data, svg);
|
|
46
38
|
}
|
|
47
39
|
static makeIn(ctx, tag, data = {}, svg = false) {
|
|
48
|
-
data
|
|
49
|
-
return EL.make(tag, data, svg);
|
|
40
|
+
return EL.make(tag, { ...data, context: ctx }, svg);
|
|
50
41
|
}
|
|
51
42
|
|
|
52
43
|
/**
|
|
@@ -54,77 +45,186 @@ export class EL {
|
|
|
54
45
|
* @param {Node | Array} el элемент или массив элементов
|
|
55
46
|
* @param {object} data параметры
|
|
56
47
|
* @param {Boolean} svg SVG
|
|
57
|
-
* @returns {Node}
|
|
48
|
+
* @returns {Node | Array}
|
|
58
49
|
*/
|
|
59
50
|
static config(el, data, svg = false) {
|
|
51
|
+
if (!(el instanceof Node) || (typeof data !== 'object')) {
|
|
52
|
+
return el;
|
|
53
|
+
}
|
|
60
54
|
if (Array.isArray(el)) {
|
|
61
|
-
el.
|
|
62
|
-
return null;
|
|
55
|
+
return el.map(e => EL.config(e, data, svg));
|
|
63
56
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
else if (obj instanceof EL) el.appendChild(obj.$root);
|
|
74
|
-
else if (typeof obj === 'string') el.innerHTML += obj;
|
|
75
|
-
else if (typeof obj === 'object') {
|
|
76
|
-
let cmp = EL.make(obj.tag ?? 'div', obj, svg || obj.tag == 'svg');
|
|
77
|
-
if (cmp) el.appendChild(cmp);
|
|
57
|
+
|
|
58
|
+
const ctx = ('context' in data) ? (EL.context = data.context) : EL.context;
|
|
59
|
+
|
|
60
|
+
const addChild = obj => {
|
|
61
|
+
if (obj) {
|
|
62
|
+
if (obj instanceof Node) el.appendChild(obj);
|
|
63
|
+
else if (obj instanceof EL) el.appendChild(obj.$root);
|
|
64
|
+
else if (typeof obj === 'string') el.insertAdjacentHTML('beforeend', obj);
|
|
65
|
+
else if (typeof obj === 'object') EL.make(obj.tag, { ...obj, parent: el }, (svg || obj.tag == 'svg'));
|
|
78
66
|
}
|
|
79
67
|
}
|
|
80
68
|
|
|
69
|
+
const call = fn => { if (fn) fn.call(ctx, el, ctx) }
|
|
70
|
+
|
|
81
71
|
for (const [key, val] of Object.entries(data)) {
|
|
82
72
|
switch (key) {
|
|
83
|
-
case 'text':
|
|
84
|
-
|
|
73
|
+
case 'text':
|
|
74
|
+
el.textContent = (val == null) ? '' : String(val); // == - null + undef
|
|
75
|
+
continue;
|
|
76
|
+
|
|
77
|
+
case 'html':
|
|
78
|
+
el.innerHTML = (val == null) ? '' : String(val);
|
|
79
|
+
continue;
|
|
80
|
+
|
|
85
81
|
case 'tag':
|
|
86
|
-
case 'context':
|
|
87
82
|
case 'get':
|
|
88
83
|
case 'also':
|
|
84
|
+
case 'parent':
|
|
85
|
+
case 'context':
|
|
86
|
+
case 'onMount':
|
|
87
|
+
case 'onUpdate':
|
|
88
|
+
case 'onDestroy':
|
|
89
89
|
continue;
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
|
|
92
|
+
if (val === undefined || val === null) continue;
|
|
92
93
|
|
|
93
94
|
switch (key) {
|
|
94
|
-
case '
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
case '
|
|
99
|
-
case '
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
case '
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
case 'push':
|
|
96
|
+
val.push(el);
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
case '$':
|
|
100
|
+
case 'var':
|
|
101
|
+
if (ctx) ctx['$' + val] = el;
|
|
102
|
+
break;
|
|
103
|
+
|
|
104
|
+
case 'events':
|
|
105
|
+
for (let ev in val) el.addEventListener(ev, e => val[ev].call(ctx, e, el, ctx));
|
|
106
|
+
break;
|
|
107
|
+
|
|
108
|
+
case 'click':
|
|
109
|
+
case 'input':
|
|
110
|
+
case 'change':
|
|
111
|
+
case 'mousewheel':
|
|
112
|
+
el.addEventListener(key, e => val.call(ctx, e, el, ctx));
|
|
113
|
+
break;
|
|
114
|
+
|
|
115
|
+
case 'attrs':
|
|
116
|
+
for (let attr in val) el.setAttribute(attr, val[attr]);
|
|
117
|
+
break;
|
|
118
|
+
|
|
119
|
+
case 'props':
|
|
120
|
+
for (let prop in val) el[prop] = val[prop];
|
|
121
|
+
break;
|
|
122
|
+
|
|
123
|
+
case 'data':
|
|
124
|
+
for (let key in val) el.dataset[key] = val[key];
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
case 'child_r':
|
|
128
|
+
EL.clear(el);
|
|
129
|
+
// fall
|
|
130
|
+
case 'child':
|
|
131
|
+
addChild(val);
|
|
132
|
+
break;
|
|
133
|
+
|
|
134
|
+
case 'children_r':
|
|
135
|
+
EL.clear(el);
|
|
136
|
+
// fall
|
|
137
|
+
case 'children':
|
|
138
|
+
for (let obj of val) addChild(obj);
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case 'style_r':
|
|
142
|
+
el.style.cssText = '';
|
|
143
|
+
// fall
|
|
107
144
|
case 'style':
|
|
108
|
-
if (typeof val === 'string')
|
|
109
|
-
|
|
145
|
+
if (typeof val === 'string') {
|
|
146
|
+
el.style.cssText += val + ';';
|
|
147
|
+
} else {
|
|
148
|
+
for (let st in val) if (val[st]) el.style[st] = val[st];
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
|
|
152
|
+
case 'class_r':
|
|
153
|
+
el.className = '';
|
|
154
|
+
// fall
|
|
155
|
+
case 'class': {
|
|
156
|
+
const getClasses = (cls) => {
|
|
157
|
+
if (Array.isArray(cls)) return Object.fromEntries(cls.filter(Boolean).map(c => [c, true]));
|
|
158
|
+
if (typeof cls === 'string') return getClasses(cls.split(/\s+/));
|
|
159
|
+
return cls;
|
|
160
|
+
}
|
|
161
|
+
for (const [cls, state] of Object.entries(getClasses(val))) {
|
|
162
|
+
state ? el.classList.add(cls) : el.classList.remove(cls);
|
|
163
|
+
}
|
|
164
|
+
} break;
|
|
165
|
+
|
|
166
|
+
case 'animate': {
|
|
167
|
+
const { duration = 300, easing = 'ease', onEnd = null, ...styles } = val;
|
|
168
|
+
el.style.transition = Object.keys(styles).map(st => `${st} ${duration}ms ${easing}`).join(', ');
|
|
169
|
+
requestAnimationFrame(() => { for (let st in styles) el.style[st] = styles[st]; });
|
|
170
|
+
|
|
171
|
+
const onEndHandler = () => {
|
|
172
|
+
el.removeEventListener('transitionend', onEndHandler);
|
|
173
|
+
call(onEnd);
|
|
174
|
+
};
|
|
175
|
+
el.addEventListener('transitionend', onEndHandler);
|
|
176
|
+
} break;
|
|
177
|
+
|
|
178
|
+
default: el[key] = val;
|
|
110
179
|
break;
|
|
111
|
-
default: el[key] = val; break;
|
|
112
180
|
}
|
|
113
181
|
}
|
|
114
|
-
|
|
182
|
+
|
|
183
|
+
if (data.parent) data.parent.appendChild(el);
|
|
184
|
+
|
|
185
|
+
let tries = 50;
|
|
186
|
+
const mount = () => {
|
|
187
|
+
if (!el._mounted) {
|
|
188
|
+
if (el.isConnected) {
|
|
189
|
+
el._mounted = true;
|
|
190
|
+
call(data.onMount);
|
|
191
|
+
} else if (--tries) {
|
|
192
|
+
requestAnimationFrame(mount);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
mount();
|
|
197
|
+
|
|
198
|
+
if (data.onDestroy) el._onDestroy = data.onDestroy.bind(ctx, el, ctx);
|
|
199
|
+
if (data.onUpdate) el._onUpdate = data.onUpdate.bind(ctx, el, ctx);
|
|
200
|
+
if (el._onUpdate) el._onUpdate();
|
|
201
|
+
call(data.also);
|
|
202
|
+
|
|
115
203
|
return el;
|
|
116
204
|
}
|
|
117
205
|
static configIn(ctx, el, data, svg = false) {
|
|
118
|
-
data
|
|
119
|
-
return EL.config(el, data, svg);
|
|
206
|
+
return EL.config(el, { ...data, context: ctx }, svg);
|
|
120
207
|
}
|
|
121
208
|
|
|
122
209
|
/**
|
|
123
210
|
* Удалить все child ноды
|
|
124
211
|
* @param {HTMLElement} el
|
|
125
212
|
*/
|
|
126
|
-
static clear(el) {
|
|
127
|
-
while (el.firstChild)
|
|
213
|
+
static clear(el, recursive = true) {
|
|
214
|
+
while (el.firstChild) {
|
|
215
|
+
if (recursive) EL.clear(el.firstChild, true);
|
|
216
|
+
EL.remove(el.firstChild, false);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Удалить элемент
|
|
222
|
+
* @param {HTMLElement} el
|
|
223
|
+
*/
|
|
224
|
+
static remove(el, recursive = true) {
|
|
225
|
+
if (recursive) EL.clear(el);
|
|
226
|
+
if (el._onDestroy) el._onDestroy();
|
|
227
|
+
el.remove();
|
|
128
228
|
}
|
|
129
229
|
|
|
130
230
|
/**
|
|
@@ -135,7 +235,10 @@ export class EL {
|
|
|
135
235
|
*/
|
|
136
236
|
static makeArray(arr, svg = false) {
|
|
137
237
|
if (!arr || !Array.isArray(arr)) return [];
|
|
138
|
-
return arr.map(
|
|
238
|
+
return arr.map(data => EL.make(data.tag, data, svg));
|
|
239
|
+
}
|
|
240
|
+
static makeArrayIn(ctx, arr, svg) {
|
|
241
|
+
return EL.makeArray(arr.map(data => ({ ...data, context: ctx })), svg);
|
|
139
242
|
}
|
|
140
243
|
|
|
141
244
|
/**
|
|
@@ -167,11 +270,33 @@ export class EL {
|
|
|
167
270
|
EL.config($host, data);
|
|
168
271
|
return $host;
|
|
169
272
|
}
|
|
273
|
+
static makeShadowIn(ctx, host, data = {}, sheet = null) {
|
|
274
|
+
return EL.makeShadow(host, { ...data, context: ctx }, sheet);
|
|
275
|
+
}
|
|
170
276
|
}
|
|
171
277
|
|
|
172
278
|
// legacy
|
|
173
279
|
export const Component = EL;
|
|
174
280
|
|
|
281
|
+
//#region State
|
|
282
|
+
export class State {
|
|
283
|
+
constructor(init = {}) {
|
|
284
|
+
this.data = init;
|
|
285
|
+
this.subs = new Set();
|
|
286
|
+
}
|
|
287
|
+
set(key, value) {
|
|
288
|
+
this.data[key] = value;
|
|
289
|
+
this.subs.forEach(fn => fn(this.data));
|
|
290
|
+
}
|
|
291
|
+
get(key) {
|
|
292
|
+
return this.data[key];
|
|
293
|
+
}
|
|
294
|
+
subscribe(fn) {
|
|
295
|
+
this.subs.add(fn);
|
|
296
|
+
return () => this.subs.delete(fn);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
175
300
|
//#region SVG
|
|
176
301
|
export class SVG {
|
|
177
302
|
static make = (tag, data) => EL.make(tag, data, true);
|
package/Component.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e={d:(t,a)=>{for(var
|
|
1
|
+
var e={d:(t,a)=>{for(var n in a)e.o(a,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:a[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{EL:()=>a,LV:()=>o,Uw:()=>s,cj:()=>c,t4:()=>r,uA:()=>n});class a{static context;constructor(e,t={},n=!1){this.$root=a.makeIn(this,e,t,n)}make(e,t={},n=!1){return a.makeIn(this,e,t,n)}makeArray(e,t=!1){return a.makeArrayIn(this,e,t)}config(e,t,n=!1){return a.configIn(this,e,t,n)}makeShadow(e,t={},n=null){return a.makeShadowIn(this,e,t,n)}static make(e,t={},n=!1){return t instanceof Node?t:("svg"==e&&(n=!0),a.config(n?document.createElementNS("http://www.w3.org/2000/svg",e??"svg"):document.createElement(e??"div"),t,n))}static makeIn(e,t,n={},s=!1){return a.make(t,{...n,context:e},s)}static config(e,t,n=!1){if(!(e instanceof Node)||"object"!=typeof t)return e;if(Array.isArray(e))return e.map(e=>a.config(e,t,n));const s="context"in t?a.context=t.context:a.context,r=t=>{t&&(t instanceof Node?e.appendChild(t):t instanceof a?e.appendChild(t.$root):"string"==typeof t?e.insertAdjacentHTML("beforeend",t):"object"==typeof t&&a.make(t.tag,{...t,parent:e},n||"svg"==t.tag))},c=t=>{t&&t.call(s,e,s)};for(const[n,o]of Object.entries(t)){switch(n){case"text":e.textContent=null==o?"":String(o);continue;case"html":e.innerHTML=null==o?"":String(o);continue;case"tag":case"get":case"also":case"parent":case"context":case"onMount":case"onUpdate":case"onDestroy":continue}if(null!=o)switch(n){case"push":o.push(e);break;case"$":case"var":s&&(s["$"+o]=e);break;case"events":for(let t in o)e.addEventListener(t,a=>o[t].call(s,a,e,s));break;case"click":case"input":case"change":case"mousewheel":e.addEventListener(n,t=>o.call(s,t,e,s));break;case"attrs":for(let t in o)e.setAttribute(t,o[t]);break;case"props":for(let t in o)e[t]=o[t];break;case"data":for(let t in o)e.dataset[t]=o[t];break;case"child_r":a.clear(e);case"child":r(o);break;case"children_r":a.clear(e);case"children":for(let e of o)r(e);break;case"style_r":e.style.cssText="";case"style":if("string"==typeof o)e.style.cssText+=o+";";else for(let t in o)o[t]&&(e.style[t]=o[t]);break;case"class_r":e.className="";case"class":{const t=e=>Array.isArray(e)?Object.fromEntries(e.filter(Boolean).map(e=>[e,!0])):"string"==typeof e?t(e.split(/\s+/)):e;for(const[a,n]of Object.entries(t(o)))n?e.classList.add(a):e.classList.remove(a)}break;case"animate":{const{duration:t=300,easing:a="ease",onEnd:n=null,...s}=o;e.style.transition=Object.keys(s).map(e=>`${e} ${t}ms ${a}`).join(", "),requestAnimationFrame(()=>{for(let t in s)e.style[t]=s[t]});const r=()=>{e.removeEventListener("transitionend",r),c(n)};e.addEventListener("transitionend",r)}break;default:e[n]=o}}t.parent&&t.parent.appendChild(e);let o=50;const i=()=>{e._mounted||(e.isConnected?(e._mounted=!0,c(t.onMount)):--o&&requestAnimationFrame(i))};return i(),t.onDestroy&&(e._onDestroy=t.onDestroy.bind(s,e,s)),t.onUpdate&&(e._onUpdate=t.onUpdate.bind(s,e,s)),e._onUpdate&&e._onUpdate(),c(t.also),e}static configIn(e,t,n,s=!1){return a.config(t,{...n,context:e},s)}static clear(e,t=!0){for(;e.firstChild;)t&&a.clear(e.firstChild,!0),a.remove(e.firstChild,!1)}static remove(e,t=!0){t&&a.clear(e),e._onDestroy&&e._onDestroy(),e.remove()}static makeArray(e,t=!1){return e&&Array.isArray(e)?e.map(e=>a.make(e.tag,e,t)):[]}static makeArrayIn(e,t,n){return a.makeArray(t.map(t=>({...t,context:e})),n)}static makeShadow(e,t={},n=null){if(!e||"object"!=typeof t)return null;let s=e instanceof Node?e:document.createElement(e);return s.attachShadow({mode:"open"}),a.config(s.shadowRoot,{context:t.context,children:[{tag:"style",textContent:n??""},t.child??{},...t.children??[]]}),delete t.children,delete t.child,a.config(s,t),s}static makeShadowIn(e,t,n={},s=null){return a.makeShadow(t,{...n,context:e},s)}}const n=a;class s{constructor(e={}){this.data=e,this.subs=new Set}set(e,t){this.data[e]=t,this.subs.forEach(e=>e(this.data))}get(e){return this.data[e]}subscribe(e){return this.subs.add(e),()=>this.subs.delete(e)}}class r{static make=(e,t)=>a.make(e,t,!0);static config=(e,t)=>a.config(e,t,!0);static makeArray=e=>a.makeArray(e,!0);static svg=(e={},t={})=>r._make("svg",e,t);static rect=(e,t,a,n,s,c,o={},i={})=>r._make("rect",{...o,x:e,y:t,width:a,height:n,rx:s,ry:c},i);static circle=(e,t,a,n={},s={})=>r._make("circle",{...n,cx:e,cy:t,r:a},s);static line=(e,t,a,n,s={},c={})=>r._make("line",{...s,x1:e,y1:t,x2:a,y2:n},c);static polyline=(e,t={},a={})=>r._make("polyline",{...t,points:e},a);static polygon=(e,t={},a={})=>r._make("polygon",{...t,points:e},a);static path=(e,t={},a={})=>r._make("path",{...t,d:e},a);static text=(e,t,a,n={},s={})=>r._make("text",{...n,x:t,y:a},{...s,text:e});static _make=(e,t={},a={})=>r.make(e,{attrs:{...t},...a})}class c{static addStyle(e,t,a=!1){if(e&&t&&("object"==typeof t&&(t=t.constructor.name),!c.#e.has(t)&&!c.#t.has(t)))if(a){let a=document.createElement("style");document.head.appendChild(a),a.textContent=e,c.#t.set(t,a)}else c.#a||(c.#a=document.head.appendChild(document.createElement("style"))),c.#a.textContent+=e+"\r\n",c.#e.add(t)}static removeStyle(e){"object"==typeof e&&(e=e.constructor.name),c.#t.has(e)&&(c.#t.get(e).remove(),c.#t.delete(e))}static#a=null;static#e=new Set;static#t=new Map}class o extends a{constructor(e,t={},a=null,n=null,s=!1){super(e,t),c.addStyle(a,n,s)}static make(e,t={},n=null,s=null,r=!1){return c.addStyle(n,s,r),a.make(e,t)}}const i=t.uA,l=t.EL,d=t.t4,m=t.cj,u=t.Uw,h=t.LV;export{i as Component,l as EL,d as SVG,m as Sheet,u as State,h as StyledComponent};
|
package/README.md
CHANGED
|
@@ -4,47 +4,63 @@
|
|
|
4
4
|
> npm i @alexgyver/component
|
|
5
5
|
|
|
6
6
|
## Дока
|
|
7
|
-
###
|
|
7
|
+
### EL
|
|
8
|
+
Параметры для конфига `data`:
|
|
9
|
+
|
|
10
|
+
- `context` [объект] - привязывает контекст для других параметров (см ниже), пробрасывается в детей и не сбрасывается между вызовами make/config
|
|
11
|
+
- `$` [текст] - добавляет созданный элемент в context с именем `$значение`
|
|
12
|
+
- `events` [объект] - подключает события `{ eventName: handlerFunc(event, element, context) }`, в this тоже прокидывается context
|
|
13
|
+
- `click`, `change`, `input`, `mousewheel` [функция] - подключает эти события как `handlerFunc(event, element, context)`, в this тоже прокидывается context
|
|
14
|
+
- `also` [функция] - вызывает указанную функцию вида `handlerFunc(element, context)`, в this тоже прокидывается context
|
|
15
|
+
- `text` [текст] - добавится в textContent, nullish значения - очистить
|
|
16
|
+
- `html` [текст] - добавится в innerHTML, nullish значения - очистить
|
|
17
|
+
- `tag` [текст] - HTML тег для child-объектов
|
|
18
|
+
- `push` [массив] - добавляет созданный элемент в указанный массив
|
|
19
|
+
- `parent` [Node] - добавит к нему созданный элемент как child
|
|
20
|
+
- `attrs` [объект] - аттрибуты будут установлены через setAttribute
|
|
21
|
+
- `props` [объект] - свойства будут установлены как el[prop] = val
|
|
22
|
+
- `data` [объект] - датасеты будут добавлены как аттрибуты data-name = value
|
|
23
|
+
- `child`, `child_r` [объект] конфиг, добавится как ребёнок к созданному элементу. Без указания tag будет добавлен div. `_r` - заменить ребёнка
|
|
24
|
+
- `children`, `children_r` [массив] объектов конфига, добавятся как дети к созданному элементу. Без указания tag будет добавлен div. `_r` - заменить всех детей на новых
|
|
25
|
+
- `animate` [объект] - добавить CSS анимаций, может содержать параметры анимации `duration` и `easing`, обработчик окончания анимации `onEnd(element, context)`, в this тоже прокидывается context
|
|
26
|
+
- `style`, `style_r` - стили. Принимает:
|
|
27
|
+
- [Строка] CSS стилей
|
|
28
|
+
- [Объект] вида `{styleName: value}`
|
|
29
|
+
- `class`, `class_r` - установка классов в classList, версия с `_r` - заменить классы. Принимает:
|
|
30
|
+
- [Строку] вида `newClass active foo bar`
|
|
31
|
+
- [Массив] вида `['newClass', 'active']`, причём можно по условию: `['newClass', isActive && 'active']`
|
|
32
|
+
- [Объект] вида `{newClass: true, active: false}` - true значение добавляет класс, false не добавляет
|
|
33
|
+
- `onUpdate` [функция] вида `handlerFunc(element, context)`, вызовется при настройке через функцию config, в this тоже прокидывается context
|
|
34
|
+
- `onMount` [функция] вида `handlerFunc(element, context)`, вызовется при присоединении к DOM, в this тоже прокидывается context
|
|
35
|
+
- `onDestroy` [функция] вида `handlerFunc(element, context)`, вызовется при удалении через EL.remove(el) или EL.clear(el), в this тоже прокидывается context
|
|
36
|
+
- Другие значения будут добавлены как свойства
|
|
37
|
+
|
|
38
|
+
#### Класс
|
|
8
39
|
```js
|
|
9
40
|
/**
|
|
10
|
-
* Создать компонент и поместить его в переменную
|
|
41
|
+
* Создать компонент и поместить его в переменную this.$root
|
|
11
42
|
* @param {string} tag html tag элемента
|
|
12
43
|
* @param {object} data параметры
|
|
13
44
|
*/
|
|
14
45
|
EL(tag, data = {}, svg = false);
|
|
15
46
|
|
|
47
|
+
// аналоги с авто-this контекстом для вызова внутри класса
|
|
48
|
+
make(tag, data = {}, svg = false);
|
|
49
|
+
makeArray(arr, svg = false);
|
|
50
|
+
config(el, data, svg = false);
|
|
51
|
+
makeShadow(host, data = {}, sheet = null);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Static
|
|
55
|
+
```js
|
|
16
56
|
/**
|
|
17
57
|
* Создать компонент
|
|
18
58
|
* @param {string} tag html tag элемента
|
|
19
59
|
* @param {object} data параметры
|
|
20
60
|
* @returns {Node}
|
|
21
|
-
* tag {string} - тег html элемента. Если 'svg' - включится режим SVG на детей
|
|
22
|
-
* context {object} - контекст для параметра 'var' и вызовов, прокидывается в детей. Если указан явно как null - прерывает проброс
|
|
23
|
-
* parent - {Element} добавляет компонент к указанному элементу
|
|
24
|
-
* text {string} - добавить в textContent
|
|
25
|
-
* html {string} - добавить в innerHTML
|
|
26
|
-
* class {string | Array} - добавить в className
|
|
27
|
-
* style {string | object} - объект в виде { padding: '0px', ... } или строка css стилей
|
|
28
|
-
* push {array} - добавить к указанному массиву
|
|
29
|
-
* var | $ {string} - создаёт переменную $имя в указанном контексте
|
|
30
|
-
* events {object} - добавляет addEventListener'ы {event: e => {}}
|
|
31
|
-
* children/children_r - массив {DOM, EL, object, html string}. _r - заменить имеющиеся. Без тега tag будет div
|
|
32
|
-
* child/child_r - {DOM, EL, object, html string}. _r - заменить имеющиеся. Без тега tag будет div
|
|
33
|
-
* attrs {object} - добавить аттрибуты (через setAttribute)
|
|
34
|
-
* props {object} - добавить свойства (как el[prop])
|
|
35
|
-
* also {function} - вызвать с текущим компонентом: also(el) { console.log(el); }
|
|
36
|
-
* всё остальное будет добавлено как property
|
|
37
61
|
*/
|
|
38
62
|
EL.make(tag, data = {});
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Создать теневой компонент от указанного tag, дети подключатся к нему в shadowRoot
|
|
42
|
-
* @param {string|Node} host html tag теневого элемента или Node
|
|
43
|
-
* @param {object} data параметры внешнего элемента
|
|
44
|
-
* @param {string} sheet css стили
|
|
45
|
-
* @returns {Node} host
|
|
46
|
-
*/
|
|
47
|
-
EL.makeShadow(host, data = {}, sheet = null);
|
|
63
|
+
EL.makeIn(ctx, tag, data = {}, svg = false);
|
|
48
64
|
|
|
49
65
|
/**
|
|
50
66
|
* Настроить элемент
|
|
@@ -53,6 +69,7 @@ EL.makeShadow(host, data = {}, sheet = null);
|
|
|
53
69
|
* @returns {Node}
|
|
54
70
|
*/
|
|
55
71
|
EL.config(el, data);
|
|
72
|
+
EL.configIn(ctx, el, data, svg = false);
|
|
56
73
|
|
|
57
74
|
/**
|
|
58
75
|
* Создать массив компонентов из массива объектов конфигурации
|
|
@@ -60,6 +77,29 @@ EL.config(el, data);
|
|
|
60
77
|
* @returns {array} of Elements
|
|
61
78
|
*/
|
|
62
79
|
EL.makeArray(arr);
|
|
80
|
+
EL.makeArrayIn(ctx, arr, svg);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Создать теневой компонент от указанного tag, дети подключатся к нему в shadowRoot
|
|
84
|
+
* @param {string|Node} host html tag теневого элемента или Node
|
|
85
|
+
* @param {object} data параметры внешнего элемента
|
|
86
|
+
* @param {string} sheet css стили
|
|
87
|
+
* @returns {Node} host
|
|
88
|
+
*/
|
|
89
|
+
EL.makeShadow(host, data = {}, sheet = null);
|
|
90
|
+
EL.makeShadowIn(ctx, host, data = {}, sheet = null);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Удалить все child ноды
|
|
94
|
+
* @param {HTMLElement} el
|
|
95
|
+
*/
|
|
96
|
+
EL.clear(el, recursive = true);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Удалить элемент
|
|
100
|
+
* @param {HTMLElement} el
|
|
101
|
+
*/
|
|
102
|
+
EL.remove(el, recursive = true);
|
|
63
103
|
```
|
|
64
104
|
|
|
65
105
|
### SVG
|
|
@@ -118,8 +158,9 @@ StyledComponent(tag, data = {}, style = null, id = null, ext = false);
|
|
|
118
158
|
StyledComponent.make(tag, data = {}, style = null, id = null, ext = false);
|
|
119
159
|
```
|
|
120
160
|
|
|
121
|
-
##
|
|
161
|
+
## Примеры
|
|
122
162
|
Создаст контейнер с двумя вложенными блоками текста и прикрепит к body
|
|
163
|
+
|
|
123
164
|
```js
|
|
124
165
|
EL.make('div', {
|
|
125
166
|
parent: document.body,
|
|
@@ -143,6 +184,46 @@ EL.make('div', {
|
|
|
143
184
|
});
|
|
144
185
|
```
|
|
145
186
|
|
|
187
|
+
Простой элемент с текстом и классами
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
const box = new EL('div', {
|
|
191
|
+
text: 'Привет, мир!',
|
|
192
|
+
class: ['box', 'highlight'],
|
|
193
|
+
style: { padding: '10px', color: 'white', backgroundColor: 'blue' },
|
|
194
|
+
click() { console.log('Box кликнут!'); },
|
|
195
|
+
$: 'myBox' // создаёт ctx.$myBox
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
document.body.appendChild(box.$root);
|
|
199
|
+
console.log(box.$root); // сам DOM-элемент
|
|
200
|
+
console.log(EL.context.$myBox); // доступ через контекст
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Полная замена классов и стилей
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
EL.config(someElement, {
|
|
207
|
+
text: 'Обновлённый блок',
|
|
208
|
+
class_r: ['newClass', 'active'], // полностью заменяет классы
|
|
209
|
+
style_r: { color: 'red', fontWeight: 'bold' } // сброс и новые стили
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Вложенные дети и массив children
|
|
214
|
+
|
|
215
|
+
```cpp
|
|
216
|
+
EL.make('div', {
|
|
217
|
+
parent: document.body,
|
|
218
|
+
class: 'parent',
|
|
219
|
+
children: [
|
|
220
|
+
{ tag: 'p', text: 'Первый ребёнок', class: 'child' },
|
|
221
|
+
{ tag: 'p', text: 'Второй ребёнок', class: ['child', 'second'] },
|
|
222
|
+
'Просто текстовый узел'
|
|
223
|
+
]
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
146
227
|
Гораздо интереснее использовать в классе и передавать контекст. Параметр `$` создаст переменную с элементом с указанным именем + префикс `$`:
|
|
147
228
|
|
|
148
229
|
```js
|
|
@@ -166,6 +247,25 @@ let btn = new Button('kek');
|
|
|
166
247
|
btn.$button; // элемент кнопки
|
|
167
248
|
```
|
|
168
249
|
|
|
250
|
+
Использование контекста для $ и событий
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
class MyComponent extends EL {
|
|
254
|
+
constructor() {
|
|
255
|
+
super('div', {
|
|
256
|
+
class: 'comp',
|
|
257
|
+
$: 'root',
|
|
258
|
+
children: [
|
|
259
|
+
{ tag: 'button', text: 'Нажми меня', click() { console.log(this.$root); } }
|
|
260
|
+
]
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const comp = new MyComponent();
|
|
266
|
+
document.body.appendChild(comp.$root);
|
|
267
|
+
```
|
|
268
|
+
|
|
169
269
|
Некоторые трюки
|
|
170
270
|
|
|
171
271
|
```js
|
|
@@ -194,3 +294,47 @@ EL.make('div', {
|
|
|
194
294
|
class: ['some', 'class', foo && 'plus_me'], // добавить plus_me если foo - true
|
|
195
295
|
});
|
|
196
296
|
```
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
Создание SVG
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
const svg = SVG.svg({ width: 200, height: 200 }, {
|
|
303
|
+
children: [
|
|
304
|
+
SVG.rect(10, 10, 50, 50, 5, 5, { fill: 'green' }),
|
|
305
|
+
SVG.circle(100, 100, 40, { fill: 'red' }),
|
|
306
|
+
SVG.line(0, 0, 200, 200, { stroke: 'blue', 'stroke-width': 2 })
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Shadow DOM со стилями
|
|
312
|
+
|
|
313
|
+
```js
|
|
314
|
+
const shadowHost = EL.makeShadow('div', {
|
|
315
|
+
child: { tag: 'p', text: 'Текст внутри Shadow DOM', class: 'shadow-text' }
|
|
316
|
+
}, `
|
|
317
|
+
.shadow-text { color: purple; font-weight: bold; }
|
|
318
|
+
`);
|
|
319
|
+
|
|
320
|
+
document.body.appendChild(shadowHost);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
Прочее
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
const state = new State({ count: 0 });
|
|
328
|
+
|
|
329
|
+
let d = EL.make('div', {
|
|
330
|
+
text: state.get('count'),
|
|
331
|
+
also: el => state.subscribe(d => el.textContent = d.count),
|
|
332
|
+
style: { width: '100px', height: '50px', background: 'red' },
|
|
333
|
+
animate: { width: '200px', background: 'blue', duration: 500 },
|
|
334
|
+
onUpdate: el => console.log('update'),
|
|
335
|
+
onMount: el => console.log('mount'),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
setInterval(() => state.set('count', state.get('count') + 1), 1000);
|
|
339
|
+
setTimeout(() => { document.body.appendChild(d) }, 2000);
|
|
340
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexgyver/component",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Simple HTML&SVG element builder",
|
|
5
5
|
"main": "./Component.js",
|
|
6
6
|
"module": "./Component.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"author": "AlexGyver <alex@alexgyver.ru>",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"webpack": "^5.
|
|
18
|
+
"webpack": "^5.105.0",
|
|
19
19
|
"webpack-cli": "^6.0.1"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/test/script.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { EL, Sheet, StyledComponent } from "https://gyverlibs.github.io/
|
|
1
|
+
// import { EL, Sheet, StyledComponent } from "https://gyverlibs.github.io/Component.js/Component.min.js";
|
|
2
|
+
import { EL, Sheet, StyledComponent } from "../Component.js";
|
|
2
3
|
|
|
3
4
|
// кнопка наследует, стили добавляются отдельно
|
|
4
5
|
class Button extends EL {
|
|
@@ -105,6 +106,29 @@ class ShadowComponent {
|
|
|
105
106
|
|
|
106
107
|
document.addEventListener('kek', () => console.log('kek!'));
|
|
107
108
|
|
|
109
|
+
let context = { ctx: 'ctx' };
|
|
110
|
+
|
|
111
|
+
let d = EL.make('div', {
|
|
112
|
+
context: context,
|
|
113
|
+
parent: document.body,
|
|
114
|
+
text: 'test',
|
|
115
|
+
style: { width: '100px', height: '50px', background: 'red' },
|
|
116
|
+
animate: { width: '200px', background: 'blue', duration: 500, onEnd: function (el) { console.log('anim', this, el) } },
|
|
117
|
+
events: {
|
|
118
|
+
mouseleave: function (e, el) { console.log('leave', this, e, el) },
|
|
119
|
+
},
|
|
120
|
+
click: (e, el, ctx) => console.log('click', this, e, el, ctx),
|
|
121
|
+
also: function (el) { console.log('also', this, el) },
|
|
122
|
+
onUpdate: (el, ctx) => console.log('update', this, el, ctx),
|
|
123
|
+
onDestroy: (el, ctx) => console.log('destroy', this, el, ctx),
|
|
124
|
+
// onMount: el => console.log('mount', this),
|
|
125
|
+
onMount: function (el) { console.log('mount', this, el) },
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// setTimeout(() => { document.body.appendChild(d) }, 2000);
|
|
129
|
+
setTimeout(() => { EL.config(d, { text: 123 }) }, 2000);
|
|
130
|
+
setTimeout(() => { EL.remove(d) }, 4000);
|
|
131
|
+
|
|
108
132
|
document.addEventListener("DOMContentLoaded", () => {
|
|
109
133
|
EL.make('h1', {
|
|
110
134
|
text: 'Hello!',
|