@manyducks.co/dolla 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -284
- package/dist/context-B5blupD2.js +363 -0
- package/dist/context-B5blupD2.js.map +1 -0
- package/dist/core/context.d.ts +29 -144
- package/dist/core/debug.d.ts +19 -0
- package/dist/core/index.d.ts +15 -16
- package/dist/core/markup/helpers.d.ts +34 -0
- package/dist/core/markup/html.d.ts +3 -0
- package/dist/core/{nodes → markup/nodes}/dom.d.ts +5 -4
- package/dist/core/markup/nodes/dynamic.d.ts +16 -0
- package/dist/core/markup/nodes/element.d.ts +14 -0
- package/dist/core/markup/nodes/portal.d.ts +15 -0
- package/dist/core/markup/nodes/repeat.d.ts +21 -0
- package/dist/core/markup/nodes/view.d.ts +17 -0
- package/dist/core/markup/scheduler.d.ts +1 -0
- package/dist/core/markup/types.d.ts +62 -0
- package/dist/core/markup/utils.d.ts +22 -0
- package/dist/core/ref.d.ts +6 -12
- package/dist/core/root.d.ts +36 -0
- package/dist/core/signals.d.ts +46 -76
- package/dist/core/symbols.d.ts +2 -0
- package/dist/core-JHktdqjt.js +242 -0
- package/dist/core-JHktdqjt.js.map +1 -0
- package/dist/http/index.d.ts +21 -33
- package/dist/http.js +89 -149
- package/dist/http.js.map +1 -1
- package/dist/index.js +4 -174
- package/dist/jsx-dev-runtime.d.ts +4 -3
- package/dist/jsx-dev-runtime.js +12 -9
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +5 -4
- package/dist/jsx-runtime.js +17 -12
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/router/index.d.ts +4 -3
- package/dist/router/router.d.ts +19 -162
- package/dist/router/store.d.ts +12 -0
- package/dist/router/types.d.ts +152 -0
- package/dist/router/utils.d.ts +99 -0
- package/dist/router/utils.test.d.ts +1 -0
- package/dist/router.js +428 -5
- package/dist/router.js.map +1 -1
- package/dist/signals-CMJPGr_M.js +354 -0
- package/dist/signals-CMJPGr_M.js.map +1 -0
- package/dist/translate/index.d.ts +82 -0
- package/dist/translate.js +125 -0
- package/dist/translate.js.map +1 -0
- package/dist/types.d.ts +21 -39
- package/dist/utils.d.ts +41 -29
- package/dist/utils.test.d.ts +1 -0
- package/dist/virtual/index.d.ts +1 -0
- package/dist/virtual/list.d.ts +53 -0
- package/package.json +19 -16
- package/dist/core/app.d.ts +0 -24
- package/dist/core/env.d.ts +0 -3
- package/dist/core/hooks.d.ts +0 -70
- package/dist/core/logger.d.ts +0 -42
- package/dist/core/logger.test.d.ts +0 -0
- package/dist/core/markup.d.ts +0 -82
- package/dist/core/markup.test.d.ts +0 -0
- package/dist/core/nodes/_markup.d.ts +0 -36
- package/dist/core/nodes/dynamic.d.ts +0 -22
- package/dist/core/nodes/element.d.ts +0 -27
- package/dist/core/nodes/portal.d.ts +0 -18
- package/dist/core/nodes/repeat.d.ts +0 -27
- package/dist/core/nodes/view.d.ts +0 -25
- package/dist/core/views/default-crash-view.d.ts +0 -25
- package/dist/core/views/for.d.ts +0 -21
- package/dist/core/views/fragment.d.ts +0 -7
- package/dist/core/views/portal.d.ts +0 -16
- package/dist/core/views/show.d.ts +0 -25
- package/dist/fragment-BahD_BJA.js +0 -7
- package/dist/fragment-BahD_BJA.js.map +0 -1
- package/dist/i18n/index.d.ts +0 -134
- package/dist/i18n.js +0 -309
- package/dist/i18n.js.map +0 -1
- package/dist/index-DRJlxs-Q.js +0 -535
- package/dist/index-DRJlxs-Q.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger-Aqi9m1CF.js +0 -565
- package/dist/logger-Aqi9m1CF.js.map +0 -1
- package/dist/markup-8jNhoqDe.js +0 -1089
- package/dist/markup-8jNhoqDe.js.map +0 -1
- package/dist/router/hooks.d.ts +0 -2
- package/dist/router/router.utils.d.ts +0 -93
- package/dist/typeChecking-5kmX0ulW.js +0 -65
- package/dist/typeChecking-5kmX0ulW.js.map +0 -1
- package/dist/typeChecking.d.ts +0 -95
- package/docs/buildless.md +0 -132
- package/docs/components.md +0 -238
- package/docs/hooks.md +0 -356
- package/docs/http.md +0 -178
- package/docs/i18n.md +0 -220
- package/docs/index.md +0 -10
- package/docs/markup.md +0 -136
- package/docs/mixins.md +0 -176
- package/docs/ref.md +0 -77
- package/docs/router.md +0 -281
- package/docs/setup.md +0 -137
- package/docs/signals.md +0 -262
- package/docs/stores.md +0 -113
- package/docs/views.md +0 -356
- package/notes/atomic.md +0 -452
- package/notes/elimination.md +0 -33
- package/notes/observable.md +0 -180
- package/notes/scratch.md +0 -565
- package/notes/splitting.md +0 -5
- package/notes/views.md +0 -195
- package/vite.config.js +0 -22
- /package/dist/core/{hooks.test.d.ts → markup/html.test.d.ts} +0 -0
- /package/dist/core/{ref.test.d.ts → markup/utils.test.d.ts} +0 -0
- /package/dist/router/{router.utils.test.d.ts → matcher.test.d.ts} +0 -0
- /package/dist/{typeChecking.test.d.ts → router/router.test.d.ts} +0 -0
package/docs/components.md
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
# The Lowdown on Dolla Components
|
|
2
|
-
|
|
3
|
-
Aight, so in Dolla, your whole app is just a bunch of **components**. They're the lego bricks for your UI, your state, all that good stuff. Getting how they work is basically the key to winning at this whole framework thing.
|
|
4
|
-
|
|
5
|
-
Dolla's got three main types of components, and each one has its own lane:
|
|
6
|
-
|
|
7
|
-
1. **Views**: For making your UI look pretty.
|
|
8
|
-
2. **Stores**: For handling and sharing state so you don't lose your mind.
|
|
9
|
-
3. **Mixins**: For giving your plain old HTML elements some extra rizz.
|
|
10
|
-
|
|
11
|
-
They're all connected by this thing called **context**, which is how they talk to each other and share stuff like stores. Let's get into it.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Views: The Stuff You See
|
|
16
|
-
|
|
17
|
-
**Views** are the components you're gonna be making all the time. They're literally just JavaScript functions that spit out some JSX. If you've ever touched React, you'll feel right at home, fr.
|
|
18
|
-
|
|
19
|
-
### Making a View
|
|
20
|
-
|
|
21
|
-
It's just a function that gets a `props` object. That's it.
|
|
22
|
-
|
|
23
|
-
```jsx
|
|
24
|
-
import { useSignal } from "@manyducks.co/dolla";
|
|
25
|
-
|
|
26
|
-
// A super simple View
|
|
27
|
-
function Greeting(props) {
|
|
28
|
-
return <h1>Yo, {props.name}!</h1>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// A View with its own state and stuff
|
|
32
|
-
function Counter() {
|
|
33
|
-
const [$count, setCount] = useSignal(0);
|
|
34
|
-
const increment = () => setCount((c) => c + 1);
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div>
|
|
38
|
-
<p>Count: {$count}</p>
|
|
39
|
-
<button onClick={increment}>+1</button>
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Passing Props
|
|
46
|
-
|
|
47
|
-
You send data into your Views with `props`. They look just like HTML attributes. This is how you make your components useful instead of just being static, boring things.
|
|
48
|
-
|
|
49
|
-
```jsx
|
|
50
|
-
function App() {
|
|
51
|
-
return (
|
|
52
|
-
<div>
|
|
53
|
-
{/* Pass a normal string */}
|
|
54
|
-
<Greeting name="Alice" />
|
|
55
|
-
|
|
56
|
-
{/* To derive a signal and keep it reactive, wrap it in a function! */}
|
|
57
|
-
<Greeting name={() => $currentUser().firstName} />
|
|
58
|
-
</div>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Stores: Stop Prop Drilling Hell
|
|
66
|
-
|
|
67
|
-
**Stores** are Dolla's answer to state management. Got some state that like, ten different components need? Instead of passing props down a million levels (aka "prop drilling," the worst), you just use a Store.
|
|
68
|
-
|
|
69
|
-
### Making a Store
|
|
70
|
-
|
|
71
|
-
A Store is a function that makes and returns an object full of signals and functions. It's like a clean little API for a piece of your app's state.
|
|
72
|
-
|
|
73
|
-
```jsx
|
|
74
|
-
import { useSignal, useMemo } from "@manyducks.co/dolla";
|
|
75
|
-
|
|
76
|
-
function UserStore(options) {
|
|
77
|
-
// `options` come from where you provide the store
|
|
78
|
-
const [$user, setUser] = useSignal({ id: options.initialUserId, name: "Guest" });
|
|
79
|
-
const $isGuest = useMemo(() => $user().id === null);
|
|
80
|
-
|
|
81
|
-
const login = (userData) => {
|
|
82
|
-
// A real login would probably fetch this data
|
|
83
|
-
setUser(userData);
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const logout = () => {
|
|
87
|
-
setUser({ id: null, name: "Guest" });
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// Send out the signals and functions for other components to use
|
|
91
|
-
return { $user, $isGuest, login, logout };
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Using a Store
|
|
96
|
-
|
|
97
|
-
First, you "provide" the store in a parent component with `useStoreProvider`. Then, any kid component can grab it with `useStore`. Easy.
|
|
98
|
-
|
|
99
|
-
```jsx
|
|
100
|
-
import { useStoreProvider, useStore } from "@manyducks.co/dolla";
|
|
101
|
-
|
|
102
|
-
// 1. Provide the store up high
|
|
103
|
-
function App() {
|
|
104
|
-
// Now the UserStore is available to App and everything inside it
|
|
105
|
-
useStoreProvider(UserStore, { initialUserId: null });
|
|
106
|
-
|
|
107
|
-
return <Navbar />;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// 2. Use it down low
|
|
111
|
-
function Navbar() {
|
|
112
|
-
// Just ask for the UserStore instance
|
|
113
|
-
const userStore = useStore(UserStore);
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<nav>
|
|
117
|
-
<Show when={() => !userStore.$isGuest()}>
|
|
118
|
-
<p>Welcome, {() => userStore.$user().name}!</p>
|
|
119
|
-
<button onClick={userStore.logout}>Log Out</button>
|
|
120
|
-
</Show>
|
|
121
|
-
<Show when={() => userStore.$isGuest()}>
|
|
122
|
-
<button onClick={() => userStore.login({ id: 1, name: "Alice" })}>Log In</button>
|
|
123
|
-
</Show>
|
|
124
|
-
</nav>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Mixins: Giving Your HTML Superpowers
|
|
132
|
-
|
|
133
|
-
**Mixins** are a sick feature for attaching reusable logic straight to your HTML elements. A mixin is a function that returns _another_ function, and that inner function gets the element it's attached to. Inside, you can use hooks to do whatever you want.
|
|
134
|
-
|
|
135
|
-
### Making a Mixin
|
|
136
|
-
|
|
137
|
-
Here's a mixin that makes an element's background change color when you hover over it.
|
|
138
|
-
|
|
139
|
-
```jsx
|
|
140
|
-
import { useMount } from "@manyducks.co/dolla";
|
|
141
|
-
|
|
142
|
-
function hoverHighlight(color = "yellow") {
|
|
143
|
-
// The outer function lets you set it up
|
|
144
|
-
return (element) => {
|
|
145
|
-
// The inner function gets the element and can use hooks
|
|
146
|
-
const originalColor = element.style.backgroundColor;
|
|
147
|
-
|
|
148
|
-
const handleMouseEnter = () => {
|
|
149
|
-
element.style.backgroundColor = color;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const handleMouseLeave = () => {
|
|
153
|
-
element.style.backgroundColor = originalColor;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
useMount(() => {
|
|
157
|
-
element.addEventListener("mouseenter", handleMouseEnter);
|
|
158
|
-
element.addEventListener("mouseleave", handleMouseLeave);
|
|
159
|
-
|
|
160
|
-
// useMount lets you return a cleanup function. Dope.
|
|
161
|
-
return () => {
|
|
162
|
-
element.removeEventListener("mouseenter", handleMouseEnter);
|
|
163
|
-
element.removeEventListener("mouseleave", handleMouseLeave);
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Using a Mixin
|
|
171
|
-
|
|
172
|
-
You slap mixins onto elements with the `mixin` prop. You can use one, or go wild and use a whole array of 'em.
|
|
173
|
-
|
|
174
|
-
```jsx
|
|
175
|
-
function InteractiveList() {
|
|
176
|
-
return (
|
|
177
|
-
<ul>
|
|
178
|
-
{/* Just call the outer function to apply it */}
|
|
179
|
-
<li mixin={hoverHighlight()}>Hover me!</li>
|
|
180
|
-
<li mixin={hoverHighlight("lightblue")}>Or me!</li>
|
|
181
|
-
<li mixin={[hoverHighlight(), otherMixin()]}>I got two, lol</li>
|
|
182
|
-
</ul>
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## The Component Lifecycle (aka Birth and Death)
|
|
190
|
-
|
|
191
|
-
Dolla components have a simple life: they get **mounted** (put on the page) and **unmounted** (yeeted off the page). You can run code at these times with lifecycle hooks.
|
|
192
|
-
|
|
193
|
-
### `useMount(callback)`
|
|
194
|
-
|
|
195
|
-
This hook runs your code right after your component shows up. It's the spot for setting up timers, listeners, whatever.
|
|
196
|
-
|
|
197
|
-
If you return a function from `useMount`, Dolla will automatically run it for you right after the component is unmounted. It's like a built-in maid service for your code.
|
|
198
|
-
|
|
199
|
-
### `useUnmount(callback)`
|
|
200
|
-
|
|
201
|
-
This hook runs your code right before the component is unmounted. Good for quick, one-off cleanup tasks.
|
|
202
|
-
|
|
203
|
-
```jsx
|
|
204
|
-
import { useMount, useUnmount, useSignal } from "@manyducks.co/dolla";
|
|
205
|
-
|
|
206
|
-
function RealtimeClock() {
|
|
207
|
-
const [$time, setTime] = useSignal(new Date().toLocaleTimeString());
|
|
208
|
-
|
|
209
|
-
// useMount is perfect for setup AND cleanup
|
|
210
|
-
useMount(() => {
|
|
211
|
-
console.log("Clock's here, starting the timer.");
|
|
212
|
-
const timerId = setInterval(() => {
|
|
213
|
-
setTime(new Date().toLocaleTimeString());
|
|
214
|
-
}, 1000);
|
|
215
|
-
|
|
216
|
-
// This cleanup function runs when the component is gone
|
|
217
|
-
return () => {
|
|
218
|
-
console.log("Clock's leaving, killing the timer.");
|
|
219
|
-
clearInterval(timerId);
|
|
220
|
-
};
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// useUnmount for other random cleanup
|
|
224
|
-
useUnmount(() => {
|
|
225
|
-
console.log("The clock is officially off the page.");
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
return <p>The time is: {$time}</p>;
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
---
|
|
233
|
-
|
|
234
|
-
End.
|
|
235
|
-
|
|
236
|
-
- [🗂️ Docs](./index.md)
|
|
237
|
-
- [🏠 README](../README.md)
|
|
238
|
-
- [🦆 That's a lot of ducks.](https://www.manyducks.co)
|
package/docs/hooks.md
DELETED
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
# Dolla Hooks: The Cheat Sheet
|
|
2
|
-
|
|
3
|
-
Aight, so here's the deal with all the hooks in Dolla. Hooks are basically functions that let you tap into Dolla's brain—its reactive system and all that lifecycle stuff—from any of your components.
|
|
4
|
-
|
|
5
|
-
## Lifecycle Hooks
|
|
6
|
-
|
|
7
|
-
These hooks let you run code when your component is born, when it dies, and all the moments in between.
|
|
8
|
-
|
|
9
|
-
### `useMount(callback)`
|
|
10
|
-
|
|
11
|
-
Runs your code right after the component shows up on the page. If your function returns _another_ function, Dolla will automatically run that right after the component gets yeeted off the page. Perfect for cleanup\!
|
|
12
|
-
|
|
13
|
-
**Signature:**
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
function useMount(callback: () => void | (() => void)): void;
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
**Example:**
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
import { useMount, useSignal } from "@manyducks.co/dolla";
|
|
23
|
-
|
|
24
|
-
function IntervalTimer() {
|
|
25
|
-
const [$seconds, setSeconds] = useSignal(0);
|
|
26
|
-
|
|
27
|
-
useMount(() => {
|
|
28
|
-
// Start a timer when the component shows up
|
|
29
|
-
const intervalId = setInterval(() => {
|
|
30
|
-
setSeconds((s) => s + 1);
|
|
31
|
-
}, 1000);
|
|
32
|
-
|
|
33
|
-
// Return a function to clean up the mess. This runs on unmount.
|
|
34
|
-
return () => {
|
|
35
|
-
console.log("k, bye interval");
|
|
36
|
-
clearInterval(intervalId);
|
|
37
|
-
};
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return <p>Seconds on page: {$seconds}</p>;
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### `useUnmount(callback)`
|
|
45
|
-
|
|
46
|
-
Runs your code right after the component is removed. Great for any last-minute cleanup.
|
|
47
|
-
|
|
48
|
-
**Signature:**
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
function useUnmount(callback: () => void): void;
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Example:**
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
import { useUnmount } from "@manyducks.co/dolla";
|
|
58
|
-
|
|
59
|
-
function AnalyticsTracker({ eventName }) {
|
|
60
|
-
useUnmount(() => {
|
|
61
|
-
// Tell your analytics that the user bounced
|
|
62
|
-
fireAnalyticsEvent(`user_left_${eventName}_view`);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return <div>...</div>;
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## State Hooks
|
|
70
|
-
|
|
71
|
-
These are the main tools for making your components interactive and smart.
|
|
72
|
-
|
|
73
|
-
### `useSignal(initialValue?)`
|
|
74
|
-
|
|
75
|
-
The main way to make reactive state in Dolla. It gives you back a `[getter, setter]` pair.
|
|
76
|
-
|
|
77
|
-
**Signature:**
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
function useSignal<T>(value?: T, options?: SignalOptions<T>): [Signal<T>, Setter<T>];
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**Example:**
|
|
84
|
-
|
|
85
|
-
```tsx
|
|
86
|
-
import { useSignal } from "@manyducks.co/dolla";
|
|
87
|
-
|
|
88
|
-
function TextInput() {
|
|
89
|
-
const [$text, setText] = useSignal("");
|
|
90
|
-
const handleInput = (e) => setText(e.target.value);
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<div>
|
|
94
|
-
<input type="text" value={$text} onInput={handleInput} />
|
|
95
|
-
<p>You typed: {$text}</p>
|
|
96
|
-
</div>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### `useMemo(compute, deps?)`
|
|
102
|
-
|
|
103
|
-
Makes a new signal that's calculated from other signals. It's smart and only re-calculates when one of the signals it depends on changes.
|
|
104
|
-
|
|
105
|
-
**Signature:**
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
function useMemo<T>(compute: () => T, deps?: Signal<any>[]): Signal<T>;
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Example:**
|
|
112
|
-
|
|
113
|
-
```tsx
|
|
114
|
-
import { useSignal, useMemo } from "@manyducks.co/dolla";
|
|
115
|
-
|
|
116
|
-
function ShoppingCart() {
|
|
117
|
-
const [$price, setPrice] = useSignal(100);
|
|
118
|
-
const [$quantity, setQuantity] = useSignal(2);
|
|
119
|
-
|
|
120
|
-
// This signal will always be the right total. No math for you.
|
|
121
|
-
const $total = useMemo(() => $price() * $quantity());
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<div>
|
|
125
|
-
<p>Price: {$price}</p>
|
|
126
|
-
<p>Quantity: {$quantity}</p>
|
|
127
|
-
<hr />
|
|
128
|
-
<p>Total: {$total}</p>
|
|
129
|
-
</div>
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### `useReducer(reducer, initialState)`
|
|
135
|
-
|
|
136
|
-
For when your state gets complicated and you wanna feel like a pro. It's just like the one in React.
|
|
137
|
-
|
|
138
|
-
**Signature:**
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
type Reducer<State, Action> = (state: State, action: Action) => State;
|
|
142
|
-
type Dispatcher<Action> = (action: Action) => void;
|
|
143
|
-
|
|
144
|
-
function useReducer<State, Action>(
|
|
145
|
-
reducer: Reducer<State, Action>,
|
|
146
|
-
initialState: State,
|
|
147
|
-
): [Signal<State>, Dispatcher<Action>];
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
**Example:**
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
import { useReducer } from "@manyducks.co/dolla";
|
|
154
|
-
|
|
155
|
-
const counterReducer = (state, action) => {
|
|
156
|
-
switch (action.type) {
|
|
157
|
-
case "INCREMENT":
|
|
158
|
-
return { ...state, count: state.count + 1 };
|
|
159
|
-
case "DECREMENT":
|
|
160
|
-
return { ...state, count: state.count - 1 };
|
|
161
|
-
default:
|
|
162
|
-
return state;
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
function ReducerCounter() {
|
|
167
|
-
const [$state, dispatch] = useReducer(counterReducer, { count: 0 });
|
|
168
|
-
|
|
169
|
-
return (
|
|
170
|
-
<>
|
|
171
|
-
<p>Count: {() => $state().count}</p>
|
|
172
|
-
<button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
|
|
173
|
-
<button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
|
|
174
|
-
</>
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### `useRef(initialValue?)`
|
|
180
|
-
|
|
181
|
-
Gives you a little box to hold onto something. Super useful for grabbing HTML elements. You can use `.current` or just call it like a function to get the value.
|
|
182
|
-
|
|
183
|
-
**Signature:**
|
|
184
|
-
|
|
185
|
-
```ts
|
|
186
|
-
function useRef<T>(initialValue?: T): HybridRef<T>;
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**Example:**
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
import { useRef, useMount } from "@manyducks.co/dolla";
|
|
193
|
-
|
|
194
|
-
function FocusOnMount() {
|
|
195
|
-
const inputEl = useRef();
|
|
196
|
-
|
|
197
|
-
useMount(() => {
|
|
198
|
-
// get the element from .current
|
|
199
|
-
if (inputEl.current) {
|
|
200
|
-
inputEl.current.focus();
|
|
201
|
-
}
|
|
202
|
-
// you can also just call it like a function, lol
|
|
203
|
-
console.log(inputEl());
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
return <input ref={inputEl} placeholder="i'm gonna be focused" />;
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Effect Hooks
|
|
211
|
-
|
|
212
|
-
These are for doing "side effects" - stuff that isn't just rendering, like fetching data or messing with the DOM directly.
|
|
213
|
-
|
|
214
|
-
### `useEffect(callback, deps?)`
|
|
215
|
-
|
|
216
|
-
The go-to hook for side effects. Your code runs after the component shows up, and then again whenever the signals it uses change. It's automatic, but you can give it a `deps` array if you wanna be extra and control it yourself.
|
|
217
|
-
|
|
218
|
-
**Signature:**
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
function useEffect(fn: () => void, deps?: Signal<any>[]): void;
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Example:**
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
import { useEffect, useSignal } from "@manyducks.co/dolla";
|
|
228
|
-
import { http } from "@manyducks.co/dolla/http";
|
|
229
|
-
|
|
230
|
-
function UserData({ $userId }) {
|
|
231
|
-
const [$user, setUser] = useSignal(null);
|
|
232
|
-
|
|
233
|
-
// This effect will re-run whenever the $userId prop changes.
|
|
234
|
-
useEffect(() => {
|
|
235
|
-
const userId = $userId();
|
|
236
|
-
http.get(`/api/users/${userId}`).then((res) => {
|
|
237
|
-
setUser(res.body);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return (
|
|
242
|
-
<Show when={$user}>
|
|
243
|
-
<p>User: {() => $user().name}</p>
|
|
244
|
-
</Show>
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## Context Hooks
|
|
250
|
-
|
|
251
|
-
These are the hooks you use to mess with the context system. Think of it like a way to pass stuff down to your components without having to prop drill, which is a total vibe killer.
|
|
252
|
-
|
|
253
|
-
### `useContext(name?)`
|
|
254
|
-
|
|
255
|
-
This just grabs the `Context` object for whatever component you're in. The context has useful stuff like loggers and is how stores get passed around.
|
|
256
|
-
|
|
257
|
-
**Signature:**
|
|
258
|
-
|
|
259
|
-
```ts
|
|
260
|
-
function useContext(name?: MaybeSignal<string>): Context;
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
**Parameters:**
|
|
264
|
-
|
|
265
|
-
- `name` (optional): A string or signal you can pass in to give your component a custom name for logging. Makes debugging less of a headache.
|
|
266
|
-
|
|
267
|
-
**Example:**
|
|
268
|
-
|
|
269
|
-
```tsx
|
|
270
|
-
import { useContext } from "@manyducks.co/dolla";
|
|
271
|
-
|
|
272
|
-
function UserProfile() {
|
|
273
|
-
// Grab the context and give it a cooler name
|
|
274
|
-
const context = useContext("UserProfilePage");
|
|
275
|
-
|
|
276
|
-
useMount(() => {
|
|
277
|
-
// The log will now say "[UserProfilePage]". Noice.
|
|
278
|
-
context.log("Component just dropped.");
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
return <div>...</div>;
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### `useStore(Store)`
|
|
286
|
-
|
|
287
|
-
This hook looks up the component tree and finds the closest `Store` that a parent component hooked you up with.
|
|
288
|
-
|
|
289
|
-
**Signature:**
|
|
290
|
-
|
|
291
|
-
```ts
|
|
292
|
-
function useStore<T>(store: Store<any, T>): T;
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
**Parameters:**
|
|
296
|
-
|
|
297
|
-
- `store`: Just tell it which Store you're looking for.
|
|
298
|
-
|
|
299
|
-
**Example:**
|
|
300
|
-
|
|
301
|
-
```tsx
|
|
302
|
-
// Pretend some parent component already provided the SessionStore
|
|
303
|
-
import { useStore } from "@manyducks.co/dolla";
|
|
304
|
-
import { SessionStore } from "./stores/SessionStore.js";
|
|
305
|
-
|
|
306
|
-
function Navbar() {
|
|
307
|
-
const session = useStore(SessionStore);
|
|
308
|
-
|
|
309
|
-
return (
|
|
310
|
-
<nav>
|
|
311
|
-
<Show when={session.$isLoggedIn}>
|
|
312
|
-
<p>Yo, {() => session.$user().name}!</p>
|
|
313
|
-
</Show>
|
|
314
|
-
</nav>
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### `useStoreProvider(Store, options?)`
|
|
320
|
-
|
|
321
|
-
This is how you make a `Store` available to a component and all its kids. You create it here, and then any component inside can just use `useStore` to grab it.
|
|
322
|
-
|
|
323
|
-
**Signature:**
|
|
324
|
-
|
|
325
|
-
```ts
|
|
326
|
-
function useStoreProvider<T, O>(store: Store<O, T>, options?: O): T;
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
**Parameters:**
|
|
330
|
-
|
|
331
|
-
- `store`: The Store you wanna provide.
|
|
332
|
-
- `options` (optional): Any options you need to pass to the Store when it's made.
|
|
333
|
-
|
|
334
|
-
**Example:**
|
|
335
|
-
|
|
336
|
-
```tsx
|
|
337
|
-
import { useStoreProvider } from "@manyducks.co/dolla";
|
|
338
|
-
import { ThemeStore } from "./stores/ThemeStore.js";
|
|
339
|
-
import { AppContent } from "./AppContent.js";
|
|
340
|
-
|
|
341
|
-
function App() {
|
|
342
|
-
// Provide the ThemeStore to the whole app.
|
|
343
|
-
// Any child can now get it with useStore(ThemeStore).
|
|
344
|
-
useStoreProvider(ThemeStore, { defaultTheme: "dark" });
|
|
345
|
-
|
|
346
|
-
return <AppContent />;
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
End.
|
|
353
|
-
|
|
354
|
-
- [🗂️ Docs](./index.md)
|
|
355
|
-
- [🏠 README](../README.md)
|
|
356
|
-
- [🦆 That's a lot of ducks.](https://www.manyducks.co)
|