{"_id":"@apart-tech/jsonforms-kit","_rev":"3-2763b3f5f15b10d085f58e9b580c7a9a","name":"@apart-tech/jsonforms-kit","dist-tags":{"latest":"2.0.0"},"versions":{"0.1.0":{"name":"@apart-tech/jsonforms-kit","version":"0.1.0","keywords":["jsonforms","react","forms","headless","json-schema"],"author":{"name":"Apart Tech"},"license":"MIT","_id":"@apart-tech/jsonforms-kit@0.1.0","maintainers":[{"name":"aleksander-apart","email":"aleksander@apart.tech"},{"name":"marcinbrandys","email":"marcin@apart.tech"},{"name":"ilia_apart","email":"ilia@apart.tech"}],"homepage":"https://github.com/apart-tech/jsonforms-kit#readme","bugs":{"url":"https://github.com/apart-tech/jsonforms-kit/issues"},"dist":{"shasum":"3e6eee66d7b6d039b15ee03338d9eac95e521fba","tarball":"https://registry.npmjs.org/@apart-tech/jsonforms-kit/-/jsonforms-kit-0.1.0.tgz","fileCount":14,"integrity":"sha512-8qWOeDvMYe+iMEpfhnIUU4rQ/Vx7x2+lYSfrS36ai9aUHjk3pLpewqXv18iN5tTDD48OrMjwoeJMlVZCDw6EcQ==","signatures":[{"sig":"MEQCIASnO/etwbCAlLcHXGr9t3J5BFBgYS7NjizQd4W897RNAiBz12QdS4P35LgU3h2HGxakyRysIZqHV8OEqTFXBabOrg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":712064},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./renderers":{"types":"./dist/renderers/index.d.ts","import":"./dist/renderers/index.mjs","require":"./dist/renderers/index.js"}},"gitHead":"b71446c7a04d7573df68d08559499ca72a5e768a","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"aleksander-apart","email":"aleksander@apart.tech"},"repository":{"url":"git+https://github.com/apart-tech/jsonforms-kit.git","type":"git"},"_npmVersion":"11.0.0","description":"A headless, bring-your-own-components library for rendering JSON Forms with any React component library","directories":{},"_nodeVersion":"22.13.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.4.0","react":"^18.3.0","typescript":"^5.7.0","@types/react":"^18.3.0","@jsonforms/core":"^3.5.1","@jsonforms/react":"^3.5.1"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","@jsonforms/core":"^3.0.0","@jsonforms/react":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/jsonforms-kit_0.1.0_1764366790244_0.981653609843893","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@apart-tech/jsonforms-kit","version":"0.2.0","keywords":["jsonforms","react","forms","headless","json-schema"],"author":{"name":"Apart Tech"},"license":"MIT","_id":"@apart-tech/jsonforms-kit@0.2.0","maintainers":[{"name":"aleksander-apart","email":"aleksander@apart.tech"},{"name":"marcinbrandys","email":"marcin@apart.tech"},{"name":"ilia_apart","email":"ilia@apart.tech"}],"homepage":"https://github.com/apart-tech/jsonforms-kit#readme","bugs":{"url":"https://github.com/apart-tech/jsonforms-kit/issues"},"dist":{"shasum":"7269e1d8399bdcff6bb39ad4838e75b531c126ed","tarball":"https://registry.npmjs.org/@apart-tech/jsonforms-kit/-/jsonforms-kit-0.2.0.tgz","fileCount":14,"integrity":"sha512-mzrozCdudeq7tmRf0QzAIc9gpxhMkHBKdkj73z7iSKuSyvvhCWkf/+WZajSD74IRbYWzcD0hFxVHRoekQ89TkA==","signatures":[{"sig":"MEQCIFkEf4nCbphLqozw0F3zAVt2CkS6Hc6DKqcc+m7YGF3+AiB7XibgUBLQQCL8Xvm/L01pYm+MWMWcD/DR6lT7cAlxVg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":783506},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./renderers":{"types":"./dist/renderers/index.d.ts","import":"./dist/renderers/index.mjs","require":"./dist/renderers/index.js"}},"gitHead":"d7a541731505a911377782112da5f5dea201a11d","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"aleksander-apart","email":"aleksander@apart.tech"},"repository":{"url":"git+https://github.com/apart-tech/jsonforms-kit.git","type":"git"},"_npmVersion":"11.0.0","description":"A headless, bring-your-own-components library for rendering JSON Forms with any React component library","directories":{},"_nodeVersion":"22.13.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.4.0","react":"^18.3.0","typescript":"^5.7.0","@types/react":"^18.3.0","@jsonforms/core":"^3.5.1","@jsonforms/react":"^3.5.1"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","@jsonforms/core":"^3.0.0","@jsonforms/react":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/jsonforms-kit_0.2.0_1764376693081_0.8059913823513558","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@apart-tech/jsonforms-kit","version":"2.0.0","description":"A headless, bring-your-own-components library for rendering JSON Forms with any React component library","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./renderers":{"types":"./dist/renderers/index.d.ts","import":"./dist/renderers/index.mjs","require":"./dist/renderers/index.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint src --ext .ts,.tsx","clean":"rm -rf dist"},"peerDependencies":{"@jsonforms/core":"^3.0.0","@jsonforms/react":"^3.0.0","react":"^18.0.0 || ^19.0.0"},"devDependencies":{"@jsonforms/core":"^3.5.1","@jsonforms/react":"^3.5.1","@types/react":"^18.3.0","react":"^18.3.0","tsup":"^8.4.0","typescript":"^5.7.0"},"keywords":["jsonforms","react","forms","headless","json-schema"],"author":{"name":"Apart Tech"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/apart-tech/jsonforms-kit.git"},"publishConfig":{"access":"public"},"_id":"@apart-tech/jsonforms-kit@2.0.0","gitHead":"cba3cb2b1b03957c14cbce410e6b29ce8bfcf40f","bugs":{"url":"https://github.com/apart-tech/jsonforms-kit/issues"},"homepage":"https://github.com/apart-tech/jsonforms-kit#readme","_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-a3GJbrYpxx6Dy4ybjBSEsppUyPTprI1Mh+r7Sr2NpSyoDSdOQjbGytAO0w2PLHr3VErew1niEyut63YWgUw+jQ==","shasum":"02b0655cf24fdc977ee7ab61e71f3bc412a2a5a0","tarball":"https://registry.npmjs.org/@apart-tech/jsonforms-kit/-/jsonforms-kit-2.0.0.tgz","fileCount":14,"unpackedSize":1158544,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC2ZAPkvkP0ePpajYVJAAhQ9jjePK/DVIseoWu+dch2zQIhAIwyDYOy91y3ZV5MCUHcT2NUGRRELUnyc8yciirPA47j"}]},"_npmUser":{"name":"aleksander-apart","email":"aleksander@apart.tech"},"directories":{},"maintainers":[{"name":"aleksander-apart","email":"aleksander@apart.tech"},{"name":"marcinbrandys","email":"marcin@apart.tech"},{"name":"ilia_apart","email":"ilia@apart.tech"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jsonforms-kit_2.0.0_1765932272206_0.625286706125153"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-28T21:53:10.127Z","modified":"2025-12-17T00:44:32.576Z","0.1.0":"2025-11-28T21:53:10.474Z","0.2.0":"2025-11-29T00:38:13.270Z","2.0.0":"2025-12-17T00:44:32.364Z"},"bugs":{"url":"https://github.com/apart-tech/jsonforms-kit/issues"},"author":{"name":"Apart Tech"},"license":"MIT","homepage":"https://github.com/apart-tech/jsonforms-kit#readme","keywords":["jsonforms","react","forms","headless","json-schema"],"repository":{"type":"git","url":"git+https://github.com/apart-tech/jsonforms-kit.git"},"description":"A headless, bring-your-own-components library for rendering JSON Forms with any React component library","maintainers":[{"name":"aleksander-apart","email":"aleksander@apart.tech"},{"name":"marcinbrandys","email":"marcin@apart.tech"},{"name":"ilia_apart","email":"ilia@apart.tech"}],"readme":"# @apart-tech/jsonforms-kit\n\nA headless, bring-your-own-components library for rendering JSON Forms with any React component library. The library handles all the heavy lifting (renderer registration, tester logic, layout dispatching, i18n integration, conditional visibility) while allowing consumers to provide their own UI components.\n\n## Features\n\n- **Headless**: No CSS or styling dependencies - bring your own components\n- **Type-safe**: Full TypeScript support with component contracts\n- **Flexible**: Works with shadcn/ui, MUI, Chakra UI, or any component library\n- **Comprehensive**: Supports all common form controls out of the box\n- **Extensible**: Easy to add custom controls and testers\n\n## Installation\n\n```bash\nnpm install @apart-tech/jsonforms-kit @jsonforms/core @jsonforms/react\n```\n\n## Quick Start\n\n### 1. Create your component map\n\n```tsx\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select';\nimport { Checkbox } from '@/components/ui/checkbox';\n\nconst componentMap = {\n  // Required components\n  Input: ({ value, onChange, type, placeholder, disabled, className, ...props }) => (\n    <Input\n      type={type}\n      value={value || ''}\n      onChange={(e) => onChange(e.target.value)}\n      placeholder={placeholder}\n      disabled={disabled}\n      className={className}\n      {...props}\n    />\n  ),\n\n  Label: ({ children, className, htmlFor }) => (\n    <Label className={className} htmlFor={htmlFor}>{children}</Label>\n  ),\n\n  // Optional components\n  Select: ({ value, onChange, options, placeholder, disabled, className }) => (\n    <Select value={value} onValueChange={onChange} disabled={disabled}>\n      <SelectTrigger className={className}>\n        <SelectValue placeholder={placeholder} />\n      </SelectTrigger>\n      <SelectContent>\n        {options.map((opt) => (\n          <SelectItem key={opt.value} value={opt.value}>\n            {opt.label}\n          </SelectItem>\n        ))}\n      </SelectContent>\n    </Select>\n  ),\n\n  Checkbox: ({ checked, onChange, disabled, className }) => (\n    <Checkbox\n      checked={checked}\n      onCheckedChange={onChange}\n      disabled={disabled}\n      className={className}\n    />\n  ),\n\n  // Layout components\n  VerticalLayout: ({ children, className }) => (\n    <div className={className || 'space-y-6'}>{children}</div>\n  ),\n\n  HorizontalLayout: ({ children, className }) => (\n    <div className={className || 'flex gap-4 items-end'}>{children}</div>\n  ),\n\n  Group: ({ label, children, className }) => (\n    <fieldset className={className || 'space-y-4 border rounded-lg p-4'}>\n      {label && <legend className=\"text-lg font-semibold\">{label}</legend>}\n      {children}\n    </fieldset>\n  ),\n\n  // Error display\n  ErrorMessage: ({ message, className }) => (\n    <p className={className || 'text-sm text-red-600 mt-1'}>{message}</p>\n  ),\n\n  RequiredIndicator: ({ className }) => (\n    <span className={className || 'text-red-500 ml-1'}>*</span>\n  ),\n};\n```\n\n### 2. Create renderers\n\n```tsx\nimport { createRenderers } from '@apart-tech/jsonforms-kit';\n\nconst renderers = createRenderers({\n  components: componentMap,\n  classNames: {\n    field: 'space-y-1',\n    label: 'text-sm font-medium',\n    error: 'text-sm text-red-600 mt-1',\n    required: 'text-red-500 ml-1',\n    layouts: {\n      vertical: 'space-y-6',\n      horizontal: 'flex gap-4 items-end',\n      group: 'border rounded-lg p-4',\n    },\n  },\n});\n```\n\n### 3. Use with JsonForms\n\n```tsx\nimport { useState } from 'react';\nimport { JsonForms } from '@jsonforms/react';\nimport { FormProvider } from '@apart-tech/jsonforms-kit';\n\nfunction MyForm() {\n  const [data, setData] = useState({});\n\n  const schema = {\n    type: 'object',\n    properties: {\n      name: { type: 'string', title: 'Name' },\n      email: { type: 'string', format: 'email', title: 'Email' },\n      role: {\n        type: 'string',\n        title: 'Role',\n        enum: ['admin', 'user', 'guest'],\n      },\n    },\n    required: ['name', 'email'],\n  };\n\n  return (\n    <FormProvider components={componentMap}>\n      <JsonForms\n        schema={schema}\n        data={data}\n        renderers={renderers}\n        onChange={({ data }) => setData(data || {})}\n      />\n    </FormProvider>\n  );\n}\n```\n\n## Component Contracts\n\nEach component type has a defined prop interface:\n\n### Input\n\n```typescript\ninterface InputProps {\n  value: string;\n  onChange: (value: string) => void;\n  disabled?: boolean;\n  placeholder?: string;\n  type?: 'text' | 'email' | 'password' | 'tel' | 'url' | 'number';\n  className?: string;\n}\n```\n\n### Select\n\n```typescript\ninterface SelectProps {\n  value: string;\n  onChange: (value: string) => void;\n  options: Array<{ value: string; label: string }>;\n  placeholder?: string;\n  disabled?: boolean;\n  className?: string;\n}\n```\n\n### Checkbox\n\n```typescript\ninterface CheckboxProps {\n  checked: boolean;\n  onChange: (checked: boolean) => void;\n  disabled?: boolean;\n  className?: string;\n}\n```\n\nSee the [types documentation](./src/types/components.ts) for all component contracts.\n\n## Supported Controls\n\n| Control | Schema Match | Component |\n|---------|--------------|-----------|\n| String | `type: \"string\"` | Input |\n| Email | `format: \"email\"` | Input (type=\"email\") |\n| Password | `format: \"password\"` | Input (type=\"password\") |\n| URL | `format: \"uri\"` | Input (type=\"url\") |\n| Phone | `format: \"phone\"` or scope ends with `phone` | Input (type=\"tel\") |\n| Number | `type: \"number\"` or `type: \"integer\"` | Input (type=\"number\") |\n| Boolean | `type: \"boolean\"` | Checkbox |\n| Toggle | `type: \"boolean\"` + `options.format: \"toggle\"` | Toggle |\n| Select | `enum` or `oneOf` | Select |\n| Radio | enum/boolean + `options.format: \"radio\"` | RadioGroup |\n| Combobox | enum + `options.format: \"combobox\"` | Combobox |\n| Date | `format: \"date\"` | DatePicker |\n| DateTime | `format: \"date-time\"` | DateTimePicker |\n| Textarea | string + `options.multi: true` | Textarea |\n| Slider | number + `options.format: \"slider\"` | Slider |\n| Currency | `format: \"currency\"` | Input (with formatting) |\n| File | `format: \"file\"` or `contentMediaType` | FileUpload |\n\n## i18n Support\n\n```tsx\nimport { createI18n } from '@apart-tech/jsonforms-kit';\nimport { useTranslations } from 'next-intl';\n\nfunction useFormI18n(namespace: string) {\n  const t = useTranslations(namespace);\n  const tErrors = useTranslations('formErrors');\n\n  return createI18n({\n    translate: (key, defaultValue) => {\n      const translated = t(key);\n      return translated !== key ? translated : defaultValue;\n    },\n    translateError: (error) => {\n      const translated = tErrors(error.keyword);\n      return translated !== error.keyword ? translated : error.message;\n    },\n    locale: 'en',\n  });\n}\n\n// Usage\nfunction MyForm() {\n  const i18n = useFormI18n('forms.personalInfo');\n\n  return (\n    <JsonForms\n      // ...\n      i18n={i18n}\n    />\n  );\n}\n```\n\n## Custom Testers\n\nOverride default tester ranks or add custom testers:\n\n```tsx\nimport { createRenderers, rankWith, scopeEndsWith } from '@apart-tech/jsonforms-kit';\n\nconst renderers = createRenderers({\n  components: componentMap,\n  testers: {\n    // Override default ranks\n    ranks: {\n      email: 10, // Higher priority for email fields\n      select: 4,\n    },\n    // Add custom testers\n    custom: [\n      {\n        name: 'specialPhone',\n        tester: rankWith(10, scopeEndsWith('mobileNumber')),\n        renderer: 'Input',\n        props: { type: 'tel' },\n      },\n    ],\n  },\n});\n```\n\n## API Reference\n\n### `createRenderers(config)`\n\nCreates JSON Forms renderer registry entries.\n\n### `createI18n(config)`\n\nCreates a JSON Forms i18n configuration object.\n\n### `FormProvider`\n\nReact context provider for component map and class names.\n\n### Hooks\n\n- `useComponents()` - Access the component map\n- `useClassNames()` - Access class name configuration\n- `useFieldWrapper(props)` - Common field wrapper logic\n- `useHasComponent(name)` - Check if a component is available\n\n## License\n\nMIT\n","readmeFilename":"README.md"}