{"_id":"@biyonik/zignal","_rev":"4-c7d2675fe4d328fd804a3db30fdc9059","name":"@biyonik/zignal","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@biyonik/zignal","version":"0.1.0","keywords":["angular","signals","forms","form-builder","schema-driven","zod","validation","reactive-forms","material","typescript","zoneless"],"author":{"url":"https://github.com/biyonik","name":"Ahmet ALTUN","email":"ahmet.altun60@gmail.com"},"license":"MIT","_id":"@biyonik/zignal@0.1.0","maintainers":[{"name":"biyonik","email":"ahmet.altun60@gmail.com"}],"homepage":"https://github.com/biyonik/zignal#readme","bugs":{"url":"https://github.com/biyonik/zignal/issues"},"dist":{"shasum":"2d5554c4aad5a40b841b6cfafbc1d5c99aa87a0b","tarball":"https://registry.npmjs.org/@biyonik/zignal/-/zignal-0.1.0.tgz","fileCount":105,"integrity":"sha512-HLD3gkZlwTDK9RLQ5XmkwoseWcPHosUYL1Jm9fN6gz8wwLnpdBMmGJ0dE4Fpd9KcddFzckFQoBad5G5sAbCfqQ==","signatures":[{"sig":"MEYCIQC8KxwWvogarrs5YuELOrW/FV/1cczQ9QBxzePobV9/lwIhAMWOtBd+laSeWqLiq6O8/wZlopI9aKoffAcXu4a4UzZM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2324148},"module":"fesm2022/biyonik-zignal.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"esm":"./esm2022/biyonik-zignal.mjs","types":"./index.d.ts","default":"./fesm2022/biyonik-zignal.mjs","esm2022":"./esm2022/biyonik-zignal.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"aabed3c42dca6f4e6aa8ccaa8cca31139070a959","typings":"index.d.ts","_npmUser":{"name":"biyonik","email":"ahmet.altun60@gmail.com"},"repository":{"url":"git+https://github.com/biyonik/zignal.git","type":"git"},"_npmVersion":"11.6.3","description":"Signal-first, schema-driven form library for Angular 17+. Powered by Zod validation.","directories":{},"sideEffects":false,"_nodeVersion":"24.1.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"zod":"^3.22.0","@angular/core":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/forms":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/common":"^17.0.0 || ^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"ts-node":{"optional":true},"@angular/cdk":{"optional":true},"@angular/material":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zignal_0.1.0_1765994417617_0.4168029365540302","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@biyonik/zignal","version":"0.1.1","keywords":["angular","signals","forms","form-builder","schema-driven","zod","validation","reactive-forms","material","typescript","zoneless"],"author":{"url":"https://github.com/biyonik","name":"Ahmet ALTUN","email":"ahmet.altun60@gmail.com"},"license":"MIT","_id":"@biyonik/zignal@0.1.1","maintainers":[{"name":"biyonik","email":"ahmet.altun60@gmail.com"}],"homepage":"https://github.com/biyonik/zignal#readme","bugs":{"url":"https://github.com/biyonik/zignal/issues"},"dist":{"shasum":"eee8e468c88cb91ab4f56af2918657e9c6311d8e","tarball":"https://registry.npmjs.org/@biyonik/zignal/-/zignal-0.1.1.tgz","fileCount":123,"integrity":"sha512-RWGxRTPI1LqKp0Oyar7V7wGBF6nzGDpb5mkLqYHxCNSaVSKY4RPODo2FLyABgc0I8XWNpA89m5tf0ipgww1WkQ==","signatures":[{"sig":"MEYCIQDYlbxfMUHHqyiq9P9KHF92ke/Og2uRKX0fOlINijfbqQIhAKfh/7DJpATiWiTEJFtJdLk2o6YizRwzJlUWXmZKhMOp","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2454891},"module":"fesm2022/biyonik-zignal.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"esm":"./esm2022/biyonik-zignal.mjs","types":"./index.d.ts","default":"./fesm2022/biyonik-zignal.mjs","esm2022":"./esm2022/biyonik-zignal.mjs"},"./package.json":{"default":"./package.json"},"./src/lib/ui/adapters/material":{"esm":"./esm2022/src/lib/ui/adapters/material/biyonik-zignal-src-lib-ui-adapters-material.mjs","types":"./src/lib/ui/adapters/material/index.d.ts","default":"./fesm2022/biyonik-zignal-src-lib-ui-adapters-material.mjs","esm2022":"./esm2022/src/lib/ui/adapters/material/biyonik-zignal-src-lib-ui-adapters-material.mjs"}},"gitHead":"94ac65a5a4b197f89339b7701a95ef55cafe5e66","typings":"index.d.ts","_npmUser":{"name":"biyonik","email":"ahmet.altun60@gmail.com"},"repository":{"url":"git+https://github.com/biyonik/zignal.git","type":"git"},"_npmVersion":"11.2.0","description":"Signal-first, schema-driven form library for Angular 17+. Powered by Zod validation.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"zod":"^3.22.0","@angular/core":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/forms":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/common":"^17.0.0 || ^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"ts-node":{"optional":true},"@angular/cdk":{"optional":true},"@angular/material":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zignal_0.1.1_1766059371656_0.01576849557907023","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@biyonik/zignal","version":"0.1.2","keywords":["angular","signals","forms","form-builder","schema-driven","zod","validation","reactive-forms","material","typescript","zoneless"],"author":{"url":"https://github.com/biyonik","name":"Ahmet ALTUN","email":"ahmet.altun60@gmail.com"},"license":"MIT","_id":"@biyonik/zignal@0.1.2","maintainers":[{"name":"biyonik","email":"ahmet.altun60@gmail.com"}],"homepage":"https://github.com/biyonik/zignal#readme","bugs":{"url":"https://github.com/biyonik/zignal/issues"},"dist":{"shasum":"7758dcfa845cf455b9a11053fac5d164bc0912c3","tarball":"https://registry.npmjs.org/@biyonik/zignal/-/zignal-0.1.2.tgz","fileCount":187,"integrity":"sha512-UU7sgs2abqZvuTZc9ID8zHCAeWvbNH80RT0lwVbN2nIMOXWe7eT327nvuD/lwvjgqXIeFTZkXhntdIILU5j+tQ==","signatures":[{"sig":"MEUCIFRQLK501CYjh0U+0dXpuHGP7HDNP4WwmuAA2uAExJG5AiEA1QRHvq2IE0MmjTmDvApeJMHopcjm7r+8hYGBEXrTXSs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3711696},"module":"fesm2022/biyonik-zignal.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"esm":"./esm2022/biyonik-zignal.mjs","types":"./index.d.ts","default":"./fesm2022/biyonik-zignal.mjs","esm2022":"./esm2022/biyonik-zignal.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"a89904dbc83181bb4cae2854262c95f5530dfe82","typings":"index.d.ts","_npmUser":{"name":"biyonik","email":"ahmet.altun60@gmail.com"},"repository":{"url":"git+https://github.com/biyonik/zignal.git","type":"git"},"_npmVersion":"11.6.3","description":"Signal-first, schema-driven form library for Angular 17+. Powered by Zod validation.","directories":{},"sideEffects":false,"_nodeVersion":"24.1.0","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"zod":"^3.22.0","@angular/cdk":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/core":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/forms":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/common":"^17.0.0 || ^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"ts-node":{"optional":true},"@angular/cdk":{"optional":true},"@angular/material":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/zignal_0.1.2_1766858955392_0.605094998310113","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@biyonik/zignal","version":"0.1.3","description":"Signal-first, schema-driven form library for Angular 17+. Powered by Zod validation.","keywords":["angular","signals","forms","form-builder","schema-driven","zod","validation","reactive-forms","material","typescript","zoneless"],"author":{"name":"Ahmet ALTUN","email":"ahmet.altun60@gmail.com","url":"https://github.com/biyonik"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/biyonik/zignal.git"},"bugs":{"url":"https://github.com/biyonik/zignal/issues"},"homepage":"https://github.com/biyonik/zignal#readme","peerDependencies":{"@angular/cdk":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/common":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/core":"^17.0.0 || ^18.0.0 || ^19.0.0","@angular/forms":"^17.0.0 || ^18.0.0 || ^19.0.0","zod":"^3.22.0"},"peerDependenciesMeta":{"@angular/material":{"optional":true},"@angular/cdk":{"optional":true},"ts-node":{"optional":true}},"sideEffects":false,"engines":{"node":">=18.0.0"},"module":"fesm2022/biyonik-zignal.mjs","typings":"index.d.ts","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./index.d.ts","esm2022":"./esm2022/biyonik-zignal.mjs","esm":"./esm2022/biyonik-zignal.mjs","default":"./fesm2022/biyonik-zignal.mjs"}},"dependencies":{"tslib":"^2.3.0"},"gitHead":"4360928ef46a71dc2a873ae888fbabcf8ffdcbe4","_id":"@biyonik/zignal@0.1.3","_nodeVersion":"24.1.0","_npmVersion":"11.6.3","dist":{"integrity":"sha512-S3Kfo0ys8n5xkxCX1ZweSXP1DmMTbkfie8q6jFvQ+XS+1fERMUcpFmLZfFirnIKke2REDJSYdNLXp5/xAVcdmA==","shasum":"de8fd172781b77bf3c28fa616df22560ae3500a6","tarball":"https://registry.npmjs.org/@biyonik/zignal/-/zignal-0.1.3.tgz","fileCount":187,"unpackedSize":3736549,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGsJZzPe01+9FNNyLgcnGh1V6eJ7LidD3+kfctJOZc6rAiEAgMmZBBXH//E385XFb7xLX5hIahfYMwUgUae5nrLhBLQ="}]},"_npmUser":{"name":"biyonik","email":"ahmet.altun60@gmail.com"},"directories":{},"maintainers":[{"name":"biyonik","email":"ahmet.altun60@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zignal_0.1.3_1768067012966_0.9307832783777883"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-17T18:00:17.491Z","modified":"2026-01-10T17:43:33.399Z","0.1.0":"2025-12-17T18:00:17.810Z","0.1.1":"2025-12-18T12:02:51.894Z","0.1.2":"2025-12-27T18:09:15.601Z","0.1.3":"2026-01-10T17:43:33.169Z"},"bugs":{"url":"https://github.com/biyonik/zignal/issues"},"author":{"name":"Ahmet ALTUN","email":"ahmet.altun60@gmail.com","url":"https://github.com/biyonik"},"license":"MIT","homepage":"https://github.com/biyonik/zignal#readme","keywords":["angular","signals","forms","form-builder","schema-driven","zod","validation","reactive-forms","material","typescript","zoneless"],"repository":{"type":"git","url":"git+https://github.com/biyonik/zignal.git"},"description":"Signal-first, schema-driven form library for Angular 17+. Powered by Zod validation.","maintainers":[{"name":"biyonik","email":"ahmet.altun60@gmail.com"}],"readme":"<div align=\"center\">\r\n  <img src=\"logo.svg\" alt=\"Zignal Logo\" width=\"120\" height=\"120\" />\r\n  <h1>Zignal</h1>\r\n\r\n  <p>\r\n    <strong>Signal-first, schema-driven form library for Angular 17+</strong>\r\n    <br />\r\n    Angular 17+ için Signal tabanlı, şema güdümlü form kütüphanesi\r\n  </p>\r\n\r\n  <div align=\"center\">\r\n\r\n[![npm version](https://img.shields.io/npm/v/@biyonik/zignal.svg)](https://www.npmjs.com/package/@biyonik/zignal)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n[![Angular](https://img.shields.io/badge/Angular-17%2B-DD0031.svg?logo=angular&logoColor=white)](https://angular.io/)\r\n[![Zod](https://img.shields.io/badge/Zod-Schema-3068B7.svg)](https://zod.dev/)\r\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)\r\n<a href=\"https://github.com/biyonik/zignal/actions\"><img src=\"https://github.com/biyonik/zignal/workflows/CI/badge.svg\" alt=\"CI Status\"></a>\r\n\r\n  </div>\r\n</div>\r\n\r\n---\r\n\r\n## TR: Hakkında | EN: About\r\n\r\n**TR:** Zignal, Angular Signals kullanarak reaktif form yönetimi sağlayan, Zod validasyonu ile type-safe bir form kütüphanesidir. Türkiye'ye özgü validatorlar (TCKN, VKN, IBAN) ve çoklu dil desteği içerir.\r\n\r\n**EN:** Zignal is a type-safe form library that provides reactive form management using Angular Signals with Zod validation. It includes Turkey-specific validators (TCKN, VKN, IBAN) and multi-language support.\r\n\r\n---\r\n\r\n## TR: Özellikler | EN: Features\r\n\r\n| TR | EN |\r\n|----|----|\r\n| **Signal-first** - Angular Signals ile fine-grained reactivity | **Signal-first** - Fine-grained reactivity with Angular Signals |\r\n| **Schema-driven** - JSON'dan dinamik form oluşturma | **Schema-driven** - Dynamic form generation from JSON |\r\n| **Type-safe** - Zod entegrasyonu ile runtime + compile-time güvenlik | **Type-safe** - Runtime + compile-time safety with Zod integration |\r\n| **Zoneless ready** - Angular 18+ zoneless mode uyumlu | **Zoneless ready** - Compatible with Angular 18+ zoneless mode |\r\n| **i18n** - Çoklu dil desteği (TR, EN ve custom) | **i18n** - Multi-language support (TR, EN and custom) |\r\n| **Form Persistence** - localStorage/sessionStorage desteği | **Form Persistence** - localStorage/sessionStorage support |\r\n| **Async Validation** - API-based asenkron validasyon | **Async Validation** - API-based asynchronous validation |\r\n| **TR Validators** - TCKN, VKN, IBAN, Plaka validasyonu | **TR Validators** - Turkish ID, Tax ID, IBAN, License plate validation |\r\n\r\n---\r\n\r\n## TR: Kurulum | EN: Installation\r\n\r\n```bash\r\nnpm install @biyonik/zignal zod\r\n```\r\n\r\n---\r\n\r\n## TR: Hızlı Başlangıç | EN: Quick Start\r\n\r\n### 1. Field Tanımlama | Define Fields\r\n\r\n```typescript\r\nimport { StringField, NumberField, BooleanField, PasswordField } from '@biyonik/zignal';\r\n\r\n// TR: E-posta alanı\r\n// EN: Email field\r\nconst emailField = new StringField('email', 'E-posta', {\r\n  required: true,\r\n  email: true\r\n});\r\n\r\n// TR: Yaş alanı\r\n// EN: Age field\r\nconst ageField = new NumberField('age', 'Yaş', {\r\n  required: true,\r\n  min: 18,\r\n  max: 100,\r\n  integer: true\r\n});\r\n\r\n// TR: Şifre alanı (güçlü şifre kuralları)\r\n// EN: Password field (strong password rules)\r\nconst passwordField = new PasswordField('password', 'Şifre', {\r\n  required: true,\r\n  minLength: 8,\r\n  requireUppercase: true,\r\n  requireNumber: true,\r\n  requireSpecial: true\r\n});\r\n\r\n// TR: Şartları kabul checkbox\r\n// EN: Terms acceptance checkbox\r\nconst acceptTerms = new BooleanField('acceptTerms', 'Şartları kabul ediyorum', {\r\n  required: true  // true olması zorunlu\r\n});\r\n```\r\n\r\n### 2. Form Schema Oluşturma | Create Form Schema\r\n\r\n```typescript\r\nimport { FormSchema } from '@biyonik/zignal';\r\n\r\ninterface UserForm {\r\n  email: string;\r\n  age: number;\r\n  password: string;\r\n  acceptTerms: boolean;\r\n}\r\n\r\nconst userSchema = new FormSchema<UserForm>([\r\n  emailField,\r\n  ageField,\r\n  passwordField,\r\n  acceptTerms\r\n]);\r\n```\r\n\r\n### 3. Component'te Kullanım | Use in Component\r\n\r\n```typescript\r\nimport { Component } from '@angular/core';\r\n\r\n@Component({\r\n  selector: 'app-user-form',\r\n  template: `\r\n    <form (ngSubmit)=\"onSubmit()\">\r\n      <!-- Email -->\r\n      <div class=\"field\">\r\n        <label>{{ form.fields.email.label }}</label>\r\n        <input\r\n          type=\"email\"\r\n          [value]=\"form.fields.email.value()\"\r\n          (input)=\"form.setValue('email', $event.target.value)\"\r\n          (blur)=\"form.fields.email.touched.set(true)\"\r\n        />\r\n        @if (form.fields.email.error()) {\r\n          <span class=\"error\">{{ form.fields.email.error() }}</span>\r\n        }\r\n      </div>\r\n\r\n      <!-- Password -->\r\n      <div class=\"field\">\r\n        <label>{{ form.fields.password.label }}</label>\r\n        <input\r\n          type=\"password\"\r\n          [value]=\"form.fields.password.value()\"\r\n          (input)=\"form.setValue('password', $event.target.value)\"\r\n        />\r\n        @if (form.fields.password.error()) {\r\n          <span class=\"error\">{{ form.fields.password.error() }}</span>\r\n        }\r\n      </div>\r\n\r\n      <button type=\"submit\" [disabled]=\"!form.valid()\">\r\n        Kaydet / Save\r\n      </button>\r\n    </form>\r\n  `\r\n})\r\nexport class UserFormComponent {\r\n  form = userSchema.createForm({\r\n    email: '',\r\n    age: null,\r\n    password: '',\r\n    acceptTerms: false\r\n  });\r\n\r\n  async onSubmit() {\r\n    if (await this.form.validateAll()) {\r\n      const data = this.form.getValues();\r\n      console.log('Form data:', data);\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n## TR: Dil Desteği (i18n) | EN: Language Support (i18n)\r\n\r\n```typescript\r\nimport { setLocale, addMessages, t, detectBrowserLocale, useAutoLocale } from '@biyonik/zignal';\r\n\r\n// TR: Browser diline göre otomatik ayarla\r\n// EN: Auto-detect browser language\r\nconst locale = useAutoLocale(); // Returns 'tr' or 'en'\r\n\r\n// TR: Manuel dil değiştir\r\n// EN: Change language manually\r\nsetLocale('en');\r\n\r\n// TR: Custom mesajlar ekle (firma özel)\r\n// EN: Add custom messages (company specific)\r\naddMessages('tr', {\r\n  required: 'Bu bilgi zorunludur',\r\n  'string.email': 'Lütfen kurumsal e-posta adresinizi giriniz',\r\n});\r\n\r\n// TR: Yeni dil ekle (örn: Almanca)\r\n// EN: Add new language (e.g., German)\r\naddMessages('de', {\r\n  required: 'Dieses Feld ist erforderlich',\r\n  'string.min': 'Mindestens {min} Zeichen erforderlich',\r\n});\r\nsetLocale('de');\r\n\r\n// TR: Validation mesajını al\r\n// EN: Get validation message\r\nconst msg = t('password.min', { min: 8 });\r\n// TR: \"Şifre en az 8 karakter olmalıdır\"\r\n// EN: \"Password must be at least 8 characters\"\r\n```\r\n\r\n---\r\n\r\n## TR: Form Persistence | EN: Form Persistence\r\n\r\n```typescript\r\nimport { createFormPersistence } from '@biyonik/zignal';\r\n\r\n// TR: Form verilerini localStorage'a kaydet\r\n// EN: Save form data to localStorage\r\nconst persistence = createFormPersistence<UserForm>('user-form', {\r\n  storage: 'local',           // 'local' | 'session'\r\n  debounceMs: 500,            // Auto-save debounce\r\n  exclude: ['password'],      // Hassas alanları hariç tut\r\n  ttl: 24 * 60 * 60 * 1000,   // 24 saat sonra expire\r\n});\r\n\r\n// TR: Form verilerini yükle\r\n// EN: Load form data\r\nconst savedData = persistence.load();\r\nif (savedData) {\r\n  form.patchValues(savedData);\r\n}\r\n\r\n// TR: Auto-save aktifleştir\r\n// EN: Enable auto-save\r\npersistence.enableAutoSave(form.values);\r\n\r\n// TR: Manuel kaydet\r\n// EN: Manual save\r\npersistence.save(form.getValues());\r\n\r\n// TR: Temizle\r\n// EN: Clear\r\npersistence.clear();\r\n```\r\n\r\n---\r\n\r\n## TR: Asenkron Validasyon | EN: Async Validation\r\n\r\n```typescript\r\nimport { createEmailValidator, createUsernameValidator } from '@biyonik/zignal';\r\n\r\n// TR: E-posta benzersizlik kontrolü\r\n// EN: Email uniqueness check\r\nconst emailValidator = createEmailValidator(\r\n  async (email) => {\r\n    const response = await fetch(`/api/check-email?email=${email}`);\r\n    const { exists } = await response.json();\r\n    return !exists; // true = geçerli, false = zaten var\r\n  },\r\n  {\r\n    debounceMs: 300,\r\n    cacheSize: 50,\r\n    errorMessage: 'Bu e-posta adresi zaten kullanımda'\r\n  }\r\n);\r\n\r\n// TR: Component'te kullan\r\n// EN: Use in component\r\n@Component({...})\r\nexport class RegisterComponent {\r\n  emailValidator = emailValidator;\r\n\r\n  async checkEmail(email: string) {\r\n    const error = await this.emailValidator.validate(email);\r\n    if (error) {\r\n      console.log('Validation error:', error);\r\n    }\r\n  }\r\n\r\n  // TR: Reactive state\r\n  isPending = this.emailValidator.pending;   // Signal<boolean>\r\n  isValid = this.emailValidator.valid;       // Signal<boolean>\r\n  errorMsg = this.emailValidator.error;      // Signal<string | null>\r\n}\r\n```\r\n\r\n---\r\n\r\n## TR: Türkiye Validatorları | EN: Turkey Validators\r\n\r\n```typescript\r\nimport {\r\n  tcknSchema,\r\n  vknSchema,\r\n  turkishIbanSchema,\r\n  turkishPhoneSchema,\r\n  turkishPlateSchema,\r\n  isValidTCKN,\r\n  isValidVKN\r\n} from '@biyonik/zignal';\r\n\r\n// TR: TCKN validasyonu\r\n// EN: Turkish ID validation\r\nconst tckn = tcknSchema.safeParse('12345678901');\r\nif (!tckn.success) {\r\n  console.log('Geçersiz TCKN');\r\n}\r\n\r\n// TR: Direkt fonksiyon kullanımı\r\n// EN: Direct function usage\r\nif (isValidTCKN('12345678901')) {\r\n  console.log('TCKN geçerli');\r\n}\r\n\r\n// TR: Form field olarak\r\n// EN: As form field\r\nconst tcknField = new StringField('tckn', 'T.C. Kimlik No', {\r\n  required: true,\r\n  pattern: /^\\d{11}$/,\r\n  customValidator: (value) => isValidTCKN(value) ? null : 'Geçersiz TCKN'\r\n});\r\n```\r\n\r\n---\r\n\r\n## TR: Field Tipleri | EN: Field Types\r\n\r\n| Field | Type | TR: Açıklama | EN: Description |\r\n|-------|------|--------------|-----------------|\r\n| `StringField` | `string` | Tek satır metin | Single line text |\r\n| `NumberField` | `number` | Sayısal değer | Numeric value |\r\n| `BooleanField` | `boolean` | Evet/Hayır | Yes/No |\r\n| `DateField` | `Date` | Tarih seçici | Date picker |\r\n| `PasswordField` | `string` | Şifre (güç göstergeli) | Password (with strength) |\r\n| `EmailField` | `string` | E-posta | Email |\r\n| `UrlField` | `string` | URL | URL |\r\n| `TextareaField` | `string` | Çok satırlı metin | Multi-line text |\r\n| `SelectField<T>` | `T` | Dropdown seçimi | Dropdown selection |\r\n| `MultiselectField<T>` | `T[]` | Çoklu seçim | Multiple selection |\r\n| `ArrayField` | `object[]` | Tekrarlayan kayıtlar | Repeatable records |\r\n| `JsonField` | `object` | JSON/Object | JSON/Object |\r\n| `FileField` | `FileInfo` | Dosya yükleme | File upload |\r\n\r\n---\r\n\r\n## TR: FormState API | EN: FormState API\r\n\r\n```typescript\r\nconst form = schema.createForm(initialValues);\r\n\r\n// ===============================================\r\n// TR: Signals (Reaktif)\r\n// EN: Signals (Reactive)\r\n// ===============================================\r\nform.values();           // Signal<T> - Tüm değerler / All values\r\nform.valid();            // Signal<boolean> - Geçerlilik / Validity\r\nform.dirty();            // Signal<boolean> - Değişiklik var mı? / Has changes?\r\nform.errors();           // Signal<Record<string, string | null>>\r\n\r\n// ===============================================\r\n// TR: Field Erişimi\r\n// EN: Field Access\r\n// ===============================================\r\nform.fields.email.value();     // Signal<string>\r\nform.fields.email.error();     // Signal<string | null>\r\nform.fields.email.touched();   // Signal<boolean>\r\nform.fields.email.valid();     // Signal<boolean>\r\nform.fields.email.dirty();     // Signal<boolean>\r\n\r\n// ===============================================\r\n// TR: Aksiyonlar\r\n// EN: Actions\r\n// ===============================================\r\nform.setValue('email', 'test@example.com');\r\nform.patchValues({ email: 'a@b.com', age: 25 });\r\nform.touchAll();               // Tüm hataları göster / Show all errors\r\nform.reset();                  // Başlangıç değerlerine dön / Reset to initial\r\nform.validateAll();            // Async validation\r\n\r\n// ===============================================\r\n// TR: Getter'lar\r\n// EN: Getters\r\n// ===============================================\r\nform.getValues();              // Type-safe data (Zod parsed)\r\nform.getDirtyValues();         // Sadece değişenler / Only changed fields\r\n```\r\n\r\n---\r\n\r\n## TR: JSON'dan Dinamik Form | EN: Dynamic Form from JSON\r\n\r\n```typescript\r\nimport { SchemaFactory } from '@biyonik/zignal';\r\n\r\n@Component({...})\r\nexport class DynamicFormComponent {\r\n  private factory = inject(SchemaFactory);\r\n\r\n  form = this.factory.parse([\r\n    {\r\n      type: 'string',\r\n      name: 'email',\r\n      label: 'E-posta',\r\n      config: { required: true, email: true }\r\n    },\r\n    {\r\n      type: 'number',\r\n      name: 'age',\r\n      label: 'Yaş',\r\n      config: { min: 18, max: 100 }\r\n    },\r\n    {\r\n      type: 'select',\r\n      name: 'country',\r\n      label: 'Ülke',\r\n      config: {\r\n        required: true,\r\n        options: [\r\n          { value: 'TR', label: 'Türkiye' },\r\n          { value: 'US', label: 'USA' }\r\n        ]\r\n      }\r\n    }\r\n  ]);\r\n}\r\n```\r\n\r\n---\r\n\r\n## TR: Karşılaştırma | EN: Comparison\r\n\r\n| TR: Özellik / EN: Feature | ngx-formly | Reactive Forms | **Zignal** |\r\n|---------------------------|------------|----------------|------------|\r\n| Reactivity | RxJS | RxJS | **Angular Signals** |\r\n| Zoneless Support | ❌ | ⚠️ | **✅** |\r\n| Type Safety | Limited | Limited | **Full (Zod)** |\r\n| i18n Support | Plugin | Manual | **Built-in** |\r\n| Form Persistence | ❌ | Manual | **Built-in** |\r\n| Async Validation | ✅ | ✅ | **✅ + Cache** |\r\n| Bundle Size | ~50KB | ~0KB (Angular) | **<20KB** |\r\n| Learning Curve | High | Medium | **Low** |\r\n\r\n---\r\n\r\n## TR: Gereksinimler | EN: Requirements\r\n\r\n- Angular 17.0.0+\r\n- Zod 3.22.0+\r\n- TypeScript 5.0+\r\n\r\n---\r\n\r\n## TR: Form Validation Behavior | EN: Form Validation Behavior\r\n\r\n### TR: Validation Lifecycle | EN: Validation Lifecycle\r\n\r\nZignal forms provide comprehensive validation with configurable behavior:\r\n\r\n#### Default Behavior\r\n\r\n```typescript\r\nconst schema = new FormSchema<LoginForm>([\r\n  new EmailField('email', 'Email', { required: true }),\r\n  new PasswordField('password', 'Password', { required: true })\r\n]);\r\n\r\nconst form = schema.createForm({ email: '', password: '' });\r\n```\r\n\r\n**Key Concepts:**\r\n- **`valid()`**: Returns `true` if all fields are valid, **independent of touched state**\r\n- **`error()`**: Shows error **only if field is touched**\r\n- **`validateAll()`**: Validates all fields and **automatically touches them** (default behavior)\r\n- **`touchAll()`**: Marks all fields as touched to show all errors\r\n\r\n#### Form Renderer Configuration\r\n\r\n```typescript\r\n<zg-form-renderer\r\n  [schema]=\"schema\"\r\n  [formState]=\"form\"\r\n  [config]=\"{\r\n    submitDisabledWhenInvalid: true,  // Disable submit if invalid (default: false)\r\n    validateOnInit: true,              // Validate when form loads (default: true)\r\n    validateOnChange: true,            // Validate on value change (default: true)\r\n    touchAllOnSubmit: true,            // Touch all on submit (default: true)\r\n    showErrorsWhenUntouched: false     // Show errors before touch (default: false)\r\n  }\"\r\n  (submitted)=\"onSubmit($event)\"\r\n/>\r\n```\r\n\r\n#### Submit Validation Workflow\r\n\r\n```typescript\r\nasync handleSubmit() {\r\n  // 1. Mark submit attempted (for error display)\r\n  form.setSubmitAttempted(true);\r\n\r\n  // 2. Touch all fields (default behavior)\r\n  form.touchAll();\r\n\r\n  // 3. Wait for signal updates\r\n  await new Promise(resolve => setTimeout(resolve, 0));\r\n\r\n  // 4. Validate all fields\r\n  const isValid = await form.validateAll();\r\n\r\n  // 5. Submit only if valid\r\n  if (isValid) {\r\n    const data = form.getValues();\r\n    // Send to API...\r\n  }\r\n}\r\n```\r\n\r\n#### Validation Options\r\n\r\n**validateAll() Parameters:**\r\n\r\n```typescript\r\n// Touch all fields before validation (default)\r\nawait form.validateAll();  // Same as validateAll(true)\r\n\r\n// Skip touching fields\r\nawait form.validateAll(false);\r\n```\r\n\r\n**Partial Validation:**\r\n\r\n```typescript\r\n// Validate only specific fields\r\nconst isValid = form.validateFields(['email', 'password']);\r\n// Only email and password are touched and validated\r\n```\r\n\r\n#### Error Display Patterns\r\n\r\n**Pattern 1: Show errors only after touch**\r\n\r\n```html\r\n@if (form.fields.email.error()) {\r\n  <span class=\"error\">{{ form.fields.email.error() }}</span>\r\n}\r\n```\r\n\r\n**Pattern 2: Show errors after submit attempt**\r\n\r\n```html\r\n@if (form.fields.email.error() || form.submitAttempted()) {\r\n  <span class=\"error\">{{ form.fields.email.error() }}</span>\r\n}\r\n```\r\n\r\n**Pattern 3: Always show errors (not recommended)**\r\n\r\n```html\r\n@if (!form.fields.email.valid()) {\r\n  <span class=\"error\">Required field validation failed</span>\r\n}\r\n```\r\n\r\n#### Button State Management\r\n\r\nThe form renderer uses a reactive `isFormValid()` computed signal:\r\n\r\n```typescript\r\n// In component\r\nreadonly isFormValid = computed(() => {\r\n  const state = this.formState();\r\n  return state ? state.valid() : false;\r\n});\r\n\r\n// In template\r\n<button\r\n  type=\"submit\"\r\n  [disabled]=\"config()?.submitDisabledWhenInvalid && !isFormValid()\">\r\n  Submit\r\n</button>\r\n```\r\n\r\nThis ensures the button state is always synchronized with form validity.\r\n\r\n#### Best Practices\r\n\r\n1. **Always use `validateAll()` before submit**\r\n   ```typescript\r\n   if (await form.validateAll()) {\r\n     // Submit...\r\n   }\r\n   ```\r\n\r\n2. **Touch fields on blur for better UX**\r\n   ```html\r\n   <input\r\n     (blur)=\"form.fields.email.touched.set(true)\"\r\n   />\r\n   ```\r\n\r\n3. **Use `submitAttempted` for comprehensive error display**\r\n   ```typescript\r\n   const shouldShowError = computed(() =>\r\n     form.fields.email.error() &&\r\n     (form.fields.email.touched() || form.submitAttempted())\r\n   );\r\n   ```\r\n\r\n4. **Leverage auto-validation on change**\r\n   ```typescript\r\n   // Enabled by default in form renderer\r\n   validateOnChange: true  // Validates 100ms after value change\r\n   ```\r\n\r\n#### Migration Notes\r\n\r\nIf you're upgrading from an earlier version:\r\n\r\n- `validateAll()` now touches all fields by default (use `validateAll(false)` to disable)\r\n- `valid()` is independent of touched state (always reflects true validity)\r\n- `submitAttempted` signal is now available on FormState\r\n- Form renderer validates on init by default (use `validateOnInit: false` to disable)\r\n\r\n---\r\n\r\n## TR: Lisans | EN: License\r\n\r\nMIT License - Ahmet ALTUN\r\n\r\n---\r\n\r\n## TR: Katkıda Bulunma | EN: Contributing\r\n\r\n1. Fork edin / Fork\r\n2. Feature branch oluşturun / Create feature branch (`git checkout -b feature/amazing-feature`)\r\n3. Commit edin / Commit (`git commit -m 'feat: add amazing feature'`)\r\n4. Push edin / Push (`git push origin feature/amazing-feature`)\r\n5. Pull Request açın / Open Pull Request\r\n\r\n---\r\n\r\n## TR: Destek | EN: Support\r\n\r\n- [GitHub Issues](https://github.com/biyonik/zignal/issues)\r\n- [Discussions](https://github.com/biyonik/zignal/discussions)\r\n- [Documentation](./DOCUMENTATION.md)","readmeFilename":"README.md"}