@seahax/elemental 0.4.1 → 0.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/README.md +82 -16
- package/dist/component.d.ts +5 -0
- package/dist/component.js +42 -19
- package/dist/component.js.map +1 -1
- package/dist/hooks/async.d.ts +11 -0
- package/dist/hooks/{loading.js → async.js} +3 -3
- package/dist/hooks/async.js.map +1 -0
- package/dist/hooks/{child-effect.js → child.js} +2 -2
- package/dist/hooks/child.js.map +1 -0
- package/dist/hooks/controller.d.ts +3 -0
- package/dist/hooks/controller.js +11 -0
- package/dist/hooks/controller.js.map +1 -0
- package/dist/hooks/disconnect.d.ts +2 -0
- package/dist/hooks/disconnect.js +9 -0
- package/dist/hooks/disconnect.js.map +1 -0
- package/dist/hooks/document.d.ts +3 -0
- package/dist/hooks/document.js +9 -0
- package/dist/hooks/document.js.map +1 -0
- package/dist/hooks/effect.js +9 -9
- package/dist/hooks/effect.js.map +1 -1
- package/dist/hooks/form.d.ts +9 -0
- package/dist/hooks/form.js +23 -0
- package/dist/hooks/form.js.map +1 -0
- package/dist/hooks/host.d.ts +1 -1
- package/dist/hooks/host.js +1 -1
- package/dist/hooks/host.js.map +1 -1
- package/dist/hooks/internals.d.ts +2 -0
- package/dist/hooks/internals.js +9 -0
- package/dist/hooks/internals.js.map +1 -0
- package/dist/hooks/parent.d.ts +3 -0
- package/dist/hooks/parent.js +9 -0
- package/dist/hooks/parent.js.map +1 -0
- package/dist/hooks/ref.d.ts +1 -2
- package/dist/hooks/ref.js +4 -14
- package/dist/hooks/ref.js.map +1 -1
- package/dist/hooks/route.d.ts +2 -2
- package/dist/hooks/route.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +16 -11
- package/dist/internal/controller.d.ts +33 -0
- package/dist/internal/controller.js +72 -0
- package/dist/internal/controller.js.map +1 -0
- package/package.json +1 -1
- package/dist/hooks/child-effect.js.map +0 -1
- package/dist/hooks/context.d.ts +0 -3
- package/dist/hooks/context.js +0 -11
- package/dist/hooks/context.js.map +0 -1
- package/dist/hooks/loading.d.ts +0 -11
- package/dist/hooks/loading.js.map +0 -1
- package/dist/internal/context.d.ts +0 -13
- package/dist/internal/context.js +0 -32
- package/dist/internal/context.js.map +0 -1
- /package/dist/hooks/{child-effect.d.ts → child.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -14,8 +14,8 @@ Contains everything you need to build anything from a single component up to a f
|
|
|
14
14
|
- No Dependencies
|
|
15
15
|
- Tiny Bundle Size
|
|
16
16
|
|
|
17
|
-
](https://www.npmjs.com/package/@seahax/elemental) [)
|
|
18
|
+
](https://bundlejs.com/?q=%40seahax%2Felemental%40latest&treeshake=%5B*%5D)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
## Define A Web Component
|
|
@@ -23,20 +23,30 @@ Contains everything you need to build anything from a single component up to a f
|
|
|
23
23
|
```ts
|
|
24
24
|
import {
|
|
25
25
|
defineComponent,
|
|
26
|
+
h,
|
|
26
27
|
useRef,
|
|
27
28
|
useStore,
|
|
28
29
|
useAttributes,
|
|
30
|
+
useParent,
|
|
31
|
+
useDocument,
|
|
29
32
|
useRoute,
|
|
30
|
-
|
|
33
|
+
useAsync,
|
|
31
34
|
useEffect,
|
|
32
35
|
useChildEffect,
|
|
36
|
+
useDisconnectCallback,
|
|
37
|
+
useElementInternals,
|
|
33
38
|
useHost,
|
|
34
|
-
h,
|
|
35
39
|
} from '@seahax/elemental';
|
|
36
40
|
|
|
37
41
|
export const MyComponent = defineComponent((shadow) => {
|
|
38
|
-
// This function is
|
|
39
|
-
//
|
|
42
|
+
// This function is called every time the component is connected to the
|
|
43
|
+
// document.
|
|
44
|
+
//
|
|
45
|
+
// For the most part, a component's lifecycle should be handled as if it
|
|
46
|
+
// starts on connect and ends on disconnect, even though the component
|
|
47
|
+
// can be reconnected to the document. Restore internal state on
|
|
48
|
+
// connection from host attributes and properties. Effect hooks are
|
|
49
|
+
// designed to facilitate this pattern.
|
|
40
50
|
|
|
41
51
|
// Create HTML elements and save references to them.
|
|
42
52
|
const myInput = h('input');
|
|
@@ -58,9 +68,15 @@ export const MyComponent = defineComponent((shadow) => {
|
|
|
58
68
|
// Use a reference (reactive state) bound to a (shared) store.
|
|
59
69
|
const globalStateRef = useStore(myStore, select, mutate);
|
|
60
70
|
|
|
61
|
-
// Use references (reactive state) bound to attributes.
|
|
71
|
+
// Use references (reactive state) bound to the component's attributes.
|
|
62
72
|
const [dataValueRef, ...] = useAttributes('data-value', ...);
|
|
63
73
|
|
|
74
|
+
// Use a reference (reactive state) bound to the component's parent node.
|
|
75
|
+
const parentNode = useParent();
|
|
76
|
+
|
|
77
|
+
// Use a reference (reactive state) bound to the component's owner document.
|
|
78
|
+
const ownerDocument = useDocument();
|
|
79
|
+
|
|
64
80
|
// Use a reference (reactive state) bound to route matching.
|
|
65
81
|
const routeMatchRef = useRoute('/path/', {
|
|
66
82
|
match: 'prefix', // 'exact' | 'prefix' | RegExp
|
|
@@ -68,7 +84,7 @@ export const MyComponent = defineComponent((shadow) => {
|
|
|
68
84
|
});
|
|
69
85
|
|
|
70
86
|
// Use a reference (reactive state) bound to an async loader function.
|
|
71
|
-
const
|
|
87
|
+
const asyncRef = useAsync([
|
|
72
88
|
// dependency references
|
|
73
89
|
], async (signal, ...dependencyValues) => {
|
|
74
90
|
// Reactive async code runs when the component is connected to the
|
|
@@ -84,15 +100,15 @@ export const MyComponent = defineComponent((shadow) => {
|
|
|
84
100
|
globalStateRef,
|
|
85
101
|
dataValueRef,
|
|
86
102
|
routeMatchRef,
|
|
87
|
-
|
|
88
|
-
loadingStateRef,
|
|
103
|
+
asyncRef,
|
|
89
104
|
], (...dependencyValues) => {
|
|
90
105
|
// Reactive code runs when the component is connected to the document,
|
|
91
106
|
// and when any of the dependencies change.
|
|
92
107
|
|
|
93
108
|
return () => {
|
|
94
|
-
// Cleanup
|
|
95
|
-
// is disconnected from the
|
|
109
|
+
// Cleanup after dependency refs are changed (before the next effect
|
|
110
|
+
// callback) and after the component is disconnected from the
|
|
111
|
+
// document.
|
|
96
112
|
};
|
|
97
113
|
});
|
|
98
114
|
|
|
@@ -108,24 +124,74 @@ export const MyComponent = defineComponent((shadow) => {
|
|
|
108
124
|
};
|
|
109
125
|
});
|
|
110
126
|
|
|
111
|
-
//
|
|
127
|
+
// Register a document disconnection callback.
|
|
128
|
+
useDisconnectCallback(() => {
|
|
129
|
+
// Called when the component is disconnected from the document.
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Use the element's internals.
|
|
133
|
+
const elementInternals = useElementInternals();
|
|
134
|
+
|
|
135
|
+
// Use the component host element.
|
|
112
136
|
const host = useHost();
|
|
113
137
|
});
|
|
114
138
|
```
|
|
115
139
|
|
|
140
|
+
## Enable Form Association
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import {
|
|
144
|
+
useElementInternals,
|
|
145
|
+
useForm,
|
|
146
|
+
useFormDisabled,
|
|
147
|
+
useFormResetCallback,
|
|
148
|
+
useFormRestoreCallback,
|
|
149
|
+
} from '@seahax/elemental';
|
|
150
|
+
|
|
151
|
+
const MyComponent = defineComponent(
|
|
152
|
+
(shadow) => {
|
|
153
|
+
// Use the element's internals.
|
|
154
|
+
const elementInternals = useElementInternals();
|
|
155
|
+
|
|
156
|
+
// Use a reference (reactive state) bound to the associated form.
|
|
157
|
+
const formRef = useForm();
|
|
158
|
+
|
|
159
|
+
// Use a reference (reactive state) bound to the form disabled state.
|
|
160
|
+
const formDisabledRef = useFormDisabled();
|
|
161
|
+
|
|
162
|
+
// Register a form reset callback.
|
|
163
|
+
useFormResetCallback(() => {
|
|
164
|
+
// Called when the associated form is reset. Only called on connect
|
|
165
|
+
// if the form was reset while the component was disconnected.
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Register a form restore callback.
|
|
169
|
+
useFormRestoreCallback((state, reason) => {
|
|
170
|
+
// Called when the associated form is restored. Only called on connect
|
|
171
|
+
// if the form was restored while the component was disconnected.
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
// Enable form association.
|
|
176
|
+
formAssociated: true,
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
```
|
|
180
|
+
|
|
116
181
|
## Customize The Shadow Root
|
|
117
182
|
|
|
118
183
|
```ts
|
|
119
184
|
const MyComponent = defineComponent(
|
|
120
185
|
(shadow) => {
|
|
121
|
-
|
|
186
|
+
...
|
|
122
187
|
},
|
|
123
188
|
{
|
|
124
|
-
//
|
|
189
|
+
// Use custom shadow root initialization options.
|
|
190
|
+
// (default: { mode: 'open' }).
|
|
125
191
|
shadow: {
|
|
126
192
|
mode: 'closed',
|
|
127
193
|
...
|
|
128
|
-
}
|
|
194
|
+
},
|
|
129
195
|
}
|
|
130
196
|
);
|
|
131
197
|
```
|
package/dist/component.d.ts
CHANGED
|
@@ -3,11 +3,16 @@ type SafeProps<TProps> = any extends any ? {
|
|
|
3
3
|
[P in keyof TProps as P extends keyof HTMLElement ? never : P]: TProps[P];
|
|
4
4
|
} : never;
|
|
5
5
|
export interface ComponentConstructor<TProps extends object> {
|
|
6
|
+
readonly formAssociated: boolean;
|
|
6
7
|
new (): ComponentWithProps<TProps>;
|
|
7
8
|
}
|
|
8
9
|
export interface ComponentOptions<TProps extends object> {
|
|
10
|
+
/** Shadow root attachment options. */
|
|
9
11
|
readonly shadow?: Partial<ShadowRootInit>;
|
|
12
|
+
/** Component custom property descriptors. */
|
|
10
13
|
readonly props?: ComponentPropDescriptors<TProps>;
|
|
14
|
+
/** True to mark the component as form-associated. */
|
|
15
|
+
readonly formAssociated?: boolean;
|
|
11
16
|
}
|
|
12
17
|
export type ComponentPropDescriptors<TProps extends object> = {
|
|
13
18
|
readonly [P in keyof SafeProps<TProps>]: ComponentPropDescriptorFactory<TProps[P]>;
|
package/dist/component.js
CHANGED
|
@@ -1,34 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useRef as t } from "./hooks/ref.js";
|
|
1
|
+
import { createController as e } from "./internal/controller.js";
|
|
3
2
|
//#region src/component.ts
|
|
4
|
-
function
|
|
3
|
+
function t(t, { props: n, shadow: r, formAssociated: i = !1 } = {}) {
|
|
5
4
|
return class extends HTMLElement {
|
|
6
|
-
|
|
7
|
-
#
|
|
5
|
+
static formAssociated = i;
|
|
6
|
+
#e;
|
|
7
|
+
#t;
|
|
8
|
+
#n = {};
|
|
8
9
|
constructor() {
|
|
9
|
-
if (super(),
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
if (super(), this.#e = this.attachShadow({
|
|
11
|
+
...r,
|
|
12
|
+
mode: r?.mode ?? "open"
|
|
13
|
+
}), this.#t = e({
|
|
14
|
+
host: this,
|
|
15
|
+
formAssociated: i,
|
|
16
|
+
render: () => t(this.#e, this.#n),
|
|
17
|
+
attachInternals: () => super.attachInternals()
|
|
18
|
+
}), n) {
|
|
19
|
+
let e = this.#n;
|
|
20
|
+
for (let [t, r] of Object.entries(n)) {
|
|
21
|
+
if (t in this) continue;
|
|
22
|
+
let n = r(e[t] = this.#t.createRef(void 0), this);
|
|
23
|
+
Object.defineProperty(this, t, n);
|
|
15
24
|
}
|
|
16
25
|
}
|
|
26
|
+
i && this.attachInternals();
|
|
27
|
+
}
|
|
28
|
+
attachInternals() {
|
|
29
|
+
return this.#t.attachInternals();
|
|
17
30
|
}
|
|
18
31
|
connectedCallback() {
|
|
19
|
-
this.#t.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}), this.#e);
|
|
24
|
-
});
|
|
32
|
+
this.#t.connectedCallback();
|
|
33
|
+
}
|
|
34
|
+
connectedMoveCallback() {
|
|
35
|
+
this.#t.connectedMoveCallback();
|
|
25
36
|
}
|
|
26
37
|
disconnectedCallback() {
|
|
27
|
-
this.#t.
|
|
38
|
+
this.#t.disconnectedCallback();
|
|
39
|
+
}
|
|
40
|
+
adoptedCallback() {
|
|
41
|
+
this.#t.adoptedCallback();
|
|
42
|
+
}
|
|
43
|
+
formDisabledCallback(e) {
|
|
44
|
+
this.#t.formDisabledCallback(e);
|
|
45
|
+
}
|
|
46
|
+
formResetCallback() {
|
|
47
|
+
this.#t.formResetCallback();
|
|
48
|
+
}
|
|
49
|
+
formStateRestoreCallback(e, t) {
|
|
50
|
+
this.#t.formStateRestoreCallback(e, t);
|
|
28
51
|
}
|
|
29
52
|
};
|
|
30
53
|
}
|
|
31
54
|
//#endregion
|
|
32
|
-
export {
|
|
55
|
+
export { t as defineComponent };
|
|
33
56
|
|
|
34
57
|
//# sourceMappingURL=component.js.map
|
package/dist/component.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","names":["#
|
|
1
|
+
{"version":3,"file":"component.js","names":["#shadow","#controller","#props"],"sources":["../src/component.ts"],"sourcesContent":["import { type Ref } from './hooks/ref.ts';\nimport { type Controller, createController } from './internal/controller.ts';\n\ntype SafeProps<TProps> = any extends any\n ? { [P in keyof TProps as P extends keyof HTMLElement ? never : P]: TProps[P] }\n : never;\n\nexport interface ComponentConstructor<TProps extends object> {\n readonly formAssociated: boolean;\n new (): ComponentWithProps<TProps>;\n}\n\nexport interface ComponentOptions<TProps extends object> {\n /** Shadow root attachment options. */\n readonly shadow?: Partial<ShadowRootInit>;\n /** Component custom property descriptors. */\n readonly props?: ComponentPropDescriptors<TProps>;\n /** True to mark the component as form-associated. */\n readonly formAssociated?: boolean;\n}\n\nexport type ComponentPropDescriptors<TProps extends object> = {\n readonly [P in keyof SafeProps<TProps>]: ComponentPropDescriptorFactory<TProps[P]>;\n};\n\nexport type ComponentPropDescriptorFactory<TType> = (\n ref: Ref<TType | undefined>,\n host: HTMLElement,\n) => ComponentPropDescriptor<TType>;\n\nexport interface ComponentPropDescriptor<T> extends Omit<PropertyDescriptor, 'value' | 'get' | 'set'> {\n get(): T;\n set?(value: T): void;\n}\n\nexport type ComponentWithProps<TProps extends object> = HTMLElement & {\n -readonly [P in keyof SafeProps<TProps>]: TProps[P];\n};\n\nexport type ComponentShadowRoot<TProps extends object> = Omit<ShadowRoot, 'host'> & {\n readonly host: ComponentWithProps<TProps>;\n};\n\nexport type ComponentPropRefs<TProps extends object> = {\n readonly [P in keyof SafeProps<TProps>]: Ref<TProps[P] | undefined>;\n};\n\n/** Define a custom `HTMLElement` that is functional and reactive. */\nexport function defineComponent<TProps extends object = {}>(\n render: (shadowRoot: ComponentShadowRoot<TProps>, props: ComponentPropRefs<TProps>) => void,\n options?: ComponentOptions<TProps>,\n): ComponentConstructor<TProps>;\nexport function defineComponent(\n render: (\n shadowRoot: ComponentShadowRoot<Record<string, unknown>>,\n props: ComponentPropRefs<Record<string, unknown>>,\n ) => void,\n { props, shadow, formAssociated = false }: ComponentOptions<Record<string, unknown>> = {},\n): ComponentConstructor<{}> {\n return class extends HTMLElement {\n static readonly formAssociated = formAssociated;\n\n readonly #shadow: ComponentShadowRoot<Record<string, unknown>>;\n readonly #controller: Controller;\n readonly #props: ComponentPropRefs<Record<string, unknown>> = {};\n\n constructor() {\n super();\n\n this.#shadow = this.attachShadow({\n ...shadow,\n mode: shadow?.mode ?? 'open',\n }) as ComponentShadowRoot<Record<string, unknown>>;\n\n this.#controller = createController({\n host: this,\n formAssociated,\n render: () => render(this.#shadow, this.#props),\n attachInternals: () => super.attachInternals(),\n });\n\n if (props) {\n const propRefs: Record<string, Ref<unknown>> = this.#props;\n\n for (const [key, getDescriptor] of Object.entries(props)) {\n if (key in this) continue;\n const ref = (propRefs[key] = this.#controller.createRef<any>(undefined));\n const descriptor = getDescriptor(ref, this);\n Object.defineProperty(this, key, descriptor);\n }\n }\n\n if (formAssociated) {\n this.attachInternals();\n }\n }\n\n override attachInternals(): ElementInternals {\n return this.#controller.attachInternals();\n }\n\n protected connectedCallback(): void {\n this.#controller.connectedCallback();\n }\n\n protected connectedMoveCallback(): void {\n this.#controller.connectedMoveCallback();\n }\n\n protected disconnectedCallback(): void {\n this.#controller.disconnectedCallback();\n }\n\n protected adoptedCallback(): void {\n this.#controller.adoptedCallback();\n }\n\n protected formDisabledCallback(disabled: boolean): void {\n this.#controller.formDisabledCallback(disabled);\n }\n\n protected formResetCallback(): void {\n this.#controller.formResetCallback();\n }\n\n protected formStateRestoreCallback(state: string | File | FormData, reason: 'restore' | 'autocomplete'): void {\n this.#controller.formStateRestoreCallback(state, reason);\n }\n };\n}\n"],"mappings":";;AAoDA,SAAgB,EACd,GAIA,EAAE,UAAO,WAAQ,oBAAiB,OAAqD,EAAE,EAC/D;AAC1B,QAAO,cAAc,YAAY;EAC/B,OAAgB,iBAAiB;EAEjC;EACA;EACA,KAA8D,EAAE;EAEhE,cAAc;AAeZ,OAdA,OAAO,EAEP,MAAA,IAAe,KAAK,aAAa;IAC/B,GAAG;IACH,MAAM,GAAQ,QAAQ;IACvB,CAAC,EAEF,MAAA,IAAmB,EAAiB;IAClC,MAAM;IACN;IACA,cAAc,EAAO,MAAA,GAAc,MAAA,EAAY;IAC/C,uBAAuB,MAAM,iBAAiB;IAC/C,CAAC,EAEE,GAAO;IACT,IAAM,IAAyC,MAAA;AAE/C,SAAK,IAAM,CAAC,GAAK,MAAkB,OAAO,QAAQ,EAAM,EAAE;AACxD,SAAI,KAAO,KAAM;KAEjB,IAAM,IAAa,EAAc,EADX,KAAO,MAAA,EAAiB,UAAe,KAAA,EAAU,EACjC,KAAK;AAC3C,YAAO,eAAe,MAAM,GAAK,EAAW;;;AAIhD,GAAI,KACF,KAAK,iBAAiB;;EAI1B,kBAA6C;AAC3C,UAAO,MAAA,EAAiB,iBAAiB;;EAG3C,oBAAoC;AAClC,SAAA,EAAiB,mBAAmB;;EAGtC,wBAAwC;AACtC,SAAA,EAAiB,uBAAuB;;EAG1C,uBAAuC;AACrC,SAAA,EAAiB,sBAAsB;;EAGzC,kBAAkC;AAChC,SAAA,EAAiB,iBAAiB;;EAGpC,qBAA+B,GAAyB;AACtD,SAAA,EAAiB,qBAAqB,EAAS;;EAGjD,oBAAoC;AAClC,SAAA,EAAiB,mBAAmB;;EAGtC,yBAAmC,GAAiC,GAA0C;AAC5G,SAAA,EAAiB,yBAAyB,GAAO,EAAO"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ReadonlyRef, type Ref, type RefValues } from './ref.ts';
|
|
2
|
+
export interface AsyncValue<TValue> {
|
|
3
|
+
readonly value: TValue | undefined;
|
|
4
|
+
readonly error: unknown;
|
|
5
|
+
readonly isLoading: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface AsyncOptions {
|
|
8
|
+
readonly debounceMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Use a reference (reactive state) bound to an async loader function. */
|
|
11
|
+
export declare function useAsync<const TDeps extends readonly ReadonlyRef<any>[], TValue>(deps: TDeps, callback: (signal: AbortSignal, ...values: RefValues<TDeps>) => Promise<TValue>, { debounceMs }?: AsyncOptions): Ref<AsyncValue<TValue>>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useRef as e } from "./ref.js";
|
|
2
2
|
import { useEffect as t } from "./effect.js";
|
|
3
|
-
//#region src/hooks/
|
|
3
|
+
//#region src/hooks/async.ts
|
|
4
4
|
function n(n, r, { debounceMs: i } = {}) {
|
|
5
5
|
let a = e({
|
|
6
6
|
value: void 0,
|
|
@@ -27,6 +27,6 @@ function n(n, r, { debounceMs: i } = {}) {
|
|
|
27
27
|
}), t([], () => () => o = !0), a;
|
|
28
28
|
}
|
|
29
29
|
//#endregion
|
|
30
|
-
export { n as
|
|
30
|
+
export { n as useAsync };
|
|
31
31
|
|
|
32
|
-
//# sourceMappingURL=
|
|
32
|
+
//# sourceMappingURL=async.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async.js","names":[],"sources":["../../src/hooks/async.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { type ReadonlyRef, type Ref, type RefValues, useRef } from './ref.ts';\n\nexport interface AsyncValue<TValue> {\n readonly value: TValue | undefined;\n readonly error: unknown;\n readonly isLoading: boolean;\n}\n\nexport interface AsyncOptions {\n readonly debounceMs?: number;\n}\n\n/** Use a reference (reactive state) bound to an async loader function. */\nexport function useAsync<const TDeps extends readonly ReadonlyRef<any>[], TValue>(\n deps: TDeps,\n callback: (signal: AbortSignal, ...values: RefValues<TDeps>) => Promise<TValue>,\n { debounceMs }: AsyncOptions = {},\n): Ref<AsyncValue<TValue>> {\n const ref = useRef<AsyncValue<TValue>>({ value: undefined, error: undefined, isLoading: true });\n let skipDebounce = true;\n\n useEffect(deps, () => (...values) => {\n const ac = new AbortController();\n\n Promise.race(\n skipDebounce\n ? [Promise.resolve()]\n : [\n new Promise((resolve) => setTimeout(resolve, debounceMs)),\n new Promise((resolve) => ac.signal.addEventListener('abort', resolve, { once: true })),\n ],\n )\n .then(() => {\n if (ac.signal.aborted) return;\n return callback(ac.signal, ...(values as any));\n })\n .then((value) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value, error: undefined };\n })\n .catch((error: unknown) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value: undefined, error };\n });\n\n skipDebounce = false;\n return () => ac.abort();\n });\n\n // Skip the debounce again if the component unmounts.\n useEffect([], () => () => (skipDebounce = true));\n\n return ref;\n}\n"],"mappings":";;;AAcA,SAAgB,EACd,GACA,GACA,EAAE,kBAA6B,EAAE,EACR;CACzB,IAAM,IAAM,EAA2B;EAAE,OAAO,KAAA;EAAW,OAAO,KAAA;EAAW,WAAW;EAAM,CAAC,EAC3F,IAAe;AAiCnB,QA/BA,EAAU,UAAa,GAAG,MAAW;EACnC,IAAM,IAAK,IAAI,iBAAiB;AAwBhC,SAtBA,QAAQ,KACN,IACI,CAAC,QAAQ,SAAS,CAAC,GACnB,CACE,IAAI,SAAS,MAAY,WAAW,GAAS,EAAW,CAAC,EACzD,IAAI,SAAS,MAAY,EAAG,OAAO,iBAAiB,SAAS,GAAS,EAAE,MAAM,IAAM,CAAC,CAAC,CACvF,CACN,CACE,WAAW;AACN,UAAG,OAAO,QACd,QAAO,EAAS,EAAG,QAAQ,GAAI,EAAe;IAC9C,CACD,MAAM,MAAU;AACX,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO;IAAO,OAAO,KAAA;IAAW;IACzD,CACD,OAAO,MAAmB;AACrB,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO,OAAO,KAAA;IAAW;IAAO;IACzD,EAEJ,IAAe,UACF,EAAG,OAAO;GACvB,EAGF,EAAU,EAAE,cAAe,IAAe,GAAM,EAEzC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useRef as e } from "./ref.js";
|
|
2
2
|
import { useEffect as t } from "./effect.js";
|
|
3
3
|
import { useHost as n } from "./host.js";
|
|
4
|
-
//#region src/hooks/child
|
|
4
|
+
//#region src/hooks/child.ts
|
|
5
5
|
function r(r) {
|
|
6
6
|
let i = n(), a = e(0), o = new MutationObserver((e) => {
|
|
7
7
|
e.some((e) => e.type === "childList") && (a.value = (a.value + 1) % (2 ** 53 - 1));
|
|
@@ -11,4 +11,4 @@ function r(r) {
|
|
|
11
11
|
//#endregion
|
|
12
12
|
export { r as useChildEffect };
|
|
13
13
|
|
|
14
|
-
//# sourceMappingURL=child
|
|
14
|
+
//# sourceMappingURL=child.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child.js","names":[],"sources":["../../src/hooks/child.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { useHost } from './host.ts';\nimport { useRef } from './ref.ts';\n\n/** React to child list changes (non-recursive). */\nexport function useChildEffect(callback: () => (() => void) | void): void {\n const host = useHost();\n const ref = useRef(0);\n\n const observer = new MutationObserver((mutation) => {\n if (mutation.some((m) => m.type === 'childList')) {\n ref.value = (ref.value + 1) % Number.MAX_SAFE_INTEGER;\n }\n });\n\n useEffect([], () => {\n observer.observe(host, { childList: true });\n return () => observer.disconnect();\n });\n\n useEffect([ref], () => {\n return callback();\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,EAAe,GAA2C;CACxE,IAAM,IAAO,GAAS,EAChB,IAAM,EAAO,EAAE,EAEf,IAAW,IAAI,kBAAkB,MAAa;AAClD,EAAI,EAAS,MAAM,MAAM,EAAE,SAAS,YAAY,KAC9C,EAAI,SAAS,EAAI,QAAQ;GAE3B;AAOF,CALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM,EAAE,WAAW,IAAM,CAAC,QAC9B,EAAS,YAAY,EAClC,EAEF,EAAU,CAAC,EAAI,QACN,GAAU,CACjB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getController as e } from "../internal/controller.js";
|
|
2
|
+
//#region src/hooks/controller.ts
|
|
3
|
+
function t() {
|
|
4
|
+
let t = e();
|
|
5
|
+
if (!t) throw Error("hooks must be called by a render function");
|
|
6
|
+
return t;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { t as useController };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","names":[],"sources":["../../src/hooks/controller.ts"],"sourcesContent":["import { type Controller, getController } from '../internal/controller.ts';\n\n/** @internal Get the controller of the currently rendering component. */\nexport function useController(): Controller {\n const controller = getController();\n if (!controller) throw new Error('hooks must be called by a render function');\n return controller;\n}\n"],"mappings":";;AAGA,SAAgB,IAA4B;CAC1C,IAAM,IAAa,GAAe;AAClC,KAAI,CAAC,EAAY,OAAU,MAAM,4CAA4C;AAC7E,QAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disconnect.js","names":[],"sources":["../../src/hooks/disconnect.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Register a callback for disconnections. */\nexport function useDisconnectCallback(callback: () => void): void {\n useController().onDisconnect.push(callback);\n}\n"],"mappings":";;AAGA,SAAgB,EAAsB,GAA4B;AAChE,IAAe,CAAC,aAAa,KAAK,EAAS"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","names":[],"sources":["../../src/hooks/document.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the owner document. */\nexport function useDocument(): ReadonlyRef<Document> {\n return useController().refDocument;\n}\n"],"mappings":";;AAIA,SAAgB,IAAqC;AACnD,QAAO,GAAe,CAAC"}
|
package/dist/hooks/effect.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useController as e } from "./controller.js";
|
|
2
|
+
import { useDisconnectCallback as t } from "./disconnect.js";
|
|
3
3
|
//#region src/hooks/effect.ts
|
|
4
4
|
function n(n, r) {
|
|
5
|
-
let
|
|
6
|
-
|
|
5
|
+
let i, a, o = () => {
|
|
6
|
+
let e = i;
|
|
7
|
+
i = void 0, e?.();
|
|
8
|
+
};
|
|
9
|
+
e().onNotify.push(() => {
|
|
7
10
|
let e = n.map((e) => e.value);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let t = r(...c);
|
|
11
|
-
t && o.push(() => t());
|
|
12
|
-
}), a.push(s);
|
|
11
|
+
a?.length === e.length && a?.every((t, n) => t === e[n]) || (a = e, o(), i = r(...a));
|
|
12
|
+
}), t(o);
|
|
13
13
|
}
|
|
14
14
|
//#endregion
|
|
15
15
|
export { n as useEffect };
|
package/dist/hooks/effect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","names":[],"sources":["../../src/hooks/effect.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"effect.js","names":[],"sources":["../../src/hooks/effect.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport { useDisconnectCallback } from './disconnect.ts';\nimport type { ReadonlyRef, RefValues } from './ref.ts';\n\n/** React to observable (reference) changes. */\nexport function useEffect<const TDeps extends readonly ReadonlyRef<any>[]>(\n deps: TDeps,\n callback: (...values: RefValues<TDeps>) => (() => void) | void,\n): void {\n let cleanupCallback: (() => void) | void;\n let values: any[] | undefined;\n\n const cleanup = () => {\n const callback = cleanupCallback;\n cleanupCallback = undefined;\n callback?.();\n };\n\n useController().onNotify.push((): void => {\n const newValues = deps.map((dep) => dep.value);\n if (values?.length === newValues.length && values?.every((value, i) => value === newValues[i])) return;\n values = newValues;\n cleanup();\n cleanupCallback = callback(...(values as any));\n });\n\n useDisconnectCallback(cleanup);\n}\n"],"mappings":";;;AAKA,SAAgB,EACd,GACA,GACM;CACN,IAAI,GACA,GAEE,UAAgB;EACpB,IAAM,IAAW;AAEjB,EADA,IAAkB,KAAA,GAClB,KAAY;;AAWd,CARA,GAAe,CAAC,SAAS,WAAiB;EACxC,IAAM,IAAY,EAAK,KAAK,MAAQ,EAAI,MAAM;AAC1C,KAAQ,WAAW,EAAU,UAAU,GAAQ,OAAO,GAAO,MAAM,MAAU,EAAU,GAAG,KAC9F,IAAS,GACT,GAAS,EACT,IAAkB,EAAS,GAAI,EAAe;GAC9C,EAEF,EAAsB,EAAQ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReadonlyRef } from './ref.ts';
|
|
2
|
+
/** Use a reference (reactive state) bound to the associated form. */
|
|
3
|
+
export declare function useForm(): ReadonlyRef<HTMLFormElement | null>;
|
|
4
|
+
/** Use a reference (reactive state) bound to the form disabled state. */
|
|
5
|
+
export declare function useFormDisabled(): ReadonlyRef<boolean>;
|
|
6
|
+
/** Register a callback for form resets. */
|
|
7
|
+
export declare function useFormResetCallback(callback: () => void): void;
|
|
8
|
+
/** Register a callback for form restorations. */
|
|
9
|
+
export declare function useFormRestoreCallback(callback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useController as e } from "./controller.js";
|
|
2
|
+
//#region src/hooks/form.ts
|
|
3
|
+
function t() {
|
|
4
|
+
return a().refForm;
|
|
5
|
+
}
|
|
6
|
+
function n() {
|
|
7
|
+
return a().refDisabled;
|
|
8
|
+
}
|
|
9
|
+
function r(e) {
|
|
10
|
+
a().onReset.push(e);
|
|
11
|
+
}
|
|
12
|
+
function i(e) {
|
|
13
|
+
a().onRestore.push(e);
|
|
14
|
+
}
|
|
15
|
+
function a() {
|
|
16
|
+
let { formAssociated: t } = e();
|
|
17
|
+
if (!t) throw Error("form hooks must be called in a form-associated component");
|
|
18
|
+
return t;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { t as useForm, n as useFormDisabled, r as useFormResetCallback, i as useFormRestoreCallback };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.js","names":[],"sources":["../../src/hooks/form.ts"],"sourcesContent":["import type { Controller } from '../internal/controller.ts';\nimport { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the associated form. */\nexport function useForm(): ReadonlyRef<HTMLFormElement | null> {\n return useFormAssociated().refForm;\n}\n\n/** Use a reference (reactive state) bound to the form disabled state. */\nexport function useFormDisabled(): ReadonlyRef<boolean> {\n return useFormAssociated().refDisabled;\n}\n\n/** Register a callback for form resets. */\nexport function useFormResetCallback(callback: () => void): void {\n useFormAssociated().onReset.push(callback);\n}\n\n/** Register a callback for form restorations. */\nexport function useFormRestoreCallback(\n callback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void,\n): void {\n useFormAssociated().onRestore.push(callback);\n}\n\nfunction useFormAssociated(): Controller['formAssociated'] & {} {\n const { formAssociated } = useController();\n if (!formAssociated) throw new Error('form hooks must be called in a form-associated component');\n return formAssociated;\n}\n"],"mappings":";;AAKA,SAAgB,IAA+C;AAC7D,QAAO,GAAmB,CAAC;;AAI7B,SAAgB,IAAwC;AACtD,QAAO,GAAmB,CAAC;;AAI7B,SAAgB,EAAqB,GAA4B;AAC/D,IAAmB,CAAC,QAAQ,KAAK,EAAS;;AAI5C,SAAgB,EACd,GACM;AACN,IAAmB,CAAC,UAAU,KAAK,EAAS;;AAG9C,SAAS,IAAuD;CAC9D,IAAM,EAAE,sBAAmB,GAAe;AAC1C,KAAI,CAAC,EAAgB,OAAU,MAAM,2DAA2D;AAChG,QAAO"}
|
package/dist/hooks/host.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Use the component host element. */
|
|
2
2
|
export declare function useHost(): HTMLElement;
|
package/dist/hooks/host.js
CHANGED
package/dist/hooks/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","names":[],"sources":["../../src/hooks/host.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"host.js","names":[],"sources":["../../src/hooks/host.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Use the component host element. */\nexport function useHost(): HTMLElement {\n return useController().host;\n}\n"],"mappings":";;AAGA,SAAgB,IAAuB;AACrC,QAAO,GAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internals.js","names":[],"sources":["../../src/hooks/internals.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Use the element internals. */\nexport function useElementInternals(): ElementInternals {\n return useController().attachInternals();\n}\n"],"mappings":";;AAGA,SAAgB,IAAwC;AACtD,QAAO,GAAe,CAAC,iBAAiB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parent.js","names":[],"sources":["../../src/hooks/parent.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the parent node. */\nexport function useParent(): ReadonlyRef<ParentNode | null> {\n return useController().refParent;\n}\n"],"mappings":";;AAIA,SAAgB,IAA4C;AAC1D,QAAO,GAAe,CAAC"}
|
package/dist/hooks/ref.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { $$ref } from '../internal/controller.ts';
|
|
1
2
|
export interface Ref<T> extends ReadonlyRef<T> {
|
|
2
3
|
value: T;
|
|
3
4
|
}
|
|
@@ -9,7 +10,5 @@ export interface ReadonlyRef<T> {
|
|
|
9
10
|
export type RefValues<T> = T extends readonly any[] ? {
|
|
10
11
|
[K in keyof T]: T[K] extends ReadonlyRef<infer V> ? V : never;
|
|
11
12
|
} : never;
|
|
12
|
-
declare const $$ref: unique symbol;
|
|
13
13
|
/** Use a reference (reactive state) value. */
|
|
14
14
|
export declare function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T>;
|
|
15
|
-
export {};
|
package/dist/hooks/ref.js
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useController as e } from "./controller.js";
|
|
2
2
|
//#region src/hooks/ref.ts
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
let { notify: i } = e(), a = n;
|
|
6
|
-
return {
|
|
7
|
-
[t]: !0,
|
|
8
|
-
get value() {
|
|
9
|
-
return a;
|
|
10
|
-
},
|
|
11
|
-
set value(e) {
|
|
12
|
-
e !== a && (a = e, r?.(a), i());
|
|
13
|
-
}
|
|
14
|
-
};
|
|
3
|
+
function t(t, n) {
|
|
4
|
+
return e().createRef(t, n);
|
|
15
5
|
}
|
|
16
6
|
//#endregion
|
|
17
|
-
export {
|
|
7
|
+
export { t as useRef };
|
|
18
8
|
|
|
19
9
|
//# sourceMappingURL=ref.js.map
|
package/dist/hooks/ref.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref.js","names":[],"sources":["../../src/hooks/ref.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"ref.js","names":[],"sources":["../../src/hooks/ref.ts"],"sourcesContent":["import type { $$ref } from '../internal/controller.ts';\nimport { useController } from './controller.ts';\n\nexport interface Ref<T> extends ReadonlyRef<T> {\n value: T;\n}\n\nexport interface ReadonlyRef<T> {\n /** @hidden */\n [$$ref]: unknown;\n readonly value: T;\n}\n\nexport type RefValues<T> = T extends readonly any[]\n ? { [K in keyof T]: T[K] extends ReadonlyRef<infer V> ? V : never }\n : never;\n\n/** Use a reference (reactive state) value. */\nexport function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T> {\n return useController().createRef(initialValue, onChange);\n}\n"],"mappings":";;AAkBA,SAAgB,EAAU,GAAiB,GAAuC;AAChF,QAAO,GAAe,CAAC,UAAU,GAAc,EAAS"}
|
package/dist/hooks/route.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export interface RouteOptions {
|
|
|
3
3
|
readonly match?: 'prefix' | 'exact' | RegExp;
|
|
4
4
|
readonly source?: 'pathname' | 'hash';
|
|
5
5
|
}
|
|
6
|
-
export type
|
|
6
|
+
export type RouteMatch = readonly [string, ...string[]] & {
|
|
7
7
|
readonly groups: Record<string, string>;
|
|
8
8
|
};
|
|
9
9
|
/** Use a reference (reactive state) bound to route matching. */
|
|
10
|
-
export declare function useRoute(path: string | readonly string[], { match, source }?: RouteOptions): Ref<
|
|
10
|
+
export declare function useRoute(path: string | readonly string[], { match, source }?: RouteOptions): Ref<RouteMatch | null>;
|
package/dist/hooks/route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","names":[],"sources":["../../src/hooks/route.ts"],"sourcesContent":["import { getRouter } from '../router.ts';\nimport { useEffect } from './effect.ts';\nimport { type Ref, useRef } from './ref.ts';\nimport { useStore } from './store.ts';\n\nexport interface RouteOptions {\n readonly match?: 'prefix' | 'exact' | RegExp;\n readonly source?: 'pathname' | 'hash';\n}\n\nexport type
|
|
1
|
+
{"version":3,"file":"route.js","names":[],"sources":["../../src/hooks/route.ts"],"sourcesContent":["import { getRouter } from '../router.ts';\nimport { useEffect } from './effect.ts';\nimport { type Ref, useRef } from './ref.ts';\nimport { useStore } from './store.ts';\n\nexport interface RouteOptions {\n readonly match?: 'prefix' | 'exact' | RegExp;\n readonly source?: 'pathname' | 'hash';\n}\n\nexport type RouteMatch = readonly [string, ...string[]] & { readonly groups: Record<string, string> };\n\n/** Use a reference (reactive state) bound to route matching. */\nexport function useRoute(\n path: string | readonly string[],\n { match = 'prefix', source = 'pathname' }: RouteOptions = {},\n): Ref<RouteMatch | null> {\n const matchRx = match === 'exact' ? /^$/u : match === 'prefix' ? /^.*$/u : match;\n const paths = Array.isArray(path) ? (path as readonly string[]) : [path as string];\n const refRoute = useStore(getRouter(), (state) => state[source]);\n const refMatch = useRef<RouteMatch | null>(getMatch(refRoute.value));\n\n useEffect([refRoute], (route) => {\n refMatch.value = getMatch(route);\n });\n\n return refMatch;\n\n function getMatch(route: string): RouteMatch | null {\n const prefix = paths.find((path) => route.endsWith(path)) ?? null;\n if (prefix == null) return null;\n route = route.slice(prefix.length);\n return route.match(matchRx) as RouteMatch | null;\n }\n}\n"],"mappings":";;;;;AAaA,SAAgB,EACd,GACA,EAAE,WAAQ,UAAU,YAAS,eAA6B,EAAE,EACpC;CACxB,IAAM,IAAU,MAAU,UAAU,QAAQ,MAAU,WAAW,UAAU,GACrE,IAAQ,MAAM,QAAQ,EAAK,GAAI,IAA6B,CAAC,EAAe,EAC5E,IAAW,EAAS,GAAW,GAAG,MAAU,EAAM,GAAQ,EAC1D,IAAW,EAA0B,EAAS,EAAS,MAAM,CAAC;AAMpE,QAJA,EAAU,CAAC,EAAS,GAAG,MAAU;AAC/B,IAAS,QAAQ,EAAS,EAAM;GAChC,EAEK;CAEP,SAAS,EAAS,GAAkC;EAClD,IAAM,IAAS,EAAM,MAAM,MAAS,EAAM,SAAS,EAAK,CAAC,IAAI;AAG7D,SAFI,KAAU,OAAa,QAC3B,IAAQ,EAAM,MAAM,EAAO,OAAO,EAC3B,EAAM,MAAM,EAAQ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export * from './component.ts';
|
|
2
|
+
export * from './hooks/async.ts';
|
|
2
3
|
export * from './hooks/attributes.ts';
|
|
3
|
-
export * from './hooks/child
|
|
4
|
+
export * from './hooks/child.ts';
|
|
5
|
+
export * from './hooks/disconnect.ts';
|
|
6
|
+
export * from './hooks/document.ts';
|
|
4
7
|
export * from './hooks/effect.ts';
|
|
8
|
+
export * from './hooks/form.ts';
|
|
5
9
|
export * from './hooks/host.ts';
|
|
6
|
-
export * from './hooks/
|
|
10
|
+
export * from './hooks/internals.ts';
|
|
11
|
+
export * from './hooks/parent.ts';
|
|
7
12
|
export * from './hooks/ref.ts';
|
|
8
13
|
export * from './hooks/route.ts';
|
|
9
14
|
export * from './hooks/store.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { useRef as e } from "./hooks/ref.js";
|
|
2
2
|
import { defineComponent as t } from "./component.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
3
|
+
import { useDisconnectCallback as n } from "./hooks/disconnect.js";
|
|
4
|
+
import { useEffect as r } from "./hooks/effect.js";
|
|
5
|
+
import { useAsync as i } from "./hooks/async.js";
|
|
6
|
+
import { useHost as a } from "./hooks/host.js";
|
|
7
|
+
import { useAttributes as o } from "./hooks/attributes.js";
|
|
8
|
+
import { useChildEffect as s } from "./hooks/child.js";
|
|
9
|
+
import { useDocument as c } from "./hooks/document.js";
|
|
10
|
+
import { useForm as l, useFormDisabled as u, useFormResetCallback as d, useFormRestoreCallback as f } from "./hooks/form.js";
|
|
11
|
+
import { useElementInternals as p } from "./hooks/internals.js";
|
|
12
|
+
import { useParent as m } from "./hooks/parent.js";
|
|
13
|
+
import { createStore as h } from "./store.js";
|
|
14
|
+
import { getRouter as g } from "./router.js";
|
|
15
|
+
import { useStore as _ } from "./hooks/store.js";
|
|
16
|
+
import { useRoute as v } from "./hooks/route.js";
|
|
17
|
+
import { html as y } from "./html.js";
|
|
18
|
+
export { h as createStore, t as defineComponent, g as getRouter, y as h, y as html, i as useAsync, o as useAttributes, s as useChildEffect, n as useDisconnectCallback, c as useDocument, r as useEffect, p as useElementInternals, l as useForm, u as useFormDisabled, d as useFormResetCallback, f as useFormRestoreCallback, a as useHost, m as useParent, e as useRef, v as useRoute, _ as useStore };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ReadonlyRef, type Ref } from '../hooks/ref.ts';
|
|
2
|
+
import { type Callbacks } from './callbacks.ts';
|
|
3
|
+
export interface Controller {
|
|
4
|
+
readonly host: HTMLElement;
|
|
5
|
+
readonly onNotify: Callbacks;
|
|
6
|
+
readonly onDisconnect: Callbacks;
|
|
7
|
+
readonly refDocument: ReadonlyRef<Document>;
|
|
8
|
+
readonly refParent: ReadonlyRef<ParentNode | null>;
|
|
9
|
+
readonly formAssociated: {
|
|
10
|
+
readonly refForm: ReadonlyRef<HTMLFormElement | null>;
|
|
11
|
+
readonly refDisabled: ReadonlyRef<boolean>;
|
|
12
|
+
readonly onReset: Callbacks;
|
|
13
|
+
readonly onRestore: Callbacks<[state: string | File | FormData, reason: 'restore' | 'autocomplete']>;
|
|
14
|
+
} | undefined;
|
|
15
|
+
readonly createRef: <T>(value: T, onChange?: (value: T) => void) => Ref<T>;
|
|
16
|
+
readonly attachInternals: () => ElementInternals;
|
|
17
|
+
readonly connectedCallback: () => void;
|
|
18
|
+
readonly connectedMoveCallback: () => void;
|
|
19
|
+
readonly disconnectedCallback: () => void;
|
|
20
|
+
readonly adoptedCallback: () => void;
|
|
21
|
+
readonly formDisabledCallback: (disabled: boolean) => void;
|
|
22
|
+
readonly formResetCallback: () => void;
|
|
23
|
+
readonly formStateRestoreCallback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void;
|
|
24
|
+
}
|
|
25
|
+
export interface ControllerConfig {
|
|
26
|
+
readonly host: HTMLElement;
|
|
27
|
+
readonly formAssociated: boolean;
|
|
28
|
+
readonly render: (controller: Controller) => void;
|
|
29
|
+
readonly attachInternals: () => ElementInternals;
|
|
30
|
+
}
|
|
31
|
+
export declare const $$ref: unique symbol;
|
|
32
|
+
export declare function getController(): Controller | undefined;
|
|
33
|
+
export declare function createController({ host, formAssociated, render, attachInternals }: ControllerConfig): Controller;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createCallbacks as e } from "./callbacks.js";
|
|
2
|
+
//#region src/internal/controller.ts
|
|
3
|
+
var t = Symbol(), n = [];
|
|
4
|
+
function r() {
|
|
5
|
+
return n.at(-1);
|
|
6
|
+
}
|
|
7
|
+
function i({ host: r, formAssociated: i, render: a, attachInternals: o }) {
|
|
8
|
+
let s = !1, c = !1, l, u, d = e(), f = (e, n) => {
|
|
9
|
+
let r = e;
|
|
10
|
+
return {
|
|
11
|
+
[t]: !0,
|
|
12
|
+
get value() {
|
|
13
|
+
return r;
|
|
14
|
+
},
|
|
15
|
+
set value(e) {
|
|
16
|
+
e !== r && (r = e, n?.(r), !(!c || s) && (s = !0, queueMicrotask(() => {
|
|
17
|
+
s = !1, d.run();
|
|
18
|
+
})));
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}, p = {
|
|
22
|
+
host: r,
|
|
23
|
+
onNotify: d,
|
|
24
|
+
onDisconnect: e(),
|
|
25
|
+
refDocument: f(r.ownerDocument),
|
|
26
|
+
refParent: f(r.parentNode),
|
|
27
|
+
formAssociated: i ? {
|
|
28
|
+
refForm: f(null),
|
|
29
|
+
refDisabled: f(!1),
|
|
30
|
+
onReset: e(),
|
|
31
|
+
onRestore: e()
|
|
32
|
+
} : void 0,
|
|
33
|
+
createRef: f,
|
|
34
|
+
attachInternals: () => l ??= o(),
|
|
35
|
+
connectedCallback: () => {
|
|
36
|
+
c = !0, p.refParent.value = r.parentNode;
|
|
37
|
+
try {
|
|
38
|
+
n.push(p), a(p);
|
|
39
|
+
} finally {
|
|
40
|
+
n.pop();
|
|
41
|
+
}
|
|
42
|
+
u?.type === "reset" ? p.formAssociated?.onReset.run() : u?.type === "restore" && p.formAssociated?.onRestore.run(u.state, u.reason), p.onNotify.run();
|
|
43
|
+
},
|
|
44
|
+
connectedMoveCallback: () => {
|
|
45
|
+
p.refParent.value = r.parentNode, p.onNotify.run();
|
|
46
|
+
},
|
|
47
|
+
disconnectedCallback: () => {
|
|
48
|
+
p.onNotify.clear(), p.formAssociated?.onReset.clear(), p.formAssociated?.onRestore.clear(), p.onDisconnect.runAndClear();
|
|
49
|
+
},
|
|
50
|
+
adoptedCallback: () => {
|
|
51
|
+
p.refDocument.value = r.ownerDocument, p.onNotify.run();
|
|
52
|
+
},
|
|
53
|
+
formDisabledCallback: (e) => {
|
|
54
|
+
p.formAssociated && (p.formAssociated.refDisabled.value = e, p.onNotify.run());
|
|
55
|
+
},
|
|
56
|
+
formResetCallback: () => {
|
|
57
|
+
p.formAssociated && (c ? p.formAssociated.onReset.run() : u = { type: "reset" });
|
|
58
|
+
},
|
|
59
|
+
formStateRestoreCallback: (e, t) => {
|
|
60
|
+
p.formAssociated && (c ? p.formAssociated.onRestore.run(e, t) : u = {
|
|
61
|
+
type: "restore",
|
|
62
|
+
state: e,
|
|
63
|
+
reason: t
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return p;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { i as createController, r as getController };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","names":[],"sources":["../../src/internal/controller.ts"],"sourcesContent":["import { type ReadonlyRef, type Ref } from '../hooks/ref.ts';\nimport { type Callbacks, createCallbacks } from './callbacks.ts';\n\nexport interface Controller {\n readonly host: HTMLElement;\n readonly onNotify: Callbacks;\n readonly onDisconnect: Callbacks;\n readonly refDocument: ReadonlyRef<Document>;\n readonly refParent: ReadonlyRef<ParentNode | null>;\n readonly formAssociated:\n | {\n readonly refForm: ReadonlyRef<HTMLFormElement | null>;\n readonly refDisabled: ReadonlyRef<boolean>;\n readonly onReset: Callbacks;\n readonly onRestore: Callbacks<[state: string | File | FormData, reason: 'restore' | 'autocomplete']>;\n }\n | undefined;\n readonly createRef: <T>(value: T, onChange?: (value: T) => void) => Ref<T>;\n readonly attachInternals: () => ElementInternals;\n readonly connectedCallback: () => void;\n readonly connectedMoveCallback: () => void;\n readonly disconnectedCallback: () => void;\n readonly adoptedCallback: () => void;\n readonly formDisabledCallback: (disabled: boolean) => void;\n readonly formResetCallback: () => void;\n readonly formStateRestoreCallback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void;\n}\n\nexport interface ControllerConfig {\n readonly host: HTMLElement;\n readonly formAssociated: boolean;\n readonly render: (controller: Controller) => void;\n readonly attachInternals: () => ElementInternals;\n}\n\nexport const $$ref = Symbol();\n\nconst controllers: Controller[] = [];\n\nexport function getController(): Controller | undefined {\n return controllers.at(-1);\n}\n\nexport function createController({ host, formAssociated, render, attachInternals }: ControllerConfig): Controller {\n let notifying = false;\n let connected = false;\n let internals: ElementInternals | undefined;\n\n let deferredFormUpdate:\n | { readonly type: 'reset' }\n | { readonly type: 'restore'; state: string | File | FormData; reason: 'restore' | 'autocomplete' }\n | undefined;\n\n const onNotify = createCallbacks();\n\n const createRef = <T>(initialValue: T, onChange?: (value: T) => void): Ref<T> => {\n let value = initialValue;\n\n return {\n [$$ref]: true,\n get value() {\n return value;\n },\n set value(newValue) {\n if (newValue === value) return;\n value = newValue;\n onChange?.(value);\n if (!connected || notifying) return;\n notifying = true;\n\n queueMicrotask(() => {\n notifying = false;\n onNotify.run();\n });\n },\n };\n };\n\n const controller = {\n host,\n onNotify,\n onDisconnect: createCallbacks(),\n refDocument: createRef(host.ownerDocument),\n refParent: createRef(host.parentNode),\n formAssociated: formAssociated\n ? {\n refForm: createRef<HTMLFormElement | null>(null),\n refDisabled: createRef(false),\n onReset: createCallbacks(),\n onRestore: createCallbacks(),\n }\n : undefined,\n createRef,\n attachInternals: () => {\n return (internals ??= attachInternals());\n },\n connectedCallback: () => {\n connected = true;\n controller.refParent.value = host.parentNode;\n\n try {\n controllers.push(controller);\n render(controller);\n } finally {\n controllers.pop();\n }\n\n if (deferredFormUpdate?.type === 'reset') {\n controller.formAssociated?.onReset.run();\n } else if (deferredFormUpdate?.type === 'restore') {\n controller.formAssociated?.onRestore.run(deferredFormUpdate.state, deferredFormUpdate.reason);\n }\n\n controller.onNotify.run();\n },\n connectedMoveCallback: () => {\n controller.refParent.value = host.parentNode;\n controller.onNotify.run();\n },\n disconnectedCallback: () => {\n controller.onNotify.clear();\n controller.formAssociated?.onReset.clear();\n controller.formAssociated?.onRestore.clear();\n controller.onDisconnect.runAndClear();\n },\n adoptedCallback: () => {\n controller.refDocument.value = host.ownerDocument;\n controller.onNotify.run();\n },\n formDisabledCallback: (disabled: boolean) => {\n if (!controller.formAssociated) return;\n controller.formAssociated.refDisabled.value = disabled;\n controller.onNotify.run();\n },\n formResetCallback: () => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onReset.run();\n else deferredFormUpdate = { type: 'reset' };\n },\n formStateRestoreCallback: (state, reason) => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onRestore.run(state, reason);\n else deferredFormUpdate = { type: 'restore', state, reason };\n },\n } satisfies Controller;\n\n return controller;\n}\n"],"mappings":";;AAmCA,IAAa,IAAQ,QAAQ,EAEvB,IAA4B,EAAE;AAEpC,SAAgB,IAAwC;AACtD,QAAO,EAAY,GAAG,GAAG;;AAG3B,SAAgB,EAAiB,EAAE,SAAM,mBAAgB,WAAQ,sBAAiD;CAChH,IAAI,IAAY,IACZ,IAAY,IACZ,GAEA,GAKE,IAAW,GAAiB,EAE5B,KAAgB,GAAiB,MAA0C;EAC/E,IAAI,IAAQ;AAEZ,SAAO;IACJ,IAAQ;GACT,IAAI,QAAQ;AACV,WAAO;;GAET,IAAI,MAAM,GAAU;AACd,UAAa,MACjB,IAAQ,GACR,IAAW,EAAM,EACb,GAAC,KAAa,OAClB,IAAY,IAEZ,qBAAqB;AAEnB,KADA,IAAY,IACZ,EAAS,KAAK;MACd;;GAEL;IAGG,IAAa;EACjB;EACA;EACA,cAAc,GAAiB;EAC/B,aAAa,EAAU,EAAK,cAAc;EAC1C,WAAW,EAAU,EAAK,WAAW;EACrC,gBAAgB,IACZ;GACE,SAAS,EAAkC,KAAK;GAChD,aAAa,EAAU,GAAM;GAC7B,SAAS,GAAiB;GAC1B,WAAW,GAAiB;GAC7B,GACD,KAAA;EACJ;EACA,uBACU,MAAc,GAAiB;EAEzC,yBAAyB;AAEvB,GADA,IAAY,IACZ,EAAW,UAAU,QAAQ,EAAK;AAElC,OAAI;AAEF,IADA,EAAY,KAAK,EAAW,EAC5B,EAAO,EAAW;aACV;AACR,MAAY,KAAK;;AASnB,GANI,GAAoB,SAAS,UAC/B,EAAW,gBAAgB,QAAQ,KAAK,GAC/B,GAAoB,SAAS,aACtC,EAAW,gBAAgB,UAAU,IAAI,EAAmB,OAAO,EAAmB,OAAO,EAG/F,EAAW,SAAS,KAAK;;EAE3B,6BAA6B;AAE3B,GADA,EAAW,UAAU,QAAQ,EAAK,YAClC,EAAW,SAAS,KAAK;;EAE3B,4BAA4B;AAI1B,GAHA,EAAW,SAAS,OAAO,EAC3B,EAAW,gBAAgB,QAAQ,OAAO,EAC1C,EAAW,gBAAgB,UAAU,OAAO,EAC5C,EAAW,aAAa,aAAa;;EAEvC,uBAAuB;AAErB,GADA,EAAW,YAAY,QAAQ,EAAK,eACpC,EAAW,SAAS,KAAK;;EAE3B,uBAAuB,MAAsB;AACtC,KAAW,mBAChB,EAAW,eAAe,YAAY,QAAQ,GAC9C,EAAW,SAAS,KAAK;;EAE3B,yBAAyB;AAClB,KAAW,mBACZ,IAAW,EAAW,eAAe,QAAQ,KAAK,GACjD,IAAqB,EAAE,MAAM,SAAS;;EAE7C,2BAA2B,GAAO,MAAW;AACtC,KAAW,mBACZ,IAAW,EAAW,eAAe,UAAU,IAAI,GAAO,EAAO,GAChE,IAAqB;IAAE,MAAM;IAAW;IAAO;IAAQ;;EAE/D;AAED,QAAO"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"child-effect.js","names":[],"sources":["../../src/hooks/child-effect.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { useHost } from './host.ts';\nimport { useRef } from './ref.ts';\n\n/** React to child list changes (non-recursive). */\nexport function useChildEffect(callback: () => (() => void) | void): void {\n const host = useHost();\n const ref = useRef(0);\n\n const observer = new MutationObserver((mutation) => {\n if (mutation.some((m) => m.type === 'childList')) {\n ref.value = (ref.value + 1) % Number.MAX_SAFE_INTEGER;\n }\n });\n\n useEffect([], () => {\n observer.observe(host, { childList: true });\n return () => observer.disconnect();\n });\n\n useEffect([ref], () => {\n return callback();\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,EAAe,GAA2C;CACxE,IAAM,IAAO,GAAS,EAChB,IAAM,EAAO,EAAE,EAEf,IAAW,IAAI,kBAAkB,MAAa;AAClD,EAAI,EAAS,MAAM,MAAM,EAAE,SAAS,YAAY,KAC9C,EAAI,SAAS,EAAI,QAAQ;GAE3B;AAOF,CALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM,EAAE,WAAW,IAAM,CAAC,QAC9B,EAAS,YAAY,EAClC,EAEF,EAAU,CAAC,EAAI,QACN,GAAU,CACjB"}
|
package/dist/hooks/context.d.ts
DELETED
package/dist/hooks/context.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { contextStack as e } from "../internal/context.js";
|
|
2
|
-
//#region src/hooks/context.ts
|
|
3
|
-
function t() {
|
|
4
|
-
let t = e.at(-1);
|
|
5
|
-
if (!t) throw Error("hooks must be called inside a render function");
|
|
6
|
-
return t;
|
|
7
|
-
}
|
|
8
|
-
//#endregion
|
|
9
|
-
export { t as useContext };
|
|
10
|
-
|
|
11
|
-
//# sourceMappingURL=context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../src/hooks/context.ts"],"sourcesContent":["import { type Context, contextStack } from '../internal/context.ts';\n\n/** @internal Get the context of the currently rendering component. */\nexport function useContext(): Context {\n const context = contextStack.at(-1);\n if (!context) throw new Error('hooks must be called inside a render function');\n return context;\n}\n"],"mappings":";;AAGA,SAAgB,IAAsB;CACpC,IAAM,IAAU,EAAa,GAAG,GAAG;AACnC,KAAI,CAAC,EAAS,OAAU,MAAM,gDAAgD;AAC9E,QAAO"}
|
package/dist/hooks/loading.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type ReadonlyRef, type Ref, type RefValues } from './ref.ts';
|
|
2
|
-
export interface LoadingValue<TValue> {
|
|
3
|
-
readonly value: TValue | undefined;
|
|
4
|
-
readonly error: unknown;
|
|
5
|
-
readonly isLoading: boolean;
|
|
6
|
-
}
|
|
7
|
-
export interface LoadingOptions {
|
|
8
|
-
readonly debounceMs?: number;
|
|
9
|
-
}
|
|
10
|
-
/** Use a reference (reactive state) bound to an async loader function. */
|
|
11
|
-
export declare function useLoading<const TDeps extends readonly ReadonlyRef<any>[], TValue>(deps: TDeps, callback: (signal: AbortSignal, ...values: RefValues<TDeps>) => Promise<TValue>, { debounceMs }?: LoadingOptions): Ref<LoadingValue<TValue>>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loading.js","names":[],"sources":["../../src/hooks/loading.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { type ReadonlyRef, type Ref, type RefValues, useRef } from './ref.ts';\n\nexport interface LoadingValue<TValue> {\n readonly value: TValue | undefined;\n readonly error: unknown;\n readonly isLoading: boolean;\n}\n\nexport interface LoadingOptions {\n readonly debounceMs?: number;\n}\n\n/** Use a reference (reactive state) bound to an async loader function. */\nexport function useLoading<const TDeps extends readonly ReadonlyRef<any>[], TValue>(\n deps: TDeps,\n callback: (signal: AbortSignal, ...values: RefValues<TDeps>) => Promise<TValue>,\n { debounceMs }: LoadingOptions = {},\n): Ref<LoadingValue<TValue>> {\n const ref = useRef<LoadingValue<TValue>>({ value: undefined, error: undefined, isLoading: true });\n let skipDebounce = true;\n\n useEffect(deps, () => (...values) => {\n const ac = new AbortController();\n\n Promise.race(\n skipDebounce\n ? [Promise.resolve()]\n : [\n new Promise((resolve) => setTimeout(resolve, debounceMs)),\n new Promise((resolve) => ac.signal.addEventListener('abort', resolve, { once: true })),\n ],\n )\n .then(() => {\n if (ac.signal.aborted) return;\n return callback(ac.signal, ...(values as any));\n })\n .then((value) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value, error: undefined };\n })\n .catch((error: unknown) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value: undefined, error };\n });\n\n skipDebounce = false;\n return () => ac.abort();\n });\n\n // Skip the debounce again if the component unmounts.\n useEffect([], () => () => (skipDebounce = true));\n\n return ref;\n}\n"],"mappings":";;;AAcA,SAAgB,EACd,GACA,GACA,EAAE,kBAA+B,EAAE,EACR;CAC3B,IAAM,IAAM,EAA6B;EAAE,OAAO,KAAA;EAAW,OAAO,KAAA;EAAW,WAAW;EAAM,CAAC,EAC7F,IAAe;AAiCnB,QA/BA,EAAU,UAAa,GAAG,MAAW;EACnC,IAAM,IAAK,IAAI,iBAAiB;AAwBhC,SAtBA,QAAQ,KACN,IACI,CAAC,QAAQ,SAAS,CAAC,GACnB,CACE,IAAI,SAAS,MAAY,WAAW,GAAS,EAAW,CAAC,EACzD,IAAI,SAAS,MAAY,EAAG,OAAO,iBAAiB,SAAS,GAAS,EAAE,MAAM,IAAM,CAAC,CAAC,CACvF,CACN,CACE,WAAW;AACN,UAAG,OAAO,QACd,QAAO,EAAS,EAAG,QAAQ,GAAI,EAAe;IAC9C,CACD,MAAM,MAAU;AACX,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO;IAAO,OAAO,KAAA;IAAW;IACzD,CACD,OAAO,MAAmB;AACrB,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO,OAAO,KAAA;IAAW;IAAO;IACzD,EAEJ,IAAe,UACF,EAAG,OAAO;GACvB,EAGF,EAAU,EAAE,cAAe,IAAe,GAAM,EAEzC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type Callbacks } from './callbacks.ts';
|
|
2
|
-
export interface Context {
|
|
3
|
-
readonly host: HTMLElement;
|
|
4
|
-
readonly onNotify: Callbacks;
|
|
5
|
-
readonly onDisconnect: Callbacks;
|
|
6
|
-
readonly notify: () => void;
|
|
7
|
-
}
|
|
8
|
-
export interface ContextController {
|
|
9
|
-
readonly connect: (callback: () => void) => void;
|
|
10
|
-
readonly disconnect: () => void;
|
|
11
|
-
}
|
|
12
|
-
export declare const contextStack: Context[];
|
|
13
|
-
export declare function createContextController(host: HTMLElement): ContextController;
|
package/dist/internal/context.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createCallbacks as e } from "./callbacks.js";
|
|
2
|
-
//#region src/internal/context.ts
|
|
3
|
-
var t = [];
|
|
4
|
-
function n(n) {
|
|
5
|
-
let r = !1, i = {
|
|
6
|
-
host: n,
|
|
7
|
-
onNotify: e(),
|
|
8
|
-
onDisconnect: e(),
|
|
9
|
-
notify: () => {
|
|
10
|
-
r || (r = !0, queueMicrotask(() => {
|
|
11
|
-
r = !1, i.onNotify.run();
|
|
12
|
-
}));
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
return {
|
|
16
|
-
connect: (e) => {
|
|
17
|
-
try {
|
|
18
|
-
t.push(i), e();
|
|
19
|
-
} finally {
|
|
20
|
-
t.pop();
|
|
21
|
-
}
|
|
22
|
-
i.onNotify.run();
|
|
23
|
-
},
|
|
24
|
-
disconnect: () => {
|
|
25
|
-
i.onNotify.clear(), i.onDisconnect.runAndClear();
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { t as contextStack, n as createContextController };
|
|
31
|
-
|
|
32
|
-
//# sourceMappingURL=context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../src/internal/context.ts"],"sourcesContent":["import { type Callbacks, createCallbacks } from './callbacks.ts';\n\nexport interface Context {\n readonly host: HTMLElement;\n readonly onNotify: Callbacks;\n readonly onDisconnect: Callbacks;\n readonly notify: () => void;\n}\n\nexport interface ContextController {\n readonly connect: (callback: () => void) => void;\n readonly disconnect: () => void;\n}\n\nexport const contextStack: Context[] = [];\n\nexport function createContextController(host: HTMLElement): ContextController {\n let notifying = false;\n\n const context: Context = {\n host,\n onNotify: createCallbacks(),\n onDisconnect: createCallbacks(),\n notify: () => {\n if (notifying) return;\n notifying = true;\n\n queueMicrotask(() => {\n notifying = false;\n context.onNotify.run();\n });\n },\n };\n\n return {\n connect: (callback) => {\n try {\n contextStack.push(context);\n callback();\n } finally {\n contextStack.pop();\n }\n\n context.onNotify.run();\n },\n disconnect: () => {\n context.onNotify.clear();\n context.onDisconnect.runAndClear();\n },\n };\n}\n"],"mappings":";;AAcA,IAAa,IAA0B,EAAE;AAEzC,SAAgB,EAAwB,GAAsC;CAC5E,IAAI,IAAY,IAEV,IAAmB;EACvB;EACA,UAAU,GAAiB;EAC3B,cAAc,GAAiB;EAC/B,cAAc;AACR,SACJ,IAAY,IAEZ,qBAAqB;AAEnB,IADA,IAAY,IACZ,EAAQ,SAAS,KAAK;KACtB;;EAEL;AAED,QAAO;EACL,UAAU,MAAa;AACrB,OAAI;AAEF,IADA,EAAa,KAAK,EAAQ,EAC1B,GAAU;aACF;AACR,MAAa,KAAK;;AAGpB,KAAQ,SAAS,KAAK;;EAExB,kBAAkB;AAEhB,GADA,EAAQ,SAAS,OAAO,EACxB,EAAQ,aAAa,aAAa;;EAErC"}
|
|
File without changes
|