{"_id":"@burgantech/pseudo-ui","_rev":"4-97c7626efd932285ea19f42509a801a8","name":"@burgantech/pseudo-ui","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@burgantech/pseudo-ui","version":"0.1.0","license":"MIT","_id":"@burgantech/pseudo-ui@0.1.0","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"homepage":"https://github.com/burgan-tech/pseudo-ui#readme","bugs":{"url":"https://github.com/burgan-tech/pseudo-ui/issues"},"dist":{"shasum":"a9cd329c541f22ed089df3465e36dbc036f669c9","tarball":"https://registry.npmjs.org/@burgantech/pseudo-ui/-/pseudo-ui-0.1.0.tgz","fileCount":38,"integrity":"sha512-1Na0kNb17xHPpnrIy80HyXLMqVPpuyp1cEXmXzpBVwCg3JzxzdPk67LHqa25LNVUNVeebEapbD+0IoJCghDJ0w==","signatures":[{"sig":"MEQCIGleMyxZrpwK3U5briEwqnPLFV1EGOf55Rv7Ssuw99ejAiB5yQV/18OmOYZjc3nrzPiv9m9980jDodEvbpptCnNutw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":182000},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/adapters/vue/index.d.ts","import":"./dist/adapters/vue/index.js"},"./vue/style.css":"./dist/pseudo-ui.css","./vocabularies/view-vocabulary.json":"./vocabularies/view-vocabulary.json","./vocabularies/view-model-vocabulary.json":"./vocabularies/view-model-vocabulary.json"},"gitHead":"d886082e14eaa8b1c58fa8ab76b68ce1bdf09a3b","scripts":{"lint":"eslint src/","test":"vitest run","build":"vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist && npm run copy:vocabularies","typecheck":"vue-tsc --noEmit","copy:vocabularies":"mkdir -p vocabularies && cp ../../vocabularies/*.json vocabularies/"},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"repository":{"url":"git+https://github.com/burgan-tech/pseudo-ui.git","type":"git","directory":"core/ts-pseudo-ui"},"_npmVersion":"10.9.4","description":"Server-Driven UI rendering engine with framework adapters. JSON Schema + Pseudo UI → platform widgets.","directories":{},"_nodeVersion":"22.22.1","dependencies":{"vue":"^3.5.0","primevue":"^4.5.0","primeicons":"^7.0.0","@primeuix/themes":"^2.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.0","vue-tsc":"^3.1.0","typescript":"~5.9.0","@vue/tsconfig":"^0.8.0","vite-plugin-dts":"^4.5.0","@vitejs/plugin-vue":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/pseudo-ui_0.1.0_1773902263345_0.016607398615323232","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@burgantech/pseudo-ui","version":"0.1.1","license":"MIT","_id":"@burgantech/pseudo-ui@0.1.1","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"homepage":"https://github.com/burgan-tech/pseudo-ui#readme","bugs":{"url":"https://github.com/burgan-tech/pseudo-ui/issues"},"dist":{"shasum":"528f0d1789ed59d0a935873d79c641f5c71cc4b8","tarball":"https://registry.npmjs.org/@burgantech/pseudo-ui/-/pseudo-ui-0.1.1.tgz","fileCount":42,"integrity":"sha512-OQEBzG81vFILqCE41oJTog1mOQ8ZDod2nEeZEVt+tJU2aW8T3VEzyLP3pOpj5cmsMK3lPvzp96vIZ/egbQG9Dg==","signatures":[{"sig":"MEQCIBwjl3FDBa0iki5ghxnvbE3E/J2Owtq5LFGAa7g0Vg2aAiBm0jHAOBORsWo/Ww7a0xeZVjLP1y+8/wHot/6KfWzk+g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":190887},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/adapters/vue/index.d.ts","import":"./dist/adapters/vue/index.js"},"./vue/style.css":"./dist/pseudo-ui.css","./vocabularies/view-vocabulary.json":"./vocabularies/view-vocabulary.json","./vocabularies/view-model-vocabulary.json":"./vocabularies/view-model-vocabulary.json"},"gitHead":"b7645b3181a56faa92ff8e6953ea27ed982d5742","scripts":{"lint":"eslint src/","test":"vitest run","build":"vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist && npm run copy:vocabularies","typecheck":"vue-tsc --noEmit","test:watch":"vitest","copy:vocabularies":"mkdir -p vocabularies && cp ../../vocabularies/*.json vocabularies/"},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"repository":{"url":"git+https://github.com/burgan-tech/pseudo-ui.git","type":"git","directory":"core/ts-pseudo-ui"},"_npmVersion":"10.9.4","description":"Server-Driven UI rendering engine with framework adapters. JSON Schema + Pseudo UI → platform widgets.","directories":{},"_nodeVersion":"22.22.1","dependencies":{"vue":"^3.5.0","primevue":"^4.5.0","primeicons":"^7.0.0","@primeuix/themes":"^2.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.0","vitest":"^4.1.0","vue-tsc":"^3.1.0","happy-dom":"^20.8.4","typescript":"~5.9.0","@vue/tsconfig":"^0.8.0","@vue/test-utils":"^2.4.6","vite-plugin-dts":"^4.5.0","@vitejs/plugin-vue":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/pseudo-ui_0.1.1_1773907831402_0.4690153369079093","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@burgantech/pseudo-ui","version":"0.1.2","license":"MIT","_id":"@burgantech/pseudo-ui@0.1.2","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"homepage":"https://github.com/burgan-tech/pseudo-ui#readme","bugs":{"url":"https://github.com/burgan-tech/pseudo-ui/issues"},"dist":{"shasum":"767e2742d40d13bae889dfcf7cd8eafc0bec2efc","tarball":"https://registry.npmjs.org/@burgantech/pseudo-ui/-/pseudo-ui-0.1.2.tgz","fileCount":102,"integrity":"sha512-t+c2DGXt+Y/xHEq/chV60CX0F8Ctfds8tDMTHEJoXvH+8ZkrPNwPrd3lqoKk0/nlQIgzHGYInJnVexWh38Tdcg==","signatures":[{"sig":"MEUCIGu7tV147CxJ4IK+0UyvqaCYIaFddc8ECRk9QJxhHGjQAiEA6AXSWSdjc9wEZZFB575VrAxQpMDJWfsBTkA2bEg+htY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":513803},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/adapters/vue/index.d.ts","import":"./dist/adapters/vue/index.js"},"./react":{"types":"./dist/adapters/react/index.d.ts","import":"./dist/adapters/react/index.js"},"./angular":{"types":"./dist/angular/index.d.ts","import":"./dist/angular/fesm2022/pseudo-ui.mjs","default":"./dist/angular/fesm2022/pseudo-ui.mjs"},"./vue/style.css":"./dist/pseudo-ui.css","./vocabularies/view-vocabulary.json":"./vocabularies/view-vocabulary.json","./vocabularies/view-model-vocabulary.json":"./vocabularies/view-model-vocabulary.json"},"gitHead":"4b7d197a64bfd1ebe7f1300e6c69bf0abeb701b7","scripts":{"lint":"eslint src/","test":"vitest run","build":"vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist && tsc -p tsconfig.react.json --emitDeclarationOnly --outDir dist && npm run build:angular && npm run copy:vocabularies","typecheck":"vue-tsc --noEmit","test:watch":"vitest","build:angular":"ng-packagr -p ng-package.angular.json -c tsconfig.angular.json","copy:vocabularies":"mkdir -p vocabularies && cp ../../vocabularies/*.json vocabularies/"},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"repository":{"url":"git+https://github.com/burgan-tech/pseudo-ui.git","type":"git","directory":"core/ts-pseudo-ui"},"_npmVersion":"10.9.7","description":"Server-Driven UI rendering engine with framework adapters. JSON Schema + Pseudo UI → platform widgets.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"vue":"^3.5.0","tslib":"^2.8.0","primevue":"^4.5.0","primeicons":"^7.0.0","@primeuix/themes":"^2.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.1","vite":"^7.3.0","react":"^19.2.6","vitest":"^4.1.0","vue-tsc":"^3.1.0","zone.js":"^0.15.0","happy-dom":"^20.8.4","react-dom":"^19.2.6","ng-packagr":"^19.2.0","primereact":"^10.9.8","typescript":"~5.8.0","@angular/cdk":"^19.2.0","@types/react":"^19.2.14","@angular/core":"^19.2.0","@vue/tsconfig":"^0.8.0","@angular/forms":"^19.2.0","@angular/common":"^19.2.0","@vue/test-utils":"^2.4.6","vite-plugin-dts":"^4.5.0","@types/react-dom":"^19.2.3","@angular/compiler":"^19.2.0","@angular/material":"^19.2.0","@vitejs/plugin-vue":"^6.0.0","@angular/animations":"^19.2.0","@vitejs/plugin-react":"^5.1.4","@angular/compiler-cli":"^19.2.0","@angular/platform-browser":"^19.2.0"},"peerDependencies":{"rxjs":"^7.8.0","react":">=18.0.0","react-dom":">=18.0.0","primereact":">=10.0.0","@angular/cdk":">=19.0.0 <21.0.0","@angular/core":">=19.0.0 <21.0.0","@angular/forms":">=19.0.0 <21.0.0","@angular/common":">=19.0.0 <21.0.0","@angular/material":">=19.0.0 <21.0.0","@angular/animations":">=19.0.0 <21.0.0","@angular/platform-browser":">=19.0.0 <21.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"primereact":{"optional":true},"@angular/cdk":{"optional":true},"@angular/core":{"optional":true},"@angular/forms":{"optional":true},"@angular/common":{"optional":true},"@angular/material":{"optional":true},"@angular/animations":{"optional":true},"@angular/platform-browser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pseudo-ui_0.1.2_1779001351021_0.2179214075810758","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@burgantech/pseudo-ui","version":"0.1.3","description":"Server-Driven UI rendering engine with framework adapters. JSON Schema + Pseudo UI → platform widgets.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./vue":{"import":"./dist/adapters/vue/index.js","types":"./dist/adapters/vue/index.d.ts"},"./vue/style.css":"./dist/pseudo-ui.css","./angular":{"types":"./dist/angular/index.d.ts","import":"./dist/angular/fesm2022/pseudo-ui.mjs","default":"./dist/angular/fesm2022/pseudo-ui.mjs"},"./react":{"import":"./dist/adapters/react/index.js","types":"./dist/adapters/react/index.d.ts"},"./react/style.css":"./dist/pseudo-ui-react.css","./vocabularies/view-vocabulary.json":"./vocabularies/view-vocabulary.json","./vocabularies/view-model-vocabulary.json":"./vocabularies/view-model-vocabulary.json"},"scripts":{"build":"vite build && vue-tsc --declaration --emitDeclarationOnly --outDir dist && tsc -p tsconfig.react.json --emitDeclarationOnly --outDir dist && npm run build:angular && npm run copy:vocabularies && npm run copy:react-css","build:angular":"ng-packagr -p ng-package.angular.json -c tsconfig.angular.json","copy:vocabularies":"mkdir -p vocabularies && cp ../../vocabularies/*.json vocabularies/","copy:react-css":"cp src/adapters/react/pseudo-ui-react.css dist/pseudo-ui-react.css","typecheck":"vue-tsc --noEmit","test":"vitest run","test:watch":"vitest","lint":"eslint src/"},"peerDependencies":{"@angular/animations":">=19.0.0 <21.0.0","@angular/cdk":">=19.0.0 <21.0.0","@angular/common":">=19.0.0 <21.0.0","@angular/core":">=19.0.0 <21.0.0","@angular/forms":">=19.0.0 <21.0.0","@angular/material":">=19.0.0 <21.0.0","@angular/platform-browser":">=19.0.0 <21.0.0","rxjs":"^7.8.0","react":">=18.0.0","react-dom":">=18.0.0","primereact":">=10.0.0"},"peerDependenciesMeta":{"@angular/animations":{"optional":true},"@angular/cdk":{"optional":true},"@angular/common":{"optional":true},"@angular/core":{"optional":true},"@angular/forms":{"optional":true},"@angular/material":{"optional":true},"@angular/platform-browser":{"optional":true},"rxjs":{"optional":true},"react":{"optional":true},"react-dom":{"optional":true},"primereact":{"optional":true}},"dependencies":{"@primeuix/themes":"^2.0.0","primeicons":"^7.0.0","primevue":"^4.5.0","tslib":"^2.8.0","vue":"^3.5.0"},"devDependencies":{"@angular/animations":"^19.2.0","@angular/cdk":"^19.2.0","@angular/common":"^19.2.0","@angular/compiler":"^19.2.0","@angular/compiler-cli":"^19.2.0","@angular/core":"^19.2.0","@angular/forms":"^19.2.0","@angular/material":"^19.2.0","@angular/platform-browser":"^19.2.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.1.4","@vitejs/plugin-vue":"^6.0.0","@vue/test-utils":"^2.4.6","@vue/tsconfig":"^0.8.0","happy-dom":"^20.8.4","ng-packagr":"^19.2.0","primereact":"^10.9.8","react":"^19.2.6","react-dom":"^19.2.6","rxjs":"^7.8.1","typescript":"~5.8.0","vite":"^7.3.0","vite-plugin-dts":"^4.5.0","vitest":"^4.1.0","vue-tsc":"^3.1.0","zone.js":"^0.15.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"repository":{"type":"git","url":"git+https://github.com/burgan-tech/pseudo-ui.git","directory":"core/ts-pseudo-ui"},"license":"MIT","_id":"@burgantech/pseudo-ui@0.1.3","gitHead":"40138c8e20e600c6b7ae880161f8a974217c2f29","bugs":{"url":"https://github.com/burgan-tech/pseudo-ui/issues"},"homepage":"https://github.com/burgan-tech/pseudo-ui#readme","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-nQpW8T9AHWPWFuMd+QGe4l/7uRRICor2y59rk7rSJ2jyUxjkZhFZgCK+O7/+fY52RACYCRzQL6cswh2sZ4DQqg==","shasum":"6f1be563143ee184c249e47fa1c270c07ebb435d","tarball":"https://registry.npmjs.org/@burgantech/pseudo-ui/-/pseudo-ui-0.1.3.tgz","fileCount":103,"unpackedSize":525391,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDGpZkfd1WYYUrkz/t4G69fbGZajnWTQz1RAvEsLRy/cAIgYHNydbu38I1176m1XjNaxgUOWEtMPqc2+IbhWfJrHk4="}]},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"directories":{},"maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pseudo-ui_0.1.3_1779058139288_0.4849045453318519"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-19T06:37:43.234Z","modified":"2026-05-17T22:48:59.566Z","0.1.0":"2026-03-19T06:37:43.458Z","0.1.1":"2026-03-19T08:10:31.552Z","0.1.2":"2026-05-17T07:02:31.154Z","0.1.3":"2026-05-17T22:48:59.443Z"},"bugs":{"url":"https://github.com/burgan-tech/pseudo-ui/issues"},"license":"MIT","homepage":"https://github.com/burgan-tech/pseudo-ui#readme","repository":{"type":"git","url":"git+https://github.com/burgan-tech/pseudo-ui.git","directory":"core/ts-pseudo-ui"},"description":"Server-Driven UI rendering engine with framework adapters. JSON Schema + Pseudo UI → platform widgets.","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"readme":"# @burgantech/pseudo-ui\n\nA **Server-Driven UI (SDUI)** rendering engine for TypeScript. Define your UI once with JSON — render it natively on any platform.\n\nThe 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.\n\n## Features\n\n- **30+ Material Design 3 components** — TextField, Dropdown, DatePicker, TabView, Dialog, Stepper, Carousel, and more\n- **Delegate-driven architecture** — the SDK never makes HTTP calls; your app provides data via a simple interface\n- **Expression engine** — `$form`, `$instance`, `$param`, `$ui`, `$lov`, `$lookup`, `$schema`, `$item`, `$context` namespaces for dynamic value resolution\n- **Conditional engine** — `showIf` / `hideIf` / `enableIf` / `disableIf` with `allOf`, `anyOf`, `not` compound rules and 13 operators\n- **Validation engine** — JSON Schema validation (`pattern`, `format`, `minLength`, `min/max`) plus async custom validation via delegate\n- **LOV & Lookup** — List-of-Values dropdowns with cascade filtering and real-time data enrichment\n- **Nested components** — reusable sub-components with isolated contexts, input contracts (`x-binding`), and two-way data flow\n- **`$ui` state** — transient UI state (dialog visibility, active tab) that never pollutes form data\n- **Accessibility** — `aria-required`, `aria-invalid`, `aria-label` on all inputs; `role=\"alert\"` on errors\n- **Error boundaries** — `Component` and `ForEach` nodes are wrapped to prevent child crashes from taking down the app\n- **Multi-language** — all labels, errors, and enum values support `{ \"en\": \"...\", \"tr\": \"...\", \"ar\": \"...\" }`\n- **View & ViewModel vocabularies** — included JSON Schema definitions for tooling and IDE auto-complete\n\n## Installation\n\n```bash\nnpm install @burgantech/pseudo-ui\n```\n\n### Peer dependencies\n\nThe Vue adapter requires these in your project:\n\n```bash\nnpm install vue@^3.5 primevue@^4.5 @primeuix/themes@^2 primeicons@^7\n```\n\nThe Angular adapter (`@burgantech/pseudo-ui/angular`, Angular Material) requires:\n\n```bash\nnpm install @angular/core@^19 @angular/common@^19 @angular/forms@^19 @angular/platform-browser@^19 \\\n  @angular/material@^19 @angular/cdk@^19 @angular/animations@^19 rxjs@^7.8\n```\n\nUse `provideAnimationsAsync()` and `provideNativeDateAdapter()` (or another `DateAdapter`) in your application config when using date pickers.\n\n## Quick Start\n\nTwo steps: first a minimal form, then we enrich it with a nested component and a dropdown. Each step is self-contained.\n\n---\n\n### Step 1: Minimal form\n\nName, surname, birth date, and a Submit button. No dropdowns, no nested components — just schema, view, and a minimal delegate.\n\n**Schema:**\n```json\n{\n  \"$schema\": \"https://amorphie.io/meta/view-model-vocabulary\",\n  \"$id\": \"urn:amorphie:res:schema:demo:quick-start\",\n  \"type\": \"object\",\n  \"required\": [\"name\", \"surname\"],\n  \"properties\": {\n    \"name\": { \"type\": \"string\", \"minLength\": 1, \"x-labels\": { \"en\": \"First Name\", \"tr\": \"Ad\" } },\n    \"surname\": { \"type\": \"string\", \"minLength\": 1, \"x-labels\": { \"en\": \"Surname\", \"tr\": \"Soyad\" } },\n    \"birthDate\": { \"type\": \"string\", \"format\": \"date\", \"x-labels\": { \"en\": \"Date of Birth\", \"tr\": \"Doğum Tarihi\" } }\n  }\n}\n```\n\n**View:**\n```json\n{\n  \"$schema\": \"https://amorphie.io/meta/view-vocabulary/1.0\",\n  \"dataSchema\": \"urn:amorphie:res:schema:demo:quick-start\",\n  \"view\": {\n    \"type\": \"Column\",\n    \"gap\": \"md\",\n    \"children\": [\n      { \"type\": \"TextField\", \"bind\": \"name\" },\n      { \"type\": \"TextField\", \"bind\": \"surname\" },\n      { \"type\": \"DatePicker\", \"bind\": \"birthDate\" },\n      { \"type\": \"Button\", \"label\": { \"en\": \"Submit\", \"tr\": \"Gönder\" }, \"variant\": \"filled\", \"action\": \"submit\" }\n    ]\n  }\n}\n```\n\n**Delegate + render:** `requestData` and `loadComponent` are never called here, so we stub them to throw. Only `onAction` matters.\n\n```vue\n<script setup lang=\"ts\">\nimport { provideDelegate } from '@burgantech/pseudo-ui/vue'\nimport { PseudoView } from '@burgantech/pseudo-ui/vue'\nimport '@burgantech/pseudo-ui/vue/style.css'\n\nimport type { PseudoViewDelegate, DataSchema, ViewDefinition } from '@burgantech/pseudo-ui'\n\nconst schema: DataSchema = {\n  $schema: 'https://amorphie.io/meta/view-model-vocabulary',\n  $id: 'urn:amorphie:res:schema:demo:quick-start',\n  type: 'object',\n  required: ['name', 'surname'],\n  properties: {\n    name: { type: 'string', minLength: 1, 'x-labels': { en: 'First Name', tr: 'Ad' } },\n    surname: { type: 'string', minLength: 1, 'x-labels': { en: 'Surname', tr: 'Soyad' } },\n    birthDate: { type: 'string', format: 'date', 'x-labels': { en: 'Date of Birth', tr: 'Doğum Tarihi' } },\n  },\n}\n\nconst view: ViewDefinition = {\n  $schema: 'https://amorphie.io/meta/view-vocabulary/1.0',\n  dataSchema: 'urn:amorphie:res:schema:demo:quick-start',\n  view: {\n    type: 'Column',\n    gap: 'md',\n    children: [\n      { type: 'TextField', bind: 'name' },\n      { type: 'TextField', bind: 'surname' },\n      { type: 'DatePicker', bind: 'birthDate' },\n      { type: 'Button', label: { en: 'Submit', tr: 'Gönder' }, variant: 'filled', action: 'submit' },\n    ],\n  },\n}\n\nconst delegate: PseudoViewDelegate = {\n  async requestData() { throw new Error('No LOV in this example — add a dropdown to trigger this') },\n  async loadComponent() { throw new Error('No nested components — add type: \"Component\" to trigger this') },\n  async onAction(action, formData) {\n    if (action === 'submit') console.log('Form submitted:', formData)\n  },\n}\n</script>\n\n<template>\n  <PseudoView :schema=\"schema\" :view=\"view\" lang=\"en\" :delegate=\"delegate\" />\n</template>\n```\n\n---\n\n### Step 2: Add a continent dropdown (nested component + LOV)\n\nWe extend the form with a **continent** field. The dropdown lives in a nested sub-component and gets its options via `requestData` — so you see both `loadComponent` (nested UI) and `requestData` (LOV data) in action. All data is inline.\n\n**Add to main schema:**\n```json\n\"continent\": { \"type\": \"string\", \"x-labels\": { \"en\": \"Continent you live in\", \"tr\": \"Yaşadığınız kıta\" } }\n```\n\n**Add to main view** (between DatePicker and Button):\n```json\n{\n  \"type\": \"Component\",\n  \"ref\": \"continent-selector\",\n  \"bind\": { \"continent\": \"$form.continent\" }\n}\n```\n\n**Sub-component schema** (continent-selector — has `x-lov`, so the SDK calls `requestData(\"get-continents\")`):\n```json\n{\n  \"$schema\": \"https://amorphie.io/meta/view-model-vocabulary\",\n  \"$id\": \"urn:amorphie:res:schema:demo:continent-selector\",\n  \"type\": \"object\",\n  \"required\": [\"continent\"],\n  \"properties\": {\n    \"continent\": {\n      \"type\": \"string\",\n      \"x-labels\": { \"en\": \"Continent you live in\", \"tr\": \"Yaşadığınız kıta\" },\n      \"x-lov\": {\n        \"source\": \"get-continents\",\n        \"valueField\": \"$.response.data.code\",\n        \"displayField\": \"$.response.data.name\"\n      }\n    }\n  }\n}\n```\n\n**Sub-component view:**\n```json\n{\n  \"$schema\": \"https://amorphie.io/meta/view-vocabulary/1.0\",\n  \"dataSchema\": \"urn:amorphie:res:schema:demo:continent-selector\",\n  \"view\": { \"type\": \"Dropdown\", \"bind\": \"continent\" }\n}\n```\n\n**Full delegate** (replace the stubs with real implementations):\n\n```vue\n<script setup lang=\"ts\">\nimport { provideDelegate } from '@burgantech/pseudo-ui/vue'\nimport { PseudoView } from '@burgantech/pseudo-ui/vue'\nimport '@burgantech/pseudo-ui/vue/style.css'\n\nimport type { PseudoViewDelegate, DataSchema, ViewDefinition } from '@burgantech/pseudo-ui'\n\nconst CONTINENTS = [\n  { code: 'eu', name: 'Europe' },\n  { code: 'as', name: 'Asia' },\n  { code: 'na', name: 'North America' },\n  { code: 'sa', name: 'South America' },\n  { code: 'af', name: 'Africa' },\n  { code: 'oc', name: 'Oceania' },\n  { code: 'an', name: 'Antarctica' },\n]\n\nconst mainSchema: DataSchema = {\n  $schema: 'https://amorphie.io/meta/view-model-vocabulary',\n  $id: 'urn:amorphie:res:schema:demo:quick-start',\n  type: 'object',\n  required: ['name', 'surname'],\n  properties: {\n    name: { type: 'string', minLength: 1, 'x-labels': { en: 'First Name', tr: 'Ad' } },\n    surname: { type: 'string', minLength: 1, 'x-labels': { en: 'Surname', tr: 'Soyad' } },\n    birthDate: { type: 'string', format: 'date', 'x-labels': { en: 'Date of Birth', tr: 'Doğum Tarihi' } },\n    continent: { type: 'string', 'x-labels': { en: 'Continent you live in', tr: 'Yaşadığınız kıta' } },\n  },\n}\n\nconst continentSchema: DataSchema = {\n  $schema: 'https://amorphie.io/meta/view-model-vocabulary',\n  $id: 'urn:amorphie:res:schema:demo:continent-selector',\n  type: 'object',\n  required: ['continent'],\n  properties: {\n    continent: {\n      type: 'string',\n      'x-labels': { en: 'Continent you live in', tr: 'Yaşadığınız kıta' },\n      'x-lov': { source: 'get-continents', valueField: '$.response.data.code', displayField: '$.response.data.name' },\n    },\n  },\n}\n\nconst mainView: ViewDefinition = {\n  $schema: 'https://amorphie.io/meta/view-vocabulary/1.0',\n  dataSchema: 'urn:amorphie:res:schema:demo:quick-start',\n  view: {\n    type: 'Column',\n    gap: 'md',\n    children: [\n      { type: 'TextField', bind: 'name' },\n      { type: 'TextField', bind: 'surname' },\n      { type: 'DatePicker', bind: 'birthDate' },\n      { type: 'Component', ref: 'continent-selector', bind: { continent: '$form.continent' } },\n      { type: 'Button', label: { en: 'Submit', tr: 'Gönder' }, variant: 'filled', action: 'submit' },\n    ],\n  },\n}\n\nconst delegate: PseudoViewDelegate = {\n  async requestData(ref, params) {\n    if (ref === 'get-continents') return { response: { data: CONTINENTS } }\n    throw new Error(`Unknown data source: ${ref}`)\n  },\n  async loadComponent(ref) {\n    if (ref === 'continent-selector') {\n      return {\n        schema: continentSchema,\n        view: { $schema: 'https://amorphie.io/meta/view-vocabulary/1.0', dataSchema: 'urn:amorphie:res:schema:demo:continent-selector', view: { type: 'Dropdown', bind: 'continent' } },\n      }\n    }\n    throw new Error(`Unknown component: ${ref}`)\n  },\n  async onAction(action, formData) {\n    if (action === 'submit') console.log('Form submitted:', formData)\n  },\n}\n</script>\n\n<template>\n  <PseudoView :schema=\"mainSchema\" :view=\"mainView\" lang=\"en\" :delegate=\"delegate\" />\n</template>\n```\n\nStep 1 gives you the basics. Step 2 shows how to add a nested component and LOV — `requestData` serves dropdown options, `loadComponent` serves the sub-component.\n\n---\n\n### Initial data (optional)\n\nYou can pass initial values when the view first renders:\n\n| Prop | Purpose |\n|---|---|\n| `formData` | Pre-fill editable fields (e.g. user draft, edit mode). Fields are bound to `$form` and can be changed by the user. |\n| `instanceData` | Backend/persisted data (e.g. read-only display, lookup filters). Used by `$instance` expressions and summary views. |\n\n```vue\n<PseudoView\n  :schema=\"schema\"\n  :view=\"view\"\n  :form-data=\"{ name: 'Jane', surname: 'Doe', birthDate: '1990-05-15' }\"\n  :instance-data=\"{ status: 'active', createdAt: '2024-01-01' }\"\n  lang=\"en\"\n  :delegate=\"delegate\"\n/>\n```\n\n`formData` is for user-editable data. `instanceData` is for backend state that drives display and lookups — both are optional and merged when the view mounts.\n\n---\n\n### Lookups (enrichment)\n\nWhen a schema property has `x-lookup`, the SDK fetches enrichment data via `requestData`. You must **activate** the lookup by listing it in the view's `lookups` array — otherwise it won't run.\n\n**Schema** (defines the lookup):\n```json\n{\n  \"branchDetail\": {\n    \"type\": \"object\",\n    \"x-lookup\": {\n      \"source\": \"get-branch-details\",\n      \"resultField\": \"$.response.data\",\n      \"filter\": [{ \"param\": \"branchCode\", \"value\": \"$param.selectedBranchCode\", \"required\": true }]\n    }\n  }\n}\n```\n\n**View** (activates it):\n```json\n{\n  \"$schema\": \"https://amorphie.io/meta/view-vocabulary/1.0\",\n  \"dataSchema\": \"urn:amorphie:res:schema:shared:branch-info\",\n  \"lookups\": [\"branchDetail\"],\n  \"view\": { ... }\n}\n```\n\nThen use `$lookup.branchDetail.address`, `$lookup.branchDetail.phone`, etc. in Text or other components. The SDK calls `requestData(source, filterParams)` when the view mounts; the delegate returns the enrichment payload.\n\n## Package Exports\n\n| Import path | Content |\n|---|---|\n| `@burgantech/pseudo-ui` | Core engine: types, expression resolver, schema resolver, conditional engine |\n| `@burgantech/pseudo-ui/vue` | Vue 3 adapter: `PseudoView`, `DynamicRenderer`, `provideDelegate` |\n| `@burgantech/pseudo-ui/angular` | Angular 19 adapter (standalone, Angular Material): `PseudoViewComponent`, `DynamicRendererComponent`, `FORM_CONTEXT`, `PSEUDO_DELEGATE` |\n| `@burgantech/pseudo-ui/vue/style.css` | Component styles (Material Design 3 tokens) |\n| `@burgantech/pseudo-ui/vocabularies/view-vocabulary.json` | View meta-schema (UI component tree definition) |\n| `@burgantech/pseudo-ui/vocabularies/view-model-vocabulary.json` | ViewModel meta-schema (JSON Schema x- extensions) |\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────┐\n│                   Your Application                   │\n│                                                      │\n│  ┌──────────────┐   implements   ┌────────────────┐ │\n│  │   App.vue    │ ──────────────▶│  Delegate      │ │\n│  │              │                │  - requestData │ │\n│  │  <PseudoView │                │  - loadComponent│ │\n│  │   :schema    │                │  - onAction    │ │\n│  │   :view      │                │  - onLog       │ │\n│  │   lang=\"en\"/>│                └────────────────┘ │\n│  └──────┬───────┘                        ▲          │\n│         │ provides                       │          │\n├─────────┼────────────────────────────────┼──────────┤\n│  SDK    │                                │          │\n│         ▼                                │          │\n│  ┌─────────────────┐  ┌──────────────┐   │          │\n│  │ DynamicRenderer  │  │ Expression   │   │          │\n│  │ (recursive)      │  │ Resolver     │   │          │\n│  │                  │  ├──────────────┤   │          │\n│  │ 30+ MD3 widgets  │  │ Conditional  │   │          │\n│  │ via PrimeVue 4   │  │ Engine       │   │          │\n│  │                  │  ├──────────────┤   │          │\n│  │ ErrorBoundary    │  │ Schema       │   │          │\n│  │ for Component &  │  │ Resolver     │◀──┘          │\n│  │ ForEach          │  │ (validation) │              │\n│  └─────────────────┘  └──────────────┘              │\n└─────────────────────────────────────────────────────┘\n```\n\n## Data Model (MVVM)\n\n| Layer | File | Purpose |\n|---|---|---|\n| **ViewModel** | `schema.json` | Data contract — field types, validation, LOV sources, conditionals, multi-lang labels |\n| **View** | `view.json` | UI component tree — layout, binding, actions, transient UI state |\n| **Model** | Backend | Persisted data, served via delegate's `requestData` |\n\n## Delegate Interface\n\n```typescript\ninterface PseudoViewDelegate {\n  /** Fetch data from backend (LOV items, lookup enrichment). ref = source (required); params = resolved filter from x-lookup (optional when no filter). */\n  requestData(ref: string, params?: Record<string, string>): Promise<unknown>\n\n  /** Load a nested component's schema + view by reference */\n  loadComponent(ref: string): Promise<{ schema: DataSchema; view: ViewDefinition }>\n\n  /** Handle user actions (submit, cancel, back, custom commands) */\n  onAction(action: string, formData: Record<string, unknown>, command?: string): Promise<void>\n\n  /** Optional: custom async validation after built-in checks pass */\n  onValidationRequest?(field: string, value: unknown, formData: Record<string, unknown>): Promise<string | null>\n\n  /** Optional: capture SDK logs (debug, info, warn, error) */\n  onLog?(level: LogLevel, message: string, error?: unknown, context?: Record<string, unknown>): void\n}\n```\n\n## Supported Components\n\n### Layout\n`Column` · `Row` · `Stack` · `Grid` · `Expanded` · `SizedBox` · `Divider` · `Spacer`\n\n### Input\n`TextField` · `TextArea` · `NumberField` · `Dropdown` · `Checkbox` · `RadioGroup` · `DatePicker` · `TimePicker` · `Switch` · `Slider` · `SegmentedButton` · `SearchField` · `AutoComplete`\n\n### Display\n`Text` · `Image` · `Chip` · `ListTile` · `Avatar` · `RichText` · `LoadingIndicator`\n\n### Surface & Overlay\n`Card` · `Dialog` · `BottomSheet` · `SideSheet` · `Snackbar` · `Tooltip`\n\n### Navigation\n`TabView` · `AppBar` · `NavigationBar` · `NavigationDrawer`\n\n### Container\n`ExpansionPanel` · `Stepper`\n\n### Action\n`Button` · `IconButton` · `FAB` · `Menu` · `Toolbar` · `Carousel`\n\n### Control\n`ForEach` · `Component` (nested)\n\n## Expression Namespaces\n\n| Namespace | Source | Example |\n|---|---|---|\n| `$form.field` | User input data | `$form.firstName` |\n| `$instance.field` | Backend persisted data | `$instance.status` |\n| `$param.field` | Parent-bound data (nested components) | `$param.cityCode` |\n| `$ui.key` | Transient UI state (not submitted) | `$ui.showDialog` |\n| `$schema.field.label` | Schema label for current language | `$schema.city.label` |\n| `$lov.field` | LOV items array | `$lov.city` |\n| `$lov.field.display` | Localized display name for current value | `$lov.city.display` |\n| `$lookup.prop.field` | Enrichment data | `$lookup.branch.address` |\n| `$item.field` | ForEach iteration item | `$item.name` |\n| `$context.lang` | Runtime context | `$context.lang` |\n\n## Conditional Operators\n\n`equals` · `notEquals` · `in` · `notIn` · `greaterThan` · `lessThan` · `greaterThanOrEquals` · `lessThanOrEquals` · `contains` · `startsWith` · `endsWith` · `isEmpty` · `isNotEmpty`\n\nCompound rules: `allOf` (AND), `anyOf` (OR), `not` (negate) — recursive nesting supported.\n\n## Validation Formats\n\nBuilt-in `format` validators: `email` · `uri` / `url` · `date` · `date-time` · `time` · `phone` / `tel` · `iban`\n\n## Vocabularies\n\nThe package includes JSON Schema vocabulary definitions for IDE auto-complete and tooling:\n\n```typescript\n// Import as JSON modules\nimport viewVocab from '@burgantech/pseudo-ui/vocabularies/view-vocabulary.json'\nimport viewModelVocab from '@burgantech/pseudo-ui/vocabularies/view-model-vocabulary.json'\n```\n\n- **View Vocabulary** — defines all valid component types, properties, and their constraints\n- **ViewModel Vocabulary** — defines all `x-*` extensions (`x-labels`, `x-lov`, `x-conditional`, etc.)\n\n## Cross-Platform\n\nThis package provides the **TypeScript/Vue** implementation. A **Dart/Flutter** package is planned and will render the same JSON schemas and views using Material 3 widgets. Both will share the same vocabulary definitions, ensuring consistent behavior across platforms.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}