@shamar/core 0.1.0 → 0.1.1
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 +180 -0
- package/package.json +6 -1
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# @shamar/core
|
|
2
|
+
|
|
3
|
+
Filament-inspired **Resource DSL** for Shamar — forms, tables, infolists, actions, navigation, and auth contracts. ORM-agnostic: persistence lives in adapters (`@shamar/lucid`, `@shamar/mongoose`) or your own `DataAdapter`.
|
|
4
|
+
|
|
5
|
+
Most apps consume this transitively via [`@shamar/adonis`](../adonis). Use `@shamar/core` directly when building a custom host or adapter.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @shamar/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No peer dependencies.
|
|
14
|
+
|
|
15
|
+
## Resource skeleton
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
Resource,
|
|
20
|
+
form,
|
|
21
|
+
table,
|
|
22
|
+
infolist,
|
|
23
|
+
actions,
|
|
24
|
+
Section,
|
|
25
|
+
TextInput,
|
|
26
|
+
Toggle,
|
|
27
|
+
TextColumn,
|
|
28
|
+
TextEntry,
|
|
29
|
+
} from '@shamar/core'
|
|
30
|
+
import User from '#models/user'
|
|
31
|
+
|
|
32
|
+
export default class UserResource extends Resource {
|
|
33
|
+
static model = User
|
|
34
|
+
static slug = 'users'
|
|
35
|
+
static label = 'Users'
|
|
36
|
+
static singularLabel = 'User'
|
|
37
|
+
static recordTitleField = 'email'
|
|
38
|
+
static navigationGroup = 'System'
|
|
39
|
+
static navigationSort = 5
|
|
40
|
+
|
|
41
|
+
static form() {
|
|
42
|
+
return form((f) => {
|
|
43
|
+
f.schema([
|
|
44
|
+
Section.make('Identity')
|
|
45
|
+
.columns(2)
|
|
46
|
+
.schema([
|
|
47
|
+
TextInput.make('fullName').required(),
|
|
48
|
+
TextInput.make('email').email().required().unique(),
|
|
49
|
+
TextInput.make('password').password().createOnly().required(),
|
|
50
|
+
Toggle.make('active'),
|
|
51
|
+
]),
|
|
52
|
+
])
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static table() {
|
|
57
|
+
return table((t) => {
|
|
58
|
+
t.schema([
|
|
59
|
+
TextColumn.make('fullName').sortable().searchable(),
|
|
60
|
+
TextColumn.make('email').sortable().searchable().filterable(),
|
|
61
|
+
TextColumn.make('active').boolean().filterable(),
|
|
62
|
+
])
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static infolist() {
|
|
67
|
+
return infolist((i) => {
|
|
68
|
+
i.schema([
|
|
69
|
+
Section.make('User').schema([
|
|
70
|
+
TextEntry.make('fullName'),
|
|
71
|
+
TextEntry.make('email'),
|
|
72
|
+
TextEntry.make('active').boolean(),
|
|
73
|
+
]),
|
|
74
|
+
])
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static resourceActions() {
|
|
79
|
+
return actions((a) => {
|
|
80
|
+
a.create()
|
|
81
|
+
a.view()
|
|
82
|
+
a.edit()
|
|
83
|
+
a.delete()
|
|
84
|
+
a.bulkDelete()
|
|
85
|
+
a.header('export', 'Export').ability('viewAny')
|
|
86
|
+
a.row('archive', 'Archive').confirm('Archive this user?')
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Builders
|
|
93
|
+
|
|
94
|
+
| Builder | Purpose |
|
|
95
|
+
|---------|---------|
|
|
96
|
+
| `form((f) => …)` | Create / edit schemas |
|
|
97
|
+
| `table((t) => …)` | List columns, filters, group-by defaults |
|
|
98
|
+
| `infolist((i) => …)` | Show / view schemas |
|
|
99
|
+
| `actions((a) => …)` | Create, view, edit, delete, bulk, header, and row actions |
|
|
100
|
+
| `panel(id)` | Multi-panel registration (also re-exported from `@shamar/adonis`) |
|
|
101
|
+
|
|
102
|
+
Containers use `.schema([...])` for children. Layout width uses `.columns(n)` on sections and fieldsets.
|
|
103
|
+
|
|
104
|
+
### Layout
|
|
105
|
+
|
|
106
|
+
`Section`, `Fieldset`, `Grid`, `Group`, `Flex`, `Tabs` / `Tab`, `Wizard` / `Step`, `Callout`, `EmptyState`, `Placeholder`
|
|
107
|
+
|
|
108
|
+
### Form fields
|
|
109
|
+
|
|
110
|
+
`TextInput`, `Textarea`, `Select`, `Toggle`, `Checkbox`, `Radio`, `CheckboxList`, `Hidden`, `ColorPicker`, `TagsInput`, `DatePicker`, `DateTimePicker`, `FileUpload`, `RelationTable`, `PermissionsAssignment`, `AbilitiesAssignment`
|
|
111
|
+
|
|
112
|
+
### Table / infolist
|
|
113
|
+
|
|
114
|
+
`TextColumn` · `TextEntry`, `IconEntry`, `ColorEntry`, `ImageEntry`
|
|
115
|
+
|
|
116
|
+
## Common modifiers
|
|
117
|
+
|
|
118
|
+
| Modifier | Applies to | Notes |
|
|
119
|
+
|----------|------------|--------|
|
|
120
|
+
| `.required()` | fields | Validation |
|
|
121
|
+
| `.live()` / `.afterStateUpdated()` | fields | Reactive form-state POST |
|
|
122
|
+
| `.searchable()` | fields / columns | Global list search |
|
|
123
|
+
| `.sortable()` | columns | Order by |
|
|
124
|
+
| `.filterable()` / `.groupable()` | columns | List Filters / Group menus |
|
|
125
|
+
| `.relationship(slug, titleAttr)` | relation fields | BelongsTo / M2M pickers |
|
|
126
|
+
| `.unique()` | fields | Uses adapter `exists()` |
|
|
127
|
+
| `.createOnly()` / `.editOnly()` | fields | Visibility by page |
|
|
128
|
+
| `.columnSpan(n)` / `.columnSpanFull()` | fields / entries | Grid span |
|
|
129
|
+
|
|
130
|
+
List defaults:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
table((t) => {
|
|
134
|
+
t.defaultFilters([{ field: 'active', value: true, label: 'Active' }])
|
|
135
|
+
t.defaultGroupBy('status')
|
|
136
|
+
t.schema([/* columns */])
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Soft delete & tenancy hooks
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
export default class OrderResource extends Resource {
|
|
144
|
+
static softDelete = true // or { field: 'deleted_at' }
|
|
145
|
+
// static companyScoped = true // when tenancy is enabled in the host
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Adapters exclude soft-deleted rows from list/find and stamp the field on delete when enabled.
|
|
150
|
+
|
|
151
|
+
## Auth contracts
|
|
152
|
+
|
|
153
|
+
`Resource` exposes `canAccess` / `canViewAny` / `canView` / `canCreate` / `canEdit` / `canDelete`. Set `static policy` to a Cherubim `Policy` (or register via Adonis `auth.policies`) for record rules and `scopeList`.
|
|
154
|
+
|
|
155
|
+
See [`@shamar/cherubim`](../cherubim) for RBAC, policies, and API keys.
|
|
156
|
+
|
|
157
|
+
## Custom ORM (`DataAdapter`)
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import type { DataAdapter } from '@shamar/core'
|
|
161
|
+
|
|
162
|
+
const adapter: DataAdapter = {
|
|
163
|
+
list(meta, query) { /* … */ },
|
|
164
|
+
findOne(meta, id) { /* … */ },
|
|
165
|
+
create(meta, data) { /* … */ },
|
|
166
|
+
update(meta, id, data) { /* … */ },
|
|
167
|
+
delete(meta, id) { /* … */ },
|
|
168
|
+
exists(meta, column, value, options) { /* … */ },
|
|
169
|
+
search(meta, query) { /* … */ },
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Pass it as `adapter` in `@shamar/adonis` `defineConfig`, or wire it in a custom host.
|
|
174
|
+
|
|
175
|
+
## Related
|
|
176
|
+
|
|
177
|
+
- [`@shamar/adonis`](../adonis) — Adonis provider, routes, Edge UI
|
|
178
|
+
- [`@shamar/lucid`](../lucid) / [`@shamar/mongoose`](../mongoose) — stock adapters
|
|
179
|
+
- [`@shamar/cherubim`](../cherubim) — auth & policies
|
|
180
|
+
- [Playground](../../apps/playground) — living demo
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shamar/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Filament-inspired resource DSL for Shamar admin (ORM-agnostic core).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/coolsam726/shamar.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
7
12
|
"main": "./dist/index.js",
|
|
8
13
|
"types": "./dist/index.d.ts",
|
|
9
14
|
"exports": {
|