@stonecrop/aform 0.11.8 → 0.11.10
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 +134 -0
- package/dist/aform.d.ts +46 -0
- package/dist/aform.js +1370 -1253
- package/dist/aform.js.map +1 -1
- package/dist/assets/index.css +1 -1
- package/dist/src/directives/mask.d.ts.map +1 -1
- package/dist/src/directives/mask.js +5 -7
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -1
- package/dist/src/types/index.d.ts +25 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/deserialize.d.ts +16 -0
- package/dist/src/utils/deserialize.d.ts.map +1 -0
- package/dist/src/utils/deserialize.js +18 -0
- package/package.json +4 -4
- package/src/components/AForm.vue +2 -2
- package/src/components/form/AFormLink.vue +219 -0
- package/src/directives/mask.ts +7 -8
- package/src/index.ts +4 -0
- package/src/types/index.ts +28 -0
- package/src/utils/deserialize.ts +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @stonecrop/aform
|
|
2
|
+
|
|
3
|
+
Schema-driven form components for the Stonecrop framework. Renders a `SchemaTypes[]` array into a form, wiring field values to a `data` object via `v-model:data`.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
| Component | Description |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `AForm` | Root form renderer — iterates schema, renders child components, handles nested forms |
|
|
10
|
+
| `ACheckbox` | Boolean toggle |
|
|
11
|
+
| `AComboBox` | Editable combo box with option list |
|
|
12
|
+
| `ADate` | Date text input |
|
|
13
|
+
| `ADatePicker` | Date picker with calendar UI |
|
|
14
|
+
| `ADropdown` | Single-select dropdown for string enum fields |
|
|
15
|
+
| `AFieldset` | Collapsible grouping container for other fields |
|
|
16
|
+
| `AFileAttach` | File upload and attachment |
|
|
17
|
+
| `AFormLink` | Linked document selector with search dropdown and navigation arrow |
|
|
18
|
+
| `ANumericInput` | Numeric input with type-specific formatting |
|
|
19
|
+
| `ATextInput` | Single-line text input |
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { install } from '@stonecrop/aform'
|
|
25
|
+
|
|
26
|
+
app.use(install)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This registers all components globally. They can also be imported individually.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## AFormLink
|
|
34
|
+
|
|
35
|
+
A form input for selecting and navigating to linked documents (`fieldtype: 'Link'`). Combines a searchable text input, an optional dropdown of results, and a navigation arrow button.
|
|
36
|
+
|
|
37
|
+
### Value shape
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
interface AFormLinkValue {
|
|
41
|
+
id: string | number // the linked record's ID; id: 0 is valid
|
|
42
|
+
displayText?: string // shown in the input; falls back to String(id)
|
|
43
|
+
[extra: string]: any // extra fields available to formatter
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
When `id` is falsy, the component shows a `—` placeholder and hides the navigation arrow.
|
|
48
|
+
|
|
49
|
+
### Props
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
{
|
|
53
|
+
modelValue: AFormLinkValue
|
|
54
|
+
label?: string
|
|
55
|
+
mode?: 'edit' | 'read' | 'display'
|
|
56
|
+
doctype?: string // target doctype slug — used by the navigation arrow
|
|
57
|
+
filterFunction?: (search: string) => AFormLinkValue[] | Promise<AFormLinkValue[]>
|
|
58
|
+
isAsync?: boolean // show loading indicator while filterFunction resolves
|
|
59
|
+
formatter?: (value: AFormLinkValue) => string // custom display text transform
|
|
60
|
+
icon?: 'arrow-right' | 'chevron-right' // navigation arrow icon
|
|
61
|
+
disabled?: boolean
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Modes
|
|
66
|
+
|
|
67
|
+
| Mode | Input | Arrow | Dropdown |
|
|
68
|
+
|-----------|----------|----------------------|---------------------|
|
|
69
|
+
| `edit` | Enabled | Visible (if has id) | Opens on focus/type |
|
|
70
|
+
| `read` | Disabled | Visible (if has id) | Never opens |
|
|
71
|
+
| `display` | Hidden | Hidden | — |
|
|
72
|
+
|
|
73
|
+
### Filter function
|
|
74
|
+
|
|
75
|
+
Provide `filterFunction` to enable the search dropdown. The function receives the current input text and must return `AFormLinkValue[]` or a `Promise<AFormLinkValue[]>`.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Sync
|
|
79
|
+
const filterFunction = (search: string): AFormLinkValue[] =>
|
|
80
|
+
records
|
|
81
|
+
.filter(r => r.name.toLowerCase().includes(search.toLowerCase()))
|
|
82
|
+
.map(r => ({ id: r.id, displayText: r.name }))
|
|
83
|
+
|
|
84
|
+
// Async — set isAsync: true for loading indicator
|
|
85
|
+
const filterFunction = async (search: string): Promise<AFormLinkValue[]> => {
|
|
86
|
+
const results = await api.search(search)
|
|
87
|
+
return results.map(r => ({ id: r.id, displayText: r.name }))
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Navigation
|
|
92
|
+
|
|
93
|
+
AFormLink injects `aformLinkNavigator` from the app layer rather than depending on vue-router directly. Provide it once in your app plugin:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import type { AFormLinkNavigator } from '@stonecrop/aform'
|
|
97
|
+
|
|
98
|
+
app.provide('aformLinkNavigator', {
|
|
99
|
+
navigate(doctype: string, id: string | number) {
|
|
100
|
+
router.push(`/${doctype}/${id}`)
|
|
101
|
+
},
|
|
102
|
+
} satisfies AFormLinkNavigator)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
interface AFormLinkNavigator {
|
|
107
|
+
navigate(doctype: string, id: string | number): void
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If no navigator is provided, the arrow button is still rendered but navigation clicks are silent no-ops.
|
|
112
|
+
|
|
113
|
+
### Via resolveSchema
|
|
114
|
+
|
|
115
|
+
For `fieldtype: 'Link'` fields with no matching `links` declaration, `Registry.resolveSchema()` automatically assigns `component: 'AFormLink'` and sets `doctype` from `field.options`. No manual wiring required:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const config: DoctypeConfig = {
|
|
119
|
+
slug: 'sales-order',
|
|
120
|
+
fields: [
|
|
121
|
+
{ fieldname: 'order_number', fieldtype: 'Data', component: 'ATextInput', label: 'Order Number' },
|
|
122
|
+
{ fieldname: 'territory', fieldtype: 'Link', options: 'territory', label: 'Territory' },
|
|
123
|
+
// no 'links' entry for territory
|
|
124
|
+
],
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
registry.addDoctype(Doctype.fromObject(config))
|
|
128
|
+
const resolved = registry.resolveSchema(registry.registry['sales-order'])
|
|
129
|
+
// resolved[1] === { fieldname: 'territory', component: 'AFormLink', doctype: 'territory', label: 'Territory' }
|
|
130
|
+
|
|
131
|
+
// Pass to AForm as normal — the territory field renders as AFormLink automatically
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Declared links (those with a `links` entry and a registered target doctype) are unaffected — they continue to resolve as embedded `AForm` (1:1) or `ATable` (1:many) entries.
|
package/dist/aform.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import ADropdown from './components/form/ADropdown.vue';
|
|
|
6
6
|
import AFieldset from './components/form/AFieldset.vue';
|
|
7
7
|
import AFileAttach from './components/form/AFileAttach.vue';
|
|
8
8
|
import AForm from './components/AForm.vue';
|
|
9
|
+
import AFormLink from './components/form/AFormLink.vue';
|
|
9
10
|
import ANumericInput from './components/form/ANumericInput.vue';
|
|
10
11
|
import type { App } from 'vue';
|
|
11
12
|
import ATextInput from './components/form/ATextInput.vue';
|
|
@@ -30,6 +31,29 @@ export { AFileAttach }
|
|
|
30
31
|
|
|
31
32
|
export { AForm }
|
|
32
33
|
|
|
34
|
+
export { AFormLink }
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Navigation contract for AFormLink. Provide via `provide('aformLinkNavigator', ...)` in the app plugin.
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare interface AFormLinkNavigator {
|
|
41
|
+
/** Navigate to the linked document. Implementation is app-defined. */
|
|
42
|
+
navigate(doctype: string, id: string | number): void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The value shape for AFormLink — a linked document reference with optional display text
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export declare interface AFormLinkValue {
|
|
50
|
+
/** The FK/linked document ID. `id: 0` is a valid ID. */
|
|
51
|
+
id: string | number;
|
|
52
|
+
/** Display text shown in the input. Falls back to `String(id)` if omitted. */
|
|
53
|
+
displayText?: string;
|
|
54
|
+
[extra: string]: any;
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
export { ANumericInput }
|
|
34
58
|
|
|
35
59
|
export { ATextInput }
|
|
@@ -59,6 +83,12 @@ export declare type BaseSchema = {
|
|
|
59
83
|
* @public
|
|
60
84
|
*/
|
|
61
85
|
mode?: FormMode;
|
|
86
|
+
/**
|
|
87
|
+
* Hide the field from the form UI while keeping it in the data model.
|
|
88
|
+
* Consumed by AForm — not passed down to field components.
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
hidden?: boolean;
|
|
62
92
|
};
|
|
63
93
|
|
|
64
94
|
/**
|
|
@@ -113,6 +143,22 @@ export declare type ComponentProps = {
|
|
|
113
143
|
};
|
|
114
144
|
};
|
|
115
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Deserializes a stringified function expression into a typed callable.
|
|
148
|
+
*
|
|
149
|
+
* Throws if the string cannot be parsed as a function (SyntaxError) or if the
|
|
150
|
+
* resulting expression is not callable (TypeError), or if the expression references
|
|
151
|
+
* an undefined variable (ReferenceError). Callers are responsible for try/catch.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* const fn = deserializeFunction<(x: number) => number>('(x) => x * 2')
|
|
156
|
+
* fn(5) // 10
|
|
157
|
+
* ```
|
|
158
|
+
* @public
|
|
159
|
+
*/
|
|
160
|
+
export declare function deserializeFunction<T extends (...args: any[]) => any>(source: string): T;
|
|
161
|
+
|
|
116
162
|
/**
|
|
117
163
|
* Schema structure for defining fieldsets inside AForm
|
|
118
164
|
* @public
|