@alexgyver/component 1.5.0 → 2.0.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.min.js +1 -1
- package/Component.min.js.gz +0 -0
- package/Component.pico.min.js +1 -0
- package/Component.pico.min.js.gz +0 -0
- package/Component.tiny.min.js +1 -0
- package/Component.tiny.min.js.gz +0 -0
- package/README.md +651 -259
- package/package.json +16 -9
- package/src/Component.js +15 -0
- package/src/EL.js +371 -0
- package/src/SVG.js +18 -0
- package/src/Sheet.js +73 -0
- package/src/State.js +47 -0
- package/src/utils.js +94 -0
- package/test/index.html +12 -0
- package/test/script.js +434 -148
- package/webpack.config.js +29 -10
- package/webpack.dev.config.js +32 -0
- package/Component.js +0 -388
- package/test/example.html +0 -15
package/Component.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
//#region EL
|
|
2
|
-
export class EL {
|
|
3
|
-
static context;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Создать элемент и поместить его в переменную $root
|
|
7
|
-
* @param {string} tag html tag элемента
|
|
8
|
-
* @param {object} data параметры
|
|
9
|
-
* @param {Boolean} svg SVG
|
|
10
|
-
*/
|
|
11
|
-
constructor(tag, data = {}, svg = false) {
|
|
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);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Создать элемент
|
|
29
|
-
* @param {string} tag html tag элемента
|
|
30
|
-
* @param {object} data параметры
|
|
31
|
-
* @param {Boolean} svg SVG
|
|
32
|
-
* @returns {Node}
|
|
33
|
-
*/
|
|
34
|
-
static make(tag, data = {}, svg = false) {
|
|
35
|
-
if (data instanceof Node) return data;
|
|
36
|
-
if (tag == 'svg') svg = true;
|
|
37
|
-
return EL.config(svg ? document.createElementNS("http://www.w3.org/2000/svg", tag ?? 'svg') : document.createElement(tag ?? 'div'), data, svg);
|
|
38
|
-
}
|
|
39
|
-
static makeIn(ctx, tag, data = {}, svg = false) {
|
|
40
|
-
return EL.make(tag, { ...data, context: ctx }, svg);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Настроить элемент
|
|
45
|
-
* @param {Node | Array} el элемент или массив элементов
|
|
46
|
-
* @param {object} data параметры
|
|
47
|
-
* @param {Boolean} svg SVG
|
|
48
|
-
* @returns {Node | Array}
|
|
49
|
-
*/
|
|
50
|
-
static config(el, data, svg = false) {
|
|
51
|
-
if (!(el instanceof Node) || (typeof data !== 'object')) {
|
|
52
|
-
return el;
|
|
53
|
-
}
|
|
54
|
-
if (Array.isArray(el)) {
|
|
55
|
-
return el.map(e => EL.config(e, data, svg));
|
|
56
|
-
}
|
|
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'));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const call = fn => { if (fn) fn.call(ctx, el, ctx) }
|
|
70
|
-
|
|
71
|
-
for (const [key, val] of Object.entries(data)) {
|
|
72
|
-
switch (key) {
|
|
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
|
-
|
|
81
|
-
case 'tag':
|
|
82
|
-
case 'get':
|
|
83
|
-
case 'also':
|
|
84
|
-
case 'parent':
|
|
85
|
-
case 'context':
|
|
86
|
-
case 'onMount':
|
|
87
|
-
case 'onUpdate':
|
|
88
|
-
case 'onDestroy':
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (val === undefined || val === null) continue;
|
|
93
|
-
|
|
94
|
-
switch (key) {
|
|
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
|
|
144
|
-
case 'style':
|
|
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;
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
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
|
-
|
|
203
|
-
return el;
|
|
204
|
-
}
|
|
205
|
-
static configIn(ctx, el, data, svg = false) {
|
|
206
|
-
return EL.config(el, { ...data, context: ctx }, svg);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Удалить все child ноды
|
|
211
|
-
* @param {HTMLElement} el
|
|
212
|
-
*/
|
|
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();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Создать массив элементов из массива объектов конфигурации
|
|
232
|
-
* @param {array} arr массив объектов конфигурации
|
|
233
|
-
* @param {Boolean} svg SVG
|
|
234
|
-
* @returns {array} of Elements
|
|
235
|
-
*/
|
|
236
|
-
static makeArray(arr, svg = false) {
|
|
237
|
-
if (!arr || !Array.isArray(arr)) return [];
|
|
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);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Создать теневой элемент от указанного tag, дети подключатся к нему в shadowRoot
|
|
246
|
-
* @param {string|Node} host html tag теневого элемента или Node
|
|
247
|
-
* @param {object} data параметры внешнего элемента
|
|
248
|
-
* @param {string} sheet css стили
|
|
249
|
-
* @returns {Node} host
|
|
250
|
-
*/
|
|
251
|
-
static makeShadow(host, data = {}, sheet = null) {
|
|
252
|
-
if (!host || typeof data !== 'object') return null;
|
|
253
|
-
|
|
254
|
-
let $host = (host instanceof Node) ? host : document.createElement(host);
|
|
255
|
-
$host.attachShadow({ mode: 'open' });
|
|
256
|
-
|
|
257
|
-
EL.config($host.shadowRoot, {
|
|
258
|
-
context: data.context,
|
|
259
|
-
children: [
|
|
260
|
-
{
|
|
261
|
-
tag: 'style',
|
|
262
|
-
textContent: sheet ?? '',
|
|
263
|
-
},
|
|
264
|
-
data.child ?? {},
|
|
265
|
-
...(data.children ?? []),
|
|
266
|
-
]
|
|
267
|
-
});
|
|
268
|
-
delete data.children;
|
|
269
|
-
delete data.child;
|
|
270
|
-
EL.config($host, data);
|
|
271
|
-
return $host;
|
|
272
|
-
}
|
|
273
|
-
static makeShadowIn(ctx, host, data = {}, sheet = null) {
|
|
274
|
-
return EL.makeShadow(host, { ...data, context: ctx }, sheet);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// legacy
|
|
279
|
-
export const Component = EL;
|
|
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
|
-
|
|
300
|
-
//#region SVG
|
|
301
|
-
export class SVG {
|
|
302
|
-
static make = (tag, data) => EL.make(tag, data, true);
|
|
303
|
-
static config = (el, data) => EL.config(el, data, true);
|
|
304
|
-
static makeArray = (arr) => EL.makeArray(arr, true);
|
|
305
|
-
|
|
306
|
-
static svg = (attrs = {}, props = {}) => SVG._make('svg', attrs, props);
|
|
307
|
-
static rect = (x, y, w, h, rx, ry, attrs = {}, props = {}) => SVG._make('rect', { ...attrs, x: x, y: y, width: w, height: h, rx: rx, ry: ry }, props);
|
|
308
|
-
static circle = (x, y, r, attrs = {}, props = {}) => SVG._make('circle', { ...attrs, cx: x, cy: y, r: r }, props);
|
|
309
|
-
static line = (x1, y1, x2, y2, attrs = {}, props = {}) => SVG._make('line', { ...attrs, x1: x1, y1: y1, x2: x2, y2: y2 }, props);
|
|
310
|
-
static polyline = (points, attrs = {}, props = {}) => SVG._make('polyline', { ...attrs, points: points }, props);
|
|
311
|
-
static polygon = (points, attrs = {}, props = {}) => SVG._make('polygon', { ...attrs, points: points }, props);
|
|
312
|
-
static path = (d, attrs = {}, props = {}) => SVG._make('path', { ...attrs, d: d }, props);
|
|
313
|
-
static text = (text, x, y, attrs = {}, props = {}) => SVG._make('text', { ...attrs, x: x, y: y }, { ...props, text: text });
|
|
314
|
-
|
|
315
|
-
static _make = (tag, attrs = {}, props = {}) => SVG.make(tag, { attrs: { ...attrs }, ...props });
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
//#region Sheet
|
|
319
|
-
export class Sheet {
|
|
320
|
-
/**
|
|
321
|
-
* Добавить стиль с уникальным id в head. ext - стиль можно будет удалить по id
|
|
322
|
-
* @param {string|array} style стили в виде css строки
|
|
323
|
-
* @param {string|this} id уникальный id стиля. При передаче this будет именем класса
|
|
324
|
-
* @param {boolean} ext внешний стиль - может быть удалён по id
|
|
325
|
-
*/
|
|
326
|
-
static addStyle(style, id, ext = false) {
|
|
327
|
-
if (!style || !id) return;
|
|
328
|
-
if (typeof id === 'object') id = id.constructor.name;
|
|
329
|
-
|
|
330
|
-
if (!Sheet.#int.has(id) && !Sheet.#ext.has(id)) {
|
|
331
|
-
if (ext) {
|
|
332
|
-
let sheet = document.createElement('style');
|
|
333
|
-
document.head.appendChild(sheet);
|
|
334
|
-
sheet.textContent = style;
|
|
335
|
-
Sheet.#ext.set(id, sheet);
|
|
336
|
-
} else {
|
|
337
|
-
if (!Sheet.#sheet) Sheet.#sheet = document.head.appendChild(document.createElement('style'));
|
|
338
|
-
Sheet.#sheet.textContent += style + '\r\n';
|
|
339
|
-
Sheet.#int.add(id);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Удалить ext стиль по его id
|
|
346
|
-
* @param {string} id id стиля. При передаче this будет именем класса
|
|
347
|
-
*/
|
|
348
|
-
static removeStyle(id) {
|
|
349
|
-
if (typeof id === 'object') id = id.constructor.name;
|
|
350
|
-
if (Sheet.#ext.has(id)) {
|
|
351
|
-
Sheet.#ext.get(id).remove();
|
|
352
|
-
Sheet.#ext.delete(id);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
static #sheet = null;
|
|
357
|
-
static #int = new Set();
|
|
358
|
-
static #ext = new Map();
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
//#region StyledComponent
|
|
362
|
-
export class StyledComponent extends EL {
|
|
363
|
-
/**
|
|
364
|
-
* Создать элемент и поместить его в переменную $root
|
|
365
|
-
* @param {string} tag html tag элемента
|
|
366
|
-
* @param {object} data параметры
|
|
367
|
-
* @param {string|array} style стили в виде css строки
|
|
368
|
-
* @param {string|this} id уникальный id стиля. При передаче this будет именем класса
|
|
369
|
-
* @param {boolean} ext внешний стиль - может быть удалён по id
|
|
370
|
-
*/
|
|
371
|
-
constructor(tag, data = {}, style = null, id = null, ext = false) {
|
|
372
|
-
super(tag, data);
|
|
373
|
-
Sheet.addStyle(style, id, ext);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Создать элемент
|
|
378
|
-
* @param {string} tag html tag элемента
|
|
379
|
-
* @param {object} data параметры
|
|
380
|
-
* @param {string|array} style стили в виде css строки
|
|
381
|
-
* @param {string|this} id уникальный id стиля. При передаче this будет именем класса
|
|
382
|
-
* @param {boolean} ext внешний стиль - может быть удалён по id
|
|
383
|
-
*/
|
|
384
|
-
static make(tag, data = {}, style = null, id = null, ext = false) {
|
|
385
|
-
Sheet.addStyle(style, id, ext);
|
|
386
|
-
return EL.make(tag, data);
|
|
387
|
-
}
|
|
388
|
-
}
|
package/test/example.html
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>Document</title>
|
|
8
|
-
<script type="module" src="script.js"></script>
|
|
9
|
-
</head>
|
|
10
|
-
|
|
11
|
-
<body>
|
|
12
|
-
|
|
13
|
-
</body>
|
|
14
|
-
|
|
15
|
-
</html>
|