@stonecrop/nuxt 0.6.0 → 0.6.2

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 CHANGED
@@ -3,57 +3,299 @@
3
3
  [![npm version][npm-version-src]][npm-version-href]
4
4
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
5
 
6
- Nuxt module for Stonecrop.
6
+ The official Nuxt module for Stonecrop - a schema-driven UI framework with event-driven workflows and hierarchical state management.
7
7
 
8
- ## Features
8
+ ## What is Stonecrop?
9
9
 
10
- <!-- Highlight some of the features your module provide here -->
11
- - ⛰ &nbsp;Foo
12
- - 🚠 &nbsp;Bar
13
- - 🌲 &nbsp;Baz
10
+ Stonecrop is a **schema-driven UI framework** that generates forms, tables, and workflows from JSON schemas. Instead of manually creating CRUD interfaces for every data model, you define your data structure once and Stonecrop handles the UI generation, state management, and validation automatically.
11
+
12
+ **Key Benefits:**
13
+ - **Schema-Driven**: Define data models in JSON, get full CRUD interfaces automatically
14
+ - **HST State Management**: Hierarchical State Tree for complex, nested application state
15
+ - **FSM Workflows**: XState-powered finite state machines for predictable business logic
16
+ - **Nuxt Native**: First-class integration with Nuxt 4's architecture
17
+ - **Live Validation**: Real-time form validation based on schema rules
18
+ - **Excel-like Tables**: Rich table component with keyboard navigation and inline editing
19
+
20
+ ## Module Features
21
+
22
+ - **Automatic Page Generation**: Creates routes from DocType schemas in your `/doctypes` folder
23
+ - **Form & Table Components**: Pre-configured AForm and ATable components with HST integration
24
+ - **Plugin System**: Auto-registers Stonecrop composables and utilities
25
+ - **Theme Support**: Import and customize Stonecrop themes
26
+ - **TypeScript First**: Full type safety and IntelliSense support
27
+ - **Zero Config**: Works out of the box with sensible defaults
14
28
 
15
29
  ## Quick Setup
16
30
 
17
- Install the module to your Nuxt application with one command:
31
+ Install the module to your Nuxt application:
18
32
 
19
33
  ```bash
20
34
  npx nuxi module add @stonecrop/nuxt
21
35
  ```
22
36
 
23
- That's it! You can now use Nuxt Stonecrop in your Nuxt app
37
+ That's it! You can now use Stonecrop in your Nuxt app.
24
38
 
39
+ ## Basic Usage
25
40
 
26
- ## Contribution
41
+ ### Define a DocType Schema
42
+
43
+ Create a JSON schema in `/doctypes/task.json`:
44
+
45
+ ```json
46
+ {
47
+ "name": "task",
48
+ "label": "Task",
49
+ "schema": [
50
+ {
51
+ "fieldname": "title",
52
+ "label": "Title",
53
+ "fieldtype": "Data",
54
+ "required": true
55
+ },
56
+ {
57
+ "fieldname": "description",
58
+ "label": "Description",
59
+ "fieldtype": "Text"
60
+ },
61
+ {
62
+ "fieldname": "completed",
63
+ "label": "Completed",
64
+ "fieldtype": "Check"
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ The module automatically generates routes at `/task` for this DocType.
71
+
72
+ ### Use the Stonecrop Composable
73
+
74
+ In your page or component:
75
+
76
+ ```vue
77
+ <script setup lang="ts">
78
+ import taskDoctype from '~/doctypes/task.json'
79
+
80
+ // HST-reactive form setup
81
+ const { stonecrop, provideHSTPath, handleHSTChange, formData } = useStonecrop({
82
+ doctype: taskDoctype,
83
+ recordId: 'task-123' // or undefined for new records
84
+ })
85
+
86
+ // Access the hierarchical state tree
87
+ const taskTitle = stonecrop.getStore().get('task.task-123.title')
88
+ </script>
89
+
90
+ <template>
91
+ <AForm
92
+ :schema="formData.schema"
93
+ :data="formData"
94
+ @update="handleHSTChange"
95
+ />
96
+ </template>
97
+ ```
98
+
99
+ ### Understanding Schema-Driven Development
100
+
101
+ **Traditional Approach:**
102
+ ```vue
103
+ <!-- Manual form creation -->
104
+ <template>
105
+ <form>
106
+ <input v-model="task.title" required />
107
+ <textarea v-model="task.description" />
108
+ <input type="checkbox" v-model="task.completed" />
109
+ <button @click="validate">Save</button>
110
+ </form>
111
+ </template>
112
+
113
+ <script setup>
114
+ // Manual validation logic
115
+ const validate = () => {
116
+ if (!task.title) {
117
+ errors.title = 'Required'
118
+ }
119
+ // ... more validation
120
+ }
121
+ </script>
122
+ ```
123
+
124
+ **Stonecrop Approach:**
125
+ ```vue
126
+ <!-- Schema generates form automatically -->
127
+ <template>
128
+ <AForm :schema="taskSchema" :data="formData" />
129
+ </template>
130
+
131
+ <script setup>
132
+ // Validation is automatic from schema
133
+ const { formData } = useStonecrop({
134
+ doctype: taskDoctype,
135
+ recordId: taskId
136
+ })
137
+ </script>
138
+ ```
139
+
140
+ The schema defines:
141
+ - Field types (text input, checkbox, select, etc.)
142
+ - Validation rules (required, patterns, min/max)
143
+ - Labels and help text
144
+ - Relationships between data models
145
+
146
+ ## Configuration
147
+
148
+ Add options to your `nuxt.config.ts`:
149
+
150
+ ```typescript
151
+ export default defineNuxtConfig({
152
+ modules: ['@stonecrop/nuxt'],
153
+
154
+ stonecrop: {
155
+ // Enable DocBuilder for visual schema editing
156
+ docbuilder: true,
157
+
158
+ // Custom router configuration
159
+ router: {
160
+ // Router options
161
+ }
162
+ },
163
+
164
+ // Import Stonecrop theme
165
+ css: [
166
+ '@stonecrop/themes/default/default.css',
167
+ // or your custom theme
168
+ ]
169
+ })
170
+ ```
27
171
 
28
- <details>
29
- <summary>Local development</summary>
172
+ ## Module Behavior
30
173
 
31
- ```bash
32
- # Install dependencies
33
- npm install
174
+ ### Automatic Page Generation
34
175
 
35
- # Generate type stubs
36
- npm run dev:prepare
176
+ The module scans your `/doctypes` folder and creates routes automatically:
37
177
 
38
- # Develop with the playground
39
- npm run dev
178
+ ```
179
+ doctypes/
180
+ ├── task.json → /task
181
+ ├── user.json → /user
182
+ └── project.json → /project
183
+ ```
184
+
185
+ Each route uses the `StonecropPage.vue` layout that provides:
186
+ - List view with ATable component
187
+ - Detail view with AForm component
188
+ - HST state management
189
+ - Router integration for navigation
190
+
191
+ ### Plugin Registration
192
+
193
+ The module auto-registers:
194
+ - `useStonecrop()` - Main composable for HST integration
195
+ - `useTableNavigation()` - Helper for table-to-detail navigation
196
+ - Pinia store configuration
197
+ - Component auto-imports (AForm, ATable, etc.)
198
+
199
+ ## Why Schema-Driven?
200
+
201
+ **Problem:** Building CRUD applications is repetitive. Every data model needs:
202
+ - Forms for creating/editing
203
+ - Tables for listing
204
+ - Validation logic
205
+ - State management
206
+ - API integration
207
+
208
+ **Solution:** Define the structure once, generate everything automatically.
209
+
210
+ **Benefits:**
211
+ - **Faster Development**: Write less boilerplate code
212
+ - **Consistency**: All forms/tables follow the same patterns
213
+ - **Fewer Bugs**: Validation and state management are centralized
214
+ - **Self-Documenting**: Schemas serve as data model documentation
215
+ - **Easy Updates**: Change schema, UI updates automatically
216
+
217
+ ## Advanced Features
218
+
219
+ ### Hierarchical State Tree (HST)
220
+
221
+ HST provides path-based state addressing:
222
+
223
+ ```typescript
224
+ const store = stonecrop.getStore()
225
+
226
+ // Set nested values with dot notation
227
+ store.set('project.proj-1.tasks.task-1.completed', true)
228
+
229
+ // Get values anywhere in the tree
230
+ const completed = store.get('project.proj-1.tasks.task-1.completed')
40
231
 
41
- # Build the playground
42
- npm run dev:build
232
+ // Navigate the tree hierarchy
233
+ const taskNode = store.getNode('project.proj-1.tasks.task-1')
234
+ const parent = taskNode.getParent() // Returns project node
235
+ const breadcrumbs = taskNode.getBreadcrumbs()
236
+ ```
237
+
238
+ ### XState Integration
239
+
240
+ Define workflows as finite state machines:
241
+
242
+ ```typescript
243
+ import { createMachine } from 'xstate'
43
244
 
44
- # Run ESLint
45
- npm run lint
245
+ const taskMachine = createMachine({
246
+ id: 'task',
247
+ initial: 'draft',
248
+ states: {
249
+ draft: {
250
+ on: { SUBMIT: 'pending' }
251
+ },
252
+ pending: {
253
+ on: {
254
+ APPROVE: 'completed',
255
+ REJECT: 'draft'
256
+ }
257
+ },
258
+ completed: {
259
+ type: 'final'
260
+ }
261
+ }
262
+ })
46
263
 
47
- # Run Vitest
48
- npm run test
49
- npm run test:watch
264
+ // Stonecrop persists state machine data in HST
265
+ ```
266
+
267
+ ## Examples
50
268
 
51
- # Release new version
52
- npm run release
53
- ```
269
+ Check out the [playground](./playground) for an example featuring:
270
+ - Permission management system (RBAC)
271
+ - DocType builder with visual state machine editor
272
+ - Complex nested forms with relationships
273
+ - Table views with inline editing
274
+ - HST state visualization
54
275
 
55
- </details>
56
276
 
277
+ ## Contribution
278
+
279
+ ```bash
280
+ # Install dependencies
281
+ npm install
282
+
283
+ # Generate type stubs
284
+ npm run dev:prepare
285
+
286
+ # Develop with the playground
287
+ npm run dev
288
+
289
+ # Build the playground
290
+ npm run dev:build
291
+
292
+ # Run ESLint
293
+ npm run lint
294
+
295
+ # Run Vitest
296
+ npm run test
297
+ npm run test:watch
298
+ ```
57
299
 
58
300
  <!-- Badges -->
59
301
  [npm-version-src]: https://img.shields.io/npm/v/@stonecrop/nuxt/latest.svg?style=flat&colorA=020420&colorB=00DC82
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stonecrop/nuxt",
3
3
  "configKey": "stonecrop",
4
- "version": "0.6.0",
4
+ "version": "0.6.2",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -31,15 +31,16 @@ const module = defineNuxtModule({
31
31
  extendPages(async (pages) => {
32
32
  try {
33
33
  const pagePaths = pages.map((page) => page.path);
34
- if (pagePaths.includes("/")) {
35
- logger.error('Conflict found: existing root page "/" detected.');
36
- throw new Error("[@stonecrop/nuxt] Conflict found with existing root page");
34
+ if (!pagePaths.includes("/")) {
35
+ pages.unshift({
36
+ name: "stonecrop-home",
37
+ path: "/",
38
+ file: homepage
39
+ });
40
+ logger.log("Added Stonecrop home page at /");
41
+ } else {
42
+ logger.log("Skipping Stonecrop home page: root page already exists");
37
43
  }
38
- pages.unshift({
39
- name: "stonecrop-home",
40
- path: "/",
41
- file: homepage
42
- });
43
44
  for (const schema of schemas) {
44
45
  try {
45
46
  const schemaName = schema.replace(".json", "");
@@ -1,6 +1,7 @@
1
1
  import { install as AForm } from "@stonecrop/aform";
2
2
  import { install as ATable } from "@stonecrop/atable";
3
- import { Stonecrop } from "@stonecrop/stonecrop";
3
+ import { install as NodeEditor } from "@stonecrop/node-editor";
4
+ import StonecropPlugin from "@stonecrop/stonecrop";
4
5
  import { createPinia } from "pinia";
5
6
  import { defineNuxtPlugin, useRouter } from "nuxt/app";
6
7
  export default defineNuxtPlugin((nuxt) => {
@@ -10,5 +11,6 @@ export default defineNuxtPlugin((nuxt) => {
10
11
  app.use(pinia);
11
12
  app.use(AForm);
12
13
  app.use(ATable);
13
- app.use(Stonecrop, { router });
14
+ app.use(NodeEditor);
15
+ app.use(StonecropPlugin, { router });
14
16
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/nuxt",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Nuxt module for Stonecrop",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,9 +33,10 @@
33
33
  "dependencies": {
34
34
  "@nuxt/kit": "^4.2.0",
35
35
  "pinia": "^3.0.3",
36
- "@stonecrop/aform": "0.6.0",
37
- "@stonecrop/atable": "0.6.0",
38
- "@stonecrop/stonecrop": "0.6.0"
36
+ "@stonecrop/aform": "0.6.2",
37
+ "@stonecrop/node-editor": "0.6.2",
38
+ "@stonecrop/atable": "0.6.2",
39
+ "@stonecrop/stonecrop": "0.6.2"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@eslint/js": "^9.38.0",