stagnate 1.0.7 → 1.1.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.d.ts +121 -0
- package/Component.js +206 -0
- package/Component.js.map +1 -0
- package/README.md +124 -47
- package/Slot.d.ts +33 -0
- package/Slot.js +60 -0
- package/Slot.js.map +1 -0
- package/{lib/index.d.ts → index.d.ts} +1 -2
- package/{lib/index.js → index.js} +0 -2
- package/index.js.map +1 -0
- package/{lib/jsx-runtime.d.ts → jsx-runtime.d.ts} +2 -1
- package/{lib/jsx-runtime.js → jsx-runtime.js} +18 -12
- package/jsx-runtime.js.map +1 -0
- package/package.json +7 -20
- package/types.d.ts +616 -0
- package/lib/Component.d.ts +0 -27
- package/lib/Component.js +0 -160
- package/lib/Component.js.map +0 -1
- package/lib/Slot.d.ts +0 -8
- package/lib/Slot.js +0 -32
- package/lib/Slot.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/types.d.ts +0 -187
- /package/{lib/types.js → types.js} +0 -0
- /package/{lib/types.js.map → types.js.map} +0 -0
package/Component.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stagnate Component class
|
|
3
|
+
*
|
|
4
|
+
* @typeParam REFS - interface describing jsx references stored on this component, see {@link Component.refs}
|
|
5
|
+
* @typeParam PROPS - interface describing jsx props passed to this component
|
|
6
|
+
* @typeParam ROOT - type of the html root element
|
|
7
|
+
*/
|
|
8
|
+
export declare class Component<REFS = {}, PROPS = undefined, ROOT extends SVGElement | HTMLElement = SVGElement | HTMLElement> {
|
|
9
|
+
/** properties received from jsx (or set via constructor) */
|
|
10
|
+
readonly props: PROPS extends undefined ? {} : PROPS;
|
|
11
|
+
private _components;
|
|
12
|
+
private _attached;
|
|
13
|
+
/** html root element, only accessible after {@link build} was called */
|
|
14
|
+
protected root: ROOT;
|
|
15
|
+
/**
|
|
16
|
+
* parent component, only accessible after {@link bind} was called
|
|
17
|
+
* for self-bound components `this.parent = this`
|
|
18
|
+
*/
|
|
19
|
+
protected parent: Component<any, any>;
|
|
20
|
+
/**
|
|
21
|
+
* jsx references stored on this component,
|
|
22
|
+
* the REFS type should be set to a interface describing what references the component will use
|
|
23
|
+
* see {@link ref} for how to set references
|
|
24
|
+
*/
|
|
25
|
+
protected refs: REFS;
|
|
26
|
+
/**
|
|
27
|
+
* if component is to be used from jsx it has to have one constructor argument being the props,
|
|
28
|
+
* any other constructor signature will fail when used from jsx
|
|
29
|
+
*/
|
|
30
|
+
constructor(...props: PROPS extends undefined ? [] : [props: PROPS]);
|
|
31
|
+
private attach;
|
|
32
|
+
private detach;
|
|
33
|
+
/**
|
|
34
|
+
* component render function, should return the component JSX
|
|
35
|
+
* if null is returned {@link build} call will fail with an exception
|
|
36
|
+
*/
|
|
37
|
+
protected render(): Element | null;
|
|
38
|
+
/** called in {@link build} before render is called */
|
|
39
|
+
protected onBeforeRender(): void;
|
|
40
|
+
/** called in {@link build} after render is called and root is set */
|
|
41
|
+
protected onRender(): void;
|
|
42
|
+
/**
|
|
43
|
+
* called when component if fully attached (children are attached and `this.attached = true`),
|
|
44
|
+
* `onAttach` will be called only if the component is bound to a parent component or the component
|
|
45
|
+
* is self-bound
|
|
46
|
+
*/
|
|
47
|
+
protected onAttach(): void;
|
|
48
|
+
/**
|
|
49
|
+
* called when component if fully detached (children are detached and `this.attached = false`),
|
|
50
|
+
* `onDetach` will be called only if the component is bound to a parent component or it {@link destroy} was
|
|
51
|
+
* called on the component directly
|
|
52
|
+
*/
|
|
53
|
+
protected onDetach(): void;
|
|
54
|
+
/**
|
|
55
|
+
* function meant to be used in jsx for binding references
|
|
56
|
+
*
|
|
57
|
+
* the following will bind the div under `this.refs.foo` and requires the `REFS` type to include `{foo: HTMLDivElement}`
|
|
58
|
+
* ```
|
|
59
|
+
* <div ref={this.ref("foo")} />
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* the following will bind the child component under `this.refs.bar` and requires the `REFS` type to include `{bar: BarComponent}`
|
|
63
|
+
* ```
|
|
64
|
+
* <BarComponent ref={this.ref("bar")} />
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* the following will bind the child component without adding it to refs
|
|
68
|
+
* ```
|
|
69
|
+
* <BarComponent ref={this.ref()} />
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
protected ref<T extends keyof REFS | undefined = undefined>(key?: T): (x: REFS[NonNullable<T>] extends never ? any : REFS[NonNullable<T>]) => void;
|
|
73
|
+
/**
|
|
74
|
+
* calls {@link render} and sets {@link root}
|
|
75
|
+
* @returns the created DOM element ({@link root})
|
|
76
|
+
*/
|
|
77
|
+
build(): Element;
|
|
78
|
+
/**
|
|
79
|
+
* add component to a parent component,
|
|
80
|
+
* attach component if parent component is attached
|
|
81
|
+
*
|
|
82
|
+
* a component can be self-bound by passing itself as parent (`x.bind(x)`),
|
|
83
|
+
* self-bound components get automatically attached
|
|
84
|
+
*/
|
|
85
|
+
bind(parent: Component<any, any>): void;
|
|
86
|
+
/**
|
|
87
|
+
* render the component, add it as a child of {@link parent} and insert it into DOM
|
|
88
|
+
*
|
|
89
|
+
* calls {@link build} and {@link bind} internally
|
|
90
|
+
*
|
|
91
|
+
* @param parent - parent component
|
|
92
|
+
* @param target - DOM element to add the component to, if unset or null `parent.root` is used, if a component is passed it's root will be used
|
|
93
|
+
* @param before - add the element before the given DOM child, a number can be used as a child index, if unset adds the element as the last child
|
|
94
|
+
*/
|
|
95
|
+
create(parent: Component<any, any>, target?: Element | Component<any, any> | null, before?: Element | Component<any, any> | number): void;
|
|
96
|
+
/**
|
|
97
|
+
* render the component, add it as a child of {@link parent} and add it to DOM by replacing a existing element or component
|
|
98
|
+
*
|
|
99
|
+
* calls {@link build} and {@link bind} internally
|
|
100
|
+
*
|
|
101
|
+
* @param parent - parent component
|
|
102
|
+
* @param target - component or DOM element to replace, if component is passed {@link destroy} will be called on it
|
|
103
|
+
*/
|
|
104
|
+
replace(parent: Component<any, any>, target: Element | Component<any, any>): void;
|
|
105
|
+
/**
|
|
106
|
+
* render the component, add it to DOM and self-bound, meant to be used for creating the root component
|
|
107
|
+
*
|
|
108
|
+
* calls {@link build} and {@link bind} internally
|
|
109
|
+
*
|
|
110
|
+
* @param target - DOM target to append the component to
|
|
111
|
+
*/
|
|
112
|
+
createOrphanized(target: Node): void;
|
|
113
|
+
/** remove this component from DOM and its parent component */
|
|
114
|
+
destroy(): void;
|
|
115
|
+
/** true if component is attached */
|
|
116
|
+
get attached(): boolean;
|
|
117
|
+
/** public accessor for {@link root} */
|
|
118
|
+
get htmlRoot(): ROOT;
|
|
119
|
+
/** child component list accessor */
|
|
120
|
+
get components(): Readonly<Component<any, any, any>[]>;
|
|
121
|
+
}
|
package/Component.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stagnate Component class
|
|
3
|
+
*
|
|
4
|
+
* @typeParam REFS - interface describing jsx references stored on this component, see {@link Component.refs}
|
|
5
|
+
* @typeParam PROPS - interface describing jsx props passed to this component
|
|
6
|
+
* @typeParam ROOT - type of the html root element
|
|
7
|
+
*/
|
|
8
|
+
export class Component {
|
|
9
|
+
constructor(props) {
|
|
10
|
+
this._components = [];
|
|
11
|
+
this._attached = false;
|
|
12
|
+
this.refs = {};
|
|
13
|
+
this.props = props;
|
|
14
|
+
}
|
|
15
|
+
attach() {
|
|
16
|
+
for (let i = 0; i < this._components.length; i += 1) {
|
|
17
|
+
const component = this._components[i];
|
|
18
|
+
if (!component._attached) {
|
|
19
|
+
component.attach();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
this._attached = true;
|
|
23
|
+
this.onAttach();
|
|
24
|
+
}
|
|
25
|
+
detach() {
|
|
26
|
+
this._components.forEach(x => x.detach());
|
|
27
|
+
this._components = [];
|
|
28
|
+
this._attached = false;
|
|
29
|
+
this.refs = {};
|
|
30
|
+
this.parent = null;
|
|
31
|
+
this.root = null;
|
|
32
|
+
this.onDetach();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* component render function, should return the component JSX
|
|
36
|
+
* if null is returned {@link build} call will fail with an exception
|
|
37
|
+
*/
|
|
38
|
+
render() {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/** called in {@link build} before render is called */
|
|
42
|
+
onBeforeRender() {
|
|
43
|
+
}
|
|
44
|
+
/** called in {@link build} after render is called and root is set */
|
|
45
|
+
onRender() {
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* called when component if fully attached (children are attached and `this.attached = true`),
|
|
49
|
+
* `onAttach` will be called only if the component is bound to a parent component or the component
|
|
50
|
+
* is self-bound
|
|
51
|
+
*/
|
|
52
|
+
onAttach() {
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* called when component if fully detached (children are detached and `this.attached = false`),
|
|
56
|
+
* `onDetach` will be called only if the component is bound to a parent component or it {@link destroy} was
|
|
57
|
+
* called on the component directly
|
|
58
|
+
*/
|
|
59
|
+
onDetach() {
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* function meant to be used in jsx for binding references
|
|
63
|
+
*
|
|
64
|
+
* the following will bind the div under `this.refs.foo` and requires the `REFS` type to include `{foo: HTMLDivElement}`
|
|
65
|
+
* ```
|
|
66
|
+
* <div ref={this.ref("foo")} />
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* the following will bind the child component under `this.refs.bar` and requires the `REFS` type to include `{bar: BarComponent}`
|
|
70
|
+
* ```
|
|
71
|
+
* <BarComponent ref={this.ref("bar")} />
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* the following will bind the child component without adding it to refs
|
|
75
|
+
* ```
|
|
76
|
+
* <BarComponent ref={this.ref()} />
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
ref(key) {
|
|
80
|
+
return (x) => {
|
|
81
|
+
if (x instanceof Component) {
|
|
82
|
+
x.parent = this;
|
|
83
|
+
this._components.push(x);
|
|
84
|
+
if (this._attached) {
|
|
85
|
+
x.attach();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (key) {
|
|
89
|
+
this.refs[key] = x;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* calls {@link render} and sets {@link root}
|
|
95
|
+
* @returns the created DOM element ({@link root})
|
|
96
|
+
*/
|
|
97
|
+
build() {
|
|
98
|
+
this.onBeforeRender();
|
|
99
|
+
const html = this.render();
|
|
100
|
+
if (!html) {
|
|
101
|
+
throw new Error("can not render component: render function returned null");
|
|
102
|
+
}
|
|
103
|
+
this.root = html;
|
|
104
|
+
this.onRender();
|
|
105
|
+
return html;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* add component to a parent component,
|
|
109
|
+
* attach component if parent component is attached
|
|
110
|
+
*
|
|
111
|
+
* a component can be self-bound by passing itself as parent (`x.bind(x)`),
|
|
112
|
+
* self-bound components get automatically attached
|
|
113
|
+
*/
|
|
114
|
+
bind(parent) {
|
|
115
|
+
this.parent = parent;
|
|
116
|
+
if (parent != this) {
|
|
117
|
+
parent._components.push(this);
|
|
118
|
+
if (parent._attached) {
|
|
119
|
+
this.attach();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
this.attach();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* render the component, add it as a child of {@link parent} and insert it into DOM
|
|
128
|
+
*
|
|
129
|
+
* calls {@link build} and {@link bind} internally
|
|
130
|
+
*
|
|
131
|
+
* @param parent - parent component
|
|
132
|
+
* @param target - DOM element to add the component to, if unset or null `parent.root` is used, if a component is passed it's root will be used
|
|
133
|
+
* @param before - add the element before the given DOM child, a number can be used as a child index, if unset adds the element as the last child
|
|
134
|
+
*/
|
|
135
|
+
create(parent, target, before) {
|
|
136
|
+
if (!target) {
|
|
137
|
+
target = parent.root;
|
|
138
|
+
}
|
|
139
|
+
else if (target instanceof Component) {
|
|
140
|
+
target = target.root;
|
|
141
|
+
}
|
|
142
|
+
if (typeof before === "number") {
|
|
143
|
+
before = before < target.children.length ? target.children[Math.max(0, before)] : undefined;
|
|
144
|
+
}
|
|
145
|
+
else if (before instanceof Component) {
|
|
146
|
+
before = before.root;
|
|
147
|
+
}
|
|
148
|
+
target.insertBefore(this.build(), before === undefined ? null : before);
|
|
149
|
+
this.bind(parent);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* render the component, add it as a child of {@link parent} and add it to DOM by replacing a existing element or component
|
|
153
|
+
*
|
|
154
|
+
* calls {@link build} and {@link bind} internally
|
|
155
|
+
*
|
|
156
|
+
* @param parent - parent component
|
|
157
|
+
* @param target - component or DOM element to replace, if component is passed {@link destroy} will be called on it
|
|
158
|
+
*/
|
|
159
|
+
replace(parent, target) {
|
|
160
|
+
if (target instanceof Component) {
|
|
161
|
+
target.root.replaceWith(this.build());
|
|
162
|
+
target.destroy();
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
target.replaceWith(this.build());
|
|
166
|
+
}
|
|
167
|
+
this.bind(parent);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* render the component, add it to DOM and self-bound, meant to be used for creating the root component
|
|
171
|
+
*
|
|
172
|
+
* calls {@link build} and {@link bind} internally
|
|
173
|
+
*
|
|
174
|
+
* @param target - DOM target to append the component to
|
|
175
|
+
*/
|
|
176
|
+
createOrphanized(target) {
|
|
177
|
+
target.appendChild(this.build());
|
|
178
|
+
this.bind(this);
|
|
179
|
+
}
|
|
180
|
+
/** remove this component from DOM and its parent component */
|
|
181
|
+
destroy() {
|
|
182
|
+
if (this.root) {
|
|
183
|
+
this.root.remove();
|
|
184
|
+
}
|
|
185
|
+
if (this.parent) {
|
|
186
|
+
const index = this.parent._components.indexOf(this);
|
|
187
|
+
if (index >= 0) {
|
|
188
|
+
this.parent._components.splice(index, 1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
this.detach();
|
|
192
|
+
}
|
|
193
|
+
/** true if component is attached */
|
|
194
|
+
get attached() {
|
|
195
|
+
return this._attached;
|
|
196
|
+
}
|
|
197
|
+
/** public accessor for {@link root} */
|
|
198
|
+
get htmlRoot() {
|
|
199
|
+
return this.root;
|
|
200
|
+
}
|
|
201
|
+
/** child component list accessor */
|
|
202
|
+
get components() {
|
|
203
|
+
return this._components;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=Component.js.map
|
package/Component.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Component.js","sourceRoot":"","sources":["../src/Component.ts"],"names":[],"mappings":"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"}
|
package/README.md
CHANGED
|
@@ -99,13 +99,11 @@ Same as `create` but replaces `target` instead of being appended to it.
|
|
|
99
99
|
#### The `createOrphanized` member function
|
|
100
100
|
|
|
101
101
|
```typescript
|
|
102
|
-
createOrphanized(target?:
|
|
102
|
+
createOrphanized(target?: Node)
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
Same as `create` but intended to create the root component. The component is automatically set as attached after render.
|
|
106
106
|
|
|
107
|
-
If `target` is `null` then component is appended to `document.body`.
|
|
108
|
-
|
|
109
107
|
## JSX attribute handling
|
|
110
108
|
|
|
111
109
|
### `ref` attribute
|
|
@@ -174,58 +172,137 @@ Primary used to avoid passing nested JSX elements as props.
|
|
|
174
172
|
|
|
175
173
|
### Component class
|
|
176
174
|
```typescript
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Stagnate Component class
|
|
177
|
+
*
|
|
178
|
+
* @typeParam REFS - interface describing jsx references stored on this component, see {@link Component.refs}
|
|
179
|
+
* @typeParam PROPS - interface describing jsx props passed to this component
|
|
180
|
+
* @typeParam ROOT - type of the html root element
|
|
181
|
+
*/
|
|
182
|
+
class Component<REFS = {}, PROPS = undefined, ROOT extends SVGElement | HTMLElement = SVGElement | HTMLElement> {
|
|
183
|
+
/** properties received from jsx (or set via constructor) */
|
|
184
|
+
readonly props: PROPS extends undefined ? {} : PROPS
|
|
185
|
+
|
|
186
|
+
/** html root element, only accessible after {@link build} was called */
|
|
187
|
+
protected root: ROOT
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* parent component, only accessible after {@link bind} was called
|
|
191
|
+
* for self-bound components `this.parent = this`
|
|
192
|
+
*/
|
|
193
|
+
protected parent: Component<any, any>
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* jsx references stored on this component,
|
|
197
|
+
* the REFS type should be set to a interface describing what references the component will use
|
|
198
|
+
* see {@link ref} for how to set references
|
|
199
|
+
*/
|
|
200
|
+
protected refs: REFS
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* if component is to be used from jsx it has to have one constructor argument being the props,
|
|
204
|
+
* any other constructor signature will fail when used from jsx
|
|
205
|
+
*/
|
|
206
|
+
constructor(props: PROPS)
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* component render function, should return the component JSX
|
|
210
|
+
* if null is returned {@link build} call will fail with an exception
|
|
211
|
+
*/
|
|
212
|
+
protected render(): Element | null
|
|
213
|
+
|
|
214
|
+
/** called in {@link build} before render is called */
|
|
215
|
+
protected onBeforeRender(): void
|
|
216
|
+
|
|
217
|
+
/** called in {@link build} after render is called and root is set */
|
|
218
|
+
protected onRender(): void
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* called when component if fully attached (children are attached and `this.attached = true`),
|
|
222
|
+
* `onAttach` will be called only if the component is bound to a parent component or the component
|
|
223
|
+
* is self-bound
|
|
224
|
+
*/
|
|
225
|
+
protected onAttach(): void
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* called when component if fully detached (children are detached and `this.attached = false`),
|
|
229
|
+
* `onDetach` will be called only if the component is bound to a parent component or it {@link destroy} was
|
|
230
|
+
* called on the component directly
|
|
231
|
+
*/
|
|
232
|
+
protected onDetach(): void
|
|
233
|
+
|
|
234
|
+
/** function meant to be used in jsx for binding references */
|
|
235
|
+
protected ref<T extends keyof REFS | undefined = undefined>(key?: T): (x: REFS[NonNullable<T>] extends never ? any : REFS[NonNullable<T>]) => void
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* calls {@link render} and sets {@link root}
|
|
239
|
+
* @returns the created DOM element ({@link root})
|
|
240
|
+
*/
|
|
241
|
+
build(): Element
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* add component to a parent component,
|
|
245
|
+
* attach component if parent component is attached
|
|
246
|
+
*
|
|
247
|
+
* a component can be self-bound by passing itself as parent (`x.bind(x)`),
|
|
248
|
+
* self-bound components get automatically attached
|
|
249
|
+
*/
|
|
250
|
+
bind(parent: Component<any, any>): void
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* render the component, add it as a child of {@link parent} and insert it into DOM
|
|
254
|
+
*
|
|
255
|
+
* calls {@link build} and {@link bind} internally
|
|
256
|
+
*
|
|
257
|
+
* @param parent - parent component
|
|
258
|
+
* @param target - DOM element to add the component to, if unset or null `parent.root` is used, if a component is passed it's root will be used
|
|
259
|
+
* @param before - add the element before the given DOM child, a number can be used as a child index, if unset adds the element as the last child
|
|
260
|
+
*/
|
|
261
|
+
create(parent: Component<any, any>, target?: Element | Component<any, any> | null, before?: Element | Component<any, any> | number): void
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* render the component, add it as a child of {@link parent} and add it to DOM by replacing a existing element or component
|
|
265
|
+
*
|
|
266
|
+
* calls {@link build} and {@link bind} internally
|
|
267
|
+
*
|
|
268
|
+
* @param parent - parent component
|
|
269
|
+
* @param target - component or DOM element to replace, if component is passed {@link destroy} will be called on it
|
|
270
|
+
*/
|
|
271
|
+
replace(parent: Component<any, any>, target: Element | Component<any, any>): void
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* render the component, add it to DOM and self-bound, meant to be used for creating the root component
|
|
275
|
+
*
|
|
276
|
+
* calls {@link build} and {@link bind} internally
|
|
277
|
+
*
|
|
278
|
+
* @param target - DOM target to append the component to
|
|
279
|
+
*/
|
|
280
|
+
createOrphanized(target: Node): void
|
|
281
|
+
|
|
282
|
+
/** remove this component from DOM and its parent component */
|
|
283
|
+
destroy(): void
|
|
284
|
+
|
|
285
|
+
/** true if component is attached */
|
|
286
|
+
get attached(): boolean
|
|
287
|
+
|
|
288
|
+
/** public accessor for {@link root} */
|
|
289
|
+
get htmlRoot(): ROOT
|
|
290
|
+
|
|
291
|
+
/** child component list accessor */
|
|
292
|
+
get components(): Readonly<Component<any, any, any>[]>
|
|
217
293
|
}
|
|
218
|
-
|
|
219
294
|
```
|
|
220
295
|
|
|
221
296
|
### Utility Types
|
|
222
297
|
|
|
223
298
|
```typescript
|
|
224
|
-
|
|
299
|
+
/** get props of an JSX element or component function / class */
|
|
225
300
|
type ComponentProps<IntrinsicElement | ClassElement | FunctionElement>
|
|
226
|
-
|
|
301
|
+
|
|
302
|
+
/** any value that can be used in JSX */
|
|
227
303
|
type StagnateNode
|
|
228
|
-
|
|
304
|
+
|
|
305
|
+
/** the JSX element css class attribute */
|
|
229
306
|
type ClassAttribute
|
|
230
307
|
```
|
|
231
308
|
|
package/Slot.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { JSX, StagnateNode } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Pseudo component used to create named slots.
|
|
4
|
+
*
|
|
5
|
+
* example use:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* function Foo(props: {children: StagnateNode}) {
|
|
8
|
+
* const slots = Slot.extract<{foo: HTMLElement, bar: HTMLElement}>(props.children)
|
|
9
|
+
* return <div>
|
|
10
|
+
* <div>{slots.foo}</div>
|
|
11
|
+
* <div>{slots.bar}</div>
|
|
12
|
+
* </div>
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* const example = <Foo>
|
|
16
|
+
* <Slot name="foo">FOO</Slot>
|
|
17
|
+
* <Slot name="bar">BAR</Slot>
|
|
18
|
+
* </Foo>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function Slot(props: {
|
|
22
|
+
name: string;
|
|
23
|
+
children: StagnateNode;
|
|
24
|
+
}): JSX.Element;
|
|
25
|
+
export declare namespace Slot {
|
|
26
|
+
/**
|
|
27
|
+
* This function extracts slotted children from the child list,
|
|
28
|
+
* it has to be called if slots are in the child list or render will fail on un-extracted slot data.
|
|
29
|
+
*
|
|
30
|
+
* see {@link Slot} for a usage example
|
|
31
|
+
*/
|
|
32
|
+
function extract<T = Record<string, any>>(input: StagnateNode, slots?: Record<string, any>): T;
|
|
33
|
+
}
|
package/Slot.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class SlotArray extends Array {
|
|
2
|
+
constructor(name, elements) {
|
|
3
|
+
super();
|
|
4
|
+
this.name = name;
|
|
5
|
+
this.push(elements);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Pseudo component used to create named slots.
|
|
10
|
+
*
|
|
11
|
+
* example use:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* function Foo(props: {children: StagnateNode}) {
|
|
14
|
+
* const slots = Slot.extract<{foo: HTMLElement, bar: HTMLElement}>(props.children)
|
|
15
|
+
* return <div>
|
|
16
|
+
* <div>{slots.foo}</div>
|
|
17
|
+
* <div>{slots.bar}</div>
|
|
18
|
+
* </div>
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const example = <Foo>
|
|
22
|
+
* <Slot name="foo">FOO</Slot>
|
|
23
|
+
* <Slot name="bar">BAR</Slot>
|
|
24
|
+
* </Foo>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function Slot(props) {
|
|
28
|
+
return new SlotArray(props.name, props.children);
|
|
29
|
+
}
|
|
30
|
+
(function (Slot) {
|
|
31
|
+
/**
|
|
32
|
+
* This function extracts slotted children from the child list,
|
|
33
|
+
* it has to be called if slots are in the child list or render will fail on un-extracted slot data.
|
|
34
|
+
*
|
|
35
|
+
* see {@link Slot} for a usage example
|
|
36
|
+
*/
|
|
37
|
+
function extract(input, slots = {}) {
|
|
38
|
+
if (input instanceof SlotArray && input.length) {
|
|
39
|
+
slots[input.name] = input[0];
|
|
40
|
+
input.pop();
|
|
41
|
+
}
|
|
42
|
+
else if (Array.isArray(input)) {
|
|
43
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
44
|
+
const item = input[i];
|
|
45
|
+
if (item instanceof SlotArray) {
|
|
46
|
+
if (item.length) {
|
|
47
|
+
slots[item.name] = item[0];
|
|
48
|
+
}
|
|
49
|
+
input[i] = null;
|
|
50
|
+
}
|
|
51
|
+
else if (Array.isArray(item)) {
|
|
52
|
+
extract(item, slots);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return slots;
|
|
57
|
+
}
|
|
58
|
+
Slot.extract = extract;
|
|
59
|
+
})(Slot || (Slot = {}));
|
|
60
|
+
//# sourceMappingURL=Slot.js.map
|
package/Slot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Slot.js","sourceRoot":"","sources":["../src/Slot.ts"],"names":[],"mappings":"AAEA,MAAM,SAAU,SAAQ,KAAmB;IAE1C,YAAa,IAAY,EAAE,QAAsB;QAChD,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACpB,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,IAAI,CAAC,KAA6C;IACjE,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAQ,CAAA;AACxD,CAAC;AAED,WAAiB,IAAI;IACpB;;;;;OAKG;IACH,SAAgB,OAAO,CAA0B,KAAmB,EAAE,QAA6B,EAAE;QACpG,IAAI,KAAK,YAAY,SAAS,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAChD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YAC5B,KAAK,CAAC,GAAG,EAAE,CAAA;QACZ,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;gBACrB,IAAI,IAAI,YAAY,SAAS,EAAE,CAAC;oBAC/B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;wBACjB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;oBAC3B,CAAC;oBACD,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;gBAChB,CAAC;qBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAChC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;gBACrB,CAAC;YACF,CAAC;QACF,CAAC;QACD,OAAO,KAAU,CAAA;IAClB,CAAC;IAlBe,YAAO,UAkBtB,CAAA;AACF,CAAC,EA1BgB,IAAI,KAAJ,IAAI,QA0BpB"}
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { JSX, StagnateNode } from "./types";
|
|
2
2
|
export declare function jsx(type: any, props: any): any;
|
|
3
3
|
export declare function createElement(type: any, props: any, ...children: any[]): any;
|
|
4
|
+
/** JSX fragment component, <> can be used as an alias */
|
|
4
5
|
export declare function Fragment(props: {
|
|
5
6
|
children: StagnateNode;
|
|
6
7
|
}): JSX.Element;
|
|
7
8
|
export { jsx as jsxs };
|
|
8
|
-
export { JSX };
|
|
9
|
+
export type { JSX };
|