@htmlplus/element 0.1.0 → 0.1.1
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/README.md +119 -55
- package/dist/client/decorators/attributes.js +3 -2
- package/dist/client/decorators/bind.d.ts +1 -1
- package/dist/client/decorators/event.d.ts +1 -1
- package/dist/client/decorators/listen.d.ts +1 -1
- package/dist/client/decorators/listen.js +5 -3
- package/dist/client/decorators/method.d.ts +1 -1
- package/dist/client/decorators/property.d.ts +1 -1
- package/dist/client/decorators/state.d.ts +1 -1
- package/dist/client/utils/decorator.d.ts +1 -1
- package/dist/client/utils/decorator.js +4 -2
- package/dist/client/utils/define-method.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
# Create Custom HTML Element
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@htmlplus/element)
|
|
4
|
+
[](https://github.com/htmlplus/element/network/members)
|
|
5
|
+
[](https://github.com/htmlplus/element/stargazers)
|
|
6
|
+
[](https://github.com/htmlplus/core/blob/main/LICENSE)
|
|
7
|
+
[](https://www.linkedin.com/company/htmlplus)
|
|
8
|
+
[](https://coveralls.io/r/htmlplus/element/)
|
|
9
|
+
[](https://packagephobia.now.sh/result?p=element)
|
|
10
|
+
|
|
11
|
+
Element is powerful library for building scalable, reusable design system for any technology.
|
|
12
|
+
It is one of the fastest and most testable libraries for building web components on the web.
|
|
13
|
+
Completely compatible for Typescript and tsx.
|
|
4
14
|
|
|
5
15
|
## Table of content
|
|
6
16
|
|
|
7
17
|
- [Install](#install)
|
|
8
18
|
- [Start](#start)
|
|
9
|
-
- [First
|
|
19
|
+
- [First Element](#FirstElement)
|
|
20
|
+
- [Styles](#Styles)
|
|
21
|
+
- [Development Environment](#DevelopmentEnvironment)
|
|
10
22
|
- [Decorators](#decorators)
|
|
11
23
|
- [Helpers](#helpers)
|
|
12
24
|
- [Lifecycles](#lifecycles)
|
|
13
25
|
- [Services](#services)
|
|
14
|
-
- [Tag
|
|
26
|
+
- [Tag Name Configuration](#TagNameConfiguration)
|
|
15
27
|
- [Compiler](#compiler)
|
|
16
28
|
|
|
17
29
|
## Install
|
|
@@ -31,19 +43,34 @@ pnpm create @htmlplus/element
|
|
|
31
43
|
|
|
32
44
|
## Start
|
|
33
45
|
|
|
34
|
-
TODO
|
|
35
|
-
|
|
36
46
|
```bash
|
|
37
47
|
cd htmlplus-project
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
To start your Element project, run:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# with npm
|
|
38
54
|
npm i
|
|
39
55
|
npm start
|
|
56
|
+
|
|
57
|
+
# with yarn
|
|
58
|
+
yarn install
|
|
59
|
+
yarn start
|
|
60
|
+
|
|
61
|
+
# with pnpm
|
|
62
|
+
pnpm install
|
|
63
|
+
pnpm start
|
|
40
64
|
```
|
|
41
65
|
|
|
42
|
-
## First
|
|
66
|
+
## First Element
|
|
43
67
|
|
|
44
|
-
|
|
68
|
+
Element is based on classes, so all components are based on `decorator`.
|
|
69
|
+
The decorator converts the next component code based on it's properties during the build.
|
|
45
70
|
|
|
46
71
|
```tsx
|
|
72
|
+
// my-element/my-element.tsx
|
|
73
|
+
|
|
47
74
|
import { Element } from '@htmlplus/element';
|
|
48
75
|
|
|
49
76
|
@Element('my-element')
|
|
@@ -54,23 +81,55 @@ export class MyElement {
|
|
|
54
81
|
}
|
|
55
82
|
```
|
|
56
83
|
|
|
84
|
+
The result of this component after build is provide `my-element` web component.
|
|
85
|
+
|
|
57
86
|
```html
|
|
58
87
|
<my-element></my-element>
|
|
59
88
|
```
|
|
60
89
|
|
|
90
|
+
## Styles
|
|
91
|
+
|
|
92
|
+
The element automatically adds a same name style file to this component. Create `my-element.scss` file for style.
|
|
93
|
+
|
|
94
|
+
```scss
|
|
95
|
+
// my-element/my-element.scss
|
|
96
|
+
|
|
97
|
+
:host {
|
|
98
|
+
display: block;
|
|
99
|
+
background-color: red;
|
|
100
|
+
font-size: 2rem;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Development Environment
|
|
105
|
+
|
|
106
|
+
For run any of the component, you must write element name tag into the `public/index.html`
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<!-- public/index.html -->
|
|
110
|
+
|
|
111
|
+
<body>
|
|
112
|
+
<my-element></my-element>
|
|
113
|
+
</body>
|
|
114
|
+
```
|
|
115
|
+
|
|
61
116
|
## Decorators
|
|
62
117
|
|
|
63
|
-
|
|
118
|
+
With the introduction of Classes in TypeScript and ES6, there now exist certain scenarios that require additional features to support annotating or modifying classes and class members. Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members [More information](https://www.typescriptlang.org/docs/handbook/decorators.html).
|
|
64
119
|
|
|
65
120
|
<details>
|
|
66
121
|
<summary>Element</summary>
|
|
67
122
|
|
|
68
|
-
|
|
123
|
+
Any component must be decorated with `@Element()` decorator. It also makes your web component tag name.
|
|
124
|
+
|
|
125
|
+
Options:
|
|
126
|
+
|
|
127
|
+
- **name**: `String` tag name
|
|
69
128
|
|
|
70
129
|
```tsx
|
|
71
130
|
import { Element } from '@htmlplus/element';
|
|
72
131
|
|
|
73
|
-
@Element()
|
|
132
|
+
@Element('my-element')
|
|
74
133
|
export class MyElement {
|
|
75
134
|
render() {
|
|
76
135
|
return <h1>Hi Everybody</h1>
|
|
@@ -87,12 +146,12 @@ export class MyElement {
|
|
|
87
146
|
<details>
|
|
88
147
|
<summary>Property</summary>
|
|
89
148
|
|
|
90
|
-
|
|
149
|
+
Property is decorated all the component properties for exposed attributes.
|
|
91
150
|
|
|
92
151
|
Options:
|
|
93
152
|
|
|
94
153
|
- **attribute**: TODO
|
|
95
|
-
- **reflect**:
|
|
154
|
+
- **reflect**: `Boolean` For watch mode, when you want to be notified of the attribute change.
|
|
96
155
|
|
|
97
156
|
```tsx
|
|
98
157
|
import { Element, Property } from '@htmlplus/element';
|
|
@@ -122,14 +181,14 @@ export class SayGreeting {
|
|
|
122
181
|
<details>
|
|
123
182
|
<summary>Event</summary>
|
|
124
183
|
|
|
125
|
-
|
|
184
|
+
Components can emit data and events using the Event decorator.
|
|
126
185
|
|
|
127
186
|
Options:
|
|
128
187
|
|
|
129
|
-
- **name**: A
|
|
130
|
-
- **bubbles**: A Boolean indicating whether the event bubbles up through the DOM or not. default is `false`.
|
|
131
|
-
- **cancelable**: A Boolean indicating whether the event is cancelable. default is `false`.
|
|
132
|
-
- **composed**: A Boolean value indicating whether or not the event can bubble across the boundary between the shadow DOM and the regular DOM. The default is false
|
|
188
|
+
- **name**: A `String` custom event name to override the default.
|
|
189
|
+
- **bubbles**: A `Boolean` indicating whether the event bubbles up through the DOM or not. default is `false`.
|
|
190
|
+
- **cancelable**: A `Boolean` indicating whether the event is cancelable. default is `false`.
|
|
191
|
+
- **composed**: A `Boolean` value indicating whether or not the event can bubble across the boundary between the shadow DOM and the regular DOM. The default is `false`.
|
|
133
192
|
|
|
134
193
|
```tsx
|
|
135
194
|
import { Element, Event, EventEmitter } from '@htmlplus/element';
|
|
@@ -163,25 +222,37 @@ export class MyButton {
|
|
|
163
222
|
<details>
|
|
164
223
|
<summary>Method</summary>
|
|
165
224
|
|
|
166
|
-
|
|
225
|
+
Ths `@Method` decorator can be called directly from the element. It can be called from the outside.
|
|
167
226
|
|
|
168
227
|
```tsx
|
|
169
|
-
import { Element, Method } from '@htmlplus/element';
|
|
228
|
+
import { Element, Method, State } from '@htmlplus/element';
|
|
170
229
|
|
|
171
230
|
@Element()
|
|
172
|
-
export class
|
|
231
|
+
export class MyCounter {
|
|
232
|
+
|
|
233
|
+
@State()
|
|
234
|
+
counter?: number;
|
|
235
|
+
|
|
173
236
|
@Method()
|
|
174
|
-
|
|
175
|
-
|
|
237
|
+
increase() {
|
|
238
|
+
this.counter++;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
render() {
|
|
242
|
+
return (
|
|
243
|
+
<button>
|
|
244
|
+
{this.counter}
|
|
245
|
+
</button>
|
|
246
|
+
)
|
|
176
247
|
}
|
|
177
248
|
}
|
|
178
249
|
```
|
|
179
250
|
|
|
180
251
|
```html
|
|
181
|
-
<my-
|
|
252
|
+
<my-counter id="counter"></my-counter>
|
|
182
253
|
|
|
183
254
|
<script>
|
|
184
|
-
document.getElementById('
|
|
255
|
+
document.getElementById('counter').increase();
|
|
185
256
|
</script>
|
|
186
257
|
```
|
|
187
258
|
|
|
@@ -190,11 +261,14 @@ export class MyDialog {
|
|
|
190
261
|
<details>
|
|
191
262
|
<summary>Watch</summary>
|
|
192
263
|
|
|
193
|
-
|
|
264
|
+
`@Watch` take the name of the `@Property` and `@State` variable to monitor as a parameter. Any time the value of that property changes the function decorated by `@Watch` will be invoked with the `key`, `newValue` and `oldValue` as parameters. This is called first out of the lifecycle callbacks after a property changes.
|
|
265
|
+
|
|
266
|
+
- **name**: `String` property name
|
|
194
267
|
|
|
195
268
|
```tsx
|
|
196
269
|
import { Element, Property, Watch } from '@htmlplus/element';
|
|
197
270
|
|
|
271
|
+
|
|
198
272
|
@Element()
|
|
199
273
|
export class MyElement {
|
|
200
274
|
|
|
@@ -211,17 +285,16 @@ export class MyElement {
|
|
|
211
285
|
<details>
|
|
212
286
|
<summary>Listen</summary>
|
|
213
287
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
TODO
|
|
288
|
+
The `@Listen` decorates a function that will handle the event.
|
|
289
|
+
It takes two parameter, event name and event config.
|
|
217
290
|
|
|
218
291
|
Options:
|
|
219
292
|
|
|
220
|
-
- **target**:
|
|
221
|
-
- **once**:
|
|
222
|
-
- **passive**:
|
|
293
|
+
- **target**: `body | document | window | host` This option allows us to set where we will listen for the event.
|
|
294
|
+
- **once**: `Boolean` Listen just for one time.
|
|
295
|
+
- **passive**: `Boolean` This will guarantee to the DOM that the event being fired will not `.stopPropagation()`.
|
|
223
296
|
- **signal**: TODO
|
|
224
|
-
- **capture**:
|
|
297
|
+
- **capture**: `Boolean` This option is about when during the event lifecycle the handler will be called.
|
|
225
298
|
|
|
226
299
|
```tsx
|
|
227
300
|
import { Element, Listen } from '@htmlplus/element';
|
|
@@ -229,25 +302,19 @@ import { Element, Listen } from '@htmlplus/element';
|
|
|
229
302
|
@Element()
|
|
230
303
|
export class MyButton {
|
|
231
304
|
@Listen('click')
|
|
232
|
-
onClick(event) {
|
|
233
|
-
/* TODO */
|
|
234
|
-
}
|
|
305
|
+
onClick(event) {}
|
|
235
306
|
}
|
|
236
307
|
```
|
|
237
308
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
<details>
|
|
241
|
-
<summary>ListenOptions</summary>
|
|
242
|
-
|
|
243
|
-
TODO
|
|
244
|
-
|
|
245
|
-
Options:
|
|
309
|
+
```tsx
|
|
310
|
+
import { Element, Listen } from '@htmlplus/element';
|
|
246
311
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
312
|
+
@Element()
|
|
313
|
+
export class MyContainer {
|
|
314
|
+
@Listen('scroll', { target: 'window' })
|
|
315
|
+
onScroll(event) {}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
251
318
|
|
|
252
319
|
```tsx
|
|
253
320
|
import { Element, ListenOptions } from '@htmlplus/element';
|
|
@@ -256,9 +323,7 @@ import { Element, ListenOptions } from '@htmlplus/element';
|
|
|
256
323
|
export class MyButton {
|
|
257
324
|
|
|
258
325
|
@ListenOptions({ once: true })
|
|
259
|
-
onClick(event) {
|
|
260
|
-
/* TODO */
|
|
261
|
-
}
|
|
326
|
+
onClick(event) {}
|
|
262
327
|
|
|
263
328
|
render() {
|
|
264
329
|
return (
|
|
@@ -275,7 +340,8 @@ export class MyButton {
|
|
|
275
340
|
<details>
|
|
276
341
|
<summary>State</summary>
|
|
277
342
|
|
|
278
|
-
|
|
343
|
+
The `@State` decorator is for manage data inside the component.
|
|
344
|
+
Any changes of `@State` will cause the render function to called again.
|
|
279
345
|
|
|
280
346
|
```tsx
|
|
281
347
|
import { Element, Listen, State } from '@htmlplus/element';
|
|
@@ -306,9 +372,7 @@ export class MySwitch {
|
|
|
306
372
|
<details>
|
|
307
373
|
<summary>Bind</summary>
|
|
308
374
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
TODO
|
|
375
|
+
The `@Bind` for decorating methods only, by binding them to the current context.
|
|
312
376
|
|
|
313
377
|
```tsx
|
|
314
378
|
import { Bind, Element } from '@htmlplus/element';
|
|
@@ -669,7 +733,7 @@ TODO
|
|
|
669
733
|
|
|
670
734
|
</details>
|
|
671
735
|
|
|
672
|
-
## Tag
|
|
736
|
+
## Tag Name Configuration
|
|
673
737
|
|
|
674
738
|
All examples below produce output `<plus-button></plus-button>`
|
|
675
739
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as CONSTANTS from '../../configs/constants.js';
|
|
2
|
+
import { host } from '../helpers/index.js';
|
|
2
3
|
import { defineMethod, sync } from '../utils/index.js';
|
|
3
4
|
export function Attributes() {
|
|
4
5
|
return function (target, propertyKey) {
|
|
5
6
|
let update;
|
|
6
7
|
defineMethod(target, CONSTANTS.TOKEN_LIFECYCLE_CONNECTED, function (instance, callback, args) {
|
|
7
|
-
update = sync(instance);
|
|
8
|
+
update = sync(host(instance));
|
|
8
9
|
return callback === null || callback === void 0 ? void 0 : callback(...args);
|
|
9
10
|
});
|
|
10
|
-
defineMethod(target, CONSTANTS.
|
|
11
|
+
defineMethod(target, CONSTANTS.TOKEN_LIFECYCLE_UPDATED, function (instance, callback, args) {
|
|
11
12
|
update(instance[propertyKey]);
|
|
12
13
|
return callback === null || callback === void 0 ? void 0 : callback(...args);
|
|
13
14
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function Bind(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
1
|
+
export declare function Bind(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { EventOptions } from '../../types/index.js';
|
|
2
2
|
export declare type EventEmitter<T = any> = (data?: T) => CustomEvent<T>;
|
|
3
|
-
export declare function Event<T = any>(options?: EventOptions): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
3
|
+
export declare function Event<T = any>(options?: EventOptions): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ListenOptions, PlusElement } from '../../types/index.js';
|
|
2
|
-
export declare function Listen(name: string, options?: ListenOptions): (target: PlusElement, propertyKey: PropertyKey) =>
|
|
2
|
+
export declare function Listen(name: string, options?: ListenOptions): (target: PlusElement, propertyKey: PropertyKey, descriptor: PropertyDescriptor) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as CONSTANTS from '../../configs/constants.js';
|
|
2
2
|
import { host } from '../helpers/index.js';
|
|
3
3
|
import { defineMethod } from '../utils/index.js';
|
|
4
|
+
import { Bind } from './bind.js';
|
|
4
5
|
const defaults = {
|
|
5
6
|
target: 'host'
|
|
6
7
|
};
|
|
7
8
|
export function Listen(name, options = defaults) {
|
|
8
|
-
return function (target, propertyKey) {
|
|
9
|
+
return function (target, propertyKey, descriptor) {
|
|
9
10
|
// TODO: types
|
|
10
11
|
const element = (instance) => {
|
|
11
12
|
switch (options.target) {
|
|
@@ -21,13 +22,14 @@ export function Listen(name, options = defaults) {
|
|
|
21
22
|
};
|
|
22
23
|
defineMethod(target, CONSTANTS.TOKEN_LIFECYCLE_CONNECTED, function (instance, callback, args) {
|
|
23
24
|
var _a;
|
|
24
|
-
(_a = element(instance)) === null || _a === void 0 ? void 0 : _a.addEventListener(name,
|
|
25
|
+
(_a = element(instance)) === null || _a === void 0 ? void 0 : _a.addEventListener(name, instance[propertyKey], options);
|
|
25
26
|
return callback === null || callback === void 0 ? void 0 : callback(...args);
|
|
26
27
|
});
|
|
27
28
|
defineMethod(target, CONSTANTS.TOKEN_LIFECYCLE_DISCONNECTED, function (instance, callback, args) {
|
|
28
29
|
var _a;
|
|
29
|
-
(_a = element(instance)) === null || _a === void 0 ? void 0 : _a.removeEventListener(name,
|
|
30
|
+
(_a = element(instance)) === null || _a === void 0 ? void 0 : _a.removeEventListener(name, instance[propertyKey], options);
|
|
30
31
|
return callback === null || callback === void 0 ? void 0 : callback(...args);
|
|
31
32
|
});
|
|
33
|
+
return Bind()(target, propertyKey, descriptor);
|
|
32
34
|
};
|
|
33
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function Method(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
1
|
+
export declare function Method(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { PropertyOptions } from '../../types/index.js';
|
|
2
|
-
export declare function Property(options?: PropertyOptions): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
2
|
+
export declare function Property(options?: PropertyOptions): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function State(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
1
|
+
export declare function State(): (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => import("../utils/decorator.js").DecoratorSetupReturn | undefined;
|
|
@@ -2,4 +2,4 @@ export declare type DecoratorSetup = (target: Object, propertyKey: PropertyKey,
|
|
|
2
2
|
export declare type DecoratorSetupReturn = PropertyDescriptor & {
|
|
3
3
|
onReady?(): void;
|
|
4
4
|
};
|
|
5
|
-
export declare const decorator: (setup: DecoratorSetup) => (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) =>
|
|
5
|
+
export declare const decorator: (setup: DecoratorSetup) => (target: Object, propertyKey: PropertyKey, descriptor?: PropertyDescriptor | undefined) => DecoratorSetupReturn | undefined;
|
|
@@ -3,10 +3,12 @@ export const decorator = (setup) => {
|
|
|
3
3
|
return function (target, propertyKey, descriptor) {
|
|
4
4
|
var _a;
|
|
5
5
|
const options = setup(target, propertyKey, descriptor);
|
|
6
|
-
if (Object.keys(options).some((key) => ['configurable', 'enumerable', 'value', 'writable', 'get', 'set'].includes(key)))
|
|
7
|
-
defineProperty(target, propertyKey, options);
|
|
8
6
|
// TODO
|
|
9
7
|
if (options.onReady)
|
|
10
8
|
((_a = target['setup']) !== null && _a !== void 0 ? _a : (target['setup'] = [])).push(options.onReady);
|
|
9
|
+
if (descriptor)
|
|
10
|
+
return options;
|
|
11
|
+
if (Object.keys(options).some((key) => ['configurable', 'enumerable', 'value', 'writable', 'get', 'set'].includes(key)))
|
|
12
|
+
defineProperty(target, propertyKey, options);
|
|
11
13
|
};
|
|
12
14
|
};
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
export const defineMethod = (target, propertyKey, handler) => {
|
|
3
3
|
const callback = target[propertyKey];
|
|
4
4
|
target[propertyKey] = function (...args) {
|
|
5
|
-
handler(this, callback, args);
|
|
5
|
+
return handler(this, callback === null || callback === void 0 ? void 0 : callback.bind(this), args);
|
|
6
6
|
};
|
|
7
7
|
};
|