{"id":13339461,"url":"https://github.com/unified-doc/unified-doc-react","last_synced_at":"2025-03-11T14:31:22.112Z","repository":{"id":57386200,"uuid":"266489850","full_name":"unified-doc/unified-doc-react","owner":"unified-doc","description":"react wrapper for unified-doc","archived":false,"fork":false,"pushed_at":"2020-09-25T05:06:22.000Z","size":92,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-17T02:46:20.841Z","etag":null,"topics":["annotate","compile","content","document","export","file","hast","highlight","html","markdown","nlp","parse","react","search","text","unifiedjs","unist"],"latest_commit_sha":null,"homepage":"https://unified-doc.netlify.app/wrappers/#unified-doc-react","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unified-doc.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-24T07:18:17.000Z","updated_at":"2020-12-19T13:50:46.000Z","dependencies_parsed_at":"2022-09-02T01:10:43.862Z","dependency_job_id":null,"html_url":"https://github.com/unified-doc/unified-doc-react","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unified-doc%2Funified-doc-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unified-doc%2Funified-doc-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unified-doc%2Funified-doc-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unified-doc%2Funified-doc-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unified-doc","download_url":"https://codeload.github.com/unified-doc/unified-doc-react/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243051850,"owners_count":20228282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotate","compile","content","document","export","file","hast","highlight","html","markdown","nlp","parse","react","search","text","unifiedjs","unist"],"created_at":"2024-07-29T19:20:03.590Z","updated_at":"2025-03-11T14:31:21.731Z","avatar_url":"https://github.com/unified-doc.png","language":"JavaScript","readme":"# unified-doc-react\n[`react`][react] wrapper for [**unified-doc**][unified-doc].\n\n---\n\n## Install\n```sh\nnpm install unified-doc-react\n```\n\n## Use\n\n### `DocComponent`\nFor quick and simple rendering of a document, use the React component:\n\n```js\nimport React from 'react';\nimport { DocComponent } from 'unified-doc-react';\n\nconst options = {\n  content: '\u003e some **strong** content',\n  filename: 'doc.md',\n  marks: [\n    { id: 'a', start: 0, end: 5 },\n    { id: 'a', start: 10, end: 12 },\n  ],\n};\n\nfunction MyDoc() {\n  return (\n    \u003cDocComponent\n      className=\"my-doc\"\n      options={options}\n    /\u003e\n  );\n}\n```\n\n### `DocProvider` and `useDoc`\nFor building advanced and interactive document applications, wrap your component with a `DocProvider`.  Components under the `DocProvider` have access to the `doc` instance via the `useDoc` hook.\n\n```js\n// App.js\nimport React from 'react';\nimport { DocProvider } from 'unified-doc-react';\n\nimport MyDoc from './MyDoc';\n\nconst options = {\n  content: '\u003e some **strong** content',\n  filename: 'doc.md',\n};\n\nfunction MyApp() {\n  return (\n    \u003cDocProvider options={options}\u003e\n      \u003cMyDoc /\u003e\n    \u003c/DocProvider\u003e\n  );\n}\n\n// MyDoc.js\nimport React, { useState } from 'react';\nimport { saveFile } from 'unified-doc-dom';\nimport { useDoc } from 'unified-doc-react';\n\nfunction MyDoc() {\n  const doc = useDoc();\n  const [query, setQuery] = useState('');\n  const [results, setResults] = useState([]);\n\n  function clearSearch() {\n    setQuery('');\n    setResults([]);\n  }\n\n  function handleSearch(e) {\n    const query = e.target.value;\n    const results = doc.search(query);\n    setQuery(query);\n    setResults(results);\n  }\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{doc.file().name}\u003c/h1\u003e\n      \u003ch2\u003eSearch\u003c/h2\u003e\n      \u003cinput value={query} onChange={handleSearch} /\u003e\n      {results.map((result, i) =\u003e {\n        const [left, matched, right] = result.snippet;\n        return (\n          \u003cdiv key={i}\u003e\n            {left}\n            \u003cstrong\u003e{matched}\u003c/strong\u003e\n            {right}\n          \u003c/div\u003e\n        );\n      })}\n      \u003cbutton onClick={clearSearch}\u003e\n        Clear search\n      \u003c/button\u003e\n      \u003ch2\u003eContents\u003c/h2\u003e\n      \u003cdiv\u003e{doc.compile().result}\u003c/div\u003e\n      \u003cbutton onClick={() =\u003e saveFile(doc.file())}\u003e\n        Download original\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e saveFile(doc.file('.html'))}\u003e\n        Download HTML\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e saveFile(doc.file('.txt'))}\u003e\n        Download text\n      \u003c/button\u003e\n      \u003ch2\u003eText Contents\u003c/h2\u003e\n      \u003cpre\u003e{doc.textContent()}\u003c/pre\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Use with `unified-doc-dom`\n`unified-doc-react` can be used seamlessly with methods in `unified-doc-dom` to build interactive document applications.\n\n```js\nimport React, { useEffect, useRef, useState } from 'react';\nimport { fromFile, highlight, registerMarks, selectText } from 'unified-doc-dom';\nimport { DocComponent } from 'unified-doc-react';\nimport { v4 as uuidv4 } from 'uuid';\n\n// import optional highlight styles\nimport 'unified-doc-dom/css/highlight.css';\n\nfunction MyDoc() {\n  const docRef = useRef();\n  const [fileData, setFileData] = useState();\n  const [marks, setMarks] = useState([]);\n\n  function addMark(newMark) {\n    setMarks(oldMarks =\u003e [...oldMarks, { ...newMark, id: uuidv4() }]);\n  }\n\n  // enable and capture selected text as marks\n  useEffect(() =\u003e {\n    // cleanup function conveniently returned\n    return selectText(docRef.current, { callback: addMark });\n  }, []);\n\n  // register marks with callbacks\n  useEffect(() =\u003e {\n    const callbacks = {\n      onClick: (event, mark) =\u003e console.log('clicked', event, mark),\n      onMouseEnter: (event, mark) =\u003e console.log('mouseenter', event, mark),\n      onMouseOut: (event, mark) =\u003e console.log('mouseout', event, mark),\n    }\n    // cleanup function conveniently returned\n    return registerMarks(docRef.current, marks, callbacks);\n  }, [marks]);\n\n  // highlight applied marks given its ID\n  function highlightLastMark() {\n    highlight(docRef.current, marks[marks.length - 1].id);\n  }\n\n  // read file data from a JS file\n  async function uploadFile(e) {\n    const fileData = await fromFile(e.target.files[0]);\n    setFileData(fileData);\n  }\n\n  let docContent;\n  if (!fileData) {\n    docContent = \u003cinput type=\"file\" onChange={uploadFile}\u003e\u003c/input\u003e;\n  } else {\n    const options = {\n      content: fileData.content,\n      filename: fileData.name,\n      marks,\n    };\n    docContent = \u003cDocComponent options={options} /\u003e;\n  }\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={highlightLastMark}\u003e\n        Highlight last mark\n      \u003c/button\u003e\n      \u003cdiv ref={docRef}\u003e\n        {docContent}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## API\n- [`DocComponent(props)`](#DocComponentprops)\n- [`DocProvider(props)`](#DocProviderprops)\n- [`useDoc()`](#useDoc)\n- [`options`](#options)\n\nThe term `doc` used below refers to a `unified-doc` instance.  Please refer to [**unified-doc**][unified-doc] for detailed documentation of `doc` API methods.\n\n### `DocComponent(props)`\n#### Interface\n```ts\nfunction DocComponent(props: Props): React.ReactElement;\n```\nA simple React component that wraps around a `doc` instance.\n\n#### Related interfaces\n```ts\ninterface Props {\n  /** options for `doc` instance */\n  options: Options;\n  /** optional `className` to attach to rendered `docElement` */\n  className?: string;\n  /** a reference to the rendered `docElement` */\n  ref?: React.Ref\u003cHTMLDivElement\u003e;\n}\n```\n\n### `DocProvider(props)`\n#### Interface\n```ts\nfunction DocProvider(props: ProviderProps): React.ReactElement;\n```\nUse the `DocProvider` to expose the `doc` instance in a React context.  Components under `DocProvider` can access the `doc` instance via the `useDoc` hook.\n\n#### Related interfaces\n```ts\ninterface ProviderProps {\n  /** any React node */\n  children: React.ReactNode;\n  /** options for `doc` instance */\n  options: Options;\n}\n```\n\n### `useDoc()`\n#### Interface\n```ts\nexport function useDoc(): DocInstance;\n```\nAccess the `doc` instance in any components under the `DocProvider`.\n\n### `options`\nProvide `options` to configure `unified-doc`.\n\nPlease refer to [**unified-doc**][unified-doc] for detailed documentation of `options`.\n\n\n## Development\nThis project is:\n- implemented with the `unified-doc` interface.\n- linted with `xo` + `prettier` + `tsc`.\n- developed and built with `microbundle`.\n- tested with `jest`.\n- softly-typed with `typescript` with `checkJs` (only public APIs are typed).\n\n```sh\n# install dependencies\nnpm run bootstrap\n\n# build package with microbundle\nnpm run build\n\n# clean package (rm dist + node_modules)\nnpm run clean\n\n# watch/rebuild package with microbundle\nnpm run dev\n\n# lint package with xo + prettier + tsc\nnpm run lint\n\n# update semantic version with changelog\nnpm run release\n\n# test package with jest in --watch mode (make sure to run the 'dev' script)\nnpm run test\n\n# test package in a single run\nnpm run test:run\n```\n\n\u003c!-- Definitions --\u003e\n[react]: https://github.com/facebook/react\n[unified-doc]: https://github.com/unified-doc/unified-doc\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funified-doc%2Funified-doc-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funified-doc%2Funified-doc-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funified-doc%2Funified-doc-react/lists"}