ProtonMail / ProtonMail/WebClients

odf-kit — JavaScript/TypeScript library for ODT export from Lexical editor state

Open
#488 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
5.6k
Forks
715
PR merge metrics
No merged PRs in 30d

Description

Please complete the following checklist (by adding [x]):

  • [X ] I have searched open and closed issues for duplicates
  • This isn't a feature request
  • [X ] This is not a report about my app not working as expected

Context: The Proton community has been requesting ODT support across several UserVoice threads (1, 2, 3). A Proton team member noted in one thread that "there are no libraries whatsoever for ODT processing for browsers." This is no longer accurate.
odf-kit is a pure TypeScript library (Apache 2.0, ESM, zero dependencies beyond fflate) that generates, reads, and converts ODT files entirely client-side — no LibreOffice, no server required. It passes the OASIS ODF validator on every release.
As of v0.12.0 it includes lexicalToOdt() — a function that converts a Lexical SerializedEditorState directly to a valid .odt file. It handles the node types registered in AllNodes.ts: paragraphs, headings, blockquotes, code blocks, lists (including CustomListNode), tables, links, images, horizontal rules, and inline formatting.
The integration point in this codebase is well-defined:
New file: applications/docs-editor/src/app/Conversion/Exporter/EditorOdtExporter.ts
typescriptimport { lexicalToOdt } from 'odf-kit/lexical'
import { EditorExporter } from './EditorExporter'

export class EditorOdtExporter extends EditorExporter {
async export(): Promise<Uint8Array> {
return lexicalToOdt(this.editor.getEditorState().toJSON(), {
pageFormat: 'A4',
fetchImage: async (src) => {
const b64 = await this.callbacks.fetchExternalImageAsBase64(src)
if (!b64) return undefined
const binary = atob(b64.split(',')[1] ?? b64)
return Uint8Array.from(binary, c => c.charCodeAt(0))
},
})
}
}
Edit: ExportDataFromEditorState.ts — add one case:
typescriptcase 'odt':
return new EditorOdtExporter(editorState, callbacks).export()
Edit: DataTypesThatDocumentCanBeExportedAs in @proton/docs-shared — add 'odt' to the union type.
Posting here in case it's useful. Happy to answer any questions about the library.


Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing exporter structure around applications/docs-editor/src/app/Conversion/Exporter/EditorExporter.ts and the named ExportDataFromEditorState.ts entry point. Add the ODT exporter and update DataTypesThatDocumentCanBeExportedAs in @proton/docs-shared; done means the odt export path returns a valid ODT file, including the documented image-fetch behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.