{"_id":"@alsocoder/apna-editor","_rev":"3-8170fca46093fc1463f6dca2c6fe008d","name":"@alsocoder/apna-editor","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@alsocoder/apna-editor","version":"0.1.0","keywords":["react","react-component","rich-text-editor","wysiwyg","tiptap","editor","html-editor","content-editor","form","ui-component","css-variables","typescript","apna-editor","alsocoder"],"author":{"url":"https://alsocoder.com","name":"Also Coder"},"license":"MIT","_id":"@alsocoder/apna-editor@0.1.0","maintainers":[{"name":"alsocoder-org","email":"alsocoder@gmail.com"}],"homepage":"https://github.com/alsocoders/apna-editor#readme","bugs":{"url":"https://github.com/alsocoders/apna-editor/issues"},"dist":{"shasum":"19d182df332e764c43c0ed0b681b8c86a83e9340","tarball":"https://registry.npmjs.org/@alsocoder/apna-editor/-/apna-editor-0.1.0.tgz","fileCount":10,"integrity":"sha512-YArSX5brN7kqbVtUeG7BAIqx9WaZA0t/7OVlQMi+z0IlfPVZJHnoQcRi0vRrdCHFJxlbkRDSEjJF8k/D+osBBA==","signatures":[{"sig":"MEQCIFTVwCMNWmbJ1T02ukdLtOMpB4NAYabSfap6NwypBUnYAiA1EVEq41dlPloF4ym7oYey6q++Yc2HUwVlsFZEbYfXXg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":459047},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles.css":"./dist/styles.css","./content.css":"./dist/content.css"},"scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"alsocoder-org","email":"alsocoder@gmail.com"},"repository":{"url":"git+https://github.com/alsocoders/apna-editor.git","type":"git"},"_npmVersion":"12.0.1","description":"A rich text editor React component with toolbar, fullscreen, HTML mode, tables, and optional image upload API.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.16.0","browserslist":["Chrome >= 90","Firefox >= 90","Safari >= 14","Edge >= 90","iOS >= 14","Samsung >= 15","not dead"],"dependencies":{"clsx":"^2.1.1","@tiptap/react":"^3.29.0","@tiptap/starter-kit":"^3.29.0","@radix-ui/react-dialog":"^1.1.14","@tiptap/extension-link":"^3.29.0","@tiptap/extension-color":"^3.29.0","@tiptap/extension-image":"^3.29.0","@tiptap/extension-table":"^3.29.0","@tiptap/extension-highlight":"^3.29.0","@tiptap/extension-subscript":"^3.29.0","@tiptap/extension-table-row":"^3.29.0","@tiptap/extension-underline":"^3.29.0","@tiptap/extension-table-cell":"^3.29.0","@tiptap/extension-text-align":"^3.29.0","@tiptap/extension-text-style":"^3.29.0","@radix-ui/react-dropdown-menu":"^2.1.15","@tiptap/extension-placeholder":"^3.29.0","@tiptap/extension-superscript":"^3.29.0","@tiptap/extension-table-header":"^3.29.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","react":"^19.1.0","react-dom":"^19.1.0","typescript":"^5.9.2","@types/react":"^19.1.8","@types/react-dom":"^19.1.6"},"peerDependencies":{"react":">=18","react-dom":">=18"},"_npmOperationalInternal":{"tmp":"tmp/apna-editor_0.1.0_1785503026685_0.20618989190615888","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@alsocoder/apna-editor","version":"0.1.1","keywords":["react","react-component","rich-text-editor","wysiwyg","tiptap","editor","html-editor","content-editor","form","ui-component","css-variables","typescript","apna-editor","alsocoder"],"author":{"url":"https://alsocoder.com","name":"Also Coder"},"license":"MIT","_id":"@alsocoder/apna-editor@0.1.1","maintainers":[{"name":"alsocoder-org","email":"alsocoder@gmail.com"}],"homepage":"https://github.com/alsocoders/apna-editor#readme","bugs":{"url":"https://github.com/alsocoders/apna-editor/issues"},"dist":{"shasum":"8cbd523ffb9f77d223830737773aa6efc58151df","tarball":"https://registry.npmjs.org/@alsocoder/apna-editor/-/apna-editor-0.1.1.tgz","fileCount":13,"integrity":"sha512-XhXNoBEc4O4Guss+2ME4Vi3xdoNUnwfnVnSqLU3lqeEZHEd6CQVmOizTYCT4oIWkKHb9U4Fd/y0nNvevp9oPsg==","signatures":[{"sig":"MEUCIQDe8lqDGqaCuTPm6OO/zBPrP15LZfatp2GTp+QR9l4QBgIgETFhWEsfiDSVJZSCIQLklZPMhdSUv0AMX9NDSpHCBdQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":474926},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./dark.css":"./dist/dark.css","./styles.css":"./dist/styles.css","./content.css":"./dist/content.css"},"scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"alsocoder-org","email":"alsocoder@gmail.com"},"repository":{"url":"git+https://github.com/alsocoders/apna-editor.git","type":"git"},"_npmVersion":"12.0.1","description":"A rich text editor React component with toolbar, fullscreen, HTML mode, tables, and optional image upload API.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.16.0","browserslist":["Chrome >= 90","Firefox >= 90","Safari >= 14","Edge >= 90","iOS >= 14","Samsung >= 15","not dead"],"dependencies":{"clsx":"^2.1.1","@tiptap/react":"^3.29.0","@tiptap/starter-kit":"^3.29.0","@radix-ui/react-dialog":"^1.1.14","@tiptap/extension-link":"^3.29.0","@tiptap/extension-color":"^3.29.0","@tiptap/extension-image":"^3.29.0","@tiptap/extension-table":"^3.29.0","@tiptap/extension-highlight":"^3.29.0","@tiptap/extension-subscript":"^3.29.0","@tiptap/extension-table-row":"^3.29.0","@tiptap/extension-underline":"^3.29.0","@tiptap/extension-table-cell":"^3.29.0","@tiptap/extension-text-align":"^3.29.0","@tiptap/extension-text-style":"^3.29.0","@radix-ui/react-dropdown-menu":"^2.1.15","@tiptap/extension-placeholder":"^3.29.0","@tiptap/extension-superscript":"^3.29.0","@tiptap/extension-table-header":"^3.29.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","react":"^19.1.0","react-dom":"^19.1.0","typescript":"^5.9.2","@types/react":"^19.1.8","@types/react-dom":"^19.1.6"},"peerDependencies":{"react":">=18","react-dom":">=18"},"_npmOperationalInternal":{"tmp":"tmp/apna-editor_0.1.1_1785504310357_0.9540124534007619","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@alsocoder/apna-editor","version":"0.1.2","description":"A rich text editor React component with toolbar, fullscreen, HTML mode, tables, and optional image upload API.","license":"MIT","author":{"name":"Also Coder","url":"https://alsocoder.com"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles.css":"./dist/styles.css","./content.css":"./dist/content.css","./dark.css":"./dist/dark.css"},"sideEffects":["*.css"],"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"keywords":["react","react-component","rich-text-editor","wysiwyg","tiptap","editor","html-editor","content-editor","form","ui-component","css-variables","typescript","apna-editor","alsocoder"],"browserslist":["Chrome >= 90","Firefox >= 90","Safari >= 14","Edge >= 90","iOS >= 14","Samsung >= 15","not dead"],"repository":{"type":"git","url":"git+https://github.com/alsocoders/apna-editor.git"},"bugs":{"url":"https://github.com/alsocoders/apna-editor/issues"},"homepage":"https://github.com/alsocoders/apna-editor#readme","peerDependencies":{"react":">=18","react-dom":">=18"},"dependencies":{"@radix-ui/react-dialog":"^1.1.14","@radix-ui/react-dropdown-menu":"^2.1.15","@tiptap/extension-color":"^3.29.0","@tiptap/extension-highlight":"^3.29.0","@tiptap/extension-image":"^3.29.0","@tiptap/extension-link":"^3.29.0","@tiptap/extension-placeholder":"^3.29.0","@tiptap/extension-subscript":"^3.29.0","@tiptap/extension-superscript":"^3.29.0","@tiptap/extension-table":"^3.29.0","@tiptap/extension-table-cell":"^3.29.0","@tiptap/extension-table-header":"^3.29.0","@tiptap/extension-table-row":"^3.29.0","@tiptap/extension-text-align":"^3.29.0","@tiptap/extension-text-style":"^3.29.0","@tiptap/extension-underline":"^3.29.0","@tiptap/react":"^3.29.0","@tiptap/starter-kit":"^3.29.0","clsx":"^2.1.1"},"devDependencies":{"@types/react":"^19.1.8","@types/react-dom":"^19.1.6","react":"^19.1.0","react-dom":"^19.1.0","tsup":"^8.5.0","typescript":"^5.9.2"},"gitHead":"42ecf4fd4bd20d88bb199d31c514d067085b09b1","_id":"@alsocoder/apna-editor@0.1.2","_nodeVersion":"24.16.0","_npmVersion":"12.0.1","dist":{"integrity":"sha512-dZMOcD7ZCirqN/ST/zl5uuqS61xGO4P3WeMx5aOHcA3l1FS4GcJ9QArrPzJ1/7axBnwkVeYCkrXD9aSLPxaduA==","shasum":"6e446968f62a42dada8b5a7cbd7f348faad1cb7c","tarball":"https://registry.npmjs.org/@alsocoder/apna-editor/-/apna-editor-0.1.2.tgz","fileCount":13,"unpackedSize":477128,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIC3gh1YkH9wdT4BENjXDX80l00Mr+GdSBjNouchuIeGrAiEA7+dq8FR0ojSQfbdbrKTyCWjLUrxSlWVFHxjL18yTKKc="}]},"_npmUser":{"name":"alsocoder-org","email":"alsocoder@gmail.com"},"directories":{},"maintainers":[{"name":"alsocoder-org","email":"alsocoder@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/apna-editor_0.1.2_1785797599944_0.1514020974292729"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-31T13:03:46.564Z","modified":"2026-08-03T22:53:20.274Z","0.1.0":"2026-07-31T13:03:46.855Z","0.1.1":"2026-07-31T13:25:10.502Z","0.1.2":"2026-08-03T22:53:20.127Z"},"bugs":{"url":"https://github.com/alsocoders/apna-editor/issues"},"author":{"name":"Also Coder","url":"https://alsocoder.com"},"license":"MIT","homepage":"https://github.com/alsocoders/apna-editor#readme","keywords":["react","react-component","rich-text-editor","wysiwyg","tiptap","editor","html-editor","content-editor","form","ui-component","css-variables","typescript","apna-editor","alsocoder"],"repository":{"type":"git","url":"git+https://github.com/alsocoders/apna-editor.git"},"description":"A rich text editor React component with toolbar, fullscreen, HTML mode, tables, and optional image upload API.","maintainers":[{"name":"alsocoder-org","email":"alsocoder@gmail.com"}],"readme":"# @alsocoder/apna-editor\r\n\r\nA rich text editor React component built on TipTap with toolbar, fullscreen, HTML mode, tables, and optional image upload API.\r\n\r\n## Features\r\n\r\n- Rich formatting: headings, bold, italic, underline, lists, alignment, links, tables\r\n- Fullscreen editing mode\r\n- Optional Visual / HTML source mode\r\n- Image button only when `imageUpload` API is provided\r\n- Custom media picker (`pick`) or direct file upload (`upload`)\r\n- Form-friendly: `readOnly`, `error`, `onBlur`, `name` for native forms\r\n- Fully customizable via `className`, `classNames`, and CSS variables\r\n- Optional dark theme preset (`dark.css`)\r\n- Content CSS for rendering saved HTML outside the editor\r\n- Fullscreen helpers for dialog/sheet integration\r\n- No Tailwind required — plain CSS only\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @alsocoder/apna-editor\r\n```\r\n\r\nPeer dependencies:\r\n\r\n```bash\r\nnpm install react react-dom\r\n```\r\n\r\n## Setup\r\n\r\nImport the stylesheet once in your app entry:\r\n\r\n```tsx\r\nimport { ApnaEditor } from \"@alsocoder/apna-editor\"\r\nimport \"@alsocoder/apna-editor/styles.css\"\r\n```\r\n\r\nOptional dark theme:\r\n\r\n```tsx\r\nimport \"@alsocoder/apna-editor/dark.css\"\r\n\r\n<div className=\"apna-editor-dark\">\r\n  <ApnaEditor ... />\r\n</div>\r\n```\r\n\r\n## Basic Usage\r\n\r\n```tsx\r\nimport { useState } from \"react\"\r\nimport { ApnaEditor } from \"@alsocoder/apna-editor\"\r\nimport \"@alsocoder/apna-editor/styles.css\"\r\n\r\nexport function ContentForm() {\r\n  const [content, setContent] = useState(\"\")\r\n\r\n  return (\r\n    <ApnaEditor\r\n      label=\"Description\"\r\n      value={content}\r\n      onChange={setContent}\r\n      placeholder=\"Write something…\"\r\n    />\r\n  )\r\n}\r\n```\r\n\r\n## Props\r\n\r\n| Prop | Type | Default | Description |\r\n|------|------|---------|-------------|\r\n| `label` | `string` | `\"Content\"` | Label above editor (used as fullscreen header title) |\r\n| `value` | `string` | `\"\"` | Controlled HTML value |\r\n| `onChange` | `(html: string) => void` | — | Called when content changes |\r\n| `className` | `string` | — | Class on field wrapper |\r\n| `classNames` | `ApnaEditorClassNames` | — | Per-part class overrides (see below) |\r\n| `placeholder` | `string` | `\"Start writing…\"` | Empty state placeholder in visual mode |\r\n| `minHeight` | `string` | `\"280px\"` | Minimum editor body height |\r\n| `maxHeight` | `string` | `\"480px\"` | Maximum editor body height |\r\n| `disabled` | `boolean` | `false` | Disable all interactions |\r\n| `readOnly` | `boolean` | `false` | View-only — content visible, editing disabled |\r\n| `error` | `string \\| Error \\| null` | — | Validation error state |\r\n| `errorText` | `string` | — | Custom error message (overrides `error`) |\r\n| `onBlur` | `() => void` | — | Blur handler for editor / HTML textarea |\r\n| `id` | `string` | — | HTML id (linked to `label`) |\r\n| `name` | `string` | — | Hidden input name for native form submit |\r\n| `enableHtmlMode` | `boolean` | `false` | Show Visual / HTML toggle |\r\n| `imageUpload` | `ApnaEditorImageUpload` | — | Image API — button hidden without this |\r\n| `onNotify` | `(message) => void` | — | Toast handler for clipboard actions |\r\n\r\n### `classNames` keys\r\n\r\n| Key | Default class |\r\n|-----|---------------|\r\n| `field` | `apna-editor-field` |\r\n| `label` | `apna-editor-label` |\r\n| `editor` | `apna-editor` |\r\n| `editorFullscreen` | `apna-editor-fullscreen` |\r\n| `body` | `apna-editor-body` |\r\n| `scroll` | `apna-editor-scroll` |\r\n| `content` | `apna-editor-content` (ProseMirror editable area) |\r\n| `htmlTextarea` | `apna-editor-html` |\r\n| `footer` | `apna-editor-footer` |\r\n| `error` | `apna-editor-field-error` |\r\n\r\n## Image Upload API\r\n\r\nImage button **only appears** when `imageUpload.pick` or `imageUpload.upload` is provided.\r\n\r\n### Custom media library picker\r\n\r\n```tsx\r\n<ApnaEditor\r\n  value={content}\r\n  onChange={setContent}\r\n  imageUpload={{\r\n    pick: () => openMediaLibrary({ folder: \"blog\" }),\r\n  }}\r\n/>\r\n```\r\n\r\n### Direct file upload\r\n\r\n```tsx\r\n<ApnaEditor\r\n  value={content}\r\n  onChange={setContent}\r\n  imageUpload={{\r\n    upload: async (file) => {\r\n      const formData = new FormData()\r\n      formData.append(\"file\", file)\r\n      const res = await fetch(\"/api/media/upload\", { method: \"POST\", body: formData })\r\n      const data = await res.json()\r\n      return { url: data.url, alt: file.name }\r\n    },\r\n    accept: \"image/*\",\r\n  }}\r\n/>\r\n```\r\n\r\n## HTML Mode\r\n\r\n```tsx\r\n<ApnaEditor\r\n  value={content}\r\n  onChange={setContent}\r\n  enableHtmlMode\r\n/>\r\n```\r\n\r\n## Form Integration\r\n\r\n```tsx\r\n<form onSubmit={handleSubmit}>\r\n  <ApnaEditor\r\n    name=\"description\"\r\n    id=\"description\"\r\n    label=\"Description\"\r\n    value={content}\r\n    onChange={setContent}\r\n    onBlur={() => validate(\"description\")}\r\n    error={errors.description}\r\n    readOnly={isSubmitted}\r\n  />\r\n</form>\r\n```\r\n\r\n## react-hook-form Example\r\n\r\n```tsx\r\nimport { Controller, useForm } from \"react-hook-form\"\r\nimport { ApnaEditor } from \"@alsocoder/apna-editor\"\r\n\r\nfunction MyForm() {\r\n  const { control, handleSubmit } = useForm()\r\n\r\n  return (\r\n    <form onSubmit={handleSubmit(console.log)}>\r\n      <Controller\r\n        name=\"content\"\r\n        control={control}\r\n        render={({ field, fieldState }) => (\r\n          <ApnaEditor\r\n            label=\"Content\"\r\n            value={field.value}\r\n            onChange={field.onChange}\r\n            onBlur={field.onBlur}\r\n            error={fieldState.error}\r\n            errorText={fieldState.error?.message}\r\n          />\r\n        )}\r\n      />\r\n      <button type=\"submit\">Save</button>\r\n    </form>\r\n  )\r\n}\r\n```\r\n\r\n## Notifications\r\n\r\n```tsx\r\n<ApnaEditor\r\n  value={content}\r\n  onChange={setContent}\r\n  onNotify={({ type, title }) => toast[type](title)}\r\n/>\r\n```\r\n\r\n## Fullscreen in Dialogs\r\n\r\n```tsx\r\nimport { preventDismissWhenApnaEditorFullscreen } from \"@alsocoder/apna-editor\"\r\n\r\n<DialogContent onInteractOutside={preventDismissWhenApnaEditorFullscreen}>\r\n```\r\n\r\n## Theming with CSS Variables\r\n\r\n```css\r\n:root {\r\n  --apna-editor-primary: #2563eb;\r\n  --apna-editor-border: #e5e7eb;\r\n  --apna-editor-radius: 0.5rem;\r\n}\r\n```\r\n\r\n### Dark mode preset\r\n\r\n```tsx\r\nimport \"@alsocoder/apna-editor/dark.css\"\r\n\r\n<div className=\"apna-editor-dark\">\r\n  <ApnaEditor ... />\r\n</div>\r\n```\r\n\r\nOr set `data-apna-editor-theme=\"dark\"` on a parent element.\r\n\r\n## Content Styles (tables, quotes, code, etc.)\r\n\r\nEditor content styles are injected automatically inside `ApnaEditor`. To render saved HTML **outside** the editor:\r\n\r\n```tsx\r\nimport \"@alsocoder/apna-editor/content.css\"\r\nimport { APNA_EDITOR_CONTENT_PREVIEW_CLASS } from \"@alsocoder/apna-editor\"\r\n\r\n<div\r\n  className={APNA_EDITOR_CONTENT_PREVIEW_CLASS}\r\n  dangerouslySetInnerHTML={{ __html: content }}\r\n/>\r\n```\r\n\r\n### Content element classes\r\n\r\n| Class | Element |\r\n|-------|---------|\r\n| `apna-editor-table` | Table |\r\n| `apna-editor-table-header` | Table header cell |\r\n| `apna-editor-table-cell` | Table body cell |\r\n| `apna-editor-blockquote` | Blockquote |\r\n| `apna-editor-code-block` | Code block |\r\n| `apna-editor-hr` | Horizontal rule |\r\n| `apna-editor-image` | Image |\r\n| `apna-editor-link` | Link |\r\n\r\n## Exports\r\n\r\n```tsx\r\nimport {\r\n  ApnaEditor,\r\n  createApnaEditorExtensions,\r\n  formatHtml,\r\n  APNA_EDITOR_CONTENT_CSS,\r\n  APNA_EDITOR_CONTENT_PREVIEW_CLASS,\r\n  defaultClassNames,\r\n  mergeClassNames,\r\n  preventDismissWhenApnaEditorFullscreen,\r\n} from \"@alsocoder/apna-editor\"\r\n```\r\n\r\n## Publishing (maintainers)\r\n\r\n```bash\r\nnpm run typecheck\r\nnpm run build\r\nnpm publish --access public\r\n```\r\n\r\n## License\r\n\r\nMIT © [Also Coder](https://alsocoder.com)\r\n","readmeFilename":"README.md"}