diff --git a/aform/CHANGELOG.json b/aform/CHANGELOG.json index f7047a6f..eba829b3 100644 --- a/aform/CHANGELOG.json +++ b/aform/CHANGELOG.json @@ -1,6 +1,60 @@ { "name": "@stonecrop/aform", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/aform_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": { + "patch": [ + { + "comment": "add strict null checks to improve logic" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@stonecrop/aform_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/aform_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": {} + }, + { + "version": "0.3.5", + "tag": "@stonecrop/aform_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": { + "patch": [ + { + "comment": "fix broken table stories" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@stonecrop/aform_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/aform_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": { + "none": [ + { + "comment": "small style update to Adate" + } + ] + } + }, { "version": "0.3.2", "tag": "@stonecrop/aform_v0.3.2", diff --git a/aform/CHANGELOG.md b/aform/CHANGELOG.md index 31081f1c..75c452cb 100644 --- a/aform/CHANGELOG.md +++ b/aform/CHANGELOG.md @@ -1,6 +1,42 @@ # Change Log - @stonecrop/aform -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +### Patches + +- add strict null checks to improve logic + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +_Version update only_ + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +### Patches + +- fix broken table stories + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +### Updates + +- small style update to Adate ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/aform/package.json b/aform/package.json index f1c94e23..9b6e9bc1 100644 --- a/aform/package.json +++ b/aform/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/aform", - "version": "0.3.2", + "version": "0.3.8", "license": "MIT", "type": "module", "author": { diff --git a/aform/src/components/form/ACheckbox.vue b/aform/src/components/form/ACheckbox.vue index 3cea3b4f..f4e635f4 100644 --- a/aform/src/components/form/ACheckbox.vue +++ b/aform/src/components/form/ACheckbox.vue @@ -19,7 +19,14 @@ import { InputHTMLAttributes } from 'vue' import { ComponentProps } from '../../types' -const { label, required, readonly, uuid, validation = { errorMessage: ' ' } } = defineProps() +const { + schema, // don't remove to allow masking to work + label, + required, + readonly, + uuid, + validation = { errorMessage: ' ' }, +} = defineProps() const checkbox = defineModel() diff --git a/aform/src/components/form/ADate.vue b/aform/src/components/form/ADate.vue index ca2e6dfe..08276de8 100644 --- a/aform/src/components/form/ADate.vue +++ b/aform/src/components/form/ADate.vue @@ -19,6 +19,7 @@ import { useTemplateRef } from 'vue' import { ComponentProps } from '../../types' const { + schema, // don't remove to allow masking to work label = 'Date', required, readonly, @@ -47,6 +48,8 @@ const showPicker = () => { diff --git a/examples/docbuilder/index.ts b/examples/docbuilder/index.ts index 9bfdbe3d..1cb46a06 100644 --- a/examples/docbuilder/index.ts +++ b/examples/docbuilder/index.ts @@ -1,30 +1,23 @@ +import { createPinia } from 'pinia' import { createApp } from 'vue' -import '@stonecrop/aform/styles' -import '@stonecrop/atable/styles' import '@stonecrop/desktop/styles' import '@stonecrop/node-editor/styles' -import { AFieldset, AForm, ANumericInput, ATextInput } from '@stonecrop/aform' -import { ACell, ARow, ATableHeader, ATableModal, ATable } from '@stonecrop/atable' +import { install as ATablePlugin } from '@stonecrop/aform' +import { install as AFormPlugin } from '@stonecrop/atable' import { ActionSet, SheetNav } from '@stonecrop/desktop' -import { NodeEditor, StateEditor } from '@stonecrop/node-editor' +import { install as NodeEditorPlugin } from '@stonecrop/node-editor' import App from './App.vue' import router from './router' -let app = createApp(App) +const app = createApp(App) +const pinia = createPinia() +app.use(pinia) app.use(router) -app.component('ACell', ACell) -app.component('AFieldset', AFieldset) -app.component('AForm', AForm) -app.component('ANumericInput', ANumericInput) -app.component('ARow', ARow) -app.component('ATable', ATable) -app.component('ATableHeader', ATableHeader) -app.component('ATableModal', ATableModal) -app.component('ATextInput', ATextInput) -app.component('NodeEditor', NodeEditor) -app.component('StateEditor', StateEditor) +app.use(AFormPlugin) +app.use(ATablePlugin) +app.use(NodeEditorPlugin) app.component('ActionSet', ActionSet) app.component('SheetNav', SheetNav) app.mount('#app') diff --git a/examples/docbuilder/server.ts b/examples/docbuilder/server.ts index c364d477..98fafe66 100644 --- a/examples/docbuilder/server.ts +++ b/examples/docbuilder/server.ts @@ -20,7 +20,7 @@ export function makeServer({ environment = 'development' } = {}) { doctypes: [{ name: 'Issue' }, { name: 'Assignment' }, { name: 'User' }], stateMachines: [ { - name: 'Issue', + name: 'issue', machine: { id: 'Issue', initial: 'New', @@ -88,7 +88,7 @@ export function makeServer({ environment = 'development' } = {}) { }, }, { - name: 'Assignment', + name: 'assignment', machine: { id: 'Assignment', initial: 'New', @@ -133,7 +133,7 @@ export function makeServer({ environment = 'development' } = {}) { }, }, { - name: 'User', + name: 'user', machine: { id: 'User', invoke: { @@ -174,7 +174,7 @@ export function makeServer({ environment = 'development' } = {}) { ], meta: [ { - name: 'Issue', + name: 'issue', fields: [ { id: 'subject', @@ -225,7 +225,7 @@ export function makeServer({ environment = 'development' } = {}) { ], }, { - name: 'Assignment', + name: 'assignment', fields: [ { id: 'user', @@ -264,7 +264,7 @@ export function makeServer({ environment = 'development' } = {}) { ], }, { - name: 'User', + name: 'user', fields: [ { id: 'username', @@ -294,7 +294,7 @@ export function makeServer({ environment = 'development' } = {}) { ], actions: [ { - name: 'Issue', + name: 'issue', side_effects: [ { event_name: 'LOAD', @@ -321,7 +321,7 @@ export function makeServer({ environment = 'development' } = {}) { ], }, { - name: 'Assignment', + name: 'assignment', side_effects: [ { event_name: 'LOAD', @@ -348,7 +348,7 @@ export function makeServer({ environment = 'development' } = {}) { ], }, { - name: 'User', + name: 'user', side_effects: [ { event_name: 'LOAD', @@ -398,21 +398,24 @@ export function makeServer({ environment = 'development' } = {}) { }) this.get('/load_state_machine', (schema, request) => { - let machine = schema.stateMachines.findBy({ name: request.queryParams.doctype }) + const doctype = request.queryParams.doctype.toString().toLowerCase() + const machine = schema.stateMachines.findBy({ name: doctype }) return machine ? machine.attrs : new Response(400, { some: 'Not Found' }, { errors: ['StateMachine for Doctype not found'] }) }) this.get('/load_meta', (schema, request) => { - let meta = schema.meta.findBy({ name: request.queryParams.doctype }) + const doctype = request.queryParams.doctype.toString().toLowerCase() + const meta = schema.meta.findBy({ name: doctype }) return meta ? meta.attrs.fields : new Response(400, { some: 'Not Found' }, { errors: ['Metadata for Doctype not found'] }) }) this.get('/load_side_effects', (schema, request) => { - let actions = schema.actions.findBy({ name: request.queryParams.doctype }) + const doctype = request.queryParams.doctype.toString().toLowerCase() + const actions = schema.actions.findBy({ name: doctype }) return actions ? actions.attrs.side_effects : new Response(400, { some: 'Not Found' }, { errors: ['Actions for Doctype not found'] }) diff --git a/examples/docbuilder/vite.config.ts b/examples/docbuilder/vite.config.ts index 6a43aa7d..56d342f3 100644 --- a/examples/docbuilder/vite.config.ts +++ b/examples/docbuilder/vite.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ build: { sourcemap: true, lib: { - entry: resolve(projectRootDir, 'docbuilder/index.ts'), + entry: resolve(projectRootDir, 'index.ts'), name: '@stonecrop/examples', }, rollupOptions: { diff --git a/graphql_client/CHANGELOG.json b/graphql_client/CHANGELOG.json index b9872c80..33d2ca18 100644 --- a/graphql_client/CHANGELOG.json +++ b/graphql_client/CHANGELOG.json @@ -1,6 +1,42 @@ { "name": "@stonecrop/graphql-client", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/graphql-client_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": {} + }, + { + "version": "0.3.7", + "tag": "@stonecrop/graphql-client_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/graphql-client_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": {} + }, + { + "version": "0.3.5", + "tag": "@stonecrop/graphql-client_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": {} + }, + { + "version": "0.3.4", + "tag": "@stonecrop/graphql-client_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/graphql-client_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": {} + }, { "version": "0.3.2", "tag": "@stonecrop/graphql-client_v0.3.2", diff --git a/graphql_client/CHANGELOG.md b/graphql_client/CHANGELOG.md index 43c2b5b7..3cdd1936 100644 --- a/graphql_client/CHANGELOG.md +++ b/graphql_client/CHANGELOG.md @@ -1,6 +1,36 @@ # Change Log - @stonecrop/graphql-client -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +_Version update only_ + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +_Version update only_ + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +_Version update only_ + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +_Version update only_ ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/graphql_client/package.json b/graphql_client/package.json index 2704374c..41e8fd7a 100644 --- a/graphql_client/package.json +++ b/graphql_client/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/graphql-client", - "version": "0.3.2", + "version": "0.3.8", "license": "MIT", "type": "module", "author": { diff --git a/node_editor/CHANGELOG.json b/node_editor/CHANGELOG.json index 91cff41a..1e4c75b3 100644 --- a/node_editor/CHANGELOG.json +++ b/node_editor/CHANGELOG.json @@ -1,6 +1,42 @@ { "name": "@stonecrop/node-editor", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/node-editor_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": {} + }, + { + "version": "0.3.7", + "tag": "@stonecrop/node-editor_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/node-editor_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": {} + }, + { + "version": "0.3.5", + "tag": "@stonecrop/node-editor_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": {} + }, + { + "version": "0.3.4", + "tag": "@stonecrop/node-editor_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/node-editor_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": {} + }, { "version": "0.3.2", "tag": "@stonecrop/node-editor_v0.3.2", diff --git a/node_editor/CHANGELOG.md b/node_editor/CHANGELOG.md index 864b6dfa..36bad675 100644 --- a/node_editor/CHANGELOG.md +++ b/node_editor/CHANGELOG.md @@ -1,6 +1,36 @@ # Change Log - @stonecrop/node-editor -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +_Version update only_ + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +_Version update only_ + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +_Version update only_ + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +_Version update only_ ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/node_editor/package.json b/node_editor/package.json index 6f1bf1c1..c0e51409 100644 --- a/node_editor/package.json +++ b/node_editor/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/node-editor", - "version": "0.3.2", + "version": "0.3.8", "description": "Node editor UI for Stonecrop", "license": "MIT", "type": "module", diff --git a/rigs/stonecrop-rig/profiles/default/config/api-extractor-task.json b/rigs/stonecrop-rig/profiles/default/config/api-extractor-task.json index 56721e9b..ecc329c2 100644 --- a/rigs/stonecrop-rig/profiles/default/config/api-extractor-task.json +++ b/rigs/stonecrop-rig/profiles/default/config/api-extractor-task.json @@ -1,4 +1,3 @@ { - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json", - "useProjectTypescriptVersion": true + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/api-extractor-task.schema.json" } diff --git a/stonecrop/CHANGELOG.json b/stonecrop/CHANGELOG.json index 3ad67c83..f8b8ef01 100644 --- a/stonecrop/CHANGELOG.json +++ b/stonecrop/CHANGELOG.json @@ -1,6 +1,60 @@ { "name": "@stonecrop/stonecrop", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/stonecrop_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": { + "patch": [ + { + "comment": "add strict null checks to improve logic" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@stonecrop/stonecrop_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/stonecrop_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": { + "patch": [ + { + "comment": "fix stonecrop documentation generation" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@stonecrop/stonecrop_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": { + "patch": [ + { + "comment": "throw error if Stonecrop plugin isn't installed" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@stonecrop/stonecrop_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/stonecrop_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": {} + }, { "version": "0.3.2", "tag": "@stonecrop/stonecrop_v0.3.2", diff --git a/stonecrop/CHANGELOG.md b/stonecrop/CHANGELOG.md index 8f12dc1a..fc650c52 100644 --- a/stonecrop/CHANGELOG.md +++ b/stonecrop/CHANGELOG.md @@ -1,6 +1,42 @@ # Change Log - @stonecrop/stonecrop -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +### Patches + +- add strict null checks to improve logic + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +### Patches + +- fix stonecrop documentation generation + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +### Patches + +- throw error if Stonecrop plugin isn't installed + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +_Version update only_ ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/stonecrop/config/heft.json b/stonecrop/config/heft.json deleted file mode 100644 index 99244526..00000000 --- a/stonecrop/config/heft.json +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Defines configuration used by core Heft. - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - - "phasesByName": { - "build": { - "phaseDescription": "This phase compiles the project source code.", - - "cleanFiles": [{ "sourcePath": "dist" }], - - "tasksByName": { - "typescript": { - "taskPlugin": { - "pluginPackage": "@rushstack/heft-typescript-plugin" - } - } - } - } - } -} diff --git a/stonecrop/package.json b/stonecrop/package.json index f0e01486..f953538f 100644 --- a/stonecrop/package.json +++ b/stonecrop/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/stonecrop", - "version": "0.3.2", + "version": "0.3.8", "description": "schema helper", "license": "MIT", "type": "module", @@ -31,8 +31,8 @@ "src/*" ], "scripts": { - "prepublish": "heft build && vite build", - "build": "heft build && vite build", + "prepublish": "heft build && vite build && rushx docs", + "build": "heft build && vite build && rushx docs", "docs": "api-documenter markdown -i temp -o ../docs/stonecrop", "lint": "eslint . --ext .ts,.vue", "preview": "vite preview" @@ -41,7 +41,7 @@ "immutable": "^4.3.0", "pinia": "^2.3.0", "pinia-shared-state": "^0.3.0", - "pinia-xstate": "^1.0.9", + "pinia-xstate": "^2.2.1", "vue": "^3.5.11", "vue-router": "^4.4.0", "xstate": "^4.38.3" diff --git a/stonecrop/src/composable.ts b/stonecrop/src/composable.ts index 622e7d19..3b0dced3 100644 --- a/stonecrop/src/composable.ts +++ b/stonecrop/src/composable.ts @@ -4,21 +4,41 @@ import Registry from './registry' import { Stonecrop } from './stonecrop' import { useDataStore } from './stores/data' -type StonecropReturn = { +/** + * Stonecrop composable return type + * @public + */ +export type StonecropReturn = { stonecrop: Ref isReady: Ref } +/** + * Stonecrop composable + * @param registry - An existing Stonecrop Registry instance + * @returns The Stonecrop instance and a boolean indicating if Stonecrop is setup and ready + * @throws Error if the Stonecrop plugin is not enabled before using the composable + * @public + */ export function useStonecrop(registry?: Registry): StonecropReturn { if (!registry) { registry = inject('$registry') } - const store = useDataStore() + let store: ReturnType + try { + store = useDataStore() + } catch (e) { + throw new Error('Please enable the Stonecrop plugin before using the Stonecrop composable') + } + + // @ts-expect-error TODO: handle empty registry passed to Stonecrop const stonecrop = ref(new Stonecrop(registry, store)) const isReady = ref(false) onBeforeMount(async () => { + if (!registry) return + const route = registry.router.currentRoute.value const doctypeSlug = route.params.records?.toString().toLowerCase() const recordId = route.params.record?.toString().toLowerCase() @@ -29,19 +49,22 @@ export function useStonecrop(registry?: Registry): StonecropReturn { } // setup doctype via registry - const doctype = await registry.getMeta(doctypeSlug) - registry.addDoctype(doctype) - stonecrop.value.setup(doctype) - - if (doctypeSlug) { - if (recordId) { - await stonecrop.value.getRecord(doctype, recordId) - } else { - await stonecrop.value.getRecords(doctype) + const doctype = await registry.getMeta?.(doctypeSlug) + if (doctype) { + registry.addDoctype(doctype) + stonecrop.value.setup(doctype) + + if (doctypeSlug) { + if (recordId) { + await stonecrop.value.getRecord(doctype, recordId) + } else { + await stonecrop.value.getRecords(doctype) + } } + + stonecrop.value.runAction(doctype, 'LOAD', recordId ? [recordId] : undefined) } - stonecrop.value.runAction(doctype, 'LOAD', recordId ? [recordId] : undefined) isReady.value = true }) diff --git a/stonecrop/src/doctype.ts b/stonecrop/src/doctype.ts index 050b5316..3b67d3ba 100644 --- a/stonecrop/src/doctype.ts +++ b/stonecrop/src/doctype.ts @@ -2,14 +2,47 @@ import { Component } from 'vue' import type { ImmutableDoctype } from './types' +/** + * Doctype Meta class + * @public + */ export default class DoctypeMeta { + /** + * The doctype name + * @public + * @readonly + */ readonly doctype: string + + /** + * The doctype schema + * @public + * @readonly + */ readonly schema: ImmutableDoctype['schema'] + + /** + * The doctype workflow + * @public + * @readonly + */ readonly workflow: ImmutableDoctype['workflow'] + + /** + * The doctype actions + * @public + * @readonly + */ readonly actions: ImmutableDoctype['actions'] + + /** + * The doctype component + * @public + * @readonly + */ + readonly component?: Component // TODO: allow different components for different views; probably // should be defined in the schema instead? - readonly component?: Component constructor( doctype: string, @@ -25,15 +58,15 @@ export default class DoctypeMeta { this.component = component } + /** + * Converts the registered doctype to a slug (kebab-case) + * @returns The slugified doctype string + * @public + */ get slug() { - // kebab case return this.doctype .replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/[\s_]+/g, '-') .toLowerCase() } - - get __typename() { - return this.doctype - } } diff --git a/stonecrop/src/index.ts b/stonecrop/src/index.ts index e9192138..04294f8d 100644 --- a/stonecrop/src/index.ts +++ b/stonecrop/src/index.ts @@ -1,7 +1,10 @@ -import { useStonecrop } from './composable' +export type { BaseSchema, FieldsetSchema, FormSchema, SchemaTypes, TableSchema } from '@stonecrop/aform' +export type { CellContext, TableColumn, TableConfig, TableRow } from '@stonecrop/atable' + +import { type StonecropReturn, useStonecrop } from './composable' import DoctypeMeta from './doctype' import Registry from './registry' import Stonecrop from './plugins' export type { ImmutableDoctype, MutableDoctype, Schema, InstallOptions } from './types' -export { DoctypeMeta, Registry, Stonecrop, useStonecrop } +export { DoctypeMeta, Registry, Stonecrop, StonecropReturn, useStonecrop } diff --git a/stonecrop/src/plugins/index.ts b/stonecrop/src/plugins/index.ts index 2d4e1eac..6a41e716 100644 --- a/stonecrop/src/plugins/index.ts +++ b/stonecrop/src/plugins/index.ts @@ -5,6 +5,34 @@ import router from '../router' import { pinia } from '../stores' import type { InstallOptions } from '../types' +/** + * Stonecrop Vue plugin + * @param app - The Vue app instance + * @param options - The plugin options + * @example + * ```ts + * + * import { createApp } from 'vue' + * import Stonecrop from 'stonecrop' + * + * import App from './App.vue' + * + * const app = createApp(App) + * app.use(Stonecrop, { + * router, + * components: { + * // register custom components + * }, + * getMeta: async (doctype: string) => { + * // fetch doctype meta from API + * }, + * }) + * + * app.mount('#app') + * ``` + * + * @public + */ const plugin: Plugin = { install: (app: App, options?: InstallOptions) => { const appRouter = options?.router || router diff --git a/stonecrop/src/registry.ts b/stonecrop/src/registry.ts index 2f215e9b..ba2a534e 100644 --- a/stonecrop/src/registry.ts +++ b/stonecrop/src/registry.ts @@ -2,11 +2,39 @@ import { Router } from 'vue-router' import DoctypeMeta from './doctype' +/** + * Stonecrop Registry class + * @public + */ export default class Registry { + /** + * The root Registry instance + */ static _root: Registry + + /** + * The name of the Registry instance + * + * @defaultValue 'Registry' + */ name: string + + /** + * The Vue router instance + * @see {@link https://router.vuejs.org/} + */ router: Router + + /** + * The registry property contains a collection of doctypes + * @see {@link DoctypeMeta} + */ registry: Record + + /** + * The getMeta function fetches doctype metadata from an API + * @see {@link DoctypeMeta} + */ getMeta?: (doctype: string) => DoctypeMeta | Promise constructor(router: Router, getMeta?: (doctype: string) => DoctypeMeta | Promise) { @@ -20,11 +48,17 @@ export default class Registry { this.getMeta = getMeta } + /** + * Get doctype metadata + * @param doctype - The doctype to fetch metadata for + * @returns The doctype metadata + * @see {@link DoctypeMeta} + */ addDoctype(doctype: DoctypeMeta) { if (!(doctype.doctype in Object.keys(this.registry))) { this.registry[doctype.slug] = doctype } - if (!this.router.hasRoute(doctype.doctype)) { + if (!this.router.hasRoute(doctype.doctype) && doctype.component) { this.router.addRoute({ path: `/${doctype.slug}`, name: doctype.slug, diff --git a/stonecrop/src/stonecrop.ts b/stonecrop/src/stonecrop.ts index e8b7d674..7e513a4b 100644 --- a/stonecrop/src/stonecrop.ts +++ b/stonecrop/src/stonecrop.ts @@ -4,25 +4,28 @@ import Registry from './registry' import { useDataStore } from './stores/data' import type { ImmutableDoctype, Schema } from './types' +/** + * Stonecrop class + * @public + */ export class Stonecrop { /** - * @property {Stonecrop} _root - * @description The root Stonecrop instance + * The root Stonecrop instance */ static _root: Stonecrop /** - * @property {string} name - * @description The name of the Stonecrop instance - * @example - * 'Stonecrop' + * The name of the Stonecrop instance + * @readonly + * + * @defaultValue 'Stonecrop' */ readonly name = 'Stonecrop' /** - * @property {Registry} registry - * @description The registry is an immutable collection of doctypes + * The registry is an immutable collection of doctypes * @example + * ```ts * { * 'task': { * doctype: 'Task', @@ -34,15 +37,21 @@ export class Stonecrop { * }, * ... * } + * ``` * @see {@link Registry} * @see {@link DoctypeMeta} */ readonly registry: Registry /** - * @property {Schema} schema - The Stonecrop schema - * @description The schema is a subset of the registry + * The Pinia store that manages the mutable records + */ + store: ReturnType + + /** + * schema - The Stonecrop schema; the schema is a subset of the registry * @example + * ```ts * { * doctype: 'Task', * schema: { @@ -51,43 +60,36 @@ export class Stonecrop { * ... * } * } + * ``` * @see {@link Registry} * @see {@link DoctypeMeta} * @see {@link DoctypeMeta.schema} */ - schema: Schema - - /** - * @property {ImmutableDoctype['workflow']} workflow - * @description The workflow is a subset of the registry - */ - workflow: ImmutableDoctype['workflow'] + schema?: Schema /** - * @property {ImmutableDoctype['actions']} actions - * @description The actions are a subset of the registry + * The workflow is a subset of the registry */ - actions: ImmutableDoctype['actions'] + workflow?: ImmutableDoctype['workflow'] /** - * @property {ReturnType} store - * @description The Pinia store that manages the mutable records + * The actions are a subset of the registry */ - store: ReturnType + actions?: ImmutableDoctype['actions'] /** - * @constructor - * @param {Registry} registry - The immutable registry - * @param {ReturnType} store - The mutable Pinia store - * @param {Schema} [schema] - (optional) The Stonecrop schema - * @param {ImmutableDoctype['workflow']} [workflow] - (optional) The Stonecrop workflow - * @param {ImmutableDoctype['actions']} [actions] - (optional) The Stonecrop actions - * @returns {Stonecrop} The Stonecrop instance - * @description The Stonecrop constructor initializes a new Stonecrop instance with the given registry, store, schema, workflow, and actions. If a Stonecrop instance has already been created, it returns the existing instance instead of creating a new one. + * @param registry - The immutable registry + * @param store - The mutable Pinia store + * @param schema - The Stonecrop schema + * @param workflow - The Stonecrop workflow + * @param actions - The Stonecrop actions + * @returns The Stonecrop instance with the given registry, store, schema, workflow, and actions. If a Stonecrop instance has already been created, it returns the existing instance instead of creating a new one. * @example + * ```ts * const registry = new Registry() * const store = useDataStore() - * const stonecrop = new Stonecrop(registry, store, schema, workflow, actions) + * const stonecrop = new Stonecrop(registry, store) + * ``` */ constructor( registry: Registry, @@ -108,13 +110,13 @@ export class Stonecrop { } /** - * @method setup - * @param {DoctypeMeta} doctype - The doctype to setup - * @returns {void} - * @description Sets up the Stonecrop instance with the given doctype + * Sets up the Stonecrop instance with the given doctype + * @param doctype - The doctype to setup * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.setup(doctype) + * ``` */ setup(doctype: DoctypeMeta): void { void this.getMeta(doctype) @@ -123,28 +125,29 @@ export class Stonecrop { } /** - * @method getMeta - * @param {DoctypeMeta} doctype - The doctype to get meta for - * @returns {DoctypeMeta} - * @see {@link DoctypeMeta} + * Gets the meta for the given doctype + * @param doctype - The doctype to get meta for + * @returns The meta for the given doctype * @throws NotImplementedError - * @description Gets the meta for the given doctype * @example + * ```ts * const doctype = await registry.getMeta('Task') * const meta = stonecrop.getMeta(doctype) + * ``` + * @see {@link DoctypeMeta} */ getMeta(doctype: DoctypeMeta): DoctypeMeta | Promise | never { return this.registry.getMeta ? this.registry.getMeta(doctype.doctype) : new NotImplementedError(doctype.doctype) } /** - * @method getWorkflow - * @param {DoctypeMeta} doctype - The doctype to get workflow for - * @returns {void} - * @description Gets the workflow for the given doctype + * Gets the workflow for the given doctype + * @param doctype - The doctype to get workflow for * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.getWorkflow(doctype) + * ``` */ getWorkflow(doctype: DoctypeMeta): void { const doctypeRegistry = this.registry.registry[doctype.slug] @@ -152,13 +155,13 @@ export class Stonecrop { } /** - * @method getActions - * @param {DoctypeMeta} doctype - The doctype to get actions for - * @returns {void} - * @description Gets the actions for the given doctype + * Gets the actions for the given doctype + * @param doctype - The doctype to get actions for * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.getActions(doctype) + * ``` */ getActions(doctype: DoctypeMeta): void { const doctypeRegistry = this.registry.registry[doctype.slug] @@ -166,18 +169,20 @@ export class Stonecrop { } /** - * @method getRecords - * @param {DoctypeMeta} doctype - The doctype to get records for - * @param {RequestInit} [filters] - The filters to apply to the records - * @returns {Promise} - * @description Gets the records for the given doctype + * Gets the records for the given doctype + * @param doctype - The doctype to get records for + * @param filters - The filters to apply to the records * @example + * ```ts * const doctype = await registry.getMeta('Task') * await stonecrop.getRecords(doctype) + * ``` * @example + * ```ts * const doctype = await registry.getMeta('Task') * const filters = JSON.stringify({ status: 'Open' }) * await stonecrop.getRecords(doctype, { body: filters }) + * ``` */ async getRecords(doctype: DoctypeMeta, filters?: RequestInit): Promise { this.store.$patch({ records: [] }) @@ -187,14 +192,14 @@ export class Stonecrop { } /** - * @method getRecord - * @param {DoctypeMeta} doctype - The doctype to get record for - * @param {string} id - The id of the record to get - * @returns {Promise} - * @description Gets the record for the given doctype and id + * Gets the record for the given doctype and id + * @param doctype - The doctype to get record for + * @param id - The id of the record to get * @example + * ```ts * const doctype = await registry.getMeta('Task') * await stonecrop.getRecord(doctype, 'TASK-00001') + * ``` */ async getRecord(doctype: DoctypeMeta, id: string): Promise { this.store.$patch({ record: {} }) @@ -204,40 +209,49 @@ export class Stonecrop { } /** - * @method runAction - * @param {DoctypeMeta} doctype - The doctype to run action for - * @param {string} action - The action to run - * @param {string[]} [id] - The id(s) of the record(s) to run action on - * @returns {void} - * @description Runs the action for the given doctype and id + * Runs the action for the given doctype and id + * @param doctype - The doctype to run action for + * @param action - The action to run + * @param id - The id(s) of the record(s) to run action on * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.runAction(doctype, 'CREATE') + * ``` * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.runAction(doctype, 'UPDATE', ['TASK-00001']) + * ``` * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.runAction(doctype, 'DELETE', ['TASK-00001']) + * ``` * @example + * ```ts * const doctype = await registry.getMeta('Task') * stonecrop.runAction(doctype, 'TRANSITION', ['TASK-00001', 'TASK-00002']) + * ``` */ runAction(doctype: DoctypeMeta, action: string, id?: string[]): void { const doctypeRegistry = this.registry.registry[doctype.slug] - const actions = doctypeRegistry.actions.get(action) + const actions = doctypeRegistry.actions?.get(action) // trigger the action on the state machine - const { initialState } = this.workflow - this.workflow.transition(initialState, { type: action }) - - // run actions after state machine transition - if (actions.length > 0) { - actions.forEach(action => { - // eslint-disable-next-line @typescript-eslint/no-implied-eval - const actionFn = new Function(action) - actionFn(id) - }) + if (this.workflow) { + const { initialState } = this.workflow + this.workflow.transition(initialState, { type: action }) + + // run actions after state machine transition + // TODO: should this happen with or without the workflow? + if (actions && actions.length > 0) { + actions.forEach(action => { + // eslint-disable-next-line @typescript-eslint/no-implied-eval + const actionFn = new Function(action) + actionFn(id) + }) + } } } } diff --git a/stonecrop/src/stores/xstate.ts b/stonecrop/src/stores/xstate.ts index 493a298a..e4c0dd0c 100644 --- a/stonecrop/src/stores/xstate.ts +++ b/stonecrop/src/stores/xstate.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia' -import xstate from 'pinia-xstate' +import { xstate } from 'pinia-xstate' import { createMachine } from 'xstate' export const counterMachine = createMachine( diff --git a/stonecrop/src/types/index.ts b/stonecrop/src/types/index.ts index 1aedd627..bc0bcc6d 100644 --- a/stonecrop/src/types/index.ts +++ b/stonecrop/src/types/index.ts @@ -1,30 +1,46 @@ -import { SchemaTypes } from '@stonecrop/aform' +import type { SchemaTypes } from '@stonecrop/aform' import { List, Map } from 'immutable' -import { Component } from 'vue' -import { Router } from 'vue-router' -import { MachineConfig, StateMachine } from 'xstate' +import type { Component } from 'vue' +import type { Router } from 'vue-router' +import type { MachineConfig, StateMachine } from 'xstate' import DoctypeMeta from '../doctype' +/** + * Immutable Doctype type for Stonecrop instances + * @public + */ export type ImmutableDoctype = { // TODO: allow schema to be a function readonly schema?: List - readonly workflow: StateMachine + readonly workflow: StateMachine readonly actions?: Map } +/** + * Mutable Doctype type for Stonecrop instances + * @public + */ export type MutableDoctype = { // TODO: allow schema to be a function schema?: SchemaTypes[] - workflow: MachineConfig + workflow: MachineConfig actions?: Record } +/** + * Schema type for Stonecrop instances + * @public + */ export type Schema = { doctype: string schema: List } +/** + * Install options for Stonecrop Vue plugin + * @public + */ export type InstallOptions = { router?: Router components?: Record diff --git a/themes/CHANGELOG.json b/themes/CHANGELOG.json index 18f88071..cae97467 100644 --- a/themes/CHANGELOG.json +++ b/themes/CHANGELOG.json @@ -1,6 +1,42 @@ { "name": "@stonecrop/themes", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/themes_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": {} + }, + { + "version": "0.3.7", + "tag": "@stonecrop/themes_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/themes_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": {} + }, + { + "version": "0.3.5", + "tag": "@stonecrop/themes_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": {} + }, + { + "version": "0.3.4", + "tag": "@stonecrop/themes_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/themes_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": {} + }, { "version": "0.3.2", "tag": "@stonecrop/themes_v0.3.2", diff --git a/themes/CHANGELOG.md b/themes/CHANGELOG.md index 408a2712..7b90446f 100644 --- a/themes/CHANGELOG.md +++ b/themes/CHANGELOG.md @@ -1,6 +1,36 @@ # Change Log - @stonecrop/themes -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +_Version update only_ + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +_Version update only_ + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +_Version update only_ + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +_Version update only_ ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/themes/package.json b/themes/package.json index 92e29af8..cb1e99f3 100644 --- a/themes/package.json +++ b/themes/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/themes", - "version": "0.3.2", + "version": "0.3.8", "type": "module", "author": { "name": "Tyler Matteson", diff --git a/tsconfig.options.json b/tsconfig.options.json index 4186ec92..c3f3638a 100644 --- a/tsconfig.options.json +++ b/tsconfig.options.json @@ -10,7 +10,8 @@ "disableReferencedProjectLoad": true, "emitDeclarationOnly": true, "isolatedModules": true, - "skipLibCheck": true + "skipLibCheck": true, + "strictNullChecks": true }, "exclude": ["node_modules", "**/*.spec.ts"] } diff --git a/utilities/CHANGELOG.json b/utilities/CHANGELOG.json index c94d7e53..0cf56653 100644 --- a/utilities/CHANGELOG.json +++ b/utilities/CHANGELOG.json @@ -1,6 +1,48 @@ { "name": "@stonecrop/utilities", "entries": [ + { + "version": "0.3.8", + "tag": "@stonecrop/utilities_v0.3.8", + "date": "Thu, 09 Jan 2025 11:21:58 GMT", + "comments": { + "patch": [ + { + "comment": "add strict null checks to improve logic" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@stonecrop/utilities_v0.3.7", + "date": "Fri, 03 Jan 2025 06:27:07 GMT", + "comments": {} + }, + { + "version": "0.3.6", + "tag": "@stonecrop/utilities_v0.3.6", + "date": "Fri, 27 Dec 2024 09:24:01 GMT", + "comments": {} + }, + { + "version": "0.3.5", + "tag": "@stonecrop/utilities_v0.3.5", + "date": "Tue, 24 Dec 2024 11:42:53 GMT", + "comments": {} + }, + { + "version": "0.3.4", + "tag": "@stonecrop/utilities_v0.3.4", + "date": "Wed, 18 Dec 2024 09:54:31 GMT", + "comments": {} + }, + { + "version": "0.3.3", + "tag": "@stonecrop/utilities_v0.3.3", + "date": "Tue, 17 Dec 2024 13:42:30 GMT", + "comments": {} + }, { "version": "0.3.2", "tag": "@stonecrop/utilities_v0.3.2", diff --git a/utilities/CHANGELOG.md b/utilities/CHANGELOG.md index 956e378b..86046e4f 100644 --- a/utilities/CHANGELOG.md +++ b/utilities/CHANGELOG.md @@ -1,6 +1,38 @@ # Change Log - @stonecrop/utilities -This log was last generated on Tue, 17 Dec 2024 10:07:54 GMT and should not be manually modified. +This log was last generated on Thu, 09 Jan 2025 11:21:58 GMT and should not be manually modified. + +## 0.3.8 +Thu, 09 Jan 2025 11:21:58 GMT + +### Patches + +- add strict null checks to improve logic + +## 0.3.7 +Fri, 03 Jan 2025 06:27:07 GMT + +_Version update only_ + +## 0.3.6 +Fri, 27 Dec 2024 09:24:01 GMT + +_Version update only_ + +## 0.3.5 +Tue, 24 Dec 2024 11:42:53 GMT + +_Version update only_ + +## 0.3.4 +Wed, 18 Dec 2024 09:54:31 GMT + +_Version update only_ + +## 0.3.3 +Tue, 17 Dec 2024 13:42:30 GMT + +_Version update only_ ## 0.3.2 Tue, 17 Dec 2024 10:07:54 GMT diff --git a/utilities/package.json b/utilities/package.json index 3bc3959f..1e7194fd 100644 --- a/utilities/package.json +++ b/utilities/package.json @@ -1,6 +1,6 @@ { "name": "@stonecrop/utilities", - "version": "0.3.2", + "version": "0.3.8", "license": "MIT", "type": "module", "author": { diff --git a/utilities/src/composables/keyboard.ts b/utilities/src/composables/keyboard.ts index 0f75ca24..d55ad27f 100644 --- a/utilities/src/composables/keyboard.ts +++ b/utilities/src/composables/keyboard.ts @@ -53,7 +53,7 @@ const getTopCell = (event: KeyboardEvent) => { const $table = $target.parentElement?.parentElement if ($table) { const $firstRow = $table.firstElementChild - const $navCell = $firstRow.children[$target.cellIndex] as HTMLElement + const $navCell = $firstRow?.children[$target.cellIndex] as HTMLElement if ($navCell) { $topCell = $navCell } @@ -112,7 +112,7 @@ const getBottomCell = (event: KeyboardEvent) => { const $table = $target.parentElement?.parentElement if ($table) { const $lastRow = $table.lastElementChild - const $navCell = $lastRow.children[$target.cellIndex] as HTMLElement + const $navCell = $lastRow?.children[$target.cellIndex] as HTMLElement if ($navCell) { $bottomCell = $navCell } @@ -175,7 +175,7 @@ const _getNextCell = (element: HTMLElement): HTMLElement | undefined => { const getFirstCell = (event: KeyboardEvent) => { const $target = event.target as HTMLElement const $parent = $target.parentElement - const $firstCell = $parent.firstElementChild as HTMLElement | null + const $firstCell = $parent?.firstElementChild as HTMLElement | null if ($firstCell && (!isFocusable($firstCell) || !isVisible($firstCell))) { return _getNextCell($firstCell) } @@ -185,7 +185,7 @@ const getFirstCell = (event: KeyboardEvent) => { const getLastCell = (event: KeyboardEvent) => { const $target = event.target as HTMLElement const $parent = $target.parentElement - const $lastCell = $parent.lastElementChild as HTMLElement | null + const $lastCell = $parent?.lastElementChild as HTMLElement | null if ($lastCell && (!isFocusable($lastCell) || !isVisible($lastCell))) { return _getPrevCell($lastCell) } @@ -370,7 +370,7 @@ export function useKeyboardNav(options: KeyboardNavigationOptions[]) { } } else if (option.selectors instanceof HTMLElement) { selectors.push(option.selectors) - } else { + } else if (option.selectors?.value) { if (Array.isArray(option.selectors.value)) { for (const element of option.selectors.value) { if (element instanceof HTMLElement) {