@burgantech/pseudo-ui 0.1.0

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.
Files changed (38) hide show
  1. package/README.md +336 -0
  2. package/dist/_virtual/_plugin-vue_export-helper.js +9 -0
  3. package/dist/adapters/vue/DynamicRenderer.vue.d.ts +8 -0
  4. package/dist/adapters/vue/DynamicRenderer.vue.js +7 -0
  5. package/dist/adapters/vue/DynamicRenderer.vue2.js +1302 -0
  6. package/dist/adapters/vue/ErrorBoundary.vue.d.ts +16 -0
  7. package/dist/adapters/vue/ErrorBoundary.vue.js +7 -0
  8. package/dist/adapters/vue/ErrorBoundary.vue2.js +27 -0
  9. package/dist/adapters/vue/NestedComponentWrapper.vue.d.ts +15 -0
  10. package/dist/adapters/vue/NestedComponentWrapper.vue.js +96 -0
  11. package/dist/adapters/vue/NestedComponentWrapper.vue2.js +4 -0
  12. package/dist/adapters/vue/PseudoView.vue.d.ts +18 -0
  13. package/dist/adapters/vue/PseudoView.vue.js +59 -0
  14. package/dist/adapters/vue/PseudoView.vue2.js +4 -0
  15. package/dist/adapters/vue/index.d.ts +6 -0
  16. package/dist/adapters/vue/index.js +17 -0
  17. package/dist/adapters/vue/injection.d.ts +3 -0
  18. package/dist/adapters/vue/injection.js +14 -0
  19. package/dist/adapters/vue/useFormContext.d.ts +4 -0
  20. package/dist/adapters/vue/useFormContext.js +35 -0
  21. package/dist/adapters/vue/useLookups.d.ts +4 -0
  22. package/dist/adapters/vue/useLookups.js +38 -0
  23. package/dist/engine/conditionalEngine.d.ts +6 -0
  24. package/dist/engine/conditionalEngine.js +56 -0
  25. package/dist/engine/dataClient.d.ts +5 -0
  26. package/dist/engine/dataClient.js +39 -0
  27. package/dist/engine/expressionResolver.d.ts +13 -0
  28. package/dist/engine/expressionResolver.js +136 -0
  29. package/dist/engine/index.d.ts +7 -0
  30. package/dist/engine/schemaResolver.d.ts +14 -0
  31. package/dist/engine/schemaResolver.js +97 -0
  32. package/dist/engine/types.d.ts +155 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +23 -0
  35. package/dist/pseudo-ui.css +1 -0
  36. package/package.json +57 -0
  37. package/vocabularies/view-model-vocabulary.json +474 -0
  38. package/vocabularies/view-vocabulary.json +1104 -0
package/README.md ADDED
@@ -0,0 +1,336 @@
1
+ # @burgantech/pseudo-ui
2
+
3
+ A **Server-Driven UI (SDUI)** rendering engine for TypeScript. Define your UI once with JSON — render it natively on any platform.
4
+
5
+ The SDK pairs a **JSON Schema** data contract with a **View JSON** component tree to produce fully interactive forms, summaries, and multi-step workflows without shipping new client code.
6
+
7
+ ## Features
8
+
9
+ - **30+ Material Design 3 components** — TextField, Dropdown, DatePicker, TabView, Dialog, Stepper, Carousel, and more
10
+ - **Delegate-driven architecture** — the SDK never makes HTTP calls; your app provides data via a simple interface
11
+ - **Expression engine** — `$form`, `$instance`, `$param`, `$ui`, `$lov`, `$lookup`, `$schema`, `$item`, `$context` namespaces for dynamic value resolution
12
+ - **Conditional engine** — `showIf` / `hideIf` / `enableIf` / `disableIf` with `allOf`, `anyOf`, `not` compound rules and 13 operators
13
+ - **Validation engine** — JSON Schema validation (`pattern`, `format`, `minLength`, `min/max`) plus async custom validation via delegate
14
+ - **LOV & Lookup** — List-of-Values dropdowns with cascade filtering and real-time data enrichment
15
+ - **Nested components** — reusable sub-components with isolated contexts, input contracts (`x-binding`), and two-way data flow
16
+ - **`$ui` state** — transient UI state (dialog visibility, active tab) that never pollutes form data
17
+ - **Accessibility** — `aria-required`, `aria-invalid`, `aria-label` on all inputs; `role="alert"` on errors
18
+ - **Error boundaries** — `Component` and `ForEach` nodes are wrapped to prevent child crashes from taking down the app
19
+ - **Multi-language** — all labels, errors, and enum values support `{ "en": "...", "tr": "...", "ar": "..." }`
20
+ - **View & ViewModel vocabularies** — included JSON Schema definitions for tooling and IDE auto-complete
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @burgantech/pseudo-ui
26
+ ```
27
+
28
+ ### Peer dependencies
29
+
30
+ The Vue adapter requires these in your project:
31
+
32
+ ```bash
33
+ npm install vue@^3.5 primevue@^4.5 @primeuix/themes@^2 primeicons@^7
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ### 1. Set up the delegate
39
+
40
+ The SDK uses **inversion of control** — you implement `PseudoViewDelegate` to supply data, load nested components, and handle actions:
41
+
42
+ ```typescript
43
+ import type { PseudoViewDelegate } from '@burgantech/pseudo-ui'
44
+
45
+ const delegate: PseudoViewDelegate = {
46
+ async requestData(ref, params) {
47
+ const res = await fetch(`/api/functions/${ref}`, {
48
+ method: 'POST',
49
+ headers: { 'Content-Type': 'application/json' },
50
+ body: JSON.stringify({ params }),
51
+ })
52
+ return res.json()
53
+ },
54
+
55
+ async loadComponent(ref) {
56
+ const [schema, view] = await Promise.all([
57
+ fetch(`/api/components/${ref}/schema.json`).then(r => r.json()),
58
+ fetch(`/api/components/${ref}/view.json`).then(r => r.json()),
59
+ ])
60
+ return { schema, view }
61
+ },
62
+
63
+ async onAction(action, formData, command) {
64
+ if (action === 'submit') {
65
+ await fetch('/api/submit', {
66
+ method: 'POST',
67
+ headers: { 'Content-Type': 'application/json' },
68
+ body: JSON.stringify(formData),
69
+ })
70
+ }
71
+ },
72
+
73
+ // Optional: custom server-side validation
74
+ async onValidationRequest(field, value, formData) {
75
+ const res = await fetch(`/api/validate/${field}`, {
76
+ method: 'POST',
77
+ headers: { 'Content-Type': 'application/json' },
78
+ body: JSON.stringify({ value, formData }),
79
+ })
80
+ const { error } = await res.json()
81
+ return error ?? null
82
+ },
83
+
84
+ // Optional: capture SDK internal logs
85
+ onLog(level, message, error, context) {
86
+ console[level](`[pseudo-ui] ${message}`, context ?? '')
87
+ },
88
+ }
89
+ ```
90
+
91
+ ### 2. Provide the delegate and render
92
+
93
+ ```vue
94
+ <script setup lang="ts">
95
+ import { ref, onMounted } from 'vue'
96
+ import { provideDelegate } from '@burgantech/pseudo-ui/vue'
97
+ import { PseudoView } from '@burgantech/pseudo-ui/vue'
98
+ import '@burgantech/pseudo-ui/vue/style.css'
99
+
100
+ import type { DataSchema, ViewDefinition } from '@burgantech/pseudo-ui'
101
+
102
+ provideDelegate(delegate)
103
+
104
+ const schema = ref<DataSchema>()
105
+ const view = ref<ViewDefinition>()
106
+
107
+ onMounted(async () => {
108
+ const [s, v] = await Promise.all([
109
+ fetch('/api/components/my-form/schema.json').then(r => r.json()),
110
+ fetch('/api/components/my-form/view.json').then(r => r.json()),
111
+ ])
112
+ schema.value = s
113
+ view.value = v
114
+ })
115
+ </script>
116
+
117
+ <template>
118
+ <PseudoView
119
+ v-if="schema && view"
120
+ :schema="schema"
121
+ :view="view"
122
+ lang="en"
123
+ @form-change="console.log('form data:', $event)"
124
+ @validation-change="console.log('is valid:', $event)"
125
+ />
126
+ </template>
127
+ ```
128
+
129
+ ## Package Exports
130
+
131
+ | Import path | Content |
132
+ |---|---|
133
+ | `@burgantech/pseudo-ui` | Core engine: types, expression resolver, schema resolver, conditional engine |
134
+ | `@burgantech/pseudo-ui/vue` | Vue 3 adapter: `PseudoView`, `DynamicRenderer`, `provideDelegate` |
135
+ | `@burgantech/pseudo-ui/vue/style.css` | Component styles (Material Design 3 tokens) |
136
+ | `@burgantech/pseudo-ui/vocabularies/view-vocabulary.json` | View meta-schema (UI component tree definition) |
137
+ | `@burgantech/pseudo-ui/vocabularies/view-model-vocabulary.json` | ViewModel meta-schema (JSON Schema x- extensions) |
138
+
139
+ ## Architecture
140
+
141
+ ```
142
+ ┌─────────────────────────────────────────────────────┐
143
+ │ Your Application │
144
+ │ │
145
+ │ ┌──────────────┐ implements ┌────────────────┐ │
146
+ │ │ App.vue │ ──────────────▶│ Delegate │ │
147
+ │ │ │ │ - requestData │ │
148
+ │ │ <PseudoView │ │ - loadComponent│ │
149
+ │ │ :schema │ │ - onAction │ │
150
+ │ │ :view │ │ - onLog │ │
151
+ │ │ lang="en"/>│ └────────────────┘ │
152
+ │ └──────┬───────┘ ▲ │
153
+ │ │ provides │ │
154
+ ├─────────┼────────────────────────────────┼──────────┤
155
+ │ SDK │ │ │
156
+ │ ▼ │ │
157
+ │ ┌─────────────────┐ ┌──────────────┐ │ │
158
+ │ │ DynamicRenderer │ │ Expression │ │ │
159
+ │ │ (recursive) │ │ Resolver │ │ │
160
+ │ │ │ ├──────────────┤ │ │
161
+ │ │ 30+ MD3 widgets │ │ Conditional │ │ │
162
+ │ │ via PrimeVue 4 │ │ Engine │ │ │
163
+ │ │ │ ├──────────────┤ │ │
164
+ │ │ ErrorBoundary │ │ Schema │ │ │
165
+ │ │ for Component & │ │ Resolver │◀──┘ │
166
+ │ │ ForEach │ │ (validation) │ │
167
+ │ └─────────────────┘ └──────────────┘ │
168
+ └─────────────────────────────────────────────────────┘
169
+ ```
170
+
171
+ ## Data Model (MVVM)
172
+
173
+ | Layer | File | Purpose |
174
+ |---|---|---|
175
+ | **ViewModel** | `schema.json` | Data contract — field types, validation, LOV sources, conditionals, multi-lang labels |
176
+ | **View** | `view.json` | UI component tree — layout, binding, actions, transient UI state |
177
+ | **Model** | Backend | Persisted data, served via delegate's `requestData` |
178
+
179
+ ### Schema example (ViewModel)
180
+
181
+ ```json
182
+ {
183
+ "$id": "urn:amorphie:res:schema:shared:customer-form",
184
+ "type": "object",
185
+ "required": ["fullName", "city"],
186
+ "properties": {
187
+ "fullName": {
188
+ "type": "string",
189
+ "minLength": 2,
190
+ "x-labels": { "en": "Full Name", "tr": "Ad Soyad" },
191
+ "x-errorMessages": {
192
+ "required": { "en": "Required", "tr": "Zorunlu" }
193
+ }
194
+ },
195
+ "city": {
196
+ "type": "string",
197
+ "x-labels": { "en": "City", "tr": "Şehir" },
198
+ "x-lov": {
199
+ "source": "urn:amorphie:func:domain:shared:get-cities",
200
+ "valueField": "$.response.data.code",
201
+ "displayField": "$.response.data.name"
202
+ }
203
+ },
204
+ "companyName": {
205
+ "type": "string",
206
+ "x-labels": { "en": "Company", "tr": "Şirket" },
207
+ "x-conditional": {
208
+ "showIf": {
209
+ "allOf": [
210
+ { "field": "accountType", "operator": "equals", "value": "corporate" },
211
+ { "field": "age", "operator": "greaterThan", "value": 17 }
212
+ ]
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ ### View example
221
+
222
+ ```json
223
+ {
224
+ "$schema": "https://amorphie.io/meta/view-vocabulary/1.0",
225
+ "dataSchema": "urn:amorphie:res:schema:shared:customer-form",
226
+ "uiState": { "showDialog": false },
227
+ "view": {
228
+ "type": "Column",
229
+ "gap": "md",
230
+ "children": [
231
+ { "type": "TextField", "bind": "fullName" },
232
+ { "type": "Dropdown", "bind": "city" },
233
+ { "type": "TextField", "bind": "companyName" },
234
+ {
235
+ "type": "Button",
236
+ "label": { "en": "Submit", "tr": "Gönder" },
237
+ "variant": "filled",
238
+ "action": "submit"
239
+ }
240
+ ]
241
+ }
242
+ }
243
+ ```
244
+
245
+ ## Delegate Interface
246
+
247
+ ```typescript
248
+ interface PseudoViewDelegate {
249
+ /** Fetch data from backend (LOV items, lookup enrichment) */
250
+ requestData(ref: string, params?: Record<string, string>): Promise<unknown>
251
+
252
+ /** Load a nested component's schema + view by reference */
253
+ loadComponent(ref: string): Promise<{ schema: DataSchema; view: ViewDefinition }>
254
+
255
+ /** Handle user actions (submit, cancel, back, custom commands) */
256
+ onAction(action: string, formData: Record<string, unknown>, command?: string): Promise<void>
257
+
258
+ /** Optional: custom async validation after built-in checks pass */
259
+ onValidationRequest?(field: string, value: unknown, formData: Record<string, unknown>): Promise<string | null>
260
+
261
+ /** Optional: capture SDK logs (debug, info, warn, error) */
262
+ onLog?(level: LogLevel, message: string, error?: unknown, context?: Record<string, unknown>): void
263
+ }
264
+ ```
265
+
266
+ ## Supported Components
267
+
268
+ ### Layout
269
+ `Column` · `Row` · `Stack` · `Grid` · `Expanded` · `SizedBox` · `Divider` · `Spacer`
270
+
271
+ ### Input
272
+ `TextField` · `TextArea` · `NumberField` · `Dropdown` · `Checkbox` · `RadioGroup` · `DatePicker` · `TimePicker` · `Switch` · `Slider` · `SegmentedButton` · `SearchField` · `AutoComplete`
273
+
274
+ ### Display
275
+ `Text` · `Image` · `Chip` · `ListTile` · `Avatar` · `RichText` · `LoadingIndicator`
276
+
277
+ ### Surface & Overlay
278
+ `Card` · `Dialog` · `BottomSheet` · `SideSheet` · `Snackbar` · `Tooltip`
279
+
280
+ ### Navigation
281
+ `TabView` · `AppBar` · `NavigationBar` · `NavigationDrawer`
282
+
283
+ ### Container
284
+ `ExpansionPanel` · `Stepper`
285
+
286
+ ### Action
287
+ `Button` · `IconButton` · `FAB` · `Menu` · `Toolbar` · `Carousel`
288
+
289
+ ### Control
290
+ `ForEach` · `Component` (nested)
291
+
292
+ ## Expression Namespaces
293
+
294
+ | Namespace | Source | Example |
295
+ |---|---|---|
296
+ | `$form.field` | User input data | `$form.firstName` |
297
+ | `$instance.field` | Backend persisted data | `$instance.status` |
298
+ | `$param.field` | Parent-bound data (nested components) | `$param.cityCode` |
299
+ | `$ui.key` | Transient UI state (not submitted) | `$ui.showDialog` |
300
+ | `$schema.field.label` | Schema label for current language | `$schema.city.label` |
301
+ | `$lov.field` | LOV items array | `$lov.city` |
302
+ | `$lov.field.display` | Localized display name for current value | `$lov.city.display` |
303
+ | `$lookup.prop.field` | Enrichment data | `$lookup.branch.address` |
304
+ | `$item.field` | ForEach iteration item | `$item.name` |
305
+ | `$context.lang` | Runtime context | `$context.lang` |
306
+
307
+ ## Conditional Operators
308
+
309
+ `equals` · `notEquals` · `in` · `notIn` · `greaterThan` · `lessThan` · `greaterThanOrEquals` · `lessThanOrEquals` · `contains` · `startsWith` · `endsWith` · `isEmpty` · `isNotEmpty`
310
+
311
+ Compound rules: `allOf` (AND), `anyOf` (OR), `not` (negate) — recursive nesting supported.
312
+
313
+ ## Validation Formats
314
+
315
+ Built-in `format` validators: `email` · `uri` / `url` · `date` · `date-time` · `time` · `phone` / `tel` · `iban`
316
+
317
+ ## Vocabularies
318
+
319
+ The package includes JSON Schema vocabulary definitions for IDE auto-complete and tooling:
320
+
321
+ ```typescript
322
+ // Import as JSON modules
323
+ import viewVocab from '@burgantech/pseudo-ui/vocabularies/view-vocabulary.json'
324
+ import viewModelVocab from '@burgantech/pseudo-ui/vocabularies/view-model-vocabulary.json'
325
+ ```
326
+
327
+ - **View Vocabulary** — defines all valid component types, properties, and their constraints
328
+ - **ViewModel Vocabulary** — defines all `x-*` extensions (`x-labels`, `x-lov`, `x-conditional`, etc.)
329
+
330
+ ## Cross-Platform
331
+
332
+ This package provides the **TypeScript/Vue** implementation. A **Dart/Flutter** package (`pseudo_ui`) renders the same JSON schemas and views using Material 3 widgets. Both packages share the same vocabulary definitions, ensuring consistent behavior across platforms.
333
+
334
+ ## License
335
+
336
+ MIT
@@ -0,0 +1,9 @@
1
+ const s = (t, e) => {
2
+ const o = t.__vccOpts || t;
3
+ for (const [r, c] of e)
4
+ o[r] = c;
5
+ return o;
6
+ };
7
+ export {
8
+ s as default
9
+ };
@@ -0,0 +1,8 @@
1
+ import type { ComponentNode } from '../../engine/types';
2
+ type __VLS_Props = {
3
+ node: ComponentNode;
4
+ item?: Record<string, unknown>;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import o from "./DynamicRenderer.vue2.js";
2
+ /* empty css */
3
+ import r from "../../_virtual/_plugin-vue_export-helper.js";
4
+ const a = /* @__PURE__ */ r(o, [["__scopeId", "data-v-c6e3365d"]]);
5
+ export {
6
+ a as default
7
+ };