{"id":4433,"url":"https://github.com/typeskill/typer","last_synced_at":"2025-08-04T01:32:28.718Z","repository":{"id":48553497,"uuid":"188840103","full_name":"typeskill/typer","owner":"typeskill","description":"Typeskill, the Operational-Transform Based (React) Native Rich Text Library.","archived":true,"fork":false,"pushed_at":"2021-07-20T18:27:46.000Z","size":9340,"stargazers_count":26,"open_issues_count":20,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-11T06:36:39.265Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/typeskill.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-27T12:33:50.000Z","updated_at":"2024-04-16T03:48:05.000Z","dependencies_parsed_at":"2022-09-26T20:01:19.249Z","dependency_job_id":null,"html_url":"https://github.com/typeskill/typer","commit_stats":null,"previous_names":["typeskill/typeskill"],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeskill%2Ftyper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeskill%2Ftyper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeskill%2Ftyper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeskill%2Ftyper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typeskill","download_url":"https://codeload.github.com/typeskill/typer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228582487,"owners_count":17940587,"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":[],"created_at":"2024-01-05T20:17:11.784Z","updated_at":"2024-12-07T08:30:39.332Z","avatar_url":"https://github.com/typeskill.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003e\n\u003ccode\u003e\n    @typeskill/typer\n\u003c/code\u003e\n\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003cem\u003e\n    Typeskill, the Operational-Transform Based (React) Native Rich Text Library.\n  \u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.npmjs.com/package/@typeskill/typer\" alt=\"Npm Version\"\u003e\n        \u003cimg src=\"https://img.shields.io/npm/v/@typeskill/typer.svg\" /\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/platforms-android%20|%20ios%20|%20windows-lightgrey.svg\" /\u003e\n    \u003cimg src=\"https://img.shields.io/npm/l/@typeskill/typer.svg\"/\u003e\n    \u003ca href=\"https://github.com/typeskill/typer/issues?q=is%3Aissue+is%3Aopen+label%3A%22scheduled+feature%22\" \u003e\n        \u003cimg src=\"https://img.shields.io/github/issues-raw/typeskill/typer/scheduled%20feature.svg?label=scheduled%20feature\u0026colorB=125bba\" alt=\"scheduled features\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://circleci.com/gh/typeskill/typer\"\u003e\n        \u003cimg src=\"https://circleci.com/gh/typeskill/typer.svg?style=shield\" alt=\"Circle CI\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/typeskill/typer\"\u003e\n        \u003cimg src=\"https://codecov.io/gh/typeskill/typer/branch/master/graph/badge.svg\" alt=\"Code coverage\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/typeskill/typer/issues?q=is%3Aissue+is%3Aopen+label%3Abug\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/issues-raw/typeskill/typer/bug.svg?label=open%20bugs\" alt=\"open bugs\"\u003e\n    \u003c/a\u003e\n    \u003cimg alt=\"Greenkeeper badge\" src=\"https://badges.greenkeeper.io/typeskill/typer.svg\"\u003e\n    \u003ca href=\"https://snyk.io/test/github/typeskill/typer\"\u003e\n      \u003cimg alt=\"vulnerabilities\" src=\"https://snyk.io/test/github/typeskill/typer/badge.svg\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ccode\u003e\n      npm install --save @typeskill/typer\n  \u003c/code\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"400\" src=\"https://raw.githubusercontent.com/typeskill/typeskill/HEAD/images/screenshot.png\" alt=\"Typeskill screenshot\"\u003e\n\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://expo.io/@jsamr/typeskill-showcase\"\u003e\n        \u003cstrong\u003eGive it a try on Expo\u003c/strong\u003e\n    \u003c/a\u003e\n    \u003cbr/\u003e\u003cbr/\u003e\n    \u003ca href=\"https://expo.io/@jsamr/typeskill-showcase\"\u003e\n        \u003cimg src=\"https://raw.githubusercontent.com/typeskill/typeskill/HEAD/images/qr-showcase.png\" alt=\"Expo QR code\"\u003e\n    \u003c/a\u003e\n    \u003cbr/\u003e\n    \u003ca href=\"#trying-locally\"\u003eYou can also run it locally in seconds\u003c/a\u003e\n\u003c/p\u003e\n\n## Features \u0026 design principles\n\n### Design\n\n- Extensively **modular** architecture: Typeskill handles the logic, you chose the layout;\n- No bloated/clumsy `WebView` ; this library only relies on (React) **Native** components;\n- Fully [controlled components](https://reactjs.org/docs/forms.html#controlled-components);\n- Based on the reliable [Delta](https://github.com/quilljs/delta) **operational transform** library from [quilljs](https://github.com/quilljs).\n\n### Features\n\n- Support for **arbitrary embedded contents**;\n- Support for **arbitrary controllers** with the `Bridge` class;\n- JSON-**serializable** rich content.\n\n\u003ca name=\"trying-locally\" /\u003e\n\n## Trying locally\n\n*Prerequisite: you must have `npm` and `expo-cli` globally installed*\n\n``` bash\ngit clone https://github.com/typeskill/examples/tree/master\ncd examples/expo-showcase\nnpm install\nexpo start\n```\n\n## Architecture \u0026 example\n\n### Introduction\n\nThe library exposes two components to render documents:\n\n- The `Typer` component is responsible for **editing** a document;\n- The `Print` component is responsible for **displaying** a document.\n\n### Definitions\n\n- A *document* is a JSON-serializable object describing rich content;\n- A *document renderer* is any controlled component which renders a document—i.e. `Typer` or `Print`;\n- The *master component* is referred to as the component containing and controlling the document renderer;\n- A *document control* is any controlled component owned by the master component capable of altering the document—i.e. `Typer` or `Toolbar`;\n- An *external [document] control* is any document control which is not a document renderer—i.e. `Toolbar` or any custom control.\n\n### The shape of a Document\n\nA document is an object describing rich content and the current selection. Its `op` field is an array of operational transforms implemented with [delta library](https://github.com/quilljs/delta). Its `schemaVersion` guarantees retro-compatibility in the future and, if needed, utilities to convert from one version to the other.\n\nTo explore the structure in seconds, the easiest way is with the debugger: [`@typeskill/debugger`](https://github.com/typeskill/debugger).\n\n### Controlled components\n\nDocument renderers and controls are **[controlled components](https://reactjs.org/docs/forms.html#controlled-components)**, which means you need to define how to store the state from a master component, or through a store architecture such as a Redux. [You can study `Editor.tsx`, a minimal example master component.](https://github.com/typeskill/examples/blob/master/expo-minimal/src/Editor.tsx)\n\n### A domain of shared events\n\nDocument renderers need an invariant `Bridge` instance prop.\nThe bridge has two responsibilities:\n\n- To convey actions such as *insert an image at selection* or *change text attributes in selection* from external controls;\n- To notify selection attributes changes to external controls.\n\nA `Bridge` instance must be hold by the master component, and can be shared with any external control such as `Toolbar` to operate on the document.\n\n**Remarks**\n\n- The `Bridge` constructor **is not exposed**. You must consume the `buildBridge` function or `useBridge` hook instead;\n- To grasp how the bridge is interfaced with the `Toolbar` component, you can [read its implementation](src/components/Toolbar.tsx).\n\n### Robustness\n\nThis decoupled design has the following advantages:\n\n- the logic can be tested independently from React components;\n- the library consumer can integrate the library to fit its graphical and architectural design;\n- support for arbitrary content in the future.\n\n### Minimal example\n\nBellow is a simplified snippet [from the minimal expo example](https://github.com/typeskill/examples/tree/master/expo-minimal) to show you how the `Toolbar` can be interfaced with the `Typer` component.\nYou need a linked `react-native-vector-icons` or `@expo/vector-icons` if you are on expo to make this example work.\n\n```jsx\nimport React from 'react';\nimport { View } from 'react-native';\nimport {\n  Typer,\n  Toolbar,\n  DocumentControlAction,\n  buildVectorIconControlSpec,\n  useBridge,\n  useDocument,\n} from '@typeskill/typer';\n/** NON EXPO **/\nimport { MaterialCommunityIcons } from 'react-native-vector-icons/MaterialCommunityIcons';\n/** EXPO **/\n// import { MaterialCommunityIcons } from '@expo/vector-icons'\n\nfunction buildMaterialControlSpec(actionType, name) {\n  return buildVectorIconControlSpec(MaterialCommunityIcons, actionType, name);\n}\n\nconst toolbarLayout = [\n  buildMaterialControlSpec(\n    DocumentControlAction.SELECT_TEXT_BOLD,\n    'format-bold',\n  ),\n  buildMaterialControlSpec(\n    DocumentControlAction.SELECT_TEXT_ITALIC,\n    'format-italic',\n  ),\n  buildMaterialControlSpec(\n    DocumentControlAction.SELECT_TEXT_UNDERLINE,\n    'format-underline',\n  ),\n  buildMaterialControlSpec(\n    DocumentControlAction.SELECT_TEXT_STRIKETHROUGH,\n    'format-strikethrough-variant',\n  ),\n];\n\nexport function Editor() {\n  const [document, setDocument] = useDocument();\n  const bridge = useBridge();\n  return (\n    \u003cView style={{ flex: 1 }}\u003e\n      \u003cTyper\n        document={document}\n        onDocumentUpdate={setDocument}\n        bridge={bridge}\n        maxMediaBlockHeight={300}\n      /\u003e\n      \u003cToolbar document={document} layout={toolbarLayout} bridge={bridge} /\u003e\n    \u003c/View\u003e\n  );\n}\n```\n\n### API Contract\n\nYou need to comply with this contract to avoid bugs:\n\n- The `Bridge` instance should be instantiated by the master component with `buildBridge`, during mount or with `useBridge` hook;\n- There should be exactly one `Bridge` instance for one document renderer.\n\n## API Reference\n\n[**Typescript definitions**](types/typer.d.ts) provide an exhaustive and curated documentation reference. The comments are [100% compliant with tsdoc](https://github.com/microsoft/tsdoc) and generated with Microsoft famous [API Extractor](https://api-extractor.com/) utility. [**These definitions follow semantic versioning.**](https://semver.org/)\n\nPlease note that `props` definitions are namespaced. For example, if you are looking at `Toolbar` component definitions, you should look for `Props` definition inside `Toolbar` namespace.\n\n## Inspecting and reporting bugs\n\n[`@typeskill/debugger`](https://github.com/typeskill/debugger) is a tool to inspect and reproduce bugs. If you witness a bug, please try a reproduction on the debugger prior to reporting it.\n\n## Customizing\n\n### Integrating your image picker\n\nTypeskill won't chose a picker on your behalf, as it would break its commitment to modular design.\nYou can check [`Editor.tsx` component](https://github.com/typeskill/examples/blob/master/expo-showcase/src/Editor.tsx) from [the showcase expo example](https://github.com/typeskill/examples/tree/master/expo-showcase) to see how to integrate your image picker.\n","funding_links":[],"categories":["Components"],"sub_categories":["Text \u0026 Rich Content"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeskill%2Ftyper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypeskill%2Ftyper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeskill%2Ftyper/lists"}