|
@@ -188,6 +188,22 @@ Schema options:
|
|
|
| `resolvePropValue(value, ctx)` | Resolve a single prop expression |
|
|
| `resolvePropValue(value, ctx)` | Resolve a single prop expression |
|
|
|
| `resolveElementProps(props, ctx)` | Resolve all prop expressions in an element |
|
|
| `resolveElementProps(props, ctx)` | Resolve all prop expressions in an element |
|
|
|
| `PropExpression<T>` | Type for prop values that may contain expressions |
|
|
| `PropExpression<T>` | Type for prop values that may contain expressions |
|
|
|
|
|
+| `ComputedFunction` | Function signature for `$computed` expressions |
|
|
|
|
|
+| `PropResolutionContext` | Context for resolving props (includes `functions` for `$computed`) |
|
|
|
|
|
+
|
|
|
|
|
+### Validation
|
|
|
|
|
+
|
|
|
|
|
+| Export | Purpose |
|
|
|
|
|
+|--------|---------|
|
|
|
|
|
+| `check.required()` | Required validation helper |
|
|
|
|
|
+| `check.email()` | Email validation helper |
|
|
|
|
|
+| `check.matches(path)` | Cross-field match helper |
|
|
|
|
|
+| `check.equalTo(path)` | Cross-field equality helper |
|
|
|
|
|
+| `check.lessThan(path)` | Cross-field less-than helper |
|
|
|
|
|
+| `check.greaterThan(path)` | Cross-field greater-than helper |
|
|
|
|
|
+| `check.requiredIf(path)` | Conditional required helper |
|
|
|
|
|
+| `builtInValidationFunctions` | All built-in validation functions |
|
|
|
|
|
+| `runValidationCheck()` | Run a single validation check |
|
|
|
|
|
|
|
|
### User Prompt
|
|
### User Prompt
|
|
|
|
|
|
|
@@ -285,6 +301,7 @@ The official adapter packages (`@json-render/redux`, `@json-render/zustand`, `@j
|
|
|
| `Spec` | Base spec type |
|
|
| `Spec` | Base spec type |
|
|
|
| `Catalog` | Catalog type |
|
|
| `Catalog` | Catalog type |
|
|
|
| `BuiltInAction` | Built-in action type (`name` + `description`) |
|
|
| `BuiltInAction` | Built-in action type (`name` + `description`) |
|
|
|
|
|
+| `ComputedFunction` | Function signature for `$computed` expressions |
|
|
|
| `VisibilityCondition` | Visibility condition type (used by `$cond`) |
|
|
| `VisibilityCondition` | Visibility condition type (used by `$cond`) |
|
|
|
| `VisibilityContext` | Context for evaluating visibility and prop expressions |
|
|
| `VisibilityContext` | Context for evaluating visibility and prop expressions |
|
|
|
| `SpecStreamLine` | Single patch operation |
|
|
| `SpecStreamLine` | Single patch operation |
|
|
@@ -372,6 +389,44 @@ Get the current array index inside a repeat:
|
|
|
|
|
|
|
|
`$index` uses `true` as a sentinel flag because the index is a scalar value with no sub-path to navigate (unlike `$item` which needs a path).
|
|
`$index` uses `true` as a sentinel flag because the index is a scalar value with no sub-path to navigate (unlike `$item` which needs a path).
|
|
|
|
|
|
|
|
|
|
+### Template (`$template`)
|
|
|
|
|
+
|
|
|
|
|
+Interpolate state values into strings using `${/path}` syntax:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "label": { "$template": "Hello, ${/user/name}! You have ${/inbox/count} messages." }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Missing paths resolve to an empty string.
|
|
|
|
|
+
|
|
|
|
|
+### Computed (`$computed`)
|
|
|
|
|
+
|
|
|
|
|
+Call a registered function with resolved arguments:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "text": {
|
|
|
|
|
+ "$computed": "fullName",
|
|
|
|
|
+ "args": {
|
|
|
|
|
+ "first": { "$state": "/form/firstName" },
|
|
|
|
|
+ "last": { "$state": "/form/lastName" }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Functions are registered in the catalog and provided at runtime via the `functions` prop on the renderer.
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import type { ComputedFunction } from "@json-render/core";
|
|
|
|
|
+
|
|
|
|
|
+const functions: Record<string, ComputedFunction> = {
|
|
|
|
|
+ fullName: (args) => `${args.first} ${args.last}`,
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
### API
|
|
### API
|
|
|
|
|
|
|
|
```typescript
|
|
```typescript
|
|
@@ -466,6 +521,65 @@ console.log(formatSpecIssues(issues));
|
|
|
const fixed = autoFixSpec(spec);
|
|
const fixed = autoFixSpec(spec);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+## State Watchers
|
|
|
|
|
+
|
|
|
|
|
+Elements can declare a `watch` field to trigger actions when state values change. `watch` is a top-level field on the element (sibling of `type`, `props`, `children`), not inside `props`.
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "type": "Select",
|
|
|
|
|
+ "props": {
|
|
|
|
|
+ "label": "Country",
|
|
|
|
|
+ "value": { "$bindState": "/form/country" },
|
|
|
|
|
+ "options": ["US", "Canada", "UK"]
|
|
|
|
|
+ },
|
|
|
|
|
+ "watch": {
|
|
|
|
|
+ "/form/country": {
|
|
|
|
|
+ "action": "loadCities",
|
|
|
|
|
+ "params": { "country": { "$state": "/form/country" } }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "children": []
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Watchers only fire on value changes, not on initial render. Multiple action bindings per path execute sequentially.
|
|
|
|
|
+
|
|
|
|
|
+## Validation
|
|
|
|
|
+
|
|
|
|
|
+### Built-in Validation Functions
|
|
|
|
|
+
|
|
|
|
|
+| Function | Description | Args |
|
|
|
|
|
+|----------|-------------|------|
|
|
|
|
|
+| `required` | Value must not be empty | — |
|
|
|
|
|
+| `email` | Must be a valid email | — |
|
|
|
|
|
+| `url` | Must be a valid URL | — |
|
|
|
|
|
+| `numeric` | Must be a number | — |
|
|
|
|
|
+| `minLength` | Minimum string length | `{ min: number }` |
|
|
|
|
|
+| `maxLength` | Maximum string length | `{ max: number }` |
|
|
|
|
|
+| `min` | Minimum numeric value | `{ min: number }` |
|
|
|
|
|
+| `max` | Maximum numeric value | `{ max: number }` |
|
|
|
|
|
+| `pattern` | Must match regex | `{ pattern: string }` |
|
|
|
|
|
+| `matches` | Must equal another field | `{ other: { $state: "/path" } }` |
|
|
|
|
|
+| `equalTo` | Alias for matches | `{ other: { $state: "/path" } }` |
|
|
|
|
|
+| `lessThan` | Must be less than another field | `{ other: { $state: "/path" } }` |
|
|
|
|
|
+| `greaterThan` | Must be greater than another field | `{ other: { $state: "/path" } }` |
|
|
|
|
|
+| `requiredIf` | Required when condition is truthy | `{ field: { $state: "/path" } }` |
|
|
|
|
|
+
|
|
|
|
|
+### TypeScript Helpers
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { check } from "@json-render/core";
|
|
|
|
|
+
|
|
|
|
|
+check.required("Field is required");
|
|
|
|
|
+check.email("Invalid email");
|
|
|
|
|
+check.matches("/form/password", "Passwords must match");
|
|
|
|
|
+check.equalTo("/form/password", "Passwords must match");
|
|
|
|
|
+check.lessThan("/form/endDate", "Must be before end date");
|
|
|
|
|
+check.greaterThan("/form/startDate", "Must be after start date");
|
|
|
|
|
+check.requiredIf("/form/enableNotifications", "Required when notifications enabled");
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
## Custom Schemas
|
|
## Custom Schemas
|
|
|
|
|
|
|
|
json-render supports completely different spec formats for different renderers:
|
|
json-render supports completely different spec formats for different renderers:
|