@usenagi/core 0.1.0 → 0.2.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.ja.md +248 -0
- package/README.md +75 -69
- package/dist/main.es.js +2 -7
- package/dist/main.umd.js +1 -1
- package/package.json +1 -1
- package/types/core/reactivity.d.ts +9 -9
- package/types/hooks/useMediaQuery.d.ts +1 -1
- package/types/main.d.ts +2 -3
- package/types/hooks/useRootRef.d.ts +0 -2
package/README.ja.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
[English](./README.md) | **日本語**
|
|
2
|
+
|
|
3
|
+
# nagi
|
|
4
|
+
|
|
5
|
+
**Composition-style ergonomics for vanilla DOM. Bring your own mounter.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@usenagi/core)
|
|
8
|
+
[](https://bundlephobia.com/package/@usenagi/core)
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Why nagi?
|
|
14
|
+
|
|
15
|
+
**既存 HTML に小さく足せる**
|
|
16
|
+
|
|
17
|
+
WordPress、CMS、Webflow、静的サイトなどに、仮想 DOM やテンプレートを持ち込まず、`setup()` / lifecycle / reactivity を追加できる。
|
|
18
|
+
|
|
19
|
+
**アニメーションと相性が良い**
|
|
20
|
+
|
|
21
|
+
GSAP、Lenis、IntersectionObserver などを `setup()` で初期化し、`useUnmount()` でクリーンアップできる。
|
|
22
|
+
|
|
23
|
+
**マウント戦略を縛らない**
|
|
24
|
+
|
|
25
|
+
`[data-component]` スキャン、manifest、lazy import、MutationObserver などは、利用側で自由に組み立てられる。
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 30-second example
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// counter.ts
|
|
33
|
+
import { create, signal, useWatch, useDomRef } from "@usenagi/core";
|
|
34
|
+
|
|
35
|
+
const { component } = create();
|
|
36
|
+
|
|
37
|
+
component({
|
|
38
|
+
name: "counter",
|
|
39
|
+
setup() {
|
|
40
|
+
const { refs } = useDomRef<{
|
|
41
|
+
count: HTMLSpanElement;
|
|
42
|
+
btn: HTMLButtonElement;
|
|
43
|
+
}>();
|
|
44
|
+
|
|
45
|
+
const n = signal(0);
|
|
46
|
+
useWatch(n, (v) => {
|
|
47
|
+
refs.count.textContent = String(v);
|
|
48
|
+
});
|
|
49
|
+
refs.btn.addEventListener("click", () => {
|
|
50
|
+
n.value++;
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
})(document.querySelector("#counter")!);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<div id="counter">
|
|
58
|
+
<span data-ref="count">0</span>
|
|
59
|
+
<button data-ref="btn">+</button>
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Quick start
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm i @usenagi/core
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### First component
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { create, defineComponent, signal, useWatch, useDomRef } from "@usenagi/core";
|
|
75
|
+
|
|
76
|
+
const Greeting = defineComponent({
|
|
77
|
+
name: "greeting",
|
|
78
|
+
setup(el, props) {
|
|
79
|
+
const { refs } = useDomRef<{ message: HTMLParagraphElement }>();
|
|
80
|
+
const text = signal((props.name as string) ?? "world");
|
|
81
|
+
|
|
82
|
+
useWatch(text, (v) => {
|
|
83
|
+
refs.message.textContent = `Hello, ${v}!`;
|
|
84
|
+
});
|
|
85
|
+
refs.message.textContent = `Hello, ${text.value}!`;
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
create().component(Greeting)(document.querySelector("#app")!);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Scheduler + deferred mount
|
|
93
|
+
|
|
94
|
+
遅延マウントが必要な場合は、scheduler / cue addons を追加する。
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { create } from "@usenagi/core";
|
|
98
|
+
import { createScheduler } from "@usenagi/core/addons/scheduler";
|
|
99
|
+
import { visible, idle } from "@usenagi/core/addons/cue";
|
|
100
|
+
|
|
101
|
+
const app = create({ scheduler: createScheduler() });
|
|
102
|
+
|
|
103
|
+
// mount when the element enters the viewport
|
|
104
|
+
app.component(HeavyWidget, { when: visible() })(el);
|
|
105
|
+
|
|
106
|
+
// mount during browser idle time
|
|
107
|
+
app.component(Analytics, { when: idle() })(el);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`when` は `setup()` の前に待機する条件、`priority` は `setup()` を含む mount task の実行タイミングを決める。
|
|
111
|
+
|
|
112
|
+
### BYO mounter recipe
|
|
113
|
+
|
|
114
|
+
`[data-component]` スキャン、manifest、cue を組み合わせた自動マウントの例。
|
|
115
|
+
→ [examples/recipes/byo-mounter](./examples/recipes/byo-mounter/main.ts)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## API
|
|
120
|
+
|
|
121
|
+
### Reactivity
|
|
122
|
+
|
|
123
|
+
| API | 説明 |
|
|
124
|
+
| ---------------------- | -------------------------------------------------------------------- |
|
|
125
|
+
| `signal(value)` | `.value` を持つリアクティブな値コンテナを作成する |
|
|
126
|
+
| `readonly(signal)` | 書き込み可能な `signal` の読み取り専用ラッパー |
|
|
127
|
+
| `useComputed(fn)` | `signal` の依存を自動追跡する派生値 |
|
|
128
|
+
| `useWatch(target, cb)` | 値変更時に `cb` を呼ぶ。unmount 時に自動で購読解除する |
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const width = signal(10);
|
|
132
|
+
const height = signal(5);
|
|
133
|
+
const area = useComputed(() => width.value * height.value); // auto-recomputed
|
|
134
|
+
|
|
135
|
+
useWatch(area, (v) => {
|
|
136
|
+
output.textContent = String(v);
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Lifecycle
|
|
141
|
+
|
|
142
|
+
| API | 説明 |
|
|
143
|
+
| ---------------- | ------------------------------------------------------ |
|
|
144
|
+
| `useMount(fn)` | コンポーネントのマウント完了後に1回実行する |
|
|
145
|
+
| `useUnmount(fn)` | unmount 時に実行する。クリーンアップに使う |
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import gsap from 'gsap';
|
|
149
|
+
|
|
150
|
+
setup(el) {
|
|
151
|
+
const tween = gsap.from(el, { opacity: 0, duration: 0.4 });
|
|
152
|
+
useUnmount(() => tween.kill());
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### DOM helpers
|
|
157
|
+
|
|
158
|
+
ルート要素には **`setup(el)`** を、**`[data-ref]`** の子要素には **`useDomRef()`** を使う。
|
|
159
|
+
|
|
160
|
+
| API | 説明 |
|
|
161
|
+
| ------------------------------ | ---------------------------------------------------------- |
|
|
162
|
+
| `useDomRef<T>()` | `[data-ref]` 要素への型付きアクセス |
|
|
163
|
+
| `useEvent(el, event, handler)` | イベントリスナーを追加する。unmount 時に自動で除去する |
|
|
164
|
+
| `useSlot()` | 子コンポーネントをマウントする。親の unmount に連動する |
|
|
165
|
+
|
|
166
|
+
### Parent / child
|
|
167
|
+
|
|
168
|
+
`useSlot()` で子コンポーネントをマウントできる。親から子へは `props` または `createContext` / `withContext` で値を渡せる。`addChild()` が返す child context から、子の `setup()` の返り値も参照できる。
|
|
169
|
+
|
|
170
|
+
→ [examples/parent-child](./examples/parent-child/main.ts)
|
|
171
|
+
|
|
172
|
+
### Observers
|
|
173
|
+
|
|
174
|
+
| API | 説明 |
|
|
175
|
+
| --------------------------------- | ----------------------------------------------------------------- |
|
|
176
|
+
| `useIntersectionWatch(cb, opts?)` | IntersectionObserver のラッパー。unmount 時に自動で切断する |
|
|
177
|
+
| `useMediaQuery(query)` | `matchMedia` の結果を `ReadonlySignal<boolean>` で返す |
|
|
178
|
+
|
|
179
|
+
### Addons
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { createScheduler } from "@usenagi/core/addons/scheduler";
|
|
183
|
+
import { visible, idle, interaction, media } from "@usenagi/core/addons/cue";
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| API | 説明 |
|
|
187
|
+
| ------------------------ | ------------------------------------------------------------------------------------- |
|
|
188
|
+
| `createScheduler(opts?)` | `schedule(task, { priority, signal })` を実装した Scheduler を返す |
|
|
189
|
+
| `visible(opts?)` | 要素が viewport に入ったときに解決する Cue |
|
|
190
|
+
| `idle(timeout?)` | `requestIdleCallback` で解決する Cue |
|
|
191
|
+
| `interaction(events?)` | 最初のユーザー操作で解決する Cue |
|
|
192
|
+
| `media(query)` | media query が一致したときに解決する Cue |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Comparison
|
|
197
|
+
|
|
198
|
+
| | **nagi** | Alpine.js | Stimulus | petite-vue |
|
|
199
|
+
| ----------------------- | ----------- | --------- | -------- | ---------- |
|
|
200
|
+
| Inline JS in HTML | ✗ | ◯ | ✗ | ◯ |
|
|
201
|
+
| Composition-style setup | ◯ | △ | ✗ | ◯ |
|
|
202
|
+
| BYO mounter | ◯ | △ | △ | △ |
|
|
203
|
+
| Async mount cue | ◯ | ✗ | ✗ | ✗ |
|
|
204
|
+
| Lifecycle cleanup | ◯ | △ | ◯ | △ |
|
|
205
|
+
| `useComputed` (derived signals) | ◯ | ◯ | ✗ | ◯ |
|
|
206
|
+
| Core gzip | ~2.5 kB | ~16 kB | ~8 kB | ~6 kB |
|
|
207
|
+
|
|
208
|
+
(◯ = 組み込み、△ = 利用側の実装・規約で対応可能、✗ = 主な機能ではない)
|
|
209
|
+
|
|
210
|
+
- **vs Alpine / petite-vue**: HTML に式を直接書かず、ロジックを `.ts` に集約する。
|
|
211
|
+
- **vs Stimulus**: Controller 規約はない。マウント戦略は利用側で自由に組み立てられる。
|
|
212
|
+
- **vs React / Vue**: 宣言的 UI フレームワークではなく、既存 DOM に lifecycle を足す薄いレイヤー。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## When to use / When not to
|
|
217
|
+
|
|
218
|
+
**向いているケース:**
|
|
219
|
+
|
|
220
|
+
- React や Vue のランタイムを持ち込みにくいプロジェクト(CMS、Webflow、WordPress など)
|
|
221
|
+
- GSAP や Lenis を多用する、アニメーション主体のサイト
|
|
222
|
+
- ページの一部だけにインタラクティブな UI を追加したい場合
|
|
223
|
+
- `setup()`、lifecycle、reactivity による composition-style で書きたいが、仮想 DOM は不要な場合
|
|
224
|
+
|
|
225
|
+
**向いていないケース:**
|
|
226
|
+
|
|
227
|
+
- リスト描画や条件分岐を HTML テンプレートで書きたい場合(`v-for` や `v-if` 相当はない)
|
|
228
|
+
- 複雑なオブジェクトの深いリアクティビティが必要な場合(`reactive({})` は提供しない)
|
|
229
|
+
- SSR / hydration が必要な場合
|
|
230
|
+
- 状態管理、ルーティング、宣言的な view rendering をフレームワークにまとめて任せたい場合
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Examples
|
|
235
|
+
|
|
236
|
+
| Example | 説明 |
|
|
237
|
+
| ----------------------------------------------------- | ----------------------------------------------------------------- |
|
|
238
|
+
| [basic-counter](./examples/basic-counter/) | 最小の `signal` + `useWatch` 例 |
|
|
239
|
+
| [computed](./examples/computed/) | `useComputed` による派生値(width × height = area) |
|
|
240
|
+
| [parent-child](./examples/parent-child/) | `createContext` + `withContext` + `useSlot` |
|
|
241
|
+
| [lenis-scroll-scene](./examples/lenis-scroll-scene/) | Lenis + `useComputed` によるスクロール進捗連動 |
|
|
242
|
+
| [byo-mounter recipe](./examples/recipes/byo-mounter/) | `[data-component]` スキャン + manifest + cue |
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT © [hayakawasho](https://github.com/hayakawasho)
|
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
**English** | [日本語](./README.ja.md)
|
|
2
|
+
|
|
1
3
|
# nagi
|
|
2
4
|
|
|
3
5
|
**Composition-style ergonomics for vanilla DOM. Bring your own mounter.**
|
|
@@ -10,14 +12,17 @@
|
|
|
10
12
|
|
|
11
13
|
## Why nagi?
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
**Can be added in small parts to existing HTML**
|
|
16
|
+
|
|
17
|
+
You can add `setup()`, lifecycle, and reactivity to WordPress, CMS, Webflow, static sites, etc., without introducing a virtual DOM or templates.
|
|
18
|
+
|
|
19
|
+
**Compatible with animation**
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
GSAP、Lenis、IntersectionObserver などを `setup()` で初期化し、`useUnmount()` でクリーンアップできる。
|
|
21
|
+
You can initialize GSAP, Lenis, IntersectionObserver, etc., in `setup()` and clean them up with `useUnmount()`.
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
**Does not restrict mounting strategies**
|
|
24
|
+
|
|
25
|
+
You are free to implement `[data-component]` scanning, manifests, lazy imports, MutationObserver, and so on, on the consuming side.
|
|
21
26
|
|
|
22
27
|
---
|
|
23
28
|
|
|
@@ -25,7 +30,7 @@ GSAP、Lenis、IntersectionObserver などを `setup()` で初期化し、`useUn
|
|
|
25
30
|
|
|
26
31
|
```ts
|
|
27
32
|
// counter.ts
|
|
28
|
-
import { create,
|
|
33
|
+
import { create, signal, useWatch, useDomRef } from "@usenagi/core";
|
|
29
34
|
|
|
30
35
|
const { component } = create();
|
|
31
36
|
|
|
@@ -37,7 +42,7 @@ component({
|
|
|
37
42
|
btn: HTMLButtonElement;
|
|
38
43
|
}>();
|
|
39
44
|
|
|
40
|
-
const n =
|
|
45
|
+
const n = signal(0);
|
|
41
46
|
useWatch(n, (v) => {
|
|
42
47
|
refs.count.textContent = String(v);
|
|
43
48
|
});
|
|
@@ -66,13 +71,13 @@ npm i @usenagi/core
|
|
|
66
71
|
### First component
|
|
67
72
|
|
|
68
73
|
```ts
|
|
69
|
-
import { create, defineComponent,
|
|
74
|
+
import { create, defineComponent, signal, useWatch, useDomRef } from "@usenagi/core";
|
|
70
75
|
|
|
71
76
|
const Greeting = defineComponent({
|
|
72
77
|
name: "greeting",
|
|
73
78
|
setup(el, props) {
|
|
74
79
|
const { refs } = useDomRef<{ message: HTMLParagraphElement }>();
|
|
75
|
-
const text =
|
|
80
|
+
const text = signal((props.name as string) ?? "world");
|
|
76
81
|
|
|
77
82
|
useWatch(text, (v) => {
|
|
78
83
|
refs.message.textContent = `Hello, ${v}!`;
|
|
@@ -86,7 +91,7 @@ create().component(Greeting)(document.querySelector("#app")!);
|
|
|
86
91
|
|
|
87
92
|
### Scheduler + deferred mount
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
If delayed mounting is required, add the scheduler / cue addons.
|
|
90
95
|
|
|
91
96
|
```ts
|
|
92
97
|
import { create } from "@usenagi/core";
|
|
@@ -95,18 +100,18 @@ import { visible, idle } from "@usenagi/core/addons/cue";
|
|
|
95
100
|
|
|
96
101
|
const app = create({ scheduler: createScheduler() });
|
|
97
102
|
|
|
98
|
-
//
|
|
103
|
+
// mount when the element enters the viewport
|
|
99
104
|
app.component(HeavyWidget, { when: visible() })(el);
|
|
100
105
|
|
|
101
|
-
//
|
|
106
|
+
// mount during browser idle time
|
|
102
107
|
app.component(Analytics, { when: idle() })(el);
|
|
103
108
|
```
|
|
104
109
|
|
|
105
|
-
`when`
|
|
110
|
+
`when` is a condition to wait for before `setup()`, and `priority` determines the execution timing of the mount task that includes `setup()`.
|
|
106
111
|
|
|
107
112
|
### BYO mounter recipe
|
|
108
113
|
|
|
109
|
-
`[data-component]`
|
|
114
|
+
An example of automatic mounting by combining `[data-component]` scanning, manifests, and cues.
|
|
110
115
|
→ [examples/recipes/byo-mounter](./examples/recipes/byo-mounter/main.ts)
|
|
111
116
|
|
|
112
117
|
---
|
|
@@ -115,17 +120,17 @@ app.component(Analytics, { when: idle() })(el);
|
|
|
115
120
|
|
|
116
121
|
### Reactivity
|
|
117
122
|
|
|
118
|
-
| API
|
|
119
|
-
|
|
|
120
|
-
| `
|
|
121
|
-
| `readonly(
|
|
122
|
-
| `
|
|
123
|
-
| `useWatch(
|
|
123
|
+
| API | Description |
|
|
124
|
+
| ---------------------- | -------------------------------------------------------------- |
|
|
125
|
+
| `signal(value)` | Creates a reactive value container (`.value`) |
|
|
126
|
+
| `readonly(signal)` | Read-only wrapper around a writable `signal` |
|
|
127
|
+
| `useComputed(fn)` | Derived value that auto-tracks `signal` dependencies |
|
|
128
|
+
| `useWatch(target, cb)` | Calls `cb` on value change; automatically unsubscribes on unmount |
|
|
124
129
|
|
|
125
130
|
```ts
|
|
126
|
-
const width =
|
|
127
|
-
const height =
|
|
128
|
-
const area =
|
|
131
|
+
const width = signal(10);
|
|
132
|
+
const height = signal(5);
|
|
133
|
+
const area = useComputed(() => width.value * height.value); // auto-recomputed
|
|
129
134
|
|
|
130
135
|
useWatch(area, (v) => {
|
|
131
136
|
output.textContent = String(v);
|
|
@@ -134,10 +139,10 @@ useWatch(area, (v) => {
|
|
|
134
139
|
|
|
135
140
|
### Lifecycle
|
|
136
141
|
|
|
137
|
-
| API |
|
|
138
|
-
| ---------------- |
|
|
139
|
-
| `useMount(fn)` |
|
|
140
|
-
| `useUnmount(fn)` |
|
|
142
|
+
| API | Description |
|
|
143
|
+
| ---------------- | ----------------------------------------- |
|
|
144
|
+
| `useMount(fn)` | Runs once after the component mounts |
|
|
145
|
+
| `useUnmount(fn)` | Runs on unmount; use for cleanup |
|
|
141
146
|
|
|
142
147
|
```ts
|
|
143
148
|
import gsap from 'gsap';
|
|
@@ -150,25 +155,26 @@ setup(el) {
|
|
|
150
155
|
|
|
151
156
|
### DOM helpers
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
158
|
+
Use **`setup(el)`** for the root element and **`useDomRef()`** for `[data-ref]` descendants.
|
|
159
|
+
|
|
160
|
+
| API | Description |
|
|
161
|
+
| ------------------------------ | ------------------------------------------------------------ |
|
|
162
|
+
| `useDomRef<T>()` | Typed access to `[data-ref]` elements |
|
|
163
|
+
| `useEvent(el, event, handler)` | Adds an event listener; automatically removed on unmount |
|
|
164
|
+
| `useSlot()` | Mounts child components; tied to the parent's unmount |
|
|
159
165
|
|
|
160
166
|
### Parent / child
|
|
161
167
|
|
|
162
|
-
`useSlot()
|
|
168
|
+
You can mount child components with `useSlot()`. You can pass values from parent to child via `props` or `createContext` / `withContext`. From the child context returned by `addChild()`, you can also reference the return value of the child's `setup()`.
|
|
163
169
|
|
|
164
170
|
→ [examples/parent-child](./examples/parent-child/main.ts)
|
|
165
171
|
|
|
166
172
|
### Observers
|
|
167
173
|
|
|
168
|
-
| API |
|
|
169
|
-
| --------------------------------- |
|
|
170
|
-
| `useIntersectionWatch(cb, opts?)` | IntersectionObserver
|
|
171
|
-
| `useMediaQuery(query)` | `matchMedia`
|
|
174
|
+
| API | Description |
|
|
175
|
+
| --------------------------------- | ------------------------------------------------------------------- |
|
|
176
|
+
| `useIntersectionWatch(cb, opts?)` | IntersectionObserver wrapper; automatically disconnected on unmount |
|
|
177
|
+
| `useMediaQuery(query)` | Returns `matchMedia` result as a `ReadonlySignal<boolean>` |
|
|
172
178
|
|
|
173
179
|
### Addons
|
|
174
180
|
|
|
@@ -177,13 +183,13 @@ import { createScheduler } from "@usenagi/core/addons/scheduler";
|
|
|
177
183
|
import { visible, idle, interaction, media } from "@usenagi/core/addons/cue";
|
|
178
184
|
```
|
|
179
185
|
|
|
180
|
-
| API |
|
|
181
|
-
| ------------------------ |
|
|
182
|
-
| `createScheduler(opts?)` | `
|
|
183
|
-
| `visible(opts?)` |
|
|
184
|
-
| `idle(timeout?)` | `requestIdleCallback`
|
|
185
|
-
| `interaction(events?)` |
|
|
186
|
-
| `media(query)` | media query
|
|
186
|
+
| API | Description |
|
|
187
|
+
| ------------------------ | --------------------------------------------------------------------- |
|
|
188
|
+
| `createScheduler(opts?)` | Returns a Scheduler implementing `schedule(task, { priority, signal })` |
|
|
189
|
+
| `visible(opts?)` | A Cue that resolves when the element enters the viewport |
|
|
190
|
+
| `idle(timeout?)` | A Cue that resolves via `requestIdleCallback` |
|
|
191
|
+
| `interaction(events?)` | A Cue that resolves on the first user interaction |
|
|
192
|
+
| `media(query)` | A Cue that resolves when the media query matches |
|
|
187
193
|
|
|
188
194
|
---
|
|
189
195
|
|
|
@@ -196,44 +202,44 @@ import { visible, idle, interaction, media } from "@usenagi/core/addons/cue";
|
|
|
196
202
|
| BYO mounter | ◯ | △ | △ | △ |
|
|
197
203
|
| Async mount cue | ◯ | ✗ | ✗ | ✗ |
|
|
198
204
|
| Lifecycle cleanup | ◯ | △ | ◯ | △ |
|
|
199
|
-
| `
|
|
200
|
-
| Core gzip | ~2.
|
|
205
|
+
| `useComputed` (derived signals) | ◯ | ◯ | ✗ | ◯ |
|
|
206
|
+
| Core gzip | ~2.5 kB | ~16 kB | ~8 kB | ~6 kB |
|
|
201
207
|
|
|
202
|
-
◯ = built-in
|
|
208
|
+
(◯ = built-in, △ = handled via userland/convention, ✗ = not a primary feature)
|
|
203
209
|
|
|
204
|
-
- **vs Alpine / petite-vue**: HTML
|
|
205
|
-
- **vs Stimulus**:
|
|
206
|
-
- **vs React / Vue**:
|
|
210
|
+
- **vs Alpine / petite-vue**: Instead of writing logic expressions directly in HTML, you centralize your logic in `.ts` files.
|
|
211
|
+
- **vs Stimulus**: No controller conventions; you are free to implement your own mounting strategy.
|
|
212
|
+
- **vs React / Vue**: It is not a declarative UI framework, but rather a thin layer that adds lifecycle hooks to existing DOM.
|
|
207
213
|
|
|
208
214
|
---
|
|
209
215
|
|
|
210
216
|
## When to use / When not to
|
|
211
217
|
|
|
212
|
-
|
|
218
|
+
**Recommended Use Cases:**
|
|
213
219
|
|
|
214
|
-
- React
|
|
215
|
-
- GSAP
|
|
216
|
-
-
|
|
217
|
-
-
|
|
220
|
+
- Projects where you cannot justify the runtime overhead of React or Vue (e.g., CMS, Webflow, WordPress).
|
|
221
|
+
- Animation-heavy sites that rely heavily on libraries like GSAP or Lenis.
|
|
222
|
+
- Scenarios where you only need to add interactive UI to specific parts of a page.
|
|
223
|
+
- When you want to use a composition-style approach with `setup()`, lifecycle hooks, and reactivity, but do not require a virtual DOM.
|
|
218
224
|
|
|
219
|
-
|
|
225
|
+
**Not Recommended For:**
|
|
220
226
|
|
|
221
|
-
-
|
|
222
|
-
-
|
|
223
|
-
- SSR/hydration
|
|
224
|
-
-
|
|
227
|
+
- When you want to handle list rendering or conditional logic via HTML templates (it does not support equivalents to `v-for` or `v-if`).
|
|
228
|
+
- When you need deep reactivity for complex objects (it does not provide `reactive({})`).
|
|
229
|
+
- When SSR/hydration is required.
|
|
230
|
+
- When you want a full-featured framework to handle global state management, routing, and declarative view rendering.
|
|
225
231
|
|
|
226
232
|
---
|
|
227
233
|
|
|
228
234
|
## Examples
|
|
229
235
|
|
|
230
|
-
| Example |
|
|
231
|
-
| ----------------------------------------------------- |
|
|
232
|
-
| [basic-counter](./examples/basic-counter/) | `
|
|
233
|
-
| [computed](./examples/computed/)
|
|
234
|
-
| [parent-child](./examples/parent-child/) | `createContext` + `withContext` + `useSlot`
|
|
235
|
-
| [lenis-scroll-scene](./examples/lenis-scroll-scene/) | Lenis + `
|
|
236
|
-
| [byo-mounter recipe](./examples/recipes/byo-mounter/) | `[data-component]`
|
|
236
|
+
| Example | Description |
|
|
237
|
+
| ----------------------------------------------------- | ------------------------------------------------------ |
|
|
238
|
+
| [basic-counter](./examples/basic-counter/) | Minimal `signal` + `useWatch` example |
|
|
239
|
+
| [computed](./examples/computed/) | Derived value with `useComputed` (width × height = area) |
|
|
240
|
+
| [parent-child](./examples/parent-child/) | `createContext` + `withContext` + `useSlot` |
|
|
241
|
+
| [lenis-scroll-scene](./examples/lenis-scroll-scene/) | Scroll-progress animation with Lenis + `useComputed` |
|
|
242
|
+
| [byo-mounter recipe](./examples/recipes/byo-mounter/) | `[data-component]` scanning + manifest + cue |
|
|
237
243
|
|
|
238
244
|
---
|
|
239
245
|
|
package/dist/main.es.js
CHANGED
|
@@ -346,13 +346,8 @@ function F(e, t) {
|
|
|
346
346
|
})), { matchesQuery: C(r) };
|
|
347
347
|
}
|
|
348
348
|
//#endregion
|
|
349
|
-
//#region lib/hooks/useRootRef.ts
|
|
350
|
-
function I() {
|
|
351
|
-
return f("useRootRef").element;
|
|
352
|
-
}
|
|
353
|
-
//#endregion
|
|
354
349
|
//#region lib/hooks/useSlot.ts
|
|
355
|
-
function
|
|
350
|
+
function I() {
|
|
356
351
|
let e = f("useSlot");
|
|
357
352
|
return {
|
|
358
353
|
addChild(t, n, r = {}) {
|
|
@@ -374,4 +369,4 @@ function L() {
|
|
|
374
369
|
};
|
|
375
370
|
}
|
|
376
371
|
//#endregion
|
|
377
|
-
export { r as LifecycleError,
|
|
372
|
+
export { r as LifecycleError, m as create, D as createContext, u as defineComponent, i as isLifecycleError, C as readonly, x as signal, E as useComputed, M as useDomRef, N as useEvent, P as useIntersectionWatch, F as useMediaQuery, g as useMount, I as useSlot, _ as useUnmount, T as useWatch, O as withContext };
|
package/dist/main.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.Lake={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){return(e instanceof DOMException||e instanceof Error)&&e.name===`AbortError`}function n(){let e=new Map;return{add(t){let n=e.get(t);n&&n.abort();let r=new AbortController;return e.set(t,r),{signal:r.signal,complete(){return e.get(t)!==r||r.signal.aborted?!1:(e.delete(t),!0)},abort(){e.get(t)===r&&(r.abort(),e.delete(t))}}},abort(t){let n=e.get(t);n&&(n.abort(),e.delete(t))}}}function r(e){let t=[],n=e;for(;n;)t.unshift(n.name),n=n.parent;return t.join(` > `)}var i=class e extends Error{details;constructor(e){super(`[nagi] Component error in phase "${e.phase}" for "${e.name}"${e.path?` (${e.path})`:``}`,{cause:e.cause}),this.name=`LifecycleError`,this.details=e}static create(t,n,i,a=n.parent,o){return new e({phase:t,name:n.name,uid:n.uid,path:r(n),parentName:a?.name,parentUid:a?.uid,element:n.element,cause:i,...o})}};function a(e){return e instanceof i}var o=new WeakMap;function s(e,t){let n=o.get(e);if(n)throw i.create(`mount`,t,Error(`Component "${n.name}" (${n.uid}) is already mounted on this element`),n);o.set(e,t)}var c=function(e){return e.MOUNTED=`Mounted`,e.UNMOUNTED=`Unmounted`,e}({}),l=0,u=class{Mounted=[];Unmounted=[];parent=null;#e=[];uid;name;current={};props={};element;provides=new Map;constructor(e,t){this.uid=`${t}.${l++}`,this.name=t,this.element=e}onMount=()=>{let e=[];for(let t of this.Mounted)try{let n=t();typeof n==`function`&&e.push(n)}catch(e){console.error(`[nagi] onMount hook failed`,i.create(`mount`,this,e))}this.Unmounted.push(...e)};onUnmount=()=>{for(let e of this.Unmounted)try{e()}catch(e){console.error(`[nagi] onUnmount cleanup failed`,i.create(`unmount`,this,e))}for(let e of this.#e)e.onUnmount()};addChild=e=>{this.#e.push(e),e.parent=this;try{e.onMount()}catch(t){let n=this.#e.indexOf(e);throw n!==-1&&this.#e.splice(n,1),e.parent=null,t}};removeChild=e=>{let t=this.#e.indexOf(e);t!==-1&&(this.#e.splice(t,1),e.parent=null,e.onUnmount())};get childElements(){return this.#e.map(e=>e.element)}};function d(e){return e===void 0?e=>t=>({name:e.name,setup(n){return e.setup(n,t)}}):e}var f;function p(e){if(!f)throw Error(`"${e}" called outside setup() will never be run.`);return f}function m(e,t,n){let r=new u(t,e.name),o=f;f=r;try{o&&(r.parent=o),r.props=n,r.current=e.setup(t,n)||{}}catch(e){throw f=o,a(e)?e:i.create(`setup`,r,e,o,{props:r.props})}return f=o,r}function h(e={}){let{scheduler:r}=e,i=n();return{component(e,{priority:n,when:a}={}){return(o,c={})=>{function l(){let t=m(e,o,c);return s(o,t),t.onMount(),t}if(!r)return l();let u=i.add(o),d=()=>{r.schedule(()=>{u.complete()&&l()},{priority:n,signal:u.signal})};a?a(o,u.signal).then(()=>{u.signal.aborted||d()},e=>{t(e)||(u.abort(),queueMicrotask(()=>{throw e}))}):d()}},unmount(e){for(let t of e){i.abort(t);let e=o.get(t);e&&(e.onUnmount(),o.delete(t))}}}}function g(e){return t=>{p(e)[e].push(t)}}var _=g(c.MOUNTED),v=g(c.UNMOUNTED),y=Symbol(`watch`),b=null,x=class{#e;#t=new Set;constructor(e){this.#e=e}get value(){return b!==null&&b.add(this),this.#e}set value(e){if(Object.is(e,this.#e))return;let t=this.#e;this.#e=e;for(let n of Array.from(this.#t))n(e,t)}[y](e){return this.#t.add(e),()=>{this.#t.delete(e)}}},S=e=>new x(e),C=class{#e;constructor(e){this.#e=e}get value(){return this.#e.value}[y](e){return this.#e[y](e)}},w=e=>new C(e);function T(e,t){return e[y](t)}function E(e,t){v(T(e,t))}function D(e){let t=S(void 0),n=[],r=()=>{n.forEach(e=>{e()}),n=[]},i=()=>{r();let a=b,o=new Set;b=o;let s;try{s=e()}finally{b=a}t.value=s;for(let e of o)n.push(e[y](()=>{i()}))};return i(),v(r),w(t)}function O(){let e=Symbol();return[{_id:e},()=>{let t=p(`createContext.use`);for(;t!==null;){if(t.provides.has(e))return t.provides.get(e);t=t.parent}throw Error(`createContext.use: no provider found`)}]}function k(e,t){return n=>({name:n.name,setup(r,i){return p(`withContext.${n.name}`).provides.set(e._id,t),n.setup(r,i)}})}function A(e,t){return t.some(t=>t!==e&&t.contains(e))}function j(e,t,n){let r=`[data-ref="${CSS.escape(e)}"]`,i=Array.from(t.querySelectorAll(r)).filter(e=>!A(e,n));return i.length===0?null:i.length===1?i[0]:i}function M(e,t){let n=new Map;return new Proxy({},{get(r,i){if(typeof i==`symbol`||i===`then`)return;if(n.has(i))return n.get(i);let a=j(i,e,t());return n.set(i,a),a},has(e,t){return typeof t==`string`},ownKeys(){return[]},getOwnPropertyDescriptor(){},set(){return!1},deleteProperty(){return!1}})}function N(){let e=p(`useDomRef`);return{refs:M(e.element,()=>e.childElements)}}function P(e,t,n,r){_(()=>(e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}))}function F(e,t,n={rootMargin:`0px`,threshold:.1}){let r=new IntersectionObserver(t,n);function i(e){Array.isArray(e)?e.forEach(e=>{r.observe(e)}):r.observe(e)}i(e),v(()=>{r.disconnect()});function a(e){r.unobserve(e)}return{unwatch:a}}function I(e,t){let n=window.matchMedia(e),r=S(n.matches),i=null;function a(e){r.value=e.matches,e.matches?i=t():(i?.(),i=null)}return _(()=>(n.addEventListener(`change`,a),n.matches&&(i=t()),()=>{i?.(),n.removeEventListener(`change`,a)})),{matchesQuery:w(r)}}function L(){
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.Lake={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){return(e instanceof DOMException||e instanceof Error)&&e.name===`AbortError`}function n(){let e=new Map;return{add(t){let n=e.get(t);n&&n.abort();let r=new AbortController;return e.set(t,r),{signal:r.signal,complete(){return e.get(t)!==r||r.signal.aborted?!1:(e.delete(t),!0)},abort(){e.get(t)===r&&(r.abort(),e.delete(t))}}},abort(t){let n=e.get(t);n&&(n.abort(),e.delete(t))}}}function r(e){let t=[],n=e;for(;n;)t.unshift(n.name),n=n.parent;return t.join(` > `)}var i=class e extends Error{details;constructor(e){super(`[nagi] Component error in phase "${e.phase}" for "${e.name}"${e.path?` (${e.path})`:``}`,{cause:e.cause}),this.name=`LifecycleError`,this.details=e}static create(t,n,i,a=n.parent,o){return new e({phase:t,name:n.name,uid:n.uid,path:r(n),parentName:a?.name,parentUid:a?.uid,element:n.element,cause:i,...o})}};function a(e){return e instanceof i}var o=new WeakMap;function s(e,t){let n=o.get(e);if(n)throw i.create(`mount`,t,Error(`Component "${n.name}" (${n.uid}) is already mounted on this element`),n);o.set(e,t)}var c=function(e){return e.MOUNTED=`Mounted`,e.UNMOUNTED=`Unmounted`,e}({}),l=0,u=class{Mounted=[];Unmounted=[];parent=null;#e=[];uid;name;current={};props={};element;provides=new Map;constructor(e,t){this.uid=`${t}.${l++}`,this.name=t,this.element=e}onMount=()=>{let e=[];for(let t of this.Mounted)try{let n=t();typeof n==`function`&&e.push(n)}catch(e){console.error(`[nagi] onMount hook failed`,i.create(`mount`,this,e))}this.Unmounted.push(...e)};onUnmount=()=>{for(let e of this.Unmounted)try{e()}catch(e){console.error(`[nagi] onUnmount cleanup failed`,i.create(`unmount`,this,e))}for(let e of this.#e)e.onUnmount()};addChild=e=>{this.#e.push(e),e.parent=this;try{e.onMount()}catch(t){let n=this.#e.indexOf(e);throw n!==-1&&this.#e.splice(n,1),e.parent=null,t}};removeChild=e=>{let t=this.#e.indexOf(e);t!==-1&&(this.#e.splice(t,1),e.parent=null,e.onUnmount())};get childElements(){return this.#e.map(e=>e.element)}};function d(e){return e===void 0?e=>t=>({name:e.name,setup(n){return e.setup(n,t)}}):e}var f;function p(e){if(!f)throw Error(`"${e}" called outside setup() will never be run.`);return f}function m(e,t,n){let r=new u(t,e.name),o=f;f=r;try{o&&(r.parent=o),r.props=n,r.current=e.setup(t,n)||{}}catch(e){throw f=o,a(e)?e:i.create(`setup`,r,e,o,{props:r.props})}return f=o,r}function h(e={}){let{scheduler:r}=e,i=n();return{component(e,{priority:n,when:a}={}){return(o,c={})=>{function l(){let t=m(e,o,c);return s(o,t),t.onMount(),t}if(!r)return l();let u=i.add(o),d=()=>{r.schedule(()=>{u.complete()&&l()},{priority:n,signal:u.signal})};a?a(o,u.signal).then(()=>{u.signal.aborted||d()},e=>{t(e)||(u.abort(),queueMicrotask(()=>{throw e}))}):d()}},unmount(e){for(let t of e){i.abort(t);let e=o.get(t);e&&(e.onUnmount(),o.delete(t))}}}}function g(e){return t=>{p(e)[e].push(t)}}var _=g(c.MOUNTED),v=g(c.UNMOUNTED),y=Symbol(`watch`),b=null,x=class{#e;#t=new Set;constructor(e){this.#e=e}get value(){return b!==null&&b.add(this),this.#e}set value(e){if(Object.is(e,this.#e))return;let t=this.#e;this.#e=e;for(let n of Array.from(this.#t))n(e,t)}[y](e){return this.#t.add(e),()=>{this.#t.delete(e)}}},S=e=>new x(e),C=class{#e;constructor(e){this.#e=e}get value(){return this.#e.value}[y](e){return this.#e[y](e)}},w=e=>new C(e);function T(e,t){return e[y](t)}function E(e,t){v(T(e,t))}function D(e){let t=S(void 0),n=[],r=()=>{n.forEach(e=>{e()}),n=[]},i=()=>{r();let a=b,o=new Set;b=o;let s;try{s=e()}finally{b=a}t.value=s;for(let e of o)n.push(e[y](()=>{i()}))};return i(),v(r),w(t)}function O(){let e=Symbol();return[{_id:e},()=>{let t=p(`createContext.use`);for(;t!==null;){if(t.provides.has(e))return t.provides.get(e);t=t.parent}throw Error(`createContext.use: no provider found`)}]}function k(e,t){return n=>({name:n.name,setup(r,i){return p(`withContext.${n.name}`).provides.set(e._id,t),n.setup(r,i)}})}function A(e,t){return t.some(t=>t!==e&&t.contains(e))}function j(e,t,n){let r=`[data-ref="${CSS.escape(e)}"]`,i=Array.from(t.querySelectorAll(r)).filter(e=>!A(e,n));return i.length===0?null:i.length===1?i[0]:i}function M(e,t){let n=new Map;return new Proxy({},{get(r,i){if(typeof i==`symbol`||i===`then`)return;if(n.has(i))return n.get(i);let a=j(i,e,t());return n.set(i,a),a},has(e,t){return typeof t==`string`},ownKeys(){return[]},getOwnPropertyDescriptor(){},set(){return!1},deleteProperty(){return!1}})}function N(){let e=p(`useDomRef`);return{refs:M(e.element,()=>e.childElements)}}function P(e,t,n,r){_(()=>(e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}))}function F(e,t,n={rootMargin:`0px`,threshold:.1}){let r=new IntersectionObserver(t,n);function i(e){Array.isArray(e)?e.forEach(e=>{r.observe(e)}):r.observe(e)}i(e),v(()=>{r.disconnect()});function a(e){r.unobserve(e)}return{unwatch:a}}function I(e,t){let n=window.matchMedia(e),r=S(n.matches),i=null;function a(e){r.value=e.matches,e.matches?i=t():(i?.(),i=null)}return _(()=>(n.addEventListener(`change`,a),n.matches&&(i=t()),()=>{i?.(),n.removeEventListener(`change`,a)})),{matchesQuery:w(r)}}function L(){let e=p(`useSlot`);return{addChild(t,n,r={}){let i=t=>{let i=m(n,t,r);return e.addChild(i),i};return Array.isArray(t)?t.map(e=>i(e)):[i(t)]},removeChild(t){t.forEach(t=>{try{e.removeChild(t)}catch(n){console.error(`[nagi] removeChild failed`,i.create(`removeChild`,t,n,e))}})}}}e.LifecycleError=i,e.create=h,e.createContext=O,e.defineComponent=d,e.isLifecycleError=a,e.readonly=w,e.signal=S,e.useComputed=D,e.useDomRef=N,e.useEvent=P,e.useIntersectionWatch=F,e.useMediaQuery=I,e.useMount=_,e.useSlot=L,e.useUnmount=v,e.useWatch=E,e.withContext=k});
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
type WatchCallback<T> = (newVal: T, oldVal: T) => void;
|
|
2
2
|
type Unwatch = () => void;
|
|
3
3
|
declare const WATCH: unique symbol;
|
|
4
|
-
declare class
|
|
4
|
+
declare class Signal<T> {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(value: T);
|
|
7
7
|
get value(): T;
|
|
8
8
|
set value(newVal: T);
|
|
9
9
|
[WATCH](callback: WatchCallback<T>): Unwatch;
|
|
10
10
|
}
|
|
11
|
-
declare const
|
|
12
|
-
declare class
|
|
11
|
+
declare const signal: <T = any>(val: T) => Signal<T>;
|
|
12
|
+
declare class ReadonlySignal<T> {
|
|
13
13
|
#private;
|
|
14
|
-
constructor(value:
|
|
14
|
+
constructor(value: Signal<T>);
|
|
15
15
|
get value(): T;
|
|
16
16
|
[WATCH](callback: WatchCallback<T>): Unwatch;
|
|
17
17
|
}
|
|
18
|
-
declare const readonly: <T = any>(
|
|
19
|
-
declare function useWatch<T>(
|
|
20
|
-
declare function
|
|
21
|
-
export {
|
|
22
|
-
export type {
|
|
18
|
+
declare const readonly: <T = any>(s: Signal<T>) => ReadonlySignal<T>;
|
|
19
|
+
declare function useWatch<T>(target: Signal<T> | ReadonlySignal<T>, callback: WatchCallback<T>): void;
|
|
20
|
+
declare function useComputed<T>(getter: () => T): ReadonlySignal<T>;
|
|
21
|
+
export { readonly, signal, useComputed, useWatch };
|
|
22
|
+
export type { ReadonlySignal, Signal };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Cleanup } from "../types";
|
|
2
2
|
export declare function useMediaQuery(query: string, callbackWhenMatches: () => Cleanup): {
|
|
3
|
-
readonly matchesQuery: import("../main").
|
|
3
|
+
readonly matchesQuery: import("../main").ReadonlySignal<boolean>;
|
|
4
4
|
};
|
package/types/main.d.ts
CHANGED
|
@@ -2,16 +2,15 @@ export { create } from "./core/app";
|
|
|
2
2
|
export { defineComponent } from "./core/component";
|
|
3
3
|
export { isLifecycleError, LifecycleError } from "./core/error";
|
|
4
4
|
export { useMount, useUnmount } from "./core/lifecycle";
|
|
5
|
-
export {
|
|
5
|
+
export { readonly, signal, useComputed, useWatch } from "./core/reactivity";
|
|
6
6
|
export { createContext, withContext } from "./hooks/createContext";
|
|
7
7
|
export { useDomRef } from "./hooks/useDomRef";
|
|
8
8
|
export { useEvent } from "./hooks/useEvent";
|
|
9
9
|
export { useIntersectionWatch } from "./hooks/useIntersectionWatch";
|
|
10
10
|
export { useMediaQuery } from "./hooks/useMediaQuery";
|
|
11
|
-
export { useRootRef } from "./hooks/useRootRef";
|
|
12
11
|
export { useSlot } from "./hooks/useSlot";
|
|
13
12
|
export type { ComponentContext } from "./core/component";
|
|
14
13
|
export type { LifecycleErrorDetails } from "./core/error";
|
|
15
|
-
export type {
|
|
14
|
+
export type { ReadonlySignal, Signal } from "./core/reactivity";
|
|
16
15
|
export type { Provider } from "./hooks/createContext";
|
|
17
16
|
export type { ComponentSetup, Cue, IComponent, RefElement, SchedulePriority, Scheduler, } from "./types";
|