{"id":15315353,"url":"https://github.com/himself65/blocksuite","last_synced_at":"2025-10-09T01:30:28.880Z","repository":{"id":64171180,"uuid":"573242622","full_name":"himself65/blocksuite","owner":"himself65","description":"💠 BlockSuite provides building blocks for collaborative applications.","archived":false,"fork":true,"pushed_at":"2023-01-23T14:42:23.000Z","size":3307,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-01-26T23:33:00.912Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://block-suite.com","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"toeverything/blocksuite","license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/himself65.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-02T02:12:31.000Z","updated_at":"2025-01-23T02:35:21.000Z","dependencies_parsed_at":"2023-02-13T00:01:20.326Z","dependency_job_id":null,"html_url":"https://github.com/himself65/blocksuite","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/himself65/blocksuite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/himself65%2Fblocksuite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/himself65%2Fblocksuite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/himself65%2Fblocksuite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/himself65%2Fblocksuite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/himself65","download_url":"https://codeload.github.com/himself65/blocksuite/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/himself65%2Fblocksuite/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000725,"owners_count":26082895,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-10-01T08:50:09.512Z","updated_at":"2025-10-09T01:30:27.841Z","avatar_url":"https://github.com/himself65.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BlockSuite\n\n[![Checks Status](https://img.shields.io/github/checks-status/toeverything/blocksuite/master)](https://github.com/toeverything/blocksuite/actions?query=branch%3Amaster)\n[![Issues Closed](https://img.shields.io/github/issues-closed/toeverything/blocksuite?color=6880ff)](https://github.com/toeverything/blocksuite/issues?q=is%3Aissue+is%3Aclosed)\n[![NPM Latest Release](https://img.shields.io/npm/v/@blocksuite/store.svg?maxAge=300\u0026color=6880ff)](./packages/store/package.json)\n[![NPM Nightly Release](https://img.shields.io/npm/v/@blocksuite/editor/nightly?color=6880ff)](https://github.com/toeverything/blocksuite/actions/workflows/nightly-release.yml?query=branch%3Amaster)\n\n💠 BlockSuite is the open-source editor project behind [AFFiNE](https://github.com/toeverything/AFFiNE). It provides an out-of-the-box block-based editor built on top of a framework designed for general-purpose collaborative applications. This monorepo maintains both the editor and the underlying framework.\n\n👉 [Try BlockSuite-based AFFiNE online](https://pathfinder.affine.pro/)\n\n## Introduction\n\nBlockSuite works very differently than traditional rich text frameworks:\n\n- For the data model, BlockSuite does not implement the [event sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) pattern but instead provides a [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)-based block tree based directly on [Yjs](https://github.com/yjs/yjs), supporting zero-cost time travel and real-time collaboration out of the box. Its data persistence layer is also designed to be [local-first](https://martin.kleppmann.com/papers/local-first.pdf).\n- For rich text editing, multiple different nodes in the BlockSuite block tree can be connected to different rich text editing components, thus modeling rich text content as multiple _UI components_ instead of a single _UI container_, eliminating the use of the dangerous monolith [`contenteditale`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable).\n- For the rendering layer, BlockSuite does not assume that content can only be rendered through the DOM. It not only implements a basic document editing UI based on [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components), but also develops a hybrid [canvas-based renderer](./packages/phasor/) for parts of the whiteboard content. Both renderers can coexist on the same page and are updated from the same store.\n\nBlockSuite is not intended to be yet another plugin-based rich text editing framework. Instead, **it encourages building various collaborative applications directly through whatever UI framework you're comfortable with**. To this end, we will try to open-source more foundational modules as reusable packages for this in the BlockSuite project.\n\nAlthough BlockSuite is still in its early stages, you can already use the `@blocksuite/editor` package, the collaborative editor used in AFFiNE Alpha. Note that this editor is also a web component and is completely framework-independent!\n\n## Current Status (`@blocksuite/editor`)\n\n\u003e ⚠️ This project is under heavy development and is in a stage of rapid evolution. Stay tuned!\n\n- Basic text editing\n  - ✅ Paragraph with inline style\n  - ✅ Nested list\n  - ✅ Code block\n  - ✅ Markdown shortcuts\n- Block-level editing\n  - ✅ Inline text format bar\n  - ⚛️ Block-level selection\n  - ⚛️ Block drag handle\n  - ⚛️ Block hub\n  - ⚛️ Inline slash menu\n- Rich-content\n  - ⚛️ Image block\n  - 🚧 Database block\n  - 📌 Third-party embedded block\n- Whiteboard (edgeless mode)\n  - ✅ Zooming and panning\n  - ⚛️ Frame block\n  - ⚛️ Shape element\n  - 🚧 Handwriting element\n  - 📌 Grouping\n- Playground\n  - ✅ Multiplayer collaboration\n  - ✅ Local data persistence\n  - ✅ E2E test suite\n- Developer experience\n  - ✅ Block tree update API\n  - ✅ Zero cost time travel (undo/redo)\n  - ✅ Reusable NPM package\n  - ⚛️ React hooks integration\n  - 📌 Dynamic block registration\n\nIcons above correspond to the following meanings:\n\n- ✅ - **Beta**\n- ⚛️ - **Alpha**\n- 🚧 - **Developing**\n- 📌 - **Planned**\n\n## Resources\n\n- 🎁 Examples\n  - [Nightly Playground](https://blocksuite-toeverything.vercel.app/?init) ([🔗 source](./packages/playground/src/main.ts))\n  - [The `SimpleAffineEditor` Example](https://blocksuite-toeverything.vercel.app/examples/basic/) ([🔗 source](./packages/playground/examples/basic/index.html))\n  - [AFFiNE Alpha Editor](https://pathfinder.affine.pro/) ([🔗 source](https://github.com/toeverything/AFFiNE/tree/master/packages/app))\n  - [Multiple Workspace Example with React](https://blocksuite-react.vercel.app/) ([🔗 source](./packages/react/))\n- 📍 [GitHub Issues](https://github.com/toeverything/blocksuite/issues)\n- 🎙️ [GitHub Discussions](https://github.com/toeverything/blocksuite/discussions)\n- 🏠 [AFFiNE Community](https://community.affine.pro/c/open-development/)\n- 🚀 [Releases](https://github.com/toeverything/blocksuite/releases)\n\n## Getting Started\n\nThe `@blocksuite/editor` package contains the editor built into AFFiNE. Its `nightly` versions are released daily based on the master branch, and they are always tested on CI. This means that the `nightly` versions can already be used in real-world projects like AFFiNE at any time:\n\n```sh\npnpm i @blocksuite/editor@nightly\n```\n\nIf you want to easily reuse most of the rich-text editing features, you can use the `SimpleAffineEditor` web component directly ([code example here](./packages/playground/examples/basic/index.html)):\n\n```ts\nimport { SimpleAffineEditor } from '@blocksuite/editor';\nimport '@blocksuite/editor/src/themes/affine.css';\n\nconst editor = new SimpleAffineEditor();\ndocument.body.appendChild(editor);\n```\n\nOr equivalently, you can also use the declarative style:\n\n```html\n\u003cbody\u003e\n  \u003csimple-affine-editor\u003e\u003c/simple-affine-editor\u003e\n  \u003cscript type=\"module\"\u003e\n    import '@blocksuite/editor';\n    import '@blocksuite/editor/src/themes/affine.css';\n  \u003c/script\u003e\n\u003c/body\u003e\n```\n\n👉 [Try `SimpleAffineEditor` online](https://blocksuite-toeverything.vercel.app/examples/basic/)\n\nHowever, the `SimpleAffineEditor` here is just a [thin wrapper with dozens of lines](https://github.com/toeverything/blocksuite/blob/master/packages/editor/src/components/simple-affine-editor.ts) that doesn't enable the opt-in collaboration and data persistence features. If you are going to support more complicated real-world use cases (e.g., with customized block models and configured data sources), this will involve the use of these three following core packages:\n\n- The `packages/store` package is a data store built for general-purpose state management.\n- The `packages/blocks` package holds the default BlockSuite editable blocks.\n- The `packages/editor` package ships a complete BlockSuite-based editor.\n\n```sh\npnpm i \\\n  @blocksuite/store@nightly \\\n  @blocksuite/blocks@nightly \\\n  @blocksuite/editor@nightly\n```\n\nAnd here is a minimal collaboration-ready editor showing how these underlying BlockSuite packages are composed together:\n\n\u003e 🚧 Here we will work with the concepts of `Workspace`, `Page`, `Block` and `Signal`. These are the primitives for building a block-based collaborative application. We are preparing a comprehensive documentation about their usage!\n\n```ts\nimport '@blocksuite/blocks';\n// A workspace can hold multiple pages, and a page can hold multiple blocks.\nimport { Workspace, Page } from '@blocksuite/store';\nimport { BlockSchema } from '@blocksuite/blocks/models';\nimport { EditorContainer } from '@blocksuite/editor';\n\n/**\n * Manually create the initial page structure.\n * In collaboration mode or on page refresh with local persistence,\n * the page data will be automatically loaded from store providers.\n * In these cases, this function should not be called.\n */\nfunction createInitialPage(workspace: Workspace) {\n  // Events are being emitted using signals.\n  workspace.signals.pageAdded.once(id =\u003e {\n    const page = workspace.getPage(id) as Page;\n\n    // Block types are defined and registered in BlockSchema.\n    const pageBlockId = page.addBlock({ flavour: 'affine:page' });\n    const frameId = page.addBlock({ flavour: 'affine:frame' }, pageBlockId);\n    page.addBlock({ flavour: 'affine:paragraph' }, frameId);\n  });\n\n  // Create a new page. This will trigger the signal above.\n  workspace.createPage('page0');\n}\n\n// Subscribe for page update and create editor on page added.\nfunction initEditorOnPageAdded(workspace: Workspace) {\n  workspace.signals.pageAdded.once(pageId =\u003e {\n    const page = workspace.getPage(pageId) as Page;\n    const editor = new EditorContainer();\n    editor.page = page;\n    document.body.appendChild(editor);\n  });\n}\n\nfunction main() {\n  // Initialize the store.\n  const workspace = new Workspace({}).register(BlockSchema);\n\n  // Start waiting for the first page...\n  initEditorOnPageAdded(workspace);\n\n  // Suppose we are the first one to create the page.\n  createInitialPage(workspace);\n}\n\nmain();\n```\n\nFor React developers, check out the [`@blocksuite/react`](./packages/react/README.md) doc for React components and hooks support.\n\n## Building\n\nSee [BUILDING.md](BUILDING.md) for instructions on how to build BlockSuite from source code.\n\n## License\n\n[MPL 2.0](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhimself65%2Fblocksuite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhimself65%2Fblocksuite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhimself65%2Fblocksuite/lists"}