{"id":22134147,"url":"https://github.com/lukeramsden/react-native-draftjs-display","last_synced_at":"2025-07-25T20:31:57.276Z","repository":{"id":40766659,"uuid":"267551541","full_name":"lukeramsden/react-native-draftjs-display","owner":"lukeramsden","description":"React Native component to render Draft.js ContentState.","archived":false,"fork":false,"pushed_at":"2023-01-06T07:16:37.000Z","size":996,"stargazers_count":4,"open_issues_count":14,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-03-05T22:59:01.832Z","etag":null,"topics":["draft-js","react-native"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukeramsden.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-28T09:44:26.000Z","updated_at":"2023-03-05T22:59:01.832Z","dependencies_parsed_at":"2023-02-05T15:00:25.280Z","dependency_job_id":null,"html_url":"https://github.com/lukeramsden/react-native-draftjs-display","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeramsden%2Freact-native-draftjs-display","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeramsden%2Freact-native-draftjs-display/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeramsden%2Freact-native-draftjs-display/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeramsden%2Freact-native-draftjs-display/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukeramsden","download_url":"https://codeload.github.com/lukeramsden/react-native-draftjs-display/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227614682,"owners_count":17793949,"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":["draft-js","react-native"],"created_at":"2024-12-01T19:09:54.671Z","updated_at":"2024-12-01T19:09:55.400Z","avatar_url":"https://github.com/lukeramsden.png","language":"TypeScript","readme":"# react-native-draftjs-display\n\n![CI](https://github.com/lukeramsden/react-native-draftjs-display/workflows/CI/badge.svg) [![CodeFactor](https://www.codefactor.io/repository/github/lukeramsden/react-native-draftjs-display/badge)](https://www.codefactor.io/repository/github/lukeramsden/react-native-draftjs-display)\n\nBarebones React Native component to display Draft.js content.\n\nPartly forked from [jdponomarev/react-native-draftjs-render](https://github.com/jdponomarev/react-native-draftjs-render), with the original code coming from [globocom/react-native-draftjs-render](https://github.com/globocom/react-native-draftjs-render). Re-written to use TypeScript, and to better fit in with my use-case.\n\nThis library is intentionally very minimal to allow you to use your own components (or a component kit like material design) and styling easily, and as such has very few defaults in that regard.\n\n## Usage\n\n```tsx\n// Use DraftText but with our own text component, or one from a UI kit.\nconst TextBlockHandler = useCallback(\n  (category: string) =\u003e ({block}: {block: DraftContentBlock}) =\u003e (\n    \u003cDraftText\n      block={block}\n      TextComponent={(props) =\u003e \u003cMyCustomText {...props} category={category} /\u003e}\n    /\u003e\n  ),\n  [],\n);\n// ...\n\u003c\u003e\n  {data.getPost?.content \u0026\u0026 (\n    \u003cDraftDisplay\n      contentState={JSON.parse(data.getPost.content)}\n      blockHandlers={{\n        // This is where the magic happens. Use this to render your content block types.\n        atomic: ({block}) =\u003e \u003cPostMediaBlock block={block} /\u003e,\n        'header-one': TextBlockHandler('h1'),\n        'header-two': TextBlockHandler('h2'),\n        'header-three': TextBlockHandler('h3'),\n        'header-four': TextBlockHandler('h4'),\n        'header-five': TextBlockHandler('h5'),\n        'header-six': TextBlockHandler('h6'),\n        paragraph: TextBlockHandler('p1'),\n        unstyled: TextBlockHandler('p1'),\n        // see below, \"List Handlers\"\n        'ordered-list-item': OrderedListBlockHandler(),\n        'unordered-list-item': UnorderedListBlockHandler(),\n      }}\n    /\u003e\n  )}\n\u003c/\u003e;\n```\n\n### List Handlers\n\nThis library, as of writing, has no list handling functionality or helpers. That may change, but for now, here's my provisional implementation of rendering nested lists:\n\nIn these examples, `tw('...')` is from [tailwind-rn](github.com/vadimdemedes/tailwind-rn), and `\u003cListItem\u003e`, `\u003cIcon\u003e`, and `\u003cText\u003e` are from [react-native-ui-kitten](github.com/akveo/react-native-ui-kitten). Use this as an example for your own apps.\n\n##### Unordered list\n\nThese are easy, as you just render an indent and a prefix icon based on the `block.depth` property.\n\n```tsx\nconst UnorderedListBlockHandler = useCallback(\n  () =\u003e ({block}: {block: DraftContentBlock}) =\u003e (\n    \u003cListItem\n      // ...other properties and styles\n      style={[\n        // render indent based on `block.depth`\n        block.depth === 0\n          ? tw('ml-0')\n          : block.depth === 1\n          ? tw('ml-4')\n          : block.depth === 2\n          ? tw('ml-8')\n          : block.depth === 3\n          ? tw('ml-12')\n          : block.depth === 4\n          ? tw('ml-16')\n          : tw('ml-0'),\n      ]}\n      accessoryLeft={() =\u003e (\n        \u003cIcon\n          // ...again, other proprties and styles\n          name={\n            // render different icons based on indentation. not strictly necessary, but very pretty!\n            block.depth === 0\n              ? 'minus-circle'\n              : block.depth === 1\n              ? 'minus-circle-outline'\n              : block.depth === 2\n              ? 'minus-square'\n              : block.depth === 3\n              ? 'minus-square-outline'\n              : block.depth === 4\n              ? 'square'\n              : 'minus-circle'\n          }\n        /\u003e\n      )}\n      title={() =\u003e (\n        \u003cDraftText\n          block={block}\n          TextComponent={(props) =\u003e \u003cText {...props} category=\"p1\" /\u003e}\n        /\u003e\n      )}\n    /\u003e\n  ),\n  [],\n);\n```\n\n##### Ordered list\n\nNow these are a little more involved, as you need to have your own counter, which counts each depth separately, and then resets between separate lists. Here's my implementation:\n\n```tsx\nconst OrderedListBlockHandler = useCallback(() =\u003e {\n  // an array of numbers, with the index being the depth, and the number being the counter\n  let listCountersAtDepth: number[] = [];\n\n  return ({\n    block,\n    prevBlock,\n  }: {\n    block: DraftContentBlock;\n    prevBlock?: DraftContentBlock; // introduced in v1.3.0\n  }) =\u003e {\n    // reset list counter completely if previous block is not a list item\n    if (prevBlock \u0026\u0026 prevBlock.type !== 'ordered-list-item') {\n      listCountersAtDepth = [];\n    }\n\n    // initialise counter at this block's depth\n    if (!listCountersAtDepth[block.depth]) {\n      listCountersAtDepth[block.depth] = 0;\n    }\n\n    // increase counter\n    listCountersAtDepth[block.depth]++;\n\n    return (\n      \u003cView\n        style={[\n          tw('flex flex-row py-1'),\n          // same indentation as unordered lists, pretty simple\n          block.depth === 0\n            ? tw('ml-0')\n            : block.depth === 1\n            ? tw('ml-4')\n            : block.depth === 2\n            ? tw('ml-8')\n            : block.depth === 3\n            ? tw('ml-12')\n            : block.depth === 4\n            ? tw('ml-16')\n            : tw('ml-0'),\n        ]}\u003e\n        \u003cText category=\"p1\" style={[tw('pl-0 ml-0 mr-2')]}\u003e\n          {/*\n            you could just do `listCountersAtDepth[block.depth]` and call it a day,\n            but this renders each indentation a different way, to differentiate them\n\n            numberToBase26 does exactly as it sounds, takes a number and turns it in to the alphabet\n            with 1 being a, 26 being z, and 27 being aa etc.\n\n            arabicToRoman also does exactly what you'd expect\n\n            the implementation of these is left to the reader (hint: StackOverflow!)\n\n            The `block.depth % 3` is so that it loops, as technically you could have any maximum block.depth,\n            but we only have 3 options to display the counter\n          */}\n          {block.depth % 3 === 0\n            ? listCountersAtDepth[block.depth]\n            : block.depth % 3 === 1\n            ? numberToBase26(listCountersAtDepth[block.depth]).toLowerCase()\n            : block.depth % 3 === 2\n            ? arabicToRoman(listCountersAtDepth[block.depth]).toLowerCase()\n            : listCountersAtDepth[block.depth]}.\n        \u003c/Text\u003e\n        \u003cDraftText\n          block={block}\n          TextComponent={(props) =\u003e \u003cText {...props} category=\"p1\" /\u003e}\n        /\u003e\n      \u003c/View\u003e\n    );\n  };\n}, []);\n```\n\n## Development\n\nClone this repository and install its dependencies:\n\n```bash\ngit clone https://github.com/lukeramsden/react-native-draftjs-display\ncd react-native-draftjs-display\nyarn # or npm install, if you're so inclined\n```\n\n`yarn run build` builds the library to `dist`.\n\n`yarn test` builds the library, then tests it.\n\n## License\n\n[ISC](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukeramsden%2Freact-native-draftjs-display","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukeramsden%2Freact-native-draftjs-display","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukeramsden%2Freact-native-draftjs-display/lists"}