{"_id":"@adexdsamson/forge","_rev":"2-0e060f486b72b90f0197e7a8effe0232","name":"@adexdsamson/forge","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@adexdsamson/forge","version":"1.0.0","keywords":["react","react-native","form","forms","react-hook-form","hooks","cross-platform"],"author":{"url":"https://github.com/adexdsamson","name":"adexdsamson"},"license":"MIT","_id":"@adexdsamson/forge@1.0.0","maintainers":[{"name":"adexdsamson","email":"adexdsamson@gmail.com"}],"homepage":"https://github.com/adexdsamson/Forge#readme","bugs":{"url":"https://github.com/adexdsamson/Forge/issues"},"dist":{"shasum":"7b5e6e8c39920ff92616f2b7f73dca62c9bef07a","tarball":"https://registry.npmjs.org/@adexdsamson/forge/-/forge-1.0.0.tgz","fileCount":8,"integrity":"sha512-ZBIygjN7KVPaQ9tcIX1mPG3+50sNV0TvLvheWe/Huuf9Rp0aRwnEOwI6fva/XWQfyLS1Npm6euqJ0jm3+TgWcA==","signatures":[{"sig":"MEQCIFlx7VSA7QE/DLB4S1Rg2JWU4gmhmqeTAKyjgtk2kGeiAiBrCS9mlOyMmCbCNl9rn/baPbPQVm0WQJn4X31Q2ZUHfA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adexdsamson%2fforge@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":187158},"main":"dist/index.cjs.js","types":"dist/index.d.ts","module":"dist/index.esm.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"gitHead":"c6d4f9061ea11065d338b19cec9fee5a1903659b","scripts":{"lint":"eslint src/ && prettier --check src/","test":"vitest run --coverage","build":"rollup -c","rollup":"rollup -c","prepack":"npm run build","lint:fix":"eslint src/ --fix && prettier --write src/","changelog":"commit-and-tag-version --skip.bump --skip.tag --skip.commit","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"adexdsamson","email":"adexdsamson@gmail.com"},"repository":{"url":"git+https://github.com/adexdsamson/Forge.git","type":"git"},"_npmVersion":"10.8.2","description":"Forge is a custom React library that enhances the functionality of react-hook-form by providing a more streamlined, composable approach to building forms in React (web and React Native).","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^29.1.1","react":"^18.2.0","tslib":"^2.6.2","eslint":"^10.4.1","rollup":"^4.12.0","vitest":"^4.1.7","prettier":"^3.8.3","react-dom":"^18.2.0","@eslint/js":"^10.0.1","typescript":"^5.3.3","@types/react":"^18.2.55","react-dropzone":"^14.2.3","react-hook-form":"^7.50.1","rollup-plugin-dts":"^6.1.0","typescript-eslint":"^8.60.0","@hookform/devtools":"^4.3.1","@vitest/coverage-v8":"^4.1.7","@testing-library/react":"^16.3.2","commit-and-tag-version":"^12.7.3","eslint-config-prettier":"^10.1.8","@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-typescript":"^11.1.6","@testing-library/jest-dom":"^6.9.1","eslint-plugin-react-hooks":"^7.1.1","@rollup/plugin-node-resolve":"^15.2.3","@testing-library/user-event":"^14.6.1"},"peerDependencies":{"react":">=18","react-hook-form":"^7.34.0"},"peerDependenciesMeta":{"react-dropzone":{"optional":true},"@hookform/devtools":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/forge_1.0.0_1780295871673_0.03430528508137165","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@adexdsamson/forge","version":"1.1.0","description":"Forge is a custom React library that enhances the functionality of react-hook-form by providing a more streamlined, composable approach to building forms in React (web and React Native).","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.cjs.js"}},"scripts":{"prepack":"npm run build","build":"rollup -c","rollup":"rollup -c","typecheck":"tsc --noEmit","test":"vitest run --coverage","test:watch":"vitest","lint":"eslint src/ && prettier --check src/","lint:fix":"eslint src/ --fix && prettier --write src/","changelog":"commit-and-tag-version --skip.bump --skip.tag --skip.commit"},"repository":{"type":"git","url":"git+https://github.com/adexdsamson/Forge.git"},"publishConfig":{"registry":"https://registry.npmjs.org","access":"public"},"keywords":["react","react-native","form","forms","react-hook-form","hooks","cross-platform"],"author":{"name":"adexdsamson","url":"https://github.com/adexdsamson"},"license":"MIT","sideEffects":false,"engines":{"node":">=18"},"bugs":{"url":"https://github.com/adexdsamson/Forge/issues"},"homepage":"https://github.com/adexdsamson/Forge#readme","peerDependencies":{"react":">=18","react-hook-form":"^7.34.0"},"peerDependenciesMeta":{"@hookform/devtools":{"optional":true},"react-dropzone":{"optional":true}},"devDependencies":{"@eslint/js":"^10.0.1","@hookform/devtools":"^4.3.1","@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-node-resolve":"^15.2.3","@rollup/plugin-typescript":"^11.1.6","@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.2","@testing-library/user-event":"^14.6.1","@types/react":"^18.2.55","@vitest/coverage-v8":"^4.1.7","commit-and-tag-version":"^12.7.3","eslint":"^10.4.1","eslint-config-prettier":"^10.1.8","eslint-plugin-react-hooks":"^7.1.1","jsdom":"^29.1.1","prettier":"^3.8.3","react":"^18.2.0","react-dom":"^18.2.0","react-dropzone":"^14.2.3","react-hook-form":"^7.50.1","rollup":"^4.12.0","rollup-plugin-dts":"^6.1.0","tslib":"^2.6.2","typescript":"^5.3.3","typescript-eslint":"^8.60.0","vitest":"^4.1.7"},"_id":"@adexdsamson/forge@1.1.0","gitHead":"ef2eae94fd0ed1340972e4722938687ccf96dfb6","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-aqLB87+QaJqloRRfbFlkbm80zRB6GgLiNkSj3SfhoQq9TN4a12U3cW0BTyKoagEtpWCWAeYfNDysJhfybx3PTA==","shasum":"5ff2c8a1955e6500ff6878755649e90f6368d20e","tarball":"https://registry.npmjs.org/@adexdsamson/forge/-/forge-1.1.0.tgz","fileCount":8,"unpackedSize":228336,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adexdsamson%2fforge@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGnipt2SA5Onuhn1AFbJkaZbWQTftUzT2QxdkzA4D2wMAiEAiZlHRYdKK2vIYyqPsWH2Dp4sO22d7hl3emt6U59h/lM="}]},"_npmUser":{"name":"adexdsamson","email":"adexdsamson@gmail.com"},"directories":{},"maintainers":[{"name":"adexdsamson","email":"adexdsamson@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/forge_1.1.0_1780305074608_0.04315317316074263"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T06:37:51.518Z","modified":"2026-06-01T09:11:15.074Z","1.0.0":"2026-06-01T06:37:51.804Z","1.1.0":"2026-06-01T09:11:14.766Z"},"bugs":{"url":"https://github.com/adexdsamson/Forge/issues"},"author":{"name":"adexdsamson","url":"https://github.com/adexdsamson"},"license":"MIT","homepage":"https://github.com/adexdsamson/Forge#readme","keywords":["react","react-native","form","forms","react-hook-form","hooks","cross-platform"],"repository":{"type":"git","url":"git+https://github.com/adexdsamson/Forge.git"},"description":"Forge is a custom React library that enhances the functionality of react-hook-form by providing a more streamlined, composable approach to building forms in React (web and React Native).","maintainers":[{"name":"adexdsamson","email":"adexdsamson@gmail.com"}],"readme":"# Forge\n\nForge is a cross-platform React form library that wraps [react-hook-form](https://react-hook-form.com/) with a streamlined, composable API. Call `useForge(...)` to get the full react-hook-form toolkit plus an augmented `control`, render a `<Forge control={...}>` form container, and drop in `<Forger>` field wrappers around any custom input — web or React Native. Forge auto-detects the platform and wires the right event handlers, so the same component tree works on both.\n\n[![npm version](https://img.shields.io/npm/v/@adexdsamson/forge.svg)](https://www.npmjs.com/package/@adexdsamson/forge)\n[![CI](https://img.shields.io/github/actions/workflow/status/adexdsamson/Forge/ci.yml.svg)](https://github.com/adexdsamson/Forge/actions)\n[![License](https://img.shields.io/npm/l/@adexdsamson/forge.svg)](./LICENSE)\n\n---\n\n## Installation\n\n```bash\nnpm install @adexdsamson/forge\n```\n\nInstall required peer dependencies:\n\n```bash\nnpm install react react-hook-form\n```\n\nOptional peer dependency (for file input `accept` types):\n\n```bash\nnpm install react-dropzone\n```\n\n---\n\n## Quickstart (Web)\n\nA signup form with a text field, a role select, and a terms checkbox:\n\n```tsx\nimport React from 'react';\nimport { useForge, Forge, Forger } from '@adexdsamson/forge';\n\n// --- Custom input components ---\n\ninterface TextInputProps {\n  value?: string;\n  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n  onBlur?: () => void;\n  error?: string;\n  placeholder?: string;\n}\n\nconst TextInput = ({ value, onChange, onBlur, error, placeholder }: TextInputProps) => (\n  <div>\n    <input\n      value={value ?? ''}\n      onChange={onChange}\n      onBlur={onBlur}\n      placeholder={placeholder}\n      style={{ borderColor: error ? 'red' : undefined }}\n    />\n    {error && <span style={{ color: 'red', fontSize: 12 }}>{error}</span>}\n  </div>\n);\n\ninterface SelectProps {\n  value?: string;\n  onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void;\n  onBlur?: () => void;\n  error?: string;\n}\n\nconst RoleSelect = ({ value, onChange, onBlur, error }: SelectProps) => (\n  <div>\n    <select value={value ?? ''} onChange={onChange} onBlur={onBlur}>\n      <option value=\"\">Select a role</option>\n      <option value=\"user\">User</option>\n      <option value=\"admin\">Admin</option>\n      <option value=\"editor\">Editor</option>\n    </select>\n    {error && <span style={{ color: 'red', fontSize: 12 }}>{error}</span>}\n  </div>\n);\n\ninterface CheckboxProps {\n  value?: boolean;\n  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n  onBlur?: () => void;\n  error?: string;\n  label?: string;\n}\n\nconst CheckboxInput = ({ value, onChange, onBlur, error, label }: CheckboxProps) => (\n  <div>\n    <label>\n      <input type=\"checkbox\" checked={!!value} onChange={onChange} onBlur={onBlur} />\n      {label}\n    </label>\n    {error && <span style={{ color: 'red', fontSize: 12 }}>{error}</span>}\n  </div>\n);\n\n// --- Form ---\n\ninterface SignupFormData {\n  name: string;\n  role: string;\n  acceptTerms: boolean;\n}\n\nexport function SignupForm() {\n  const { control } = useForge<SignupFormData>({\n    defaultValues: {\n      name: '',\n      role: '',\n      acceptTerms: false,\n    },\n    mode: 'onBlur',\n  });\n\n  const onSubmit = (data: SignupFormData) => {\n    console.log('Submitted:', data);\n  };\n\n  return (\n    <Forge control={control} onSubmit={onSubmit} noValidate>\n      <Forger\n        name=\"name\"\n        component={TextInput}\n        placeholder=\"Your name\"\n        rules={{ required: 'Name is required', minLength: { value: 2, message: 'At least 2 characters' } }}\n      />\n\n      <Forger\n        name=\"role\"\n        component={RoleSelect}\n        rules={{ required: 'Please select a role' }}\n      />\n\n      <Forger\n        name=\"acceptTerms\"\n        component={CheckboxInput}\n        label=\"I accept the terms and conditions\"\n        rules={{ required: 'You must accept the terms' }}\n      />\n\n      <button type=\"submit\">Sign up</button>\n    </Forge>\n  );\n}\n```\n\n**What happens:**\n\n1. `useForge` calls `useForm` internally and returns the full react-hook-form API plus an augmented `control`.\n2. `<Forge control={control}>` renders a `<form>`, provides `FormProvider` context, and wires the submit handler.\n3. Each `<Forger>` connects one field to RHF state via `useController`, injects `value`, `onChange`, `onBlur`, and `error` into the custom component, and applies the `rules`.\n4. On submit, RHF validates all fields, then calls `onSubmit` with the typed form data.\n\n---\n\n## React Native\n\nThe same API works on React Native. Pass `platform=\"react-native\"` to `<Forge>` (or let it auto-detect). Forge maps `onChange` to `onChangeText` for `TextInput` and `onValueChange` for `Switch`/`Picker`/`Slider` automatically. Mark your submit button with `forgeSubmit` and Forge auto-wires `onPress` — no manual `handleSubmit` call needed.\n\n```tsx\nimport React from 'react';\nimport { View, TextInput, Switch, Text, TouchableOpacity } from 'react-native';\nimport { Picker } from '@react-native-picker/picker';\nimport { useForge, Forge, Forger } from '@adexdsamson/forge';\n\n// --- Custom RN components ---\n\nconst RNTextInput = ({ value, onChangeText, onBlur, error, placeholder }: any) => (\n  <View>\n    <TextInput\n      value={value ?? ''}\n      onChangeText={onChangeText}\n      onBlur={onBlur}\n      placeholder={placeholder}\n      style={{ borderWidth: 1, borderColor: error ? 'red' : '#ccc', padding: 8, borderRadius: 4 }}\n    />\n    {error ? <Text style={{ color: 'red', fontSize: 12 }}>{error}</Text> : null}\n  </View>\n);\n\nconst RolePickerInput = ({ value, onValueChange, error }: any) => (\n  <View style={{ borderWidth: 1, borderColor: error ? 'red' : '#ccc', borderRadius: 4 }}>\n    <Picker selectedValue={value} onValueChange={onValueChange}>\n      <Picker.Item label=\"Select a role\" value=\"\" />\n      <Picker.Item label=\"User\" value=\"user\" />\n      <Picker.Item label=\"Admin\" value=\"admin\" />\n      <Picker.Item label=\"Editor\" value=\"editor\" />\n    </Picker>\n    {error ? <Text style={{ color: 'red', fontSize: 12 }}>{error}</Text> : null}\n  </View>\n);\n\nconst TermsSwitch = ({ value, onValueChange, label }: any) => (\n  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>\n    <Switch value={!!value} onValueChange={onValueChange} />\n    <Text>{label}</Text>\n  </View>\n);\n\n// --- Form ---\n\ninterface SignupFormData {\n  name: string;\n  role: string;\n  acceptTerms: boolean;\n}\n\nexport function SignupFormRN() {\n  const { control } = useForge<SignupFormData>({\n    defaultValues: { name: '', role: '', acceptTerms: false },\n    mode: 'onBlur',\n  });\n\n  const onSubmit = (data: SignupFormData) => {\n    console.log('Submitted:', data);\n  };\n\n  return (\n    <Forge control={control} onSubmit={onSubmit} platform=\"react-native\">\n      <Forger\n        name=\"name\"\n        component={RNTextInput}\n        placeholder=\"Your name\"\n        rules={{ required: 'Name is required' }}\n      />\n\n      <Forger\n        name=\"role\"\n        component={RolePickerInput}\n        rules={{ required: 'Please select a role' }}\n      />\n\n      <Forger\n        name=\"acceptTerms\"\n        component={TermsSwitch}\n        label=\"I accept the terms and conditions\"\n      />\n\n      <TouchableOpacity forgeSubmit>\n        <Text>Sign up</Text>\n      </TouchableOpacity>\n    </Forge>\n  );\n}\n```\n\n> **Cross-platform note:** Forge uses runtime detection (`navigator.product === 'ReactNative'`) to select the right event handler names. You do not need a separate component tree for web vs. React Native — the same `<Forge>` + `<Forger>` pattern works on both platforms.\n\n---\n\n## Key Concepts\n\n- **`useForge`** — Configures the form instance. Wraps `useForm` from react-hook-form and returns the full RHF toolkit plus an augmented `control` handle that carries wizard state and declarative field definitions.\n\n- **`<Forge control={...}>`** — Renders the form container. On web it outputs a `<form>` element; on React Native it outputs a Fragment. Provides `FormProvider` context so all child `<Forger>` fields can subscribe to form state without prop-drilling.\n\n- **`<Forger name=\"...\" component={...}>`** — Connects one field to RHF state via `useController`. Injects `value`, `onChange`/`onChangeText`, `onBlur`, and `error` into your custom component. Applies `rules` validation and optional value `transform` (coerce between stored type and display type).\n\n---\n\n## API Reference\n\nFull prop and return-value tables for every exported symbol:\n\n[docs/API.md](docs/API.md)\n\n---\n\n## Examples\n\nA complete runnable React Native example with multiple field types, validation, and submission handling:\n\n[examples/ReactNativeExample.md](examples/ReactNativeExample.md)\n\n---\n\n## License\n\nMIT © adexdsamson\n","readmeFilename":"ReadMe.md"}