cabloy 5.1.58 → 5.1.60
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/.claude/skills/cabloy-contract-loop/SKILL.md +16 -0
- package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +26 -0
- package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +144 -0
- package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +18 -0
- package/.claude/skills/cabloy-resource-field-update/SKILL.md +267 -0
- package/.claude/skills/cabloy-resource-field-update/evals/evals.json +53 -0
- package/.claude/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +102 -0
- package/.claude/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +120 -0
- package/.claude/skills/cabloy-resource-field-update/references/follow-up-checklist.md +80 -0
- package/.claude/skills/cabloy-resource-field-update/references/verification-checklist.md +97 -0
- package/.github/workflows/docs-pages.yml +2 -0
- package/.github/workflows/vona-cov-pg.yml +2 -0
- package/.github/workflows/vona-test-crud.yml +4 -2
- package/.github/workflows/vona-test-mysql.yml +2 -0
- package/.github/workflows/vona-test-pg.yml +2 -0
- package/.github/workflows/vona-test-sqlite3.yml +2 -0
- package/.github/workflows/vona-tsc.yml +2 -0
- package/.github/workflows/zova-ui.yml +2 -0
- package/.gitignore +0 -4
- package/CHANGELOG.md +41 -0
- package/CLAUDE.md +2 -0
- package/README.md +15 -0
- package/cabloy-docs/.vitepress/config.mjs +43 -0
- package/cabloy-docs/ai/class-placement-rule.md +2 -0
- package/cabloy-docs/ai/cli-to-skill-map.md +7 -0
- package/cabloy-docs/ai/future-skill-roadmap.md +17 -2
- package/cabloy-docs/backend/bean-scene-authoring.md +350 -0
- package/cabloy-docs/backend/cli.md +26 -1
- package/cabloy-docs/backend/foundation.md +28 -3
- package/cabloy-docs/backend/introduction.md +8 -0
- package/cabloy-docs/backend/service-guide.md +2 -0
- package/cabloy-docs/backend/websocket-call-flow.md +435 -0
- package/cabloy-docs/backend/websocket-guide.md +455 -0
- package/cabloy-docs/backend/websocket-protocol-guide.md +381 -0
- package/cabloy-docs/backend/websocket-usage-guide.md +356 -0
- package/cabloy-docs/frontend/bean-scene-authoring.md +372 -0
- package/cabloy-docs/frontend/behavior-guide.md +449 -0
- package/cabloy-docs/frontend/cli.md +12 -0
- package/cabloy-docs/frontend/introduction.md +5 -0
- package/cabloy-docs/frontend/ioc-and-beans.md +10 -9
- package/cabloy-docs/frontend/router-tabs-admin-web-comparison.md +206 -0
- package/cabloy-docs/frontend/router-tabs-introduction.md +106 -0
- package/cabloy-docs/frontend/router-tabs-mechanism.md +469 -0
- package/cabloy-docs/frontend/router-tabs-overview.md +227 -0
- package/cabloy-docs/frontend/router-tabs-route-meta-cookbook.md +343 -0
- package/cabloy-docs/frontend/ssr-architecture-overview.md +211 -0
- package/cabloy-docs/frontend/ssr-build-deploy-guide.md +308 -0
- package/cabloy-docs/frontend/ssr-review-checklist.md +184 -0
- package/cabloy-docs/frontend/ssr-troubleshooting-guide.md +301 -0
- package/cabloy-docs/fullstack/framework-performance.md +3 -3
- package/cabloy-docs/fullstack/introduction.md +29 -0
- package/cabloy-docs/fullstack/quickstart.md +7 -1
- package/cabloy-docs/fullstack/tutorial-1-first-module.md +111 -0
- package/cabloy-docs/fullstack/tutorial-2-first-crud.md +122 -0
- package/cabloy-docs/fullstack/tutorial-3-frontend-metadata-sharing.md +131 -0
- package/cabloy-docs/fullstack/tutorial-4-custom-level-renderers.md +119 -0
- package/cabloy-docs/fullstack/tutorial-5-backend-contract-sharing.md +144 -0
- package/cabloy-docs/fullstack/tutorial-6-one-contract-four-uses.md +168 -0
- package/cabloy-docs/fullstack/tutorials-overview.md +179 -0
- package/cabloy-docs/index.md +4 -3
- package/cabloy-docs/reference/bean-scene-boilerplates.md +73 -0
- package/cabloy-docs/reference/cli-reference.md +2 -0
- package/package.json +6 -2
- package/scripts/init.ts +18 -2
- package/scripts/upgrade.ts +6 -0
- package/vona/packages-cli/cabloy-cli/package.json +2 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/cli.create.module.ts +4 -0
- package/vona/packages-utils/zod-query/package.json +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +133 -1088
- package/vona/pnpm-workspace.yaml +0 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/assets/static/img/vona.svg +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-permission/src/bean/bean.permission.ts +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-upload/package.json +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/package.original.json +1 -1
- package/zova/packages-cli/cli/package.json +3 -3
- package/zova/packages-cli/cli-set-front/cli/templates/init/icon/boilerplate/icons/default/zova.svg +1 -1
- package/zova/packages-cli/cli-set-front/package.json +3 -3
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.create.module.ts +4 -0
- package/zova/packages-cli/cli-set-front/src/lib/command/create.bean.ts +5 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-utils/zova-vite/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +2 -2
- package/zova/pnpm-lock.yaml +284 -1313
- package/zova/pnpm-workspace.yaml +0 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/cabloy.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/vona.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/icons/social/zova.svg +1 -1
- package/zova/src/suite/a-home/modules/home-icon/src/.metadata/icons/groups/social.svg +3 -3
- package/zova/src/suite/cabloy-basic/modules/basic-select/src/component/formFieldSelect/controller.tsx +9 -0
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +66 -16
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-routertabs/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-routertabs/src/model/tabs.ts +60 -18
- package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableActionRow/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/cli/tableCell/boilerplate/{{sceneName}}.{{beanName}}.tsx_ +6 -1
- package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-zod/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +3 -3
- package/zova/src/suite-vendor/a-zova/package.json +5 -5
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
# Behavior Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how **Behavior** works in Zova and how to use it to add reusable render-time capabilities around components and native elements.
|
|
4
|
+
|
|
5
|
+
Behavior is a built-in frontend bean scene in Zova. It is implemented on top of the onion-composition system, so a Behavior is not only a helper function or a plain Vue wrapper. It is a structured bean that can participate in composition, lifecycle, host-scoped injection, and reactive reloading.
|
|
6
|
+
|
|
7
|
+
## What a Behavior is
|
|
8
|
+
|
|
9
|
+
A Zova Behavior is a render-time middleware bean.
|
|
10
|
+
|
|
11
|
+
A Behavior can:
|
|
12
|
+
|
|
13
|
+
- receive render props
|
|
14
|
+
- adjust those props before rendering continues
|
|
15
|
+
- wrap the rendered vnode
|
|
16
|
+
- compose with other behaviors in a stable order
|
|
17
|
+
- react to option changes through bean lifecycle
|
|
18
|
+
|
|
19
|
+
The public decorator is:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
@Behavior()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
At the source level, the decorator is implemented as:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
createBeanDecorator('behavior', 'new', true, options)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That matters because Behavior is authored as a **fresh-instance bean scene** with decorator options, while the runtime may reuse existing behavior instances across reloads when appropriate.
|
|
32
|
+
|
|
33
|
+
## When to use Behavior
|
|
34
|
+
|
|
35
|
+
Use Behavior when you need reusable render-time composition that should stay inside the Zova bean model.
|
|
36
|
+
|
|
37
|
+
Typical use cases include:
|
|
38
|
+
|
|
39
|
+
- focus and ref interception for native elements
|
|
40
|
+
- reusable form-field layout wrappers
|
|
41
|
+
- prop transformation before the final render
|
|
42
|
+
- UI wrappers that should stay composable instead of being copied into many components
|
|
43
|
+
- module-level behavior selection through provider config
|
|
44
|
+
|
|
45
|
+
Do **not** reach for Behavior first when a plain helper or a normal component is enough.
|
|
46
|
+
|
|
47
|
+
A practical rule is:
|
|
48
|
+
|
|
49
|
+
- use a helper for framework-neutral logic
|
|
50
|
+
- use a normal component for standalone UI composition
|
|
51
|
+
- use a Behavior when the main need is **composable render-time interception around another render target**
|
|
52
|
+
|
|
53
|
+
## Behavior vs Component vs Helper
|
|
54
|
+
|
|
55
|
+
Use these three tools for different kinds of reuse.
|
|
56
|
+
|
|
57
|
+
| Tool | Best fit | Typical responsibility |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| Behavior | render-time interception or wrapping | adjust props, intercept refs, wrap a vnode, compose multiple render concerns |
|
|
60
|
+
| Component | standalone UI unit | own a reusable UI contract and render structure directly |
|
|
61
|
+
| Helper | framework-neutral utility | transform data, normalize values, or share logic that does not need bean lifecycle or render composition |
|
|
62
|
+
|
|
63
|
+
A practical decision map is:
|
|
64
|
+
|
|
65
|
+
- choose a **Behavior** when the concern should wrap or intercept another render target and stay composable
|
|
66
|
+
- choose a **Component** when the concern should present its own stable UI surface
|
|
67
|
+
- choose a **Helper** when the concern does not need IoC, lifecycle, host injection, or render-chain composition
|
|
68
|
+
|
|
69
|
+
Representative examples from this repository:
|
|
70
|
+
|
|
71
|
+
- `a-behaviors:focus` is a **Behavior** because it intercepts `ref` and augments native-element rendering
|
|
72
|
+
- `ZFormFieldPreset` is a **Component** because it exposes a reusable UI/render contract directly
|
|
73
|
+
- small data or option normalization utilities are better kept as **Helpers** because they do not need the behavior pipeline
|
|
74
|
+
|
|
75
|
+
### Quick decision tree
|
|
76
|
+
|
|
77
|
+
Use this quick check when choosing the implementation shape:
|
|
78
|
+
|
|
79
|
+
1. does the concern need to wrap or intercept another render target?
|
|
80
|
+
- yes -> use a **Behavior**
|
|
81
|
+
- no -> continue
|
|
82
|
+
2. does the concern need to expose its own reusable UI surface?
|
|
83
|
+
- yes -> use a **Component**
|
|
84
|
+
- no -> continue
|
|
85
|
+
3. does the concern mainly transform data or options without needing bean lifecycle or host injection?
|
|
86
|
+
- yes -> use a **Helper**
|
|
87
|
+
- no -> re-check whether the concern actually belongs in a Behavior or another bean type
|
|
88
|
+
|
|
89
|
+
## Mental model
|
|
90
|
+
|
|
91
|
+
A good mental model is:
|
|
92
|
+
|
|
93
|
+
- **component**: renders itself
|
|
94
|
+
- **helper**: transforms data
|
|
95
|
+
- **Behavior**: intercepts or wraps another render step
|
|
96
|
+
|
|
97
|
+
The authoring contract is middleware-like:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
protected render(props, next) {
|
|
101
|
+
return next(props)
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
A Behavior can leave the render path unchanged, modify the props before delegating, or wrap the vnode returned by `next(...)`.
|
|
106
|
+
|
|
107
|
+
## The public authoring surface
|
|
108
|
+
|
|
109
|
+
The core public API is small.
|
|
110
|
+
|
|
111
|
+
### `@Behavior()`
|
|
112
|
+
|
|
113
|
+
Use `@Behavior()` to declare a behavior bean.
|
|
114
|
+
|
|
115
|
+
Representative shape:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { BeanBehaviorBase, Behavior } from 'zova-module-a-behavior'
|
|
119
|
+
|
|
120
|
+
@Behavior()
|
|
121
|
+
export class BehaviorFocus extends BeanBehaviorBase {
|
|
122
|
+
protected render(props, next) {
|
|
123
|
+
return next(props)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `BeanBehaviorBase`
|
|
129
|
+
|
|
130
|
+
Most custom behaviors inherit from `BeanBehaviorBase`.
|
|
131
|
+
|
|
132
|
+
The base class provides:
|
|
133
|
+
|
|
134
|
+
- `$options` for decorator/runtime options
|
|
135
|
+
- `createComposer(...)` for nested behavior composition
|
|
136
|
+
- `render(props, next)` as the main extension point
|
|
137
|
+
- host-scoped access to the behavior host through injection
|
|
138
|
+
|
|
139
|
+
Representative host-scoped injection pattern:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
@Use({ injectionScope: 'host' })
|
|
143
|
+
$$formField: ControllerFormField;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This is one of the main reasons Behavior fits naturally into the Zova bean architecture rather than acting like a generic Vue-only hook.
|
|
147
|
+
|
|
148
|
+
### `$UseBehavior()`
|
|
149
|
+
|
|
150
|
+
`$UseBehavior()` creates a behavior declaration object.
|
|
151
|
+
|
|
152
|
+
Representative shape:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
$UseBehavior('a-behaviors:focus', { always: true })
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The helper returns one behavior declaration item in object form. Broader normalization into onion items happens later in the runtime composer path.
|
|
159
|
+
|
|
160
|
+
### `$UseBehaviorTag()`
|
|
161
|
+
|
|
162
|
+
`$UseBehaviorTag()` creates the target tag descriptor used by the behavior wrapper.
|
|
163
|
+
|
|
164
|
+
Representative shape:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
$UseBehaviorTag('input')
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### `ZBehavior`
|
|
171
|
+
|
|
172
|
+
`ZBehavior` is the public wrapper component exported by the behavior module.
|
|
173
|
+
|
|
174
|
+
Its controller-facing path is:
|
|
175
|
+
|
|
176
|
+
- `ZBehavior`
|
|
177
|
+
- `ControllerBehavior`
|
|
178
|
+
- `BeanBehaviorsHolder`
|
|
179
|
+
- `BeanBehavior`
|
|
180
|
+
- `ServiceComposer`
|
|
181
|
+
|
|
182
|
+
Inside that flow, `BeanBehaviorsHolder` wraps the requested behaviors with `a-behavior:root`, and `BehaviorRoot` delegates into the nested behavior stack.
|
|
183
|
+
|
|
184
|
+
Use this wrapper when you want a component-oriented entrypoint into the behavior system.
|
|
185
|
+
|
|
186
|
+
## Behavior declaration shapes
|
|
187
|
+
|
|
188
|
+
At the type level, `IBehaviors` accepts these shapes:
|
|
189
|
+
|
|
190
|
+
- a single behavior name
|
|
191
|
+
- one behavior-options object
|
|
192
|
+
- an array of behavior names and/or behavior-options objects
|
|
193
|
+
|
|
194
|
+
Representative forms:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
'a-behaviors:focus'
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
{ 'a-behaviors:focus': { always: true } }
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
[
|
|
206
|
+
'a-behaviors:focus',
|
|
207
|
+
{ 'home-login:formFieldLayoutLogin': {} },
|
|
208
|
+
]
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
At runtime, the composer normalizes these forms into onion items before the render chain is built.
|
|
212
|
+
|
|
213
|
+
## How the render pipeline works
|
|
214
|
+
|
|
215
|
+
The runtime path is easiest to understand from the public wrapper inward.
|
|
216
|
+
|
|
217
|
+
### 1. The wrapper/controller layer
|
|
218
|
+
|
|
219
|
+
`ZBehavior` uses `ControllerBehavior`, and the controller initializes `BeanBehaviorsHolder` with:
|
|
220
|
+
|
|
221
|
+
- a `behaviorTag` that identifies the target component or element
|
|
222
|
+
- a `behaviors` source that can be reactive
|
|
223
|
+
|
|
224
|
+
### 2. The holder layer
|
|
225
|
+
|
|
226
|
+
`BeanBehaviorsHolder` is the component-facing adapter.
|
|
227
|
+
|
|
228
|
+
Its main responsibilities are:
|
|
229
|
+
|
|
230
|
+
- store the target tag in `$$behaviorTag`
|
|
231
|
+
- build a synthetic root behavior declaration through `a-behavior:root`
|
|
232
|
+
- create a composer through `BeanBehavior`
|
|
233
|
+
- watch reactive behavior declarations and reload the composer when they change
|
|
234
|
+
- strip behavior-only props such as `behaviorTag` and `behaviors` before final render
|
|
235
|
+
|
|
236
|
+
This makes the behavior system reactive without requiring each behavior implementation to manually watch upstream inputs.
|
|
237
|
+
|
|
238
|
+
### 3. The synthetic root behavior
|
|
239
|
+
|
|
240
|
+
`BehaviorRoot` is an internal root behavior used to compose nested behavior stacks.
|
|
241
|
+
|
|
242
|
+
It creates an inner composer in `__init__`, reloads that composer in `onOptionsChange(...)`, and delegates rendering to the inner composer.
|
|
243
|
+
|
|
244
|
+
This is why the holder can wrap a whole behavior stack in one stable entry behavior.
|
|
245
|
+
|
|
246
|
+
### 4. The composition engine
|
|
247
|
+
|
|
248
|
+
`ServiceComposer` is the core runtime.
|
|
249
|
+
|
|
250
|
+
It:
|
|
251
|
+
|
|
252
|
+
- normalizes behavior declarations into onion items
|
|
253
|
+
- loads behavior onion slices through `SysOnion.behavior`
|
|
254
|
+
- reuses prior behavior bean instances by `beanFullName`
|
|
255
|
+
- calls `onOptionsChange(...)` when options changed
|
|
256
|
+
- disposes behavior beans that were removed
|
|
257
|
+
- composes the final render function by invoking each behavior bean’s `render(...)`
|
|
258
|
+
|
|
259
|
+
That reuse path is important because Behavior is not only a stateless functional transform. A behavior bean can keep instance state and still react correctly when options change.
|
|
260
|
+
|
|
261
|
+
## The authoring contract inside a behavior
|
|
262
|
+
|
|
263
|
+
A Behavior typically overrides `render(props, next)`.
|
|
264
|
+
|
|
265
|
+
There are three common patterns.
|
|
266
|
+
|
|
267
|
+
### 1. Pass-through behavior
|
|
268
|
+
|
|
269
|
+
A pass-through behavior keeps the pipeline intact and mainly exists to participate in host injection or future extension.
|
|
270
|
+
|
|
271
|
+
Representative pattern:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
protected render(renderContext, next) {
|
|
275
|
+
return next(renderContext)
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This is the shape used by the basic form-field behavior.
|
|
280
|
+
|
|
281
|
+
### 2. Prop interception behavior
|
|
282
|
+
|
|
283
|
+
A behavior can adjust props before the next render step runs.
|
|
284
|
+
|
|
285
|
+
Representative focus behavior:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
protected render(props, next) {
|
|
289
|
+
const refOuter = props?.ref
|
|
290
|
+
props = {
|
|
291
|
+
...props,
|
|
292
|
+
ref: ref => {
|
|
293
|
+
ref.focus?.()
|
|
294
|
+
refOuter?.(ref)
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
return next(props)
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
This is a good fit for concerns such as:
|
|
302
|
+
|
|
303
|
+
- focus management
|
|
304
|
+
- ref chaining
|
|
305
|
+
- attribute injection
|
|
306
|
+
- prop normalization
|
|
307
|
+
|
|
308
|
+
### 3. Wrapper/layout behavior
|
|
309
|
+
|
|
310
|
+
A behavior can render `next(...)`, inspect the returned vnode, and then wrap it with layout markup.
|
|
311
|
+
|
|
312
|
+
That is the main pattern used by form-field layout behaviors.
|
|
313
|
+
|
|
314
|
+
Representative uses include:
|
|
315
|
+
|
|
316
|
+
- block or inline layout wrappers
|
|
317
|
+
- label and error rendering
|
|
318
|
+
- icon prefix/suffix rendering
|
|
319
|
+
- page-specific form layout customization
|
|
320
|
+
|
|
321
|
+
## Real examples in this repository
|
|
322
|
+
|
|
323
|
+
The current source contains several representative behavior implementations.
|
|
324
|
+
|
|
325
|
+
### Focus behavior on a native element
|
|
326
|
+
|
|
327
|
+
The module `a-behaviors` includes a small canonical example:
|
|
328
|
+
|
|
329
|
+
- behavior bean: `a-behaviors:focus`
|
|
330
|
+
- implementation idea: intercept `ref`, focus the element, then forward the outer ref
|
|
331
|
+
|
|
332
|
+
Representative usage:
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
<input bs-behaviors-focus type="text" class="input w-full max-w-xs" />
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This is a clean example of attaching a behavior to a native element through a generated `bs-*` attribute.
|
|
339
|
+
|
|
340
|
+
### Form-field behavior composition
|
|
341
|
+
|
|
342
|
+
The form-field controller composes behaviors from two sources:
|
|
343
|
+
|
|
344
|
+
- the field component’s own `behaviors` prop
|
|
345
|
+
- the form provider’s behavior selection
|
|
346
|
+
|
|
347
|
+
Representative logic:
|
|
348
|
+
|
|
349
|
+
- `FormField` behavior from `formProvider.behaviors?.FormField`
|
|
350
|
+
- `FormFieldLayout` behavior from `formProvider.behaviors?.FormFieldLayout`
|
|
351
|
+
|
|
352
|
+
This is how one page can switch layout behavior without rewriting the form-field component itself.
|
|
353
|
+
|
|
354
|
+
### Page-level behavior selection
|
|
355
|
+
|
|
356
|
+
The login page shows a useful page-level configuration pattern:
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
<ZForm
|
|
360
|
+
formProvider={{ behaviors: { FormFieldLayout: 'home-login:formFieldLayoutLogin' } }}
|
|
361
|
+
>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
That selects a page-specific layout behavior while keeping the same form-field rendering flow.
|
|
365
|
+
|
|
366
|
+
## Generated `bs-*` attributes
|
|
367
|
+
|
|
368
|
+
Behavior metadata generation also exposes shorthand HTML/JSX attributes.
|
|
369
|
+
|
|
370
|
+
For example, a behavior such as `a-behaviors:focus` generates an attribute like:
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
bs-behaviors-focus
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
The generation rule is defined by the behavior metadata generator and is based on the module name and bean name.
|
|
377
|
+
|
|
378
|
+
This is why behavior usage on native elements often appears as named `bs-*` attributes rather than only as one generic prop.
|
|
379
|
+
|
|
380
|
+
The base behavior types also extend HTML/JSX surfaces with:
|
|
381
|
+
|
|
382
|
+
- `behaviors?: IBehaviors` on HTML input-style attribute surfaces
|
|
383
|
+
- `bs_all?: IBehaviors` on JSX/runtime HTML attribute surfaces
|
|
384
|
+
|
|
385
|
+
In practice, the generated named `bs-*` attributes are the clearer and more discoverable entrypoint for native-element usage.
|
|
386
|
+
|
|
387
|
+
## Reactive behavior reloading
|
|
388
|
+
|
|
389
|
+
`BeanBehaviorsHolder` accepts a behavior source that can be a function.
|
|
390
|
+
|
|
391
|
+
When the holder receives the behavior declaration as a function, it watches that source and reloads the composer only when the value actually changed.
|
|
392
|
+
|
|
393
|
+
That means a behavior stack can evolve with component state while still using the same composition pipeline and bean lifecycle.
|
|
394
|
+
|
|
395
|
+
## Design rules for Behavior authors
|
|
396
|
+
|
|
397
|
+
When writing a custom Behavior, ask these questions.
|
|
398
|
+
|
|
399
|
+
### Is the concern really render-time middleware?
|
|
400
|
+
|
|
401
|
+
If the concern is mainly around wrapping or intercepting another render target, Behavior is a strong fit.
|
|
402
|
+
|
|
403
|
+
If the concern is pure data transformation or standalone UI structure, prefer a helper or a normal component.
|
|
404
|
+
|
|
405
|
+
### Does the behavior need host-scoped dependencies?
|
|
406
|
+
|
|
407
|
+
Many useful behaviors need the host object, such as a form-field controller.
|
|
408
|
+
|
|
409
|
+
If the logic depends on host state, prefer host-scoped injection instead of reaching around the framework with ad hoc shared state.
|
|
410
|
+
|
|
411
|
+
### Should the behavior mutate props or wrap the vnode?
|
|
412
|
+
|
|
413
|
+
A practical split is:
|
|
414
|
+
|
|
415
|
+
- mutate props when the concern is about the next render input
|
|
416
|
+
- wrap the vnode when the concern is about layout or presentation around the rendered result
|
|
417
|
+
|
|
418
|
+
### Does the behavior need instance state?
|
|
419
|
+
|
|
420
|
+
Because behaviors are fresh bean instances, they can safely keep local instance state and still participate in lifecycle and disposal.
|
|
421
|
+
|
|
422
|
+
That is useful for cases such as cached refs, local style handles, or nested composer ownership.
|
|
423
|
+
|
|
424
|
+
## Relationship to other frontend guides
|
|
425
|
+
|
|
426
|
+
Read this guide together with:
|
|
427
|
+
|
|
428
|
+
- [IoC and Beans](/frontend/ioc-and-beans)
|
|
429
|
+
- [Frontend Bean Scene Authoring](/frontend/bean-scene-authoring)
|
|
430
|
+
- [Component Guide](/frontend/component-guide)
|
|
431
|
+
|
|
432
|
+
Use [Frontend Bean Scene Authoring](/frontend/bean-scene-authoring) when you need to create a **new bean scene**.
|
|
433
|
+
|
|
434
|
+
Use this page when you need to understand or author beans inside the existing **Behavior** scene.
|
|
435
|
+
|
|
436
|
+
## Verification checklist
|
|
437
|
+
|
|
438
|
+
When documenting or changing Behavior-related frontend code, verify in this order:
|
|
439
|
+
|
|
440
|
+
1. confirm the behavior API and runtime claims against the current `a-behavior` source
|
|
441
|
+
2. confirm representative usage still exists in real modules such as form-field and focus behaviors
|
|
442
|
+
3. confirm any generated `bs-*` attribute examples match current metadata output
|
|
443
|
+
4. build the docs site:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
npm run docs:build
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
5. verify the page is reachable from the frontend sidebar and related frontend guides
|
|
@@ -71,6 +71,18 @@ A practical rule is:
|
|
|
71
71
|
|
|
72
72
|
These are not competing workflow systems. They are two entrypoints to the same underlying Zova command families.
|
|
73
73
|
|
|
74
|
+
## Bean boilerplate variants
|
|
75
|
+
|
|
76
|
+
Some frontend bean scenes also expose named boilerplate variants.
|
|
77
|
+
|
|
78
|
+
A practical rule is:
|
|
79
|
+
|
|
80
|
+
- the default scene template comes from the scene metadata `boilerplate`
|
|
81
|
+
- a named variant such as `--boilerplate=commandRow` maps to a metadata key such as `boilerplateCommandRow`
|
|
82
|
+
- supported variants are scene-defined, so do not assume every scene exposes them
|
|
83
|
+
|
|
84
|
+
For the current cross-stack lookup table, see [Bean Scene Boilerplate Variants](/reference/bean-scene-boilerplates).
|
|
85
|
+
|
|
74
86
|
## Practical workflow rule
|
|
75
87
|
|
|
76
88
|
When creating or refactoring frontend code, inspect `npm run zova :` or the relevant command family first, prefer the matching generator or refactor command, inspect the generated or transformed output, and only then make minimal follow-up edits.
|
|
@@ -33,6 +33,7 @@ Start here when you need the shortest route to the frontend mental model and sta
|
|
|
33
33
|
- [Quickstart](/frontend/quickstart)
|
|
34
34
|
- [Foundation](/frontend/foundation)
|
|
35
35
|
- [IoC and Beans](/frontend/ioc-and-beans)
|
|
36
|
+
- [Behavior Guide](/frontend/behavior-guide)
|
|
36
37
|
- [Modules and Suites](/frontend/modules-and-suites)
|
|
37
38
|
- [Module Scope](/frontend/module-scope)
|
|
38
39
|
- [Design Principles](/frontend/design-principles)
|
|
@@ -76,6 +77,10 @@ Use this path when the task is about data loading, API contracts, generated SDKs
|
|
|
76
77
|
- [OpenAPI SDK Guide](/frontend/openapi-sdk-guide)
|
|
77
78
|
- [API Schema Guide](/frontend/api-schema-guide)
|
|
78
79
|
- [SDK Guide](/frontend/sdk-guide)
|
|
80
|
+
- [SSR Architecture Overview](/frontend/ssr-architecture-overview)
|
|
81
|
+
- [SSR Build and Deploy Guide](/frontend/ssr-build-deploy-guide)
|
|
82
|
+
- [SSR Troubleshooting Guide](/frontend/ssr-troubleshooting-guide)
|
|
83
|
+
- [SSR Review Checklist](/frontend/ssr-review-checklist)
|
|
79
84
|
- [SSR Overview](/frontend/ssr-overview)
|
|
80
85
|
- [SSR Init Data](/frontend/ssr-init-data)
|
|
81
86
|
- [SSR ClientOnly](/frontend/ssr-client-only)
|
|
@@ -35,9 +35,9 @@ All beans inherit from `BeanBase`, which exposes common framework capabilities a
|
|
|
35
35
|
|
|
36
36
|
## `BeanBase`
|
|
37
37
|
|
|
38
|
-
`BeanBase`
|
|
38
|
+
`BeanBase` sits on top of the simpler core bean surface and is also a host for members extended by modules and adapters.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Core inherited members include:
|
|
41
41
|
|
|
42
42
|
- `sys`
|
|
43
43
|
- `app`
|
|
@@ -46,14 +46,13 @@ Representative members include:
|
|
|
46
46
|
- `scope`
|
|
47
47
|
- `$el`
|
|
48
48
|
- `$event`
|
|
49
|
-
- `$ssr`
|
|
50
|
-
- `$useMeta`
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
Module and adapter layers can extend that surface further. For example, SSR-related modules can add members such as `$ssr` and `$useMeta`.
|
|
53
51
|
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
- `$props`
|
|
52
|
+
More specialized controller bases can also add frontend-specific members:
|
|
53
|
+
|
|
54
|
+
- component-style controller bases expose `$props`
|
|
55
|
+
- page-controller bases expose `$params` and `$query`
|
|
57
56
|
|
|
58
57
|
Module and UI adapters can further extend the base surface.
|
|
59
58
|
|
|
@@ -193,11 +192,13 @@ This matters especially in large systems, where business modules should remain r
|
|
|
193
192
|
|
|
194
193
|
Read this together with:
|
|
195
194
|
|
|
195
|
+
- [Behavior Guide](/frontend/behavior-guide) when the task is about render-time interception, behavior composition, or authoring beans inside the existing Behavior scene
|
|
196
|
+
- [Frontend Bean Scene Authoring](/frontend/bean-scene-authoring) when you need to create a **new bean scene** rather than only adding a bean inside an existing scene
|
|
196
197
|
- [Modules and Suites](/frontend/modules-and-suites)
|
|
197
198
|
- [Module Scope](/frontend/module-scope)
|
|
198
199
|
- [Frontend Design Principles](/frontend/design-principles)
|
|
199
200
|
|
|
200
|
-
Those pages explain how beans fit into module boundaries, scope-based resources, and the broader Zova architectural model.
|
|
201
|
+
Those pages explain how beans fit into module boundaries, scope-based resources, the existing Behavior scene, and the broader Zova architectural model.
|
|
201
202
|
|
|
202
203
|
## Implementation checks for frontend bean-architecture changes
|
|
203
204
|
|