@slux/ripple 0.0.0-stage → 0.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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +186 -2
- package/dist/6.js +2 -0
- package/dist/6.js.map +1 -0
- package/dist/atom.d.ts +11 -0
- package/dist/atom.js +2 -0
- package/dist/atom.js.map +1 -0
- package/dist/flux.d.ts +7 -0
- package/dist/flux.js +2 -0
- package/dist/flux.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +6 -0
- package/dist/proxy.js +2 -0
- package/dist/proxy.js.map +1 -0
- package/dist/rxjs.d.ts +6 -0
- package/dist/rxjs.js +2 -0
- package/dist/rxjs.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/state-machine.d.ts +9 -0
- package/dist/state-machine.js +2 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/store.d.ts +8 -0
- package/dist/store.js +2 -0
- package/dist/store.js.map +1 -0
- package/dist/t.js +2 -0
- package/dist/t.js.map +1 -0
- package/package.json +121 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @slux/ripple
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 首次公开发布 slux 的 25 个包,统一版本为 0.1.0。
|
|
8
|
+
|
|
9
|
+
- 提供框架无关的响应式核心与共享工具,以及 Store、Atom、Proxy、Flux、状态机和 RxJS 六种状态组织方式。
|
|
10
|
+
- 提供持久化、历史记录、跨标签页同步、遥测和开发工具五类 Store 扩展。
|
|
11
|
+
- 提供 React、Vue、Solid、Svelte、Angular、Preact、Ripple、Inferno、Octane、Vitarx、ActView 和 Viewfly 绑定。
|
|
12
|
+
- 提供各包文档与对应示例,并接入发布检查和文档部署工作流。
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @slux/atom@0.1.0
|
|
18
|
+
- @slux/core@0.1.0
|
|
19
|
+
- @slux/flux@0.1.0
|
|
20
|
+
- @slux/proxy@0.1.0
|
|
21
|
+
- @slux/rxjs@0.1.0
|
|
22
|
+
- @slux/shared@0.1.0
|
|
23
|
+
- @slux/state-machine@0.1.0
|
|
24
|
+
- @slux/store@0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 itmanyong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,187 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @slux/ripple
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ripple(`ripple@^0.6.1`)的 slux 绑定,基于 `@slux/core` 的 `Subscribable<T>` 订阅模型。原生绑定形式是 **Ripple 原生 `track` / `effect`**:所有绑定返回 `Derived<T>`,以 **`.value` 读取**。`.` 入口按 `browser` / `default` 条件分流到客户端与服务端实现。所有写入仍走原实例,绑定只读。
|
|
4
|
+
|
|
5
|
+
## 特性与适用场景
|
|
6
|
+
|
|
7
|
+
| 项 | 说明 |
|
|
8
|
+
| -------- | ----------------------------------------------------------------------------------- |
|
|
9
|
+
| 绑定形式 | `useSignal(source)` 及六个子入口返回 `Derived<T>`,以 `.value` 读取 |
|
|
10
|
+
| 框架依赖 | `ripple` 的 `track`、`effect`、`Context`;服务端用 `ripple/server` 的 `render` |
|
|
11
|
+
| 范式覆盖 | core 主入口 + atom / store / proxy / flux / state-machine / rxjs 六个子入口 |
|
|
12
|
+
| SSR | `default` 条件 / `@slux/ripple/server` 提供不订阅的服务端 `useSignal`,读显式 Scope |
|
|
13
|
+
|
|
14
|
+
| 场景 | 是否适合 | 说明 |
|
|
15
|
+
| ------------------------------------------------- | -------- | ----------------------------------------------------- |
|
|
16
|
+
| 在 Ripple 编译组件里读 core `signal` / `computed` | 适合 | 订阅内 core `effect` 主动刷新惰性 computed |
|
|
17
|
+
| 用 atom / store / proxy 或新增三种范式 | 适合 | 各子入口返回 `Derived`,范式包按需安装 |
|
|
18
|
+
| SSR 首屏读取 Scope 覆盖值 | 适合 | 服务端 `useSignal` 读 `scope.get(source)`,不建立订阅 |
|
|
19
|
+
| 需要绑定替你写入状态 | 不适合 | `Derived<T>` 只读,写入走 `set` / `dispatch` / `send` |
|
|
20
|
+
| 需要 CJS 消费 | 不适合 | 本包只发布 ESM |
|
|
21
|
+
| 未接入 Ripple 编译器 | 不适合 | 组件 JSX 与 `.value` 读取需消费端编译器处理 |
|
|
22
|
+
|
|
23
|
+
## 安装
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pnpm add @slux/core @slux/ripple ripple@^0.6.1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- **必需 peer**:`@slux/core`(`workspace:^`)、`ripple@^0.6.1`。
|
|
30
|
+
- **可选 peer(范式包)**:`@slux/atom`、`@slux/store`、`@slux/proxy`、`@slux/flux`、`@slux/state-machine`、`@slux/rxjs` 均为 `optional`,**只装实际使用的子入口**。
|
|
31
|
+
- `@slux/shared` 是本包运行时依赖,安装时自动带入。
|
|
32
|
+
- 本包只发布 ESM:`exports` 没有 `require` 条件,也没有 `.d.cts`;`main` 指向 `dist/server.js`,`module` 指向 `dist/index.js`。
|
|
33
|
+
- 消费端组件(JSX 与 `.value` 读取)需按 Ripple 官方要求接入编译器,本包不内置编译器。
|
|
34
|
+
|
|
35
|
+
`package.json` 的 `exports` 子入口(逐个列出):
|
|
36
|
+
|
|
37
|
+
| 子路径 | 条件 / 产物 | 导出内容 |
|
|
38
|
+
| ---------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
39
|
+
| `@slux/ripple` | `browser` → `dist/index.js`(客户端);`default` → `dist/server.js`(服务端) | `ScopeContext`、`provideScope`、`useScopeContext`、`useSignal`、`createAutoImportApis` |
|
|
40
|
+
| `@slux/ripple/server` | `default` → `dist/server.js` | `ScopeContext`、`provideScope`、`useScopeContext`、服务端 `useSignal` |
|
|
41
|
+
| `@slux/ripple/atom` | `default` → `dist/atom.js` | `useAtomValue`、`useSetAtom`、`useAtom` |
|
|
42
|
+
| `@slux/ripple/store` | `default` → `dist/store.js` | `useStore` |
|
|
43
|
+
| `@slux/ripple/proxy` | `default` → `dist/proxy.js` | `useSnapshot` |
|
|
44
|
+
| `@slux/ripple/flux` | `default` → `dist/flux.js` | `useFluxStore` |
|
|
45
|
+
| `@slux/ripple/state-machine` | `default` → `dist/state-machine.js` | `useMachine` |
|
|
46
|
+
| `@slux/ripple/rxjs` | `default` → `dist/rxjs.js` | `useObservable` |
|
|
47
|
+
| `@slux/ripple/package.json` | 包元数据(非 API) | — |
|
|
48
|
+
|
|
49
|
+
## 快速开始
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { signal } from "@slux/core";
|
|
53
|
+
import { useSignal } from "@slux/ripple";
|
|
54
|
+
|
|
55
|
+
const count = signal(0);
|
|
56
|
+
|
|
57
|
+
export function Counter() {
|
|
58
|
+
const value = useSignal(count);
|
|
59
|
+
return <button onClick={() => count.set((n) => n + 1)}>{value.value}</button>;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`useSignal(count)` 返回 `Derived<number>`,模板用 `.value` 读取;点击时仍通过 core 的 `count.set(recipe)` 写入。
|
|
64
|
+
|
|
65
|
+
## 主入口 API
|
|
66
|
+
|
|
67
|
+
主入口的运行时导出来自 `src/index.ts`(客户端)与 `src/scope.ts`;`scope.ts` 的三个导出在客户端与服务端入口都会重新导出。
|
|
68
|
+
|
|
69
|
+
| 成员 | 签名 | 行为 |
|
|
70
|
+
| -------------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
71
|
+
| `useSignal`(客户端) | `<T>(source: Subscribable<T>) => Derived<T>` | 基于 `useExternal`:`track` 状态 + `effect` 建立订阅并刷新;订阅内 `source.subscribe` 与 core `effect(() => { source.get(); })` 同时驱动惰性 computed |
|
|
72
|
+
| `useSignal`(服务端,`/server`) | `<T>(source: Subscribable<T>) => Derived<T>` | `track(() => (scope ? scope.get(source) : source.get()))`,**不建立订阅** |
|
|
73
|
+
| `ScopeContext` | `new Context<Scope \| null>(null)` | Ripple 原生 Context,默认 `null` |
|
|
74
|
+
| `provideScope` | `(scope: Scope) => void` | `ScopeContext.set(scope)`,在父组件初始化中调用 |
|
|
75
|
+
| `useScopeContext` | `() => Scope \| null` | `ScopeContext.get()` |
|
|
76
|
+
| `createAutoImportApis` | `(prefix?: string) => ImportsMap` | 生成 `unplugin-auto-import` 配置,见「自动导入」 |
|
|
77
|
+
|
|
78
|
+
内部 `useExternal`(`src/external.ts`,**不由 `exports` 暴露**)是所有客户端绑定的共同机制:用 `track({ value: read() })` 包裹值(避免 Ripple `track` 把函数类型的值误当作派生计算执行),在 `effect` 内订阅、刷新并把 `unsubscribe` 作为清理返回,最后返回 `track(() => state.value.value)` 形式的 `Derived<T>`。六个子入口都基于它。
|
|
79
|
+
|
|
80
|
+
服务端 `useSignal` 与 Scope 用法:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { render } from "ripple/server";
|
|
84
|
+
import { createScope, signal } from "@slux/core";
|
|
85
|
+
import { provideScope, useSignal } from "@slux/ripple/server";
|
|
86
|
+
|
|
87
|
+
const source = signal(1);
|
|
88
|
+
const scope = createScope();
|
|
89
|
+
scope.set(source, 42);
|
|
90
|
+
|
|
91
|
+
const result = await render(() => {
|
|
92
|
+
provideScope(scope);
|
|
93
|
+
return String(useSignal(source).value); // 读取 Scope 覆盖值
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 子入口 API
|
|
98
|
+
|
|
99
|
+
所有子入口返回 `Derived<T>`,以 `.value` 读取;**不返回写入 tuple,也不创建副本**。
|
|
100
|
+
|
|
101
|
+
### `@slux/ripple/atom`
|
|
102
|
+
|
|
103
|
+
| 导出 | 签名 | 返回值 / 写入 |
|
|
104
|
+
| -------------- | -------------------------------------------------------- | -------------------------------------------- |
|
|
105
|
+
| `useAtomValue` | `<T>(atom: AnyReadableAtom<T>) => Derived<T>` | 只读派生值,支持只读派生 atom |
|
|
106
|
+
| `useSetAtom` | `<T>(atom: Atom<T>) => (value: T) => void` | setter;按 atom 替换契约写值,函数值不被执行 |
|
|
107
|
+
| `useAtom` | `<T>(atom: Atom<T>) => [Derived<T>, (value: T) => void]` | `[只读派生值, setter]` |
|
|
108
|
+
|
|
109
|
+
### `@slux/ripple/store`
|
|
110
|
+
|
|
111
|
+
`useStore` 有两个重载:
|
|
112
|
+
|
|
113
|
+
| 调用 | 返回值 |
|
|
114
|
+
| ---------------------------------------- | ---------------------------- |
|
|
115
|
+
| `useStore(store)` | `Derived<State>`(完整状态) |
|
|
116
|
+
| `useStore(store, selector, equalityFn?)` | `Derived<Selection>`(选值) |
|
|
117
|
+
|
|
118
|
+
`selector = (state: State) => Selection`;`equalityFn(previous, next)` 默认 `Object.is`。带 selector 时按 state 引用缓存选值,`equalityFn` 判定相等时保留旧选值引用。写入仍用 `store.setState(...)`。
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { createStore } from "@slux/store";
|
|
122
|
+
import { useStore } from "@slux/ripple/store";
|
|
123
|
+
|
|
124
|
+
const store = createStore(() => ({ count: 1 }));
|
|
125
|
+
|
|
126
|
+
export function Count() {
|
|
127
|
+
const count = useStore(store, (state) => state.count);
|
|
128
|
+
return <output>{count.value}</output>;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `@slux/ripple/proxy`
|
|
133
|
+
|
|
134
|
+
| 导出 | 签名 | 返回值 |
|
|
135
|
+
| ------------- | ------------------------------------------------------ | --------------------------------------------- |
|
|
136
|
+
| `useSnapshot` | `<T extends object>(proxy: T) => Derived<Snapshot<T>>` | 整个 proxy 的深只读、冻结快照,无字段访问追踪 |
|
|
137
|
+
|
|
138
|
+
### 新增三种范式(只读)
|
|
139
|
+
|
|
140
|
+
| 子路径 | 导出 | 签名 | 返回值 | 写入方式 |
|
|
141
|
+
| ---------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------ |
|
|
142
|
+
| `@slux/ripple/flux` | `useFluxStore` | `<State, Action extends FluxAction>(store: FluxStore<State, Action>) => Derived<State>` | Flux 完整状态 | `store.dispatch(action)` |
|
|
143
|
+
| `@slux/ripple/state-machine` | `useMachine` | `<Context, Event extends { type: string }, State extends string>(machine: StateMachine<Context, Event, State>) => Derived<MachineSnapshot<Context, State>>` | 状态机快照 | `machine.send(event)` |
|
|
144
|
+
| `@slux/ripple/rxjs` | `useObservable` | `<T>(source: ObservableState<T>) => Derived<T>` | 桥接最近值 | 桥接创建者持有上游 |
|
|
145
|
+
|
|
146
|
+
三者都基于 `useExternal`:`read` 取各自实例的 `.get()`,`subscribe` 取各自实例的 `.subscribe(notify)`。
|
|
147
|
+
|
|
148
|
+
## 专属语义与边界
|
|
149
|
+
|
|
150
|
+
- **条件导出与 SSR**:`.` 入口的 `browser` 条件选客户端 `index.js`,`default` 条件选服务端 `server.js`;`main` 指向 `server.js`,`module` 指向 `index.js`,也可显式导入 `@slux/ripple/server`。服务端渲染时 Ripple **不执行 `effect`**,因此基于 `useExternal` 的所有子入口(以及客户端 `useSignal`)不会建立 `source.subscribe` 订阅,首值来自 `read()` 的同步求值;服务端 `useSignal` 进一步读取 `scope.get(source)` 覆盖值。子入口在服务端读各自实例的当前值,**不应用 core Scope**。
|
|
151
|
+
- **客户端 Scope**:`ScopeContext` 用 Ripple 原生 `Context`;父组件初始化中 `provideScope(scope)`,后代用 `useScopeContext()` 取得。**客户端 `useSignal` 不读 Scope 覆盖值**,始终读取并跟随全局来源;覆盖值只由服务端入口的 `useSignal` 应用,或由调用方显式 `useScopeContext()?.get(source)` 读取。服务端按请求创建独立状态实例与 Scope,不自动序列化 / 恢复(通用约定见 [仓库根 README](../../README.md))。
|
|
152
|
+
- **订阅与清理**:`useExternal` 在 Ripple 原生 `effect` 内建立订阅并把 `unsubscribe` 作为清理函数返回,组件卸载时释放组件订阅;主入口 `useSignal` 额外建立 core `effect` 驱动惰性 computed。组件卸载**不销毁**业务 store / flux / machine / observable,桥接创建者负责 `dispose()`。
|
|
153
|
+
- **数据源固定**:`useExternal` 的订阅在组件初始化时建立一次(Ripple `effect` 不接收依赖数组),**组件实例内数据源固定**;需要替换来源时重建该组件实例。这与用 `useCallback` / `componentDidUpdate` 可重连来源的框架绑定不同。
|
|
154
|
+
- **快照相等判定**:订阅触发时 `useExternal` 重新 `read()` 并写入 `track` 状态;`useStore` 的 `equalityFn`(默认 `Object.is`)在选值相等时保留旧引用,`@slux/proxy` 的不可变快照保持未变分支引用。`external.ts` 用 `{ value: read() }` 包裹值,保证函数类型的值不被 `track` 当作派生计算执行。
|
|
155
|
+
- **错误处理**:绑定层不新增错误包装;写入、通知与 `effect` 的错误行为遵循 `@slux/core`。RxJS 桥接的完成 / 错误状态由 `@slux/rxjs` 的 `status` / `error` 只读信号读取。
|
|
156
|
+
- **通用约定**:跨框架的写入形式、Scope、SSR 与桥接生命周期约定见 [仓库根 README](../../README.md) 的「框架适配 · 通用约定」;仓库内验证命令见「本地开发」,本文不重复。
|
|
157
|
+
|
|
158
|
+
## 自动导入
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import AutoImport from "unplugin-auto-import/vite";
|
|
162
|
+
import { createAutoImportApis } from "@slux/ripple";
|
|
163
|
+
|
|
164
|
+
export default {
|
|
165
|
+
plugins: [AutoImport({ imports: [createAutoImportApis()] })],
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`createAutoImportApis(prefix = "")` 的登记清单以 `src/auto-import-api.ts` 的 `allImportApis` 为准,当前为 **`ScopeContext`、`provideScope`、`useScopeContext`、`useSignal`** 四项,来源名 `@slux/ripple`。传入前缀可生成别名,大写规则由 `@slux/shared` 的 `generateBatchAutoImports` 决定。清单**只含主入口运行时导出**,不含 `createAutoImportApis` 自身,也不含任何子入口导出。
|
|
170
|
+
|
|
171
|
+
## 类型导出
|
|
172
|
+
|
|
173
|
+
本包**没有显式 `export type`**:`Derived<T>` 与 `Context` 来自 `ripple`,`Scope` / `Subscribable<T>` 来自 `@slux/core`,`Snapshot<T>` 来自 `@slux/proxy`,其余范式类型(`AnyReadableAtom` / `Atom`、`StoreApi`、`FluxStore` / `FluxAction`、`MachineSnapshot` / `StateMachine`、`ObservableState`)都通过函数签名暴露,从各自包导入。`ScopeContext` 是 `Context<Scope | null>` 实例,其类型由 `ripple` 提供。
|
|
174
|
+
|
|
175
|
+
## 不适用的场景
|
|
176
|
+
|
|
177
|
+
- 需要在组件外(Node / 脚本)读写状态:用 `@slux/core`。
|
|
178
|
+
- 需要绑定返回写入 tuple、selector 之外的写入接口或状态副本:返回的是只读 `Derived<T>`。
|
|
179
|
+
- 需要在同一组件实例内切换数据源:数据源在初始化时固定,需重建组件实例。
|
|
180
|
+
- 需要 CJS / `require` 消费:本包只发布 ESM。
|
|
181
|
+
- 未接入 Ripple 编译器:组件 JSX 与 `.value` 读取无法在消费端工作。
|
|
182
|
+
|
|
183
|
+
## 版本、许可与反馈
|
|
184
|
+
|
|
185
|
+
- 版本:`0.1.0`(`package.json`);许可:[MIT](../../LICENSE) © itmanyong。
|
|
186
|
+
- 问题反馈:`https://github.com/itmanyong/slux/issues`。
|
|
187
|
+
- 通用约定与本地开发命令见 [仓库根 README](../../README.md)。
|
package/dist/6.js
ADDED
package/dist/6.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"6.js","sources":["../src/scope.ts"],"sourcesContent":["import { Context } from \"ripple\";\nimport type { Scope } from \"@slux/core\";\n\nexport const ScopeContext = new Context<Scope | null>(null);\n\nexport function provideScope(scope: Scope): void {\n ScopeContext.set(scope);\n}\n\nexport function useScopeContext(): Scope | null {\n return ScopeContext.get();\n}\n"],"names":["ScopeContext","Context","provideScope","scope","useScopeContext"],"mappings":"iCAGO,IAAMA,EAAe,IAAIC,EAAsB,MAE/C,SAASC,EAAaC,CAAY,EACvCH,EAAa,GAAG,CAACG,EACnB,CAEO,SAASC,IACd,OAAOJ,EAAa,GAAG,EACzB,Q"}
|
package/dist/atom.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AnyReadableAtom } from '@slux/atom';
|
|
2
|
+
import type { Atom } from '@slux/atom';
|
|
3
|
+
import type { Derived } from 'ripple';
|
|
4
|
+
|
|
5
|
+
export declare function useAtom<T>(atom: Atom<T>): [Derived<T>, (value: T) => void];
|
|
6
|
+
|
|
7
|
+
export declare function useAtomValue<T>(atom: AnyReadableAtom<T>): Derived<T>;
|
|
8
|
+
|
|
9
|
+
export declare function useSetAtom<T>(atom: Atom<T>): (value: T) => void;
|
|
10
|
+
|
|
11
|
+
export { }
|
package/dist/atom.js
ADDED
package/dist/atom.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atom.js","sources":["../src/atom.ts"],"sourcesContent":["import type { Atom, AnyReadableAtom } from \"@slux/atom\";\nimport type { Derived } from \"ripple\";\nimport { useExternal } from \"./external.js\";\n\nexport function useAtom<T>(atom: Atom<T>): [Derived<T>, (value: T) => void] {\n return [useAtomValue(atom), useSetAtom(atom)];\n}\n\nexport function useAtomValue<T>(atom: AnyReadableAtom<T>): Derived<T> {\n return useExternal(\n () => atom.get(),\n (notify) => atom.subscribe(notify),\n );\n}\n\nexport function useSetAtom<T>(atom: Atom<T>): (value: T) => void {\n return (value) => atom.set(value);\n}\n"],"names":["useAtom","atom","useAtomValue","useSetAtom","useExternal","notify","value"],"mappings":"mDAIO,SAASA,EAAWC,CAAa,EACtC,MAAO,CAACC,EAAaD,GAAOE,EAAWF,GAAM,AAC/C,CAEO,SAASC,EAAgBD,CAAwB,EACtD,OAAOG,EACL,IAAMH,EAAK,GAAG,GACd,AAACI,GAAWJ,EAAK,SAAS,CAACI,GAE/B,CAEO,SAASF,EAAcF,CAAa,EACzC,OAAO,AAACK,GAAUL,EAAK,GAAG,CAACK,EAC7B,Q"}
|
package/dist/flux.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Derived } from 'ripple';
|
|
2
|
+
import type { FluxAction } from '@slux/flux';
|
|
3
|
+
import type { FluxStore } from '@slux/flux';
|
|
4
|
+
|
|
5
|
+
export declare function useFluxStore<State, Action extends FluxAction>(store: FluxStore<State, Action>): Derived<State>;
|
|
6
|
+
|
|
7
|
+
export { }
|
package/dist/flux.js
ADDED
package/dist/flux.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flux.js","sources":["../src/flux.ts"],"sourcesContent":["import { useExternal } from \"./external.js\";\nimport type { FluxAction, FluxStore } from \"@slux/flux\";\nimport type { Derived } from \"ripple\";\n\nexport function useFluxStore<State, Action extends FluxAction>(store: FluxStore<State, Action>): Derived<State> {\n return useExternal(\n () => store.get(),\n (notify) => store.subscribe(notify),\n );\n}\n"],"names":["useFluxStore","store","useExternal","notify"],"mappings":"mDAIO,SAASA,EAA+CC,CAA+B,EAC5F,OAAOC,EACL,IAAMD,EAAM,GAAG,GACf,AAACE,GAAWF,EAAM,SAAS,CAACE,GAEhC,Q"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Context } from 'ripple';
|
|
2
|
+
import type { Derived } from 'ripple';
|
|
3
|
+
import type { Scope } from '@slux/core';
|
|
4
|
+
import type { Subscribable } from '@slux/core';
|
|
5
|
+
|
|
6
|
+
export declare const createAutoImportApis: (prefix?: string) => {
|
|
7
|
+
[x: string]: (string | [string, string])[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export declare function provideScope(scope: Scope): void;
|
|
11
|
+
|
|
12
|
+
export declare const ScopeContext: Context<Scope | null>;
|
|
13
|
+
|
|
14
|
+
export declare function useScopeContext(): Scope | null;
|
|
15
|
+
|
|
16
|
+
export declare function useSignal<T>(source: Subscribable<T>): Derived<T>;
|
|
17
|
+
|
|
18
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{effect as e}from"@slux/core";import{generateBatchAutoImports as o}from"@slux/shared";import{useExternal as t}from"./t.js";let r=["ScopeContext","provideScope","useScopeContext","useSignal"],p=(e="")=>o([{prefix:e,fromName:"@slux/ripple",imports:r}]);function i(o){return t(()=>o.get(),t=>{let r=o.subscribe(t),p=e(()=>{o.get()});return()=>{r(),p()}})}export{ScopeContext,provideScope,useScopeContext}from"./6.js";export{p as createAutoImportApis,i as useSignal};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/auto-import-api.ts","../src/index.ts"],"sourcesContent":["import { generateBatchAutoImports } from \"@slux/shared\";\n\nconst allImportApis: string[] = [\"ScopeContext\", \"provideScope\", \"useScopeContext\", \"useSignal\"];\n\nexport const createAutoImportApis = (prefix: string = \"\") => {\n return generateBatchAutoImports([\n {\n prefix,\n fromName: \"@slux/ripple\",\n imports: allImportApis,\n },\n ]);\n};\n","import { effect } from \"@slux/core\";\nimport type { Subscribable } from \"@slux/core\";\nimport type { Derived } from \"ripple\";\nimport { useExternal } from \"./external.js\";\n\nexport { ScopeContext, provideScope, useScopeContext } from \"./scope.js\";\n\nexport function useSignal<T>(source: Subscribable<T>): Derived<T> {\n return useExternal(\n () => source.get(),\n (notify) => {\n const unsubscribe = source.subscribe(notify);\n // computed 需要活跃读取才能向订阅者发布最新值。\n const dispose = effect(() => {\n source.get();\n });\n return () => {\n unsubscribe();\n dispose();\n };\n },\n );\n}\nexport { createAutoImportApis } from \"./auto-import-api.js\";\n"],"names":["allImportApis","createAutoImportApis","prefix","generateBatchAutoImports","useSignal","source","useExternal","notify","unsubscribe","dispose","effect"],"mappings":"+IAEA,IAAMA,EAA0B,CAAC,eAAgB,eAAgB,kBAAmB,YAAY,CAEnFC,EAAuB,CAACC,EAAiB,EAAE,GAC/CC,EAAyB,CAC9B,CACED,OAAAA,EACA,SAAU,eACV,QAASF,CACX,EACD,ECJI,SAASI,EAAaC,CAAuB,EAClD,OAAOC,EACL,IAAMD,EAAO,GAAG,GAChB,AAACE,IACC,IAAMC,EAAcH,EAAO,SAAS,CAACE,GAE/BE,EAAUC,EAAO,KACrBL,EAAO,GAAG,EACZ,GACA,MAAO,KACLG,IACAC,GACF,CACF,EAEJ,C"}
|
package/dist/proxy.d.ts
ADDED
package/dist/proxy.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sources":["../src/proxy.ts"],"sourcesContent":["import { snapshot, subscribe } from \"@slux/proxy\";\nimport type { Snapshot } from \"@slux/proxy\";\nimport type { Derived } from \"ripple\";\nimport { useExternal } from \"./external.js\";\n\nexport function useSnapshot<T extends object>(proxy: T): Derived<Snapshot<T>> {\n return useExternal(\n () => snapshot(proxy),\n (notify) => subscribe(proxy, notify),\n );\n}\n"],"names":["useSnapshot","proxy","useExternal","snapshot","notify","subscribe"],"mappings":"yGAKO,SAASA,EAA8BC,CAAQ,EACpD,OAAOC,EACL,IAAMC,EAASF,GACf,AAACG,GAAWC,EAAUJ,EAAOG,GAEjC,Q"}
|
package/dist/rxjs.d.ts
ADDED
package/dist/rxjs.js
ADDED
package/dist/rxjs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rxjs.js","sources":["../src/rxjs.ts"],"sourcesContent":["import { useExternal } from \"./external.js\";\nimport type { ObservableState } from \"@slux/rxjs\";\nimport type { Derived } from \"ripple\";\n\nexport function useObservable<T>(source: ObservableState<T>): Derived<T> {\n return useExternal(\n () => source.get(),\n (notify) => source.subscribe(notify),\n );\n}\n"],"names":["useObservable","source","useExternal","notify"],"mappings":"mDAIO,SAASA,EAAiBC,CAA0B,EACzD,OAAOC,EACL,IAAMD,EAAO,GAAG,GAChB,AAACE,GAAWF,EAAO,SAAS,CAACE,GAEjC,Q"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Context } from 'ripple';
|
|
2
|
+
import type { Derived } from 'ripple';
|
|
3
|
+
import type { Scope } from '@slux/core';
|
|
4
|
+
import type { Subscribable } from '@slux/core';
|
|
5
|
+
|
|
6
|
+
export declare function provideScope(scope: Scope): void;
|
|
7
|
+
|
|
8
|
+
export declare const ScopeContext: Context<Scope | null>;
|
|
9
|
+
|
|
10
|
+
export declare function useScopeContext(): Scope | null;
|
|
11
|
+
|
|
12
|
+
/** 在 Ripple 服务端组件初始化中读取显式 Scope,不创建订阅。 */
|
|
13
|
+
export declare function useSignal<T>(source: Subscribable<T>): Derived<T>;
|
|
14
|
+
|
|
15
|
+
export { }
|
package/dist/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../src/server.ts"],"sourcesContent":["import { track } from \"ripple\";\nimport type { Derived } from \"ripple\";\nimport type { Subscribable } from \"@slux/core\";\nimport { useScopeContext } from \"./scope.js\";\n\nexport { ScopeContext, provideScope, useScopeContext } from \"./scope.js\";\n\n/** 在 Ripple 服务端组件初始化中读取显式 Scope,不创建订阅。 */\nexport function useSignal<T>(source: Subscribable<T>): Derived<T> {\n const scope = useScopeContext();\n return track(() => (scope ? scope.get(source) : source.get()));\n}\n"],"names":["useSignal","source","scope","useScopeContext","track"],"mappings":"sFAQO,SAASA,EAAaC,CAAuB,EAClD,IAAMC,EAAQC,IACd,OAAOC,EAAM,IAAOF,EAAQA,EAAM,GAAG,CAACD,GAAUA,EAAO,GAAG,GAC5D,C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Derived } from 'ripple';
|
|
2
|
+
import type { MachineSnapshot } from '@slux/state-machine';
|
|
3
|
+
import type { StateMachine } from '@slux/state-machine';
|
|
4
|
+
|
|
5
|
+
export declare function useMachine<Context, Event extends {
|
|
6
|
+
type: string;
|
|
7
|
+
}, State extends string>(machine: StateMachine<Context, Event, State>): Derived<MachineSnapshot<Context, State>>;
|
|
8
|
+
|
|
9
|
+
export { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.js","sources":["../src/state-machine.ts"],"sourcesContent":["import { useExternal } from \"./external.js\";\nimport type { MachineSnapshot, StateMachine } from \"@slux/state-machine\";\nimport type { Derived } from \"ripple\";\n\nexport function useMachine<Context, Event extends { type: string }, State extends string>(\n machine: StateMachine<Context, Event, State>,\n): Derived<MachineSnapshot<Context, State>> {\n return useExternal(\n () => machine.get(),\n (notify) => machine.subscribe(notify),\n );\n}\n"],"names":["useMachine","machine","useExternal","notify"],"mappings":"mDAIO,SAASA,EACdC,CAA4C,EAE5C,OAAOC,EACL,IAAMD,EAAQ,GAAG,GACjB,AAACE,GAAWF,EAAQ,SAAS,CAACE,GAElC,Q"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Derived } from 'ripple';
|
|
2
|
+
import type { StoreApi } from '@slux/store';
|
|
3
|
+
|
|
4
|
+
export declare function useStore<State extends object>(store: StoreApi<State>): Derived<State>;
|
|
5
|
+
|
|
6
|
+
export declare function useStore<State extends object, Selection>(store: StoreApi<State>, selector: (state: State) => Selection, equalityFn?: (previous: Selection, next: Selection) => boolean): Derived<Selection>;
|
|
7
|
+
|
|
8
|
+
export { }
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useExternal as e}from"./t.js";function t(r,i,n=Object.is){let s;return e(()=>{let e=r.getState();if(!i)return e;if(s&&Object.is(s.state,e))return s.selection;let t=i(e),o=s&&n(s.selection,t)?s.selection:t;return s={state:e,selection:o},o},e=>r.subscribe(e))}export{t as useStore};
|
|
2
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sources":["../src/store.ts"],"sourcesContent":["import type { StoreApi } from \"@slux/store\";\nimport type { Derived } from \"ripple\";\nimport { useExternal } from \"./external.js\";\n\nexport function useStore<State extends object>(store: StoreApi<State>): Derived<State>;\nexport function useStore<State extends object, Selection>(\n store: StoreApi<State>,\n selector: (state: State) => Selection,\n equalityFn?: (previous: Selection, next: Selection) => boolean,\n): Derived<Selection>;\nexport function useStore<State extends object, Selection>(\n store: StoreApi<State>,\n selector?: (state: State) => Selection,\n equalityFn: (previous: Selection, next: Selection) => boolean = Object.is,\n): Derived<State | Selection> {\n let cache: { state: State; selection: Selection } | undefined;\n return useExternal(\n () => {\n const state = store.getState();\n if (!selector) return state;\n if (cache && Object.is(cache.state, state)) return cache.selection;\n const next = selector(state);\n const selection = cache && equalityFn(cache.selection, next) ? cache.selection : next;\n cache = { state, selection };\n return selection;\n },\n (notify) => store.subscribe(notify),\n );\n}\n"],"names":["useStore","store","selector","equalityFn","Object","cache","useExternal","state","next","selection","notify"],"mappings":"mDAUO,SAASA,EACdC,CAAsB,CACtBC,CAAsC,CACtCC,EAAgEC,OAAO,EAAE,EAEzE,IAAIC,EACJ,OAAOC,EACL,KACE,IAAMC,EAAQN,EAAM,QAAQ,GAC5B,GAAI,CAACC,EAAU,OAAOK,EACtB,GAAIF,GAASD,OAAO,EAAE,CAACC,EAAM,KAAK,CAAEE,GAAQ,OAAOF,EAAM,SAAS,CAClE,IAAMG,EAAON,EAASK,GAChBE,EAAYJ,GAASF,EAAWE,EAAM,SAAS,CAAEG,GAAQH,EAAM,SAAS,CAAGG,EAEjF,OADAH,EAAQ,CAAEE,MAAAA,EAAOE,UAAAA,CAAU,EACpBA,CACT,EACA,AAACC,GAAWT,EAAM,SAAS,CAACS,GAEhC,Q"}
|
package/dist/t.js
ADDED
package/dist/t.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"t.js","sources":["../src/external.ts"],"sourcesContent":["import { effect, track } from \"ripple\";\nimport type { Derived } from \"ripple\";\n\nexport function useExternal<T>(read: () => T, subscribe: (notify: () => void) => () => void): Derived<T> {\n // 包裹函数值,避免 track 将用户函数误当作派生计算执行。\n const state = track({ value: read() });\n effect(() => {\n const refresh = () => {\n state.value = { value: read() };\n };\n const unsubscribe = subscribe(refresh);\n refresh();\n return unsubscribe;\n });\n return track(() => state.value.value);\n}\n"],"names":["useExternal","read","subscribe","state","track","effect","refresh","unsubscribe"],"mappings":"2CAGO,SAASA,EAAeC,CAAa,CAAEC,CAA6C,EAEzF,IAAMC,EAAQC,EAAM,CAAE,MAAOH,GAAO,GASpC,OARAI,EAAO,KACL,IAAMC,EAAU,KACdH,EAAM,KAAK,CAAG,CAAE,MAAOF,GAAO,CAChC,EACMM,EAAcL,EAAUI,GAE9B,OADAA,IACOC,CACT,GACOH,EAAM,IAAMD,EAAM,KAAK,CAAC,KAAK,CACtC,Q"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,124 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slux/ripple",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "slux ripple bindings",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"slux",
|
|
7
|
+
"ripple",
|
|
8
|
+
"bindings",
|
|
9
|
+
"state-management"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "itmanyong <itmanyong@gmail.com>",
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/itmanyong/slux.git",
|
|
21
|
+
"directory": "packages/ripple"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"CHANGELOG.md",
|
|
27
|
+
"package.json"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/server.js",
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"browser": "./dist/index.js",
|
|
36
|
+
"default": "./dist/server.js"
|
|
37
|
+
},
|
|
38
|
+
"./atom": {
|
|
39
|
+
"types": "./dist/atom.d.ts",
|
|
40
|
+
"default": "./dist/atom.js"
|
|
41
|
+
},
|
|
42
|
+
"./store": {
|
|
43
|
+
"types": "./dist/store.d.ts",
|
|
44
|
+
"default": "./dist/store.js"
|
|
45
|
+
},
|
|
46
|
+
"./proxy": {
|
|
47
|
+
"types": "./dist/proxy.d.ts",
|
|
48
|
+
"default": "./dist/proxy.js"
|
|
49
|
+
},
|
|
50
|
+
"./package.json": "./package.json",
|
|
51
|
+
"./server": {
|
|
52
|
+
"types": "./dist/server.d.ts",
|
|
53
|
+
"default": "./dist/server.js"
|
|
54
|
+
},
|
|
55
|
+
"./flux": {
|
|
56
|
+
"types": "./dist/flux.d.ts",
|
|
57
|
+
"default": "./dist/flux.js"
|
|
58
|
+
},
|
|
59
|
+
"./state-machine": {
|
|
60
|
+
"types": "./dist/state-machine.d.ts",
|
|
61
|
+
"default": "./dist/state-machine.js"
|
|
62
|
+
},
|
|
63
|
+
"./rxjs": {
|
|
64
|
+
"types": "./dist/rxjs.d.ts",
|
|
65
|
+
"default": "./dist/rxjs.js"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@slux/atom": "^0.1.0",
|
|
70
|
+
"@slux/core": "^0.1.0",
|
|
71
|
+
"@slux/proxy": "^0.1.0",
|
|
72
|
+
"@slux/store": "^0.1.0",
|
|
73
|
+
"ripple": ">=0.6.0",
|
|
74
|
+
"@slux/flux": "^0.1.0",
|
|
75
|
+
"@slux/state-machine": "^0.1.0",
|
|
76
|
+
"@slux/rxjs": "^0.1.0"
|
|
77
|
+
},
|
|
78
|
+
"peerDependenciesMeta": {
|
|
79
|
+
"@slux/atom": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"@slux/proxy": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"@slux/store": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@slux/flux": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"@slux/state-machine": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"@slux/rxjs": {
|
|
95
|
+
"optional": true
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@slux/atom": "0.1.0",
|
|
100
|
+
"@slux/core": "0.1.0",
|
|
101
|
+
"@slux/proxy": "0.1.0",
|
|
102
|
+
"@slux/store": "0.1.0",
|
|
103
|
+
"jsdom": "30.1.3",
|
|
104
|
+
"rstack": "0.9.0",
|
|
105
|
+
"typescript": "7.1.0-beta",
|
|
106
|
+
"ripple": "0.6.1",
|
|
107
|
+
"@slux/flux": "0.1.0",
|
|
108
|
+
"@slux/state-machine": "0.1.0",
|
|
109
|
+
"@slux/rxjs": "0.1.0",
|
|
110
|
+
"rxjs": "7.8.2"
|
|
111
|
+
},
|
|
112
|
+
"dependencies": {
|
|
113
|
+
"@slux/shared": "0.1.0"
|
|
114
|
+
},
|
|
115
|
+
"scripts": {
|
|
116
|
+
"dev": "rs lib -w",
|
|
117
|
+
"build": "rs lib",
|
|
118
|
+
"test": "rs test",
|
|
119
|
+
"lint": "rs lint",
|
|
120
|
+
"fmt": "rs fmt",
|
|
121
|
+
"typecheck": "tsc --noEmit --project tsconfig.typecheck.json",
|
|
122
|
+
"clean": "rm -rf dist node_modules .turbo"
|
|
123
|
+
}
|
|
6
124
|
}
|