@virid/vue 0.0.1

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 ADDED
@@ -0,0 +1,294 @@
1
+ # 🛰️ @virid/vue
2
+
3
+ [中文说明](README.zh.md)
4
+ ---
5
+ **The Bridge between virid Core and Vue.**
6
+
7
+ **_Turning Vue into the most elegant "State Projectionist" for the virid Engine._**
8
+
9
+ ---
10
+
11
+ ## 🧩 Positioning: Governing View Projections
12
+
13
+ `@virid/vue` is by no means just another state management plugin. On the contrary, in the virid worldview: **Vue itself is a plugin for virid.**
14
+
15
+ #### **Core Philosophy: Architectural Sovereignty**
16
+
17
+ The traditional paradigm is "Writing business logic inside Vue"; in virid, **business logic is immortal within the Core**, while Vue is merely a transient projection of that logic onto the browser DOM.
18
+
19
+ - **Logic Sovereignty**: All causality (**Messages**), rule sets (**Systems**), and data sources (**Components**) operate independently of Vue.
20
+ - **View Terminal**: Vue surrenders its authority to mutate state. It is demoted to an intelligent terminal, responsible only for rendering projections and triggering instructions.
21
+
22
+ ---
23
+
24
+ ### 🛡️ How it Empowers the Core
25
+
26
+ If the Core is the brain, `@virid/vue` provides the neurons. It grants the Core the privilege to bridge the chasm between "Logic" and "View":
27
+
28
+ #### **1. Data Manifestation: Reactive Projection**
29
+
30
+ Components within the Core are pure data structures, incapable of driving a UI on their own.
31
+
32
+ - **Enhancement**: Using `@Project` and `@Responsive`, the adapter transforms static Core data into Vue-compatible reactive Proxies via the **Deep Shield**.
33
+ - **Behavior**: When data shifts within the Core, the UI senses it instantly. However, if the UI attempts to mutate the projection directly, the Shield intercepts the violation immediately.
34
+
35
+ #### **2. Perceptual Synergy: Dependency Tethering**
36
+
37
+ The Core is singleton and flat; the UI is tree-like and volatile.
38
+
39
+ - **Enhancement**: By introducing `useController` and `@Inherit`, the adapter allows the Core to "perceive" UI hierarchy. Through the **Global Registry**, logic is no longer rigid—it dynamically establishes "logic tunnels" based on UI mounting states.
40
+ - **Behavior**: Child components maintain weak references to parent logic via `@Inherit`. The flow of logic strictly adheres to the topological structure defined by the Core.
41
+
42
+ #### **3. Causal Closed-Loop: Immediate UI Arbitration**
43
+
44
+ Vue’s native lifecycles and events can often become chaotic.
45
+
46
+ - **Enhancement**: The adapter introduces `@Listener` and `@OnHook`. It ensures UI actions (e.g., clicks, mounting) no longer execute business logic directly but are instead converted into a **ControllerMessage**.
47
+ - **Behavior**: Every UI behavior is standardized as a "Message." The Core acts as an arbiter, judging these messages through **Systems**. This guarantees that even in a Vue environment, every line of logic must pass through the virid Dispatcher's priority queue.
48
+
49
+ ## 🚀 Quick Start: virid in Action
50
+
51
+ In this example, we will implement a classic scenario: **Click a song from a list, send a command through the Controller, and let the System determine the playback logic.**
52
+
53
+ ### 1. Define Data (Component)
54
+
55
+ First, define your data structure in the Core. No need to worry about Vue here.
56
+
57
+ ```typescript
58
+ // PlayerComponent.ts
59
+ import { Component } from "@virid/core";
60
+ import { Responsive } from "@virid/vue";
61
+
62
+ @Component()
63
+ export class PlaylistComponent {
64
+ @Responsive() // Make Core data perceptible to Vue
65
+ public currentSongName: string = "Not Playing";
66
+ }
67
+ ```
68
+
69
+ ### 2. Define Instructions (Message)
70
+
71
+ Define what the user intends to do.
72
+
73
+ ```typescript
74
+ // logic/messages.ts
75
+ import { SingleMessage } from "@virid/core";
76
+
77
+ export class PlaySongMessage extends SingleMessage {
78
+ constructor(public songName: string) {
79
+ super();
80
+ }
81
+ }
82
+ ```
83
+
84
+ ### 3. Define Rules (System)
85
+
86
+ Write business logic in the Core. It acts as the absolute arbiter.
87
+
88
+ ```typescript
89
+ // PlayerSystem.ts
90
+ import { System, Message } from "@virid/core";
91
+ import { PlaySongMessage } from "../messages";
92
+ import { PlaylistComponent } from "../components/PlayerComponent";
93
+
94
+ export class PlayerSystem {
95
+ @System()
96
+ static onPlay(
97
+ @Message(PlaySongMessage) msg: PlaySongMessage,
98
+ state: PlaylistComponent,
99
+ ) {
100
+ // All logic loops are closed here: Mutate data
101
+ state.currentSongName = msg.songName;
102
+ console.log(`Core is now playing: ${msg.songName}`);
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### 4. Bridge the View (Controller & Vue)
108
+
109
+ This is where `@virid/vue` performs its magic, "projecting" logic onto Vue.
110
+
111
+ **Controller (Logic Adapter):**
112
+
113
+ ```typescript
114
+ // logic/controllers/SongController.ts
115
+ import { Controller } from "@virid/core";
116
+ import { Project, Responsive } from "@virid/vue";
117
+ import { PlaylistComponent } from "../components/PlayerComponent";
118
+ import { PlaySongMessage } from "../messages";
119
+
120
+ @Controller()
121
+ export class SongController {
122
+ @Project(PlaylistComponent, (c) => c.currentSongName)
123
+ public playing!: string; // Projection: Read-only mirror of Core data
124
+
125
+ // Define local UI state
126
+ @Responsive()
127
+ public list = ["think of you", "ROCK IN!", "Instant Love"];
128
+
129
+ play(name: string) {
130
+ PlaySongMessage.send(name); // Send instruction instead of mutating data directly
131
+ }
132
+ }
133
+ ```
134
+
135
+ **Vue Component:**
136
+
137
+ ```vue
138
+ <template>
139
+ <div>
140
+ <h3>Now Playing: {{ ctrl.playing }}</h3>
141
+ <ul>
142
+ <li v-for="s in ctrl.list" :key="s" @click="ctrl.play(s)">
143
+ Play: {{ s }}
144
+ </li>
145
+ </ul>
146
+ </div>
147
+ </template>
148
+
149
+ <script setup lang="ts">
150
+ import { useController } from "@virid/vue";
151
+ import { SongController } from "./logic/controllers/SongController";
152
+
153
+ // All the magic happens here: bind the Controller to the Vue lifecycle
154
+ const ctrl = useController(SongController);
155
+ </script>
156
+ ```
157
+
158
+ ## 📘 virid Core Concepts: The "Layman's Legend" Edition
159
+
160
+ ### 1. `@Project` —— The One-Way Lens (The Projector)
161
+
162
+ - **Plain English**: Imagine installing a one-way peephole on the window of the Core's engine room from the UI side.
163
+ - **What it does**: The `playing` property in a Controller doesn't store data; it’s a **real-time shadow** of `currentSongName` inside the `PlaylistComponent`.
164
+ - **The Law**: Since it’s a projection, you cannot change the entity by modifying the shadow. If you try `this.playing = "New Song"`, the framework will shout: "Read-only! Want a change? Submit a **Message**."
165
+
166
+ ### 2. `@Responsive` —— The Reactive Neuron
167
+
168
+ - **Plain English**: Giving a standard TypeScript class a shot of "Vue Adrenaline."
169
+ - **What it does**: Core classes are usually cold, static data structures. With this, when a **System** modifies a value deep in the Core, the change flows through the `@Project` pipeline and **instantly lights up** every Vue component referencing it.
170
+ - **The Law**: It is the "sole base station" for the UI to perceive logical shifts.
171
+
172
+ ### 3. `useController` —— The Logical Anchor (The Tether)
173
+
174
+ - **Plain English**: Dropping an anchor into the Vue ocean to tether a "Logic Beast" from the virid Core.
175
+ - **What it does**: The Vue component says, "I only care about styling, not business logic." It hires a representative (the Controller) through `useController`. This proxy is retrieved from the **IoC Container**, appearing when the component mounts and vanishing when it unmounts.
176
+ - **The Law**: This is the **only official gateway** between the Vue world and the virid Core world.
177
+
178
+ ### 4. `Message.send` —— Activating Causality (The Formal Petition)
179
+
180
+ - **Plain English**: The UI layer completely surrenders its "executive power" and can only send a formal courier to request work from the Core.
181
+ - **What it does**: Forget `count++` in Vue. Now you can only submit a petition: "I suggest incrementing the count by 1."
182
+ - **Why?**: Because the **System (The Arbiter)** will intercept this message to check rules: Do you have permission? Is this song in the database? Only when the Arbiter nods does the data change and the UI react.
183
+
184
+ ### 5. `@Inherit` —— Logical Parasitism (The Wireless Receiver)
185
+
186
+ - **Plain English**: It allows child components to "parasitize" and absorb nutrients (data) from parent components or other Controllers from a distance.
187
+ - **What it does**: `SongController` doesn't need props to get the playlist. Use `@Inherit(PlaylistController, 'playlist')`, and it automatically locates the parent in the **Global Registry** and builds a private data tunnel.
188
+ - **The Law**: This tunnel is a "Weak Reference" with a "Shield." You can look at the parent's data, but you can't touch (mutate) it.
189
+
190
+ ### 6. `@Env` —— The Identity Tag (The Birth Certificate)
191
+
192
+ - **Plain English**: A small note tucked into a component's pocket at birth (from the Vue side) saying, "This is who you are."
193
+ - **What it does**: Pass `:index="index"` in a Vue template and receive it via `@Env() public index!: number` in the Controller. It helps logic instances know their physical position in the UI hierarchy (e.g., "I am the 5th item in the list").
194
+ - **The Law**: It’s a metadata marker. It reminds you: "This is air-dropped from the external Vue environment—don't try to change it here."
195
+
196
+ ### 7. `@Listener` —— Intent Radar (The Relay Station)
197
+
198
+ - **Plain English**: A parent component installs a monitor at home, specifically listening for "local signals" emitted by its children.
199
+ - **What it does**: When a child emits a `SongControllerMessage`, the parent's `@Listener` catches it instantly. It translates these fragmented UI actions into **Global Domain Messages** that the entire Core engine can understand.
200
+ - **The Law**: It only handles "Translation" and "Forwarding." The final judgment remains the sovereignty of the **System**.
201
+
202
+ ### 8. `@Watch` —— The Action Scout
203
+
204
+ - **Plain English**: Staring at a specific piece of data and immediately executing a pre-planned "side effect" the moment it changes.
205
+ - **What it does**: When the song changes, you might need to trigger a Vue Router jump or a browser notification. Tasks that aren't core business logic but belong to "UI behavior" go here.
206
+ - **The Law**: It can scout both Core Components and local Controller states. It’s the trigger for UI ripples after logic shifts.
207
+
208
+ ### 9. `@Use` —— The Toolbelt (The External Plugin)
209
+
210
+ - **Plain English**: Lawfully borrowing "magic weapons" from the Vue ecosystem (like `useRouter` or `useI18n`) while inside the logic layer.
211
+ - **What it does**: Through `@Use(() => useRouter())`, your Controller gains the ability to navigate without having to pass router instances down through ten layers of components.
212
+ - **The Law**: It ensures dependencies are **Lazy-Loaded**; the tool is only sought when the Controller is actually activated.
213
+
214
+ ### 10. `@OnHook` —— The Lifecycle Diver
215
+
216
+ - **Plain English**: Lurking deep in the Vue lifecycle, waiting for the "water level" (mount/unmount) to reach a certain point before jumping out to work.
217
+
218
+ - **What it does**: Use `@OnHook('onSetup')` to fetch the initial playlist from a server as soon as the Controller is initialized.
219
+
220
+ - **The Law**: It ensures that while your Controller "lives" in the virid Core philosophy, it dances perfectly to the rhythm of the Vue stage.
221
+
222
+ ---
223
+
224
+ ## ⚡ The Chain of Causality
225
+
226
+ 1. **User Action**: User clicks a `<li>` in the Vue interface.
227
+ 2. **Controller Relay**: Controller calls `play(name)`, executing `PlaySongMessage.send(name)`.
228
+ 3. **Core Dispatch**: The Message enters the Core. Since it inherits from `SingleMessage`, the dispatcher queues it automatically.
229
+ 4. **Arbitration (System)**: `PlayerSystem` wakes up, receives the message packet, and modifies the data in `PlaylistComponent`.
230
+ 5. **Data Projection**: Because the data is marked `@Responsive` and the Controller is marked `@Project`, the shadow variable `playing` updates automatically.
231
+ 6. **UI Vibration**: Vue detects the change, re-renders the interface, and the user sees the "Now Playing" status update.
232
+
233
+ ---
234
+
235
+ ## 💡 Why Is This More Elegant?
236
+
237
+ - **Zero-IQ UI**: Vue components contain no decision-making logic; they simply "click and report."
238
+ - **Extreme Data Security**: You cannot execute `state.name = 'xxx'` in a component. Everything must go through a Message, making your logic flow **100% traceable**.
239
+ - **Developer Experience**: You still write the Vue templates you love, but you are backed by a rigorous, battle-hardened Core engine.
240
+
241
+ ## Partial data flow chart in the example
242
+
243
+ ```mermaid
244
+ graph TD
245
+ %% 视图层
246
+ subgraph ViewLayer ["Vue View Layer"]
247
+ SUI(["Song.vue"]) -->|Click| SC[SongController]
248
+ end
249
+
250
+ %% 适配层:装饰器魔法与消息路由
251
+ subgraph Adapter ["virid Vue Adapter"]
252
+ direction TB
253
+ SC -->|"SongControllerMessage.send(this.index)"| SCM["SongControllerMessage (Local)"]
254
+
255
+ %% 核心拦截逻辑
256
+ SCM -->|"@Listener"| PC[PlaylistController]
257
+
258
+ subgraph Magic ["Logic Decoration"]
259
+ SC -- "@Env" --> E["index (From Context)"]
260
+ SC -- "@Inherit" --> I["playlist (From PC)"]
261
+ SC -- "@Project" --> P["song (Computed by index)"]
262
+ end
263
+
264
+ PC -->|"PlaySongMesage.send(song)"| PSM["PlaySongMesage (Global Domain)"]
265
+ end
266
+
267
+ %% 核心引擎:确定性处理
268
+ subgraph Core ["virid Core Engine"]
269
+ direction TB
270
+ PSM --> Hub["EventHub (Queueing)"]
271
+ Hub -->|"Tick / Buffer Flip"| Active["Active Pool"]
272
+
273
+ subgraph Execution ["System Execution"]
274
+ Active --> Sys["Player.playThisSong (Static)"]
275
+ DI[("(Inversify Container)")] -.->|Inject| PLC["PlaylistComponent"]
276
+ DI -.->|Inject| PCMP["PlayerComponent"]
277
+ Sys -->|"Update currentSong"| PLC
278
+ Sys -->|"Call player.play()"| PCMP
279
+ end
280
+ end
281
+
282
+ %% 响应式回馈
283
+ subgraph Feedback ["Reactive Feedback Loop"]
284
+ PLC -->|"@Responsive"| Mirror["State Mirror"]
285
+ Mirror -->|"@Project / @Watch"| HPC["HomePageController"]
286
+ HPC -->|Sync| HUI(["HomePage.vue"])
287
+ end
288
+
289
+ %% 样式
290
+ style Core fill:#f9f9f9,stroke:#333,stroke-width:2px
291
+ style Adapter fill:#e1f5fe,stroke:#01579b
292
+ style ViewLayer fill:#fff,stroke:#ef6c00
293
+ style DI fill:#e8f5e9,stroke:#2e7d32
294
+ ```
package/README.zh.md ADDED
@@ -0,0 +1,279 @@
1
+ # @virid/vue
2
+
3
+ > **The Bridge between virid Core and Vue.**
4
+ >
5
+ > **使 Vue 成为 virid 引擎最华丽的“状态投影仪”。**
6
+
7
+ ## 🧩 定位:统治视图投影
8
+
9
+ `@virid/vue` 绝非一个普通的 Vue 状态管理插件。相反,在 virid 的世界观里:**Vue 才是 virid 的插件。**
10
+
11
+ ### 核心哲学:架构主权
12
+
13
+ 传统的开发模式是“在 Vue 中写业务”;而在 virid 中,**业务在 Core 中永生**,Vue 仅仅是业务逻辑在浏览器 DOM 上的一层**临时投影**。
14
+
15
+ - **逻辑主权**:所有的因果律(Message)、规则集(System)和数据源(Component)都独立于 Vue 运行。
16
+ - **视图终端**:Vue 失去了对状态的修改权。它被降级为一个智能终端,仅负责接收投影并触发指令。
17
+
18
+ ### 🛡️ 它为 Core 增加了什么能力?
19
+
20
+ 如果说 Core 是大脑,那么 `@virid/vue` 就为大脑接入了神经元。它赋予了 Core 跨越“逻辑与视图”鸿沟的特权:
21
+
22
+ #### 1. **数据现世化:响应式投影 (Reactive Projection)**
23
+
24
+ Core 里的 `Component` 只是纯粹的数据结构,本无法驱动 UI。
25
+
26
+ - **能力增强**:通过 `@Project` 和 `@Responsive`,插件将 Core 内部的静态数据通过 **Deep Shield (深度护盾)** 转化为 Vue 的响应式 Proxy。
27
+ - **能力表现**:数据在 Core 中发生偏移,UI 自动感应;但 UI 试图直接修改投影时,护盾会立即拦截。
28
+
29
+ #### 2. **感知协同:跨层级依赖系留 (Dependency Tethering)**
30
+
31
+ Core 是单例且扁平的,而 UI 是树状且多变的。
32
+
33
+ - **能力增强**:插件引入了 `useController` 和 `@Inherit`。它让 Core 具备了“感知 UI 结构”的能力。通过 **Global Registry**,逻辑不再死板,它能根据 UI 的挂载情况动态建立“逻辑隧道”。
34
+ - **能力表现**:子组件通过 `@Inherit` 弱引用父级逻辑,逻辑的流动方向严丝合缝地遵循 Core 定义的拓扑结构。
35
+
36
+ #### 3. **因果闭环:UI 逻辑的即时裁决 (Immediate UI Arbitration)**
37
+
38
+ Vue 自身的生命周期和事件通常是混乱的。
39
+
40
+ - **能力增强**:插件引入了 `@Listener` 和 `@OnHook`。它让 UI 的动作(如点击、挂载)不再直接运行业务,而是转化为一条 `ControllerMessage`。
41
+ - **能力表现**:一切 UI 行为都被规范化为“消息”。Core 像裁判一样通过 `System` 裁决这些消息。这确保了即便是在 Vue 环境下,每一行逻辑的执行也必须经过 virid 调度中心的优先级排队。
42
+
43
+ ## 🚀 快速上手:virid 实战示例
44
+
45
+ 在这个例子中,我们将实现:**点击列表中的一首歌,通过 Controller 发送指令,最后由 System 决定播放逻辑。**
46
+
47
+ ### 1. 定义数据 (Component)
48
+
49
+ 首先,在 Core 中定义你的数据结构。这里不需要关心 Vue。
50
+
51
+ ```vue
52
+ //PlayerComponent.ts import { Component } from '@virid/core' import { Responsive
53
+ } from '@virid/vue' @Component() export class PlaylistComponent { @Responsive()
54
+ // 让 Core 的数据在 Vue 里可感应 public currentSongName: string = '未播放' }
55
+ ```
56
+
57
+ ### 2. 定义指令 (Message)
58
+
59
+ 定义用户想做什么。
60
+
61
+ ```
62
+ // logic/messages.ts
63
+ import { SingleMessage } from '@virid/core'
64
+
65
+ export class PlaySongMessage extends SingleMessage {
66
+ constructor(public songName: string) { super() }
67
+ }
68
+ ```
69
+
70
+ ### 3. 定义规则 (System)
71
+
72
+ 在 Core 中编写业务逻辑。它是绝对的裁判。
73
+
74
+ ```
75
+ // PlayerSystem.ts
76
+ import { System, Message } from '@virid/core'
77
+ import { PlaySongMessage } from '../messages'
78
+ import { PlaylistComponent } from '../components/PlayerComponent'
79
+
80
+ export class PlayerSystem {
81
+ @System()
82
+ static onPlay(@Message(PlaySongMessage) msg: PlaySongMessage, state: PlaylistComponent) {
83
+ // 所有的逻辑闭环在这里:修改数据
84
+ state.currentSongName = msg.songName
85
+ console.log(`Core 正在播放: ${msg.songName}`)
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### 4. 接入视图 (Controller & Vue)
91
+
92
+ 这是 `@virid/vue` 展现魔力的地方。它把逻辑“投影”给 Vue。
93
+
94
+ **Controller (逻辑适配器):**
95
+
96
+ ```
97
+ // logic/controllers/SongController.ts
98
+ import { Controller } from '@virid/core'
99
+ import { Project } from '@virid/vue'
100
+ import { PlaylistComponent } from '../components/PlayerComponent'
101
+ import { PlaySongMessage } from '../messages'
102
+
103
+ @Controller()
104
+ export class SongController {
105
+ @Project(PlaylistComponent, (c) => c.currentSongName)
106
+ public playing!: string // 投影:只读 Core 的数据
107
+ //定义自己的数据
108
+ @Responsive()
109
+ public list = ['think of you', 'ROCK IN!', 'Instant Love']
110
+
111
+ play(name: string) {
112
+ PlaySongMessage.send(name) // 发送指令,而不是直接改数据
113
+ }
114
+ }
115
+ ```
116
+
117
+ **Vue 组件:**
118
+
119
+ ```
120
+ <template>
121
+ <div>
122
+ <h3>当前播放:{{ ctrl.playing }}</h3>
123
+ <ul>
124
+ <li v-for="s in ctrl.list" @click="ctrl.play(s)">点击播放:{{ s }}</li>
125
+ </ul>
126
+ </div>
127
+ </template>
128
+
129
+ <script setup lang="ts">
130
+ import { useController } from '@virid/vue'
131
+ import { SongController } from './logic/controllers/SongController'
132
+ //所有的魔法在这里发生
133
+ const ctrl = useController(SongController)
134
+ </script>
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 📘 virid 核心概念:通俗演义版
140
+
141
+ ### 1. `@Project` —— 单向透镜(投影仪)
142
+
143
+ - **白话解释**:它就像是 UI 层在 Core 层卧室窗户上装的一个**单向猫眼**。
144
+ - **它在做什么**:Controller 里的 `playing` 属性本身是不存数据的,它只是 `PlaylistComponent` 中 `currentSongName` 的一个**实时影子**。
145
+ - **潜规则**:既然是投影,你就**不能通过改影子来改变实体**。如果你在 Controller 里尝试 `this.playing = "新歌"`,框架会警告你:这是只读的!想改?去发 `Message`。
146
+
147
+ ### 2. `@Responsive` —— 响应式神经元
148
+
149
+ - **白话解释**:给普通的 TypeScript 类打一针“Vue 兴奋剂”。
150
+ - **它在做什么**:原本 Core 里的类只是冷冰冰的数据结构。加了它,当 System 在底层修改 `state.currentSongName` 时,这个变化会顺着 `@Project` 的管道,**瞬间点亮**所有正在引用这个数据的 Vue 组件。
151
+ - **潜规则**:它是 UI 能感知到逻辑变化的“唯一通信基站”。
152
+
153
+ ### 3. `useController` —— 逻辑锚点(牵引绳)
154
+
155
+ - **白话解释**:在 Vue 的海洋里,扔下一个锚点,把 Core 里的逻辑怪兽“牵”过来。
156
+ - **它在做什么**:Vue 组件说:“我只想管样式,不想管怎么播放。”于是它通过 `useController` 找来了一个代办人(Controller)。这个代办人已经在 IOC 容器里准备好了,组件挂载它就出现,组件销毁它就隐退。
157
+ - **潜规则**:它是 Vue 世界与 virid Core 世界的**唯一官方接口**。
158
+
159
+ ### 4. `Message.send` —— 因果律启动(递交申请书)
160
+
161
+ - **白话解释**:UI 层彻底丧失“执法权”,只能通过**发快递**的方式建议 Core 层干活。
162
+ - **它在做什么**:以前你在 Vue 里写 `count++`;现在你只能发送一个“我想让 count 加 1”的申请书。
163
+ - **为什么要这么做**:因为 System(裁判)会拦截这个消息,检查你有没有权限播放、这首歌在不在库里。只有裁判(System)点头了,数据才会变,UI 才会跳。
164
+
165
+ ### 5. `@Inherit` —— 逻辑寄生(无线电接收机)
166
+
167
+ - **白话解释**:它让子组件像“寄生虫”一样,隔空吸取父组件(或其他 Controller)的营养。
168
+ - **它在做什么**:你的 `SongController` 不需要手动传 props 拿歌单,只要用 `@Inherit(PlaylistController, 'playlist')`,它就能自动从全局注册表中定位到父组件,并建立一条数据隧道。
169
+ - **潜规则**:这条隧道是“弱引用”且带有“护盾”的。即使你拿到了父级的数据,你也只能看,不能碰(只读)。
170
+
171
+ ### 6. `@Env` —— 身份铭牌(出生证明)
172
+
173
+ - **白话解释**:组件出生时,外面(Vue)塞给它的一张写着“你是谁”的小纸条。
174
+ - **它在做什么**:在 Vue 模板里传 `:index="index"`,在 Controller 里用 `@Env() public index!: number` 接收。它解决了逻辑实例如何获知自己在 UI 层级中的物理位置(比如是列表中的第几个)。
175
+ - **潜规则**:它只是一个元数据标记,提醒你:这个数据是从外部 Vue 环境“空投”进来的,不要在逻辑层乱改。
176
+
177
+ ### 7. `@Listener` —— 意图雷达(中转站)
178
+
179
+ - **白话解释**:父组件在家里装了个监控,专门盯着子组件发出的“局部信号”。
180
+ - **它在做什么**:当子组件发出了一个 `SongControllerMessage`,父组件的 `@Listener` 会瞬间捕捉到。它负责把这些零碎的小动作,翻译成能惊动整个 Core 引擎的全局大动作。
181
+ - **潜规则**:它只负责“翻译”和“转发”,具体的判决依然要交给 `System`。
182
+
183
+ ### 8. `@Watch` —— 动作侦察兵
184
+
185
+ - **白话解释**:盯着某块数据,一旦它变了,就立刻执行一套预定的“副作用”。
186
+ - **它在做什么**:比如歌曲变了,你要调用 Vue Router 跳个转,或者给浏览器弹个通知。这类不属于核心业务逻辑、但属于 UI 表现的需求,交给它。
187
+ - **潜规则**:它既能看 Core 里的组件数据,也能看 Controller 里的本地数据。它是逻辑变动后触发 UI 涟漪的开关。
188
+
189
+ ### 9. `@Use` —— 工具包(外挂模组)
190
+
191
+ - **白话解释**:在逻辑层合法地借用 Vue 生态里的“魔法武器”(如 `useRouter`, `useI18n`)。
192
+ - **它在做什么**:通过 `@Use(() => useRouter())`,让你的 Controller 拥有了操作路由的能力,而不需要在 Vue 组件里传来传去。
193
+ - **潜规则**:它确保了你的依赖项是延迟加载的,只有在 Controller 真正被激活时才会去寻找这些工具。
194
+
195
+ ### 10. `@OnHook` —— 生命周期潜水员
196
+
197
+ - **白话解释**:潜伏在 Vue 的生命周期里,等水位到了(比如挂载或销毁)就跳出来干活。
198
+ - **它在做什么**:比如 `@OnHook('onSetup')`,让你在 Controller 初始化时去服务器拉取初始歌单。
199
+ - **潜规则**:它让你的 Controller 虽然住在 Core 的思想里,但却能精准踩上 Vue 舞台的节拍。
200
+
201
+ ---
202
+
203
+ ## ⚡ 这一套流程的“因果链条”
204
+
205
+ 1. **用户动作**:用户在 Vue 界面点了一下 `<li>`。
206
+ 2. **Controller 传话**:Controller 调用 `play(name)` 方法,执行 `PlaySongMessage.send(name)`。
207
+ 3. **核心调度**:`Message` 飞进 Core,由于它继承自 `SingleMessage`,调度器会自动排队。
208
+ 4. **裁判决策 (System)**:`PlayerSystem` 被唤醒,它拿到消息包,修改了 `PlaylistComponent` 里的数据。
209
+ 5. **数据投影**:由于数据标记了 `@Responsive`,且 Controller 标记了 `@Project`,影子变量 `playing` 自动更新。
210
+ 6. **UI 震荡**:Vue 发现数据变了,重新渲染界面,用户看到“当前播放”变了。
211
+
212
+ ---
213
+
214
+ ### 💡 为什么这样写更优雅?
215
+
216
+ 1. **UI 零智商**:Vue 组件里没有任何判断逻辑,它只负责“点一下发个消息”。
217
+ 2. **数据极度安全**:组件里不能直接执行 `state.name = 'xxx'`,必须通过消息,这让你的逻辑流 100% 可追踪。
218
+ 3. **开发体验**:你依然在写熟悉的 Vue 模板,但你背后站着一整个严谨的 Core 引擎。
219
+
220
+ ## 🌌 结语:让 UI 回归投影,让逻辑重获自由
221
+
222
+ 在传统的开发模式中,业务逻辑往往沦为 UI 框架的附庸,散落在组件的生命周期与副作用钩子中。**virid** 的诞生,是为了重新划定边界。
223
+
224
+ 核心业务逻辑应该是**纯粹、稳固且可测试的**。它不应被特定的 UI 渲染管线所绑架,而应像星辰般独立运行在自己的轨道上。通过剥离 UI 的主权,virid 赋予了开发者构建跨端、高鲁棒性复杂系统的能力。
225
+
226
+ ## 示例中的部分数据流向图
227
+
228
+ ```mermaid
229
+ graph TD
230
+ %% 视图层
231
+ subgraph ViewLayer ["Vue View Layer"]
232
+ SUI(["Song.vue"]) -->|Click| SC[SongController]
233
+ end
234
+
235
+ %% 适配层:装饰器魔法与消息路由
236
+ subgraph Adapter ["virid Vue Adapter"]
237
+ direction TB
238
+ SC -->|"SongControllerMessage.send(this.index)"| SCM["SongControllerMessage (Local)"]
239
+
240
+ %% 核心拦截逻辑
241
+ SCM -->|"@Listener"| PC[PlaylistController]
242
+
243
+ subgraph Magic ["Logic Decoration"]
244
+ SC -- "@Env" --> E["index (From Context)"]
245
+ SC -- "@Inherit" --> I["playlist (From PC)"]
246
+ SC -- "@Project" --> P["song (Computed by index)"]
247
+ end
248
+
249
+ PC -->|"PlaySongMesage.send(song)"| PSM["PlaySongMesage (Global Domain)"]
250
+ end
251
+
252
+ %% 核心引擎:确定性处理
253
+ subgraph Core ["virid Core Engine"]
254
+ direction TB
255
+ PSM --> Hub["EventHub (Queueing)"]
256
+ Hub -->|"Tick / Buffer Flip"| Active["Active Pool"]
257
+
258
+ subgraph Execution ["System Execution"]
259
+ Active --> Sys["Player.playThisSong (Static)"]
260
+ DI[("(Inversify Container)")] -.->|Inject| PLC["PlaylistComponent"]
261
+ DI -.->|Inject| PCMP["PlayerComponent"]
262
+ Sys -->|"Update currentSong"| PLC
263
+ Sys -->|"Call player.play()"| PCMP
264
+ end
265
+ end
266
+
267
+ %% 响应式回馈
268
+ subgraph Feedback ["Reactive Feedback Loop"]
269
+ PLC -->|"@Responsive"| Mirror["State Mirror"]
270
+ Mirror -->|"@Project / @Watch"| HPC["HomePageController"]
271
+ HPC -->|Sync| HUI(["HomePage.vue"])
272
+ end
273
+
274
+ %% 样式
275
+ style Core fill:#f9f9f9,stroke:#333,stroke-width:2px
276
+ style Adapter fill:#e1f5fe,stroke:#01579b
277
+ style ViewLayer fill:#fff,stroke:#ef6c00
278
+ style DI fill:#e8f5e9,stroke:#2e7d32
279
+ ```
@@ -0,0 +1,63 @@
1
+ import { SingleMessage, ViridPlugin } from '@virid/core';
2
+ export { CCSSystemContext } from '@virid/core';
3
+ import { WatchOptions } from 'vue';
4
+
5
+ declare abstract class ControllerMessage extends SingleMessage {
6
+ }
7
+
8
+ /**
9
+ * @description:实现Watch
10
+ * 用法:@Watch('a.b.c') 或 @Watch(instance => instance.a.b.c)
11
+ */
12
+ declare function Watch<T>(source: (instance: T) => any, options?: WatchOptions): any;
13
+ declare function Watch<C>(component: new (...args: any[]) => C, source: (comp: C) => any, options?: WatchOptions): any;
14
+ /**
15
+ * @description: 实现数据投影
16
+ * 用法:@Project() 或 @Project('a.b.c')
17
+ */
18
+ declare function Project<T>(source: (instance: T) => any): any;
19
+ declare function Project<C>(component: new (...args: any[]) => C, source: (comp: C) => any): any;
20
+ /**
21
+ * @description: 给数据增加响应式
22
+ * 用法:@Responsive()
23
+ */
24
+ declare function Responsive(shallow?: boolean): (target: any, propertyKey: string) => void;
25
+ /**
26
+ * @description: 声明式生命周期钩子
27
+ * 用法:@OnHook("onMounted")
28
+ */
29
+ declare function OnHook(hookName: "onMounted" | "onUnmounted" | "onUpdated" | "onActivated" | "onDeactivated" | "onSetup"): (target: any, methodName: string) => void;
30
+ /**
31
+ * @description: 万能 Hook 注入装饰器
32
+ * 用法:@Use(() => useRoute()) public route!: RouteLocationNormalized
33
+ */
34
+ declare function Use(hookFactory: () => any): (target: any, propertyKey: string) => void;
35
+ /**
36
+ * @description: Inherit注入装饰器
37
+ * 用法:@Inherit(Contronller,(instance) => instance.xxxx) public data!: SomeType
38
+ */
39
+ declare function Inherit<T>(token: new (...args: any[]) => T, id: string, selector?: (instance: T) => any): (target: any, propertyKey: string) => void;
40
+ /**
41
+ * @description: 标记一个属性是从外部环境(context)注入的
42
+ * 纯元数据标记,什么也不干,方便后期做自动化文档或 TS 类型提示
43
+ */
44
+ declare function Env(): (_target: any, _propertyKey: string) => void;
45
+ /**
46
+ * @description: Listener 装饰器 - 标记 Controller 的成员方法为消息监听器
47
+ * 模仿 Bevy 的即时响应机制,但严格限制其只能处理 UI 逻辑
48
+ */
49
+ declare function Listener<T extends ControllerMessage>(eventClass: new (...args: any[]) => T, priority?: number, single?: boolean): (target: any, propertyKey: string) => void;
50
+
51
+ /**
52
+ * @description: vue的hooks适配器,注入IOC容器中的Controller实例,并挂在vue的各种方法
53
+ * @param token
54
+ * @return {*}
55
+ */
56
+ declare function useController<T>(token: new (...args: any[]) => T, options?: {
57
+ id?: string;
58
+ context?: any;
59
+ }): T;
60
+
61
+ declare const VuePlugin: ViridPlugin;
62
+
63
+ export { ControllerMessage, Env, Inherit, Listener, OnHook, Project, Responsive, Use, VuePlugin, Watch, useController };